Skip to content

Release Process

dde follows semantic versioning and uses GitHub Actions for automated releases.

dde uses Semantic Versioning:

  • Major (v3.0.0): breaking changes
  • Minor (v2.1.0): new features, backward-compatible
  • Patch (v2.0.1): bug fixes, backward-compatible

A release bundles three artifacts that must stay in lockstep: a new section at the top of CHANGELOG.md, the APP_VERSION constant in src/Application.php, and a GPG-signed annotated tag v<version>.

The repo ships a releasing skill (.claude/skills/releasing/SKILL.md) that walks Claude Code through the whole sequence — categorising commits, drafting the changelog entry, bumping APP_VERSION, creating the signed commit + tag, and pausing before the push for explicit approval. To trigger it inside Claude Code, ask Claude to “create a release” (or invoke the skill directly via /releasing if the slash binding is available); the model loads the skill and follows it step by step.

If you prefer to drive the release by hand:

  1. Ensure all changes are merged to the release branch and the QA pipeline passes
  2. Add a ## [<version>] - YYYY-MM-DD section at the top of CHANGELOG.md with the user-visible Added/Changed/Fixed bullets
  3. Update APP_VERSION in src/Application.php (single source of truth for dde --version)
  4. Commit signed + signed-off:
Terminal window
git add CHANGELOG.md src/Application.php
git commit -S --signoff -m "chore(release): bump version to v2.1.0"
  1. Create the annotated, signed tag and push:
Terminal window
git tag -s v2.1.0 -m "v2.1.0"
git push origin <branch> v2.1.0

The tag name must start with v (e.g. v2.0.0, v2.1.0).

Pushing a v* tag triggers the release workflow (.github/workflows/release.yml). The pipeline:

  1. Reads the PHP version from composer.json (single source of truth)
  2. Runs quality checks: ECS, PHPStan, Rector, and tests
  3. Builds the PHAR using humbug/box
  4. Combines PHAR with micro.sfx from static-php-cli to produce standalone binaries
  5. Uploads binaries to a GitHub Release
  6. Publishes the package repos (APT, Alpine, Arch, RPM) and the Homebrew binaries to the packages.dde.sh S3 bucket
  7. Invalidates the CloudFront cache so the freshly published repo indexes are served immediately instead of stale cached copies

The same publish + invalidate flow runs on every push to v2 via the nightly workflow (.github/workflows/nightly.yml), targeting the *-nightly repo paths in the same bucket and the same CloudFront distribution.

The publishing jobs read these repository secrets:

SecretPurpose
AWS_ACCESS_KEY_ID / AWS_SECRET_ACCESS_KEYIAM credentials for the packages.dde.sh bucket and the CloudFront invalidation
CLOUDFRONT_DISTRIBUTION_IDThe distribution that fronts packages.dde.sh; used by aws cloudfront create-invalidation --paths "/*"
GPG_PRIVATE_KEY / GPG_PASSPHRASESign the APT/Arch/RPM repo metadata
ALPINE_RSA_PRIVATE_KEYSign the Alpine repo index
HOMEBREW_SSH_KEYPush the updated formula to the Homebrew tap repo

The IAM principal behind AWS_ACCESS_KEY_ID needs cloudfront:CreateInvalidation (and cloudfront:GetInvalidation) on the distribution in addition to its existing s3:* access to the bucket. A whole-distribution /* invalidation counts as a single path for billing.

The release pipeline produces binaries for 4 platforms:

PlatformArchitectureBinary Name
macOSx86_64dde-darwin-amd64
macOSarm64 (Apple Silicon)dde-darwin-arm64
Linuxx86_64dde-linux-amd64
Linuxarm64dde-linux-arm64

The scripts/build.sh script automates the binary creation:

  1. Reads the PHP version from composer.json
  2. Downloads the matching micro.sfx from static-php-cli
  3. Combines micro.sfx + bin/dde.phar into a standalone executable

Users install or update via the package managers listed in the installation documentation (Homebrew, APT, Alpine, Arch Linux, RPM).