An open source collection of Linchpin's configs. Primarily used for Renovate bot and shared workflows. While there are some aspects of this repo that are specific to Linchpin and our build process, other organizations can take advantage of them if they want to use them.
v4 is a ground-up rework of the build/deploy pipeline. The full previous/next story — including the v3 bugs it fixes and the caller migration steps — lives in docs/MIGRATION-v3-to-v4.md. The headlines:
- Release-please publishes; the deploy builds and archives. release-please
publishes each GitHub release directly (no draft step). The production deploy
(
deploy.ymlwithbuild_for_release) builds the project, deploys it, and attaches the deploy-readyrelease.zipto that release.deploy.ymlalso accepts arelease_taginput that downloads an already-attached asset and deploys it without rebuilding — an instant rollback: dispatch a deploy with a previous tag. - One build job instead of five. Composer, theme and plugin builds run serially in one job with working caches (Composer keyed on composer.lock, npm via setup-node). The v3 artifact-reshuffle job is gone.
- Composite actions instead of runtime wget. Scripts that v3 fetched from
a branch at run time now ship inside
actions/composite actions (setup-wp-php,build-release,deploy-pressable,update-readme) — the ref you pin is the code that runs. - One PR lint workflow.
lint.ymlreplaces phplint + phpcs + phpcbf with a single cached job: syntax lint (any PHP version), phpcs on changed files with inline annotations, optional PHPStan. - Deploys verify themselves. A post-deploy health check gates the GitHub deployment status; maintenance mode is opt-in; bookkeeping jobs became steps.
- Least-privilege permissions declared in every workflow, and secrets are passed via env (no auth.json on disk).
v3 was a moving branch. v4 will GA as an immutable v4.0.0 tag with a moving
v4 major tag (see the migration doc for the plan). Until GA, @v4
references the development branch while linchpin/linchpin.com validates it.
Below is a list of standard secrets and variables used in Linchpin's shared workflows.
To learn more about secrets in your workflows please see GitHub's documentation.
| Key | Default | Description |
|---|---|---|
| SSH_KEY | The SSH key used to interact w/ the remote environment | |
| SSH_USER | The SSH user used to interact w/ the remote environment | |
| SSH_PASS | The SSH pass for environments that cannot support SSH Keys (Cloudways Autonomous) | |
| SSH_HOST | The SSH IP or Host Name | |
| PACKAGIST_COMPOSER_AUTH_JSON | auth.json contents for packagist.linchpin.com (v4 passes this via the COMPOSER_AUTH env) | |
| PRESSABLE_API_CLIENT_ID | Pressable API client (maintenance mode, backups) | |
| PRESSABLE_API_CLIENT_SECRET | Pressable API secret | |
| MANTLE_API_BEARER | Mantle API token used by the backup-and-continue deploy flow | |
| GH_BOT_TOKEN | Bot token used by update-readme.yml to open PRs | |
| SATISPRESS_USER | Private Packagist auth (remote-plugin-install path — not yet ported to v4) | |
| SATISPRESS_PASSWORD | Private Packagist auth (remote-plugin-install path — not yet ported to v4) |
To learn more about variables in your workflows please see GitHub's documentation.
| Key | Default | Description |
|---|---|---|
| HOST | The host of the project, one of pressable, wpengine, cloudways |
|
| SITE_URL | The url of the site including https:// (also used by the v4 post-deploy health check) | |
| SITE_ID | When using Pressable this is how we reference a site | |
| INSTALL_NAME | Install name when project is hosted on WP Engine | |
| DEPLOYMENT_AUTH_TYPE | key | Cloudways SSH auth type: key or pass (Cloudways Autonomous) |
| REMOTE_PLUGIN_INSTALL | false | Install plugins on the server via WP CLI instead of shipping them (not yet ported to v4) |
| BRANCH | staging | The default branch associated with the environment |
| PHP_VERSION | PHP version used for builds and linting (e.g. 8.5) |
|
| NODE_VERSION | Node version used for builds (e.g. 24) |
|
| THEMES | A JSON formatted array of themes to build Ex ["linchpin"] |
|
| PLUGINS | A JSON formatted array of plugins to build Ex ["linchpin-functionality"] |
|
| THEME_USES_COMPOSER | false | Do the theme(s) use composer to load dependencies |
| PLUGIN_USES_COMPOSER | true | Do the plugin(s) use composer to load dependencies |
v3's
ENVIRONMENTandDEPLOYMENT_PATHvariables are no longer read by v4 workflows (deployment paths are composite-action inputs with per-host defaults).
Linchpin WordPress projects use Release Please with Conventional Commits to create releases.
| File | Description |
|---|---|
| build.yml | Single-job project build producing a deploy-ready release artifact; optionally archives it on a GitHub release as a rollback asset |
| deploy.yml | Deploys a fresh build (staging), builds + deploys + archives a release (production via build_for_release), or redeploys a prebuilt asset (rollback via release_tag) to Pressable, WP Engine, or Cloudways |
| deploy-continue.yml | Second half of the backup-and-continue flow — dispatched (via the caller) by Mantle once the Pressable backup completes |
| lint.yml | PR lint: PHP syntax (any version), phpcs on changed files via cs2pr, optional PHPStan |
| update-readme.yml | Update the project README plugin table from composer.lock |
| ci.yml | This repo's own CI: actionlint + yamllint + zizmor |
| Action | Description |
|---|---|
| setup-wp-php | PHP via setup-php + cached Composer install + COMPOSER_AUTH (no auth.json on disk) |
| build-release | Turn a built tree into a clean release/ dir using the project .distignore |
| deploy-pressable | Upload + sync a release to Pressable over SSH, maintenance mode, health check |
| deploy-wpengine | Upload + sync a release to WP Engine over SSH, health check |
| deploy-cloudways | Upload + sync a release to Cloudways (key or password SSH auth), health check |
| update-readme | Regenerate the README plugin/theme table from composer.lock |
See docs/MIGRATION-v3-to-v4.md for complete caller examples (CI, staging/production deploys, release-please wiring, and rollback).
name: Deploy to Production
on:
release:
types: [published]
concurrency:
group: deploy-production
cancel-in-progress: false
permissions:
contents: read
deployments: write
jobs:
deploy:
uses: linchpin/actions/.github/workflows/deploy.yml@v4
secrets: inherit
with:
environment: production
# Build this release, deploy it, and archive the zip on the release.
build_for_release: ${{ github.event.release.tag_name }}| File | description |
|---|---|
| global.json | Shared global config for renovatebot |
| wordpress.json | Shared config for renovatebot for WordPress installs. |
| js.json | Shared config for javascript projects (gulp builds, etc ) |
When your local project uses Release Please that action will handle bumping the version numbers of all files you define within the release-please-config.json. However it doesn't take into account replacing arbitrary strings such as release date or updating the list of plugins updated within this release. The update-readme.yml workflow seeks to fix that by updating the readme.md of your project with relevant information.
| Tag | Description |
|---|---|
<!-- x-linchpin-plugin-list-start -->.*<!-- x-linchpin-plugin-list-end --> |
Update a table of the plugins that are currently installed within the projects composer.lock file |
<!-- x-linchpin-release-date-start -->.*<!-- x-linchpin-release-date-end --> |
Update the release date of your project |
| File | Description |
|---|---|
| default.distignore | Default .distignore applied during the release build if no .distignore is provided within your project (a copy is bundled in actions/build-release) |
