Add hosted Gitea release delivery
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -22,7 +22,7 @@
|
||||
go.work
|
||||
go.work.sum
|
||||
|
||||
# Local ReleaseKit executable
|
||||
# Local ReleaseKit executable and delivery credentials
|
||||
.releasekit/
|
||||
|
||||
# env file
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
**Base Policy Version:** 1.8
|
||||
|
||||
**Last Updated**: 2026-09-27
|
||||
**Last Updated**: 2026-11-02
|
||||
|
||||
**Upstream Source:** [oss.md](https://gitea.maximumdirect.net/eric/policy/src/commit/d84a38ebab26f048cafbe59a2246700c35d29843/docs/policy/oss.md)
|
||||
|
||||
@@ -221,7 +221,8 @@ Promptkit retains its LGPL-3.0-or-later library grant in
|
||||
[COPYRIGHT](../../COPYRIGHT). Adapted policy documentation has the separate
|
||||
scope identified there and in [attribution](../oss/attribution.md).
|
||||
|
||||
Promptkit publishes source-only Go module tags on Gitea, with no binaries or
|
||||
separate hosted download page. The [release procedure](../release.md) owns
|
||||
publication and concrete footer URLs. The hosted-page guidance applies if such
|
||||
a channel is deliberately introduced; it does not require creating one.
|
||||
Promptkit publishes source-only Go module tags and Gitea release pages, with no
|
||||
binaries. Each new hosted page reuses the complete checked-in release note,
|
||||
including its licensing footer. The [release procedure](../release.md) owns
|
||||
source publication, hosted delivery, and concrete footer URLs. Previously
|
||||
published notes and tags retain their original records.
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
**Base Policy Version:** 1.6
|
||||
|
||||
**Last Updated**: 2026-10-08
|
||||
**Last Updated**: 2026-11-02
|
||||
|
||||
**Upstream Source:** [release.md](https://gitea.maximumdirect.net/eric/policy/src/commit/e833faddf120c789a9b45348edaf75720de16348/docs/policy/release.md)
|
||||
|
||||
@@ -241,9 +241,13 @@ navigation on 2026-09-26. Apply them prospectively; previously published notes
|
||||
and tags retain their original records.
|
||||
|
||||
Promptkit publishes source-only Go modules from main to origin on Gitea, using
|
||||
annotated stable SemVer tags. It has no binaries, hosted download pages, or
|
||||
asynchronous deliverables. The source commit is pushed through main before the
|
||||
tag. The [release procedure](../release.md) owns commands and recovery.
|
||||
annotated stable SemVer tags. The source commit is pushed through main before
|
||||
the tag. After source publication, maintainers use ReleaseKit locally to deliver
|
||||
a Gitea release page containing the complete checked-in note, including its
|
||||
licensing footer. There are no binaries or other deliverables. Source publication
|
||||
and hosted delivery have separate outcomes; delivery credentials and service
|
||||
availability do not gate source-release completion. The
|
||||
[release procedure](../release.md) owns commands and recovery.
|
||||
|
||||
Release preparation uses the latest Go installation available in the development
|
||||
environment to build the maintainer release executable and validate the
|
||||
@@ -268,8 +272,10 @@ ReleaseKit tool selected in `go.mod`. The committed
|
||||
[profile](../../releasekit.json) selects the race-enabled Go suite, full vet,
|
||||
committed Go formatting, local Markdown links, workspace and filesystem
|
||||
replacement inspection, and the offline semantic checks for the three
|
||||
maintained consumer examples. These are the selected checks for the final
|
||||
candidate; a separate ordinary test run or standalone build is not an
|
||||
maintained consumer examples. It also rejects the configured local delivery
|
||||
token path if committed; this narrowly scoped check is not a general credential
|
||||
scan. These are the selected checks for the final candidate; a separate
|
||||
ordinary test run or standalone build is not an
|
||||
additional release gate. The upstream tool owns candidate, remote, and tag
|
||||
publication checks. It returns native status 0 for confirmed publication, 1
|
||||
for a known validation or publication failure, 2 for invalid input or profile,
|
||||
@@ -278,3 +284,9 @@ captured publication endpoint before retrying; the repository-specific
|
||||
[procedure](../release.md#failure-recovery) links to the upstream recovery
|
||||
instructions. Do not wait for CI or Go module availability. Licensing footer
|
||||
URLs are preparation work, not a network gate.
|
||||
|
||||
Hosted delivery is a separate post-publication step for new releases. It reuses
|
||||
the immutable tag and note without rerunning candidate validation or waiting
|
||||
for CI. Retry failed delivery against that same version after resolving any
|
||||
uncertain hosted write; preserve published tags and hosted content. Report
|
||||
delivery status separately from the completed source release.
|
||||
|
||||
@@ -4,6 +4,8 @@ This runbook implements the [release policy](policy/release.md). Promptkit
|
||||
publishes source-only Go module tags from `main` to `origin`. A successful push
|
||||
of the selected annotated tag, after its source commit is available on `main`,
|
||||
completes the release. Do not wait for CI or Go module availability.
|
||||
After source publication, deliver the hosted Gitea release page as described
|
||||
below. Report source publication and hosted delivery separately.
|
||||
|
||||
## Prepare The Candidate
|
||||
|
||||
@@ -51,13 +53,22 @@ impact under the [versioning policy](policy/release.md#versioning-and-compatibil
|
||||
End each new note with the licensing footer below, using the selected version:
|
||||
|
||||
```markdown
|
||||
[COPYRIGHT](https://gitea.maximumdirect.net/eric/promptkit/src/tag/vX.Y.Z/COPYRIGHT) | [LICENSE](https://gitea.maximumdirect.net/eric/promptkit/src/tag/vX.Y.Z/LICENSE) | [ATTRIBUTION](https://gitea.maximumdirect.net/eric/promptkit/src/tag/vX.Y.Z/docs/oss/attribution.md)
|
||||
[COPYRIGHT](https://forge.maximumdirect.net/base-layer/promptkit/src/tag/vX.Y.Z/COPYRIGHT) | [LICENSE](https://forge.maximumdirect.net/base-layer/promptkit/src/tag/vX.Y.Z/LICENSE) | [ATTRIBUTION](https://forge.maximumdirect.net/base-layer/promptkit/src/tag/vX.Y.Z/docs/oss/attribution.md)
|
||||
```
|
||||
|
||||
Check the footer paths against the candidate; the future tag need not resolve
|
||||
remotely during preparation. Follow the [OSS policy](policy/oss.md) for these
|
||||
links. Promptkit publishes no binaries, hosted download page, or other
|
||||
asynchronous deliverables.
|
||||
links. Hosted delivery reuses this complete note without a separate summary.
|
||||
Promptkit publishes no binaries, attachments, or checksum manifests.
|
||||
|
||||
For hosted delivery, supply a Gitea API token with access to publish releases
|
||||
through `RELEASEKIT_GITEA_TOKEN` or the ignored local file
|
||||
`.releasekit/gitea-token`, with owner-only permissions for the file. A nonblank
|
||||
environment value takes precedence. ReleaseKit trims surrounding whitespace
|
||||
from file contents. Keep the token out of commits and shared logs. The profile
|
||||
rejects that exact token path if
|
||||
committed; it does not scan other files or Git history. Source publication uses
|
||||
Git authentication and neither reads nor requires the delivery token.
|
||||
|
||||
Retire completed roadmaps while preserving deferred work and repairing incoming
|
||||
links. Review the intended changes through the ordinary development workflow,
|
||||
@@ -87,7 +98,8 @@ The familiar wrapper delegates to the native ReleaseKit executable selected in
|
||||
`go.mod`. The committed [profile](../releasekit.json) selects the race-enabled
|
||||
Go suite, full vet, committed Go formatting, local Markdown links, workspace
|
||||
and filesystem replacement inspection, and semantic checks for the three
|
||||
maintained offline consumer examples. ReleaseKit also verifies the committed
|
||||
maintained offline consumer examples. It also checks that the configured local
|
||||
token path is not committed. ReleaseKit verifies the committed
|
||||
candidate and publication state, then publishes only the selected tag. Its
|
||||
checks run once for this candidate; do not repeat them as a separate sign-off.
|
||||
|
||||
@@ -97,8 +109,53 @@ the push outcome remains unknown. Successful publication needs no remote
|
||||
read-back, CI wait, or installation check. Provider probes and inference calls
|
||||
are not part of validation.
|
||||
|
||||
## Deliver The Hosted Release
|
||||
|
||||
After source publication succeeds, keep a clean checkout at the published tag's
|
||||
commit and run:
|
||||
|
||||
```sh
|
||||
./scripts/releasekit.sh deliver vMAJOR.MINOR.PATCH
|
||||
```
|
||||
|
||||
The profile selects Gitea at `https://forge.maximumdirect.net`, owner
|
||||
`base-layer`, repository `promptkit`. With no build targets, ReleaseKit creates
|
||||
or accepts a stable, non-draft release page containing the complete committed
|
||||
note and licensing footer. There is no binary build, attachment upload, or
|
||||
candidate revalidation. Delivery does not publish another tag or wait for CI.
|
||||
|
||||
ReleaseKit performs its authenticated, read-only repository preflight during
|
||||
delivery; no separate preflight is required before source publication. Missing
|
||||
credentials or an unavailable hosted service leave the source release complete.
|
||||
|
||||
Delivery returns status 0 for completion, 1 for an operational failure,
|
||||
conflict, or partial delivery, 2 for invalid configuration or credential/access
|
||||
errors, and 3 for an unresolved hosted write. Report the hosted URL on success
|
||||
and retain the diagnostic and delivery state on failure. See the upstream
|
||||
[delivery guide](https://forge.maximumdirect.net/base-layer/releasekit/src/tag/v0.7.0/docs/consumers/delivery.md)
|
||||
for the full result contract.
|
||||
|
||||
For a later retry, use a clean checkout of the original tag with its recorded
|
||||
module files and make the token available locally. For example, in a separate
|
||||
checkout with the tag available:
|
||||
|
||||
```sh
|
||||
git switch --detach vMAJOR.MINOR.PATCH
|
||||
./scripts/releasekit.sh deliver vMAJOR.MINOR.PATCH
|
||||
```
|
||||
|
||||
The launcher builds the tool selected by that checkout. Matching hosted content
|
||||
is accepted; conflicting content is not overwritten. Resolve an unknown hosted
|
||||
write before retrying. Retry delivery with the same immutable version rather
|
||||
than rerunning `publish` or moving a tag. Corrections to published source or
|
||||
content require a new appropriate version. These steps apply to tags containing
|
||||
this delivery configuration; older releases retain their original workflows.
|
||||
|
||||
## Failure Recovery
|
||||
|
||||
This section covers source publication. Hosted-delivery recovery is described
|
||||
[above](#deliver-the-hosted-release); its failure does not undo source publication.
|
||||
|
||||
For status 1, use the diagnostic to distinguish a validation failure from a
|
||||
known publication conflict. Correct and commit candidate defects, push `main`,
|
||||
and rerun publication with an unused version when appropriate. Status 2 means
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"product": "Promptkit",
|
||||
"remote": "origin",
|
||||
"validation": {
|
||||
"forbidden_files": [".releasekit/gitea-token"],
|
||||
"go": {
|
||||
"race": true,
|
||||
"full_vet": true
|
||||
@@ -13,6 +14,13 @@
|
||||
"local_replacements": true
|
||||
}
|
||||
},
|
||||
"delivery": {
|
||||
"forge": "gitea",
|
||||
"base_url": "https://forge.maximumdirect.net",
|
||||
"owner": "base-layer",
|
||||
"repository": "promptkit",
|
||||
"token_file": ".releasekit/gitea-token"
|
||||
},
|
||||
"checks": [
|
||||
{
|
||||
"args": ["python3", "./scripts/check-examples.py"],
|
||||
|
||||
@@ -216,6 +216,10 @@ def prepare_repository(repository, remote, environment, module_bytes, version):
|
||||
|
||||
|
||||
def verify_publication(repository, remote, temporary_root, environment, module_bytes, selected_go):
|
||||
profile = json.loads((repository / "releasekit.json").read_text(encoding="utf-8"))
|
||||
token_path = repository / profile["delivery"]["token_file"]
|
||||
if token_path.exists() or environment.get("RELEASEKIT_GITEA_TOKEN"):
|
||||
raise RuntimeError("publication fixture must not have delivery credentials")
|
||||
selected_releasekit = run(
|
||||
["go", "list", "-mod=readonly", "-m", "-f", "{{.Version}}", RELEASEKIT_MODULE],
|
||||
cwd=repository,
|
||||
@@ -387,6 +391,31 @@ def verify_validation_failure(
|
||||
raise RuntimeError(f"failure fixture checkout is not clean:\n{status}")
|
||||
|
||||
|
||||
def verify_forbidden_token(repository, environment):
|
||||
profile = json.loads((repository / "releasekit.json").read_text(encoding="utf-8"))
|
||||
token_path = profile["delivery"]["token_file"]
|
||||
write_file(repository / token_path, "disposable fixture placeholder\n")
|
||||
note_path = f"docs/releases/{FAILED_RELEASE_VERSION}.md"
|
||||
write_file(repository / note_path, f"# Promptkit {FAILED_RELEASE_VERSION}\n\nFixture.\n")
|
||||
repo_git(repository, environment, "add", "--", note_path)
|
||||
repo_git(repository, environment, "add", "-f", "--", token_path)
|
||||
repo_git(repository, environment, "commit", "-m", "Add forbidden-path fixture")
|
||||
|
||||
result = execute(
|
||||
[str(repository / ".releasekit/bin/releasekit"), "check", FAILED_RELEASE_VERSION],
|
||||
cwd=repository,
|
||||
environment=environment,
|
||||
)
|
||||
if (
|
||||
result.returncode != 1
|
||||
or "forbidden-files" not in result.stderr
|
||||
or token_path not in result.stderr
|
||||
):
|
||||
raise RuntimeError(
|
||||
f"committed delivery token path was not rejected:\n{result.stdout}\n{result.stderr}"
|
||||
)
|
||||
|
||||
|
||||
def verify_usage_classification(binary, temporary_root, environment):
|
||||
result = execute(
|
||||
[str(binary), "unknown"], cwd=temporary_root, environment=environment
|
||||
@@ -404,6 +433,7 @@ def verify_usage_classification(binary, temporary_root, environment):
|
||||
|
||||
def main():
|
||||
environment = os.environ.copy()
|
||||
environment.pop("RELEASEKIT_GITEA_TOKEN", None)
|
||||
environment.update(
|
||||
{
|
||||
"GOTOOLCHAIN": "local",
|
||||
@@ -464,11 +494,12 @@ def main():
|
||||
module_bytes,
|
||||
selected_go,
|
||||
)
|
||||
verify_forbidden_token(repository, environment)
|
||||
except (RuntimeError, OSError, json.JSONDecodeError) as error:
|
||||
print(error, file=sys.stderr)
|
||||
return 1
|
||||
|
||||
print("ReleaseKit publication success and failure fixtures passed")
|
||||
print("ReleaseKit publication and committed-token-path fixtures passed")
|
||||
return 0
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user