Simplify local release validation and publication
This commit is contained in:
@@ -90,8 +90,10 @@ Use focused checks while iterating, with validation proportionate to the change
|
|||||||
under the testing policy. Documentation-only work normally needs the local-link
|
under the testing policy. Documentation-only work normally needs the local-link
|
||||||
check below and whitespace review; behavior-bearing examples and commands also
|
check below and whitespace review; behavior-bearing examples and commands also
|
||||||
need execution. Use `go test -race ./...` for ownership or concurrency changes.
|
need execution. Use `go test -race ./...` for ownership or concurrency changes.
|
||||||
The separate [release checker](release.md#4-validate-the-source-candidate) adds
|
The [release checker](release.md#4-validate-the-source-candidate) performs one
|
||||||
two-toolchain, module-hygiene, race, and cross-build gates.
|
minimum-toolchain race-suite run, vet, module hygiene, and Linux cross-builds.
|
||||||
|
It already covers examples, links, and package boundaries; do not additionally
|
||||||
|
run the everyday checker just to repeat those checks. CI never gates a release.
|
||||||
|
|
||||||
## Task-to-test map
|
## Task-to-test map
|
||||||
|
|
||||||
|
|||||||
@@ -21,7 +21,8 @@ ConfigKit adopts a source-only Go module release model. The source tag and
|
|||||||
version-matched release note are the declared deliverables. Standalone binaries,
|
version-matched release note are the declared deliverables. Standalone binaries,
|
||||||
container images, and separate binary/package-registry publication are not
|
container images, and separate binary/package-registry publication are not
|
||||||
required. This does not waive source compilation, module hygiene, testing, or
|
required. This does not waive source compilation, module hygiene, testing, or
|
||||||
consumer-facing module retrieval and build verification.
|
local target-build validation. Post-publication consumer retrieval is optional,
|
||||||
|
as documented under Policy Exceptions.
|
||||||
|
|
||||||
The release procedure must define the module path, authoritative remote,
|
The release procedure must define the module path, authoritative remote,
|
||||||
supported Go versions and operating-system/architecture targets, prerequisite
|
supported Go versions and operating-system/architecture targets, prerequisite
|
||||||
@@ -74,6 +75,10 @@ responsibility is documented. Automation must not silently change the source
|
|||||||
candidate, move a published tag, replace a published deliverable, or repair a
|
candidate, move a published tag, replace a published deliverable, or repair a
|
||||||
release in place.
|
release in place.
|
||||||
|
|
||||||
|
A successful push of the intended annotated tag completes the source-only release.
|
||||||
|
Never wait for CI or use its status as a readiness or completion gate. Optional
|
||||||
|
post-publication checks must not delay reporting success.
|
||||||
|
|
||||||
## Versioning And Compatibility
|
## Versioning And Compatibility
|
||||||
|
|
||||||
Stable releases use Semantic Versioning in the form `vMAJOR.MINOR.PATCH`, with
|
Stable releases use Semantic Versioning in the form `vMAJOR.MINOR.PATCH`, with
|
||||||
@@ -132,38 +137,28 @@ current documentation or defer required documentation changes.
|
|||||||
|
|
||||||
## Candidate Preparation And Validation
|
## Candidate Preparation And Validation
|
||||||
|
|
||||||
Each repository must provide one documented release-check command or script
|
ConfigKit provides one local release checker. Run it once against the final
|
||||||
that exercises the complete set of automated source-candidate gates. The
|
committed candidate using one maintained patch of the minimum supported Go line
|
||||||
repository-specific procedure must state all additional manual gates.
|
on Linux. It checks module hygiene, formatting and whitespace, the full offline
|
||||||
|
suite with the race detector, static analysis, and CGO-disabled Linux amd64/arm64
|
||||||
|
builds. Examples, documentation links, consumer fixtures, and package boundaries
|
||||||
|
are covered by that suite, not separate repeated runs. Native package compilation
|
||||||
|
is covered by the test run. A second toolchain is optional and non-gating.
|
||||||
|
|
||||||
The required gates are:
|
Commit the release note and associated changes before release validation. Record
|
||||||
|
the exact validated commit; revalidate if the candidate changes. Do not require
|
||||||
|
both pre-commit and post-commit full checker runs for unchanged content.
|
||||||
|
Do not publish uncommitted or unvalidated content. Local check failures still
|
||||||
|
block publication. Skipped test cases are reported, not separate human sign-off
|
||||||
|
requirements.
|
||||||
|
|
||||||
- dependency or module hygiene appropriate to the language and ecosystem;
|
Compatibility review, release-note accuracy, removal of completed roadmaps, and
|
||||||
- the complete deterministic, offline default test suite;
|
review for unintended files, credentials, private data, and unrelated changes
|
||||||
- race, concurrency, or equivalent safety checks where the implementation can
|
are ordinary preparation. The executing agent may perform them without routine
|
||||||
be meaningfully checked for those risks;
|
human approval or separate manual evidence records. Ask the maintainer only for
|
||||||
- static analysis and linting used by the repository;
|
genuine unresolved decisions or missing authority. A clean existing checkout is
|
||||||
- production builds for every supported target that can be built in the
|
sufficient; a dedicated clone is optional. Dependency and toolchain update
|
||||||
release environment;
|
research belongs to maintenance or relevant changes, not every release.
|
||||||
- formatting and whitespace checks;
|
|
||||||
- validation of maintained examples, configuration, schemas, generated
|
|
||||||
sources, and documentation commands where applicable;
|
|
||||||
- review of changed local documentation links;
|
|
||||||
- removal of obsolete roadmap documents under `docs/roadmap/` that describe
|
|
||||||
completed work included in the release;
|
|
||||||
- review for unintended files, generated output, credentials, private data,
|
|
||||||
and unrelated changes; and
|
|
||||||
- any additional security, compatibility, migration, packaging, or platform
|
|
||||||
checks required by the product.
|
|
||||||
|
|
||||||
Unavailable tooling or an inapplicable check must be addressed explicitly in
|
|
||||||
the adopted policy or release procedure; it must not disappear silently from
|
|
||||||
the candidate gates.
|
|
||||||
|
|
||||||
Run the complete checker while preparing the candidate. Commit the release
|
|
||||||
note and all associated code, tests, documentation, and configuration, then
|
|
||||||
run the complete checker again against the exact commit intended for release.
|
|
||||||
Do not publish a release from uncommitted or unvalidated content.
|
|
||||||
|
|
||||||
## Publication Guards
|
## Publication Guards
|
||||||
|
|
||||||
@@ -178,7 +173,8 @@ verify all of the following:
|
|||||||
- the authoritative remote branch points to that same commit;
|
- the authoritative remote branch points to that same commit;
|
||||||
- the matching release note exists in that commit and has the required title
|
- the matching release note exists in that commit and has the required title
|
||||||
and sections;
|
and sections;
|
||||||
- all required approvals and automated gates succeeded for that commit; and
|
- release publication is authorized and the local automated gates succeeded for
|
||||||
|
that commit; and
|
||||||
- no local or remote tag already uses the selected version.
|
- no local or remote tag already uses the selected version.
|
||||||
|
|
||||||
Create the version tag against the guarded commit and verify its target before
|
Create the version tag against the guarded commit and verify its target before
|
||||||
@@ -219,17 +215,17 @@ order:
|
|||||||
1. maintainer prerequisites and required access;
|
1. maintainer prerequisites and required access;
|
||||||
2. version selection and compatibility review;
|
2. version selection and compatibility review;
|
||||||
3. release-note creation;
|
3. release-note creation;
|
||||||
4. candidate preparation and the complete validation command;
|
4. candidate preparation and commit;
|
||||||
5. candidate commit, push, and exact commit recording;
|
5. one local validation pass, exact candidate recording, and push;
|
||||||
6. publication guards;
|
6. publication guards;
|
||||||
7. exact tag and deliverable publication commands;
|
7. exact tag and deliverable publication commands;
|
||||||
8. authoritative remote and consumer-facing verification; and
|
8. completion on successful tag push and optional post-publication checks; and
|
||||||
9. failure handling and correction.
|
9. failure handling and correction.
|
||||||
|
|
||||||
The procedure should use copyable, fail-fast commands where practical. It must
|
The procedure should use copyable, fail-fast commands where practical. It must
|
||||||
name the primary branch, authoritative remote, tag form, published
|
name the primary branch, authoritative remote, tag form, published
|
||||||
deliverables, supported build targets, release automation responsibilities,
|
deliverables, supported build targets, release automation responsibilities,
|
||||||
and consumer verification path. It must link to this policy instead of
|
and optional consumer verification path. It must link to this policy instead of
|
||||||
restating or redefining its requirements.
|
restating or redefining its requirements.
|
||||||
|
|
||||||
## Policy Exceptions
|
## Policy Exceptions
|
||||||
@@ -240,6 +236,15 @@ compensating controls. Customizing release mechanics must not silently weaken
|
|||||||
the policy's integrity, validation, documentation, verification, or immutability
|
the policy's integrity, validation, documentation, verification, or immutability
|
||||||
requirements.
|
requirements.
|
||||||
|
|
||||||
|
For ConfigKit's source-only releases, the maintainer accepts successful publication
|
||||||
|
of the intended tag as sufficient completion evidence. This is an explicit
|
||||||
|
exception to the shared standard's mandatory post-publication verification:
|
||||||
|
authoritative tag read-back and fresh consumer retrieval are optional and
|
||||||
|
non-gating. CI status and downstream retrieval availability must not delay release
|
||||||
|
completion. Compensating controls are local validation of the exact candidate,
|
||||||
|
automated pre-publication guards, matching remote main, verification of the local
|
||||||
|
annotated tag target, explicit ref pushes, and immutable published versions.
|
||||||
|
|
||||||
For v0.1.1 only, the maintainer approved renaming the reserved `_configkit` key to
|
For v0.1.1 only, the maintainer approved renaming the reserved `_configkit` key to
|
||||||
`configkit` as an error-correcting point release because there are no current
|
`configkit` as an error-correcting point release because there are no current
|
||||||
consumers. This intentionally changes the v0.1.0 configuration contract without a
|
consumers. This intentionally changes the v0.1.0 configuration contract without a
|
||||||
@@ -253,5 +258,5 @@ only. The final candidate still requires the complete Linux release checker.
|
|||||||
This exception waives only repeating the macOS check after those documentation
|
This exception waives only repeating the macOS check after those documentation
|
||||||
changes; it does not waive other publication or verification gates.
|
changes; it does not waive other publication or verification gates.
|
||||||
|
|
||||||
Candidate selection, publication, and post-publication verification remain
|
Candidate selection and guarded publication remain mandatory; post-publication
|
||||||
mandatory steps in the [release procedure](../release.md).
|
verification is optional in the [release procedure](../release.md).
|
||||||
|
|||||||
173
docs/release.md
173
docs/release.md
@@ -12,21 +12,24 @@ binary, container image, generated package, or separate registry publication.
|
|||||||
- Authoritative remote: `origin`, expected to fetch from
|
- Authoritative remote: `origin`, expected to fetch from
|
||||||
`https://gitea.maximumdirect.net/eric/ConfigKit.git`
|
`https://gitea.maximumdirect.net/eric/ConfigKit.git`
|
||||||
- Tags: stable Semantic Versions such as `v0.1.0`; prerelease tags are not supported
|
- Tags: stable Semantic Versions such as `v0.1.0`; prerelease tags are not supported
|
||||||
- Minimum Go language/toolchain line: Go 1.25, tested with a supported patched
|
- Minimum Go language/toolchain line: Go 1.25, release-validated with one maintained
|
||||||
Go 1.25 toolchain and one newer supported toolchain
|
patch of that line; newer-toolchain testing is optional and non-gating
|
||||||
- Release-gated build targets: Linux on amd64 and arm64
|
- Release-gated build targets: Linux on amd64 and arm64
|
||||||
- Best-effort targets: macOS on amd64 and arm64, under the
|
- Best-effort targets: macOS on amd64 and arm64, under the
|
||||||
[platform support policy](policy/release.md#platform-support)
|
[platform support policy](policy/release.md#platform-support)
|
||||||
|
|
||||||
The automated checker cross-builds the Linux targets. Before release, the maintainer
|
The local Linux checker includes native race tests and CGO-disabled cross-builds.
|
||||||
must also obtain native test, race, symlink, and permission-fixture evidence on Linux;
|
Its output reports skipped filesystem cases; no separate evidence record or
|
||||||
cross-compilation is not native execution evidence. Native macOS checks and Darwin
|
human sign-off is required. Native macOS checks and Darwin cross-builds are
|
||||||
cross-builds are optional and do not gate publication.
|
optional and do not gate publication.
|
||||||
|
|
||||||
|
CI is never a release gate. Do not wait for it, poll its status, or delay reporting
|
||||||
|
completion because it is pending, unavailable, or failed.
|
||||||
|
|
||||||
## 1. Prepare access and tools
|
## 1. Prepare access and tools
|
||||||
|
|
||||||
The release maintainer owns this procedure. Work in a dedicated clone with Git, Bash 3.2 or newer,
|
The release maintainer owns this procedure. Use a clean checkout (a dedicated clone is optional) with Git, Bash 3.2 or newer,
|
||||||
and two supported Go toolchains available. The checker supports the stock macOS
|
a maintained Go 1.25 patch, and the compiler needed for native race tests. The checker supports the stock macOS
|
||||||
Bash; its filename enumeration is null-delimited, including names with whitespace. Configure private-host Git and Go module
|
Bash; its filename enumeration is null-delimited, including names with whitespace. Configure private-host Git and Go module
|
||||||
access through the normal credential manager before starting. Keep tokens, passwords,
|
access through the normal credential manager before starting. Keep tokens, passwords,
|
||||||
SSH material, and environment dumps outside the repository and command transcript.
|
SSH material, and environment dumps outside the repository and command transcript.
|
||||||
@@ -37,23 +40,24 @@ git remote get-url origin
|
|||||||
git ls-remote origin HEAD
|
git ls-remote origin HEAD
|
||||||
```
|
```
|
||||||
|
|
||||||
The remote URL must equal the authoritative URL above. Select the latest supported
|
The remote URL must equal the authoritative URL above. Acquire the selected
|
||||||
patch in the Go 1.25 line and a newer supported toolchain. The values below are the
|
toolchain and dependencies explicitly. For example, with the maintained patch
|
||||||
toolchains used while this runbook was introduced; update them to supported patch
|
used when this procedure was simplified:
|
||||||
releases during candidate preparation and record the actual versions in the release
|
|
||||||
note or validation record.
|
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
export CONFIGKIT_BASELINE_TOOLCHAIN=go1.25.5
|
export CONFIGKIT_BASELINE_TOOLCHAIN=go1.25.14
|
||||||
export CONFIGKIT_NEWER_TOOLCHAIN=go1.26.7
|
|
||||||
GOTOOLCHAIN="$CONFIGKIT_BASELINE_TOOLCHAIN" go version
|
GOTOOLCHAIN="$CONFIGKIT_BASELINE_TOOLCHAIN" go version
|
||||||
GOTOOLCHAIN="$CONFIGKIT_NEWER_TOOLCHAIN" go version
|
|
||||||
GOTOOLCHAIN="$CONFIGKIT_BASELINE_TOOLCHAIN" go mod download
|
GOTOOLCHAIN="$CONFIGKIT_BASELINE_TOOLCHAIN" go mod download
|
||||||
GOTOOLCHAIN="$CONFIGKIT_NEWER_TOOLCHAIN" go mod download
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Those commands explicitly acquire toolchains and dependencies. The checker itself
|
Keep toolchains maintained, but do not require latest-version discovery for each
|
||||||
sets `GOPROXY=off` and fails if its required cache is incomplete.
|
release. The checker sets `GOPROXY=off` and fails if the cache is incomplete.
|
||||||
|
Toolchain and YAML-dependency update research belongs to periodic maintenance or
|
||||||
|
relevant dependency changes. No renewed approval of an unchanged pin is required.
|
||||||
|
|
||||||
|
Use Bash with `set -euo pipefail` for the command blocks below so any failed gate
|
||||||
|
stops the sequence. Publication requires user authorization; the agent policy's
|
||||||
|
local-commit authorization is not permission to push or release.
|
||||||
|
|
||||||
## 2. Select the version and review compatibility
|
## 2. Select the version and review compatibility
|
||||||
|
|
||||||
@@ -63,7 +67,7 @@ For the first release, review the whole public surface and current contracts.
|
|||||||
```sh
|
```sh
|
||||||
release_version=v0.1.0
|
release_version=v0.1.0
|
||||||
printf '%s\n' "$release_version" | grep -Eq '^v(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)$'
|
printf '%s\n' "$release_version" | grep -Eq '^v(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)$'
|
||||||
git show-ref --verify --quiet "refs/tags/$release_version" && exit 1 || :
|
if git show-ref --verify --quiet "refs/tags/$release_version"; then exit 1; fi
|
||||||
if git ls-remote --exit-code --tags origin "refs/tags/$release_version" >/dev/null; then
|
if git ls-remote --exit-code --tags origin "refs/tags/$release_version" >/dev/null; then
|
||||||
printf 'remote tag already exists: %s\n' "$release_version" >&2
|
printf 'remote tag already exists: %s\n' "$release_version" >&2
|
||||||
exit 1
|
exit 1
|
||||||
@@ -79,16 +83,9 @@ intentional incompatible minor-release change must be explained with consumer ac
|
|||||||
patch releases must remain compatible within their minor line. Review the maintained
|
patch releases must remain compatible within their minor line. Review the maintained
|
||||||
consumer examples and the migration guide even when signatures did not change.
|
consumer examples and the migration guide even when signatures did not change.
|
||||||
|
|
||||||
Reassess `go.yaml.in/yaml/v4` rather than using `@latest` implicitly:
|
When dependencies change, review parser behavior and migration impact as part of
|
||||||
|
that change. Keep Compatibility accurate about the dependency pin, but do not
|
||||||
```sh
|
perform an external version survey for every patch release.
|
||||||
go list -m -versions go.yaml.in/yaml/v4
|
|
||||||
go list -m -json go.yaml.in/yaml/v4@latest
|
|
||||||
```
|
|
||||||
|
|
||||||
If changing the explicit pin, make that a reviewed dependency change and rerun the
|
|
||||||
complete checker, especially parser policy, limits, diagnostics, and rendering tests.
|
|
||||||
If retaining a prerelease pin, record that decision in Compatibility.
|
|
||||||
|
|
||||||
## 3. Write the release note
|
## 3. Write the release note
|
||||||
|
|
||||||
@@ -100,55 +97,46 @@ release note until there is a real candidate and reviewed content.
|
|||||||
|
|
||||||
## 4. Validate the source candidate
|
## 4. Validate the source candidate
|
||||||
|
|
||||||
Run the complete checker on Linux from the repository root after dependencies have been
|
Before release validation, finish compatibility review, inspect the diff and file
|
||||||
acquired. It validates module manifests in a disposable copy, both supported Go
|
list for unintended content or credentials, retire completed roadmaps, repair
|
||||||
toolchains, offline default tests, the native race detector, vet, native builds,
|
links, and review the release note. These are ordinary preparation tasks the
|
||||||
CGO-disabled Linux cross-builds, formatting and whitespace (including untracked files),
|
executing agent may perform, not separate human approvals or evidence records.
|
||||||
examples, package isolation, and local documentation links.
|
Ask the maintainer only for an unresolved product decision or missing authority.
|
||||||
|
|
||||||
|
Commit the candidate, staging only its intended changes, then run the checker
|
||||||
|
once against that clean commit. Do not run both everyday and release checkers to
|
||||||
|
repeat the same gates.
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
./scripts/release-check.sh
|
git status --short
|
||||||
```
|
# Stage the specific files belonging to the candidate, then review:
|
||||||
|
git diff --staged
|
||||||
`go vet` is the repository's static-analysis baseline. No additional linter is
|
|
||||||
claimed. Links to current ConfigKit files and headings are strict. Recorded links to
|
|
||||||
sibling consumer source are checked when those checkouts exist and are otherwise
|
|
||||||
inapplicable in an isolated clone; their immutable revisions remain recorded in the
|
|
||||||
extraction inventory.
|
|
||||||
|
|
||||||
Complete these manual gates and record their evidence with the candidate:
|
|
||||||
|
|
||||||
- The maintainer reviews compatibility and downstream migration impact against
|
|
||||||
`docs/config.md`, Go API comments, and the consumer guide.
|
|
||||||
- The maintainer inspects `git status --short`, `git diff`, and the candidate file
|
|
||||||
list for credentials, private data, generated output, unintended files, and
|
|
||||||
unrelated changes.
|
|
||||||
- The maintainer records a successful native checker run on Linux, including
|
|
||||||
filesystem capability tests. Missing required Linux evidence blocks release;
|
|
||||||
no macOS run, sign-off, or cross-build result is required.
|
|
||||||
- The maintainer removes completed, obsolete documents under `docs/roadmap/`, repairs
|
|
||||||
inbound links, and reruns the checker. ADR rationale remains historical.
|
|
||||||
- The maintainer reviews the exact version-matched release note for accuracy and
|
|
||||||
confirms it describes only deliverables that will actually be published.
|
|
||||||
|
|
||||||
## 5. Commit, push, and record the candidate
|
|
||||||
|
|
||||||
Commit all candidate source, contract, example, roadmap-retirement, and release-note
|
|
||||||
changes, rerun the checker against that clean commit, then push only `main` and record
|
|
||||||
the exact commit in Git metadata local to the clone:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
git add .
|
|
||||||
git commit --message "Prepare ConfigKit $release_version"
|
git commit --message "Prepare ConfigKit $release_version"
|
||||||
./scripts/release-check.sh
|
|
||||||
test -z "$(git status --porcelain=v1 --untracked-files=all)"
|
test -z "$(git status --porcelain=v1 --untracked-files=all)"
|
||||||
git push origin HEAD:refs/heads/main
|
candidate_commit=$(git rev-parse HEAD)
|
||||||
git rev-parse HEAD | tee .git/configkit-release-candidate
|
./scripts/release-check.sh
|
||||||
candidate_commit=$(cat .git/configkit-release-candidate)
|
test "$(git rev-parse HEAD)" = "$candidate_commit"
|
||||||
|
test -z "$(git status --porcelain=v1 --untracked-files=all)"
|
||||||
|
printf '%s\n' "$candidate_commit" > "$(git rev-parse --git-path configkit-release-candidate)"
|
||||||
```
|
```
|
||||||
|
|
||||||
If review changes the source after this point, create and validate a new candidate;
|
If the final candidate is already committed, omit the staging and commit commands;
|
||||||
do not reuse the recorded commit.
|
do not create an empty commit. The checker validates module manifests in a
|
||||||
|
disposable copy, formatting, whitespace, the full offline suite once with the race
|
||||||
|
detector and verbose skip reporting, vet once, and CGO-disabled Linux amd64/arm64
|
||||||
|
builds. The suite includes examples, consumer fixtures, documentation links, and
|
||||||
|
package boundaries; no separate reruns are required. No additional linter is
|
||||||
|
claimed. Sibling-consumer links are checked when those checkouts exist and are
|
||||||
|
otherwise inapplicable in an isolated checkout.
|
||||||
|
|
||||||
|
A changed candidate requires validation again. Do not reuse a recorded candidate
|
||||||
|
from an older revision. The record is written only after successful local checks.
|
||||||
|
|
||||||
|
## 5. Prepare publication
|
||||||
|
|
||||||
|
The following guarded sequence pushes only `main` and the selected tag. Local
|
||||||
|
validation failures block it; CI does not. Keep the selected `release_version`
|
||||||
|
from step 2 in the same shell. If starting a new shell, set it explicitly again.
|
||||||
|
|
||||||
## 6. Run publication guards
|
## 6. Run publication guards
|
||||||
|
|
||||||
@@ -156,14 +144,12 @@ Immediately before tagging, fetch the authoritative branch and tags, restore the
|
|||||||
recorded variables if this is a new shell, and execute every guard:
|
recorded variables if this is a new shell, and execute every guard:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
release_version=v0.1.0
|
candidate_commit=$(cat "$(git rev-parse --git-path configkit-release-candidate)")
|
||||||
candidate_commit=$(cat .git/configkit-release-candidate)
|
|
||||||
git fetch --prune origin main
|
git fetch --prune origin main
|
||||||
git fetch --tags origin
|
git fetch --tags origin
|
||||||
test "$(git branch --show-current)" = main
|
test "$(git branch --show-current)" = main
|
||||||
test -z "$(git status --porcelain=v1 --untracked-files=all)"
|
test -z "$(git status --porcelain=v1 --untracked-files=all)"
|
||||||
test "$(git rev-parse HEAD)" = "$candidate_commit"
|
test "$(git rev-parse HEAD)" = "$candidate_commit"
|
||||||
test "$(git rev-parse refs/remotes/origin/main)" = "$candidate_commit"
|
|
||||||
test "$(git remote get-url origin)" = 'https://gitea.maximumdirect.net/eric/ConfigKit.git'
|
test "$(git remote get-url origin)" = 'https://gitea.maximumdirect.net/eric/ConfigKit.git'
|
||||||
printf '%s\n' "$release_version" | grep -Eq '^v(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)$'
|
printf '%s\n' "$release_version" | grep -Eq '^v(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)$'
|
||||||
test -f "docs/releases/$release_version.md"
|
test -f "docs/releases/$release_version.md"
|
||||||
@@ -171,17 +157,22 @@ test "$(sed -n '1p' "docs/releases/$release_version.md")" = "# ConfigKit $releas
|
|||||||
for heading in Summary Compatibility Upgrade Changes; do
|
for heading in Summary Compatibility Upgrade Changes; do
|
||||||
grep -Fxq "## $heading" "docs/releases/$release_version.md"
|
grep -Fxq "## $heading" "docs/releases/$release_version.md"
|
||||||
done
|
done
|
||||||
git show-ref --verify --quiet "refs/tags/$release_version" && exit 1 || :
|
if git show-ref --verify --quiet "refs/tags/$release_version"; then exit 1; fi
|
||||||
if git ls-remote --exit-code --tags origin "refs/tags/$release_version" >/dev/null; then
|
if git ls-remote --exit-code --tags origin "refs/tags/$release_version" >/dev/null; then
|
||||||
printf 'remote tag already exists: %s\n' "$release_version" >&2
|
printf 'remote tag already exists: %s\n' "$release_version" >&2
|
||||||
exit 1
|
exit 1
|
||||||
else
|
else
|
||||||
test $? -eq 2
|
test $? -eq 2
|
||||||
fi
|
fi
|
||||||
|
git push origin HEAD:refs/heads/main
|
||||||
|
git fetch origin main
|
||||||
|
test "$(git rev-parse refs/remotes/origin/main)" = "$candidate_commit"
|
||||||
|
test "$(git rev-parse HEAD)" = "$candidate_commit"
|
||||||
|
test -z "$(git status --porcelain=v1 --untracked-files=all)"
|
||||||
```
|
```
|
||||||
|
|
||||||
Confirm the recorded automated and manual approvals apply to exactly
|
The recorded local validation must apply to exactly `$candidate_commit`. No
|
||||||
`$candidate_commit`. A successful older run is not evidence for a changed commit.
|
separate human sign-off, CI status, or manual evidence document is required.
|
||||||
|
|
||||||
## 7. Tag and publish the exact ref
|
## 7. Tag and publish the exact ref
|
||||||
|
|
||||||
@@ -194,15 +185,17 @@ test "$(git rev-list -n 1 "$release_version")" = "$candidate_commit"
|
|||||||
git push origin "refs/tags/$release_version:refs/tags/$release_version"
|
git push origin "refs/tags/$release_version:refs/tags/$release_version"
|
||||||
```
|
```
|
||||||
|
|
||||||
The pushed tag completes the declared source-only publication. No Gitea release
|
A successful push of the intended tag completes the release. Report success now;
|
||||||
object or binary upload is required.
|
do not wait for CI, module propagation, or any post-publication check. No Gitea
|
||||||
|
release object or binary upload is required.
|
||||||
|
|
||||||
## 8. Verify publication and clean consumer retrieval
|
## 8. Optional post-publication checks
|
||||||
|
|
||||||
Verify the authoritative tag and then retrieve that exact version into a new module
|
Only when useful or requested, read back the remote tag or retrieve the exact
|
||||||
without a local `replace` directive. Private-host credentials must already be
|
version into a new module without a local `replace` directive. These checks are
|
||||||
configured. Use direct origin retrieval unless an explicitly approved internal Go
|
optional and non-gating; their failure or unavailability does not delay release
|
||||||
proxy is the publication channel.
|
completion. Do not poll CI or wait for module propagation. Private-host credentials
|
||||||
|
must already be configured. Example direct-origin verification:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
remote_tag_commit=$(git ls-remote origin "refs/tags/$release_version^{}" | awk '{print $1}')
|
remote_tag_commit=$(git ls-remote origin "refs/tags/$release_version^{}" | awk '{print $1}')
|
||||||
@@ -229,13 +222,13 @@ EOF
|
|||||||
rm -rf -- "$consumer_dir"
|
rm -rf -- "$consumer_dir"
|
||||||
```
|
```
|
||||||
|
|
||||||
The final `go list` output must show the exact module path and `$release_version`.
|
If performed, the final `go list` output should show the exact module path and
|
||||||
Record the result with the release evidence.
|
`$release_version`. Report optional verification separately from publication success.
|
||||||
|
|
||||||
## 9. Handle failures without replacement
|
## 9. Handle failures without replacement
|
||||||
|
|
||||||
Before publication, fix the candidate, rerun every gate, commit, push, and record a
|
Before publication, fix and commit the candidate, validate it, record the new
|
||||||
new exact candidate. An unpublished local tag may be deleted only after verifying it
|
exact candidate, and repeat the guarded publication sequence. An unpublished local tag may be deleted only after verifying it
|
||||||
was never pushed or used by another release channel.
|
was never pushed or used by another release channel.
|
||||||
|
|
||||||
After publication, never move, delete, or recreate the tag and never replace its
|
After publication, never move, delete, or recreate the tag and never replace its
|
||||||
|
|||||||
@@ -1,139 +1,26 @@
|
|||||||
# Release Workflow Simplification
|
# Release Workflow Simplification
|
||||||
|
|
||||||
Status: approved target, not yet implemented.
|
Status: implemented; retain this completion record until release preparation.
|
||||||
|
|
||||||
## Intent and scope
|
## Outcome
|
||||||
|
|
||||||
ConfigKit should have the minimum release gates reasonably needed for a small
|
The maintainer-approved simplification is implemented in the
|
||||||
source-only Go library. Favor inexpensive local automation over repeated checks
|
[release policy](../policy/release.md), [procedure](../release.md), and
|
||||||
and human intervention. A successful push of the intended release tag completes
|
[checker](../../scripts/release-check.sh). Those documents own current requirements.
|
||||||
the release; CI reliability and timing must never determine release readiness
|
|
||||||
or completion.
|
|
||||||
|
|
||||||
This roadmap records the maintainer-approved outcome of the release-gate audit.
|
The workflow uses one minimum-toolchain local race-suite run, vet, module hygiene,
|
||||||
It does not itself update the [release policy](../policy/release.md),
|
formatting/whitespace, and Linux cross-builds. Redundant suite/subset runs and
|
||||||
[procedure](../release.md), or [checker](../../scripts/release-check.sh).
|
routine human sign-offs have been removed. CI never gates publication or
|
||||||
Those owners must be brought into agreement when this work is implemented.
|
completion; a successful push of the intended tag completes the release.
|
||||||
There are no library API, configuration, or runtime behavior changes in scope.
|
Post-publication verification is optional under the explicit policy exception.
|
||||||
|
|
||||||
## Target release workflow
|
The [check-script and runbook tests](../../release_check_test.go) cover the
|
||||||
|
reduced command set, failure handling, and publication guards using disposable
|
||||||
|
local repositories. Implementation does not authorize an actual release.
|
||||||
|
|
||||||
1. Prepare the version-matched release note, review the changes, retire completed
|
## Scope
|
||||||
roadmap material where applicable, and commit the final candidate.
|
|
||||||
2. Validate that committed candidate with one local release-check invocation.
|
|
||||||
3. Run automated publication guards for the clean checkout, candidate identity,
|
|
||||||
primary branch, authoritative remote, release-note structure, and unused version.
|
|
||||||
4. Push the candidate to `main`, verify the remote branch matches the candidate,
|
|
||||||
create the annotated tag at that exact commit, and push only that tag ref.
|
|
||||||
5. Report the release complete as soon as the intended tag push succeeds.
|
|
||||||
|
|
||||||
The candidate must remain the exact validated commit through publication. A
|
No library API, configuration, or runtime behavior changes were made. Published
|
||||||
changed candidate requires validation again, but there is no mandatory pair of
|
tag immutability, release notes, compatibility rules, and exact-candidate
|
||||||
full runs before and after committing unchanged content. A clean existing
|
publication safeguards remain in place. There is no remaining implementation
|
||||||
checkout is sufficient; a dedicated clone is optional.
|
work or unresolved product decision for this roadmap.
|
||||||
|
|
||||||
Retain immutable published tags, version selection and compatibility rules,
|
|
||||||
version-matched release notes, and explicit push targets. Do not add a separate
|
|
||||||
Gitea release object, binary upload, or other deliverable to this source-only model.
|
|
||||||
|
|
||||||
## Local automated gates
|
|
||||||
|
|
||||||
Use one maintained patch of the minimum supported Go toolchain line (currently
|
|
||||||
Go 1.25) in a local Linux environment. Toolchains and dependencies are acquired
|
|
||||||
explicitly; the checker remains offline. Toolchain maintenance is not a mandatory
|
|
||||||
latest-version lookup on every release.
|
|
||||||
|
|
||||||
| Check | Target treatment and reason |
|
|
||||||
| --- | --- |
|
|
||||||
| Full default test suite | Run once with `go test -race ./...`; preserve race coverage for shared-state isolation without a separate ordinary full-suite run. |
|
|
||||||
| Static analysis | Run `go vet ./...` once; it covers more than the default vet subset run by `go test`. |
|
|
||||||
| Module hygiene | Retain the disposable-copy tidy comparison without changing candidate manifests. |
|
|
||||||
| Formatting and whitespace | Retain inexpensive local checks. |
|
|
||||||
| Linux amd64/arm64 builds | Retain CGO-disabled cross-builds; these cover advertised targets and configurations distinct from the native race-test build. |
|
|
||||||
| Examples, consumer fixtures, documentation links, and package boundaries | Keep their tests in the full suite; remove separate release-time reruns already covered by that suite. |
|
|
||||||
| Separate native production builds | Remove the extra native `go build` gates; this library's packages are compiled by the test run. |
|
|
||||||
| Second Go toolchain | Make testing on a newer toolchain optional and non-gating. |
|
|
||||||
| Native filesystem evidence | Use the local suite results rather than separate manual certification. Report skipped cases without automatically requiring human approval. |
|
|
||||||
|
|
||||||
The local release suite must still pass. Removing redundant gates does not mean
|
|
||||||
ignoring actual local test failures. macOS remains best-effort, with no required
|
|
||||||
native validation or Darwin cross-builds.
|
|
||||||
|
|
||||||
Avoid requiring the everyday checker in addition to the release checker when it
|
|
||||||
would merely repeat the same checks. Do not introduce an approval service,
|
|
||||||
attestation framework, or new release dependency to implement this simplification.
|
|
||||||
|
|
||||||
## Preparation without human sign-off gates
|
|
||||||
|
|
||||||
Compatibility and version selection, release-note accuracy, reviewing the diff
|
|
||||||
for credentials or unintended content, and retiring completed roadmaps remain
|
|
||||||
normal release preparation. The executing agent may perform these tasks without
|
|
||||||
seeking routine maintainer approval or producing separate manual evidence records.
|
|
||||||
|
|
||||||
Only genuine unresolved product decisions or missing authority require a question
|
|
||||||
to the maintainer. Preserve authorization boundaries for pushing and releasing;
|
|
||||||
the standing local-commit policy alone is not publication authorization.
|
|
||||||
|
|
||||||
Move toolchain update research and reassessment of available YAML dependency
|
|
||||||
versions to periodic maintenance or relevant dependency changes. Do not require
|
|
||||||
external version research or renewed approval of an unchanged dependency pin for
|
|
||||||
every patch release. Dependency changes remain reviewed changes with applicable
|
|
||||||
validation and compatibility documentation.
|
|
||||||
|
|
||||||
## Publication is the completion condition
|
|
||||||
|
|
||||||
Never wait for CI, poll CI until it finishes, require green CI status, or treat a
|
|
||||||
missing, slow, unreliable, or failed CI run as a release blocker. This applies
|
|
||||||
both before publication and after a successful tag push. Optional CI may provide
|
|
||||||
maintenance feedback independently; it must not be a hidden release gate.
|
|
||||||
|
|
||||||
Fresh consumer-module retrieval, remote tag read-back after a successful push,
|
|
||||||
and other post-publication smoke checks are optional and non-gating. Do not wait
|
|
||||||
for module proxy propagation or credential-dependent consumer downloads before
|
|
||||||
reporting success. Publication push failures still mean publication has not been
|
|
||||||
confirmed; the completion rule requires a successful push of the intended tag.
|
|
||||||
|
|
||||||
An optional later check finding a defect does not authorize replacing the tag.
|
|
||||||
Use the existing immutable-release correction rules and an appropriate new
|
|
||||||
version for any correction.
|
|
||||||
|
|
||||||
## Explicit policy exception
|
|
||||||
|
|
||||||
The adopted release policy must record the deliberate exception to the shared
|
|
||||||
standard's mandatory post-publication verification requirement:
|
|
||||||
|
|
||||||
- Scope: ConfigKit's source-only tag publication; subsequent authoritative
|
|
||||||
read-back and fresh consumer retrieval are optional, not completion gates.
|
|
||||||
- Rationale: the maintainer accepts a successful intended tag push as sufficient
|
|
||||||
publication evidence and rejects dependence on CI or downstream retrieval
|
|
||||||
availability for release completion.
|
|
||||||
- Compensating controls: local validation of the exact candidate, automated
|
|
||||||
pre-publication guards, matching remote `main`, an annotated tag with verified
|
|
||||||
local target, explicit ref pushes, and immutable published versions.
|
|
||||||
|
|
||||||
Record this exception openly rather than retaining contradictory mandatory
|
|
||||||
verification wording elsewhere. Preserve historical release notes and scoped
|
|
||||||
historical exceptions unchanged.
|
|
||||||
|
|
||||||
## Affected owners and completion criteria
|
|
||||||
|
|
||||||
Implementation must reconcile the release policy, release procedure, checker,
|
|
||||||
relevant [check-script tests](../../release_check_test.go), and any affected
|
|
||||||
[development guidance](../development.md). Current documentation must describe
|
|
||||||
only the implemented workflow once the change lands.
|
|
||||||
|
|
||||||
Completion requires:
|
|
||||||
|
|
||||||
- One local validation pass for the final candidate, with the retained checks
|
|
||||||
and no duplicate full-suite or focused subset runs.
|
|
||||||
- No required human sign-off, dedicated clone, second toolchain, latest-version
|
|
||||||
research, CI waiting, or post-publication consumer verification.
|
|
||||||
- Automated safeguards still prevent publishing an unvalidated or unintended
|
|
||||||
candidate or reusing an existing version.
|
|
||||||
- Tests and documentation agree on the reduced workflow, including failure
|
|
||||||
handling and completion immediately after successful tag publication.
|
|
||||||
- Validation of the changes uses local tests and disposable fixtures; implementing
|
|
||||||
this roadmap does not itself authorize a real release or remote publication.
|
|
||||||
|
|
||||||
There are no outstanding product decisions for this target. A later implementation
|
|
||||||
plan may sequence the work without expanding these gates or guarantees.
|
|
||||||
|
|||||||
@@ -9,6 +9,120 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Exercise the copyable runbook against disposable Git repositories, not a
|
||||||
|
// publication service. The checker itself is covered separately.
|
||||||
|
func TestReleaseRunbookGuards(t *testing.T) {
|
||||||
|
document, err := os.ReadFile("docs/release.md")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
block := func(heading string) string {
|
||||||
|
t.Helper()
|
||||||
|
_, section, ok := strings.Cut(string(document), heading)
|
||||||
|
if !ok {
|
||||||
|
t.Fatalf("missing section %q", heading)
|
||||||
|
}
|
||||||
|
_, section, ok = strings.Cut(section, "```sh\n")
|
||||||
|
if !ok {
|
||||||
|
t.Fatalf("missing commands in %q", heading)
|
||||||
|
}
|
||||||
|
commands, _, ok := strings.Cut(section, "```")
|
||||||
|
if !ok {
|
||||||
|
t.Fatalf("unterminated commands in %q", heading)
|
||||||
|
}
|
||||||
|
return commands
|
||||||
|
}
|
||||||
|
prepare := block("## 4. Validate the source candidate")
|
||||||
|
publish := block("## 6. Run publication guards") + block("## 7. Tag and publish the exact ref")
|
||||||
|
for _, scenario := range []string{"success", "dirty", "changed-candidate", "remote-tag-exists", "failed-validation"} {
|
||||||
|
t.Run(scenario, func(t *testing.T) {
|
||||||
|
root := t.TempDir()
|
||||||
|
remote := filepath.Join(t.TempDir(), "remote.git")
|
||||||
|
run := func(program string, args ...string) string {
|
||||||
|
t.Helper()
|
||||||
|
cmd := exec.Command(program, args...)
|
||||||
|
cmd.Dir = root
|
||||||
|
out, err := cmd.CombinedOutput()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("%s %v: %v\n%s", program, args, err, out)
|
||||||
|
}
|
||||||
|
return strings.TrimSpace(string(out))
|
||||||
|
}
|
||||||
|
run("git", "init", "-q", "-b", "main")
|
||||||
|
run("git", "init", "-q", "--bare", remote)
|
||||||
|
run("git", "config", "user.name", "Test")
|
||||||
|
run("git", "config", "user.email", "test@example.invalid")
|
||||||
|
run("git", "config", "commit.gpgsign", "false")
|
||||||
|
run("git", "config", "tag.gpgsign", "false")
|
||||||
|
const origin = "https://gitea.maximumdirect.net/eric/ConfigKit.git"
|
||||||
|
run("git", "remote", "add", "origin", remote)
|
||||||
|
// Substitute only the fixture's authoritative URL; execute the guards
|
||||||
|
// themselves unchanged. Disallow network transports as a backstop.
|
||||||
|
localPublish := strings.ReplaceAll(publish, origin, remote)
|
||||||
|
for _, dir := range []string{"docs/releases", "scripts"} {
|
||||||
|
if err := os.MkdirAll(filepath.Join(root, dir), 0700); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
write := func(path, content string) {
|
||||||
|
t.Helper()
|
||||||
|
if err := os.WriteFile(filepath.Join(root, path), []byte(content), 0700); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
checker := "#!/bin/sh\nexit 0\n"
|
||||||
|
if scenario == "failed-validation" {
|
||||||
|
checker = "#!/bin/sh\nexit 37\n"
|
||||||
|
}
|
||||||
|
write("scripts/release-check.sh", checker)
|
||||||
|
write("docs/releases/v0.9.0.md", "# ConfigKit v0.9.0\n\n## Summary\n\n## Compatibility\n\n## Upgrade\n\n## Changes\n")
|
||||||
|
run("git", "add", ".")
|
||||||
|
bash := func(commands string) ([]byte, error) {
|
||||||
|
cmd := exec.Command("bash", "-c", "set -euo pipefail\nrelease_version=v0.9.0\n"+commands)
|
||||||
|
cmd.Dir = root
|
||||||
|
cmd.Env = append(os.Environ(), "GIT_ALLOW_PROTOCOL=file")
|
||||||
|
return cmd.CombinedOutput()
|
||||||
|
}
|
||||||
|
out, err := bash(prepare)
|
||||||
|
if scenario == "failed-validation" {
|
||||||
|
if err == nil {
|
||||||
|
t.Fatal("failed validation accepted")
|
||||||
|
}
|
||||||
|
if _, err := os.Stat(filepath.Join(root, ".git/configkit-release-candidate")); !os.IsNotExist(err) {
|
||||||
|
t.Fatal("failed validation recorded a candidate")
|
||||||
|
}
|
||||||
|
} else if err != nil {
|
||||||
|
t.Fatalf("prepare: %v\n%s", err, out)
|
||||||
|
}
|
||||||
|
switch scenario {
|
||||||
|
case "dirty":
|
||||||
|
write("unexpected.txt", "uncommitted\n")
|
||||||
|
case "changed-candidate":
|
||||||
|
run("git", "commit", "--allow-empty", "-qm", "Changed candidate")
|
||||||
|
case "remote-tag-exists":
|
||||||
|
run("git", "tag", "v0.9.0")
|
||||||
|
run("git", "push", remote, "refs/tags/v0.9.0")
|
||||||
|
run("git", "tag", "-d", "v0.9.0")
|
||||||
|
}
|
||||||
|
// Seed the remote primary branch so fetch works before first publication.
|
||||||
|
run("git", "push", remote, "HEAD:refs/heads/main")
|
||||||
|
out, err = bash(localPublish)
|
||||||
|
if scenario == "success" {
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("publish: %v\n%s", err, out)
|
||||||
|
}
|
||||||
|
if got := run("git", "--git-dir="+remote, "rev-parse", "v0.9.0^{}"); got != run("git", "rev-parse", "HEAD") {
|
||||||
|
t.Fatal("published wrong commit")
|
||||||
|
}
|
||||||
|
} else if err == nil {
|
||||||
|
t.Fatalf("publication accepted %s", scenario)
|
||||||
|
} else if scenario != "remote-tag-exists" && run("git", "--git-dir="+remote, "tag", "--list") != "" {
|
||||||
|
t.Fatal("failed guard published a tag")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestCheckScriptsHandleFilenamesAndStopOnFailure(t *testing.T) {
|
func TestCheckScriptsHandleFilenamesAndStopOnFailure(t *testing.T) {
|
||||||
for _, scriptName := range []string{"release-check.sh", "check.sh"} {
|
for _, scriptName := range []string{"release-check.sh", "check.sh"} {
|
||||||
t.Run(scriptName, func(t *testing.T) {
|
t.Run(scriptName, func(t *testing.T) {
|
||||||
@@ -66,7 +180,7 @@ func TestCheckScriptsHandleFilenamesAndStopOnFailure(t *testing.T) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
cmd := exec.Command("/bin/bash", filepath.Join(root, "scripts", scriptName))
|
cmd := exec.Command("/bin/bash", filepath.Join(root, "scripts", scriptName))
|
||||||
cmd.Env = append(os.Environ(), "PATH="+bin+string(os.PathListSeparator)+os.Getenv("PATH"), "CONFIGKIT_BASELINE_TOOLCHAIN=test-baseline", "CONFIGKIT_NEWER_TOOLCHAIN=test-newer", "CONFIGKIT_TEST_FMT_LOG="+log, "CONFIGKIT_TEST_GO_LOG="+calls)
|
cmd.Env = append(os.Environ(), "PATH="+bin+string(os.PathListSeparator)+os.Getenv("PATH"), "CONFIGKIT_BASELINE_TOOLCHAIN=test-baseline", "CONFIGKIT_NEWER_TOOLCHAIN=", "CONFIGKIT_TEST_FMT_LOG="+log, "CONFIGKIT_TEST_GO_LOG="+calls)
|
||||||
// Log only targets selected by the script, not inherited host settings.
|
// Log only targets selected by the script, not inherited host settings.
|
||||||
cmd.Env = append(cmd.Env, "GOOS=", "GOARCH=")
|
cmd.Env = append(cmd.Env, "GOOS=", "GOARCH=")
|
||||||
if name == "failed-go-check" {
|
if name == "failed-go-check" {
|
||||||
@@ -104,6 +218,12 @@ func TestCheckScriptsHandleFilenamesAndStopOnFailure(t *testing.T) {
|
|||||||
t.Fatal("checker continued after failed test")
|
t.Fatal("checker continued after failed test")
|
||||||
}
|
}
|
||||||
if scriptName == "release-check.sh" && !fail {
|
if scriptName == "release-check.sh" && !fail {
|
||||||
|
if strings.Count(string(invoked), " test ") != 1 || !strings.Contains(string(invoked), " test -race -v ./...\n") {
|
||||||
|
t.Fatalf("want one complete race-test run, got:\n%s", invoked)
|
||||||
|
}
|
||||||
|
if strings.Count(string(invoked), " vet ./...") != 1 || strings.Count(string(invoked), " build ./...") != 2 {
|
||||||
|
t.Fatalf("want one vet run and only two cross-builds, got:\n%s", invoked)
|
||||||
|
}
|
||||||
// These are selected release gates, not incidental loop details.
|
// These are selected release gates, not incidental loop details.
|
||||||
for _, target := range []string{"linux/amd64", "linux/arm64"} {
|
for _, target := range []string{"linux/amd64", "linux/arm64"} {
|
||||||
if !strings.Contains(string(invoked), target+" build ./...") {
|
if !strings.Contains(string(invoked), target+" build ./...") {
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ repository_dir=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." && pwd)
|
|||||||
cd "$repository_dir"
|
cd "$repository_dir"
|
||||||
|
|
||||||
baseline_toolchain=${CONFIGKIT_BASELINE_TOOLCHAIN:?set CONFIGKIT_BASELINE_TOOLCHAIN to a cached supported Go 1.25 patch release}
|
baseline_toolchain=${CONFIGKIT_BASELINE_TOOLCHAIN:?set CONFIGKIT_BASELINE_TOOLCHAIN to a cached supported Go 1.25 patch release}
|
||||||
newer_toolchain=${CONFIGKIT_NEWER_TOOLCHAIN:?set CONFIGKIT_NEWER_TOOLCHAIN to a cached newer supported Go toolchain}
|
|
||||||
|
|
||||||
run_go() {
|
run_go() {
|
||||||
local toolchain=$1
|
local toolchain=$1
|
||||||
@@ -20,7 +19,6 @@ check_toolchain() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
check_toolchain "$baseline_toolchain"
|
check_toolchain "$baseline_toolchain"
|
||||||
check_toolchain "$newer_toolchain"
|
|
||||||
bash -n scripts/release-check.sh
|
bash -n scripts/release-check.sh
|
||||||
|
|
||||||
temporary_dir=$(mktemp -d)
|
temporary_dir=$(mktemp -d)
|
||||||
@@ -69,21 +67,13 @@ while IFS= read -r -d '' candidate_file; do
|
|||||||
esac
|
esac
|
||||||
done < <(git ls-files --cached --others --exclude-standard -z)
|
done < <(git ls-files --cached --others --exclude-standard -z)
|
||||||
|
|
||||||
for toolchain in "$baseline_toolchain" "$newer_toolchain"; do
|
# Verbose output reports skipped cases without a separate evidence run.
|
||||||
run_go "$toolchain" test ./...
|
run_go "$baseline_toolchain" test -race -v ./...
|
||||||
run_go "$toolchain" vet ./...
|
run_go "$baseline_toolchain" vet ./...
|
||||||
run_go "$toolchain" build ./...
|
|
||||||
done
|
|
||||||
|
|
||||||
run_go "$newer_toolchain" test -race ./...
|
|
||||||
run_go "$newer_toolchain" test . -run '^Example'
|
|
||||||
run_go "$newer_toolchain" test ./examples/consumers
|
|
||||||
run_go "$newer_toolchain" test . -run '^TestLocalDocumentationLinks$'
|
|
||||||
run_go "$newer_toolchain" test . -run '^TestDependencyImportBoundary$'
|
|
||||||
|
|
||||||
# Only release-validated targets gate publication; macOS is best-effort.
|
# Only release-validated targets gate publication; macOS is best-effort.
|
||||||
for target in linux/amd64 linux/arm64; do
|
for target in linux/amd64 linux/arm64; do
|
||||||
target_os=${target%/*}
|
target_os=${target%/*}
|
||||||
target_arch=${target#*/}
|
target_arch=${target#*/}
|
||||||
GOTOOLCHAIN="$newer_toolchain" GOPROXY=off CGO_ENABLED=0 GOOS="$target_os" GOARCH="$target_arch" go build ./...
|
GOTOOLCHAIN="$baseline_toolchain" GOPROXY=off CGO_ENABLED=0 GOOS="$target_os" GOARCH="$target_arch" go build ./...
|
||||||
done
|
done
|
||||||
|
|||||||
Reference in New Issue
Block a user