Compare commits

..

10 Commits

Author SHA1 Message Date
Yoann Chaudet
114f9cc1f8 Merge pull request #56 from actions/cancel
Explicitly handle cancellation on errors
2022-08-24 10:46:21 -07:00
Yoann Chaudet
0dfe0f0668 Merge pull request #55 from actions/formatter
Bring back the formatter
2022-08-24 08:59:01 -07:00
Yoann Chaudet
c7c77bb21c Explicitly handle cancellation on errors 2022-08-23 21:32:40 -07:00
Yoann Chaudet
369d1aed92 Add linter 2022-08-23 17:28:44 -07:00
Yoann Chaudet
4865e84b02 Bring back the formatter 2022-08-23 17:19:21 -07:00
James M. Greene
b627026553 Merge pull request #54 from actions/codeowners-file
Add CODEOWNERS file
2022-08-19 13:29:24 -05:00
James M. Greene
9bd912c0ca Add CODEOWNERS file 2022-08-19 13:28:07 -05:00
James M. Greene
ed034ea1c3 Merge pull request #53 from actions/consistent-release-workflow
Make the major version release workflow consistent with other Actions
2022-08-19 13:27:01 -05:00
James M. Greene
8f9a38d5e7 Update major version only for full releases 2022-08-19 12:33:44 -05:00
James M. Greene
71b1669225 Make the major version release workflow consistent with other Actions
Based on https://github.com/paper-spa/configure-pages/edit/main/.github/workflows/release.yml
2022-08-19 12:26:27 -05:00
17 changed files with 723 additions and 580 deletions

View File

