* Add 'script/deploy' to enable manual deploys to Heroku * Pass API tokens into 'deploy-to-staging' module usage * Construct Octokit instance to pass in * Get PR branch name and verify state * Reorganize * Rename option to 'octokit' * Add missing option * Actually use the convenience methods for convenience * Simplify top-level script * Top-level script revisions * Add parse-pr-url module * Add create-staging-app-name module * Remove misplaced comment * Pass in owner * Use owner param * More variables * Pass owner along more * Correct prNumber param reference * Add WIP deploy-to-staging module * Prevent 'scripts/' and '.github/actions-scripts/' files from being modified in open source repo * Extract PR author earlier * Add note about optionally supplying DOCUBOT_REPO_PAT env var * Override Heroku env var during AppSetup creation instead of later to avoid triggering a second deploy * Updates to deploy-to-staging module * Lots of updates * Add dyno start-up monitoring and warmup requests * Ignore 'script/deploy' in the repository-references test * Correct path to Octokit helper * Temporarily add a 'gha-' prefix to environment names * Log whole error if terminal. Good for Octokit errors! * Correct Octokit preview configuration * Add more logging around Heroku build and release * Added more timings to log messages * Monitor dyno states specifically from the dyno list view to avoid 404 oddities when Free dynos are dropped and non-Free dynos are added * Don't wait for AppSetup status as it includes the Build time * Updating logging since we don't see DeploymentStatus update messages in the UI =( * Refactor to extract more properties from the PR object * Add a workflow to deploy PRs to Staging * Fix workflow description * Add skeleton workflow and module for undeploying * Remove commented out code * Update undeployment module * Add '--destroy' flag to 'script/deploy' options * Add timeout and concurrency key for undeployment * Add timeout and concurrency key for deployment * Remove dangling unneeded function declaration * Add ant-man preview for inactive deployment state setting * Fix reference to pull request number * Fix reference to pull request number * Refactor to extract more properties from the PR object * Fix reference to pull request number * Remove workflow * Add workflow to undeploy closed PRs from staging * Add repository filters to jobs * Update to using actions/github-script@4.0.2 * Pass more environment variables that affect deployments * Add explicit .js extensions to local require in Actions workflow * Check out the code and install deps first, of course * Try local requires without the explicit .js extension * Use our usual version of Octokit instead of the provided 'github' instance to avoid versioning discrepancies * Explicitly pass in GITHUB_TOKEN to github-script * Point to the workflow run page as a default log_url * Exclude staging deployment workflows from the workflow linter until we can get support for the 'concurrency' key (https://github.com/cschleiden/actions-linter/issues/79) * Remove 'gha-' prefix
106 lines
3.3 KiB
JavaScript
106 lines
3.3 KiB
JavaScript
const Heroku = require('heroku-client')
|
|
const createStagingAppName = require('./create-staging-app-name')
|
|
|
|
module.exports = async function undeployFromStaging ({
|
|
herokuToken,
|
|
octokit,
|
|
pullRequest,
|
|
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: herokuToken })
|
|
|
|
// 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
|
|
}
|
|
}
|