This repository contains multiple reusable GitHub Actions workflows with distinct purposes. Each workflow can be called independently or chained together, depending on the project needs.
- Centralized build and release process.
- Monorepo friendly: build one project of a repository with
working_directory. - Multi-version PHP testing.
- Safe folder synchronization with configurable mappings.
- Reusable across multiple projects.
Pin callers to the major tag @v3:
uses: WritePoetry/reusable-workflows/.github/workflows/build.yml@v3Each release is cut as an immutable tag (v3.0.0, v3.1.0, β¦); the v3 tag is
moved forward to the newest backward-compatible release. Use @main only for
testing, or a full commit SHA for maximum reproducibility.
Compiles assets (npm / Composer) and prepares artifacts for deployment or release. Designed for WordPress projects using @wordpress/scripts, at the repository root or inside a monorepo.
| Name | Description | Required | Default |
|---|---|---|---|
working_directory |
Path to the project to build, relative to the repo root. Set it to build one project of a monorepo. | No | . |
artifact_name |
Name of the folder artifact to upload. If empty, the folder upload is skipped. | No | "" |
create_zip |
If true, runs npm run plugin-zip and uploads a version-named ZIP artifact called release-zip. |
No | false |
artifact_paths |
Extra glob lines appended to the folder artifact path: (actions/upload-artifact syntax; prefix with ! to exclude). |
No | excludes .git, .github, node_modules |
| Name | Description |
|---|---|
zip_file |
File name of the generated ZIP (empty unless create_zip was true). |
- Node setup,
npm ci,npm run buildandcomposer installeach run only when the matching manifest exists inworking_directory, so npm-only, Composer-only and mixed projects all work. npm cineeds a committedpackage-lock.json(also used for the npm cache key);npm run builduses--if-present.- The folder artifact is rooted at
working_directory, soartifact_namemust not contain/.
- npm script:
"plugin-zip": "wp-scripts plugin-zip". - Versioning: the ZIP is named
<package-name>-<version>.zip, frompackage.jsonnameand the Git tag (vprefix stripped).
jobs:
build:
uses: WritePoetry/reusable-workflows/.github/workflows/build.yml@v3
with:
create_zip: true
permissions:
contents: read
packages: read
secrets: inheritDownloads a ZIP artifact and creates an official GitHub Release with automated changelogs. The job runs only for tag refs (refs/tags/*).
| Name | Description | Required | Default |
|---|---|---|---|
artifact_zip_name |
Name of the artifact containing the ZIP file(s). | No | release-zip |
jobs:
release:
needs: build
uses: WritePoetry/reusable-workflows/.github/workflows/release.yml@v3
permissions:
contents: write
secrets: inheritRuns PHPUnit tests across multiple PHP versions, with optional WordPress integration testing and coding-standards checks.
| Name | Description | Required | Default |
|---|---|---|---|
php_versions |
JSON array of PHP versions used for matrix testing | No | ['7.4', '8.0', '8.1', '8.2'] |
phpunit9_config |
PHPUnit 9-specific configuration file, used only when detected | No | phpunit-9.xml |
- A valid
composer.jsonincluding PHPUnit (and optionally WPCS). - The script
bin/install-wp-tests.shfor WordPress integration tests.
- Lint gate:
phpcsruns first; the matrix runs only if it passes. - Matrix Testing: each PHP version runs independently.
- Database: spins up MySQL 5.7 and prepares
wordpress_testautomatically whenbin/install-wp-tests.shis present. - Multisite: executes tests in both standard and Multisite (
WP_MULTISITE=1) environments.
jobs:
tests:
uses: WritePoetry/reusable-workflows/.github/workflows/php-tests.yml@v3
with:
php_versions: "['8.1','8.2']"
secrets: inheritSynchronizes selected local directories to a remote server over SSH. Each entry in mappings runs as its own matrix job. Source files come from a repository checkout, a downloaded build artifact, or both.
| Name | Description | Required | Default |
|---|---|---|---|
host |
Remote server host | Yes | β |
username |
SSH username for the remote server | Yes | β |
folder |
Base folder on the remote server where synchronization occurs | Yes | β |
mappings |
JSON array of {from, to, exclude} objects. from is a local path, to is appended to folder, exclude is a space-separated list of glob patterns. |
No | Default WordPress structure |
transport |
ssh (rsync over SSH β fast, delta transfer, but the server user needs a shell) or sftp (lftp mirror over the SFTP subsystem β works with SFTP-only users, e.g. Cloudways application users). |
No | ssh |
artifact_name |
Build artifact to download into the workspace before syncing. Skipped when empty. | No | "" |
checkout |
Check out the calling repository. Set to false when artifact_name already contains everything to deploy. |
No | true |
| Name | Description | Required |
|---|---|---|
ssh_key |
Private SSH key for rsync / SFTP authentication | Yes |
- Missing
fromsources are skipped (the job succeeds). - Host keys are pinned via
ssh-keyscanandStrictHostKeyChecking=yes. transport: sftpsupports directory mappings only, does not delete remote files, andapt-installslftpon the runner.- Set
concurrencyin the calling workflow if you need to serialize deploys.
jobs:
deploy_files:
uses: WritePoetry/reusable-workflows/.github/workflows/deploy.yml@v3
with:
host: example.com
username: deploy
folder: /var/www/html/wp-content
mappings: |
[
{"from": "themes", "to": "/themes/"},
{"from": "plugins", "to": "/plugins/", "exclude": ".git* node_modules"}
]
secrets:
ssh_key: ${{ secrets.SERVER_SSH_DEPLOY_KEY }}jobs:
tests:
uses: WritePoetry/reusable-workflows/.github/workflows/php-tests.yml@v3
secrets: inherit
build:
needs: tests
uses: WritePoetry/reusable-workflows/.github/workflows/build.yml@v3
with:
create_zip: true
permissions:
contents: read
packages: read
secrets: inherit
release:
needs: build
uses: WritePoetry/reusable-workflows/.github/workflows/release.yml@v3
permissions:
contents: write
secrets: inheritFor a repository holding more than one buildable project, run the build in the
calling workflow (a plain job or a matrix), upload one artifact with the whole
deploy tree, then hand it to deploy.yml with checkout: false and
artifact_name. See personal-website/.github/workflows/main.yml for a worked
example.
Note on persistence: Artifacts are the only way to transfer files between jobs.
upload-artifactsaves build results anddownload-artifactretrieves them downstream. Job outputs carry metadata (likezip_file) only, never files.