Repository navigation
feat(release): take absence attestations per dispatch and publish each destination separately - #126
Merged
Merged
Conversation
…h destination separately Split the tag-push workflow into a candidate workflow and a dispatched publisher with one gated job per destination; remove the stored absence record and the one-off recovery workflows. Signed-off-by: Bharath Sendhurpandi <bharathasl74185@gmail.com>
Signed-off-by: Bharath Sendhurpandi <bharathasl74185@gmail.com>
…dispatches Check the attempt before approval, ignore later dispatches waiting in the concurrency group, detect draft GitHub releases, and derive the Hangar upload flag from the dispatch input. Signed-off-by: Bharath Sendhurpandi <bharathasl74185@gmail.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Adopts
N6-REL-05. The publisher no longer reads a stored absence record, and each destination publishes in its own job.release-candidate.yml(tag push) builds, smoke-tests and binds evidence for the candidate and publishes nothing. Candidate and evidence artifacts are now retained for 90 days, and the run summary prints the candidate run ID and the owner-inventory checklist.release.ymlis now aworkflow_dispatchpublisher with inputstag,candidate_run_id,destinations(defaultgithub,modrinth,hangar),modrinth_absence_confirmed,hangar_absence_confirmedandnonce(inrun-name). Every job requiresgithub.ref == refs/tags/<tag>, the tag input is checked against the release tag grammar, and the concurrency group is keyed ongithub.ref.plan(no environment, no publishing secret): candidate run provenance (release-candidate.yml, push event, head branch = tag, head SHA = tag commit on origin, success), pins the newest candidate attempt with evidence from the same attempt, stops on an expired artifact, verifies candidate and evidence, refuses true attestations beside another publisher run for the tag, rejects an attestation for an unselected destination, runs anonymous lookups per selected destination (a registry not shown complete needs its attestation), checks Modrinth project approval and the Hangar project/channel, and dry-runs the Hangar task graph.publish-github,publish-modrinth,publish-hangar: allenvironment: releaseandneeds: [plan]. Each first runsscripts/release-preflight.sh, the non-writing credential checks for every selected destination (migration flag, tokens, GitHub releases readable, Modrinth token accepted and project approved, Hangar key, target, permission bits and project permissions, task graph). Those checks deliberately do not read other destinations' version state, since another job may be mid-upload. Then each job checks its own destination with the owner token, refuses a true attestation unlessGITHUB_RUN_ATTEMPTis 1 (and re-checks overlapping runs) in the step immediately before its registry upload, uploads only if absent and verifies the consumer download. The Hangar page sync runs only when the version is the newest public version on its Hangar channel and otherwise logs the skip.scripts/release-destination.pytakes--absence-confirmed,--public-only(plan) and--credentials-only(preflight);reconciled_absence(), theinventorydestination andrelease-candidate.py reconciliationare gone. Newscripts/release-publisher.pyholds destination parsing, candidate provenance and attempt pinning, the attestation guard and the Hangar sync decision.recover-beta1.yml,recover-hangar-rc1.yml,scripts/recover-beta1.pyand its test are deleted: they were one-off recoveries, nothing else referenced them, and they read the stored record.scripts/release.shkeeps every existing guard. After pushing the tag it waits for the candidate run, prints the owner-inventory checklist, asks for each registry attestation (absentorpresent, no default, end of input aborts) and dispatches the publisher, then finds the run by its nonce.--resume <destinations> --candidate-run <id>re-dispatches for an existing tag.release.ps1stays a thin wrapper.RELEASE_PROCESS.mddocuments the two workflows, the inputs, the attestation, the plan and publish jobs, prerequisites only an upload can prove (ModrinthVERSION_CREATEscope and owner permission, registry-side metadata validation), a per-destination retry table that replaces the "Re-run failed jobs" guidance, and a table for destinations left unpublished when a candidate expires. CHANGELOG is unchanged: it records plugin changes only.After merge: delete the
RELEASE_ABSENCE_RECONCILIATIONvariable from thereleaseenvironment. On the first real dispatch, confirm that one approval releases all three publish jobs.Related Issues
Closes #125
Type of Change
Checklist
./gradlew test). Not run: no Java or Gradle source changed.python -m unittest discover -s scripts/tests -p 'test_*.py'passes (105 tests).git commit -s), per section 5 of CONTRIBUTING.md.