mirror of
https://github.com/actions/deploy-pages.git
synced 2026-09-27 13:07:04 +00:00
Compare commits
1 Commits
dependabot
...
dependabot
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
072c032891 |
@@ -51,7 +51,7 @@ jobs:
|
||||
| `token` | `true` | `${{ github.token }}` | The GitHub token used to create an authenticated client - Provided for you by default! |
|
||||
| `timeout` | `false` | `"600000"` | Time in milliseconds after which to timeout and cancel the deployment (default: 10 minutes) |
|
||||
| `error_count` | `false` | `"10"` | Maximum number of status report errors before cancelling a deployment (default: 10) |
|
||||
| `reporting_interval` | `false` | `"5000"` | Initial time in milliseconds between deployment status reports. Successful non-terminal polls use exponential backoff up to 30 seconds, or the configured interval when higher, with ±20% jitter. Error backoff is added separately (default: 5 seconds). |
|
||||
| `reporting_interval` | `false` | `"5000"` | Time in milliseconds between two deployment status reports (default: 5 seconds) |
|
||||
| `artifact_name` | `false` | `"github-pages"` | The name of the artifact to deploy |
|
||||
| `preview` | `false` | `"false"` | Is this attempting to deploy a pull request as a GitHub Pages preview site? (NOTE: This feature is only in alpha currently and is not available to the public!) |
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ inputs:
|
||||
required: false
|
||||
default: '10'
|
||||
reporting_interval:
|
||||
description: 'Initial time between deployment status reports; successful polls use capped backoff and jitter, with error backoff added separately (default: 5 seconds)'
|
||||
description: 'Time in milliseconds between two deployment status report (default: 5 seconds)'
|
||||
required: false
|
||||
default: '5000'
|
||||
artifact_name:
|
||||
|
||||
33
dist/index.js
generated
vendored
33
dist/index.js
generated
vendored
@@ -149920,18 +149920,9 @@ const finalErrorStatus = {
|
||||
}
|
||||
|
||||
const MAX_TIMEOUT = 600000
|
||||
const DEFAULT_REPORTING_INTERVAL = 5000
|
||||
const MAX_REPORTING_INTERVAL = 30000
|
||||
const REPORTING_BACKOFF_MULTIPLIER = 1.5
|
||||
const REPORTING_JITTER_FACTOR = 0.2
|
||||
const ONE_GIGABYTE = 1073741824
|
||||
const SIZE_LIMIT_DESCRIPTION = '1 GB'
|
||||
|
||||
function getJitteredInterval(interval) {
|
||||
const jitter = interval * REPORTING_JITTER_FACTOR
|
||||
return Math.round(interval - jitter + Math.random() * jitter * 2)
|
||||
}
|
||||
|
||||
class Deployment {
|
||||
constructor() {
|
||||
const context = getContext()
|
||||
@@ -150043,19 +150034,9 @@ class Deployment {
|
||||
}
|
||||
|
||||
const deploymentId = this.deploymentInfo.id || this.buildVersion
|
||||
const reportingIntervalInput = Number(core.getInput('reporting_interval'))
|
||||
const initialReportingInterval =
|
||||
Number.isFinite(reportingIntervalInput) && reportingIntervalInput > 0
|
||||
? reportingIntervalInput
|
||||
: DEFAULT_REPORTING_INTERVAL
|
||||
const maxReportingInterval = Math.max(MAX_REPORTING_INTERVAL, initialReportingInterval)
|
||||
const reportingInterval = Number(core.getInput('reporting_interval'))
|
||||
const maxErrorCount = Number(core.getInput('error_count'))
|
||||
|
||||
if (initialReportingInterval !== reportingIntervalInput) {
|
||||
core.warning(`Invalid reporting_interval value; using the default of ${DEFAULT_REPORTING_INTERVAL} milliseconds.`)
|
||||
}
|
||||
|
||||
let reportingInterval = initialReportingInterval
|
||||
let errorCount = 0
|
||||
|
||||
// Time in milliseconds between two deployment status report when status errored, default 0.
|
||||
@@ -150066,7 +150047,7 @@ class Deployment {
|
||||
/*eslint no-constant-condition: ["error", { "checkLoops": false }]*/
|
||||
while (true) {
|
||||
// Handle reporting interval
|
||||
await new Promise(resolve => setTimeout(resolve, getJitteredInterval(reportingInterval + errorReportingInterval)))
|
||||
await new Promise(resolve => setTimeout(resolve, reportingInterval + errorReportingInterval))
|
||||
|
||||
// Check status
|
||||
try {
|
||||
@@ -150094,7 +150075,6 @@ class Deployment {
|
||||
|
||||
// reset the error reporting interval once get the proper status back.
|
||||
errorReportingInterval = 0
|
||||
reportingInterval = Math.min(Math.round(reportingInterval * REPORTING_BACKOFF_MULTIPLIER), maxReportingInterval)
|
||||
} catch (error) {
|
||||
core.error(error.stack)
|
||||
|
||||
@@ -150158,14 +150138,7 @@ class Deployment {
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
Deployment,
|
||||
MAX_TIMEOUT,
|
||||
DEFAULT_REPORTING_INTERVAL,
|
||||
MAX_REPORTING_INTERVAL,
|
||||
ONE_GIGABYTE,
|
||||
SIZE_LIMIT_DESCRIPTION
|
||||
}
|
||||
module.exports = { Deployment, MAX_TIMEOUT, ONE_GIGABYTE, SIZE_LIMIT_DESCRIPTION }
|
||||
|
||||
|
||||
/***/ }),
|
||||
|
||||
2
dist/index.js.map
generated
vendored
2
dist/index.js.map
generated
vendored
File diff suppressed because one or more lines are too long
55
package-lock.json
generated
55
package-lock.json
generated
@@ -2276,23 +2276,21 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": {
|
||||
"version": "2.1.4",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.4.tgz",
|
||||
"integrity": "sha512-hGfVzPxthbf3+2yjg/RBs60cB0FhqBS/zvdV/4wn4/BmN0bNMMHPc4V/BbFieqf1TKAGGAHnY4eSjajCl0f2Xg==",
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
|
||||
"integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"balanced-match": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": {
|
||||
"version": "9.0.9",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz",
|
||||
"integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==",
|
||||
"version": "9.0.4",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz",
|
||||
"integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"brace-expansion": "^2.0.2"
|
||||
"brace-expansion": "^2.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16 || 14 >=14.17"
|
||||
@@ -2503,10 +2501,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/archiver-utils/node_modules/brace-expansion": {
|
||||
"version": "2.1.4",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.4.tgz",
|
||||
"integrity": "sha512-hGfVzPxthbf3+2yjg/RBs60cB0FhqBS/zvdV/4wn4/BmN0bNMMHPc4V/BbFieqf1TKAGGAHnY4eSjajCl0f2Xg==",
|
||||
"license": "MIT",
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
|
||||
"integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
|
||||
"dependencies": {
|
||||
"balanced-match": "^1.0.0"
|
||||
}
|
||||
@@ -2533,12 +2530,11 @@
|
||||
}
|
||||
},
|
||||
"node_modules/archiver-utils/node_modules/minimatch": {
|
||||
"version": "9.0.9",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz",
|
||||
"integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==",
|
||||
"license": "ISC",
|
||||
"version": "9.0.4",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz",
|
||||
"integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==",
|
||||
"dependencies": {
|
||||
"brace-expansion": "^2.0.2"
|
||||
"brace-expansion": "^2.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16 || 14 >=14.17"
|
||||
@@ -4480,10 +4476,11 @@
|
||||
}
|
||||
},
|
||||
"node_modules/flatted": {
|
||||
"version": "3.2.2",
|
||||
"resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.2.tgz",
|
||||
"integrity": "sha512-JaTY/wtrcSyvXJl4IMFHPKyFur1sE9AUqc0QnhOaJ0CxHtAoIV8pYDzeEfAaNEtGkOfq4gr3LBFmdXW5mOQFnA==",
|
||||
"dev": true
|
||||
"version": "3.4.4",
|
||||
"resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.4.tgz",
|
||||
"integrity": "sha512-5+ybhBZANEJxaH3X5evAFatUxLfEHSr7n6kYJ+1Qd0mUqr4eu9gIf6GDbWHf8RJijHrjjO8G+la14SlL2SeS1Q==",
|
||||
"dev": true,
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/for-each": {
|
||||
"version": "0.3.3",
|
||||
@@ -6479,10 +6476,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/minimatch": {
|
||||
"version": "3.1.5",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz",
|
||||
"integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==",
|
||||
"license": "ISC",
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
|
||||
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
|
||||
"dependencies": {
|
||||
"brace-expansion": "^1.1.7"
|
||||
},
|
||||
@@ -7131,10 +7127,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/readdir-glob/node_modules/minimatch": {
|
||||
"version": "5.1.9",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.9.tgz",
|
||||
"integrity": "sha512-7o1wEA2RyMP7Iu7GNba9vc0RWWGACJOCZBJX2GJWip0ikV+wcOsgVuY9uE8CPiyQhkGFSlhuSkZPavN7u1c2Fw==",
|
||||
"license": "ISC",
|
||||
"version": "5.1.6",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz",
|
||||
"integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==",
|
||||
"dependencies": {
|
||||
"brace-expansion": "^2.0.1"
|
||||
},
|
||||
|
||||
@@ -4,14 +4,7 @@ const nock = require('nock')
|
||||
// For mocking network calls with native Fetch (octokit)
|
||||
const { MockAgent, setGlobalDispatcher } = require('undici')
|
||||
|
||||
const {
|
||||
Deployment,
|
||||
MAX_TIMEOUT,
|
||||
DEFAULT_REPORTING_INTERVAL,
|
||||
MAX_REPORTING_INTERVAL,
|
||||
ONE_GIGABYTE,
|
||||
SIZE_LIMIT_DESCRIPTION
|
||||
} = require('../../internal/deployment')
|
||||
const { Deployment, MAX_TIMEOUT, ONE_GIGABYTE, SIZE_LIMIT_DESCRIPTION } = require('../../internal/deployment')
|
||||
|
||||
const fakeJwt =
|
||||
'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiJiNjllMWIxOC1jOGFiLTRhZGQtOGYxOC03MzVlMzVjZGJhZjAiLCJzdWIiOiJyZXBvOnBhcGVyLXNwYS9taW55aTplbnZpcm9ubWVudDpQcm9kdWN0aW9uIiwiYXVkIjoiaHR0cHM6Ly9naXRodWIuY29tL3BhcGVyLXNwYSIsInJlZiI6InJlZnMvaGVhZHMvbWFpbiIsInNoYSI6ImEyODU1MWJmODdiZDk3NTFiMzdiMmM0YjM3M2MxZjU3NjFmYWM2MjYiLCJyZXBvc2l0b3J5IjoicGFwZXItc3BhL21pbnlpIiwicmVwb3NpdG9yeV9vd25lciI6InBhcGVyLXNwYSIsInJ1bl9pZCI6IjE1NDY0NTkzNjQiLCJydW5fbnVtYmVyIjoiMzQiLCJydW5fYXR0ZW1wdCI6IjIiLCJhY3RvciI6IllpTXlzdHkiLCJ3b3JrZmxvdyI6IkNJIiwiaGVhZF9yZWYiOiIiLCJiYXNlX3JlZiI6IiIsImV2ZW50X25hbWUiOiJwdXNoIiwicmVmX3R5cGUiOiJicmFuY2giLCJlbnZpcm9ubWVudCI6IlByb2R1Y3Rpb24iLCJqb2Jfd29ya2Zsb3dfcmVmIjoicGFwZXItc3BhL21pbnlpLy5naXRodWIvd29ya2Zsb3dzL2JsYW5rLnltbEByZWZzL2hlYWRzL21haW4iLCJpc3MiOiJodHRwczovL3Rva2VuLmFjdGlvbnMuZ2l0aHVidXNlcmNvbnRlbnQuY29tIiwibmJmIjoxNjM4ODI4MDI4LCJleHAiOjE2Mzg4Mjg5MjgsImlhdCI6MTYzODgyODYyOH0.1wyupfxu1HGoTyIqatYg0hIxy2-0bMO-yVlmLSMuu2w'
|
||||
@@ -42,7 +35,7 @@ describe('Deployment', () => {
|
||||
case 'token':
|
||||
return process.env.GITHUB_TOKEN
|
||||
case 'reporting_interval':
|
||||
return process.env.INPUT_REPORTING_INTERVAL || 50 // Lower reporting interval to speed up test
|
||||
return 50 // Lower reporting interval to speed up test
|
||||
default:
|
||||
return process.env[`INPUT_${param.toUpperCase()}`] || ''
|
||||
}
|
||||
@@ -128,58 +121,6 @@ describe('Deployment', () => {
|
||||
twirpScope.done()
|
||||
})
|
||||
|
||||
it('can successfully create a deployment with a 64-character build version', async () => {
|
||||
process.env.GITHUB_SHA = 'a'.repeat(64)
|
||||
|
||||
const twirpScope = nock(process.env.ACTIONS_RESULTS_URL)
|
||||
.post(LIST_ARTIFACTS_TWIRP_PATH)
|
||||
.reply(
|
||||
200,
|
||||
{
|
||||
artifacts: [{ databaseId: 11, name: 'github-pages', size: 221 }]
|
||||
},
|
||||
{ headers: { 'content-type': 'application/json' } }
|
||||
)
|
||||
|
||||
mockPool
|
||||
.intercept({
|
||||
path: `/repos/${process.env.GITHUB_REPOSITORY}/pages/deployments`,
|
||||
method: 'POST',
|
||||
body: bodyString => {
|
||||
const body = JSON.parse(bodyString)
|
||||
const keys = Object.keys(body).sort()
|
||||
return (
|
||||
keys.length === 3 &&
|
||||
keys[0] === 'artifact_id' &&
|
||||
keys[1] === 'oidc_token' &&
|
||||
keys[2] === 'pages_build_version' &&
|
||||
body.artifact_id === 11 &&
|
||||
body.pages_build_version === process.env.GITHUB_SHA &&
|
||||
body.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'
|
||||
},
|
||||
{ headers: { 'content-type': 'application/json' } }
|
||||
)
|
||||
|
||||
const deployment = new Deployment()
|
||||
await deployment.create(fakeJwt)
|
||||
|
||||
expect(process.env.GITHUB_SHA).toHaveLength(64)
|
||||
expect(core.setFailed).not.toHaveBeenCalled()
|
||||
expect(core.info).toHaveBeenLastCalledWith(
|
||||
expect.stringMatching(new RegExp(`^Created deployment for ${process.env.GITHUB_SHA}`))
|
||||
)
|
||||
|
||||
twirpScope.done()
|
||||
})
|
||||
|
||||
it('can successfully create a preview deployment', async () => {
|
||||
process.env.GITHUB_SHA = 'valid-build-version'
|
||||
|
||||
@@ -615,42 +556,6 @@ describe('Deployment', () => {
|
||||
})
|
||||
|
||||
describe('#check', () => {
|
||||
afterEach(() => {
|
||||
jest.restoreAllMocks()
|
||||
delete process.env.INPUT_ERROR_COUNT
|
||||
delete process.env.INPUT_REPORTING_INTERVAL
|
||||
})
|
||||
|
||||
const mockDeploymentStatus = (status, times = 1) => {
|
||||
mockPool
|
||||
.intercept({
|
||||
path: `/repos/${process.env.GITHUB_REPOSITORY}/pages/deployments/${process.env.GITHUB_SHA}`,
|
||||
method: 'GET'
|
||||
})
|
||||
.reply(200, { status }, { headers: { 'content-type': 'application/json' } })
|
||||
.times(times)
|
||||
}
|
||||
|
||||
const createPendingDeployment = () => {
|
||||
const deployment = new Deployment()
|
||||
deployment.deploymentInfo = {
|
||||
id: process.env.GITHUB_SHA,
|
||||
pending: true
|
||||
}
|
||||
deployment.startTime = Date.now()
|
||||
return deployment
|
||||
}
|
||||
|
||||
const runWithoutWaiting = async deployment => {
|
||||
const timeoutSpy = jest.spyOn(global, 'setTimeout').mockImplementation(resolve => {
|
||||
resolve()
|
||||
return 0
|
||||
})
|
||||
|
||||
await deployment.check()
|
||||
return timeoutSpy
|
||||
}
|
||||
|
||||
it('sets output to success when deployment is successful', async () => {
|
||||
process.env.GITHUB_SHA = 'valid-build-version'
|
||||
|
||||
@@ -1007,7 +912,7 @@ describe('Deployment', () => {
|
||||
case 'error_count':
|
||||
return 10
|
||||
case 'reporting_interval':
|
||||
return 1 // The default of 5000 is too long for the test
|
||||
return 0 // The default of 5000 is too long for the test
|
||||
case 'timeout':
|
||||
return 42
|
||||
default:
|
||||
@@ -1033,108 +938,6 @@ describe('Deployment', () => {
|
||||
expect(core.info).toHaveBeenLastCalledWith('Reported success!')
|
||||
twirpScope.done()
|
||||
})
|
||||
|
||||
it('backs off successful non-terminal status checks', async () => {
|
||||
process.env.GITHUB_SHA = 'valid-build-version'
|
||||
process.env.INPUT_ERROR_COUNT = '10'
|
||||
mockDeploymentStatus('deployment_in_progress', 2)
|
||||
mockDeploymentStatus('succeed')
|
||||
const randomSpy = jest.spyOn(Math, 'random').mockReturnValue(0.5)
|
||||
|
||||
const timeoutSpy = await runWithoutWaiting(createPendingDeployment())
|
||||
|
||||
expect(timeoutSpy).toHaveBeenNthCalledWith(1, expect.any(Function), 50)
|
||||
expect(timeoutSpy).toHaveBeenNthCalledWith(2, expect.any(Function), 75)
|
||||
expect(timeoutSpy).toHaveBeenNthCalledWith(3, expect.any(Function), 113)
|
||||
|
||||
timeoutSpy.mockRestore()
|
||||
randomSpy.mockRestore()
|
||||
delete process.env.INPUT_ERROR_COUNT
|
||||
})
|
||||
|
||||
it('caps the successful status check backoff', async () => {
|
||||
process.env.GITHUB_SHA = 'valid-build-version'
|
||||
process.env.INPUT_ERROR_COUNT = '10'
|
||||
process.env.INPUT_REPORTING_INTERVAL = '20000'
|
||||
mockDeploymentStatus('deployment_in_progress')
|
||||
mockDeploymentStatus('succeed')
|
||||
const randomSpy = jest.spyOn(Math, 'random').mockReturnValue(0.5)
|
||||
|
||||
const timeoutSpy = await runWithoutWaiting(createPendingDeployment())
|
||||
|
||||
expect(timeoutSpy.mock.calls.map(([, interval]) => interval)).toEqual([20000, MAX_REPORTING_INTERVAL])
|
||||
|
||||
timeoutSpy.mockRestore()
|
||||
randomSpy.mockRestore()
|
||||
})
|
||||
|
||||
it('does not reduce a configured interval above the backoff cap', async () => {
|
||||
process.env.GITHUB_SHA = 'valid-build-version'
|
||||
process.env.INPUT_ERROR_COUNT = '10'
|
||||
process.env.INPUT_REPORTING_INTERVAL = '45000'
|
||||
mockDeploymentStatus('deployment_in_progress')
|
||||
mockDeploymentStatus('succeed')
|
||||
jest.spyOn(Math, 'random').mockReturnValue(0.5)
|
||||
|
||||
const timeoutSpy = await runWithoutWaiting(createPendingDeployment())
|
||||
|
||||
expect(timeoutSpy.mock.calls.map(([, interval]) => interval)).toEqual([45000, 45000])
|
||||
})
|
||||
|
||||
it.each(['not-a-number', '0', '-1'])(
|
||||
'uses the default reporting interval for invalid input %s',
|
||||
async reportingInterval => {
|
||||
process.env.GITHUB_SHA = 'valid-build-version'
|
||||
process.env.INPUT_ERROR_COUNT = '10'
|
||||
process.env.INPUT_REPORTING_INTERVAL = reportingInterval
|
||||
mockDeploymentStatus('succeed')
|
||||
jest.spyOn(Math, 'random').mockReturnValue(0.5)
|
||||
|
||||
const timeoutSpy = await runWithoutWaiting(createPendingDeployment())
|
||||
|
||||
expect(timeoutSpy).toHaveBeenCalledWith(expect.any(Function), DEFAULT_REPORTING_INTERVAL)
|
||||
expect(core.warning).toHaveBeenCalledWith(
|
||||
`Invalid reporting_interval value; using the default of ${DEFAULT_REPORTING_INTERVAL} milliseconds.`
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
it('jitters status check intervals by up to twenty percent', async () => {
|
||||
process.env.GITHUB_SHA = 'valid-build-version'
|
||||
process.env.INPUT_ERROR_COUNT = '10'
|
||||
mockDeploymentStatus('deployment_in_progress')
|
||||
mockDeploymentStatus('succeed')
|
||||
const randomSpy = jest.spyOn(Math, 'random').mockReturnValueOnce(0).mockReturnValueOnce(1)
|
||||
|
||||
const timeoutSpy = await runWithoutWaiting(createPendingDeployment())
|
||||
|
||||
expect(timeoutSpy).toHaveBeenNthCalledWith(1, expect.any(Function), 40)
|
||||
expect(timeoutSpy).toHaveBeenNthCalledWith(2, expect.any(Function), 90)
|
||||
|
||||
timeoutSpy.mockRestore()
|
||||
randomSpy.mockRestore()
|
||||
})
|
||||
|
||||
it('keeps success backoff separate from error backoff', async () => {
|
||||
process.env.GITHUB_SHA = 'valid-build-version'
|
||||
process.env.INPUT_ERROR_COUNT = '10'
|
||||
mockPool
|
||||
.intercept({
|
||||
path: `/repos/${process.env.GITHUB_REPOSITORY}/pages/deployments/${process.env.GITHUB_SHA}`,
|
||||
method: 'GET'
|
||||
})
|
||||
.reply(500, {}, { headers: { 'content-type': 'application/json' } })
|
||||
mockDeploymentStatus('deployment_in_progress')
|
||||
mockDeploymentStatus('succeed')
|
||||
const randomSpy = jest.spyOn(Math, 'random').mockReturnValue(0.5)
|
||||
|
||||
const timeoutSpy = await runWithoutWaiting(createPendingDeployment())
|
||||
|
||||
expect(timeoutSpy.mock.calls.map(([, interval]) => interval)).toEqual([50, 51, 75])
|
||||
|
||||
timeoutSpy.mockRestore()
|
||||
randomSpy.mockRestore()
|
||||
})
|
||||
})
|
||||
|
||||
describe('#cancel', () => {
|
||||
|
||||
@@ -24,18 +24,9 @@ const finalErrorStatus = {
|
||||
}
|
||||
|
||||
const MAX_TIMEOUT = 600000
|
||||
const DEFAULT_REPORTING_INTERVAL = 5000
|
||||
const MAX_REPORTING_INTERVAL = 30000
|
||||
const REPORTING_BACKOFF_MULTIPLIER = 1.5
|
||||
const REPORTING_JITTER_FACTOR = 0.2
|
||||
const ONE_GIGABYTE = 1073741824
|
||||
const SIZE_LIMIT_DESCRIPTION = '1 GB'
|
||||
|
||||
function getJitteredInterval(interval) {
|
||||
const jitter = interval * REPORTING_JITTER_FACTOR
|
||||
return Math.round(interval - jitter + Math.random() * jitter * 2)
|
||||
}
|
||||
|
||||
class Deployment {
|
||||
constructor() {
|
||||
const context = getContext()
|
||||
@@ -147,19 +138,9 @@ class Deployment {
|
||||
}
|
||||
|
||||
const deploymentId = this.deploymentInfo.id || this.buildVersion
|
||||
const reportingIntervalInput = Number(core.getInput('reporting_interval'))
|
||||
const initialReportingInterval =
|
||||
Number.isFinite(reportingIntervalInput) && reportingIntervalInput > 0
|
||||
? reportingIntervalInput
|
||||
: DEFAULT_REPORTING_INTERVAL
|
||||
const maxReportingInterval = Math.max(MAX_REPORTING_INTERVAL, initialReportingInterval)
|
||||
const reportingInterval = Number(core.getInput('reporting_interval'))
|
||||
const maxErrorCount = Number(core.getInput('error_count'))
|
||||
|
||||
if (initialReportingInterval !== reportingIntervalInput) {
|
||||
core.warning(`Invalid reporting_interval value; using the default of ${DEFAULT_REPORTING_INTERVAL} milliseconds.`)
|
||||
}
|
||||
|
||||
let reportingInterval = initialReportingInterval
|
||||
let errorCount = 0
|
||||
|
||||
// Time in milliseconds between two deployment status report when status errored, default 0.
|
||||
@@ -170,7 +151,7 @@ class Deployment {
|
||||
/*eslint no-constant-condition: ["error", { "checkLoops": false }]*/
|
||||
while (true) {
|
||||
// Handle reporting interval
|
||||
await new Promise(resolve => setTimeout(resolve, getJitteredInterval(reportingInterval + errorReportingInterval)))
|
||||
await new Promise(resolve => setTimeout(resolve, reportingInterval + errorReportingInterval))
|
||||
|
||||
// Check status
|
||||
try {
|
||||
@@ -198,7 +179,6 @@ class Deployment {
|
||||
|
||||
// reset the error reporting interval once get the proper status back.
|
||||
errorReportingInterval = 0
|
||||
reportingInterval = Math.min(Math.round(reportingInterval * REPORTING_BACKOFF_MULTIPLIER), maxReportingInterval)
|
||||
} catch (error) {
|
||||
core.error(error.stack)
|
||||
|
||||
@@ -262,11 +242,4 @@ class Deployment {
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
Deployment,
|
||||
MAX_TIMEOUT,
|
||||
DEFAULT_REPORTING_INTERVAL,
|
||||
MAX_REPORTING_INTERVAL,
|
||||
ONE_GIGABYTE,
|
||||
SIZE_LIMIT_DESCRIPTION
|
||||
}
|
||||
module.exports = { Deployment, MAX_TIMEOUT, ONE_GIGABYTE, SIZE_LIMIT_DESCRIPTION }
|
||||
|
||||
Reference in New Issue
Block a user