Staging - Deploy PR #84
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: Staging - Deploy PR | |
# **What it does**: To deploy PRs to a Heroku staging environment. | |
# **Why we have it**: To deploy with high visibility in case of failures. | |
# **Who does it impact**: All contributors. | |
on: | |
workflow_run: | |
workflows: | |
- 'Staging - Build PR' | |
types: | |
- completed | |
permissions: | |
actions: read | |
contents: read | |
deployments: write | |
pull-requests: read | |
statuses: write | |
# IMPORTANT: Intentionally OMIT a `concurrency` configuration from this workflow's | |
# top-level as we do not have any guarantee of identifying values being available | |
# within the `github.event` context for PRs from forked repos! | |
# | |
# The implication of this shortcoming is that we may have multiple workflow runs | |
# of this running at the same time for different commits within the same PR. | |
# However, once they reach the `concurrency` configurations deeper down within | |
# this workflow's jobs, then we can expect concurrent short-circuiting to begin. | |
env: | |
CONTEXT_NAME: '${{ github.workflow }} / deploy (${{ github.event.workflow_run.event }})' | |
ACTIONS_RUN_LOG: https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }} | |
BUILD_ACTIONS_RUN_ID: ${{ github.event.workflow_run.id }} | |
BUILD_ACTIONS_RUN_LOG: https://github.com/${{ github.repository }}/actions/runs/${{ github.event.workflow_run.id }} | |
jobs: | |
debug: | |
runs-on: ubuntu-latest | |
steps: | |
- name: Dump full context for debugging | |
env: | |
GITHUB_CONTEXT: ${{ toJSON(github) }} | |
run: echo "$GITHUB_CONTEXT" | |
pr-metadata: | |
runs-on: ubuntu-latest | |
outputs: | |
number: ${{ steps.pr.outputs.number }} | |
url: ${{ steps.pr.outputs.url }} | |
state: ${{ steps.pr.outputs.state }} | |
head_sha: ${{ steps.pr.outputs.head_sha }} | |
head_branch: ${{ steps.pr.outputs.head_branch }} | |
head_label: ${{ steps.pr.outputs.head_label }} | |
head_ref: ${{ steps.pr.outputs.head_ref }} | |
steps: | |
- name: Find the originating pull request | |
id: pr | |
uses: actions/github-script@2b34a689ec86a68d8ab9478298f91d5401337b7d | |
env: | |
BUILD_ACTIONS_RUN_ID: ${{ env.BUILD_ACTIONS_RUN_ID }} | |
with: | |
script: | | |
// In order to find out the PR info for a forked repo, we must query | |
// the API for more info based on the originating workflow run | |
const { BUILD_ACTIONS_RUN_ID } = process.env | |
const { owner, repo } = context.repo | |
const { data: run } = await github.actions.getWorkflowRun({ | |
owner, | |
repo, | |
run_id: BUILD_ACTIONS_RUN_ID, | |
}) | |
// Gather PR-identifying information from the workflow run | |
const { | |
head_branch: headBranch, | |
head_sha: headSha, | |
head_repository: { | |
owner: { login: prRepoOwner }, | |
name: prRepoName | |
} | |
} = run | |
const headLabel = `${prRepoOwner}:${headBranch}` | |
const prIsInternal = owner === prRepoOwner && repo === prRepoName | |
// If the PR is external, prefix its head branch name with the | |
// forked repo owner's login, e.g. "octocat:docs" | |
const headRef = prIsInternal ? headBranch : headLabel | |
// Retrieve matching PRs (up to 30) | |
const { data: pulls } = await github.pulls.list({ | |
owner, | |
repo, | |
head: headLabel, | |
sort: 'updated', | |
direction: 'desc', | |
per_page: 30 | |
}) | |
// Find the open PR, if any, otherwise choose the most recently updated | |
const targetPull = pulls.find(pr => pr.state === 'open') || pulls[0] || {} | |
const pullNumber = targetPull.number || 0 | |
const pullUrl = targetPull.html_url || 'about:blank' | |
const pullState = targetPull.state || 'closed' | |
core.setOutput('number', pullNumber.toString()) | |
core.setOutput('url', pullUrl) | |
core.setOutput('state', pullState) | |
core.setOutput('head_sha', headSha) | |
core.setOutput('head_branch', headBranch) | |
core.setOutput('head_label', headLabel) | |
core.setOutput('head_ref', headRef) | |
debug-originating-trigger: | |
needs: pr-metadata | |
runs-on: ubuntu-latest | |
steps: | |
- name: Dump info about the originating workflow run | |
env: | |
PR_NUMBER: ${{ needs.pr-metadata.outputs.number }} | |
PR_URL: ${{ needs.pr-metadata.outputs.url }} | |
PR_STATE: ${{ needs.pr-metadata.outputs.state }} | |
HEAD_SHA: ${{ needs.pr-metadata.outputs.head_sha }} | |
HEAD_BRANCH: ${{ needs.pr-metadata.outputs.head_branch }} | |
HEAD_LABEL: ${{ needs.pr-metadata.outputs.head_label }} | |
HEAD_REF: ${{ needs.pr-metadata.outputs.head_ref }} | |
BUILD_ACTIONS_RUN_ID: ${{ env.BUILD_ACTIONS_RUN_ID }} | |
BUILD_ACTIONS_RUN_LOG: ${{ env.BUILD_ACTIONS_RUN_LOG }} | |
run: | | |
echo "Originating workflow info:" | |
echo " - PR_NUMBER = $PR_NUMBER" | |
echo " - PR_URL = $PR_URL" | |
echo " - PR_STATE = $PR_STATE" | |
echo " - HEAD_SHA = $HEAD_SHA" | |
echo " - HEAD_BRANCH = $HEAD_BRANCH" | |
echo " - HEAD_LABEL = $HEAD_LABEL" | |
echo " - HEAD_REF = $HEAD_REF" | |
echo " - BUILD_ACTIONS_RUN_ID = $BUILD_ACTIONS_RUN_ID" | |
echo " - BUILD_ACTIONS_RUN_LOG = $BUILD_ACTIONS_RUN_LOG" | |
notify-of-failed-builds: | |
needs: pr-metadata | |
if: >- | |
${{ | |
needs.pr-metadata.outputs.number != '0' && | |
github.event.workflow_run.conclusion == 'failure' && | |
(github.repository == 'github/docs-internal' || github.repository == 'github/docs') | |
}} | |
runs-on: ubuntu-latest | |
timeout-minutes: 1 | |
# Specifically omitting a concurrency group here in case the build was not | |
# successful BECAUSE a subsequent build already canceled it | |
steps: | |
- name: Verify build workflow run was not cancelled | |
id: check-workflow-run | |
uses: actions/github-script@2b34a689ec86a68d8ab9478298f91d5401337b7d | |
env: | |
BUILD_ACTIONS_RUN_ID: ${{ env.BUILD_ACTIONS_RUN_ID }} | |
with: | |
script: | | |
const { owner, repo } = context.repo | |
const { data: { jobs: buildJobs } } = await github.actions.listJobsForWorkflowRun({ | |
owner, | |
repo, | |
run_id: process.env.BUILD_ACTIONS_RUN_ID, | |
filter: 'latest' | |
}) | |
const wasCancelled = ( | |
buildJobs.length > 0 && | |
buildJobs.every(({ status, conclusion }) => { | |
return status === 'completed' && conclusion === 'cancelled' | |
}) | |
) | |
core.setOutput('cancelled', wasCancelled.toString()) | |
- if: ${{ steps.check-workflow-run.outputs.cancelled == 'false' }} | |
name: Send Slack notification if build workflow failed | |
uses: someimportantcompany/github-actions-slack-message@0b470c14b39da4260ed9e3f9a4f1298a74ccdefd | |
with: | |
channel: ${{ secrets.DOCS_STAGING_DEPLOYMENT_FAILURES_SLACK_CHANNEL_ID }} | |
bot-token: ${{ secrets.SLACK_DOCS_BOT_TOKEN }} | |
color: failure | |
text: Staging build failed for PR ${{ needs.pr-metadata.outputs.url }} at commit ${{ needs.pr-metadata.outputs.head_sha }}. See ${{ env.BUILD_ACTIONS_RUN_LOG }}. This run was ${{ env.ACTIONS_RUN_LOG }}. | |
check-pr-before-prepare: | |
needs: pr-metadata | |
if: >- | |
${{ | |
needs.pr-metadata.outputs.number != '0' && | |
github.event.workflow_run.conclusion == 'success' && | |
(github.repository == 'github/docs-internal' || github.repository == 'github/docs') | |
}} | |
runs-on: ubuntu-latest | |
# This timeout should match or exceed the value of the timeout for Undeploy | |
timeout-minutes: 5 | |
# This interrupts Build, Deploy, and pre-write Undeploy workflow runs in | |
# progress for this PR branch. | |
concurrency: | |
group: 'PR Staging @ ${{ needs.pr-metadata.outputs.head_label }}' | |
cancel-in-progress: true | |
outputs: | |
pull_request_state: ${{ steps.check-pr.outputs.state }} | |
steps: | |
- name: Check pull request state | |
id: check-pr | |
uses: actions/github-script@2b34a689ec86a68d8ab9478298f91d5401337b7d | |
env: | |
PR_NUMBER: ${{ needs.pr-metadata.outputs.number }} | |
with: | |
script: | | |
// Equivalent of the 'await-sleep' module without the install | |
const sleep = ms => new Promise(resolve => setTimeout(resolve, ms)) | |
const blockingLabel = 'automated-block-deploy' | |
const { owner, repo } = context.repo | |
const startTime = Date.now() | |
let pullRequest = {} | |
let blocked = true | |
// Keep polling the PR until the blocking label has been removed | |
while (blocked) { | |
const { data: pr } = await github.pulls.get({ | |
owner, | |
repo, | |
pull_number: process.env.PR_NUMBER | |
}) | |
blocked = pr.labels.some(({ name }) => name === blockingLabel) | |
if (blocked) { | |
console.warn(`WARNING! PR currently has blocking label "${blockingLabel}" (after ${Date.now() - startTime} ms). Will check again soon...`) | |
await sleep(15000) // Wait 15 seconds and check again | |
} else { | |
console.log(`PR was unblocked (after ${Date.now() - startTime} ms)!`) | |
pullRequest = pr | |
} | |
} | |
core.setOutput('state', pullRequest.state) | |
prepare-for-deploy: | |
needs: [pr-metadata, check-pr-before-prepare] | |
if: ${{ needs.check-pr-before-prepare.outputs.pull_request_state == 'open' }} | |
runs-on: ubuntu-latest | |
timeout-minutes: 5 | |
# This interrupts Build, Deploy, and pre-write Undeploy workflow runs in | |
# progress for this PR branch. | |
concurrency: | |
group: 'PR Staging @ ${{ needs.pr-metadata.outputs.head_label }}' | |
cancel-in-progress: true | |
outputs: | |
source_blob_url: ${{ steps.build-source.outputs.download_url }} | |
steps: | |
- name: Create initial status | |
uses: actions/github-script@2b34a689ec86a68d8ab9478298f91d5401337b7d | |
env: | |
CONTEXT_NAME: ${{ env.CONTEXT_NAME }} | |
ACTIONS_RUN_LOG: ${{ env.ACTIONS_RUN_LOG }} | |
HEAD_SHA: ${{ needs.pr-metadata.outputs.head_sha }} | |
with: | |
script: | | |
const { CONTEXT_NAME, ACTIONS_RUN_LOG, HEAD_SHA } = process.env | |
const { owner, repo } = context.repo | |
await github.repos.createCommitStatus({ | |
owner, | |
repo, | |
sha: HEAD_SHA, | |
context: CONTEXT_NAME, | |
state: 'pending', | |
description: 'The app is being deployed. See logs.', | |
target_url: ACTIONS_RUN_LOG | |
}) | |
- name: Check out repo's default branch | |
uses: actions/checkout@5a4ac9002d0be2fb38bd78e4b4dbde5606d7042f | |
with: | |
# To prevent issues with cloning early access content later | |
persist-credentials: 'false' | |
lfs: 'true' | |
- name: Check out LFS objects | |
run: git lfs checkout | |
- if: ${{ github.repository == 'github/docs-internal' }} | |
name: Setup node to clone early access | |
uses: actions/setup-node@38d90ce44d5275ad62cc48384b3d8a58c500bb5f | |
with: | |
node-version: 16.8.x | |
cache: npm | |
# Install any dependencies that are needed for the early access script | |
- if: ${{ github.repository == 'github/docs-internal' }} | |
name: Install temporary dependencies | |
run: npm install --no-save dotenv rimraf | |
- if: ${{ github.repository == 'github/docs-internal' }} | |
name: Clone early access | |
run: node script/early-access/clone-for-build.js | |
env: | |
DOCUBOT_REPO_PAT: ${{ secrets.DOCUBOT_REPO_PAT }} | |
GIT_BRANCH: ${{ needs.pr-metadata.outputs.head_ref }} | |
# Download the previously built "app.tar" | |
- name: Download build artifact | |
uses: dawidd6/action-download-artifact@af92a8455a59214b7b932932f2662fdefbd78126 | |
with: | |
workflow: ${{ github.event.workflow_run.workflow_id }} | |
run_id: ${{ env.BUILD_ACTIONS_RUN_ID }} | |
name: pr_build | |
path: ./ | |
- name: Extract user-changes to temp directory | |
run: | | |
tar -x --file=app.tar -C "$RUNNER_TEMP/" | |
rm app.tar | |
# Move the LFS content into the temp directory in chunks (destructively) | |
- name: Move the LFS objects | |
run: | | |
git lfs ls-files --name-only | xargs -n 1 -I {} sh -c 'mkdir -p "$RUNNER_TEMP/$(dirname {})"; mv {} "$RUNNER_TEMP/$(dirname {})/"' | |
# Move the early access content into the temp directory (destructively) | |
- if: ${{ github.repository == 'github/docs-internal' }} | |
name: Move the early access content | |
run: | | |
mv assets/images/early-access "$RUNNER_TEMP/assets/images/" | |
mv content/early-access "$RUNNER_TEMP/content/" | |
mv data/early-access "$RUNNER_TEMP/data/" | |
- name: Create a gzipped archive | |
run: tar -cz --file app.tar.gz "$RUNNER_TEMP/" | |
- name: Install Heroku client development-only dependency | |
run: npm install --no-save heroku-client | |
- name: Create a Heroku build source | |
id: build-source | |
uses: actions/github-script@2b34a689ec86a68d8ab9478298f91d5401337b7d | |
env: | |
HEROKU_API_TOKEN: ${{ secrets.HEROKU_API_TOKEN }} | |
with: | |
script: | | |
const { owner, repo } = context.repo | |
if (owner !== 'github') { | |
throw new Error(`Repository owner must be 'github' but was: ${owner}`) | |
} | |
if (repo !== 'docs-internal' && repo !== 'docs') { | |
throw new Error(`Repository name must be either 'docs-internal' or 'docs' but was: ${repo}`) | |
} | |
const Heroku = require('heroku-client') | |
const heroku = new Heroku({ token: process.env.HEROKU_API_TOKEN }) | |
try { | |
const { source_blob: sourceBlob } = await heroku.post('/sources') | |
const { put_url: uploadUrl, get_url: downloadUrl } = sourceBlob | |
core.setOutput('upload_url', uploadUrl) | |
core.setOutput('download_url', downloadUrl) | |
} catch (error) { | |
if (error.statusCode === 503) { | |
console.error('💀 Heroku may be down! Please check its Status page: https://status.heroku.com/') | |
} | |
throw error | |
} | |
# See: https://devcenter.heroku.com/articles/build-and-release-using-the-api#sources-endpoint | |
- name: Upload to the Heroku build source | |
env: | |
UPLOAD_URL: ${{ steps.build-source.outputs.upload_url }} | |
run: | | |
curl "$UPLOAD_URL" \ | |
-X PUT \ | |
-H 'Content-Type:' \ | |
--data-binary @app.tar.gz | |
- name: Create failure status | |
uses: actions/github-script@2b34a689ec86a68d8ab9478298f91d5401337b7d | |
if: ${{ failure() }} | |
env: | |
CONTEXT_NAME: ${{ env.CONTEXT_NAME }} | |
ACTIONS_RUN_LOG: ${{ env.ACTIONS_RUN_LOG }} | |
HEAD_SHA: ${{ needs.pr-metadata.outputs.head_sha }} | |
with: | |
script: | | |
const { CONTEXT_NAME, ACTIONS_RUN_LOG, HEAD_SHA } = process.env | |
const { owner, repo } = context.repo | |
await github.repos.createCommitStatus({ | |
owner, | |
repo, | |
sha: HEAD_SHA, | |
context: CONTEXT_NAME, | |
state: 'error', | |
description: 'Failed to deploy. See logs.', | |
target_url: ACTIONS_RUN_LOG | |
}) | |
- name: Send Slack notification if deployment preparation job failed | |
uses: someimportantcompany/github-actions-slack-message@0b470c14b39da4260ed9e3f9a4f1298a74ccdefd | |
if: ${{ failure() }} | |
with: | |
channel: ${{ secrets.DOCS_STAGING_DEPLOYMENT_FAILURES_SLACK_CHANNEL_ID }} | |
bot-token: ${{ secrets.SLACK_DOCS_BOT_TOKEN }} | |
color: failure | |
text: Staging preparation failed for PR ${{ needs.pr-metadata.outputs.url }} at commit ${{ needs.pr-metadata.outputs.head_sha }}. See ${{ env.ACTIONS_RUN_LOG }}. | |
check-pr-before-deploy: | |
needs: [pr-metadata, prepare-for-deploy] | |
runs-on: ubuntu-latest | |
timeout-minutes: 1 | |
# This interrupts Build, Deploy, and pre-write Undeploy workflow runs in | |
# progress for this PR branch. | |
concurrency: | |
group: 'PR Staging @ ${{ needs.pr-metadata.outputs.head_label }}' | |
cancel-in-progress: true | |
outputs: | |
pull_request_state: ${{ steps.check-pr.outputs.state }} | |
steps: | |
- name: Check pull request state | |
id: check-pr | |
uses: actions/github-script@2b34a689ec86a68d8ab9478298f91d5401337b7d | |
env: | |
PR_NUMBER: ${{ needs.pr-metadata.outputs.number }} | |
with: | |
script: | | |
const { owner, repo } = context.repo | |
const { data: pullRequest } = await github.pulls.get({ | |
owner, | |
repo, | |
pull_number: process.env.PR_NUMBER | |
}) | |
core.setOutput('state', pullRequest.state) | |
deploy: | |
needs: [pr-metadata, prepare-for-deploy, check-pr-before-deploy] | |
if: ${{ needs.check-pr-before-deploy.outputs.pull_request_state == 'open' }} | |
runs-on: ubuntu-latest | |
timeout-minutes: 10 | |
# This interrupts Build, Deploy, and pre-write Undeploy workflow runs in | |
# progress for this PR branch. | |
concurrency: | |
group: 'PR Staging @ ${{ needs.pr-metadata.outputs.head_label }}' | |
cancel-in-progress: true | |
steps: | |
- name: Check out repo's default branch | |
uses: actions/checkout@5a4ac9002d0be2fb38bd78e4b4dbde5606d7042f | |
- name: Setup node | |
uses: actions/setup-node@38d90ce44d5275ad62cc48384b3d8a58c500bb5f | |
with: | |
node-version: 16.8.x | |
cache: npm | |
- name: Install dependencies | |
run: npm ci | |
- name: Install one-off development-only dependencies | |
run: npm install --no-save --include=optional esm | |
- name: Deploy | |
id: deploy | |
uses: actions/github-script@2b34a689ec86a68d8ab9478298f91d5401337b7d | |
env: | |
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
HEROKU_API_TOKEN: ${{ secrets.HEROKU_API_TOKEN }} | |
HYDRO_ENDPOINT: ${{ secrets.HYDRO_ENDPOINT }} | |
HYDRO_SECRET: ${{ secrets.HYDRO_SECRET }} | |
PR_URL: ${{ needs.pr-metadata.outputs.url }} | |
SOURCE_BLOB_URL: ${{ needs.prepare-for-deploy.outputs.source_blob_url }} | |
CONTEXT_NAME: ${{ env.CONTEXT_NAME }} | |
ACTIONS_RUN_LOG: ${{ env.ACTIONS_RUN_LOG }} | |
HEAD_SHA: ${{ needs.pr-metadata.outputs.head_sha }} | |
ALLOWED_POLLING_FAILURES_PER_PHASE: '15' | |
with: | |
script: | | |
const { GITHUB_TOKEN, HEROKU_API_TOKEN } = process.env | |
// Exit if GitHub Actions PAT is not found | |
if (!GITHUB_TOKEN) { | |
throw new Error('You must supply a GITHUB_TOKEN environment variable!') | |
} | |
// Exit if Heroku API token is not found | |
if (!HEROKU_API_TOKEN) { | |
throw new Error('You must supply a HEROKU_API_TOKEN environment variable!') | |
} | |
// Workaround to allow us to load ESM files with `require(...)` | |
const esm = require('esm') | |
require = esm({}) | |
const { default: parsePrUrl } = require('./script/deployment/parse-pr-url') | |
const { default: getOctokit } = require('./script/helpers/github') | |
const { default: deployToStaging } = require('./script/deployment/deploy-to-staging') | |
// This helper uses the `GITHUB_TOKEN` implicitly! | |
// We're using our usual version of Octokit vs. the provided `github` | |
// instance to avoid versioning discrepancies. | |
const octokit = getOctokit() | |
try { | |
const { PR_URL, SOURCE_BLOB_URL, CONTEXT_NAME, ACTIONS_RUN_LOG, HEAD_SHA } = process.env | |
const { owner, repo, pullNumber } = parsePrUrl(PR_URL) | |
if (!owner || !repo || !pullNumber) { | |
throw new Error(`'pullRequestUrl' input must match URL format 'https://github.com/github/(docs|docs-internal)/pull/123' but was '${PR_URL}'`) | |
} | |
const { data: pullRequest } = await octokit.pulls.get({ | |
owner, | |
repo, | |
pull_number: pullNumber | |
}) | |
await deployToStaging({ | |
octokit, | |
pullRequest, | |
forceRebuild: false, | |
// These parameters will ONLY be set by Actions | |
sourceBlobUrl: SOURCE_BLOB_URL, | |
runId: context.runId | |
}) | |
await github.repos.createCommitStatus({ | |
owner, | |
repo, | |
sha: HEAD_SHA, | |
context: CONTEXT_NAME, | |
state: 'success', | |
description: 'Successfully deployed! See logs.', | |
target_url: ACTIONS_RUN_LOG | |
}) | |
} catch (error) { | |
console.error(`Failed to deploy to staging: ${error.message}`) | |
console.error(error) | |
throw error | |
} | |
- name: Mark the deployment as inactive if timed out | |
uses: actions/github-script@2b34a689ec86a68d8ab9478298f91d5401337b7d | |
if: ${{ steps.deploy.outcome == 'cancelled' }} | |
env: | |
DEPLOYMENT_ID: ${{ steps.deploy.outputs.deploymentId }} | |
LOG_URL: ${{ steps.deploy.outputs.logUrl }} | |
with: | |
script: | | |
const { DEPLOYMENT_ID, LOG_URL } = process.env | |
const { owner, repo } = context.repo | |
if (!DEPLOYMENT_ID) { | |
throw new Error('A deployment wasn't created before a timeout occurred!') | |
} | |
await github.repos.createDeploymentStatus({ | |
owner, | |
repo, | |
deployment_id: DEPLOYMENT_ID, | |
state: 'error', | |
description: 'The deployment step timed out. See workflow logs.', | |
log_url: LOG_URL, | |
// The 'ant-man' preview is required for `state` values of 'inactive', as well as | |
// the use of the `log_url`, `environment_url`, and `auto_inactive` parameters. | |
// The 'flash' preview is required for `state` values of 'in_progress' and 'queued'. | |
mediaType: { | |
previews: ['ant-man', 'flash'], | |
}, | |
}) | |
console.log('⏲️ Deployment status: error - The deployment timed out...') | |
- name: Create failure status | |
uses: actions/github-script@2b34a689ec86a68d8ab9478298f91d5401337b7d | |
if: ${{ failure() }} | |
env: | |
CONTEXT_NAME: ${{ env.CONTEXT_NAME }} | |
ACTIONS_RUN_LOG: ${{ env.ACTIONS_RUN_LOG }} | |
HEAD_SHA: ${{ needs.pr-metadata.outputs.head_sha }} | |
with: | |
script: | | |
const { CONTEXT_NAME, ACTIONS_RUN_LOG, HEAD_SHA } = process.env | |
const { owner, repo } = context.repo | |
await github.repos.createCommitStatus({ | |
owner, | |
repo, | |
sha: HEAD_SHA, | |
context: CONTEXT_NAME, | |
state: 'error', | |
description: 'Failed to deploy. See logs.', | |
target_url: ACTIONS_RUN_LOG | |
}) | |
- name: Send Slack notification if deployment job failed | |
uses: someimportantcompany/github-actions-slack-message@0b470c14b39da4260ed9e3f9a4f1298a74ccdefd | |
if: ${{ failure() }} | |
with: | |
channel: ${{ secrets.DOCS_STAGING_DEPLOYMENT_FAILURES_SLACK_CHANNEL_ID }} | |
bot-token: ${{ secrets.SLACK_DOCS_BOT_TOKEN }} | |
color: failure | |
text: Staging deployment failed for PR ${{ needs.pr-metadata.outputs.url }} at commit ${{ needs.pr-metadata.outputs.head_sha }}. See ${{ env.ACTIONS_RUN_LOG }}. |