Skip to content

feat(release): add release-composer-package reusable workflow#124

Merged
CybotTM merged 3 commits into
mainfrom
feat/release-composer-package
May 12, 2026
Merged

feat(release): add release-composer-package reusable workflow#124
CybotTM merged 3 commits into
mainfrom
feat/release-composer-package

Conversation

@CybotTM
Copy link
Copy Markdown
Member

@CybotTM CybotTM commented May 12, 2026

Summary

  • Adds .github/workflows/release-composer-package.yml — atomic reusable workflow for Composer packages distributed via Packagist (plugins, libraries, framework modules).
  • Mirrors the immutability-friendly single-call pattern of release-go-app.yml and skill-repo-skill/release.yml: one softprops/action-gh-release@v3 step, no post-creation edits.
  • First consumer: netresearch/composer-agent-skill-plugin (no current release workflow — v2.0.0 was published manually).

Why a new workflow?

Existing workflow Why it doesn't fit
create-release.yml Deprecated 2026-04-26 — incompatible with release-immutability when assets are uploaded after creation
release-go-app.yml Go-specific: binary matrix, ldflags, container build
golib-create-release.yml Go-specific: runs go test, expects go.mod
typo3-ci-workflows/release-typo3-extension.yml TYPO3-specific: TER publish
skill-repo-skill/release.yml Skill-package-specific: zips a skill and attaches as asset

Composer packages have no assets to upload — Packagist syncs via webhook on tag push. So the right shape is "validate the tag, create the GitHub Release atomically, done." No multi-job split, no asset orchestration.

Validation steps

  1. Strict semver gate (v<MAJOR>.<MINOR>.<PATCH> + optional -prerelease / +build)
  2. Annotated/signed tag check (lightweight tags rejected by default)
  3. composer validate --strict --no-check-publish (opt-out via composer-validate: false)
  4. Prerelease auto-detection from -rc / -alpha / -beta / -pre suffix
  5. make-latest auto-computed against existing non-draft non-prerelease semver releases via GH API

Caller example

# .github/workflows/release.yml
name: Release
on:
  push:
    tags: ['v*']
permissions: {}
jobs:
  release:
    uses: netresearch/.github/.github/workflows/release-composer-package.yml@main
    permissions:
      contents: write

Test plan

  • actionlint passes (local: clean)
  • PR CI lint-workflows check passes
  • First consumption: netresearch/composer-agent-skill-plugin (follow-up PR) — verify it creates a GitHub Release on signed tag push with auto-generated notes

Copilot AI review requested due to automatic review settings May 12, 2026 13:42
@gemini-code-assist
Copy link
Copy Markdown

Note

Gemini is unable to generate a review for this pull request due to the file types involved not being currently supported.

Comment thread .github/workflows/release-composer-package.yml Fixed
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a new reusable GitHub Actions workflow to create GitHub Releases for Composer/Packagist packages in an “atomic” way (preflight checks + single release creation), aligned with the repo’s move away from post-creation release mutation.

Changes:

  • Introduces .github/workflows/release-composer-package.yml reusable workflow for Composer package releases triggered by semver v* tags.
  • Adds tag preflight validation (strict semver, annotated tag enforcement, prerelease + make_latest computation).
  • Optionally validates composer.json via composer validate --strict --no-check-publish before creating the GitHub Release with generated notes.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread .github/workflows/release-composer-package.yml Outdated
