Follow-up to #244. Publishing on release is the right trigger only if releases happen — and they hadn't. Main ran 184 commits ahead of the last one, so :latest would have described a build neither the demo, nor production, nor anyone building from source was running.
What it does
Mondays 09:00 UTC, plus manual dispatch with a dry_run option.
A quiet week does nothing. No commits since the last release means no release: an empty one moves :latest to an identical build, spends a version number, and mails every watcher about nothing. Either way the decision is written to the run summary, so a skipped week reads as a decision rather than as a workflow that failed silently.
The trap this avoids
A release created with GITHUB_TOKENraises no release event. GitHub blocks token-triggered events to stop workflows looping on their own output.
So the obvious build — a scheduled job that cuts a release and lets publish.yml notice — would tag the commit and never build an image. Tag present, no image, :latest unchanged. Exactly the failure that looks like success.
publish.yml therefore gains a workflow_call trigger and this workflow calls it directly. The alternative was a PAT held as a secret; this needs no credential.
Two smaller decisions
Drafts excluded when finding the last release — an unpublished draft is not a release anybody has, and counting from it would hide commits that never shipped.
If the tag a release names has gone, the count falls back to the whole history. Over-counting cuts a release that was due anyway; under-counting skips one that wasn't.
Testing
actionlint clean, including shellcheck, on both workflows.
It can't be exercised from a branch — schedule and workflow_call only resolve on the default branch. After merge I can run it with dry_run: true, which exercises the whole decision path and stops before creating anything. I'd expect it to report nothing to release, since v2026.9.2-pr244 is current.
Follow-up to #244. Publishing on release is the right trigger **only if releases happen** — and they hadn't. Main ran 184 commits ahead of the last one, so `:latest` would have described a build neither the demo, nor production, nor anyone building from source was running.
## What it does
Mondays 09:00 UTC, plus manual dispatch with a `dry_run` option.
**A quiet week does nothing.** No commits since the last release means no release: an empty one moves `:latest` to an identical build, spends a version number, and mails every watcher about nothing. Either way the decision is written to the run summary, so a skipped week reads as a decision rather than as a workflow that failed silently.
## The trap this avoids
A release created with `GITHUB_TOKEN` **raises no `release` event.** GitHub blocks token-triggered events to stop workflows looping on their own output.
So the obvious build — a scheduled job that cuts a release and lets `publish.yml` notice — would tag the commit and never build an image. Tag present, no image, `:latest` unchanged. Exactly the failure that looks like success.
`publish.yml` therefore gains a `workflow_call` trigger and this workflow calls it directly. The alternative was a PAT held as a secret; this needs no credential.
## Two smaller decisions
- **Drafts excluded** when finding the last release — an unpublished draft is not a release anybody has, and counting from it would hide commits that never shipped.
- **If the tag a release names has gone**, the count falls back to the whole history. Over-counting cuts a release that was due anyway; under-counting skips one that wasn't.
## Testing
`actionlint` clean, including shellcheck, on both workflows.
It can't be exercised from a branch — `schedule` and `workflow_call` only resolve on the default branch. After merge I can run it with `dry_run: true`, which exercises the whole decision path and stops before creating anything. I'd expect it to report **nothing to release**, since `v2026.9.2-pr244` is current.
**Merged** 2026-09-02 as coffey-labs/ihasmail@60a4647a43b8
<sub>Rebuilt from: git history, session transcript.</sub>
This repo is archived. You cannot comment on issues.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Follow-up to #244. Publishing on release is the right trigger only if releases happen — and they hadn't. Main ran 184 commits ahead of the last one, so
:latestwould have described a build neither the demo, nor production, nor anyone building from source was running.What it does
Mondays 09:00 UTC, plus manual dispatch with a
dry_runoption.A quiet week does nothing. No commits since the last release means no release: an empty one moves
:latestto an identical build, spends a version number, and mails every watcher about nothing. Either way the decision is written to the run summary, so a skipped week reads as a decision rather than as a workflow that failed silently.The trap this avoids
A release created with
GITHUB_TOKENraises noreleaseevent. GitHub blocks token-triggered events to stop workflows looping on their own output.So the obvious build — a scheduled job that cuts a release and lets
publish.ymlnotice — would tag the commit and never build an image. Tag present, no image,:latestunchanged. Exactly the failure that looks like success.publish.ymltherefore gains aworkflow_calltrigger and this workflow calls it directly. The alternative was a PAT held as a secret; this needs no credential.Two smaller decisions
Testing
actionlintclean, including shellcheck, on both workflows.It can't be exercised from a branch —
scheduleandworkflow_callonly resolve on the default branch. After merge I can run it withdry_run: true, which exercises the whole decision path and stops before creating anything. I'd expect it to report nothing to release, sincev2026.9.2-pr244is current.Merged 2026-09-02 as coffey-labs/ihasmail@60a4647a43
Rebuilt from: git history, session transcript.