569 lines
34 KiB
Markdown
569 lines
34 KiB
Markdown
# Implementation plan: neutral forge delivery and credential preflight
|
||
|
||
Status: implementation in progress; Stages 1–7 are complete and Stages 8–10
|
||
are pending.
|
||
|
||
## Purpose and execution
|
||
|
||
Implement the target in the [feature roadmap](forge-boundary.md). That document
|
||
owns scope and user choices; this plan owns concrete design and ordered work.
|
||
The planning baseline is `44823ce`; source implementation remains unchanged
|
||
from `ac78e7d`. Gitea delivery, token files, and `forbidden_files` work today.
|
||
The neutral destination and credential preflight are planned.
|
||
|
||
Execute Stage 1 through Stage 10 in order as one end-to-end sprint. Each stage
|
||
is a focused Luna implementation task. Intermediate stages may leave callers
|
||
or tests uncompilable while responsibilities move. Continue without an
|
||
intermediate release, pilot, external action, or human review. Run focused
|
||
checks when the affected packages compile; Stage 10 owns final assembled
|
||
verification. Record completion here and follow the
|
||
[agent policy](../policy/agents.md) for commits and validation reporting.
|
||
|
||
Read the [development guide](../development.md) and applicable policies. Use
|
||
the [architecture policy](../policy/architecture.md),
|
||
[testing policy](../policy/testing.md), and
|
||
[documentation policy](../policy/documentation.md) throughout. Existing GoDoc,
|
||
[configuration](../config.md), [CLI](../cli.md), and
|
||
[Gitea integration](../integrations/gitea.md) documents define current contracts.
|
||
Tests supply regression evidence; assess incidental implementation assertions
|
||
against those contracts before preserving them.
|
||
|
||
This sprint implements the Gitea backend behind a neutral boundary. Git source
|
||
publication, module/tag derivation, build targets, buildinfo, receipts, token
|
||
precedence, and optional candidate validators retain their responsibilities.
|
||
Additional backends, public backend registration, new transport retry policies,
|
||
and release publication are outside this sprint.
|
||
|
||
## Selected design
|
||
|
||
### Public API and configuration
|
||
|
||
Replace the root facade's `GiteaDestination` with these facade-owned declarations:
|
||
|
||
```go
|
||
type Forge string
|
||
|
||
const ForgeGitea Forge = "gitea"
|
||
|
||
type DeliveryDestination struct {
|
||
Forge Forge
|
||
BaseURL string
|
||
Owner string
|
||
Repository string
|
||
Token string
|
||
}
|
||
```
|
||
|
||
`DeliveryRequest.Destination` becomes `DeliveryDestination`; its other fields,
|
||
the public result shape, state values, and asset categories remain as defined
|
||
today. Use explicit conversions into internal values. The facade owns backend
|
||
selection and construction through a private helper in `delivery.go`.
|
||
|
||
Add `delivery.forge` to the existing flat JSON delivery object. Its supported
|
||
value is `"gitea"`, corresponding to `ForgeGitea`. Omitted, empty, whitespace-only,
|
||
and unsupported selections are errors when delivery is requested. Selection is
|
||
explicit in both interfaces; neither URL inspection nor an omitted field selects
|
||
a backend. Keep `base_url`, `owner`, `repository`, `token_env`, and `token_file`
|
||
in their current locations. The owner/repository fields express the current
|
||
backend's addressing needs; future adapters can extend the neutral model when
|
||
needed without promising every forge the same address structure now.
|
||
|
||
Keep semantic delivery validation at the delivery entry points. Strict JSON
|
||
decoding still applies to all commands, but `check`, `publish`, and `build` do
|
||
not acquire a new requirement for a delivery object, valid forge selection, or
|
||
credentials. `ci-deliver` first prepares/verifies the tagged checkout and loads
|
||
its profile as today, then checks the forge before token loading and application
|
||
dependency preparation. Ordinary `deliver` checks it before loading receipts,
|
||
building, or making hosted requests. Library selection failure returns
|
||
`DeliveryNotAttempted` with the requested version and an error before invoking
|
||
the generic workflow. Credential preflight failures use the classification
|
||
described below.
|
||
|
||
After explicit Gitea selection, retain `RELEASEKIT_GITEA_TOKEN` as the CLI's
|
||
existing default token environment name. Preserve configured names, environment
|
||
over file precedence, trimming and file path resolution, and status 2 for
|
||
configuration/credential errors. The library receives `Token` explicitly.
|
||
Gitea's remaining destination validation stays in the adapter. Consumer
|
||
migration replaces the public type, supplies `Forge: releasekit.ForgeGitea`,
|
||
and adds `"forge": "gitea"` to each delivery profile. Use a direct API cutover
|
||
without a legacy `GiteaDestination` alias or implicit-selection compatibility
|
||
path.
|
||
|
||
### Credential preflight contract and ordering
|
||
|
||
Add `PreflightDelivery(ctx context.Context, destination DeliveryDestination) error`
|
||
to the root facade. It checks the selected destination without requiring source,
|
||
version, tag, note, or artifact inputs. `Deliver` automatically uses the same
|
||
internal preflight implementation; callers do not need to invoke the standalone
|
||
operation for ordinary delivery.
|
||
|
||
Use a facade-owned `DeliveryPreflightError` with `Kind` and `Err` fields,
|
||
`Error`, and `Unwrap`. Its named string kind, `DeliveryPreflightFailureKind`,
|
||
has these constants:
|
||
|
||
| Constant | Value |
|
||
| --- | --- |
|
||
| `DeliveryPreflightMissingCredential` | `missing_credential` |
|
||
| `DeliveryPreflightInvalidCredential` | `invalid_credential` |
|
||
| `DeliveryPreflightInsufficientPermissions` | `insufficient_permissions` |
|
||
| `DeliveryPreflightInaccessibleDestination` | `inaccessible_destination` |
|
||
| `DeliveryPreflightUnavailable` | `unavailable` |
|
||
|
||
Convert internal classifications explicitly and retain causes and cancellation
|
||
identity without exposing internal types in
|
||
exported signatures. The unavailable category includes network/service failures
|
||
and malformed responses that prevent verification. A 404 can mean hidden or
|
||
missing repository access; diagnostics must preserve that ambiguity. A 403
|
||
establishes denied access, not necessarily an expired or invalid token.
|
||
|
||
Preflight checks local destination rules and nonblank credentials, then invokes
|
||
the backend's read-only authenticated repository probe. It fails on rejected
|
||
credentials, inaccessible target access, and reliably established deficiencies
|
||
in permissions needed for delivery. Scope checks to release/asset delivery;
|
||
code-push permission alone is not an equivalent release permission. Unexposed
|
||
token scopes or write permissions remain unverified and do not independently
|
||
fail preflight. A nil error establishes authentication and repository access
|
||
plus no known delivery-permission deficiency; it does not certify every future
|
||
write. Preserve ordinary authorization and write recovery. Do not create test
|
||
releases, upload test assets, or request extra user/admin token scopes.
|
||
|
||
Library delivery performs cheap request/source/note checks, then credential
|
||
preflight before managed builds or full artifact size/digest verification.
|
||
Ordinary CLI delivery resolves credentials as today and relies on this automatic
|
||
library preflight. Reading a prebuilt receipt can remain a cheap earlier step.
|
||
After preflight succeeds, full local content verification still precedes every
|
||
hosted release/asset write. This deliberately permits the earlier read-only
|
||
credential probe before local artifact verification.
|
||
|
||
For binary `ci-deliver`, load the verified tagged profile and resolve credentials,
|
||
invoke the standalone facade preflight, then prepare application dependencies.
|
||
Subsequent `Deliver` performs its normal preflight before building; that later
|
||
check is fresh after network-capable dependency preparation. Page-only CI has
|
||
no application dependency preparation and can rely on `Deliver` alone. No
|
||
long-lived validation cache or public preflight-bypass setting is needed.
|
||
|
||
Automatic preflight failure leaves delivery `not_attempted`, including service
|
||
unavailability; unknown-write outcomes remain reserved for unresolved writes.
|
||
CLI missing/invalid credentials, established insufficient permissions, and
|
||
inaccessible destinations return status 2. Unavailable verification and
|
||
cancellation return status 1 with their actual causes. Existing local profile
|
||
errors keep status 2. Document these earlier failures and classifications as
|
||
part of the next minor release's operational compatibility impact.
|
||
|
||
`check` and standalone `build` acquire no credentials or online preflight.
|
||
`publish` retains Git's native SSH/HTTPS authentication and remote guards; it
|
||
does not invoke hosted delivery preflight or require a forge token. Consumers
|
||
can explicitly call `PreflightDelivery` before their own preparation or source
|
||
publication without making that a new mandatory publication gate. Application
|
||
dependency credentials stay with the existing Go/Git preparation mechanisms.
|
||
|
||
### Internal ownership and dependencies
|
||
|
||
| Owner | Responsibility after the sprint |
|
||
| --- | --- |
|
||
| Root facade | Public destination and callable preflight, explicit selection, concrete backend construction, request/result/error conversion. |
|
||
| `internal/forge` (new) | Backend interface, preflight classifications, observed release/asset values, opaque handles, neutral failures, and write evidence. |
|
||
| `internal/artifact` | Existing build identity helpers plus expected local assets, manifests, declaration validation, and local size/digest verification. |
|
||
| `internal/delivery` | Automatic preflight coordination, local source/build coordination, hosted tag comparison, page matching/creation recovery, remote content comparison, upload sequencing/recovery, observations, and final outcomes. |
|
||
| `internal/gitea` | Destination rules, authenticated preflight probes and permission evidence, HTTP operations, codecs, protocol acknowledgments, authentication and redirects, multipart streaming, and protocol-to-neutral failure conversion. |
|
||
| CLI | Profile adaptation, token loading, receipts, preparation, presentation, and exit statuses. |
|
||
|
||
Both delivery and Gitea depend on `internal/forge`; that contract imports neither
|
||
of them. Artifact mechanics stay independent of Gitea and delivery. The generic
|
||
workflow receives a configured backend rather than destination credentials.
|
||
The facade can import Gitea to assemble the operation. The runtime facade keeps
|
||
its existing small dependency graph.
|
||
|
||
Use one internal `Backend` interface with these logical operations. The names
|
||
below define the intended seam; small private naming adjustments are routine
|
||
implementation choices.
|
||
|
||
| Operation | Inputs and outputs |
|
||
| --- | --- |
|
||
| `Preflight` | Context; checks the backend's configured credentials/repository through read-only requests and returns a classified preflight error or nil. |
|
||
| `TagCommit` | Context and full tag; returns observed commit or a classified error. |
|
||
| `FindRelease` | Context and full tag; returns logical release data or a classified not-found/error. |
|
||
| `CreateRelease` | Context and requested tag, commit, title, body, draft/prerelease values; returns observed release, write evidence, and error. |
|
||
| `ListAssets` | Context and opaque release handle; returns logical remote assets or error. |
|
||
| `OpenAsset` | Context and opaque asset handle; returns `io.ReadCloser` or error. |
|
||
| `UploadAsset` | Context, opaque release handle, filename, and `io.Reader`; returns write evidence and error. |
|
||
|
||
Logical release data contains the URL, full tag, title, body, draft/prerelease
|
||
flags, and an opaque handle. Remote asset data contains filename, reported size,
|
||
and an opaque handle. Use internal `any` handle fields with private concrete
|
||
Gitea handle values. Only the creating adapter interprets them. Keep numeric IDs
|
||
and download URLs in those private values; the shared workflow performs no
|
||
integer-ID checks or URL construction.
|
||
|
||
Write evidence carries an `Attempted` flag and a disposition: not attempted,
|
||
accepted, rejected, conflict, or uncertain. Accepted means the adapter received
|
||
and decoded the required protocol acknowledgment; shared release-content checks
|
||
still apply. A known rejection differs from an uncertain outcome. Carry this
|
||
evidence even with an error, so successful reconciliation can retain earlier
|
||
write history. Record an attempted write when it is handed to the transport,
|
||
consistent with the existing possibly-successful-request handling; this is not
|
||
a claim that the server received it.
|
||
|
||
Neutral failure kinds cover the existing invalid, not-found, unauthorized,
|
||
conflict, malformed, unverifiable, transport, rejected, and unknown distinctions.
|
||
Retain underlying causes through wrapping/`Unwrap` or `errors.Join`. Gitea HTTP
|
||
status and operation details belong to the adapter's diagnostic cause. Shared
|
||
recovery uses the neutral kind and write evidence, with no HTTP status branches
|
||
or Gitea error assertions. Credentials stay out of errors and results.
|
||
|
||
The shared caller closes streams returned by `OpenAsset`, including on read
|
||
failure. For uploads it opens/closes the local file or supplies an inline
|
||
manifest reader; the adapter borrows that reader for the call and finishes its
|
||
multipart writer/pipe work before returning. Retain cancellation propagation
|
||
and cleanup rather than introducing detached recovery contexts, timeouts, or
|
||
buffering of complete binaries.
|
||
|
||
## Stage 1: Establish the internal backend contract
|
||
|
||
Status: complete.
|
||
|
||
1. Add `internal/forge` with the interface and logical values specified above.
|
||
Define preflight classifications, neutral failures, and write-evidence types
|
||
with comments about not-found, accepted acknowledgments, uncertain writes,
|
||
opaque handles, and
|
||
stream ownership. Use ordinary Go values and error wrapping.
|
||
2. Keep this package concerned with the delivery seam; production backend
|
||
selection belongs to the facade. Avoid a registry, capability negotiation,
|
||
public interfaces, or additional forge implementations in this work.
|
||
3. Identify the existing Gitea policy types replaced by later stages:
|
||
`Request`, `Result`, `ExpectedAsset`, `Inspection`, asset identities/states,
|
||
upload results, and failure assertions in `internal/delivery`. Assign their
|
||
replacement ownership as above rather than reproducing the whole Gitea
|
||
model under new names.
|
||
|
||
Result: an internal contract implemented independently of the public facade and
|
||
delivery policy. Type-check the new package when available. Test nontrivial
|
||
error behavior where useful; recovery is tested through the shared workflow.
|
||
|
||
## Stage 2: Move local asset and manifest mechanics
|
||
|
||
Status: complete.
|
||
|
||
1. Move `ExpectedAsset` and the generic work in `BuildManifest`,
|
||
`validateExpectedAssets`, and local verification from `internal/gitea` to
|
||
`internal/artifact`. Keep the filename, SHA-256, size, path, and inline-content
|
||
representation and existing accepted inputs.
|
||
2. Retain `artifact.ManifestFilename`, sorted complete manifest generation, its
|
||
byte format, duplicate/name/digest validation, and the empty-set result that
|
||
produces no manifest.
|
||
3. Adapt `internal/delivery/assets.go` and build validation to shared types.
|
||
Keep target/name correspondence, captured module/tag/commit binding,
|
||
`SourceVerified`, regular-file checks, and prebuilt output ownership. Keep
|
||
build results and the private receipt format unchanged.
|
||
4. Move/consolidate manifest and local-content tests with these responsibilities.
|
||
Preserve rejection of same-size local tampering.
|
||
|
||
Result: local assets are declared and verified independently of Gitea. Retain
|
||
one full local size/digest preflight before hosted writes and reuse it for
|
||
uploads; subsequent transport reads stream content without a second full
|
||
preflight. This preserves existing efficiency/integrity choices rather than
|
||
adding a guarantee against concurrent file replacement.
|
||
|
||
## Stage 3: Extract Gitea read operations
|
||
|
||
Status: complete.
|
||
|
||
1. Adapt the Gitea client into a backend configured with its private destination
|
||
and optional HTTP client. Implement `TagCommit`, `FindRelease`, `ListAssets`,
|
||
and `OpenAsset` using the existing HTTP helpers and routes.
|
||
2. Keep Gitea address/token rules, full-tag escaping, JSON handling, attachment
|
||
metadata validation, and HTTP status interpretation here. Map a release
|
||
lookup's 404 to neutral not-found; a missing hosted tag remains a failure to
|
||
verify source. Preserve operation-specific checks rather than applying
|
||
create-response requirements to every read.
|
||
3. Split `downloadHash` so the adapter opens the download stream and generic
|
||
delivery hashes it. Keep service-origin token forwarding, cross-origin
|
||
downloads without that token, redirect traversal, and response cleanup with
|
||
Gitea. Preserve current listing behavior; extracting the boundary does not
|
||
introduce pagination or a new response-completeness guarantee.
|
||
4. Retain local HTTP tests for routes, authentication, escaped tags, metadata
|
||
decoding, malformed lists, redirects, and unreadable assets. Adapt tests to
|
||
the read operations; shared comparison tests move in Stage 7.
|
||
|
||
Result: backend reads expose observations and streams. Content equality, tag
|
||
comparison, page acceptance, and delivery outcomes belong to shared policy.
|
||
|
||
## Stage 4: Implement read-only Gitea credential preflight
|
||
|
||
Status: complete.
|
||
|
||
1. Implement backend `Preflight` with local destination/token validation and
|
||
authenticated repository-scoped reads. Perform no source/tag checks here so
|
||
the same probe works before a release tag exists.
|
||
2. Resolve the configured repository with `GET /repos/{owner}/{repo}`, then
|
||
use its ID with the authenticated `GET /repositories/{id}` route. Validate
|
||
the required repository identity and successful response shape. The second
|
||
route requires authentication and repository scope, so public anonymous
|
||
repository access alone cannot satisfy preflight. Keep headers, IDs, and
|
||
route details within Gitea. See the upstream
|
||
[route definitions](https://github.com/go-gitea/gitea/blob/release/v1.26/routers/api/v1/api.go).
|
||
3. Interpret reliable release/asset permission evidence when available. Gitea's
|
||
basic `permissions.push` describes code pushes, and a successful repository
|
||
GET does not establish `write:repository` token scope. Treat unexposed
|
||
release-write/token-scope evidence as unverified. Do not equate absent
|
||
metadata with denial or add `/user` probes requiring unrelated user scope.
|
||
The upstream [repository model](https://github.com/go-gitea/gitea/blob/release/v1.26/modules/structs/repo.go)
|
||
and [scope documentation](https://docs.gitea.com/development/api-usage/)
|
||
describe those distinctions. Keep later write authorization authoritative.
|
||
4. Classify missing/blank credentials locally, server-rejected authentication,
|
||
permission denial, inaccessible/hidden destinations, and unavailable or
|
||
malformed verification responses. Preserve cancellation and useful HTTP
|
||
causes without including the token. Unsupported/malformed destination
|
||
settings retain actionable local configuration errors.
|
||
5. Use a local HTTP fixture to cover accepted repository-scoped credentials,
|
||
invalid tokens, denied/missing repositories, service/decoding failure, and
|
||
cancellation. Demonstrate that anonymous public access cannot pass the
|
||
authenticated step and that unexposed write scopes are not claimed as
|
||
verified or treated as a new failure. Assert read-only behavior at this seam.
|
||
|
||
Result: the backend checks authentication and repository access before costly
|
||
delivery work and accurately represents the limits of available permission
|
||
evidence. It uses no extra account/admin credentials or destructive probe.
|
||
|
||
## Stage 5: Extract Gitea write operations and evidence
|
||
|
||
Status: complete.
|
||
|
||
1. Implement `CreateRelease` from the current release POST and `UploadAsset`
|
||
from multipart upload. Keep explicit target commit, stable flags, full note,
|
||
query encoding, attachment field, and token header behavior. Protocol codecs
|
||
and private IDs remain here.
|
||
2. Populate attempted-write evidence on each path. Translate the existing
|
||
`shouldReconcileWrite` triggers into neutral dispositions: HTTP conflict is
|
||
conflict; server errors, transport interruption, cancellation/deadline, and
|
||
malformed acknowledgments are uncertain; definitive other rejections remain
|
||
rejected. Preserve causes and HTTP details. Local failures before transport
|
||
are not attempted. Shared policy decides how to recover.
|
||
3. Validate Gitea acknowledgments here, including positive IDs and the uploaded
|
||
asset's selected filename. Leave requested release tag/title/body/stability
|
||
comparison to Stage 6. A decoded acknowledgment that fails shared comparison
|
||
can still require reconciliation.
|
||
4. Accept a borrowed content reader for upload. Move file/inline-reader selection
|
||
to shared code and preserve multipart streaming, pipe closure, writer
|
||
completion, response cleanup, and context cancellation without an extra
|
||
content pass.
|
||
5. Keep HTTP tests for request bodies, uploads, malformed acknowledgments, known
|
||
rejections, ambiguous writes, and cancellation at this boundary. Recovery
|
||
orchestration tests move with policy in Stages 6 and 7.
|
||
|
||
Result: individual writes return evidence. Follow-up lookups, content comparison,
|
||
and continuation decisions belong to shared delivery. Remove the adapter's old
|
||
orchestration as its callers move rather than retaining a parallel policy path.
|
||
|
||
## Stage 6: Move hosted page policy and recovery
|
||
|
||
Status: complete.
|
||
|
||
1. Add shared page coordination in `internal/delivery` using `forge.Backend`.
|
||
After credential preflight and local source/build verification, obtain the
|
||
hosted full tag's commit and compare it with the captured commit before
|
||
page writes. Find the
|
||
release, accepting the same full tag/body/stable non-draft content and
|
||
retaining an existing title. Only a missing release triggers create.
|
||
2. Supply the full note and H1 title to `CreateRelease`. Apply shared comparison
|
||
to a successful create response, including its requested title. Reconcile
|
||
an inconsistent response as the existing client does.
|
||
3. Move create recovery out of `EnsureRelease`. Preserve the current single
|
||
follow-up lookup for a conflict or uncertain create:
|
||
|
||
| Follow-up observation | Result |
|
||
| --- | --- |
|
||
| Matching existing page | Accept; retain the earlier write attempt. |
|
||
| Different page | Conflict. |
|
||
| Missing after conflict | Conflict. |
|
||
| Missing after uncertain write | Unknown. |
|
||
| Result cannot be established | Unknown; retain write and inspection causes. |
|
||
|
||
4. Preserve known/read-only failures as distinct from unknown writes. Retain
|
||
resolved source identity, confirmed URL, and write history. A later asset
|
||
inspection failure after confirmed page-write progress reports partial
|
||
progress. Page-only delivery succeeds without listing/uploading assets or
|
||
creating a manifest.
|
||
5. Move page policy cases into shared tests using a small controlled backend:
|
||
matching content, conflicts, missing/wrong tag, ambiguous create recovery,
|
||
and recovered-create history. Keep wire assertions in adapter tests.
|
||
|
||
Result: page behavior runs through the seam. Current Gitea recovery remains
|
||
unchanged; this does not promise a fixed HTTP request count for future logical
|
||
backend methods.
|
||
|
||
## Stage 7: Move remote asset comparison and upload recovery
|
||
|
||
Status: complete.
|
||
|
||
1. Move inspections, asset states/identities, upload aggregation, ordering,
|
||
and recovery into `internal/delivery`. Use `ListAssets` and `OpenAsset` for
|
||
streamed SHA-256 comparison. Retain filename grouping, duplicate-name
|
||
conflicts, digest comparison, unrelated asset preservation, and unverifiable
|
||
content classification. Reported size alone remains insufficient for equality.
|
||
2. Retain complete-manifest comparison, acceptance of a matching manifest when
|
||
binaries are missing, and rejection of a subset/different manifest. Add no
|
||
independent remote-size acceptance rule.
|
||
3. Preflight declarations before uploads. Matching assets stay matching;
|
||
conflicts stop with conflict; unverifiable reads stop with not-attempted
|
||
asset work, upgraded to partial on confirmed page-write progress. Whole-list
|
||
read failures retain existing uncertain asset observations without becoming
|
||
unknown-write outcomes.
|
||
4. Upload only missing assets in filename order with `SHA256SUMS` last. Open
|
||
content through the artifact representation and close it after the borrowed
|
||
upload call. Reuse Stage 2 verification. Acknowledged uploads move from pending
|
||
to uploaded.
|
||
5. On conflict or uncertain upload, perform the existing single list/content
|
||
reconciliation for that asset. Matching bytes become matching; differing
|
||
bytes become conflicting; missing after conflict remains conflict; missing
|
||
after uncertain write or an unreadable result becomes unknown/uncertain.
|
||
Stop on unresolved/conflicting outcomes and retain later known-missing assets
|
||
as pending. Keep reconciliation free of repeated POSTs.
|
||
6. Preserve disjoint current observations, earlier successful assets, and public
|
||
states. Definitive upload failure retains partial progress; early failures
|
||
can leave declarations unreported. A new invocation re-inspects remote state
|
||
and resumes only missing work.
|
||
7. Move comparison, manifest, partial retry, and category tests here. Use a small
|
||
backend double for controlled failures, with representative assembled HTTP
|
||
coverage instead of duplicating every policy case at both layers.
|
||
|
||
Result: shared code owns asset policy/recovery. Remove the former Gitea
|
||
`InspectAssets`, `UploadMissing`, and `UploadVerifiedMissing` entry points when
|
||
their callers/tests move; keep transport helpers needed by the backend. These
|
||
internal entry points have no public compatibility obligation.
|
||
|
||
## Stage 8: Connect the neutral facade and CLI
|
||
|
||
Status: pending.
|
||
|
||
1. Implement the public declarations/conversions in Selected design. Replace
|
||
current `GiteaDestination` uses. The private facade factory switches on the
|
||
explicit forge and constructs Gitea; invalid selection returns the described
|
||
early result.
|
||
2. Implement `PreflightDelivery` and `DeliveryPreflightError` conversions using
|
||
that same backend factory and preflight implementation. Support destination
|
||
checking without a repository checkout or published tag. Preserve causes
|
||
with `Unwrap` and keep all exported named types facade-owned.
|
||
3. Change the internal delivery request to receive the backend. Replace Gitea
|
||
asset/error references in request/result conversion and build validation.
|
||
Pass delivery's single captured module/source identity through its existing
|
||
workflow. Retain local source rechecks, temporary output cleanup, and
|
||
prebuilt output ownership. Invoke backend preflight after cheap local checks
|
||
and before managed builds/full artifact hashing. Convert its failures to
|
||
the facade error and retain `not_attempted` delivery state.
|
||
4. Add `Forge` to CLI delivery settings with JSON key `forge`. Validate selection
|
||
during delivery adaptation before credentials or subsequent delivery work,
|
||
returning status 2 for invalid selection. Map the facade's supported value;
|
||
preserve strict decoding and non-delivery behavior.
|
||
5. Update `deliveryDestination`, `deliverWithDestination`, ordinary delivery,
|
||
and CI delivery. Retain tagged profile loading, module/tag checks, dependency
|
||
preparation, receipt binding, and output/exit classification. Keep token
|
||
resolution in the CLI with current precedence and Gitea environment default.
|
||
For binary CI, invoke `PreflightDelivery` after tagged profile/credential
|
||
loading and before dependency preparation. Ordinary and page-only delivery
|
||
rely on automatic library preflight; subsequent binary CI delivery rechecks
|
||
after dependency preparation. Apply the preflight exit classifications above.
|
||
6. Add `"forge": "gitea"` to ReleaseKit's profile, maintained delivery profiles,
|
||
examples, and active test fixtures. Check/build-only profiles can keep
|
||
omitting delivery. Keep token names, file paths, and Woodpecker secret mappings.
|
||
|
||
Result: both interfaces select Gitea explicitly through a neutral destination
|
||
and share generic orchestration and automatic credential preflight. CI checkout
|
||
preparation retains its earlier position because it establishes which tagged
|
||
profile is authoritative; credential verification precedes application downloads.
|
||
|
||
## Stage 9: Complete regression coverage and dependency checks
|
||
|
||
Status: pending.
|
||
|
||
1. Finish adapting facade, CLI, HTTP fixture, and benchmark callers. Retain
|
||
root/nested/major-module identities, page-only delivery, managed/prebuilt
|
||
binaries, tagged retries, source checks, partial/conflict/unknown reporting,
|
||
and cleanup coverage.
|
||
2. Add focused API/CLI selection cases: explicit Gitea succeeds; omitted, blank,
|
||
and unsupported values fail; the URL does not infer a backend. For CLI errors,
|
||
assert status/semantic diagnostics and that token access, dependency
|
||
preparation, and hosted work were not reached. Reuse existing non-delivery
|
||
tests to show those commands still need neither selection nor credentials.
|
||
3. Cover automatic and standalone preflight with controlled failures: library
|
||
and ordinary CLI failures precede builds/full artifact hashing and writes;
|
||
binary CI failures precede dependency downloads; page-only CI still checks
|
||
credentials; standalone checks need no checkout or tag. Assert typed error
|
||
kinds, causes, CLI status, and `not_attempted` even on unavailable service.
|
||
Verify unavailable permission metadata alone is not failure and no preflight
|
||
path performs test writes. Update affected "before hosted requests" fixtures
|
||
to permit credential reads while retaining assertions that local verification
|
||
precedes writes. Keep `check`, `build`, and source `publish` independent of
|
||
hosted credential preflight and preserve the existing native Git guards.
|
||
4. Use controlled backend tests to demonstrate shared page/asset policy without
|
||
Gitea imports. Consolidate obsolete client-policy tests rather than retaining
|
||
wrappers. Keep representative real-Gitea HTTP assembly tests for page
|
||
creation and binary delivery/retry, exercising conversions and opaque handles.
|
||
5. Extend `internal/apicheck` with a focused check that shared delivery, forge
|
||
contracts, and artifact mechanics have no production dependency path to
|
||
`internal/gitea`. Preserve export ownership/runtime checks, keeping new
|
||
delivery-related packages out of the runtime dependency graph through the
|
||
existing checking mechanism. Add a small violation fixture following current
|
||
apicheck tests.
|
||
6. Review stream/error paths for cancellation identity, reader closure,
|
||
multipart worker completion, and causes. Reuse cancellation tests; add a
|
||
narrow regression for a gap introduced by moved ownership. Keep the default
|
||
suite offline and credential-free.
|
||
|
||
Result: selected requirements have meaningful coverage and clear test owners.
|
||
Run relevant package tests once assembled; Stage 10 owns the final full checks.
|
||
|
||
## Stage 10: Document the cutover and verify the sprint
|
||
|
||
Status: pending.
|
||
|
||
1. Add the next sequential ADR (currently `0006`) using the documentation
|
||
policy's lightweight Nygard format. Record the shared-policy/backend boundary,
|
||
neutral facade-owned destination, explicit selection, credential preflight
|
||
ownership and evidence limits, alternatives, and consequences. Keep progress
|
||
in these roadmaps.
|
||
2. Update GoDoc, `docs/config.md`, `docs/cli.md`, and
|
||
`docs/consumers/delivery.md` for the neutral destination, selection, automatic
|
||
preflight, callable preflight, typed failures, and CLI exit classifications.
|
||
Update current README/runbook/example snippets where affected. Keep Gitea
|
||
wire/authentication details in `docs/integrations/gitea.md`; describe shared
|
||
coordination in internal documentation linked from `docs/internal/overview.md`.
|
||
Align architecture policy wording with the implemented boundary while
|
||
preserving its broader constraints.
|
||
Document the authenticated repository probe and unverified write scopes in
|
||
the Gitea guide. Describe standalone preflight as a caller option; preserve
|
||
existing source-publication completion and credential requirements.
|
||
3. Write `docs/releases/v0.6.0.md`, the next minor release note, explaining the
|
||
features, compatibility impact, and public type/profile migration. Follow
|
||
the [release policy](../policy/release.md) and
|
||
[runbook](../release.md) for note/footer requirements. Explain the unchanged
|
||
Gitea token default and profile updates before tagging: CI reads the tagged profile.
|
||
Include fail-fast credential checks, additional read-only requests, failure
|
||
classifications, and the limited meaning of successful preflight. Explain
|
||
that local artifact verification now follows credential reads and still
|
||
precedes hosted writes.
|
||
Preserve historical notes. Prepare documentation here; tagging, pushing,
|
||
and publication remain separate release work.
|
||
4. Check maintained JSON/Go examples, profile-generating fixtures, and Woodpecker
|
||
tests for explicit selection. Search active code/docs for obsolete public
|
||
type uses and implicit-selection instructions, distinguishing history and
|
||
migration examples. Verify documentation links, fragments, and whitespace.
|
||
5. Run `go test ./...` and `go run ./internal/apicheck` from the repository root
|
||
with prepared local dependencies and offline module/toolchain access. These
|
||
include representative CLI/consumer workflows. Reuse successful checks for
|
||
unchanged content; fix failures and rerun affected checks. No live forge,
|
||
real token, CI run, or consumer pilot is required for sprint completion.
|
||
6. Review the final diff and dependency flow against every feature target and
|
||
stage. Verify generic policy has no Gitea dependency; only the adapter
|
||
interprets its handles/statuses; the assembled workflow retains recovery
|
||
outcomes; current delivery profiles explicitly select Gitea; migration
|
||
instructions match the API/configuration; credential failures stop before
|
||
costly delivery work; source publication remains independent; local content
|
||
verification is reused before writes; and comparison/transport remain streamed.
|
||
7. Mark stages complete as verified. Commit completed work under the agent
|
||
policy, report validation and the final commit, and leave a clean workspace.
|
||
Retain accurate completed plans for later release-preparation cleanup.
|
||
|
||
Result: the initial refactor, migration guidance, and offline verification are
|
||
complete. All stages proceed to this end state within the sprint.
|