mirror of
https://github.com/InvoiceShelf/InvoiceShelf.git
synced 2026-08-05 07:32:14 +00:00
ci: stop at the draft; publishing is a human action (#720)
2.4.3-beta.2 was cut by tag and came out correctly — published, pre-release, zip attached, notes from CHANGELOG.md — and then nothing else happened. No updater registration, no Docker images. GitHub does not start workflow runs from events created with GITHUB_TOKEN. The publish step authenticated as github-actions[bot], so `release: published` fired and triggered nothing. Every earlier docker.yaml run was event=release from a release a human published, which is why beta.1 worked and beta.2 did not. 3.x carries the same design and would have failed identically on the first RC. The workflow now stops at the draft. Everything else is unchanged: the tag still runs the tests, reads the notes, builds the package and attaches it. Pressing Publish fires the event under a real identity and the proven downstream runs as it always has — and it puts a deliberate gate in front of a release going public. prerelease and make_latest move onto the draft rather than being applied at publish time, so the flags are already right when the button is pressed; GitHub's publish dialog otherwise defaults "Set as the latest release" to checked, which would let a 3.0.0 alpha displace 2.4.x. The run now ends by writing the draft URL and the resolved flags to the job summary, since a draft nobody knows about is no use. Documents the whole flow in AGENTS.md, including why publishing is manual — the reasoning is not guessable from the workflow alone.
This commit is contained in:
committed by
GitHub
parent
1a403984fe
commit
e958cada30
40
.github/workflows/release.yaml
vendored
40
.github/workflows/release.yaml
vendored
@@ -72,26 +72,44 @@ jobs:
|
||||
# have passed and the asset is in place, so downstream registration can
|
||||
# never race the upload — and a failed run leaves no release at all rather
|
||||
# than a published one nobody can download.
|
||||
# The draft is where this workflow stops. Publishing is left to a person,
|
||||
# because a release published by the workflow would never reach docker.yaml:
|
||||
# GitHub does not start workflow runs from events created with GITHUB_TOKEN,
|
||||
# so `release: published` fires as github-actions[bot] and triggers nothing.
|
||||
# 2.4.3-beta.2 was published that way and got no registration and no images.
|
||||
# A human pressing Publish fires the event under their own identity, and the
|
||||
# existing downstream runs untouched.
|
||||
#
|
||||
# prerelease and make_latest are set here rather than at publish time, so the
|
||||
# release is already correct when that button is pressed — GitHub's publish
|
||||
# dialog otherwise defaults "Set as the latest release" to checked, which
|
||||
# would let a 3.0.0 alpha displace 2.4.x.
|
||||
- name: Create the draft release
|
||||
id: draft
|
||||
uses: softprops/action-gh-release@v3
|
||||
with:
|
||||
files: InvoiceShelf.zip
|
||||
body_path: /tmp/notes.md
|
||||
draft: true
|
||||
prerelease: ${{ contains(github.ref_name, '-') }}
|
||||
make_latest: ${{ !contains(github.ref_name, '-') && startsWith(github.ref_name, format('{0}.', env.LATEST_MAJOR)) }}
|
||||
|
||||
- name: Publish it
|
||||
# A draft nobody knows about is no use, so the run ends by saying what was
|
||||
# built and what to do with it.
|
||||
- name: Say what to do next
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
TAG: ${{ github.ref_name }}
|
||||
# GitHub's "Latest release" pointer, gated exactly as docker.yaml gates
|
||||
# its moving image tags — so a 3.0.0 alpha cannot displace 2.4.x as the
|
||||
# release users are shown first while 2.x is still the stable line.
|
||||
URL: ${{ steps.draft.outputs.url }}
|
||||
PRERELEASE: ${{ contains(github.ref_name, '-') }}
|
||||
IS_LATEST: ${{ !contains(github.ref_name, '-') && startsWith(github.ref_name, format('{0}.', env.LATEST_MAJOR)) }}
|
||||
run: |
|
||||
if [ "$IS_LATEST" = "true" ]; then
|
||||
gh release edit "$TAG" --repo "$GITHUB_REPOSITORY" --draft=false --latest
|
||||
else
|
||||
gh release edit "$TAG" --repo "$GITHUB_REPOSITORY" --draft=false --latest=false
|
||||
fi
|
||||
echo "Published $TAG (latest=$IS_LATEST)"
|
||||
{
|
||||
echo "### $TAG is drafted and ready to publish"
|
||||
echo
|
||||
echo "- Draft: $URL"
|
||||
echo "- Pre-release: \`$PRERELEASE\` — a pre-release goes to the insider channel only"
|
||||
echo "- Mark as latest: \`$IS_LATEST\`"
|
||||
echo
|
||||
echo "**Publishing it** builds the Docker images and registers it on the updater."
|
||||
echo "Nothing reaches installs until you do."
|
||||
} >> "$GITHUB_STEP_SUMMARY"
|
||||
|
||||
36
AGENTS.md
36
AGENTS.md
@@ -153,6 +153,42 @@ InvoiceShelf follows TDD development style:
|
||||
- Run `vendor/bin/pint --dirty --format agent` after modifying PHP files
|
||||
- After editing `lang/en.json` or any file under `resources/scripts/`, rebuild via `pnpm build` — the bundled chunks (including locale chunks) are content-hashed by Vite, so the browser will pick them up on hard refresh
|
||||
|
||||
## Releasing
|
||||
|
||||
Releases are cut by pushing a tag. Nothing is typed into GitHub by hand.
|
||||
|
||||
```bash
|
||||
# 1. Add a "## <version> — <date>" section to CHANGELOG.md and bump version.md,
|
||||
# in a PR like any other change — the notes are reviewed with the code.
|
||||
# 2. Once merged, tag the merge commit:
|
||||
git tag 3.0.0-alpha.2 && git push origin 3.0.0-alpha.2
|
||||
```
|
||||
|
||||
`release.yaml` then runs the tests, reads the `CHANGELOG.md` section for that tag,
|
||||
builds the package with `make clean dist`, and creates a **draft** release with the
|
||||
zip attached. It stops there and prints the draft URL in the run summary.
|
||||
|
||||
**You publish the draft yourself.** That is deliberate, not an omission: GitHub does
|
||||
not start workflow runs from events created with `GITHUB_TOKEN`, so a release
|
||||
published by the workflow reaches nothing downstream. Pressing Publish fires
|
||||
`release: published` under your own identity, which triggers `docker.yaml` to
|
||||
register the release on the updater and build the Docker images. **Until you
|
||||
publish, no install is offered anything.**
|
||||
|
||||
Notes on the mechanics:
|
||||
|
||||
- **A tag with no `CHANGELOG.md` section fails the run** before anything is built,
|
||||
so a release can never go out with empty notes.
|
||||
- **`prerelease` and "mark as latest" are set on the draft**, derived from the tag: a
|
||||
`-` suffix (`3.0.0-alpha.2`) means pre-release, which routes it to the **insider**
|
||||
channel so ordinary installs are not offered it. "Latest" is gated on
|
||||
`LATEST_MAJOR` in the workflows — bump it there when 3.x becomes the stable line.
|
||||
- **If registration fails**, re-run it without cutting a new release: run the
|
||||
`Docker Build and Push` workflow manually with `register_tag` set to the version.
|
||||
That path is idempotent and does not rebuild the Docker images.
|
||||
- `.github/scripts/changelog-section.php <version>` prints what the updater will be
|
||||
sent, so you can check the notes locally before tagging.
|
||||
|
||||
## CI Pipeline
|
||||
|
||||
GitHub Actions (`check.yaml`): runs Pint style check, then runs Pest tests in parallel (`php artisan test --parallel`) on PHP 8.4 with Xdebug disabled (`coverage: none`). The test job does **not** build the frontend — the suite is API/JSON only and never renders the Vite blade, so no Node/Vite step is needed (release/docker workflows still build assets in their own jobs).
|
||||
|
||||
Reference in New Issue
Block a user