Skip to content

Commit 79e9e46

Browse files
authored
chore: deployment v2 (#7297)
* feat: add release-branch-sync workflow * refactor: split repeated parts into a composite action * feat: update production release flow * feat: notify on slack once approval is pending * feat: set concurrency so it triggers only once per release * feat: collect tag metadata * feat: notify also when develop sync PR is ready * feat: rename workflow to deployment v2 * fix: force checkout branch in case it's already present locally * chore: replace main with main-copy for testing REVERT ME!
1 parent a267ec6 commit 79e9e46

2 files changed

Lines changed: 257 additions & 0 deletions

File tree

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
name: Setup Release Sync
2+
description: Create a GitHub App token, resolve the app bot identity, and checkout the repository
3+
4+
inputs:
5+
app-id:
6+
description: GitHub App ID
7+
required: true
8+
private-key:
9+
description: GitHub App private key
10+
required: true
11+
owner:
12+
description: Repository owner
13+
required: true
14+
repository:
15+
description: Repository name
16+
required: true
17+
checkout-ref:
18+
description: Optional git ref to checkout
19+
required: false
20+
default: ''
21+
pull-requests-write:
22+
description: Whether the app token should include pull request write permission
23+
required: false
24+
default: 'false'
25+
26+
outputs:
27+
token:
28+
description: GitHub App installation token
29+
value: ${{ steps.app-token.outputs.token }}
30+
app-slug:
31+
description: GitHub App slug
32+
value: ${{ steps.app-token.outputs.app-slug }}
33+
app-user-id:
34+
description: Numeric GitHub App bot user id
35+
value: ${{ steps.app-user.outputs.user-id }}
36+
37+
runs:
38+
using: composite
39+
steps:
40+
- name: Create GitHub App token
41+
id: app-token
42+
uses: actions/create-github-app-token@f8d387b68d61c58ab83c6c016672934102569859 # v3.0.0
43+
with:
44+
app-id: ${{ inputs.app-id }}
45+
private-key: ${{ inputs.private-key }}
46+
owner: ${{ inputs.owner }}
47+
repositories: ${{ inputs.repository }}
48+
permission-contents: write
49+
permission-pull-requests: ${{ inputs.pull-requests-write == 'true' && 'write' || '' }}
50+
51+
- name: Get GitHub App user ID
52+
id: app-user
53+
shell: bash
54+
run: echo "user-id=$(gh api "/users/${APP_SLUG}[bot]" --jq .id)" >> "$GITHUB_OUTPUT"
55+
env:
56+
APP_SLUG: ${{ steps.app-token.outputs.app-slug }}
57+
GH_TOKEN: ${{ steps.app-token.outputs.token }}
58+
59+
- name: Checkout code
60+
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
61+
with:
62+
fetch-depth: 0
63+
persist-credentials: true
64+
token: ${{ steps.app-token.outputs.token }}
65+
ref: ${{ inputs.checkout-ref != '' && inputs.checkout-ref || github.ref }}
Lines changed: 192 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,192 @@
1+
name: Deployment v2
2+
3+
on:
4+
push:
5+
branches: [main-copy]
6+
tags: [cowswap-*, explorer-*]
7+
8+
concurrency:
9+
group: release-branch-sync
10+
cancel-in-progress: false
11+
12+
permissions:
13+
contents: write
14+
pull-requests: write
15+
16+
jobs:
17+
collect-release-metadata:
18+
name: Collect release metadata
19+
if: startsWith(github.ref, 'refs/tags/')
20+
runs-on: ubuntu-latest
21+
outputs:
22+
release-tags: ${{ steps.collect.outputs.release-tags }}
23+
steps:
24+
- name: Checkout code
25+
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
26+
with:
27+
fetch-depth: 0
28+
persist-credentials: false
29+
30+
- name: Collect tags for release commit
31+
id: collect
32+
run: |
33+
set -euo pipefail
34+
35+
git fetch --tags origin
36+
37+
release_commit="$(git rev-list -n 1 "${GITHUB_REF}")"
38+
release_tags="$(
39+
git tag --points-at "${release_commit}" \
40+
| sort \
41+
| paste -sd ', ' -
42+
)"
43+
44+
if [ -z "${release_tags}" ]; then
45+
release_tags="${GITHUB_REF_NAME}"
46+
fi
47+
48+
echo "release-tags=${release_tags}" >> "$GITHUB_OUTPUT"
49+
50+
sync-develop:
51+
name: Sync main-copy to develop
52+
if: github.ref == 'refs/heads/main-copy'
53+
runs-on: ubuntu-latest
54+
env:
55+
TARGET_BRANCH: develop
56+
SYNC_BRANCH: automation/sync-main-copy-to-develop
57+
PR_TITLE: 'chore(sync): merge main-copy into develop'
58+
PR_BODY: |
59+
This PR contains an automated merge commit from `main-copy` into `develop`.
60+
61+
Requested reviewers:
62+
- @cowprotocol/frontend
63+
steps:
64+
- name: Setup release sync
65+
id: setup
66+
uses: ./.github/actions/setup-release-sync
67+
with:
68+
app-id: ${{ vars.COWSWAP_RELEASE_SYNC_APP_ID }}
69+
private-key: ${{ secrets.COWSWAP_RELEASE_SYNC_APP_PRIVATE_KEY }}
70+
owner: ${{ github.repository_owner }}
71+
repository: ${{ github.event.repository.name }}
72+
pull-requests-write: 'true'
73+
74+
- name: Prepare merge branch
75+
id: prepare
76+
run: |
77+
set -euo pipefail
78+
79+
git config user.name "${APP_SLUG}[bot]"
80+
git config user.email "${APP_USER_ID}+${APP_SLUG}[bot]@users.noreply.github.com"
81+
82+
git fetch origin main-copy "${TARGET_BRANCH}"
83+
git checkout -B "${SYNC_BRANCH}" "origin/${TARGET_BRANCH}"
84+
85+
before_sha="$(git rev-parse HEAD)"
86+
git merge --no-ff --no-edit -m "${PR_TITLE}" origin/main-copy
87+
after_sha="$(git rev-parse HEAD)"
88+
89+
if [ "${before_sha}" = "${after_sha}" ]; then
90+
echo "has_changes=false" >> "$GITHUB_OUTPUT"
91+
exit 0
92+
fi
93+
94+
echo "has_changes=true" >> "$GITHUB_OUTPUT"
95+
env:
96+
APP_SLUG: ${{ steps.setup.outputs.app-slug }}
97+
APP_USER_ID: ${{ steps.setup.outputs.app-user-id }}
98+
99+
- name: Create or update pull request
100+
if: steps.prepare.outputs.has_changes == 'true'
101+
id: create-pr
102+
uses: peter-evans/create-pull-request@v8
103+
with:
104+
token: ${{ steps.setup.outputs.token }}
105+
branch: ${{ env.SYNC_BRANCH }}
106+
base: ${{ env.TARGET_BRANCH }}
107+
title: ${{ env.PR_TITLE }}
108+
body: ${{ env.PR_BODY }}
109+
commit-message: ${{ env.PR_TITLE }}
110+
delete-branch: false
111+
draft: false
112+
reviewers: ''
113+
team-reviewers: |
114+
frontend
115+
qa
116+
117+
- name: Notify Slack for develop review
118+
if: steps.prepare.outputs.has_changes == 'true'
119+
run: |
120+
curl -X POST -H "Content-type: application/json" \
121+
--data "{\"text\": \"➡️ Develop sync PR is ready for review. <$PR_URL|Open pull request>.\"}" \
122+
"$SLACK_WEBHOOK_URL"
123+
env:
124+
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
125+
PR_URL: ${{ steps.create-pr.outputs.pull-request-url }}
126+
127+
sync-staging:
128+
name: Fast-forward staging to main-copy
129+
if: startsWith(github.ref, 'refs/tags/cowswap-') || startsWith(github.ref, 'refs/tags/explorer-')
130+
needs: collect-release-metadata
131+
runs-on: ubuntu-latest
132+
steps:
133+
- name: Setup release sync
134+
id: setup
135+
uses: ./.github/actions/setup-release-sync
136+
with:
137+
app-id: ${{ vars.COWSWAP_RELEASE_SYNC_APP_ID }}
138+
private-key: ${{ secrets.COWSWAP_RELEASE_SYNC_APP_PRIVATE_KEY }}
139+
owner: ${{ github.repository_owner }}
140+
repository: ${{ github.event.repository.name }}
141+
142+
- name: Fast-forward staging
143+
run: |
144+
set -euo pipefail
145+
146+
git fetch origin main-copy staging
147+
git checkout -B staging origin/staging
148+
git merge --ff-only origin/main-copy
149+
git push origin staging
150+
151+
notify-production-approval:
152+
name: Notify Slack for production approval
153+
if: startsWith(github.ref, 'refs/tags/cowswap-') || startsWith(github.ref, 'refs/tags/explorer-')
154+
needs: [collect-release-metadata, sync-staging]
155+
runs-on: ubuntu-latest
156+
steps:
157+
- name: Notify Slack
158+
run: |
159+
curl -X POST -H "Content-type: application/json" \
160+
--data "{\"text\": \"⏳ Production release for tag(s) \`${RELEASE_TAGS}\` is waiting for approval. <$SERVER_URL/$REPOSITORY/actions/runs/$RUN_ID|Review the workflow run>.\"}" \
161+
"$SLACK_WEBHOOK_URL"
162+
env:
163+
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
164+
RELEASE_TAGS: ${{ needs.collect-release-metadata.outputs.release-tags }}
165+
SERVER_URL: ${{ github.server_url }}
166+
REPOSITORY: ${{ github.repository }}
167+
RUN_ID: ${{ github.run_id }}
168+
169+
sync-production:
170+
name: Fast-forward production to main-copy
171+
if: startsWith(github.ref, 'refs/tags/cowswap-') || startsWith(github.ref, 'refs/tags/explorer-')
172+
needs: [collect-release-metadata, notify-production-approval]
173+
runs-on: ubuntu-latest
174+
environment: production # Env configured in GitHub UI. Requires manual approval before this job can run
175+
steps:
176+
- name: Setup release sync
177+
id: setup
178+
uses: ./.github/actions/setup-release-sync
179+
with:
180+
app-id: ${{ vars.COWSWAP_RELEASE_SYNC_APP_ID }}
181+
private-key: ${{ secrets.COWSWAP_RELEASE_SYNC_APP_PRIVATE_KEY }}
182+
owner: ${{ github.repository_owner }}
183+
repository: ${{ github.event.repository.name }}
184+
185+
- name: Fast-forward production
186+
run: |
187+
set -euo pipefail
188+
189+
git fetch origin main-copy production
190+
git checkout -B production origin/production
191+
git merge --ff-only origin/main-copy
192+
git push origin production

0 commit comments

Comments
 (0)