Skip to content

Commit be86d84

Browse files
authored
refactor(workflow): streamline environment promotion process and enhance component tag validation (#98)
1 parent 18d0aa4 commit be86d84

File tree

5 files changed

+319
-354
lines changed

5 files changed

+319
-354
lines changed

.github/workflows/environment-promotion.yml

Lines changed: 157 additions & 189 deletions
Original file line numberDiff line numberDiff line change
@@ -8,35 +8,27 @@ env:
88
GIT_FETCH_DEPTH: 50
99
# Number of characters to use for shortened git commit hashes
1010
# 8 characters is typically enough to ensure uniqueness while keeping hashes readable
11-
GIT_HASH_LENGTH: 8
11+
GIT_HASH_LENGTH: 7
1212
# Charts repository where deployment manifests are stored
1313
CHARTS_REPO: astriaorg/charts-release-test
1414

1515
on:
16-
# Tag-based promotion
17-
push:
18-
tags:
19-
- 'devnet/v*'
20-
- 'testnet/v*'
21-
- 'mainnet/v*'
22-
2316
# Manual trigger for promotions
2417
workflow_dispatch:
2518
inputs:
26-
action:
27-
description: 'Action to perform'
19+
environment:
20+
description: 'Environment to promote to'
2821
required: true
2922
type: choice
3023
options:
31-
- promote-to-devnet
32-
- promote-to-testnet
33-
- promote-to-mainnet
34-
version:
35-
description: 'Version to tag (e.g., v1.2.3)'
36-
required: true
37-
type: string
24+
- testnet
25+
- mainnet
3826
commit_sha:
39-
description: 'Specific commit SHA to promote (defaults to latest build from previous environment)'
27+
description: 'Commit SHA to promote (optional, defaults to HEAD of current branch)'
28+
required: false
29+
type: string
30+
component_tag:
31+
description: 'Component tag to promote (optional, e.g., sequencer-relayer-v1.0.3)'
4032
required: false
4133
type: string
4234

@@ -46,185 +38,161 @@ permissions:
4638
id-token: write # For authenticating to cloud providers
4739

4840
jobs:
49-
# Security check for event source and pull request forks
50-
security_check:
41+
determine-target:
5142
runs-on: ubuntu-latest
5243
outputs:
53-
should_run: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork == false }}
54-
steps:
55-
- run: echo "Security check passed - this is a push event or the pull request is from the same repository"
56-
57-
# Determine commit to promote for DevNet
58-
determine-devnet-commit:
59-
needs: security_check
60-
if: |
61-
needs.security_check.outputs.should_run &&
62-
((github.event_name == 'push' && startsWith(github.ref, 'refs/tags/devnet/')) ||
63-
(github.event_name == 'workflow_dispatch' && github.event.inputs.action == 'promote-to-devnet'))
64-
uses: ./.github/workflows/reusable-determine-commit.yml
65-
with:
66-
environment: 'devnet'
67-
commit_sha: ${{ github.event.inputs.commit_sha }}
68-
version: ${{ github.event.inputs.version }}
69-
70-
# Sync charts for DevNet
71-
sync-devnet-charts:
72-
needs: determine-devnet-commit
73-
if: |
74-
needs.security_check.outputs.should_run &&
75-
((github.event_name == 'push' && startsWith(github.ref, 'refs/tags/devnet/')) ||
76-
(github.event_name == 'workflow_dispatch' && github.event.inputs.action == 'promote-to-devnet'))
77-
uses: ./.github/workflows/reusable-sync-charts.yml
78-
with:
79-
environment: 'devnet'
80-
commit_sha: ${{ needs.determine-devnet-commit.outputs.commit_sha }}
81-
version: ${{ needs.determine-devnet-commit.outputs.version }}
82-
secrets:
83-
CHARTS_REPO_TOKEN: ${{ secrets.CHARTS_REPO_TOKEN }}
84-
85-
# Promote to DevNet (via tag or manual trigger)
86-
promote-to-devnet:
87-
needs: [determine-devnet-commit, sync-devnet-charts]
88-
if: |
89-
needs.security_check.outputs.should_run &&
90-
((github.event_name == 'push' && startsWith(github.ref, 'refs/tags/devnet/')) ||
91-
(github.event_name == 'workflow_dispatch' && github.event.inputs.action == 'promote-to-devnet'))
92-
runs-on: ubuntu-latest
93-
environment: devnet
44+
commit_sha: ${{ steps.determine.outputs.COMMIT_SHA }}
45+
full_commit_sha: ${{ steps.determine.outputs.FULL_COMMIT_SHA }}
46+
components_with_charts: ${{ steps.determine.outputs.COMPONENTS_WITH_CHARTS }}
47+
strategy: ${{ steps.determine.outputs.STRATEGY }}
48+
component_tag: ${{ steps.determine.outputs.COMPONENT_TAG }}
9449
steps:
95-
- name: Run DevNet Verification Tests
50+
- uses: actions/checkout@v4
51+
with:
52+
fetch-depth: 50
53+
fetch-tags: true
54+
55+
- name: Determine target commit and strategy
56+
id: determine
9657
run: |
97-
# Add your DevNet verification tests here
98-
echo "Running verification tests for DevNet"
99-
100-
# Determine commit to promote for TestNet
101-
determine-testnet-commit:
102-
needs: security_check
103-
if: |
104-
needs.security_check.outputs.should_run == 'true' &&
105-
((github.event_name == 'push' && startsWith(github.ref, 'refs/tags/testnet/')) ||
106-
(github.event_name == 'workflow_dispatch' && github.event.inputs.action == 'promote-to-testnet'))
107-
uses: ./.github/workflows/reusable-determine-commit.yml
108-
with:
109-
environment: 'testnet'
110-
commit_sha: ${{ github.event.inputs.commit_sha }}
111-
version: ${{ github.event.inputs.version }}
112-
113-
# Sync charts for TestNet
114-
sync-testnet-charts:
115-
needs: determine-testnet-commit
116-
if: |
117-
needs.security_check.outputs.should_run == 'true' &&
118-
((github.event_name == 'push' && startsWith(github.ref, 'refs/tags/testnet/')) ||
119-
(github.event_name == 'workflow_dispatch' && github.event.inputs.action == 'promote-to-testnet'))
58+
ENVIRONMENT="${{ github.event.inputs.environment }}"
59+
INPUT_COMMIT="${{ github.event.inputs.commit_sha }}"
60+
INPUT_TAG="${{ github.event.inputs.component_tag }}"
61+
62+
echo "🔍 Determining promotion strategy:"
63+
echo "- Environment: $ENVIRONMENT"
64+
echo "- Commit SHA: ${INPUT_COMMIT:-'(not provided)'}"
65+
echo "- Component Tag: ${INPUT_TAG:-'(not provided)'}"
66+
67+
# Priority logic:
68+
# 1. If component_tag provided → use that commit
69+
# 2. If commit_sha provided → use that commit
70+
# 3. Otherwise → use HEAD
71+
72+
if [[ -n "$INPUT_TAG" ]]; then
73+
echo "📦 Using component tag: $INPUT_TAG"
74+
75+
# Parse component tag (e.g., sequencer-relayer-v1.0.3)
76+
if [[ "$INPUT_TAG" =~ ^([a-z-]+)-v([0-9]+\.[0-9]+\.[0-9]+.*)$ ]]; then
77+
COMPONENT="${BASH_REMATCH[1]}"
78+
79+
# Get commit SHA from tag
80+
COMMIT_SHA=$(git rev-list -n 1 "$INPUT_TAG" 2>/dev/null || echo "")
81+
if [[ -z "$COMMIT_SHA" ]]; then
82+
echo "❌ Tag $INPUT_TAG not found"
83+
exit 1
84+
fi
85+
86+
SHORT_COMMIT_SHA="${COMMIT_SHA:0:7}"
87+
STRATEGY="component_tag"
88+
COMPONENTS_WITH_CHARTS="[\"$COMPONENT\"]"
89+
COMPONENT_TAG="$INPUT_TAG"
90+
91+
echo "✅ Component tag strategy:"
92+
echo "- Component: $COMPONENT"
93+
echo "- Commit: $SHORT_COMMIT_SHA"
94+
95+
else
96+
echo "❌ Invalid component tag format. Expected: component-name-v1.2.3"
97+
exit 1
98+
fi
99+
100+
elif [[ -n "$INPUT_COMMIT" ]]; then
101+
echo "📋 Using provided commit SHA: $INPUT_COMMIT"
102+
COMMIT_SHA="$INPUT_COMMIT"
103+
SHORT_COMMIT_SHA="${COMMIT_SHA:0:7}"
104+
STRATEGY="commit_sha"
105+
106+
else
107+
echo "🎯 Using HEAD of current branch"
108+
COMMIT_SHA=$(git rev-parse HEAD)
109+
SHORT_COMMIT_SHA="${COMMIT_SHA:0:7}"
110+
STRATEGY="head"
111+
fi
112+
113+
# For commit_sha and head strategies, detect changed components
114+
if [[ "$STRATEGY" == "commit_sha" || "$STRATEGY" == "head" ]]; then
115+
echo "🔍 Analyzing commit $SHORT_COMMIT_SHA for component changes..."
116+
117+
# Get changed files
118+
if [[ "$STRATEGY" == "head" ]]; then
119+
# Compare HEAD with previous commit
120+
CHANGED_FILES=$(git diff --name-only HEAD~1 HEAD)
121+
else
122+
# Get files changed in specific commit
123+
CHANGED_FILES=$(git diff-tree --no-commit-id --name-only -r "$COMMIT_SHA")
124+
fi
125+
126+
echo "📁 Changed files:"
127+
echo "$CHANGED_FILES"
128+
129+
# Find components with changes and charts
130+
COMPONENTS_WITH_CHARTS=()
131+
COMPONENT_DIRS=("composer" "conductor" "sequencer" "sequencer-relayer" "bridge-withdrawer" "cli")
132+
133+
for component in "${COMPONENT_DIRS[@]}"; do
134+
if echo "$CHANGED_FILES" | grep -q "^crates/astria-$component/" && [[ -d "charts/$component" ]]; then
135+
COMPONENTS_WITH_CHARTS+=("$component")
136+
echo "✅ $component changed and has chart"
137+
fi
138+
done
139+
140+
# Convert to JSON
141+
COMPONENTS_WITH_CHARTS_JSON=$(printf '%s\n' "${COMPONENTS_WITH_CHARTS[@]}" | jq -R . | jq -s .)
142+
COMPONENTS_WITH_CHARTS="$COMPONENTS_WITH_CHARTS_JSON"
143+
fi
144+
145+
# Output results
146+
echo "COMMIT_SHA=$SHORT_COMMIT_SHA" >> $GITHUB_OUTPUT
147+
echo "FULL_COMMIT_SHA=$COMMIT_SHA" >> $GITHUB_OUTPUT
148+
echo "COMPONENTS_WITH_CHARTS=$COMPONENTS_WITH_CHARTS" >> $GITHUB_OUTPUT
149+
echo "STRATEGY=$STRATEGY" >> $GITHUB_OUTPUT
150+
echo "COMPONENT_TAG=$COMPONENT_TAG" >> $GITHUB_OUTPUT
151+
152+
echo ""
153+
echo "📋 Final determination:"
154+
echo "- Strategy: $STRATEGY"
155+
echo "- Commit: $SHORT_COMMIT_SHA"
156+
echo "- Components with charts: $COMPONENTS_WITH_CHARTS"
157+
158+
sync-charts:
159+
needs: determine-target
160+
if: needs.determine-target.outputs.components_with_charts != '[]'
120161
uses: ./.github/workflows/reusable-sync-charts.yml
121162
with:
122-
environment: 'testnet'
123-
commit_sha: ${{ needs.determine-testnet-commit.outputs.commit_sha }}
124-
version: ${{ needs.determine-testnet-commit.outputs.version }}
163+
environment: ${{ github.event.inputs.environment }}
164+
commit_sha: ${{ needs.determine-target.outputs.full_commit_sha }}
165+
component_tag: ${{ needs.determine-target.outputs.component_tag }}
125166
secrets:
126-
CHARTS_REPO_TOKEN: ${{ secrets.CHARTS_REPO_TOKEN }}
127-
128-
# Promote to TestNet (via tag or manual trigger)
129-
promote-to-testnet:
130-
needs: [determine-testnet-commit, sync-testnet-charts]
131-
if: |
132-
needs.security_check.outputs.should_run == 'true' &&
133-
((github.event_name == 'push' && startsWith(github.ref, 'refs/tags/testnet/')) ||
134-
(github.event_name == 'workflow_dispatch' && github.event.inputs.action == 'promote-to-testnet'))
135-
runs-on: ubuntu-latest
136-
environment: testnet
137-
steps:
138-
- name: Run TestNet Verification Tests
139-
run: |
140-
# Add TestNet verification tests here
141-
echo "Running verification tests for TestNet"
142-
143-
# Determine commit to promote for MainNet
144-
determine-mainnet-commit:
145-
needs: security_check
146-
if: |
147-
needs.security_check.outputs.should_run == 'true' &&
148-
((github.event_name == 'push' && startsWith(github.ref, 'refs/tags/mainnet/')) ||
149-
(github.event_name == 'workflow_dispatch' && github.event.inputs.action == 'promote-to-mainnet'))
150-
uses: ./.github/workflows/reusable-determine-commit.yml
151-
with:
152-
environment: 'mainnet'
153-
commit_sha: ${{ github.event.inputs.commit_sha }}
154-
version: ${{ github.event.inputs.version }}
155-
156-
# Sync charts for MainNet
157-
sync-mainnet-charts:
158-
needs: determine-mainnet-commit
159-
if: |
160-
needs.security_check.outputs.should_run == 'true' &&
161-
((github.event_name == 'push' && startsWith(github.ref, 'refs/tags/mainnet/')) ||
162-
(github.event_name == 'workflow_dispatch' && github.event.inputs.action == 'promote-to-mainnet'))
163-
uses: ./.github/workflows/reusable-sync-charts.yml
167+
CHARTS_RELEASE_TEST_REPO_TOKEN: ${{ secrets.CHARTS_RELEASE_TEST_REPO_TOKEN }}
168+
169+
update-argocd-apps:
170+
needs: sync-charts
171+
if: needs.sync-charts.result == 'success'
172+
uses: ./.github/workflows/reusable-update-argocd-apps.yml
164173
with:
165-
environment: 'mainnet'
166-
commit_sha: ${{ needs.determine-mainnet-commit.outputs.commit_sha }}
167-
version: ${{ needs.determine-mainnet-commit.outputs.version }}
168-
secrets:
169-
CHARTS_REPO_TOKEN: ${{ secrets.CHARTS_REPO_TOKEN }}
170-
171-
# Promote to MainNet (via tag or manual trigger)
172-
promote-to-mainnet:
173-
needs: [determine-mainnet-commit, sync-mainnet-charts]
174-
if: |
175-
needs.security_check.outputs.should_run == 'true' &&
176-
((github.event_name == 'push' && startsWith(github.ref, 'refs/tags/mainnet/')) ||
177-
(github.event_name == 'workflow_dispatch' && github.event.inputs.action == 'promote-to-mainnet'))
174+
environment: ${{ github.event.inputs.environment }}
175+
commit_sha: ${{ needs.determine-target.outputs.full_commit_sha }}
176+
# TODO: Uncomment this when we have a token for argocd-apps
177+
# secrets:
178+
# ARGOCD_APPS_TOKEN: ${{ secrets.ARGOCD_APPS_TOKEN }}
179+
180+
promotion-summary:
181+
needs: [determine-target, sync-charts]
182+
if: always()
178183
runs-on: ubuntu-latest
179-
environment: mainnet
180184
steps:
181-
- name: Run MainNet Verification Tests
185+
- name: Promotion summary
182186
run: |
183-
# Add MainNet verification tests here
184-
echo "Running verification tests for MainNet"
185-
186-
# Create GitHub Release similar to release-please
187-
- name: Create GitHub Release
188-
if: success()
189-
uses: actions/github-script@v6
190-
with:
191-
github-token: ${{ secrets.GITHUB_TOKEN }}
192-
script: |
193-
const version = "${{ needs.determine-mainnet-commit.outputs.version }}";
194-
const commit = "${{ needs.determine-mainnet-commit.outputs.commit_sha }}";
195-
196-
// Create a release with information from all components
197-
const releaseData = {
198-
tag_name: `release/${version}`,
199-
name: `Release ${version}`,
200-
body: `
201-
# Release ${version}
202-
203-
This release has been deployed to MainNet.
204-
205-
## Components
206-
207-
The following components have been deployed with commit SHA ${commit}:
208-
209-
- Composer
210-
- Conductor
211-
- Sequencer
212-
- Sequencer Relayer
213-
- Bridge Withdrawer
214-
- CLI
215-
216-
See CHANGELOG.md for details on what's included in this release.
217-
`,
218-
draft: false,
219-
prerelease: false
220-
};
221-
222-
console.log('Creating release:', releaseData);
223-
224-
const release = await github.rest.repos.createRelease({
225-
owner: context.repo.owner,
226-
repo: context.repo.repo,
227-
...releaseData
228-
});
229-
230-
console.log('Release created:', release.data.html_url);
187+
echo "🎉 Environment Promotion Summary"
188+
echo ""
189+
echo "**Input Details:**"
190+
echo "- Environment: ${{ github.event.inputs.environment }}"
191+
echo "- Commit SHA Input: ${{ github.event.inputs.commit_sha || '(not provided)' }}"
192+
echo "- Component Tag Input: ${{ github.event.inputs.component_tag || '(not provided)' }}"
193+
echo ""
194+
echo "**Determined Strategy:**"
195+
echo "- Strategy: ${{ needs.determine-target.outputs.strategy }}"
196+
echo "- Target Commit: ${{ needs.determine-target.outputs.commit_sha }}"
197+
echo "- Components with Charts: ${{ needs.determine-target.outputs.components_with_charts }}"
198+
echo ""

0 commit comments

Comments
 (0)