1
0
mirror of synced 2025-12-20 18:36:31 -05:00
Files
docs/script/deployment/undeploy-from-staging.js
James M. Greene 08db1c970c Refactor Staging deployment workflow to support open source PRs (#20459)
* Add a Staging build workflow

* Remove all commented out code from build workflow

It will be handled in https://github.com/github/docs-engineering/issues/726

* Use pinned version of upload-artifact action

* Tweaks to build

* Minor deployment script refactoring

* Update the Staging deployment workflow

* Missed refactoring tweak

* Add relevant comments

* Update Heroku app naming convention for Actions deploy to include 'gha-' prefix

* Update Heroku app ConfigVars and SourceBlob for optional prebuilt app

* Remove obsolete 'dist/' dir from PR build artifact

See https://github.com/github/docs-internal/pull/20405

* Ensure a new enough version of npm is used

* Switch to creating a tarball for upload

* Remove obsolete 'layouts' dir from file list

* Ditch the verbosity for 'tar'... too many files

* Add tarball support to deploy

* Add esm workaround to deploy script

See https://github.com/actions/github-script/issues/168

* Temporarily ignore staging deploy workflow from workflow linter

* Update deployment to use a Heroku Build Source instead of a GitHub Actions Artifact

* Update undeploy workflow to use ESM workaround

See https://github.com/actions/github-script/issues/168

* Add 'esm' package to optionalDependencies to better support workaround

See https://github.com/actions/github-script/issues/168

* Add Slack notifications for workflow failures

* Wrap AppSetup polling in try-catch

* Improve dyno monitoring

* Rename 'script/deploy' to have a .js extension #esm

* Update script references to include the extension

* Use non-deprecated Sources API for Heroku

* Use normal quotes

* Stub in a step to mark deployment inactive after timing out

* Apply suggestions from code review

Co-authored-by: Rachael Sewell <rachmari@github.com>

Co-authored-by: Rachael Sewell <rachmari@github.com>
2021-08-25 20:45:51 +00:00

111 lines
3.4 KiB
JavaScript

#!/usr/bin/env node
import Heroku from 'heroku-client'
import createStagingAppName from './create-staging-app-name.js'
export default async function undeployFromStaging({
octokit,
pullRequest,
// These parameters will only be set by Actions
runId = null,
}) {
// Start a timer so we can report how long the deployment takes
const startTime = Date.now()
// Extract some important properties from the PR
const {
number: pullNumber,
base: {
repo: {
name: repo,
owner: { login: owner },
},
},
head: { ref: branch },
} = pullRequest
const workflowRunLog = runId ? `https://github.com/${owner}/${repo}/actions/runs/${runId}` : null
const logUrl = workflowRunLog
const appName = createStagingAppName({ repo, pullNumber, branch })
try {
const title = `from the 'staging' environment as '${appName}'`
console.log(`About to undeploy ${title}...`)
// Time to talk to Heroku...
const heroku = new Heroku({ token: process.env.HEROKU_API_TOKEN })
// Is there already a Heroku App for this PR?
let appExists = true
try {
await heroku.get(`/apps/${appName}`)
} catch (error) {
appExists = false
}
// If there is an existing app, delete it
if (appExists) {
try {
await heroku.delete(`/apps/${appName}`)
console.log(`Heroku app '${appName}' deleted`)
} catch (error) {
throw new Error(`Failed to delete Heroku app '${appName}'. Error: ${error}`)
}
}
// Get the latest deployment environment to signal its deactivation
const { data: deployments } = await octokit.repos.listDeployments({
owner,
repo,
// In the GitHub API, there can only be one active deployment per environment.
// For our many staging apps, we must use the unique appName as the environment.
environment: appName,
})
if (deployments.length === 0) {
console.log('🚀 No deployments to deactivate!')
console.log(
`Finished undeploying after ${Math.round((Date.now() - startTime) / 1000)} seconds`
)
return
}
console.log(`Found ${deployments.length} GitHub Deployments`, deployments)
// Deactivate ALL of the deployments
for (const deployment of deployments) {
const { data: deploymentStatus } = await octokit.repos.createDeploymentStatus({
owner,
repo,
deployment_id: deployment.id,
state: 'inactive',
description: 'The app was undeployed',
...(logUrl && { log_url: logUrl }),
// 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 (ID: ${deployment.id}): ${deploymentStatus.state} - ${deploymentStatus.description}`
)
}
console.log(`Finished undeploying after ${Math.round((Date.now() - startTime) / 1000)} seconds`)
} catch (error) {
// Report failure!
const failureMessage = `Undeployment failed after ${Math.round(
(Date.now() - startTime) / 1000
)} seconds. See logs for more information.`
console.error(failureMessage)
// Re-throw the error to bubble up
throw error
}
}