@@ -11,7 +11,7 @@
"SharedArrayBuffer": "readonly" "SharedArrayBuffer": "readonly"
}, },
"parserOptions": { "parserOptions": {
"ecmaVersion": 2018 "ecmaVersion": 2020
}, },
"rules": { "rules": {
"semi": ["error", "never"] "semi": ["error", "never"]

2
.github/CODEOWNERS vendored Normal file
View File

@@ -0,0 +1,2 @@
# Default PR reviewers
* @actions/pages

34
.github/workflows/check-formatting.yml vendored Normal file
View File

@@ -0,0 +1,34 @@
name: Checking formatting
on:
push:
branches:
- main
pull_request:
permissions:
contents: read
# This allows a subsequently queued workflow run to interrupt previous runs
concurrency:
group: '${{ github.workflow }} @ ${{ github.event.pull_request.head.label || github.head_ref || github.ref }}'
cancel-in-progress: true
jobs:
test:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Setup Node.JS
uses: actions/setup-node@v3
with:
node-version: 16.x
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Verify formatting
run: npm run format:check

34
.github/workflows/check-linter.yml vendored Normal file
View File

@@ -0,0 +1,34 @@
name: Checking linter
on:
push:
branches:
- main
pull_request:
permissions:
contents: read
# This allows a subsequently queued workflow run to interrupt previous runs
concurrency:
group: '${{ github.workflow }} @ ${{ github.event.pull_request.head.label || github.head_ref || github.ref }}'
cancel-in-progress: true
jobs:
test:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Setup Node.JS
uses: actions/setup-node@v3
with:
node-version: 16.x
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Verify linter
run: npm run lint

View File

@@ -1,28 +1,30 @@
name: Release new action version name: Release
on: on:
release: release:
types: [edited] types: [released]
workflow_dispatch: workflow_dispatch:
inputs: inputs:
TAG_NAME: TAG_NAME:
description: 'Tag name that the major tag will point to' description: "Tag name that the major tag will point to"
required: true required: true
env: env:
TAG_NAME: ${{ github.event.inputs.TAG_NAME || github.event.release.tag_name }} TAG_NAME: ${{ github.event.inputs.TAG_NAME || github.event.release.tag_name }}
permissions: permissions:
contents: write contents: write
jobs: jobs:
update_tag: update_tag:
name: Update the major tag to include the ${{ github.event.inputs.TAG_NAME || github.event.release.tag_name }} changes name: Update the major tag to include the ${{ github.event.inputs.TAG_NAME || github.event.release.tag_name }} changes
environment:
name: releaseNewActionVersion
runs-on: ubuntu-latest runs-on: ubuntu-latest
environment:
# Note: this environment is protected
name: Release
steps: steps:
- name: Update the ${{ env.TAG_NAME }} tag - name: Update the ${{ env.TAG_NAME }} tag
id: update-major-tag id: update-major-tag
uses: actions/publish-action@v0.1.0 uses: actions/publish-action@v0.1.0
with: with:
source-tag: ${{ env.TAG_NAME }} source-tag: ${{ env.TAG_NAME }}
slack-webhook: ${{ secrets.SLACK_WEBHOOK }} slack-webhook: ${{ secrets.SLACK_WEBHOOK }}

View File

@@ -1,10 +0,0 @@
{
"printWidth": 80,
"tabWidth": 2,
"useTabs": false,
"semi": false,
"singleQuote": true,
"trailingComma": "none",
"bracketSpacing": false,
"arrowParens": "avoid"
}

10
.prettierrc.yml Normal file
View File

@@ -0,0 +1,10 @@
# Prettier (formatter) configuration
---
printWidth: 120
tabWidth: 2
useTabs: false
semi: false
singleQuote: true
trailingComma: none
bracketSpacing: true
arrowParens: avoid

394
dist/index.js vendored
View File

@@ -8207,184 +8207,222 @@ const axios = __nccwpck_require__(6545)
const getContext = __nccwpck_require__(1319) const getContext = __nccwpck_require__(1319)
const errorStatus = { const errorStatus = {
'unknown_status' : 'Unable to get deployment status.', unknown_status: 'Unable to get deployment status.',
'not_found' : 'Deployment not found.', not_found: 'Deployment not found.',
'deployment_attempt_error' : 'Deployment temporarily failed, a retry will be automatically scheduled...' deployment_attempt_error: 'Deployment temporarily failed, a retry will be automatically scheduled...'
} }
class Deployment { class Deployment {
constructor() { constructor() {
const context = getContext() const context = getContext()
this.runTimeUrl = context.runTimeUrl this.runTimeUrl = context.runTimeUrl
this.repositoryNwo = context.repositoryNwo this.repositoryNwo = context.repositoryNwo
this.runTimeToken = context.runTimeToken this.runTimeToken = context.runTimeToken
this.buildVersion = context.buildVersion this.buildVersion = context.buildVersion
this.buildActor = context.buildActor this.buildActor = context.buildActor
this.actionsId = context.workflowRun this.actionsId = context.workflowRun
this.githubToken = context.githubToken this.githubToken = context.githubToken
this.workflowRun = context.workflowRun this.workflowRun = context.workflowRun
this.requestedDeployment = false this.requestedDeployment = false
this.deploymentInfo = null this.deploymentInfo = null
this.githubApiUrl = context.githubApiUrl this.githubApiUrl = context.githubApiUrl
this.artifactName = context.artifactName this.artifactName = context.artifactName
} }
// Ask the runtime for the unsigned artifact URL and deploy to GitHub Pages // Ask the runtime for the unsigned artifact URL and deploy to GitHub Pages
// by creating a deployment with that artifact // by creating a deployment with that artifact
async create(idToken) { async create(idToken) {
try { try {
core.info(`Actor: ${this.buildActor}`) core.info(`Actor: ${this.buildActor}`)
core.info(`Action ID: ${this.actionsId}`) core.info(`Action ID: ${this.actionsId}`)
const pagesDeployEndpoint = `${this.githubApiUrl}/repos/${this.repositoryNwo}/pages/deployment` const pagesDeployEndpoint = `${this.githubApiUrl}/repos/${this.repositoryNwo}/pages/deployment`
const artifactExgUrl = `${this.runTimeUrl}_apis/pipelines/workflows/${this.workflowRun}/artifacts?api-version=6.0-preview` const artifactExgUrl = `${this.runTimeUrl}_apis/pipelines/workflows/${this.workflowRun}/artifacts?api-version=6.0-preview`
core.info(`Artifact URL: ${artifactExgUrl}`) core.info(`Artifact URL: ${artifactExgUrl}`)
const {data} = await axios.get(artifactExgUrl, { const { data } = await axios.get(artifactExgUrl, {
headers: {
Authorization: `Bearer ${this.runTimeToken}`,
'Content-Type': 'application/json'
}
})
core.info(JSON.stringify(data))
const artifactRawUrl = data?.value?.find(artifact => artifact.name === this.artifactName)?.url
if (!artifactRawUrl) {
throw new Error(
'No uploaded artifact was found! Please check if there are any errors at build step, or uploaded artifact name is correct.'
)
}
const artifactUrl = `${artifactRawUrl}&%24expand=SignedContent`
const payload = {
artifact_url: artifactUrl,
pages_build_version: this.buildVersion,
oidc_token: idToken
}
core.info(`Creating deployment with payload:\n${JSON.stringify(payload, null, '\t')}`)
const response = await axios.post(pagesDeployEndpoint, payload, {
headers: {
Accept: 'application/vnd.github.v3+json',
Authorization: `Bearer ${this.githubToken}`,
'Content-type': 'application/json'
}
})
this.requestedDeployment = true
core.info(`Created deployment for ${this.buildVersion}`)
if (response && response.data) {
core.info(JSON.stringify(response.data))
this.deploymentInfo = response.data
}
} catch (error) {
core.info(error.stack)
// 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
}
errorMessage += `Responded with: ${message}`
} else if (error.response.status == 403) {
errorMessage += `Ensure GITHUB_TOKEN has permission "pages: write".`
} else if (error.response.status == 404) {
errorMessage += `Ensure GitHub Pages has been enabled.`
} else if (error.response.status >= 500) {
errorMessage += `Server error, is githubstatus.com reporting a Pages outage? Please re-run the deployment at a later time.`
}
throw errorMessage
} else {
throw error
}
}
}
// Poll the deployment endpoint for status
async check() {
try {
const statusUrl =
this.deploymentInfo != null
? this.deploymentInfo['status_url']
: `${this.githubApiUrl}/repos/${this.repositoryNwo}/pages/deployment/status/${this.buildVersion}`
core.setOutput('page_url', this.deploymentInfo != null ? this.deploymentInfo['page_url'] : '')
const timeout = Number(core.getInput('timeout'))
const reportingInterval = Number(core.getInput('reporting_interval'))
const maxErrorCount = Number(core.getInput('error_count'))
var startTime = Date.now()
var errorCount = 0
// Time in milliseconds between two deployment status report when status errored, default 0.
var errorReportingInterval = 0
/*eslint no-constant-condition: ["error", { "checkLoops": false }]*/
while (true) {
// Handle reporting interval
await new Promise(r => setTimeout(r, reportingInterval + errorReportingInterval))
// Check status
var res = await axios.get(statusUrl, {
headers: { headers: {
Authorization: `Bearer ${this.runTimeToken}`, Authorization: `token ${this.githubToken}`
'Content-Type': 'application/json'
} }
}) })
core.info(JSON.stringify(data))
const artifactRawUrl = data?.value?.find(artifact => artifact.name === this.artifactName)?.url if (res.data.status == 'succeed') {
if (!artifactRawUrl) { core.info('Reported success!')
throw new Error('No uploaded artifact was found! Please check if there are any errors at build step, or uploaded artifact name is correct.') core.setOutput('status', 'succeed')
break
} else if (res.data.status == 'deployment_failed') {
// 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.')
break
} else if (res.data.status == 'deployment_content_failed') {
// 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.'
)
break
} else if (errorStatus[res.data.status]) {
// A temporary error happened, will query the status again
core.info(errorStatus[res.data.status])
} else {
core.info('Current status: ' + res.data.status)
} }
const artifactUrl = `${artifactRawUrl}&%24expand=SignedContent` if (res.status != 200 || !!errorStatus[res.data.status]) {
const payload = { errorCount++
artifact_url: artifactUrl,
pages_build_version: this.buildVersion, // set the Maximum error reporting interval greater than 15 sec but below 30 sec.
oidc_token: idToken if (errorReportingInterval < 1000 * 15) {
errorReportingInterval = (errorReportingInterval << 1) | 1
}
} else {
// reset the error reporting interval once get the proper status back.
errorReportingInterval = 0
} }
core.info(`Creating deployment with payload:\n${JSON.stringify(payload, null, '\t')}`)
const response = await axios.post(pagesDeployEndpoint, payload, { if (errorCount >= maxErrorCount) {
core.info('Too many errors, aborting!')
core.setFailed('Failed with status code: ' + res.status)
// Explicitly cancel the deployment
await this.cancel()
return
}
// Handle timeout
if (Date.now() - startTime >= timeout) {
core.info('Timeout reached, aborting!')
core.setFailed('Timeout reached, aborting!')
// Explicitly cancel the deployment
await this.cancel()
return
}
}
} catch (error) {
core.setFailed(error)
if (error.response && error.response.data) {
core.info(JSON.stringify(error.response.data))
}
}
}
async cancel() {
// Don't attemp to cancel if no deployment was created
if (!this.requestedDeployment) {
return
}
// Cancel the deployment
try {
const pagesCancelDeployEndpoint = `${this.githubApiUrl}/repos/${this.repositoryNwo}/pages/deployment/cancel/${this.buildVersion}`
await axios.put(
pagesCancelDeployEndpoint,
{},
{
headers: { headers: {
Accept: 'application/vnd.github.v3+json', Accept: 'application/vnd.github.v3+json',
Authorization: `Bearer ${this.githubToken}`, Authorization: `Bearer ${this.githubToken}`,
'Content-type': 'application/json' 'Content-type': 'application/json'
} }
})
this.requestedDeployment = true
core.info(`Created deployment for ${this.buildVersion}`)
if (response && response.data) {
core.info(JSON.stringify(response.data))
this.deploymentInfo = response.data
}
} catch (error) {
core.info(error.stack)
// 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
}
errorMessage += `Responded with: ${message}`
}
else if (error.response.status == 403) {
errorMessage += `Ensure GITHUB_TOKEN has permission "pages: write".`
} else if (error.response.status == 404) {
errorMessage += `Ensure GitHub Pages has been enabled.`
}
else if (error.response.status >= 500) {
errorMessage += `Server error, is githubstatus.com reporting a Pages outage? Please re-run the deployment at a later time.`
}
throw errorMessage
} else {
throw error
}
}
}
// Poll the deployment endpoint for status
async check() {
try {
const statusUrl = this.deploymentInfo != null ?
this.deploymentInfo["status_url"] :
`${this.githubApiUrl}/repos/${this.repositoryNwo}/pages/deployment/status/${process.env['GITHUB_SHA']}`
core.setOutput('page_url', this.deploymentInfo != null ? this.deploymentInfo["page_url"] : "")
const timeout = Number(core.getInput('timeout'))
const reportingInterval = Number(core.getInput('reporting_interval'))
const maxErrorCount = Number(core.getInput('error_count'))
var startTime = Date.now()
var errorCount = 0
// Time in milliseconds between two deployment status report when status errored, default 0.
var errorReportingInterval = 0
/*eslint no-constant-condition: ["error", { "checkLoops": false }]*/
while (true) {
// Handle reporting interval
await new Promise(r => setTimeout(r, reportingInterval + errorReportingInterval))
// Check status
var res = await axios.get(statusUrl, {
headers: {
Authorization: `token ${this.githubToken}`
}
})
if (res.data.status == 'succeed') {
core.info('Reported success!')
core.setOutput('status', 'succeed')
break
} else if (res.data.status == 'deployment_failed') {
// 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.')
break
} else if(res.data.status == 'deployment_content_failed') {
// 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.')
break
} else if (errorStatus[res.data.status]) {
// A temporary error happened, will query the status again
core.info(errorStatus[res.data.status])
} else {
core.info('Current status: ' + res.data.status)
}
if (res.status != 200 || !!errorStatus[res.data.status]) {
errorCount++
// set the Maximum error reporting interval greater than 15 sec but below 30 sec.
if (errorReportingInterval < 1000 * 15) {
errorReportingInterval = errorReportingInterval << 1 | 1
}
} else {
// reset the error reporting interval once get the proper status back.
errorReportingInterval = 0
}
if (errorCount >= maxErrorCount) {
core.info('Too many errors, aborting!')
core.setFailed('Failed with status code: ' + res.status)
break
}
// Handle timeout
if (Date.now() - startTime >= timeout) {
core.info('Timeout reached, aborting!')
core.setFailed('Timeout reached, aborting!')
return
}
}
} catch (error) {
core.setFailed(error)
if (error.response && error.response.data) {
core.info(JSON.stringify(error.response.data))
} }
)
core.info(`Deployment cancelled with ${pagesCancelDeployEndpoint}`)
} catch (error) {
core.setFailed(error)
if (error.response && error.response.data) {
core.info(JSON.stringify(error.response.data))
} }
} }
} }
module.exports = {Deployment} }
module.exports = { Deployment }
/***/ }), /***/ }),
@@ -8409,7 +8447,7 @@ axiosRetry(axios, {
} }
}) })
const {Deployment} = __nccwpck_require__(2877) const { Deployment } = __nccwpck_require__(2877)
async function emitTelemetry() { async function emitTelemetry() {
// All variables we need from the runtime are set in the Deployment constructor // All variables we need from the runtime are set in the Deployment constructor
@@ -8419,7 +8457,7 @@ async function emitTelemetry() {
await axios await axios
.post( .post(
telemetryUrl, telemetryUrl,
{github_run_id: deployment.workflowRun}, { github_run_id: deployment.workflowRun },
{ {
headers: { headers: {
Accept: 'application/vnd.github.v3+json', Accept: 'application/vnd.github.v3+json',
@@ -8447,7 +8485,7 @@ async function main() {
main() main()
module.exports = {emitTelemetry} module.exports = { emitTelemetry }
/***/ }), /***/ }),
@@ -8621,39 +8659,17 @@ __nccwpck_require__(4307)
const core = __nccwpck_require__(2186) const core = __nccwpck_require__(2186)
// const github = require('@actions/github'); // TODO: Not used until we publish API endpoint to the @action/github package // const github = require('@actions/github'); // TODO: Not used until we publish API endpoint to the @action/github package
const axios = __nccwpck_require__(6545)
const {Deployment} = __nccwpck_require__(2877) const { Deployment } = __nccwpck_require__(2877)
const deployment = new Deployment() const deployment = new Deployment()
// TODO: If the artifact hasn't been created, we can create it and upload to artifact storage ourselves
// const tar = require('tar')
async function cancelHandler(evtOrExitCodeOrError) { async function cancelHandler(evtOrExitCodeOrError) {
try { await deployment.cancel()
if (deployment.requestedDeployment) {
const pagesCancelDeployEndpoint = `${deployment.githubApiUrl}/repos/${process.env.GITHUB_REPOSITORY}/pages/deployment/cancel/${process.env.GITHUB_SHA}`
await axios.put(
pagesCancelDeployEndpoint,
{},
{
headers: {
Accept: 'application/vnd.github.v3+json',
Authorization: `Bearer ${deployment.githubToken}`,
'Content-type': 'application/json'
}
}
)
core.info(`Deployment cancelled with ${pagesCancelDeployEndpoint}`)
}
} catch (e) {
console.log('Deployment cancellation failed', e)
}
process.exit(isNaN(+evtOrExitCodeOrError) ? 1 : +evtOrExitCodeOrError) process.exit(isNaN(+evtOrExitCodeOrError) ? 1 : +evtOrExitCodeOrError)
} }
async function main() { async function main() {
let idToken = "" let idToken = ''
try { try {
idToken = await core.getIDToken() idToken = await core.getIDToken()
} catch (error) { } catch (error) {
@@ -8674,8 +8690,8 @@ process.on('SIGINT', cancelHandler)
process.on('SIGTERM', cancelHandler) process.on('SIGTERM', cancelHandler)
// Main // Main
const emitTelemetry = core.getInput("emit_telemetry") const emitTelemetry = core.getInput('emit_telemetry')
if (emitTelemetry === "true") { if (emitTelemetry === 'true') {
__nccwpck_require__(9557) __nccwpck_require__(9557)
} else { } else {
main() main()

2
dist/index.js.map vendored

File diff suppressed because one or more lines are too long

View File

@@ -27,7 +27,9 @@
"lint": "eslint src", "lint": "eslint src",
"prepare": "ncc build src/index.js -o dist --source-map --license licenses.txt && ncc build src/pre.js -o pre --source-map --license licenses.txt", "prepare": "ncc build src/index.js -o dist --source-map --license licenses.txt && ncc build src/pre.js -o pre --source-map --license licenses.txt",
"test": "jest", "test": "jest",
"all": "npm run lint && npm run prepare && npm run test" "format": "prettier --write 'src/**/*.js'",
"format:check": "prettier --check 'src/**/*.js'",
"all": "npm run format && npm run lint && npm run prepare && npm run test"
}, },
"repository": { "repository": {
"type": "git", "type": "git",

View File

@@ -8207,184 +8207,222 @@ const axios = __nccwpck_require__(6545)
const getContext = __nccwpck_require__(1319) const getContext = __nccwpck_require__(1319)
const errorStatus = { const errorStatus = {
'unknown_status' : 'Unable to get deployment status.', unknown_status: 'Unable to get deployment status.',
'not_found' : 'Deployment not found.', not_found: 'Deployment not found.',
'deployment_attempt_error' : 'Deployment temporarily failed, a retry will be automatically scheduled...' deployment_attempt_error: 'Deployment temporarily failed, a retry will be automatically scheduled...'
} }
class Deployment { class Deployment {
constructor() { constructor() {
const context = getContext() const context = getContext()
this.runTimeUrl = context.runTimeUrl this.runTimeUrl = context.runTimeUrl
this.repositoryNwo = context.repositoryNwo this.repositoryNwo = context.repositoryNwo
this.runTimeToken = context.runTimeToken this.runTimeToken = context.runTimeToken
this.buildVersion = context.buildVersion this.buildVersion = context.buildVersion
this.buildActor = context.buildActor this.buildActor = context.buildActor
this.actionsId = context.workflowRun this.actionsId = context.workflowRun
this.githubToken = context.githubToken this.githubToken = context.githubToken
this.workflowRun = context.workflowRun this.workflowRun = context.workflowRun
this.requestedDeployment = false this.requestedDeployment = false
this.deploymentInfo = null this.deploymentInfo = null
this.githubApiUrl = context.githubApiUrl this.githubApiUrl = context.githubApiUrl
this.artifactName = context.artifactName this.artifactName = context.artifactName
} }
// Ask the runtime for the unsigned artifact URL and deploy to GitHub Pages // Ask the runtime for the unsigned artifact URL and deploy to GitHub Pages
// by creating a deployment with that artifact // by creating a deployment with that artifact
async create(idToken) { async create(idToken) {
try { try {
core.info(`Actor: ${this.buildActor}`) core.info(`Actor: ${this.buildActor}`)
core.info(`Action ID: ${this.actionsId}`) core.info(`Action ID: ${this.actionsId}`)
const pagesDeployEndpoint = `${this.githubApiUrl}/repos/${this.repositoryNwo}/pages/deployment` const pagesDeployEndpoint = `${this.githubApiUrl}/repos/${this.repositoryNwo}/pages/deployment`
const artifactExgUrl = `${this.runTimeUrl}_apis/pipelines/workflows/${this.workflowRun}/artifacts?api-version=6.0-preview` const artifactExgUrl = `${this.runTimeUrl}_apis/pipelines/workflows/${this.workflowRun}/artifacts?api-version=6.0-preview`
core.info(`Artifact URL: ${artifactExgUrl}`) core.info(`Artifact URL: ${artifactExgUrl}`)
const {data} = await axios.get(artifactExgUrl, { const { data } = await axios.get(artifactExgUrl, {
headers: {
Authorization: `Bearer ${this.runTimeToken}`,
'Content-Type': 'application/json'
}
})
core.info(JSON.stringify(data))
const artifactRawUrl = data?.value?.find(artifact => artifact.name === this.artifactName)?.url
if (!artifactRawUrl) {
throw new Error(
'No uploaded artifact was found! Please check if there are any errors at build step, or uploaded artifact name is correct.'
)
}
const artifactUrl = `${artifactRawUrl}&%24expand=SignedContent`
const payload = {
artifact_url: artifactUrl,
pages_build_version: this.buildVersion,
oidc_token: idToken
}
core.info(`Creating deployment with payload:\n${JSON.stringify(payload, null, '\t')}`)
const response = await axios.post(pagesDeployEndpoint, payload, {
headers: {
Accept: 'application/vnd.github.v3+json',
Authorization: `Bearer ${this.githubToken}`,
'Content-type': 'application/json'
}
})
this.requestedDeployment = true
core.info(`Created deployment for ${this.buildVersion}`)
if (response && response.data) {
core.info(JSON.stringify(response.data))
this.deploymentInfo = response.data
}
} catch (error) {
core.info(error.stack)
// 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
}
errorMessage += `Responded with: ${message}`
} else if (error.response.status == 403) {
errorMessage += `Ensure GITHUB_TOKEN has permission "pages: write".`
} else if (error.response.status == 404) {
errorMessage += `Ensure GitHub Pages has been enabled.`
} else if (error.response.status >= 500) {
errorMessage += `Server error, is githubstatus.com reporting a Pages outage? Please re-run the deployment at a later time.`
}
throw errorMessage
} else {
throw error
}
}
}
// Poll the deployment endpoint for status
async check() {
try {
const statusUrl =
this.deploymentInfo != null
? this.deploymentInfo['status_url']
: `${this.githubApiUrl}/repos/${this.repositoryNwo}/pages/deployment/status/${this.buildVersion}`
core.setOutput('page_url', this.deploymentInfo != null ? this.deploymentInfo['page_url'] : '')
const timeout = Number(core.getInput('timeout'))
const reportingInterval = Number(core.getInput('reporting_interval'))
const maxErrorCount = Number(core.getInput('error_count'))
var startTime = Date.now()
var errorCount = 0
// Time in milliseconds between two deployment status report when status errored, default 0.
var errorReportingInterval = 0
/*eslint no-constant-condition: ["error", { "checkLoops": false }]*/
while (true) {
// Handle reporting interval
await new Promise(r => setTimeout(r, reportingInterval + errorReportingInterval))
// Check status
var res = await axios.get(statusUrl, {
headers: { headers: {
Authorization: `Bearer ${this.runTimeToken}`, Authorization: `token ${this.githubToken}`
'Content-Type': 'application/json'
} }
}) })
core.info(JSON.stringify(data))
const artifactRawUrl = data?.value?.find(artifact => artifact.name === this.artifactName)?.url if (res.data.status == 'succeed') {
if (!artifactRawUrl) { core.info('Reported success!')
throw new Error('No uploaded artifact was found! Please check if there are any errors at build step, or uploaded artifact name is correct.') core.setOutput('status', 'succeed')
break
} else if (res.data.status == 'deployment_failed') {
// 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.')
break
} else if (res.data.status == 'deployment_content_failed') {
// 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.'
)
break
} else if (errorStatus[res.data.status]) {
// A temporary error happened, will query the status again
core.info(errorStatus[res.data.status])
} else {
core.info('Current status: ' + res.data.status)
} }
const artifactUrl = `${artifactRawUrl}&%24expand=SignedContent` if (res.status != 200 || !!errorStatus[res.data.status]) {
const payload = { errorCount++
artifact_url: artifactUrl,
pages_build_version: this.buildVersion, // set the Maximum error reporting interval greater than 15 sec but below 30 sec.
oidc_token: idToken if (errorReportingInterval < 1000 * 15) {
errorReportingInterval = (errorReportingInterval << 1) | 1
}
} else {
// reset the error reporting interval once get the proper status back.
errorReportingInterval = 0
} }
core.info(`Creating deployment with payload:\n${JSON.stringify(payload, null, '\t')}`)
const response = await axios.post(pagesDeployEndpoint, payload, { if (errorCount >= maxErrorCount) {
core.info('Too many errors, aborting!')
core.setFailed('Failed with status code: ' + res.status)
// Explicitly cancel the deployment
await this.cancel()
return
}
// Handle timeout
if (Date.now() - startTime >= timeout) {
core.info('Timeout reached, aborting!')
core.setFailed('Timeout reached, aborting!')
// Explicitly cancel the deployment
await this.cancel()
return
}
}
} catch (error) {
core.setFailed(error)
if (error.response && error.response.data) {
core.info(JSON.stringify(error.response.data))
}
}
}
async cancel() {
// Don't attemp to cancel if no deployment was created
if (!this.requestedDeployment) {
return
}
// Cancel the deployment
try {
const pagesCancelDeployEndpoint = `${this.githubApiUrl}/repos/${this.repositoryNwo}/pages/deployment/cancel/${this.buildVersion}`
await axios.put(
pagesCancelDeployEndpoint,
{},
{
headers: { headers: {
Accept: 'application/vnd.github.v3+json', Accept: 'application/vnd.github.v3+json',
Authorization: `Bearer ${this.githubToken}`, Authorization: `Bearer ${this.githubToken}`,
'Content-type': 'application/json' 'Content-type': 'application/json'
} }
})
this.requestedDeployment = true
core.info(`Created deployment for ${this.buildVersion}`)
if (response && response.data) {
core.info(JSON.stringify(response.data))
this.deploymentInfo = response.data
}
} catch (error) {
core.info(error.stack)
// 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
}
errorMessage += `Responded with: ${message}`
}
else if (error.response.status == 403) {
errorMessage += `Ensure GITHUB_TOKEN has permission "pages: write".`
} else if (error.response.status == 404) {
errorMessage += `Ensure GitHub Pages has been enabled.`
}
else if (error.response.status >= 500) {
errorMessage += `Server error, is githubstatus.com reporting a Pages outage? Please re-run the deployment at a later time.`
}
throw errorMessage
} else {
throw error
}
}
}
// Poll the deployment endpoint for status
async check() {
try {
const statusUrl = this.deploymentInfo != null ?
this.deploymentInfo["status_url"] :
`${this.githubApiUrl}/repos/${this.repositoryNwo}/pages/deployment/status/${process.env['GITHUB_SHA']}`
core.setOutput('page_url', this.deploymentInfo != null ? this.deploymentInfo["page_url"] : "")
const timeout = Number(core.getInput('timeout'))
const reportingInterval = Number(core.getInput('reporting_interval'))
const maxErrorCount = Number(core.getInput('error_count'))
var startTime = Date.now()
var errorCount = 0
// Time in milliseconds between two deployment status report when status errored, default 0.
var errorReportingInterval = 0
/*eslint no-constant-condition: ["error", { "checkLoops": false }]*/
while (true) {
// Handle reporting interval
await new Promise(r => setTimeout(r, reportingInterval + errorReportingInterval))
// Check status
var res = await axios.get(statusUrl, {
headers: {
Authorization: `token ${this.githubToken}`
}
})
if (res.data.status == 'succeed') {
core.info('Reported success!')
core.setOutput('status', 'succeed')
break
} else if (res.data.status == 'deployment_failed') {
// 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.')
break
} else if(res.data.status == 'deployment_content_failed') {
// 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.')
break
} else if (errorStatus[res.data.status]) {
// A temporary error happened, will query the status again
core.info(errorStatus[res.data.status])
} else {
core.info('Current status: ' + res.data.status)
}
if (res.status != 200 || !!errorStatus[res.data.status]) {
errorCount++
// set the Maximum error reporting interval greater than 15 sec but below 30 sec.
if (errorReportingInterval < 1000 * 15) {
errorReportingInterval = errorReportingInterval << 1 | 1
}
} else {
// reset the error reporting interval once get the proper status back.
errorReportingInterval = 0
}
if (errorCount >= maxErrorCount) {
core.info('Too many errors, aborting!')
core.setFailed('Failed with status code: ' + res.status)
break
}
// Handle timeout
if (Date.now() - startTime >= timeout) {
core.info('Timeout reached, aborting!')
core.setFailed('Timeout reached, aborting!')
return
}
}
} catch (error) {
core.setFailed(error)
if (error.response && error.response.data) {
core.info(JSON.stringify(error.response.data))
} }
)
core.info(`Deployment cancelled with ${pagesCancelDeployEndpoint}`)
} catch (error) {
core.setFailed(error)
if (error.response && error.response.data) {
core.info(JSON.stringify(error.response.data))
} }
} }
} }
module.exports = {Deployment} }
module.exports = { Deployment }
/***/ }), /***/ }),
@@ -8409,7 +8447,7 @@ axiosRetry(axios, {
} }
}) })
const {Deployment} = __nccwpck_require__(2877) const { Deployment } = __nccwpck_require__(2877)
async function emitTelemetry() { async function emitTelemetry() {
// All variables we need from the runtime are set in the Deployment constructor // All variables we need from the runtime are set in the Deployment constructor
@@ -8419,7 +8457,7 @@ async function emitTelemetry() {
await axios await axios
.post( .post(
telemetryUrl, telemetryUrl,
{github_run_id: deployment.workflowRun}, { github_run_id: deployment.workflowRun },
{ {
headers: { headers: {
Accept: 'application/vnd.github.v3+json', Accept: 'application/vnd.github.v3+json',
@@ -8447,7 +8485,7 @@ async function main() {
main() main()
module.exports = {emitTelemetry} module.exports = { emitTelemetry }
/***/ }), /***/ }),

File diff suppressed because one or more lines are too long

View File

@@ -7,181 +7,218 @@ const axios = require('axios')
const getContext = require('./context') const getContext = require('./context')
const errorStatus = { const errorStatus = {
'unknown_status' : 'Unable to get deployment status.', unknown_status: 'Unable to get deployment status.',
'not_found' : 'Deployment not found.', not_found: 'Deployment not found.',
'deployment_attempt_error' : 'Deployment temporarily failed, a retry will be automatically scheduled...' deployment_attempt_error: 'Deployment temporarily failed, a retry will be automatically scheduled...'
} }
class Deployment { class Deployment {
constructor() { constructor() {
const context = getContext() const context = getContext()
this.runTimeUrl = context.runTimeUrl this.runTimeUrl = context.runTimeUrl
this.repositoryNwo = context.repositoryNwo this.repositoryNwo = context.repositoryNwo
this.runTimeToken = context.runTimeToken this.runTimeToken = context.runTimeToken
this.buildVersion = context.buildVersion this.buildVersion = context.buildVersion
this.buildActor = context.buildActor this.buildActor = context.buildActor
this.actionsId = context.workflowRun this.actionsId = context.workflowRun
this.githubToken = context.githubToken this.githubToken = context.githubToken
this.workflowRun = context.workflowRun this.workflowRun = context.workflowRun
this.requestedDeployment = false this.requestedDeployment = false
this.deploymentInfo = null this.deploymentInfo = null
this.githubApiUrl = context.githubApiUrl this.githubApiUrl = context.githubApiUrl
this.artifactName = context.artifactName this.artifactName = context.artifactName
} }
// Ask the runtime for the unsigned artifact URL and deploy to GitHub Pages // Ask the runtime for the unsigned artifact URL and deploy to GitHub Pages
// by creating a deployment with that artifact // by creating a deployment with that artifact
async create(idToken) { async create(idToken) {
try { try {
core.info(`Actor: ${this.buildActor}`) core.info(`Actor: ${this.buildActor}`)
core.info(`Action ID: ${this.actionsId}`) core.info(`Action ID: ${this.actionsId}`)
const pagesDeployEndpoint = `${this.githubApiUrl}/repos/${this.repositoryNwo}/pages/deployment` const pagesDeployEndpoint = `${this.githubApiUrl}/repos/${this.repositoryNwo}/pages/deployment`
const artifactExgUrl = `${this.runTimeUrl}_apis/pipelines/workflows/${this.workflowRun}/artifacts?api-version=6.0-preview` const artifactExgUrl = `${this.runTimeUrl}_apis/pipelines/workflows/${this.workflowRun}/artifacts?api-version=6.0-preview`
core.info(`Artifact URL: ${artifactExgUrl}`) core.info(`Artifact URL: ${artifactExgUrl}`)
const {data} = await axios.get(artifactExgUrl, { const { data } = await axios.get(artifactExgUrl, {
headers: {
Authorization: `Bearer ${this.runTimeToken}`,
'Content-Type': 'application/json'
}
})
core.info(JSON.stringify(data))
const artifactRawUrl = data?.value?.find(artifact => artifact.name === this.artifactName)?.url
if (!artifactRawUrl) {
throw new Error(
'No uploaded artifact was found! Please check if there are any errors at build step, or uploaded artifact name is correct.'
)
}
const artifactUrl = `${artifactRawUrl}&%24expand=SignedContent`
const payload = {
artifact_url: artifactUrl,
pages_build_version: this.buildVersion,
oidc_token: idToken
}
core.info(`Creating deployment with payload:\n${JSON.stringify(payload, null, '\t')}`)
const response = await axios.post(pagesDeployEndpoint, payload, {
headers: {
Accept: 'application/vnd.github.v3+json',
Authorization: `Bearer ${this.githubToken}`,
'Content-type': 'application/json'
}
})
this.requestedDeployment = true
core.info(`Created deployment for ${this.buildVersion}`)
if (response && response.data) {
core.info(JSON.stringify(response.data))
this.deploymentInfo = response.data
}
} catch (error) {
core.info(error.stack)
// 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
}
errorMessage += `Responded with: ${message}`
} else if (error.response.status == 403) {
errorMessage += `Ensure GITHUB_TOKEN has permission "pages: write".`
} else if (error.response.status == 404) {
errorMessage += `Ensure GitHub Pages has been enabled.`
} else if (error.response.status >= 500) {
errorMessage += `Server error, is githubstatus.com reporting a Pages outage? Please re-run the deployment at a later time.`
}
throw errorMessage
} else {
throw error
}
}
}
// Poll the deployment endpoint for status
async check() {
try {
const statusUrl =
this.deploymentInfo != null
? this.deploymentInfo['status_url']
: `${this.githubApiUrl}/repos/${this.repositoryNwo}/pages/deployment/status/${this.buildVersion}`
core.setOutput('page_url', this.deploymentInfo != null ? this.deploymentInfo['page_url'] : '')
const timeout = Number(core.getInput('timeout'))
const reportingInterval = Number(core.getInput('reporting_interval'))
const maxErrorCount = Number(core.getInput('error_count'))
var startTime = Date.now()
var errorCount = 0
// Time in milliseconds between two deployment status report when status errored, default 0.
var errorReportingInterval = 0
/*eslint no-constant-condition: ["error", { "checkLoops": false }]*/
while (true) {
// Handle reporting interval
await new Promise(r => setTimeout(r, reportingInterval + errorReportingInterval))
// Check status
var res = await axios.get(statusUrl, {
headers: { headers: {
Authorization: `Bearer ${this.runTimeToken}`, Authorization: `token ${this.githubToken}`
'Content-Type': 'application/json'
} }
}) })
core.info(JSON.stringify(data))
const artifactRawUrl = data?.value?.find(artifact => artifact.name === this.artifactName)?.url if (res.data.status == 'succeed') {
if (!artifactRawUrl) { core.info('Reported success!')
throw new Error('No uploaded artifact was found! Please check if there are any errors at build step, or uploaded artifact name is correct.') core.setOutput('status', 'succeed')
break
} else if (res.data.status == 'deployment_failed') {
// 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.')
break
} else if (res.data.status == 'deployment_content_failed') {
// 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.'
)
break
} else if (errorStatus[res.data.status]) {
// A temporary error happened, will query the status again
core.info(errorStatus[res.data.status])
} else {
core.info('Current status: ' + res.data.status)
} }
const artifactUrl = `${artifactRawUrl}&%24expand=SignedContent` if (res.status != 200 || !!errorStatus[res.data.status]) {
const payload = { errorCount++
artifact_url: artifactUrl,
pages_build_version: this.buildVersion, // set the Maximum error reporting interval greater than 15 sec but below 30 sec.
oidc_token: idToken if (errorReportingInterval < 1000 * 15) {
errorReportingInterval = (errorReportingInterval << 1) | 1
}
} else {
// reset the error reporting interval once get the proper status back.
errorReportingInterval = 0
} }
core.info(`Creating deployment with payload:\n${JSON.stringify(payload, null, '\t')}`)
const response = await axios.post(pagesDeployEndpoint, payload, { if (errorCount >= maxErrorCount) {
core.info('Too many errors, aborting!')
core.setFailed('Failed with status code: ' + res.status)
// Explicitly cancel the deployment
await this.cancel()
return
}
// Handle timeout
if (Date.now() - startTime >= timeout) {
core.info('Timeout reached, aborting!')
core.setFailed('Timeout reached, aborting!')
// Explicitly cancel the deployment
await this.cancel()
return
}
}
} catch (error) {
core.setFailed(error)
if (error.response && error.response.data) {
core.info(JSON.stringify(error.response.data))
}
}
}
async cancel() {
// Don't attemp to cancel if no deployment was created
if (!this.requestedDeployment) {
return
}
// Cancel the deployment
try {
const pagesCancelDeployEndpoint = `${this.githubApiUrl}/repos/${this.repositoryNwo}/pages/deployment/cancel/${this.buildVersion}`
await axios.put(
pagesCancelDeployEndpoint,
{},
{
headers: { headers: {
Accept: 'application/vnd.github.v3+json', Accept: 'application/vnd.github.v3+json',
Authorization: `Bearer ${this.githubToken}`, Authorization: `Bearer ${this.githubToken}`,
'Content-type': 'application/json' 'Content-type': 'application/json'
} }
})
this.requestedDeployment = true
core.info(`Created deployment for ${this.buildVersion}`)
if (response && response.data) {
core.info(JSON.stringify(response.data))
this.deploymentInfo = response.data
}
} catch (error) {
core.info(error.stack)
// 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
}
errorMessage += `Responded with: ${message}`
}
else if (error.response.status == 403) {
errorMessage += `Ensure GITHUB_TOKEN has permission "pages: write".`
} else if (error.response.status == 404) {
errorMessage += `Ensure GitHub Pages has been enabled.`
}
else if (error.response.status >= 500) {
errorMessage += `Server error, is githubstatus.com reporting a Pages outage? Please re-run the deployment at a later time.`
}
throw errorMessage
} else {
throw error
}
}
}
// Poll the deployment endpoint for status
async check() {
try {
const statusUrl = this.deploymentInfo != null ?
this.deploymentInfo["status_url"] :
`${this.githubApiUrl}/repos/${this.repositoryNwo}/pages/deployment/status/${process.env['GITHUB_SHA']}`
core.setOutput('page_url', this.deploymentInfo != null ? this.deploymentInfo["page_url"] : "")
const timeout = Number(core.getInput('timeout'))
const reportingInterval = Number(core.getInput('reporting_interval'))
const maxErrorCount = Number(core.getInput('error_count'))
var startTime = Date.now()
var errorCount = 0
// Time in milliseconds between two deployment status report when status errored, default 0.
var errorReportingInterval = 0
/*eslint no-constant-condition: ["error", { "checkLoops": false }]*/
while (true) {
// Handle reporting interval
await new Promise(r => setTimeout(r, reportingInterval + errorReportingInterval))
// Check status
var res = await axios.get(statusUrl, {
headers: {
Authorization: `token ${this.githubToken}`
}
})
if (res.data.status == 'succeed') {
core.info('Reported success!')
core.setOutput('status', 'succeed')
break
} else if (res.data.status == 'deployment_failed') {
// 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.')
break
} else if(res.data.status == 'deployment_content_failed') {
// 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.')
break
} else if (errorStatus[res.data.status]) {
// A temporary error happened, will query the status again
core.info(errorStatus[res.data.status])
} else {
core.info('Current status: ' + res.data.status)
}
if (res.status != 200 || !!errorStatus[res.data.status]) {
errorCount++
// set the Maximum error reporting interval greater than 15 sec but below 30 sec.
if (errorReportingInterval < 1000 * 15) {
errorReportingInterval = errorReportingInterval << 1 | 1
}
} else {
// reset the error reporting interval once get the proper status back.
errorReportingInterval = 0
}
if (errorCount >= maxErrorCount) {
core.info('Too many errors, aborting!')
core.setFailed('Failed with status code: ' + res.status)
break
}
// Handle timeout
if (Date.now() - startTime >= timeout) {
core.info('Timeout reached, aborting!')
core.setFailed('Timeout reached, aborting!')
return
}
}
} catch (error) {
core.setFailed(error)
if (error.response && error.response.data) {
core.info(JSON.stringify(error.response.data))
} }
)
core.info(`Deployment cancelled with ${pagesCancelDeployEndpoint}`)
} catch (error) {
core.setFailed(error)
if (error.response && error.response.data) {
core.info(JSON.stringify(error.response.data))
} }
} }
} }
module.exports = {Deployment} }
module.exports = { Deployment }

