Files
ReleaseKit/docs/integrations/gitea.md

5.5 KiB

Gitea release pages

ReleaseKit's public Deliver operation and deliver command verify tagged source, find or create the selected module's release page, inspect existing assets, and upload missing assets through the internal Gitea client. Page-only and binary-producing profiles use the same delivery path. The consumer delivery guide covers caller workflows; this guide describes the Gitea protocol and its failure behavior.

The caller supplies the Gitea base URL, owner, repository name, and token explicitly. The client does not read ambient credentials. The token is sent in the Authorization: token … request header and is not included in errors or results. The base URL must use HTTP or HTTPS and cannot contain URL credentials, a query, or a fragment.

The selected module derives a complete tag from its semantic version, declared module path, and physical repository-relative directory. For example, version v1.2.3 in integrations/ckconfig uses integrations/ckconfig/v1.2.3; a root module uses v1.2.3. A /v2 module stored at integrations/core/v2 uses integrations/core/v2.1.0; the same declared module stored at integrations/core derives the same tag. ReleaseKit removes a final physical /v2 directory from the tag prefix only when the module declaration has that /v2 suffix. A module-local note stays at <module>/docs/releases/<version>.md, including a physical /v2 directory. The default shared validation convention uses repository-root COPYRIGHT, LICENSE, and docs/oss/attribution.md when present. Consumers own their license layout and release-note links. Use the complete derived tag as the immutable source ref and the actual repository-relative file paths in those links. Shared-file selection controls validation inputs; delivery preserves the committed note and its footer links. The client first reads /api/v1/repos/{owner}/{repo}/tags/{tag} and requires the hosted tag's commit SHA to equal the captured source commit. It then reads /api/v1/repos/{owner}/{repo}/releases/tags/{tag}. A matching existing page must have that tag, the complete committed release note as its body, and stable non-draft state. Its existing title is retained. ReleaseKit does not edit a conflicting page. Slash-containing tags are escaped as one URL path segment.

If the page is absent, the client posts to /api/v1/repos/{owner}/{repo}/releases with the selected full tag and commit, the release note's H1 as title, the complete note as body, and draft and prerelease disabled. A create conflict, interrupted response, or malformed create response (including inconsistent decoded fields) triggers one lookup. An exact page found there confirms the existing content; a differing page is a conflict. If that lookup cannot determine the result after a possibly successful write, the client returns an unknown outcome. Other HTTP failures retain their structured failure kind and status code. A recovered create retains its write history; a later asset-inspection failure reports partial page progress.

For a binary-producing release, the client can build a deterministic SHA256SUMS file from the declared artifact names and SHA-256 digests. Entries are sorted by filename and use the standard two-space separator. A source-only release produces no manifest.

Asset inspection lists the release attachments, streams each declared existing file, and compares its SHA-256 digest. It reports each asset as matching, missing, conflicting, or unverifiable. Same-name attachments with different bytes are conflicts even when their reported size matches. An existing SHA256SUMS must exactly match the complete expected manifest; a subset or different manifest is a conflict. An unreadable attachment is unverifiable, not missing. A failed read-only inspection reports not_attempted; if this invocation already delivered the page, its outcome retains partial progress. Unknown-write outcomes are reserved for unresolved writes. Unrelated attachments are returned separately and are preserved.

Attachment downloads and redirects carry the Gitea authorization token only when their scheme, host, and port match the configured service. Cross-origin content is downloaded without that token and verified by its digest.

The upload operation accepts only an inspection result without conflicts or unverifiable assets. It uploads missing binaries in filename order and then the missing SHA256SUMS, using multipart field attachment and the filename query parameter name. Matching attachments are retained; unrelated and existing attachments are never overwritten or deleted. Results use disjoint current observations: matching, uploaded, pending, conflicting, and uncertain. An asset moved from known missing work to another category is removed from pending; later known-missing assets can remain pending when an earlier upload stops the operation. Early failures may leave declarations unreported. After an ambiguous upload or an upload name conflict, the client performs one list and content check. It does not repeat the POST when the result is missing or cannot be verified, so a caller can resolve the remote state before retrying.

Uploads use the configured service origin and the same explicit token header. Source-only page delivery supplies no binary assets and creates no manifest.

The integration tests use a local HTTP fixture and assert request paths, payloads, authorization, streaming comparisons, manifest handling, and failure handling. They do not contact a live Gitea service or use real credentials.