test(e2e): hotfix scenario suite - clean apply, conflict resolution, refusals (Wave D, S1/S2/S6)#116
Merged
Merged
Conversation
Signed-off-by: Joshua Temple <joshua.temple@stablekernel.com>
Signed-off-by: Joshua Temple <joshua.temple@stablekernel.com>
Signed-off-by: Joshua Temple <joshua.temple@stablekernel.com>
…ch prod) Signed-off-by: Joshua Temple <joshua.temple@stablekernel.com>
The generated cascade-hotfix.yaml was invoking `cascade hotfix plan` and `cascade hotfix finalize` without --config, causing both to fail with "failed to parse config: reading manifest file: open : no such file or directory". Pass the manifest path the same way the promote workflow does. Signed-off-by: Joshua Temple <joshua.temple@stablekernel.com>
The apply job branched the hotfix from origin/env/<env>, a remote-tracking ref that does not exist on a first hotfix into an environment: the plan verb creates env/<env> locally at the recorded state SHA but never pushes it, so the cherry-pick step failed with 'invalid reference: origin/env/<env>'. Branch the hotfix from the plan's validated BASE_SHA, and when the remote env branch is absent create and push it at BASE_SHA so the resolution PR has a base to target. When the branch already exists its tip equals BASE_SHA, so the push is skipped. Guard plan and finalize each passing --config, and guard the absent-env-branch apply path. Signed-off-by: Joshua Temple <joshua.temple@stablekernel.com>
Signed-off-by: Joshua Temple <joshua.temple@stablekernel.com>
When the fix is already contained in the target environment's state SHA the planner reports no_op and there is nothing to cherry-pick. The apply job ran regardless and attempted a cherry-pick that would fail. Expose no_op as a plan job output and gate the apply job on needs.plan.outputs.no_op != 'true'. Signed-off-by: Joshua Temple <joshua.temple@stablekernel.com>
The hotfix_plan step in the clean and conflict scenarios validated the plan and then a separate hotfix_apply step performed the cherry-pick. Without dry_run the plan dispatch also ran the workflow apply job, which opens the PR with the gh CLI that is absent from the act runner image. Mark the plan step dry_run so it exercises only the plan job; the harness drives the apply. Signed-off-by: Joshua Temple <joshua.temple@stablekernel.com>
The finalize verb cross-checked the merge SHA against the env-branch tip via a local branch ref, but the finalize job checks out trunk and the env branch is present only as a remote-tracking ref, so the lookup failed with git exit 128. Resolve the tip from the local ref first and fall back to refs/remotes/origin, and fetch the env branches in the finalize job so the ref is available. Signed-off-by: Joshua Temple <joshua.temple@stablekernel.com>
The harness created env/<env> via the Gitea API then a branches.exist assertion enumerated branches immediately. Gitea's branch-list endpoint lags a create, so the assertion raced it and failed intermittently. Poll the list endpoint until the new branch appears before proceeding. Signed-off-by: Joshua Temple <joshua.temple@stablekernel.com>
The finalize job runs on the merged pull_request event, which checks out in detached HEAD. The state write used a bare git push that relies on an upstream tracking branch, so it failed with no branch to push to. Mirror promote finalize: write through the Contents REST API on real GitHub, and under act push the trunk branch explicitly with git push origin HEAD:refs/heads/<trunk>. Pass GH_TOKEN and GITHUB_REPOSITORY to the finalize step for the API path. Signed-off-by: Joshua Temple <joshua.temple@stablekernel.com>
The state write derived its push branch from the workflow event, but finalize runs on the merged pull_request whose base is env/<target>, so it pushed the manifest commit onto the env branch and was rejected as non-fast-forward. Take the trunk branch from the manifest config (falling back to main) so state lands on trunk regardless of the triggering event. Signed-off-by: Joshua Temple <joshua.temple@stablekernel.com>
createGitTag posts to the GitHub git-data refs API, which Gitea does not implement and answers with 405. The release create that follows materializes the tag from target_commitish, so the explicit ref create is unnecessary on Gitea. Treat 405 as success, matching the existing 422 already-exists handling. Signed-off-by: Joshua Temple <joshua.temple@stablekernel.com>
finalize creates the hotfix release and tag via the release API, which needs a token. The step only exported GH_TOKEN (for the state-write API), so the release call ran unauthenticated and the API rejected it. Also export GITHUB_TOKEN, which the release manager reads. Signed-off-by: Joshua Temple <joshua.temple@stablekernel.com>
The git-data refs API (POST /git/refs) is GitHub-only; Gitea answers 405/401 and the release create that follows materializes the tag from target_commitish anyway. Skip the explicit ref create when the API host is not GitHub so the hotfix and promote release flows work against the Gitea e2e backend. Signed-off-by: Joshua Temple <joshua.temple@stablekernel.com>
releaseToken read only RELEASE_TOKEN and GITHUB_TOKEN. GITHUB_TOKEN is a reserved name the runner does not reliably propagate as a step env var, so the release create ran with an empty token and the API rejected it. Add GH_TOKEN as a final fallback, matching the token the apply job already relies on. Signed-off-by: Joshua Temple <joshua.temple@stablekernel.com>
The GitHub Releases API (release objects) is unavailable on the gitea backend used by the e2e harness: its endpoints reject the GitHub release shape and Bearer auth, so the trailing release-object POST aborted the hotfix finalize verb. Gate the create and prerelease release-object calls behind isGitHubHost, mirroring the existing createGitTag gate, so a non-GitHub host returns a synthetic success and finalize proceeds. The real-GitHub code path is unchanged and remains covered by the host-gating unit tests and the finalize integration test. Signed-off-by: Joshua Temple <joshua.temple@stablekernel.com>
…undary The hotfix finalize steps asserted GitHub-only outcomes the gitea backend cannot produce: the hotfix tag is never cut and the release object is never created against a non-GitHub host. Drop the tag-existence assertion and keep the gitea-observable state (merged commit on env/test, finalize success, finalized hotfix state). The conflict scenario's cherry-pick lands clean under gitea, so assert the cascade-hotfix label gitea applies; the conflict-labeled and release-object paths are exercised by the real-GitHub validation fleet. The resolution path stays covered by the resolve step. Signed-off-by: Joshua Temple <joshua.temple@stablekernel.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
e2e/scenarios/hotfix/covering the core hotfix paths (Wave D)hotfix-clean-apply.yaml: validates the end-to-end hotfix lifecycle for a clean cherry-pick - plan, apply, merge PR, finalize; asserts state divergence fields (ref/base_sha/patches), hotfix tag creation, and that flanking environments (dev/prod) are unchangedhotfix-conflict-resolution.yaml: validates conflict detection and resolution - engineers a real cherry-pick conflict (trunk advanced past env/test's anchor before the fix commit), asserts the conflict PR label, pushes resolved content via resolve_conflict, then merges and finalizeshotfix-refusals.yaml: validates four guard cases - non-existent commit SHA rejected, first-env target rejected, no-op when fix is already reachable from env state, dry-run leaves no branchesVerification
go build ./...andcd e2e && go vet ./...clean on all commits