Clarify delivery exit statuses by failure phase
This commit is contained in:
71
cmd/releasekit/delivery_status_test.go
Normal file
71
cmd/releasekit/delivery_status_test.go
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"net/http"
|
||||||
|
"net/http/httptest"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"go.maximumdirect.net/releasekit/cmd/releasekit/internal/cli"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestDeliveryFailureStatusesRespectPhase(t *testing.T) {
|
||||||
|
for _, test := range []struct {
|
||||||
|
name, rejectedPath, state string
|
||||||
|
cancelWrite bool
|
||||||
|
status int
|
||||||
|
}{
|
||||||
|
{name: "preflight authorization", rejectedPath: "/api/v1/repos/owner/example", state: "not_attempted", status: 2},
|
||||||
|
{name: "later authorization", rejectedPath: "/api/v1/repos/owner/example/tags/v1.2.3", state: "not_attempted", status: 1},
|
||||||
|
{name: "canceled unresolved write", cancelWrite: true, state: "unknown", status: 3},
|
||||||
|
} {
|
||||||
|
t.Run(test.name, func(t *testing.T) {
|
||||||
|
repository := newCLIRepository(t)
|
||||||
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
|
defer cancel()
|
||||||
|
var commit string
|
||||||
|
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
if r.URL.Path == test.rejectedPath {
|
||||||
|
http.Error(w, "rejected credential", http.StatusUnauthorized)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
switch r.URL.Path {
|
||||||
|
case "/api/v1/repos/owner/example", "/api/v1/repositories/1":
|
||||||
|
_ = json.NewEncoder(w).Encode(map[string]any{"id": 1, "name": "example", "full_name": "owner/example", "owner": map[string]string{"login": "owner"}})
|
||||||
|
case "/api/v1/repos/owner/example/tags/v1.2.3":
|
||||||
|
_ = json.NewEncoder(w).Encode(map[string]any{"commit": map[string]string{"sha": commit}})
|
||||||
|
case "/api/v1/repos/owner/example/releases/tags/v1.2.3":
|
||||||
|
http.NotFound(w, r)
|
||||||
|
case "/api/v1/repos/owner/example/releases":
|
||||||
|
if r.Method != http.MethodPost || !test.cancelWrite {
|
||||||
|
t.Errorf("unexpected release write: %s", r.Method)
|
||||||
|
}
|
||||||
|
cancel()
|
||||||
|
http.Error(w, "unacknowledged write", http.StatusServiceUnavailable)
|
||||||
|
default:
|
||||||
|
t.Errorf("unexpected request: %s", r.URL.Path)
|
||||||
|
http.NotFound(w, r)
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
defer server.Close()
|
||||||
|
writeDeliveryProfile(t, repository, cli.Settings{
|
||||||
|
Product: "Example Product",
|
||||||
|
Delivery: &cli.DeliverySettings{Forge: "gitea", BaseURL: server.URL, Owner: "owner", Repository: "example"},
|
||||||
|
})
|
||||||
|
commit = cliGitOutput(t, repository, "rev-parse", "HEAD")
|
||||||
|
cliGitRun(t, repository, "tag", "v1.2.3")
|
||||||
|
t.Setenv("RELEASEKIT_GITEA_TOKEN", "fixture-token")
|
||||||
|
var stdout, stderr bytes.Buffer
|
||||||
|
status := run(ctx, []string{"deliver", "--repo", repository, "v1.2.3"}, &stdout, &stderr)
|
||||||
|
if status != test.status || !strings.Contains(stderr.String(), "state="+test.state) {
|
||||||
|
t.Fatalf("status=%d stderr=%q, want status %d and state %s", status, stderr.String(), test.status, test.state)
|
||||||
|
}
|
||||||
|
if test.cancelWrite && !strings.Contains(stderr.String(), context.Canceled.Error()) {
|
||||||
|
t.Fatalf("cancellation cause missing: %s", stderr.String())
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
23
docs/cli.md
23
docs/cli.md
@@ -208,10 +208,14 @@ first and then run `deliver --assets DIR` with the token available. The ordinary
|
|||||||
`deliver` command does not download application dependencies or change the
|
`deliver` command does not download application dependencies or change the
|
||||||
checkout.
|
checkout.
|
||||||
|
|
||||||
The command returns 0 for complete delivery, 1 for an unavailable preflight,
|
The command returns 0 for complete delivery, 1 for an unavailable preflight or
|
||||||
cancellation, known delivery failure, conflict, or partial delivery, 2 for
|
a known delivery failure, conflict, or partial delivery, and 2 for usage,
|
||||||
usage, profile, forge-selection, credential, known permission deficiency, or
|
profile, forge-selection, local credential-loading, or classified preflight
|
||||||
inaccessible-destination errors, and 3 when a remote write remains uncertain.
|
configuration/access errors. A remote write whose outcome remains uncertain
|
||||||
|
returns 3, including when cancellation prevents reconciliation. Cancellation
|
||||||
|
without an unresolved write returns 1, including during preflight or
|
||||||
|
preparation. Later authorization failures follow
|
||||||
|
the delivery outcome: known failure returns 1; an unresolved write returns 3.
|
||||||
The result lists matching, uploaded, pending, conflicting, and uncertain assets
|
The result lists matching, uploaded, pending, conflicting, and uncertain assets
|
||||||
as disjoint current observations;
|
as disjoint current observations;
|
||||||
early failures may leave some declared assets unreported. On failure, the CLI
|
early failures may leave some declared assets unreported. On failure, the CLI
|
||||||
@@ -258,11 +262,12 @@ tag arguments. The event ID may identify an annotated tag object; see the
|
|||||||
[delivery guide](consumers/delivery.md#woodpecker-tag-workflows) for resolution
|
[delivery guide](consumers/delivery.md#woodpecker-tag-workflows) for resolution
|
||||||
and workflow preparation. The CLI does not read
|
and workflow preparation. The CLI does not read
|
||||||
provider-specific environment variable names. Checkout and dependency
|
provider-specific environment variable names. Checkout and dependency
|
||||||
preparation failures, unavailable preflight, and cancellation return status 1;
|
preparation failures, unavailable preflight, and cancellation during those
|
||||||
usage, profile, forge-selection, credential, known permission deficiency,
|
steps return status 1. Usage, profile, forge-selection, local credential-loading,
|
||||||
inaccessible-destination, and invalid-version errors return status 2. Final
|
classified preflight configuration/access, and invalid-version errors return
|
||||||
delivery uses the same statuses as `deliver`: 0 for complete, 1 for known
|
status 2. Final delivery uses the same statuses as `deliver`: 0 for complete,
|
||||||
failure, conflict, or partial delivery, and 3 for uncertain remote state.
|
1 for known failure, conflict, or partial delivery, and 3 for uncertain remote
|
||||||
|
state, including when cancellation prevents reconciliation.
|
||||||
|
|
||||||
The maintained module-based tag workflow verifies and checks out the event tag
|
The maintained module-based tag workflow verifies and checks out the event tag
|
||||||
before resolving the consumer module. It builds the ReleaseKit version already
|
before resolving the consumer module. It builds the ReleaseKit version already
|
||||||
|
|||||||
@@ -26,8 +26,11 @@ selection and introduces authenticated, read-only credential preflight.
|
|||||||
establish release-write or asset-write permission.
|
establish release-write or asset-write permission.
|
||||||
- The CLI keeps `RELEASEKIT_GITEA_TOKEN` as its default token environment
|
- The CLI keeps `RELEASEKIT_GITEA_TOKEN` as its default token environment
|
||||||
setting and preserves configured environment/file precedence. Selection,
|
setting and preserves configured environment/file precedence. Selection,
|
||||||
credential, and inaccessible-destination errors return status 2; unavailable
|
local credential-loading, and classified preflight configuration/access
|
||||||
verification and cancellation return status 1.
|
errors return status 2; unavailable preflight and cancellation during
|
||||||
|
preflight/preparation return status 1. Later authorization failures follow
|
||||||
|
delivery outcomes. An unresolved write returns status 3, including when
|
||||||
|
cancellation prevents reconciliation; known delivery failures return 1.
|
||||||
- Binary `ci-deliver` checks credentials before application dependency
|
- Binary `ci-deliver` checks credentials before application dependency
|
||||||
downloads and checks again during delivery. The automatic check now precedes
|
downloads and checks again during delivery. The automatic check now precedes
|
||||||
full local artifact size and digest verification; those checks still finish
|
full local artifact size and digest verification; those checks still finish
|
||||||
|
|||||||
@@ -121,7 +121,13 @@ require a new public package restriction or a broader dependency policy.
|
|||||||
|
|
||||||
## 3. Qualify phase-specific CLI exit-status documentation — P3
|
## 3. Qualify phase-specific CLI exit-status documentation — P3
|
||||||
|
|
||||||
Status: open.
|
Status: complete.
|
||||||
|
|
||||||
|
**Completed:** Qualified the CLI reference and unreleased v0.6.0 note by phase:
|
||||||
|
local loading/classified preflight errors use status 2; later known failures
|
||||||
|
use 1; unresolved writes retain 3 even when canceled. Added a narrow CLI
|
||||||
|
regression for preflight versus later authorization failure and cancellation
|
||||||
|
after an attempted page write. Focused CLI preflight/recovery tests passed.
|
||||||
|
|
||||||
**Evidence:** [CLI exit statuses](../cli.md),
|
**Evidence:** [CLI exit statuses](../cli.md),
|
||||||
[v0.6.0 release note](../releases/v0.6.0.md),
|
[v0.6.0 release note](../releases/v0.6.0.md),
|
||||||
|
|||||||
Reference in New Issue
Block a user