Comment thread .github/workflows/release-composer-package.yml Outdated
CybotTM added a commit that referenced this pull request May 12, 2026
- Validate tag semver BEFORE actions/checkout so the caller-supplied
  `inputs.tag` cannot reach `ref:` unvalidated
  (CodeQL actions/untrusted-checkout/medium #32 on PR #124).
- Header comment: 'signed-tag-push only' was wrong -- actual gate is
  annotated-tag push; signature verification is best-effort and the
  release proceeds with a warning if the signer's key is not on the
  runner. Reword to match implemented behavior.
- Header comment: claim that this 'matches release-go-app.yml's pattern'
  was inaccurate. release-go-app.yml flips draft and sets flags via a
  follow-up `gh release edit` step (asset-upload timing); this workflow
  is stricter -- single softprops/action-gh-release@v3 call, no
  post-creation edits, because Composer packages have no assets.

Signed-off-by: Sebastian Mendel <sebastian.mendel@netresearch.de>
CybotTM added 3 commits May 12, 2026 16:04
Atomic-release workflow for Composer packages distributed via Packagist
(plugins, libraries, framework modules). Mirrors the immutability-friendly
single-call pattern of release-go-app.yml and skill-repo-skill/release.yml:
softprops/action-gh-release@v3 in one step, no post-creation edits.

The deprecated create-release.yml split (create + finalize) does not apply
here because Composer packages have no assets to upload after the release
is created -- Packagist handles distribution via webhook on tag push.

Validation steps before publishing:
  - Strict v<MAJOR>.<MINOR>.<PATCH> semver gate on the tag
  - Annotated/signed tag check (reject lightweight)
  - composer validate --strict --no-check-publish (catches malformed
    composer.json before Packagist sees it; opt-out via composer-validate)

Same prerelease and make-latest auto-detection as create-release.yml:
prerelease auto-detected from -rc/-alpha/-beta/-pre suffix; make-latest
auto-computed by comparing the tag against existing non-draft, non-prerelease
semver releases via the GH API.

Signed-off-by: Sebastian Mendel <sebastian.mendel@netresearch.de>
- Validate tag semver BEFORE actions/checkout so the caller-supplied
  `inputs.tag` cannot reach `ref:` unvalidated
  (CodeQL actions/untrusted-checkout/medium #32 on PR #124).
- Header comment: 'signed-tag-push only' was wrong -- actual gate is
  annotated-tag push; signature verification is best-effort and the
  release proceeds with a warning if the signer's key is not on the
  runner. Reword to match implemented behavior.
- Header comment: claim that this 'matches release-go-app.yml's pattern'
  was inaccurate. release-go-app.yml flips draft and sets flags via a
  follow-up `gh release edit` step (asset-upload timing); this workflow
  is stricter -- single softprops/action-gh-release@v3 call, no
  post-creation edits, because Composer packages have no assets.

Signed-off-by: Sebastian Mendel <sebastian.mendel@netresearch.de>
…CodeQL

The previous fix (validate-then-checkout-with-validated-output) was still
flagged by CodeQL actions/untrusted-checkout because the analyzer tracks
data flow from `inputs.tag` through the validate step's output and into
`actions/checkout`'s `ref:` -- it cannot see that the value has been
constrained by a regex.

New approach: `actions/checkout` uses the default `github.ref` and never
references `inputs.tag`, eliminating the data-flow path entirely. After
checkout, a separate shell step validates the semver shape of the
caller-supplied tag and `git checkout refs/tags/$TAG --` moves the working
tree to the validated tag (no-op for tag-push, switches tree for
workflow_dispatch backfills).

CodeQL alert #32 should clear: there is no longer any expression in
`actions/checkout.with.ref` that references `inputs.*`.

Signed-off-by: Sebastian Mendel <sebastian.mendel@netresearch.de>
@CybotTM CybotTM force-pushed the feat/release-composer-package branch from c15f088 to f5deaec Compare May 12, 2026 14:04
@sonarqubecloud
Copy link
Copy Markdown

@CybotTM CybotTM merged commit 2c6869a into main May 12, 2026
9 checks passed
@CybotTM CybotTM deleted the feat/release-composer-package branch May 12, 2026 14:16
CybotTM added a commit to netresearch/composer-agent-skill-plugin that referenced this pull request May 12, 2026
## Summary

- Adds `.github/workflows/release.yml` — delegates to the org's
[`release-composer-package`](https://github.com/netresearch/.github/blob/main/.github/workflows/release-composer-package.yml)
reusable workflow ([introduced in
netresearch/.github#124](netresearch/.github#124)).
- Closes the missing-release-infrastructure gap flagged by the
github-release skill's pre-release validation: v1.x and v2.0.0 were
published manually because no automated release workflow existed.

## What the reusable workflow does

On signed-tag push (`v*`):

1. **Tag validation** — strict semver gate
(`v<MAJOR>.<MINOR>.<PATCH>[-pre][+build]`), reject lightweight tags
2. **`composer validate --strict --no-check-publish`** — catch malformed
`composer.json` before Packagist sees it
3. **Prerelease auto-detect** — from `-rc` / `-alpha` / `-beta` / `-pre`
suffix
4. **`make-latest` auto-compute** — by comparing against existing
non-draft non-prerelease semver releases via the GH API
5. **Atomic release create** — single `softprops/action-gh-release@v3`
call with `generate_release_notes: true`, no post-creation edits

Packagist syncs the new version via its existing webhook on tag push,
independent of this workflow.

## workflow_dispatch backfill

Also enables `workflow_dispatch` with a `tag` input, so a release entry
can be re-created for an existing tag (e.g. v2.0.0 if you ever want a
structured release entry for it) without re-tagging.

## Test plan

- [ ] PR CI passes (lint workflows, lint markdown, etc.)
- [ ] First real test: the upcoming v2.1.0 tag (separate follow-up PR
will land the CHANGELOG bump)
- [ ] Verify the release workflow fires on tag push, runs to green,
creates a GitHub Release with auto-generated notes
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants