Files
deploy-pages/src/deployment.js

223 lines
7.6 KiB
JavaScript
Raw Normal View History

2021-12-13 23:03:09 -05:00
const core = require('@actions/core')
// All variables we need from the runtime are loaded here
const getContext = require('./context')
const {
2023-02-22 08:26:42 -06:00
getSignedArtifactUrl,
createPagesDeployment,
getPagesDeploymentStatus,
cancelPagesDeployment
} = require('./api-client')
2021-12-13 23:03:09 -05:00
const errorStatus = {
2022-08-23 17:19:21 -07:00
unknown_status: 'Unable to get deployment status.',
not_found: 'Deployment not found.',
deployment_attempt_error: 'Deployment temporarily failed, a retry will be automatically scheduled...'
}
2021-12-13 23:03:09 -05:00
class Deployment {
2022-08-23 17:19:21 -07:00
constructor() {
const context = getContext()
this.runTimeUrl = context.runTimeUrl
this.repositoryNwo = context.repositoryNwo
this.runTimeToken = context.runTimeToken
this.buildVersion = context.buildVersion
this.buildActor = context.buildActor
this.actionsId = context.actionsId
2022-08-23 17:19:21 -07:00
this.githubToken = context.githubToken
this.workflowRun = context.workflowRun
this.deploymentInfo = null
this.githubApiUrl = context.githubApiUrl
this.githubServerUrl = context.githubServerUrl
2022-08-23 17:19:21 -07:00
this.artifactName = context.artifactName
2022-09-09 18:44:03 -05:00
this.isPreview = context.isPreview === true
2022-08-23 17:19:21 -07:00
}
2021-12-13 23:03:09 -05:00
2022-08-23 17:19:21 -07:00
// Ask the runtime for the unsigned artifact URL and deploy to GitHub Pages
// by creating a deployment with that artifact
async create(idToken) {
try {
core.info(`Actor: ${this.buildActor}`)
core.info(`Action ID: ${this.actionsId}`)
core.info(`Actions Workflow Run ID: ${this.workflowRun}`)
const artifactUrl = await getSignedArtifactUrl({
runtimeToken: this.runTimeToken,
workflowRunId: this.workflowRun,
artifactName: this.artifactName
2022-08-23 17:19:21 -07:00
})
const deployment = await createPagesDeployment({
githubToken: this.githubToken,
artifactUrl,
buildVersion: this.buildVersion,
idToken,
isPreview: this.isPreview
2022-08-23 17:19:21 -07:00
})
this.deploymentInfo = {
...deployment,
id: deployment?.['status_url']?.split('/')?.pop() || this.buildVersion,
pending: true
2022-08-23 17:19:21 -07:00
}
core.info(`Created deployment for ${this.buildVersion}, ID: ${this.deploymentInfo.id}`)
core.info(JSON.stringify(deployment))
return deployment
2022-08-23 17:19:21 -07:00
} catch (error) {
core.error(error.stack)
2022-08-23 17:19:21 -07:00
// output raw error in debug mode.
core.debug(JSON.stringify(error))
// build customized error message based on server response
if (error.response) {
let errorMessage = `Failed to create deployment (status: ${error.response.status}) with build version ${this.buildVersion}. `
if (error.response.status == 400) {
let message = ''
if (error.response.data && error.response.data.message) {
message = error.response.data.message
} else {
message = error.response.data
2022-06-28 16:08:07 -07:00
}
2022-08-23 17:19:21 -07:00
errorMessage += `Responded with: ${message}`
} else if (error.response.status == 403) {
errorMessage += 'Ensure GITHUB_TOKEN has permission "pages: write".'
2022-08-23 17:19:21 -07:00
} else if (error.response.status == 404) {
const pagesSettingsUrl = `${this.githubServerUrl}/${this.repositoryNwo}/settings/pages`
errorMessage += `Ensure GitHub Pages has been enabled: ${pagesSettingsUrl}`
2022-08-23 17:19:21 -07:00
} else if (error.response.status >= 500) {
2023-02-22 08:26:42 -06:00
errorMessage +=
'Server error, is githubstatus.com reporting a Pages outage? Please re-run the deployment at a later time.'
}
throw new Error(errorMessage)
2022-08-23 17:19:21 -07:00
} else {
throw error
2021-12-13 23:03:09 -05:00
}
}
2022-08-23 17:19:21 -07:00
}
2021-12-13 23:03:09 -05:00
2022-08-23 17:19:21 -07:00
// Poll the deployment endpoint for status
async check() {
// Don't attempt to check status if no deployment was created
if (!this.deploymentInfo) {
core.setFailed(errorStatus.not_found)
return
}
if (this.deploymentInfo.pending !== true) {
core.setFailed(errorStatus.unknown_status)
return
}
const deploymentId = this.deploymentInfo.id || this.buildVersion
const timeout = Number(core.getInput('timeout'))
const reportingInterval = Number(core.getInput('reporting_interval'))
const maxErrorCount = Number(core.getInput('error_count'))
let startTime = Date.now()
let errorCount = 0
// Time in milliseconds between two deployment status report when status errored, default 0.
let errorReportingInterval = 0
2022-08-23 17:19:21 -07:00
try {
/*eslint no-constant-condition: ["error", { "checkLoops": false }]*/
while (true) {
// Handle reporting interval
2023-02-22 08:23:39 -06:00
await new Promise(resolve => setTimeout(resolve, reportingInterval + errorReportingInterval))
2022-08-23 17:19:21 -07:00
// Check status
let res = await getPagesDeploymentStatus({
githubToken: this.githubToken,
deploymentId
2022-08-23 17:19:21 -07:00
})
2021-12-13 23:03:09 -05:00
2023-02-22 08:23:39 -06:00
if (res.data.status === 'succeed') {
2022-08-23 17:19:21 -07:00
core.info('Reported success!')
core.setOutput('status', 'succeed')
this.deploymentInfo.pending = false
2022-08-23 17:19:21 -07:00
break
2023-02-22 08:23:39 -06:00
} else if (res.data.status === 'deployment_failed') {
2022-08-23 17:19:21 -07:00
// Fall into permanent error, it may be caused by ongoing incident or malicious deployment content or exhausted automatic retry times.
core.setFailed('Deployment failed, try again later.')
this.deploymentInfo.pending = false
2022-08-23 17:19:21 -07:00
break
2023-02-22 08:23:39 -06:00
} else if (res.data.status === 'deployment_content_failed') {
2022-08-23 17:19:21 -07:00
// The uploaded artifact is invalid.
core.setFailed(
'Artifact could not be deployed. Please ensure the content does not contain any hard links, symlinks and total size is less than 10GB.'
)
this.deploymentInfo.pending = false
2022-08-23 17:19:21 -07:00
break
} else if (errorStatus[res.data.status]) {
// A temporary error happened, will query the status again
2023-02-22 08:23:39 -06:00
core.warning(errorStatus[res.data.status])
2022-08-23 17:19:21 -07:00
} else {
core.info('Current status: ' + res.data.status)
}
2023-02-22 08:23:39 -06:00
if (res.status !== 200 || !!errorStatus[res.data.status]) {
2022-08-23 17:19:21 -07:00
errorCount++
2021-12-13 23:03:09 -05:00
2023-02-22 08:23:39 -06:00
// set the maximum error reporting interval greater than 15 sec but below 30 sec.
2022-08-23 17:19:21 -07:00
if (errorReportingInterval < 1000 * 15) {
errorReportingInterval = (errorReportingInterval << 1) | 1
2021-12-13 23:03:09 -05:00
}
2022-08-23 17:19:21 -07:00
} else {
// reset the error reporting interval once get the proper status back.
errorReportingInterval = 0
}
2022-03-28 12:32:59 -07:00
2022-08-23 17:19:21 -07:00
if (errorCount >= maxErrorCount) {
2023-02-22 08:23:39 -06:00
core.error('Too many errors, aborting!')
2022-08-23 17:19:21 -07:00
core.setFailed('Failed with status code: ' + res.status)
// Explicitly cancel the deployment
await this.cancel()
return
2021-12-13 23:03:09 -05:00
}
2022-08-23 17:19:21 -07:00
// Handle timeout
if (Date.now() - startTime >= timeout) {
2023-02-22 08:23:39 -06:00
core.error('Timeout reached, aborting!')
2022-08-23 17:19:21 -07:00
core.setFailed('Timeout reached, aborting!')
// Explicitly cancel the deployment
await this.cancel()
2022-08-23 17:19:21 -07:00
return
2021-12-20 10:13:46 -08:00
}
2021-12-13 23:03:09 -05:00
}
2022-08-23 17:19:21 -07:00
} catch (error) {
core.setFailed(error)
2023-02-22 08:23:39 -06:00
if (error.response?.data) {
core.error(JSON.stringify(error.response.data))
2022-08-23 17:19:21 -07:00
}
2021-12-13 23:03:09 -05:00
}
}
async cancel() {
// Don't attempt to cancel if no deployment was created
if (!this.deploymentInfo || this.deploymentInfo.pending !== true) {
return
}
// Cancel the deployment
try {
const deploymentId = this.deploymentInfo.id || this.buildVersion
await cancelPagesDeployment({
githubToken: this.githubToken,
deploymentId
})
core.info(`Canceled deployment with ID ${deploymentId}`)
this.deploymentInfo.pending = false
} catch (error) {
core.setFailed(error)
2023-02-22 08:23:39 -06:00
if (error.response?.data) {
core.error(JSON.stringify(error.response.data))
}
}
}
2022-08-23 17:19:21 -07:00
}
module.exports = { Deployment }