Repository navigation
fix(ci): resolve deploy environment from inputs, not github.event_name #1809
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -15,6 +15,15 @@ | |
|
|
||
| name: Deploy to All Clouds | ||
|
|
||
| # Adding a trigger here, or a second caller of the deploy-* workflows, means | ||
| # revisiting the `prepare` comments in deploy-azure.yml, deploy-gcp.yml and | ||
| # deploy-aws-lambda.yml. Since #1805 those three resolve their environment from | ||
| # `inputs.environment` and fall back on `github.event_name`, which inside a | ||
| # reusable workflow is whatever event started THIS run. They are correct today | ||
| # only because this workflow is their only caller, has no `push` trigger, and | ||
| # allowlists the environment it passes. A `push:` trigger here would make | ||
| # Azure and GCP silently resolve dev for a caller that asked for something | ||
| # else, which is #1805 restored. | ||
| on: | ||
| workflow_dispatch: | ||
| inputs: | ||
|
|
@@ -56,13 +65,36 @@ jobs: | |
| steps: | ||
| - name: Set environment | ||
| id: set-env | ||
| env: | ||
| # This workflow is always the entry point of its own run, never a | ||
| # reusable one, so `github.event_name` here really is the trigger that | ||
| # started it. The called workflows cannot rely on that and read | ||
| # `inputs.environment` instead (issue #1805). | ||
| EVENT_NAME: ${{ github.event_name }} | ||
| INPUT_ENVIRONMENT: ${{ inputs.environment }} | ||
| run: | | ||
| if [[ "${{ github.event_name }}" == "release" ]]; then | ||
| echo "environment=prod" >> $GITHUB_OUTPUT | ||
| set -euo pipefail | ||
| INPUT_ENVIRONMENT="${INPUT_ENVIRONMENT:-}" | ||
|
|
||
| if [ "$EVENT_NAME" = release ]; then | ||
| ENVIRONMENT=prod | ||
| else | ||
| echo "environment=${{ inputs.environment }}" >> $GITHUB_OUTPUT | ||
| ENVIRONMENT="$INPUT_ENVIRONMENT" | ||
| fi | ||
|
|
||
| # Every called workflow takes this value verbatim, so an empty or | ||
| # unknown value has to stop the fan-out here rather than reach four | ||
| # deployments. | ||
| case "$ENVIRONMENT" in | ||
| dev|staging|prod) ;; | ||
| *) | ||
| echo "::error::Refusing unknown environment: '$ENVIRONMENT'" | ||
| exit 1 | ||
| ;; | ||
| esac | ||
|
|
||
| echo "environment=$ENVIRONMENT" >> "$GITHUB_OUTPUT" | ||
|
|
||
| - name: Set cloud providers | ||
| id: set-clouds | ||
| run: | | ||
|
|
@@ -166,8 +198,9 @@ jobs: | |
| # Deliberately carries no `concurrency` (#1801). The Terraform state guard is | ||
| # the group on the called workflow's own build-and-deploy job, which runs as a | ||
| # real job of this run and is serialized there. That group is derived from the | ||
| # called workflow's own `prepare` output, which is not necessarily the | ||
| # `environment` computed above, so do not assume the two agree. | ||
| # called workflow's own `prepare` output, which since #1805 is the | ||
| # `environment` computed above verbatim: `prepare` takes the non-empty input | ||
| # it is passed and fails the run rather than substituting a default. | ||
| # | ||
| # Putting that same group on this caller job would deadlock: this job would | ||
| # hold the group while waiting on the inner job queued behind it. GitHub | ||
|
|
@@ -263,7 +296,22 @@ jobs: | |
| run: | | ||
| FAILED=false | ||
|
|
||
| if [[ "${{ needs.deploy-aws-lambda.result }}" == "failure" ]] || \ | ||
| # determine-deployment is checked for anything other than success, not | ||
| # just "failure". When it stops the run the four deploy jobs are | ||
| # SKIPPED rather than failed, so testing only those would report "all | ||
| # deployments completed successfully" for a run that deployed nothing. | ||
| # | ||
| # The four deploy jobs are deliberately still tested for "failure" | ||
| # only. A CANCELLED run leaves them `cancelled` and reaches the | ||
| # success line, which is the same false report. That predates this | ||
| # change, so it is tracked in #1810 rather than fixed here. | ||
| # | ||
| # Note this step is the only success-by-default check in the repo. All | ||
| # four per-cloud `summary` jobs allowlist on `== "success"` instead, | ||
| # so an unenumerated result falls to their failure branch and errs | ||
| # safe. This denylist is the outlier, not the pattern. | ||
| if [[ "${{ needs.determine-deployment.result }}" != "success" ]] || \ | ||
| [[ "${{ needs.deploy-aws-lambda.result }}" == "failure" ]] || \ | ||
| [[ "${{ needs.deploy-aws-fargate.result }}" == "failure" ]] || \ | ||
| [[ "${{ needs.deploy-gcp.result }}" == "failure" ]] || \ | ||
| [[ "${{ needs.deploy-azure.result }}" == "failure" ]]; then | ||
|
Comment on lines
+313
to
317
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win 🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -euo pipefail
sed -n '286,309p' .github/workflows/deploy-all.yml
# Validate in GitHub Actions with a selected reusable deployment job that exits
# as cancelled. Expected: the `notify` job fails and does not emit the success
# summary.Repository: LeanerCloud/CUDly Length of output: 1342 🏁 Script executed: #!/bin/bash
set -euo pipefail
printf '%s\n' '--- deployment job declarations and result aggregation ---'
sed -n '1,120p' .github/workflows/deploy-all.yml
sed -n '120,220p' .github/workflows/deploy-all.yml
sed -n '250,315p' .github/workflows/deploy-all.yml
printf '%s\n' '--- all references to deployment selectors and job conditions ---'
rg -n -C 3 'deploy-(aws-lambda|aws-fargate|gcp|azure)|determine-deployment|needs\..*\.result|if:' .github/workflows/deploy-all.ymlRepository: LeanerCloud/CUDly Length of output: 20448 🏁 Script executed: #!/bin/bash
set -euo pipefail
python3 - <<'PY'
from itertools import product
selectors = {
"aws-lambda": {"all", "aws-only", "aws-gcp", "aws-azure"},
"aws-fargate": set(),
"gcp": {"all", "gcp-only", "aws-gcp", "gcp-azure"},
"azure": {"all", "azure-only", "aws-azure", "gcp-azure"},
}
strategies = ["all", "aws-only", "gcp-only", "azure-only", "aws-gcp", "aws-azure", "gcp-azure"]
results = ["success", "failure", "cancelled", "skipped"]
for strategy in strategies:
selected = [name for name, enabled in selectors.items() if strategy in enabled]
false_positive = []
for statuses in product(results, repeat=len(selected)):
current = all(status != "failure" for status in statuses)
proposed = all(status == "success" for status in statuses)
if current and not proposed:
false_positive.append(dict(zip(selected, statuses)))
print(strategy, "selected=", selected, "current-success-but-not-proposed=", false_positive[:8],
"count=", len(false_positive))
PY
printf '%s\n' '--- reusable workflow job-level conditions and cancellation-sensitive constructs ---'
for file in $(fd -i 'deploy-(aws-lambda|aws-fargate|gcp|azure)\.yml$' .github/workflows); do
echo "### $file"
rg -n -C 2 '^[[:space:]]+(if:|needs:|concurrency:)|cancel-in-progress|always\(\)|failure\(\)|cancelled\(\)' "$file" || true
doneRepository: LeanerCloud/CUDly Length of output: 7179 🌐 Web query:
💡 Result: In GitHub Actions, you can determine the result of a job in a reusable workflow using the jobs context, which is available within the reusable workflow itself [1][2]. The jobs.<job_id>.result property provides the status of a specific job and can return one of the following string values: success, failure, cancelled, or skipped [1][2]. Regarding the context in a caller workflow: 1. Caller Workflow Limitations: When a reusable workflow is triggered, the caller workflow treats the entire job that calls the reusable workflow as a single unit [3]. You can access the outputs of the reusable workflow, but the individual internal job statuses (like whether a specific internal job was cancelled or skipped) are not automatically exposed as properties in the caller workflow's jobs context [1][4]. 2. Handling Skipped or Cancelled States: If you need to trigger logic in a caller workflow based on the specific outcome of an internal job within a reusable workflow, you must explicitly define outputs in the reusable workflow [3][4]. You can set these outputs to reflect the result of internal jobs using expressions like ${{ jobs.<job_id>.result }} [1][4]. 3. Concurrency and Cancellation: If you use concurrency with cancel-in-progress: true in both the caller and the called reusable workflow, ensure you are not using the same concurrency group name, as this may lead to the caller workflow being prematurely cancelled [5][6]. To cancel sub-workflows, you can apply concurrency settings directly within the reusable workflow definition [7]. For debugging purposes, you can inspect the available information by printing the context to the logs using ${{ toJSON(jobs) }} within the reusable workflow [4]. Citations:
Treat cancelled selected deployments as unsuccessful. The current check flags only 🤖 Prompt for AI Agents
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Valid finding, and already tracked as #1810. Deliberately out of scope for this PR. You are right about the substance: the It is excluded here for one reason: this PR did not cause it. The four Some context recorded on #1810 that is worth having before anyone picks it up, since two of these were wrong when first written:
Leaving the code unchanged here; the gap is documented in-place with a pointer to #1810.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
The cancellation gap is valid, but it predates this PR and is tracked in ✏️ Learnings added
🧠 Learnings usedYou are interacting with an AI system. |
||
|
|
@@ -272,7 +320,7 @@ jobs: | |
|
|
||
| if [ "$FAILED" = true ]; then | ||
| echo "" >> $GITHUB_STEP_SUMMARY | ||
| echo "❌ **One or more deployments failed. Check individual job logs.**" >> $GITHUB_STEP_SUMMARY | ||
| echo "❌ **Deployment did not complete successfully. Check individual job logs.**" >> $GITHUB_STEP_SUMMARY | ||
| exit 1 | ||
| else | ||
| echo "" >> $GITHUB_STEP_SUMMARY | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.