Deploy to prod #291
This file contains 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
name: Deploy to prod | |
on: | |
workflow_dispatch: | |
schedule: | |
# Weekdays Mon-Fri @ 18:00 UTC (10AM PST [winter] / 11AM PDT [summer]) | |
- cron: '0 18 * * 1-5' | |
permissions: | |
contents: write | |
id-token: write | |
pull-requests: write | |
jobs: | |
find-frontend-release-pr: | |
concurrency: | |
group: create-frontend-release-${{ github.ref }} | |
cancel-in-progress: true | |
outputs: | |
pr: ${{ steps.find-release-pr.outputs.result }} | |
name: find release PR | |
runs-on: ubuntu-latest | |
if: github.repository == 'chanzuckerberg/cryoet-data-portal' | |
needs: run-staging-e2e-test | |
steps: | |
- name: find release PR | |
uses: actions/github-script@v7 | |
id: find-release-pr | |
with: | |
script: | | |
const { owner, repo } = context.repo | |
const { data: searchResult } = await github.rest.search.issuesAndPullRequests( | |
{ | |
q: `repo:${owner}/${repo} is:pr is:open label:"autorelease: pending" "chore(main): release web"`, | |
per_page: 1, | |
} | |
) | |
const [issue] = searchResult.items | |
if (!issue) { | |
throw new Error('No release PR found') | |
} | |
// Getting PR data from /pulls API has more info about the pull | |
// request like merge_commit_sha. | |
const { data: pr } = await github.rest.pulls.get({ | |
owner, | |
repo, | |
pull_number: issue.number, | |
}) | |
return pr | |
run-staging-e2e-test: | |
name: Run e2e test on staging | |
uses: ./.github/workflows/frontend-e2e-tests.yml | |
secrets: inherit | |
# The variable IS_DEPLOY_ALLOWED is used to manually gate the prod deploys | |
if: vars.IS_DEPLOY_ALLOWED == 'true' | |
with: | |
environment: staging | |
tag-frontend-release: | |
outputs: | |
tag: ${{ fromJson(steps.get-tag-name.outputs.result).tag }} | |
name: tag frontend release | |
runs-on: ubuntu-latest | |
if: github.repository == 'chanzuckerberg/cryoet-data-portal' | |
needs: find-frontend-release-pr | |
steps: | |
- name: merge release PR | |
uses: actions/github-script@v7 | |
id: merge-release-pr | |
if: fromJson(needs.find-frontend-release-pr.outputs.pr).state == 'open' | |
with: | |
result-encoding: string | |
script: | | |
const pr = ${{ needs.find-frontend-release-pr.outputs.pr }} | |
console.log(`Merging release PR #${pr.number}`) | |
const { owner, repo } = context.repo | |
const mergeResponse = await github.rest.pulls.merge({ | |
owner, | |
repo, | |
pull_number: pr.number, | |
merge_method: 'squash', | |
}) | |
return mergeResponse.data.sha | |
- name: checkout repo for tagging | |
uses: actions/checkout@v4 | |
with: | |
ref: | | |
${{ | |
fromJson(needs.find-frontend-release-pr.outputs.pr).state == 'open' && | |
steps.merge-release-pr.outputs.result || | |
fromJson(needs.find-frontend-release-pr.outputs.pr).merge_commit_sha | |
}} | |
- name: get tag name | |
id: get-tag-name | |
uses: actions/github-script@v7 | |
with: | |
script: | | |
const pr = ${{ needs.find-frontend-release-pr.outputs.pr }} | |
const version = pr.title.split(' ').at(-1) | |
return { | |
version, | |
tag: `web-v${version}`, | |
} | |
- name: tag release | |
run: | | |
git config user.name github-actions[bot] | |
git config user.email github-actions[bot]@users.noreply.github.com | |
git tag -a ${{ fromJson(steps.get-tag-name.outputs.result).tag }} -m "Releasing frontend v${{ fromJson(steps.get-tag-name.outputs.result).version }}" | |
git push origin ${{ fromJson(steps.get-tag-name.outputs.result).tag }} | |
- name: update label for release PR | |
uses: actions/github-script@v7 | |
with: | |
github-token: ${{ secrets.GITHUB_TOKEN }} | |
result-encoding: string | |
script: | | |
const pr = ${{ needs.find-frontend-release-pr.outputs.pr }} | |
const { owner, repo } = context.repo | |
const { tag } = ${{ steps.get-tag-name.outputs.result }} | |
await Promise.all([ | |
github.rest.issues.removeLabel({ | |
owner, | |
repo, | |
issue_number: pr.number, | |
name: 'autorelease: pending' | |
}), | |
github.rest.issues.addLabels({ | |
owner, | |
repo, | |
issue_number: pr.number, | |
labels: ['autorelease: tagged'] | |
}), | |
]) | |
deploy-to-prod: | |
concurrency: | |
group: prod-frontend-deploy-${{ github.ref }} | |
cancel-in-progress: true | |
name: deploy prod branch | |
runs-on: ubuntu-latest | |
environment: prod | |
needs: [find-frontend-release-pr, tag-frontend-release] | |
if: github.repository == 'chanzuckerberg/cryoet-data-portal' | |
steps: | |
- name: Configure AWS Credentials | |
uses: aws-actions/configure-aws-credentials@v4 | |
with: | |
mask-aws-account-id: true | |
aws-region: ${{ secrets.AWS_REGION }} | |
role-to-assume: ${{ secrets.AWS_ROLE_TO_ASSUME }} | |
role-duration-seconds: 1200 | |
- name: Create or update stack | |
uses: chanzuckerberg/github-actions/.github/actions/[email protected] | |
env: | |
# Force using BuildKit instead of normal Docker, required so that metadata | |
# is written/read to allow us to use layers of previous builds as cache. | |
DOCKER_BUILDKIT: 1 | |
COMPOSE_DOCKER_CLI_BUILD: 1 | |
DOCKER_REPO: ${{ secrets.ECR_REPO }}/ | |
ENV: prod | |
with: | |
stack-name: frontend | |
create-tag: true | |
tag: ${{ env.STACK_NAME }} | |
tfe-token: ${{ secrets.TFE_TOKEN }} | |
working-directory: ./frontend | |
env: prod | |
operation: create-or-update | |
github-repo-branch: ${{ needs.tag-frontend-release.outputs.tag }} | |
run-prod-e2e-test: | |
name: Run e2e test on prod | |
needs: deploy-to-prod | |
uses: ./.github/workflows/frontend-e2e-tests.yml | |
secrets: inherit | |
with: | |
environment: prod | |
notify-slack: | |
name: Notify slack channel | |
runs-on: ubuntu-latest | |
needs: [run-prod-e2e-test, find-frontend-release-pr] | |
if: needs.find-frontend-release-pr.outputs.pr != '' && !cancelled() | |
steps: | |
- name: checkout repo for tagging | |
uses: actions/checkout@v4 | |
- name: Create slack payload | |
id: slack-payload | |
uses: actions/github-script@v7 | |
with: | |
script: | | |
const createSlackPayload = require('./.github/create-slack-payload') | |
const pr = ${{ needs.find-frontend-release-pr.outputs.pr }} | |
return createSlackPayload({ | |
passed: '${{ needs.run-prod-e2e-test.result }}' === 'success', | |
prNumber: pr.number, | |
runId: '${{ github.run_id }}', | |
}) | |
- name: Send slack notification | |
uses: slackapi/[email protected] | |
env: | |
SLACK_WEBHOOK_TYPE: INCOMING_WEBHOOK | |
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }} | |
with: | |
payload: ${{ fromJson(steps.slack-payload.outputs.result) }} |