Documentation
¶
Overview ¶
Package release holds the pure, table-driven-testable logic that the release CI workflows depend on: the release-PR title grammar, the git-tag grammar, the typed release-kind derivation, and the final-release guard decision.
Everything here is deliberately side-effect-free so the negative paths (a malformed title, a non-release tag, a final release with no proven rc) are unit-testable BEFORE they run in a workflow. The thin CLI in cmd/release-guard wires these functions to real git/gh queries; the workflows shell out to that CLI.
Index ¶
- func CheckFinal(final Version, rcs []RCStatus) error
- func CheckReleaseWorkflow(path string, data []byte) error
- func CheckReleaseWorkflowFile(path string) error
- func IsMaintainer(perm CollaboratorPermission) bool
- func LatestApprovers(reviews []Review) []string
- func ParseReleaseTitle(title string) (Version, ReleaseKind, error)
- func ParseTag(tag string) (Version, ReleaseKind, error)
- type CollaboratorPermission
- type RCStatus
- type ReleaseKind
- type Review
- type ReviewState
- type ReviewUser
- type Version
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func CheckFinal ¶
CheckFinal decides whether a FINAL release may proceed.
A final release is permitted only if at least one same-base-version release candidate exists that is BOTH (a) green — its release.yml run succeeded — AND (b) an ancestor of the final commit. This enforces the "final ⇒ proven rc on the same commit lineage" invariant inside the pipeline rather than by convention. rc-to-final tree identity is impossible (they are different merge commits by construction), so ancestry is the strongest cheap invariant.
CheckFinal is pure: the caller supplies the observed rc statuses. It returns nil to proceed, or an actionable error naming exactly which condition failed for every candidate considered.
func CheckReleaseWorkflow ¶
CheckReleaseWorkflow validates release.yml from parsed YAML bytes.
func CheckReleaseWorkflowFile ¶
CheckReleaseWorkflowFile validates the release workflow's publication gates. It is intentionally narrow: the workflow may evolve, but the GitHub-Release publish job must stay behind the guard, the Nix vendorHash gate, and the contract gates.
func IsMaintainer ¶
func IsMaintainer(perm CollaboratorPermission) bool
IsMaintainer reports whether a collaborator permission grants release- maintainer authority (may open OR approve a release PR).
This is the SINGLE source of the maintainer predicate. Both release-pr.yml gates — the PR-author check and the approver check — consume it via `release-guard check-maintainer`, so the {admin, maintain} set is defined exactly once (no duplicated `admin|maintain` shell case across jobs).
func LatestApprovers ¶
LatestApprovers returns logins whose latest non-COMMENTED review is APPROVED. Plain comments do not withdraw or shadow a standing approval.
The "latest" review is determined by input slice order: the loop below is intentionally last-write-wins per reviewer. The release-guard caller feeds this from GitHub's pull-request reviews API, which returns reviews in ascending chronological/id order, and that order is preserved through `gh api --paginate --slurp` and parseReviews flattening. This id/input order is preferred over sorting by submitted_at because GitHub IDs are stable and order-preserving even when multiple reviews have same-second submitted_at timestamps.
func ParseReleaseTitle ¶
func ParseReleaseTitle(title string) (Version, ReleaseKind, error)
ParseReleaseTitle parses a release-PR title of the form "release(vX.Y.Z): subject" or "release(vX.Y.Z-rcN): subject" and returns the validated version and its kind.
On any grammar violation it returns (KindInvalid, error) with an actionable message describing the expected shape and a concrete example. This is the single implementation of the title grammar; the workflows must NOT re-encode it inline.
func ParseTag ¶
func ParseTag(tag string) (Version, ReleaseKind, error)
ParseTag parses a git tag as a schema release reference. It accepts ONLY bare "vX.Y.Z[-rcN]" tags; namespaced tags such as the legacy "pkg/schema/v1.2.3" (retained from when this module was nested in peasant) are rejected because they are not releases of THIS module and must never trigger the release pipeline. (The release.yml trigger filter `v*` already excludes pkg/schema/v* by name; this parse is the defense-in-depth guard inside the workflow.)
Types ¶
type CollaboratorPermission ¶
type CollaboratorPermission string
CollaboratorPermission is a GitHub repository collaborator permission level — the `.permission` field returned by the collaborators API. Typed per the repo's no-stringly-typed rule so the maintainer predicate compares against named constants, not bare strings.
const ( PermAdmin CollaboratorPermission = "admin" PermMaintain CollaboratorPermission = "maintain" PermWrite CollaboratorPermission = "write" PermTriage CollaboratorPermission = "triage" PermRead CollaboratorPermission = "read" PermNone CollaboratorPermission = "none" )
func (CollaboratorPermission) String ¶
func (p CollaboratorPermission) String() string
String renders the permission for CLI output and error messages.
type RCStatus ¶
type RCStatus struct {
// Tag is the release-candidate tag, e.g. v0.1.0-rc1.
Tag Version
// RunGreen is true when the rc tag's release.yml run completed successfully.
RunGreen bool
// IsAncestor is true when the rc tag's commit is an ancestor of the final
// release commit (the final was tagged on a descendant of the proven rc).
IsAncestor bool
}
RCStatus is the observed state of one release-candidate tag relative to a pending final release: whether its release.yml run was green, and whether the rc tag is an ancestor of the final release commit (git merge-base --is-ancestor). The CLI populates these from real git/gh queries; CheckFinal consumes them as pure data.
type ReleaseKind ¶
type ReleaseKind string
ReleaseKind classifies a release reference (a PR title or a git tag) as a release candidate, a final release, or an invalid/unrecognized reference.
It is a strongly-typed enum (per the repo's no-stringly-typed-API rule) so that workflow steps and Go callers compare against named constants rather than bare strings.
const ( // KindInvalid is returned together with an error whenever a reference does // not parse as a release. KindInvalid ReleaseKind = "invalid" // KindRC is a release candidate: a version carrying an -rcN prerelease // suffix (e.g. v0.1.0-rc1). RCs never publish to external package repos. KindRC ReleaseKind = "rc" // KindFinal is a final, non-prerelease version (e.g. v0.1.0). KindFinal ReleaseKind = "final" )
func (ReleaseKind) String ¶
func (k ReleaseKind) String() string
String renders the kind for CLI output and workflow consumption.
type Review ¶
type Review struct {
User *ReviewUser `json:"user"`
State ReviewState `json:"state"`
}
Review is the subset of a GitHub pull-request review needed by the release approval gate.
type ReviewState ¶
type ReviewState string
ReviewState is the `.state` field returned by the GitHub pull-request reviews API for a submitted review.
const ( ReviewStateApproved ReviewState = "APPROVED" ReviewStateCommented ReviewState = "COMMENTED" ReviewStateChangesRequested ReviewState = "CHANGES_REQUESTED" ReviewStateDismissed ReviewState = "DISMISSED" )
func (ReviewState) String ¶
func (s ReviewState) String() string
String renders the review state for CLI output and error messages.
type ReviewUser ¶
type ReviewUser struct {
Login string `json:"login"`
}
ReviewUser is the GitHub user shape embedded in a pull-request review.
type Version ¶
type Version string
Version is a validated schema release version, always including the leading "v" (e.g. "v0.1.0" or "v0.1.0-rc1"). Construct only via NewVersion so the invariant (matches the frozen grammar) holds everywhere a Version is seen.
func NewVersion ¶
NewVersion validates raw against the frozen release-version grammar and returns a typed Version. On failure it returns an actionable error naming the expected shape and a concrete example.
func (Version) Base ¶
Base returns the version with any -rcN suffix stripped: the final version a release candidate is a candidate FOR. For a final version Base is the identity (v0.1.0 -> v0.1.0); for an rc it strips the suffix (v0.1.0-rc3 -> v0.1.0).
func (Version) Kind ¶
func (v Version) Kind() ReleaseKind
Kind returns KindRC for prerelease (-rcN) versions and KindFinal otherwise. A Version is, by construction, never KindInvalid.