View File

@@ -6,39 +6,17 @@ require('regenerator-runtime/runtime')
const core = require('@actions/core') const core = require('@actions/core')
// const github = require('@actions/github'); // TODO: Not used until we publish API endpoint to the @action/github package // const github = require('@actions/github'); // TODO: Not used until we publish API endpoint to the @action/github package
const axios = require('axios')
const {Deployment} = require('./deployment') const { Deployment } = require('./deployment')
const deployment = new Deployment() const deployment = new Deployment()
// TODO: If the artifact hasn't been created, we can create it and upload to artifact storage ourselves
// const tar = require('tar')
async function cancelHandler(evtOrExitCodeOrError) { async function cancelHandler(evtOrExitCodeOrError) {
try { await deployment.cancel()
if (deployment.requestedDeployment) {
const pagesCancelDeployEndpoint = `${deployment.githubApiUrl}/repos/${process.env.GITHUB_REPOSITORY}/pages/deployment/cancel/${process.env.GITHUB_SHA}`
await axios.put(
pagesCancelDeployEndpoint,
{},
{
headers: {
Accept: 'application/vnd.github.v3+json',
Authorization: `Bearer ${deployment.githubToken}`,
'Content-type': 'application/json'
}
}
)
core.info(`Deployment cancelled with ${pagesCancelDeployEndpoint}`)
}
} catch (e) {
console.log('Deployment cancellation failed', e)
}
process.exit(isNaN(+evtOrExitCodeOrError) ? 1 : +evtOrExitCodeOrError) process.exit(isNaN(+evtOrExitCodeOrError) ? 1 : +evtOrExitCodeOrError)
} }
async function main() { async function main() {
let idToken = "" let idToken = ''
try { try {
idToken = await core.getIDToken() idToken = await core.getIDToken()
} catch (error) { } catch (error) {
@@ -59,8 +37,8 @@ process.on('SIGINT', cancelHandler)
process.on('SIGTERM', cancelHandler) process.on('SIGTERM', cancelHandler)
// Main // Main
const emitTelemetry = core.getInput("emit_telemetry") const emitTelemetry = core.getInput('emit_telemetry')
if (emitTelemetry === "true") { if (emitTelemetry === 'true') {
require('./pre') require('./pre')
} else { } else {
main() main()

View File

@@ -7,7 +7,7 @@ const axios = require('axios')
const { expect, jest } = require('@jest/globals') const { expect, jest } = require('@jest/globals')
const {Deployment} = require('./deployment') const { Deployment } = require('./deployment')
describe('with all environment variables set', () => { describe('with all environment variables set', () => {
beforeEach(() => { beforeEach(() => {
@@ -35,8 +35,8 @@ describe('with variables missing', () => {
it('execution fails if there are missing variables', done => { it('execution fails if there are missing variables', done => {
delete process.env.ACTIONS_RUNTIME_URL delete process.env.ACTIONS_RUNTIME_URL
const ip = path.join(__dirname, './index.js') const ip = path.join(__dirname, './index.js')
cp.exec(`node ${ip}`, {env: process.env}, (err, stdout) => { cp.exec(`node ${ip}`, { env: process.env }, (err, stdout) => {
expect(stdout).toBe("") expect(stdout).toBe('')
expect(err).toBeTruthy() expect(err).toBeTruthy()
expect(err.code).toBe(1) expect(err.code).toBe(1)
done() done()
@@ -80,10 +80,16 @@ describe('create', () => {
it('can successfully create a deployment', async () => { it('can successfully create a deployment', async () => {
process.env.GITHUB_SHA = 'valid-build-version' process.env.GITHUB_SHA = 'valid-build-version'
const fakeJwt = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiJiNjllMWIxOC1jOGFiLTRhZGQtOGYxOC03MzVlMzVjZGJhZjAiLCJzdWIiOiJyZXBvOnBhcGVyLXNwYS9taW55aTplbnZpcm9ubWVudDpQcm9kdWN0aW9uIiwiYXVkIjoiaHR0cHM6Ly9naXRodWIuY29tL3BhcGVyLXNwYSIsInJlZiI6InJlZnMvaGVhZHMvbWFpbiIsInNoYSI6ImEyODU1MWJmODdiZDk3NTFiMzdiMmM0YjM3M2MxZjU3NjFmYWM2MjYiLCJyZXBvc2l0b3J5IjoicGFwZXItc3BhL21pbnlpIiwicmVwb3NpdG9yeV9vd25lciI6InBhcGVyLXNwYSIsInJ1bl9pZCI6IjE1NDY0NTkzNjQiLCJydW5fbnVtYmVyIjoiMzQiLCJydW5fYXR0ZW1wdCI6IjIiLCJhY3RvciI6IllpTXlzdHkiLCJ3b3JrZmxvdyI6IkNJIiwiaGVhZF9yZWYiOiIiLCJiYXNlX3JlZiI6IiIsImV2ZW50X25hbWUiOiJwdXNoIiwicmVmX3R5cGUiOiJicmFuY2giLCJlbnZpcm9ubWVudCI6IlByb2R1Y3Rpb24iLCJqb2Jfd29ya2Zsb3dfcmVmIjoicGFwZXItc3BhL21pbnlpLy5naXRodWIvd29ya2Zsb3dzL2JsYW5rLnltbEByZWZzL2hlYWRzL21haW4iLCJpc3MiOiJodHRwczovL3Rva2VuLmFjdGlvbnMuZ2l0aHVidXNlcmNvbnRlbnQuY29tIiwibmJmIjoxNjM4ODI4MDI4LCJleHAiOjE2Mzg4Mjg5MjgsImlhdCI6MTYzODgyODYyOH0.1wyupfxu1HGoTyIqatYg0hIxy2-0bMO-yVlmLSMuu2w' const fakeJwt =
'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiJiNjllMWIxOC1jOGFiLTRhZGQtOGYxOC03MzVlMzVjZGJhZjAiLCJzdWIiOiJyZXBvOnBhcGVyLXNwYS9taW55aTplbnZpcm9ubWVudDpQcm9kdWN0aW9uIiwiYXVkIjoiaHR0cHM6Ly9naXRodWIuY29tL3BhcGVyLXNwYSIsInJlZiI6InJlZnMvaGVhZHMvbWFpbiIsInNoYSI6ImEyODU1MWJmODdiZDk3NTFiMzdiMmM0YjM3M2MxZjU3NjFmYWM2MjYiLCJyZXBvc2l0b3J5IjoicGFwZXItc3BhL21pbnlpIiwicmVwb3NpdG9yeV9vd25lciI6InBhcGVyLXNwYSIsInJ1bl9pZCI6IjE1NDY0NTkzNjQiLCJydW5fbnVtYmVyIjoiMzQiLCJydW5fYXR0ZW1wdCI6IjIiLCJhY3RvciI6IllpTXlzdHkiLCJ3b3JrZmxvdyI6IkNJIiwiaGVhZF9yZWYiOiIiLCJiYXNlX3JlZiI6IiIsImV2ZW50X25hbWUiOiJwdXNoIiwicmVmX3R5cGUiOiJicmFuY2giLCJlbnZpcm9ubWVudCI6IlByb2R1Y3Rpb24iLCJqb2Jfd29ya2Zsb3dfcmVmIjoicGFwZXItc3BhL21pbnlpLy5naXRodWIvd29ya2Zsb3dzL2JsYW5rLnltbEByZWZzL2hlYWRzL21haW4iLCJpc3MiOiJodHRwczovL3Rva2VuLmFjdGlvbnMuZ2l0aHVidXNlcmNvbnRlbnQuY29tIiwibmJmIjoxNjM4ODI4MDI4LCJleHAiOjE2Mzg4Mjg5MjgsImlhdCI6MTYzODgyODYyOH0.1wyupfxu1HGoTyIqatYg0hIxy2-0bMO-yVlmLSMuu2w'
const scope = nock(`http://my-url`) const scope = nock(`http://my-url`)
.get('/_apis/pipelines/workflows/123/artifacts?api-version=6.0-preview') .get('/_apis/pipelines/workflows/123/artifacts?api-version=6.0-preview')
.reply(200, { value: [ {url: 'https://another-artifact.com', name: 'another-artifact'}, { url: 'https://fake-artifact.com', name: 'github-pages' }] }) .reply(200, {
value: [
{ url: 'https://another-artifact.com', name: 'another-artifact' },
{ url: 'https://fake-artifact.com', name: 'github-pages' }
]
})
core.getIDToken = jest.fn().mockResolvedValue(fakeJwt) core.getIDToken = jest.fn().mockResolvedValue(fakeJwt)
axios.post = jest.fn().mockResolvedValue('test') axios.post = jest.fn().mockResolvedValue('test')
@@ -109,9 +115,7 @@ describe('create', () => {
) )
expect(core.setFailed).not.toHaveBeenCalled() expect(core.setFailed).not.toHaveBeenCalled()
expect(core.info).toHaveBeenCalledWith( expect(core.info).toHaveBeenCalledWith('Created deployment for valid-build-version')
'Created deployment for valid-build-version'
)
scope.done() scope.done()
}) })
@@ -131,7 +135,6 @@ describe('create', () => {
try { try {
deployment.create() deployment.create()
} catch (err) { } catch (err) {
expect(axios.post).toBeCalledWith( expect(axios.post).toBeCalledWith(
'https://api.github.com/repos/paper-spa/is-awesome/pages/deployment', 'https://api.github.com/repos/paper-spa/is-awesome/pages/deployment',
{ {
@@ -147,15 +150,12 @@ describe('create', () => {
} }
) )
expect(core.info).toHaveBeenLastCalledWith( expect(core.info).toHaveBeenLastCalledWith('Failed to create deployment for invalid-build-version.')
'Failed to create deployment for invalid-build-version.'
)
expect(core.setFailed).toHaveBeenCalledWith({ status: 400 }) expect(core.setFailed).toHaveBeenCalledWith({ status: 400 })
scope.done() scope.done()
} }
}) })
}) })
describe('check', () => { describe('check', () => {

View File

@@ -16,7 +16,7 @@ axiosRetry(axios, {
} }
}) })
const {Deployment} = require('./deployment') const { Deployment } = require('./deployment')
async function emitTelemetry() { async function emitTelemetry() {
// All variables we need from the runtime are set in the Deployment constructor // All variables we need from the runtime are set in the Deployment constructor
@@ -26,7 +26,7 @@ async function emitTelemetry() {
await axios await axios
.post( .post(
telemetryUrl, telemetryUrl,
{github_run_id: deployment.workflowRun}, { github_run_id: deployment.workflowRun },
{ {
headers: { headers: {
Accept: 'application/vnd.github.v3+json', Accept: 'application/vnd.github.v3+json',
@@ -54,4 +54,4 @@ async function main() {
main() main()
module.exports = {emitTelemetry} module.exports = { emitTelemetry }

View File

@@ -2,9 +2,9 @@ const core = require('@actions/core')
const process = require('process') const process = require('process')
const axios = require('axios') const axios = require('axios')
const {expect, jest} = require('@jest/globals') const { expect, jest } = require('@jest/globals')
const {emitTelemetry} = require('./pre') const { emitTelemetry } = require('./pre')
describe('emitTelemetry', () => { describe('emitTelemetry', () => {
beforeAll(() => { beforeAll(() => {