PHPackages                             schenke-io/packaging-tools - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Utility &amp; Helpers](/categories/utility)
4. /
5. schenke-io/packaging-tools

ActiveLibrary[Utility &amp; Helpers](/categories/utility)

schenke-io/packaging-tools
==========================

Tools to simplify publishing github packages

v0.2.2(3mo ago)01.1k↓50%7MITPHPPHP ^8.3CI passing

Since Jan 22Pushed 3mo agoCompare

[ Source](https://github.com/schenke-io/packaging-tools)[ Packagist](https://packagist.org/packages/schenke-io/packaging-tools)[ Docs](https://github.com/schenke-io/packaging-tools)[ RSS](/packages/schenke-io-packaging-tools/feed)WikiDiscussions main Synced 1mo ago

READMEChangelogDependencies (15)Versions (12)Used By (7)

[![Coverage](workbench/resources/md/svg/coverage.svg)](workbench/resources/md/svg/coverage.svg)[![PHPStan](workbench/resources/md/svg/phpstan.svg)](workbench/resources/md/svg/phpstan.svg)[![Version](https://camo.githubusercontent.com/44dbb1e267b0bdf713d1c2aaa13a562aa9ab5b18854246eaf612724da146a38c/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f736368656e6b652d696f2f7061636b6167696e672d746f6f6c733f7374796c653d666c6174)](https://packagist.org/packages/schenke-io/packaging-tools)[![Downloads](https://camo.githubusercontent.com/77aa5bf5aaa126ae3f37b54896868aaa2a1026710bf5edc6d3f378314adf8389/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f736368656e6b652d696f2f7061636b6167696e672d746f6f6c733f7374796c653d666c6174)](https://packagist.org/packages/schenke-io/packaging-tools)[![Tests](https://github.com/schenke-io/packaging-tools/actions/workflows/run-tests.yml/badge.svg)](https://github.com/schenke-io/packaging-tools/actions/workflows/run-tests.yml)[![License](https://camo.githubusercontent.com/2486a4c6cbcf5e72040f560bf82d20cfe777b633fb2ec05f831005b179c20d09/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f6c6963656e73652f736368656e6b652d696f2f7061636b6167696e672d746f6f6c733f7374796c653d666c6174)](https://github.com/schenke-io/packaging-tools/blob/main/LICENSE.md)[![PHP](https://camo.githubusercontent.com/485ad4202d4454be91e1158200f0ad883c3bc808d565ac377477aaf119dac605/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f7068702d762f736368656e6b652d696f2f7061636b6167696e672d746f6f6c733f7374796c653d666c6174)](https://packagist.org/packages/schenke-io/packaging-tools)

Packaging Tools
==========================================================

[](#packaging-tools)

> Tools to simplify publishing github packages

[![cover](workbench/resources/md/cover.png)](workbench/resources/md/cover.png)

This package is a collection of tools to simplify the package and project development.

The main elements are:

- **Markdown** Assemble the readme.md file out of small markdown files, class comments and other sources
- **Badge** build the badge custom or from existing files
- **Setup** read the `.packaging-tools.neon` configuration file and modify scripts in `composer.json`
- **Boost Skills &amp; Guidelines** this package supports the [Laravel Boost](https://laravel.com/docs/12.x/boost) standard for AI-ready packages.

### Skill-based documentation

[](#skill-based-documentation)

Documentation for this package is partly generated from **AI Skills**. These skills are small, focused pieces of documentation that describe specific features or workflows. They are located in `resources/boost/skills/` and are also compatible with Laravel Boost.

By using these skills, the package ensures that both human developers and AI assistants have clear, actionable instructions on how to use the provided tools.

- [Packaging Tools](#packaging-tools)
    - [Skill-based documentation](#skill-based-documentation)
    - [Badges System](#badges-system)
        - [Usage](#usage)
        - [Supported Badge Types (BadgeType Enum)](#supported-badge-types-badgetype-enum)
        - [Special Badges](#special-badges)
            - [Laravel Forge](#laravel-forge)
        - [Customization](#customization)
- [AI Guidelines and Skills for Boost](#ai-guidelines-and-skills-for-boost)
    - [When to use this skill](#when-to-use-this-skill)
    - [AI Guidelines](#ai-guidelines)
        - [Example `core.blade.php`](#example-core-blade-php)
    - [AI Skills](#ai-skills)
        - [Example `SKILL.md`](#example-skill-md)
    - [Database Migrations](#database-migrations)
        - [Usage](#usage)
        - [Process](#process)
        - [Workbench Support](#workbench-support)
        - [Model Discovery](#model-discovery)
    - [Migrations Trait](#migrations-trait)
        - [Usage](#usage)
    - [Markdown Assembler](#markdown-assembler)
        - [Usage in a Script](#usage-in-a-script)
        - [Commands and Purpose](#commands-and-purpose)
            - [Assembler Methods](#assembler-methods)
            - [Badges: `badges()`](#badges-badges)
            - [Classes: `classes()`](#classes-classes)
            - [Tables: `tables()`](#tables-tables)
            - [Table of Contents: `toc()`](#table-of-contents-toc)
    - [Installation](#installation)
    - [Concept](#concept)
    - [Configuration](#configuration)
        - [Initialization](#initialization)
        - [Configuration Keys](#configuration-keys)
        - [Detailed Key Purpose](#detailed-key-purpose)
            - [`analyse`](#analyse)
            - [`coverage`](#coverage)
            - [`infection`](#infection)
            - [`markdown`](#markdown)
            - [`migrations`](#migrations)
            - [`pint`](#pint)
            - [`quick`](#quick)
            - [`release`](#release)
            - [`sql-cache`](#sql-cache)
            - [`test`](#test)
            - [`customTasks`](#customtasks)
        - [Schema Validation](#schema-validation)
    - [Seeding Trait](#seeding-trait)
        - [Usage](#usage)
        - [MarkdownAssembler](#markdownassembler)
            - [How to assemble a markdown](#how-to-assemble-a-markdown)
                - [Bootstrapping](#bootstrapping)
                - [Assembly Example](#assembly-example)
                - [Key Methods](#key-methods)
            - [Public methods of MarkdownAssembler](#public-methods-of-markdownassembler)
        - [MakeBadge](#makebadge)
            - [Public methods of MakeBadge](#public-methods-of-makebadge)
        - [Config](#config)
            - [Public methods of Config](#public-methods-of-config)

TitleDescription[Dynamic SVG Badges](resources/boost/skills/badges/SKILL.md)Generate SVG badges for project metrics[AI-Ready Boost Guidelines](resources/boost/skills/guidelines/SKILL.md)Write AI guidelines and skills for projects based on Laravel Boost standards[Elegant Migration Management](resources/boost/skills/imported-migrations/SKILL.md)Clean up and manage database migrations[Modular Markdown Assembler](resources/boost/skills/markdown-assembly/SKILL.md)Assemble modular documentation and class references[Swift Project Setup](resources/boost/skills/setup/SKILL.md)Basic installation and configuration[Turbo Speed Seeding](resources/boost/skills/speed-seeding/SKILL.md)Speeds up database preparation in tests by loading a pre-generated SQL dumpBadges System
------------------------------------------------------

[](#badges-system)

The badges system allows for automatic generation of SVGs for various project metrics. It supports a wide range of built-in drivers and can be easily extended.

### Usage

[](#usage)

Run the following command to generate all detected badges:

```
composer setup badges
```

Alternatively, you can call it from PHP:

```
use SchenkeIo\PackagingTools\Badges\MakeBadge;

MakeBadge::auto();

// generate specific badges with auto-detected paths:
MakeBadge::makeCoverageBadge();
MakeBadge::makePhpStanBadge();
MakeBadge::makeInfectionBadge();
MakeBadge::makePhpVersionBadge();

// or with explicit paths:
MakeBadge::makeCoverageBadge('path/to/clover.xml');
MakeBadge::makePhpStanBadge('path/to/phpstan.neon');
MakeBadge::makeInfectionBadge('path/to/infection-report.json');
```

The `auto()` method iterates through all supported badge types and attempts to detect the necessary source files or configurations automatically.

### Supported Badge Types (BadgeType Enum)

[](#supported-badge-types-badgetype-enum)

The `BadgeType` Enum defines the badges that can be automatically detected and generated:

- **Coverage**: Displays the code coverage percentage. Detected from `clover.xml` (location found via `phpunit.xml`).
- **PhpStan**: Displays the PHPStan analysis level or status. Detected from `phpstan.neon` or `phpstan.neon.dist`.
- **Infection**: Displays the mutation score. Detected from `infection-report.json`.
- **PHP**: Displays the minimum PHP version requirement parsed from `composer.json`.
- **Version**: Displays the latest stable version from Packagist (via shields.io).
- **Downloads**: Displays the total number of downloads from Packagist (via shields.io).
- **Laravel**: Displays the minimum Laravel version requirement parsed from `composer.json`.
- **Tests**: Displays the GitHub Action workflow status (e.g., for "run-tests") (via shields.io).
- **License**: Displays the project license (via shields.io).

### Special Badges

[](#special-badges)

#### Laravel Forge

[](#laravel-forge)

The **Forge** badge is not included in the `BadgeType` enum because it requires specific parameters that cannot be automatically detected. It can be added via the Markdown Assembler:

```
$assembler->badges()->forge(
    hash: 'your-hash',
    server: 123456,
    site: 654321,
    date: 1, // show date
    label: 1 // show label
);
```

### Customization

[](#customization)

You can also define custom badges:

```
use SchenkeIo\PackagingTools\Badges\MakeBadge;

MakeBadge::define('My Subject', 'Success', '27AE60')
    ->store('resources/md/svg/my-badge.svg');
```

AI Guidelines and Skills for Boost
================================================================================================

[](#ai-guidelines-and-skills-for-boost)

When to use this skill
------------------------------------------------------------------------

[](#when-to-use-this-skill)

Use this skill when you need to create or update AI guidelines or skills for a Laravel package to make it "Boost-compatible".

AI Guidelines
------------------------------------------------------

[](#ai-guidelines)

To include AI guidelines for a package, add a `resources/boost/guidelines/core.blade.php` file to your package. When users of your package run `php artisan boost:install`, Boost will automatically load your guidelines.

AI guidelines should provide a short overview of what your package does, outline any required file structure or conventions, and explain how to create or use its main features (with example commands or code snippets). Keep them concise, actionable, and focused on best practices so AI can generate correct code for your users.

### Example `core.blade.php`

[](#example-corebladephp)

```
## Package Name

This package provides [brief description of functionality].

### Features

- Feature 1: [clear & short description].
- Feature 2: [clear & short description]. Example usage:

```php
$result = PackageName::featureTwo($param1, $param2);
```

```

## AI Skills

To include skills for a third-party package, add a `resources/boost/skills/{skill-name}/SKILL.md` file to your package. When users of your package run `php artisan boost:install`, Boost will automatically install your skills based on user preference.

Boost Skills support the [Agent Skills format](https://agentskills.io/what-are-skills) and should be structured as a folder containing a `SKILL.md` file with YAML frontmatter and Markdown instructions. The `SKILL.md` file must include required frontmatter (`name` and `description`) and can optionally include scripts, templates, and reference materials.

Skills should outline any required file structure or conventions, and explain how to create or use its main features (with example commands or code snippets). Keep them concise, actionable, and focused on best practices so AI can generate correct code for your users.

### Example `SKILL.md`

```markdown
---
name: package-name-development
description: Build and work with PackageName features, including components and workflows.
---

# Package Name Development

## When to use this skill
Use this skill when working with PackageName features...

## Features

- Feature 1: [clear & short description].
- Feature 2: [clear & short description]. Example usage:

$result = PackageName::featureTwo($param1, $param2);

```

Database Migrations
------------------------------------------------------------------

[](#database-migrations)

The migrations component helps you keep your package's migrations in sync with your development database. It leverages `kitloong/laravel-migrations-generator` to regenerate migrations from an existing database schema.

### Usage

[](#usage-1)

Run the following command to start the migration regeneration:

```
composer migrations
```

### Process

[](#process)

1. **Check for Generator**: The tool verifies if `kitloong/laravel-migrations-generator` is installed.
2. **Connection Selection**: The tool uses the source connection configured in `.packaging-tools.neon` or defaults to your primary database connection.
3. **Cleanup**: Existing migrations in the migrations folder will be deleted to ensure a clean state.
4. **Regeneration**: New migrations are generated from the selected database connection.
5. **Permissions**: Generated migration files are set to read-only (mode 444) to prevent accidental manual edits, encouraging the "database-first" approach for packages.

### Workbench Support

[](#workbench-support)

If you are using a workbench for package development, the tool automatically detects and uses `workbench/database/migrations` if it exists.

### Model Discovery

[](#model-discovery)

When using `connection:*` or when no tables are explicitly defined, the tool automatically scans for Eloquent models in the following directories (in order of priority):

1. `workbench/app/Models`
2. `app/Models`
3. `src/Models`

If none of these directories exist, a `PackagingToolException` is thrown to ensure the process does not proceed with incomplete information.

Migrations Trait
------------------------------------------------------------

[](#migrations-trait)

This trait is intended for use within an Artisan command. It automates the generation and cleaning of package migrations by reverse-engineering your database schema.

### Usage

[](#usage-2)

```
use SchenkeIo\PackagingTools\Traits\GeneratesPackageMigrations;
use Illuminate\Console\Command;

class MyMigrationCommand extends Command
{
    use GeneratesPackageMigrations;

    public function handle()
    {
        $this->generatePackageMigrations();
    }
}
```

- **Auto-detection:** It automatically detects models and their associated tables based on your configuration.
- **Cleaning:** It removes environment-specific connection calls from the generated migrations to ensure they are portable.
- **Consistency:** It ensures standard Laravel system tables are included as a base.

Markdown Assembler
----------------------------------------------------------------

[](#markdown-assembler)

The Markdown Assembler allows you to build complex Markdown files (like your README.md) from multiple components and source files.

### Usage in a Script

[](#usage-in-a-script)

The tool is typically used in a `MakeMarkdown` script. You can generate a boilerplate script using:

```
// This is usually part of the automated setup
```

Example of an assembler script:

```
use SchenkeIo\PackagingTools\Markdown\MarkdownAssembler;

$assembler = new MarkdownAssembler('resources/md');
$assembler->addTableOfContents()
    ->addMarkdown('header.md')
    ->badges()->all()
    ->addMarkdown('installation.md')
    ->addMarkdown('usage.md')
    ->classes()->all()
    ->writeMarkdown('README.md');
```

### Commands and Purpose

[](#commands-and-purpose)

#### Assembler Methods

[](#assembler-methods)

- `autoHeader()`: Adds a default header block based on project information.
- `skipWrittenBy()`: Skips the "DO NOT EDIT" warning and the footer "Markdown file generated by..." in the output file.
- `addMarkdown(string $filepath)`: Includes a markdown file from the source directory.
- `addTableOfContents()`: Adds a placeholder for the Table of Contents.
- `addText(string $content)`: Adds raw markdown text directly.
- `addContentProvider(MarkdownPieceInterface $provider)`: Adds a custom component that implements the `MarkdownPieceInterface`.
- `image(string $text, string $path, string $url)`: Adds an image with alt text, local path, and optional link URL.
- `writeMarkdown(string $filepath)`: Finalizes the assembly and writes the content to the specified file.

#### Badges: `badges()`

[](#badges-badges)

Returns a `Badges` component for adding project badges.

- `all()`: Adds all automatically detected badges (Version, Test, Downloads, Coverage, etc.).
- `version(BadgeStyle $badgeStyle)`: Adds a version badge from Packagist.
- `test(string $workflowFile, BadgeStyle $badgeStyle, string $branch = 'main')`: Adds a GitHub Actions test status badge.
- `download(BadgeStyle $badgeStyle)`: Adds a total downloads badge from Packagist.
- `php(BadgeStyle $badgeStyle)`: Adds a PHP version requirement badge.
- `local(string $text, string $path)`: Adds a link to a local SVG file.
- `forge(string $hash, int $server, int $site, int $date = 1, int $label = 1, BadgeStyle $badgeStyle = BadgeStyle::FlatSquare)`: Adds a Laravel Forge deployment status badge.

#### Classes: `classes()`

[](#classes-classes)

Returns a `Classes` component for documenting PHP classes.

- `all()`: Automatically documents all classes found in the `src/` directory.
- `add(string $classname)`: Documents a single class by its fully qualified name.
- `glob(string $pattern)`: Documents all classes matching a file pattern (e.g., `src/Models/*.php`).
- `custom(string $classname, Closure $callback)`: Documents a class using a custom rendering callback.

#### Tables: `tables()`

[](#tables-tables)

Returns a `Tables` component for creating Markdown tables.

- `fromFile(string $filepath)`: Reads table data from a CSV, TSV, or PSV file.
- `fromCsvString(string $csv, string $delimiter)`: Parses table data from a formatted string.
- `fromArray(array $data)`: Builds a table directly from a PHP array.

#### Table of Contents: `toc()`

[](#table-of-contents-toc)

Returns a `TOC` component for generating a linked Table of Contents.

Installation
----------------------------------------------------

[](#installation)

Install the package with composer:

```
  composer require schenke-io/packaging-tools
```

Add the setup command into `composer.json` under scripts.

```
{
    "scripts": {
        "setup": "SchenkeIo\\PackagingTools\\Setup::handle"
    }
}
```

Start the setup:

```
  composer setup
```

or initialize the configuration:

```
  composer setup config
```

Concept
------------------------------------------

[](#concept)

This package follows the following concept:

- setup and configuration is controlled by a config file
- manual edits have higher priority than automatics
- when manual edits would be overwritten there is a warning
- the documentation is organised out of components which get assembled at the end
- important classes and methods are marked and documented
- badges are written from data
- the build process is controlled by script
- missing files are explained with full path

Configuration
------------------------------------------------------

[](#configuration)

The package is configured via a `.packaging-tools.neon` file in your project root. This file uses the [NEON](https://ne-on.org/) format, which is similar to YAML but provides stronger schema validation and is ideal for configuration.

### Initialization

[](#initialization)

To create or sync your configuration file:

```
composer setup config
```

### Configuration Keys

[](#configuration-keys)

The following keys are supported in `.packaging-tools.neon`:

KeyTypePurposeExample`analyse``bool`Enables PHPStan static analysis`analyse: true``coverage``bool`Enables code coverage reporting during tests`coverage: true``infection``bool`Enables mutation testing with Infection`infection: true``markdown``string|null`The command to run for Markdown assembly`markdown: php workbench/MakeMarkdown.php``migrations``string|null`Configuration for migration generation`migrations: mysql:*``pint``bool`Enables code styling with Laravel Pint`pint: true``quick``array`Group task: `pint`, `test`, `markdown``quick: [pint, test, markdown]``release``array`Group task for pre-release checks`release: [pint, analyse, coverage, markdown]``sql-cache``boolstringnull``test``string`Test runner: `pest`, `phpunit` or `''``test: pest``customTasks``array`Mapping of custom task names to commands`customTasks: { my-task: "ls -la" }`### Detailed Key Purpose

[](#detailed-key-purpose)

#### `analyse`

[](#analyse)

Runs PHPStan to perform static analysis on your codebase. It automatically detects if you are using standard PHP or Laravel (Larastan).

#### `coverage`

[](#coverage)

Requires a test runner to be configured. It adds coverage flags to the test command and checks for the existence of `clover.xml`.

#### `infection`

[](#infection)

Runs mutation testing to check the quality of your tests. Requires `infection/infection` to be installed.

#### `markdown`

[](#markdown)

Points to the script that assembles your documentation. Usually `php workbench/MakeMarkdown.php`. Use `null` to disable.

#### `migrations`

[](#migrations)

Uses `kitloong/laravel-migrations-generator`. Can be a string in the format `connection:table1,table2`. Use `connection:*` to auto-detect tables from your models. Use `null` to disable.

#### `pint`

[](#pint)

Uses Laravel Pint to ensure your code follows the project's styling rules.

#### `quick`

[](#quick)

A shortcut to run essential checks quickly. By default it runs `pint`, `test` and `markdown`. You can override the list of tasks by providing an array.

#### `release`

[](#release)

A comprehensive check before releasing a new version. It typically runs `pint`, `analyse`, `test`, `coverage`, `infection` and `markdown`.

#### `sql-cache`

[](#sql-cache)

Dumps the current SQLite database to an SQL file (default `tests/Data/seeded.sql`). This can be loaded in tests using the `LoadsSeededSql` trait to significantly speed up database preparation. Can be `true` (default path), a `string` (custom path), or `null` (disabled).

> **Note:** To maintain the previous grouped behavior of running migrations and then sql-cache, you can add `@sql-cache` to your custom build commands or scripts.

#### `test`

[](#test)

Selects the testing framework. Supported values are `pest` and `phpunit`. Use an empty string `''` to disable tests.

#### `customTasks`

[](#customtasks)

Allows you to define your own tasks that can be run via `composer setup `.

### Schema Validation

[](#schema-validation)

All tasks in `packaging-tools` define their own configuration schema using `nette/schema`. This ensures that your configuration is always valid and provides helpful error messages if something is misconfigured.

Seeding Trait
------------------------------------------------------

[](#seeding-trait)

This trait is designed for testing environments to speed up database preparation. Instead of running all migrations and seeders for every test, you can load a pre-generated SQL dump.

### Usage

[](#usage-3)

```
use SchenkeIo\PackagingTools\Traits\LoadsSeededSql;
use Tests\TestCase;

class MyFeatureTest extends TestCase
{
    use LoadsSeededSql;

    public function setUp(): void
    {
        parent::setUp();
        $this->loadSeededSql();
    }
}
```

- **Speed:** Significantly faster than standard migrations and seeders in CI environments.
- **Ease of use:** Simply call `loadSeededSql()` in your test's `setUp` method.
- **Smart Loading:** It checks if the database is already seeded (e.g., by checking for the `users` table) before loading the SQL file to avoid redundant operations.

keydescriptionanalysefalse = disabled, true = enabled (uses phpstan/phpstan-phpunit or larastan/larastan)coveragefalse = disabled, true = enabled (adds --coverage to the test runner)infectionfalse = disabled, true = enabled (requires infection/infection)markdownnull = disabled, string = enabled (command to assemble Markdown files)migrationsnull = disabled, connection:\* = auto-detect, connection:table1,table2 = enabled (with connection and tables)pintfalse = disabled, true = enabled (uses laravel/pint)quickan array of scripts to include in this group: pint, test, markdownreleasean array of scripts to include in this group: pint, analyse, test, coverage, infection, markdownsql-cachenull = disabled, true = default path, 'path/to/file.sql' = custom pathtest'' = disabled, 'pest' or 'phpunit' = enabled### MarkdownAssembler

[](#markdownassembler)

Core engine for assembling Markdown documentation.

#### How to assemble a markdown

[](#how-to-assemble-a-markdown)

To assemble a markdown you need:

- a directory with markdown source files (e.g., `workbench/resources/md`)
- an assembly script (e.g., `workbench/MakeMarkdown.php`)

The `MarkdownAssembler` helps you combine static markdown files with dynamically generated content like badges, tables, and class documentation.

##### Bootstrapping

[](#bootstrapping)

You can initialize a markdown directory with standard files:

```
use SchenkeIo\PackagingTools\Markdown\MarkdownAssembler;

MarkdownAssembler::init('workbench/resources/md');
```

##### Assembly Example

[](#assembly-example)

```
