2023-04-14 20:43:44 +01:00
const core = require ( '@actions/core' )
const nock = require ( 'nock' )
const { Deployment } = require ( '../../src/functions/deployment' )
const fakeJwt =
'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiJiNjllMWIxOC1jOGFiLTRhZGQtOGYxOC03MzVlMzVjZGJhZjAiLCJzdWIiOiJyZXBvOnBhcGVyLXNwYS9taW55aTplbnZpcm9ubWVudDpQcm9kdWN0aW9uIiwiYXVkIjoiaHR0cHM6Ly9naXRodWIuY29tL3BhcGVyLXNwYSIsInJlZiI6InJlZnMvaGVhZHMvbWFpbiIsInNoYSI6ImEyODU1MWJmODdiZDk3NTFiMzdiMmM0YjM3M2MxZjU3NjFmYWM2MjYiLCJyZXBvc2l0b3J5IjoicGFwZXItc3BhL21pbnlpIiwicmVwb3NpdG9yeV9vd25lciI6InBhcGVyLXNwYSIsInJ1bl9pZCI6IjE1NDY0NTkzNjQiLCJydW5fbnVtYmVyIjoiMzQiLCJydW5fYXR0ZW1wdCI6IjIiLCJhY3RvciI6IllpTXlzdHkiLCJ3b3JrZmxvdyI6IkNJIiwiaGVhZF9yZWYiOiIiLCJiYXNlX3JlZiI6IiIsImV2ZW50X25hbWUiOiJwdXNoIiwicmVmX3R5cGUiOiJicmFuY2giLCJlbnZpcm9ubWVudCI6IlByb2R1Y3Rpb24iLCJqb2Jfd29ya2Zsb3dfcmVmIjoicGFwZXItc3BhL21pbnlpLy5naXRodWIvd29ya2Zsb3dzL2JsYW5rLnltbEByZWZzL2hlYWRzL21haW4iLCJpc3MiOiJodHRwczovL3Rva2VuLmFjdGlvbnMuZ2l0aHVidXNlcmNvbnRlbnQuY29tIiwibmJmIjoxNjM4ODI4MDI4LCJleHAiOjE2Mzg4Mjg5MjgsImlhdCI6MTYzODgyODYyOH0.1wyupfxu1HGoTyIqatYg0hIxy2-0bMO-yVlmLSMuu2w'
describe ( 'Deployment' , ( ) => {
2023-04-14 21:01:12 +01:00
beforeEach ( ( ) => {
2023-04-14 21:20:52 +01:00
jest . clearAllMocks ( )
2023-04-14 21:01:12 +01:00
process . env . ACTIONS _RUNTIME _URL = 'http://my-url/'
process . env . GITHUB _RUN _ID = '123'
process . env . ACTIONS _RUNTIME _TOKEN = 'a-token'
process . env . GITHUB _REPOSITORY = 'actions/is-awesome'
process . env . GITHUB _TOKEN = 'gha-token'
process . env . GITHUB _SHA = '123abc'
process . env . GITHUB _ACTOR = 'monalisa'
process . env . GITHUB _ACTION = '__monalisa/octocat'
process . env . GITHUB _ACTION _PATH = 'something'
jest . spyOn ( core , 'getInput' ) . mockImplementation ( param => {
switch ( param ) {
case 'artifact_name' :
return 'github-pages'
case 'token' :
return process . env . GITHUB _TOKEN
default :
return process . env [ ` INPUT_ ${ param . toUpperCase ( ) } ` ] || ''
}
2023-04-14 20:43:44 +01:00
} )
2023-04-14 21:01:12 +01:00
jest . spyOn ( core , 'setOutput' ) . mockImplementation ( param => {
return param
} )
jest . spyOn ( core , 'setFailed' ) . mockImplementation ( param => {
return param
} )
// Mock error/warning/info/debug
jest . spyOn ( core , 'error' ) . mockImplementation ( jest . fn ( ) )
jest . spyOn ( core , 'warning' ) . mockImplementation ( jest . fn ( ) )
jest . spyOn ( core , 'info' ) . mockImplementation ( jest . fn ( ) )
jest . spyOn ( core , 'debug' ) . mockImplementation ( jest . fn ( ) )
} )
describe ( '#create' , ( ) => {
afterEach ( ( ) => {
// Remove mock for `core.getInput('preview')`
delete process . env . INPUT _PREVIEW
} )
it ( 'can successfully create a deployment' , async ( ) => {
process . env . GITHUB _SHA = 'valid-build-version'
const artifactExchangeScope = nock ( ` http://my-url ` )
. 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' }
]
} )
const createDeploymentScope = nock ( 'https://api.github.com' )
. post ( ` /repos/ ${ process . env . GITHUB _REPOSITORY } /pages/deployments ` , {
artifact _url : 'https://fake-artifact.com&%24expand=SignedContent' ,
pages _build _version : process . env . GITHUB _SHA ,
oidc _token : fakeJwt
} )
. reply ( 200 , {
status _url : ` https://api.github.com/repos/ ${ process . env . GITHUB _REPOSITORY } /pages/deployments/ ${ process . env . GITHUB _SHA } ` ,
page _url : 'https://actions.github.io/is-awesome'
} )
core . getIDToken = jest . fn ( ) . mockResolvedValue ( fakeJwt )
// Create the deployment
const deployment = new Deployment ( )
await deployment . create ( fakeJwt )
expect ( core . setFailed ) . not . toHaveBeenCalled ( )
expect ( core . info ) . toHaveBeenLastCalledWith (
expect . stringMatching ( new RegExp ( ` ^Created deployment for ${ process . env . GITHUB _SHA } ` ) )
)
artifactExchangeScope . done ( )
createDeploymentScope . done ( )
} )
it ( 'can successfully create a preview deployment' , async ( ) => {
process . env . GITHUB _SHA = 'valid-build-version'
const artifactExchangeScope = nock ( ` http://my-url ` )
. 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' }
]
} )
const createDeploymentScope = nock ( 'https://api.github.com' )
. post ( ` /repos/ ${ process . env . GITHUB _REPOSITORY } /pages/deployments ` , {
artifact _url : 'https://fake-artifact.com&%24expand=SignedContent' ,
pages _build _version : process . env . GITHUB _SHA ,
oidc _token : fakeJwt ,
preview : true
} )
. reply ( 200 , {
status _url : ` https://api.github.com/repos/ ${ process . env . GITHUB _REPOSITORY } /pages/deployments/ ${ process . env . GITHUB _SHA } ` ,
page _url : 'https://actions.github.io/is-awesome' ,
preview _url : 'https://actions.drafts.github.io/is-awesome'
} )
core . getIDToken = jest . fn ( ) . mockResolvedValue ( fakeJwt )
// Return `"true"` for `core.getInput("preview")`
process . env . INPUT _PREVIEW = 'true'
// Create the deployment
const deployment = new Deployment ( )
await deployment . create ( fakeJwt )
expect ( core . setFailed ) . not . toHaveBeenCalled ( )
expect ( core . info ) . toHaveBeenLastCalledWith (
expect . stringMatching ( new RegExp ( ` ^Created deployment for ${ process . env . GITHUB _SHA } ` ) )
)
artifactExchangeScope . done ( )
createDeploymentScope . done ( )
} )
it ( 'reports errors with failed artifact exchange' , async ( ) => {
process . env . GITHUB _SHA = 'invalid-build-version'
const artifactExchangeScope = nock ( ` http://my-url ` )
. get ( '/_apis/pipelines/workflows/123/artifacts?api-version=6.0-preview' )
. reply ( 400 , { } )
// Create the deployment
const deployment = new Deployment ( )
await expect ( deployment . create ( ) ) . rejects . toEqual (
new Error (
` Failed to create deployment (status: 400) with build version ${ process . env . GITHUB _SHA } . Responded with: Bad Request `
2023-04-14 20:43:44 +01:00
)
2023-04-14 21:01:12 +01:00
)
artifactExchangeScope . done ( )
} )
it ( 'reports errors with a failed 500 in a deployment' , async ( ) => {
process . env . GITHUB _SHA = 'build-version'
const artifactExchangeScope = nock ( ` http://my-url ` )
. get ( '/_apis/pipelines/workflows/123/artifacts?api-version=6.0-preview' )
. reply ( 200 , { value : [ { url : 'https://invalid-artifact.com' , name : 'github-pages' } ] } )
const createDeploymentScope = nock ( 'https://api.github.com' )
. post ( ` /repos/ ${ process . env . GITHUB _REPOSITORY } /pages/deployments ` , {
artifact _url : 'https://invalid-artifact.com&%24expand=SignedContent' ,
pages _build _version : process . env . GITHUB _SHA
} )
. reply ( 500 , { message : 'oh no' } )
2023-04-14 20:58:13 +01:00
2023-04-14 21:01:12 +01:00
// Create the deployment
const deployment = new Deployment ( )
await expect ( deployment . create ( ) ) . rejects . toEqual (
new Error (
` Failed to create deployment (status: 500) with build version ${ process . env . GITHUB _SHA } . Server error, is githubstatus.com reporting a Pages outage? Please re-run the deployment at a later time. `
2023-04-14 20:58:13 +01:00
)
2023-04-14 21:01:12 +01:00
)
artifactExchangeScope . done ( )
createDeploymentScope . done ( )
} )
it ( 'reports errors with an unexpected 403 during deployment' , async ( ) => {
process . env . GITHUB _SHA = 'build-version'
const artifactExchangeScope = nock ( ` http://my-url ` )
. get ( '/_apis/pipelines/workflows/123/artifacts?api-version=6.0-preview' )
. reply ( 200 , { value : [ { url : 'https://invalid-artifact.com' , name : 'github-pages' } ] } )
const createDeploymentScope = nock ( 'https://api.github.com' )
. post ( ` /repos/ ${ process . env . GITHUB _REPOSITORY } /pages/deployments ` , {
artifact _url : 'https://invalid-artifact.com&%24expand=SignedContent' ,
pages _build _version : process . env . GITHUB _SHA
} )
. reply ( 403 , { message : 'You are forbidden' } )
2023-04-14 20:58:13 +01:00
2023-04-14 21:01:12 +01:00
// Create the deployment
const deployment = new Deployment ( )
await expect ( deployment . create ( ) ) . rejects . toEqual (
new Error (
` Failed to create deployment (status: 403) with build version ${ process . env . GITHUB _SHA } . Ensure GITHUB_TOKEN has permission "pages: write". `
2023-04-14 20:58:13 +01:00
)
2023-04-14 21:01:12 +01:00
)
artifactExchangeScope . done ( )
createDeploymentScope . done ( )
} )
it ( 'reports errors with an unexpected 404 during deployment' , async ( ) => {
process . env . GITHUB _SHA = 'build-version'
const artifactExchangeScope = nock ( ` http://my-url ` )
. get ( '/_apis/pipelines/workflows/123/artifacts?api-version=6.0-preview' )
. reply ( 200 , { value : [ { url : 'https://invalid-artifact.com' , name : 'github-pages' } ] } )
const createDeploymentScope = nock ( 'https://api.github.com' )
. post ( ` /repos/ ${ process . env . GITHUB _REPOSITORY } /pages/deployments ` , {
artifact _url : 'https://invalid-artifact.com&%24expand=SignedContent' ,
pages _build _version : process . env . GITHUB _SHA
} )
. reply ( 404 , { message : 'Not found' } )
2023-04-14 20:58:13 +01:00
2023-04-14 21:01:12 +01:00
// Create the deployment
const deployment = new Deployment ( )
await expect ( deployment . create ( ) ) . rejects . toEqual (
new Error (
` Failed to create deployment (status: 404) with build version ${ process . env . GITHUB _SHA } . Ensure GitHub Pages has been enabled: https://github.com/actions/is-awesome/settings/pages `
2023-04-14 20:58:13 +01:00
)
2023-04-14 21:01:12 +01:00
)
artifactExchangeScope . done ( )
createDeploymentScope . done ( )
} )
it ( 'reports errors with failed deployments' , async ( ) => {
process . env . GITHUB _SHA = 'invalid-build-version'
const artifactExchangeScope = nock ( ` http://my-url ` )
. get ( '/_apis/pipelines/workflows/123/artifacts?api-version=6.0-preview' )
. reply ( 200 , { value : [ { url : 'https://invalid-artifact.com' , name : 'github-pages' } ] } )
const createDeploymentScope = nock ( 'https://api.github.com' )
. post ( ` /repos/ ${ process . env . GITHUB _REPOSITORY } /pages/deployments ` , {
artifact _url : 'https://invalid-artifact.com&%24expand=SignedContent' ,
pages _build _version : process . env . GITHUB _SHA
} )
. reply ( 400 , { message : 'Bad request' } )
// Create the deployment
const deployment = new Deployment ( )
await expect ( deployment . create ( ) ) . rejects . toEqual (
new Error (
` Failed to create deployment (status: 400) with build version ${ process . env . GITHUB _SHA } . Responded with: Bad request `
2023-04-14 20:43:44 +01:00
)
2023-04-14 21:01:12 +01:00
)
artifactExchangeScope . done ( )
createDeploymentScope . done ( )
2023-04-14 20:43:44 +01:00
} )
2023-04-14 21:01:12 +01:00
} )
describe ( '#check' , ( ) => {
it ( 'sets output to success when deployment is successful' , async ( ) => {
process . env . GITHUB _SHA = 'valid-build-version'
const artifactExchangeScope = nock ( ` http://my-url ` )
. 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' }
]
2023-04-14 20:43:44 +01:00
} )
2023-04-14 21:01:12 +01:00
const createDeploymentScope = nock ( 'https://api.github.com' )
. post ( ` /repos/ ${ process . env . GITHUB _REPOSITORY } /pages/deployments ` , {
artifact _url : 'https://fake-artifact.com&%24expand=SignedContent' ,
pages _build _version : process . env . GITHUB _SHA ,
oidc _token : fakeJwt
} )
. reply ( 200 , {
status _url : ` https://api.github.com/repos/ ${ process . env . GITHUB _REPOSITORY } /pages/deployments/ ${ process . env . GITHUB _SHA } ` ,
page _url : 'https://actions.github.io/is-awesome'
} )
const deploymentStatusScope = nock ( 'https://api.github.com' )
. get ( ` /repos/ ${ process . env . GITHUB _REPOSITORY } /pages/deployments/ ${ process . env . GITHUB _SHA } ` )
. reply ( 200 , {
status : 'succeed'
} )
core . getIDToken = jest . fn ( ) . mockResolvedValue ( fakeJwt )
core . GetInput = jest . fn ( input => {
switch ( input ) {
case 'timeout' :
return 10 * 1000
case 'reporting_interval' :
return 0
}
2023-04-14 20:43:44 +01:00
} )
2023-04-14 21:01:12 +01:00
// Create the deployment
const deployment = new Deployment ( )
await deployment . create ( fakeJwt )
await deployment . check ( )
expect ( core . setOutput ) . toBeCalledWith ( 'status' , 'succeed' )
expect ( core . info ) . toHaveBeenLastCalledWith ( 'Reported success!' )
artifactExchangeScope . done ( )
createDeploymentScope . done ( )
deploymentStatusScope . done ( )
2023-04-14 20:43:44 +01:00
} )
2023-04-14 21:04:16 +01:00
it ( 'fails check when no deployment is found' , async ( ) => {
process . env . GITHUB _SHA = 'valid-build-version'
const deployment = new Deployment ( )
await deployment . check ( )
expect ( core . setFailed ) . toBeCalledWith ( 'Deployment not found.' )
} )
2023-04-14 21:10:57 +01:00
it ( 'exits early when deployment is not in progress' , async ( ) => {
process . env . GITHUB _SHA = 'valid-build-version'
const artifactExchangeScope = nock ( ` http://my-url ` )
. 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' }
]
} )
const createDeploymentScope = nock ( 'https://api.github.com' )
. post ( ` /repos/ ${ process . env . GITHUB _REPOSITORY } /pages/deployments ` , {
artifact _url : 'https://fake-artifact.com&%24expand=SignedContent' ,
pages _build _version : process . env . GITHUB _SHA ,
oidc _token : fakeJwt
} )
. reply ( 200 , {
status _url : ` https://api.github.com/repos/ ${ process . env . GITHUB _REPOSITORY } /pages/deployments/ ${ process . env . GITHUB _SHA } ` ,
page _url : 'https://actions.github.io/is-awesome'
} )
core . getIDToken = jest . fn ( ) . mockResolvedValue ( fakeJwt )
core . GetInput = jest . fn ( input => {
switch ( input ) {
case 'timeout' :
return 10 * 1000
case 'reporting_interval' :
return 0
}
} )
const deployment = new Deployment ( )
await deployment . create ( fakeJwt )
deployment . deploymentInfo . pending = false
await deployment . check ( )
expect ( core . setFailed ) . toBeCalledWith ( 'Unable to get deployment status.' )
artifactExchangeScope . done ( )
createDeploymentScope . done ( )
} )
2023-04-14 21:01:12 +01:00
} )
describe ( '#cancel' , ( ) => {
it ( 'can successfully cancel a deployment' , async ( ) => {
process . env . GITHUB _SHA = 'valid-build-version'
const artifactExchangeScope = nock ( ` http://my-url ` )
. 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' }
]
} )
const createDeploymentScope = nock ( 'https://api.github.com' )
. post ( ` /repos/ ${ process . env . GITHUB _REPOSITORY } /pages/deployments ` , {
artifact _url : 'https://fake-artifact.com&%24expand=SignedContent' ,
pages _build _version : process . env . GITHUB _SHA ,
oidc _token : fakeJwt
} )
. reply ( 200 , {
status _url : ` https://api.github.com/repos/ ${ process . env . GITHUB _REPOSITORY } /pages/deployments/ ${ process . env . GITHUB _SHA } ` ,
page _url : 'https://actions.github.io/is-awesome'
} )
const cancelDeploymentScope = nock ( 'https://api.github.com' )
. post ( ` /repos/ ${ process . env . GITHUB _REPOSITORY } /pages/deployments/ ${ process . env . GITHUB _SHA } /cancel ` )
. reply ( 200 , { } )
core . getIDToken = jest . fn ( ) . mockResolvedValue ( fakeJwt )
// Create the deployment
const deployment = new Deployment ( )
await deployment . create ( fakeJwt )
// Cancel it
await deployment . cancel ( )
expect ( core . info ) . toHaveBeenLastCalledWith ( ` Canceled deployment with ID ${ process . env . GITHUB _SHA } ` )
artifactExchangeScope . done ( )
createDeploymentScope . done ( )
cancelDeploymentScope . done ( )
2023-04-14 20:43:44 +01:00
} )
2023-04-14 21:20:52 +01:00
it ( 'can exit if a pages deployment was not created and none need to be cancelled' , async ( ) => {
process . env . GITHUB _SHA = 'valid-build-version'
// Create the deployment
const deployment = new Deployment ( )
// Cancel it
await deployment . cancel ( )
expect ( core . debug ) . toHaveBeenCalledWith ( 'all variables are set' )
expect ( core . debug ) . toHaveBeenCalledWith ( ` No deployment to cancel ` )
} )
2023-04-14 21:26:09 +01:00
it ( 'catches an error when trying to cancel a deployment' , async ( ) => {
process . env . GITHUB _SHA = 'valid-build-version'
const artifactExchangeScope = nock ( ` http://my-url ` )
. 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' }
]
} )
const createDeploymentScope = nock ( 'https://api.github.com' )
. post ( ` /repos/ ${ process . env . GITHUB _REPOSITORY } /pages/deployments ` , {
artifact _url : 'https://fake-artifact.com&%24expand=SignedContent' ,
pages _build _version : process . env . GITHUB _SHA ,
oidc _token : fakeJwt
} )
. reply ( 200 , {
status _url : ` https://api.github.com/repos/ ${ process . env . GITHUB _REPOSITORY } /pages/deployments/ ${ process . env . GITHUB _SHA } ` ,
page _url : 'https://actions.github.io/is-awesome'
} )
// nock will throw an error every time it tries to cancel the deployment
const cancelDeploymentScope = nock ( 'https://api.github.com' )
. post ( ` /repos/ ${ process . env . GITHUB _REPOSITORY } /pages/deployments/ ${ process . env . GITHUB _SHA } /cancel ` )
. reply ( 500 , { } )
core . getIDToken = jest . fn ( ) . mockResolvedValue ( fakeJwt )
// Create the deployment
const deployment = new Deployment ( )
await deployment . create ( fakeJwt )
// Cancel it
await deployment . cancel ( )
expect ( core . error ) . toHaveBeenCalledWith ( ` Canceling Pages deployment failed ` , expect . anything ( ) )
artifactExchangeScope . done ( )
createDeploymentScope . done ( )
cancelDeploymentScope . done ( )
} )
2023-04-14 20:43:44 +01:00
} )
2023-04-14 21:01:12 +01:00
} )