mirror of
https://github.com/actions/deploy-pages.git
synced 2026-03-28 17:04:53 +00:00
Compare commits
58 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
87c3283f01 | ||
|
|
87625d9f1e | ||
|
|
7a9bd943aa | ||
|
|
eee8a27158 | ||
|
|
b6e5c85160 | ||
|
|
b8d2528df3 | ||
|
|
53d1eac7fd | ||
|
|
3f0ef9d75d | ||
|
|
82751044df | ||
|
|
9be9d731c9 | ||
|
|
d8afefafec | ||
|
|
304d0b77f8 | ||
|
|
3a33eeefa1 | ||
|
|
d8af841ac3 | ||
|
|
35a0f06cfc | ||
|
|
5cba2b1245 | ||
|
|
e03d00b325 | ||
|
|
d6fbcf80b1 | ||
|
|
013b725db3 | ||
|
|
ed0e794532 | ||
|
|
1c0b543596 | ||
|
|
fe3d75dd3a | ||
|
|
b3879bac7d | ||
|
|
72ab98158a | ||
|
|
c704b8a6e2 | ||
|
|
02cb90ee32 | ||
|
|
88807a7a35 | ||
|
|
e386446c2a | ||
|
|
340b369533 | ||
|
|
4be34033fc | ||
|
|
0486580c63 | ||
|
|
af9eaca61c | ||
|
|
81251b551f | ||
|
|
47cf65bf47 | ||
|
|
1a1c979b91 | ||
|
|
925d92be20 | ||
|
|
b80d7fe30e | ||
|
|
d724c5069f | ||
|
|
f33f41b675 | ||
|
|
0d45f33cde | ||
|
|
d1e23d0efd | ||
|
|
125d07c91d | ||
|
|
7496661f94 | ||
|
|
4279385f7d | ||
|
|
a075a5970d | ||
|
|
b15b65d3e5 | ||
|
|
fa898e325d | ||
|
|
d45e4be1a6 | ||
|
|
b12897a760 | ||
|
|
499890a085 | ||
|
|
324d9f15de | ||
|
|
2196d013ad | ||
|
|
ce81cfb969 | ||
|
|
da4705cd08 | ||
|
|
961a4a1557 | ||
|
|
38d3e68bdc | ||
|
|
08232476b8 | ||
|
|
f69bebbdd5 |
2
.github/workflows/check-dist.yml
vendored
2
.github/workflows/check-dist.yml
vendored
@@ -46,7 +46,7 @@ jobs:
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
# If index.js was different than expected, upload the expected version as an artifact
|
# If index.js was different than expected, upload the expected version as an artifact
|
||||||
- uses: actions/upload-artifact@v3
|
- uses: actions/upload-artifact@v4
|
||||||
if: ${{ failure() && steps.diff.conclusion == 'failure' }}
|
if: ${{ failure() && steps.diff.conclusion == 'failure' }}
|
||||||
with:
|
with:
|
||||||
name: dist
|
name: dist
|
||||||
|
|||||||
6
.github/workflows/codeql-analysis.yml
vendored
6
.github/workflows/codeql-analysis.yml
vendored
@@ -42,7 +42,7 @@ jobs:
|
|||||||
|
|
||||||
# Initializes the CodeQL tools for scanning.
|
# Initializes the CodeQL tools for scanning.
|
||||||
- name: Initialize CodeQL
|
- name: Initialize CodeQL
|
||||||
uses: github/codeql-action/init@v2
|
uses: github/codeql-action/init@v3
|
||||||
with:
|
with:
|
||||||
languages: ${{ matrix.language }}
|
languages: ${{ matrix.language }}
|
||||||
# If you wish to specify custom queries, you can do so here or in a config file.
|
# If you wish to specify custom queries, you can do so here or in a config file.
|
||||||
@@ -53,7 +53,7 @@ jobs:
|
|||||||
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
||||||
# If this step fails, then you should remove it and run the build manually (see below)
|
# If this step fails, then you should remove it and run the build manually (see below)
|
||||||
- name: Autobuild
|
- name: Autobuild
|
||||||
uses: github/codeql-action/autobuild@v2
|
uses: github/codeql-action/autobuild@v3
|
||||||
|
|
||||||
# ℹ️ Command-line programs to run using the OS shell.
|
# ℹ️ Command-line programs to run using the OS shell.
|
||||||
# 📚 https://git.io/JvXDl
|
# 📚 https://git.io/JvXDl
|
||||||
@@ -67,4 +67,4 @@ jobs:
|
|||||||
# make release
|
# make release
|
||||||
|
|
||||||
- name: Perform CodeQL Analysis
|
- name: Perform CodeQL Analysis
|
||||||
uses: github/codeql-action/analyze@v2
|
uses: github/codeql-action/analyze@v3
|
||||||
|
|||||||
2
.github/workflows/release.yml
vendored
2
.github/workflows/release.yml
vendored
@@ -24,7 +24,7 @@ jobs:
|
|||||||
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.2.2
|
uses: actions/publish-action@v0.3.0
|
||||||
with:
|
with:
|
||||||
source-tag: ${{ env.TAG_NAME }}
|
source-tag: ${{ env.TAG_NAME }}
|
||||||
slack-webhook: ${{ secrets.SLACK_WEBHOOK }}
|
slack-webhook: ${{ secrets.SLACK_WEBHOOK }}
|
||||||
|
|||||||
@@ -6,11 +6,11 @@ This action is used to deploy [Actions artifacts][artifacts] to [GitHub Pages](h
|
|||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
See [action.yml](action.yml) for the various `inputs` this action supports.
|
See [action.yml](action.yml) for the various `inputs` this action supports (or [below](#inputs-📥)).
|
||||||
|
|
||||||
For examples that make use of this action, check out our [starter-workflows][starter-workflows] in a variety of frameworks.
|
For examples that make use of this action, check out our [starter-workflows][starter-workflows] in a variety of frameworks.
|
||||||
|
|
||||||
This action expects an artifact named `github-pages` to have been created prior to execution. This is done automatically when using [`actions/upload-pages-artifact`][upload-pages-artifact].
|
This action deploys a Pages site previously uploaded as an artifact (e.g. using [`actions/upload-pages-artifact`][upload-pages-artifact]).
|
||||||
|
|
||||||
We recommend this action to be used in a dedicated job:
|
We recommend this action to be used in a dedicated job:
|
||||||
|
|
||||||
@@ -41,7 +41,7 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- name: Deploy to GitHub Pages
|
- name: Deploy to GitHub Pages
|
||||||
id: deployment
|
id: deployment
|
||||||
uses: actions/deploy-pages@v3 # or specific "vX.X.X" version tag for this action
|
uses: actions/deploy-pages@v4 # or specific "vX.X.X" version tag for this action
|
||||||
```
|
```
|
||||||
|
|
||||||
### Inputs 📥
|
### Inputs 📥
|
||||||
@@ -71,7 +71,7 @@ jobs:
|
|||||||
|
|
||||||
There are a few important considerations to be aware of:
|
There are a few important considerations to be aware of:
|
||||||
|
|
||||||
1. The artifact being deployed must have been uploaded in a previous step, either in the same job or a separate job that doesn't execute until the upload is complete.
|
1. The artifact being deployed must have been uploaded in a previous step, either in the same job or a separate job that doesn't execute until the upload is complete. See [`actions/upload-pages-artifact`][upload-pages-artifact] for more information about the format of the artifact we expect.
|
||||||
|
|
||||||
2. The job that executes the deployment must at minimum have the following permissions:
|
2. The job that executes the deployment must at minimum have the following permissions:
|
||||||
- `pages: write`
|
- `pages: write`
|
||||||
@@ -89,6 +89,7 @@ This action is primarily designed for use with GitHub.com's Actions workflows an
|
|||||||
|
|
||||||
| Release | GHES Compatibility |
|
| Release | GHES Compatibility |
|
||||||
|:---|:---|
|
|:---|:---|
|
||||||
|
| [`v4`](https://github.com/actions/deploy-pages/releases/tag/v4) | :warning: Incompatible at this time |
|
||||||
| [`v3`](https://github.com/actions/deploy-pages/releases/tag/v3) | `>= 3.9` |
|
| [`v3`](https://github.com/actions/deploy-pages/releases/tag/v3) | `>= 3.9` |
|
||||||
| `v3.x.x` | `>= 3.9` |
|
| `v3.x.x` | `>= 3.9` |
|
||||||
| [`v2`](https://github.com/actions/deploy-pages/releases/tag/v2) | `>= 3.9` |
|
| [`v2`](https://github.com/actions/deploy-pages/releases/tag/v2) | `>= 3.9` |
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="116" height="20" role="img" aria-label="Coverage: 81.39%"><title>Coverage: 81.39%</title><linearGradient id="s" x2="0" y2="100%"><stop offset="0" stop-color="#bbb" stop-opacity=".1"/><stop offset="1" stop-opacity=".1"/></linearGradient><clipPath id="r"><rect width="116" height="20" rx="3" fill="#fff"/></clipPath><g clip-path="url(#r)"><rect width="63" height="20" fill="#555"/><rect x="63" width="53" height="20" fill="#dfb317"/><rect width="116" height="20" fill="url(#s)"/></g><g fill="#fff" text-anchor="middle" font-family="Verdana,Geneva,DejaVu Sans,sans-serif" text-rendering="geometricPrecision" font-size="110"><text aria-hidden="true" x="325" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="530">Coverage</text><text x="325" y="140" transform="scale(.1)" fill="#fff" textLength="530">Coverage</text><text aria-hidden="true" x="885" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="430">81.39%</text><text x="885" y="140" transform="scale(.1)" fill="#fff" textLength="430">81.39%</text></g></svg>
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="116" height="20" role="img" aria-label="Coverage: 81.13%"><title>Coverage: 81.13%</title><linearGradient id="s" x2="0" y2="100%"><stop offset="0" stop-color="#bbb" stop-opacity=".1"/><stop offset="1" stop-opacity=".1"/></linearGradient><clipPath id="r"><rect width="116" height="20" rx="3" fill="#fff"/></clipPath><g clip-path="url(#r)"><rect width="63" height="20" fill="#555"/><rect x="63" width="53" height="20" fill="#dfb317"/><rect width="116" height="20" fill="url(#s)"/></g><g fill="#fff" text-anchor="middle" font-family="Verdana,Geneva,DejaVu Sans,sans-serif" text-rendering="geometricPrecision" font-size="110"><text aria-hidden="true" x="325" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="530">Coverage</text><text x="325" y="140" transform="scale(.1)" fill="#fff" textLength="530">Coverage</text><text aria-hidden="true" x="885" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="430">81.13%</text><text x="885" y="140" transform="scale(.1)" fill="#fff" textLength="430">81.13%</text></g></svg>
|
||||||
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
98655
dist/index.js
generated
vendored
98655
dist/index.js
generated
vendored
File diff suppressed because one or more lines are too long
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
2764
dist/licenses.txt
generated
vendored
2764
dist/licenses.txt
generated
vendored
File diff suppressed because it is too large
Load Diff
7133
package-lock.json
generated
7133
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -4,22 +4,22 @@
|
|||||||
"description": "Deploy an actions artifact to GitHub Pages",
|
"description": "Deploy an actions artifact to GitHub Pages",
|
||||||
"main": "./dist/index.js",
|
"main": "./dist/index.js",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@actions/artifact": "^2.0.1",
|
||||||
"@actions/core": "^1.10.1",
|
"@actions/core": "^1.10.1",
|
||||||
"@actions/github": "^6.0.0",
|
"@actions/github": "^6.0.0",
|
||||||
"@actions/http-client": "^2.2.0",
|
|
||||||
"@octokit/request-error": "^5.0.1",
|
"@octokit/request-error": "^5.0.1",
|
||||||
"http-status-messages": "^1.1.0"
|
"http-status-messages": "^1.1.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@vercel/ncc": "^0.38.1",
|
"@vercel/ncc": "^0.38.1",
|
||||||
"eslint": "^8.55.0",
|
"eslint": "^8.56.0",
|
||||||
"eslint-config-prettier": "^9.1.0",
|
"eslint-config-prettier": "^9.1.0",
|
||||||
"eslint-plugin-github": "^4.10.1",
|
"eslint-plugin-github": "^4.10.1",
|
||||||
"jest": "^29.7.0",
|
"jest": "^29.7.0",
|
||||||
"make-coverage-badge": "^1.2.0",
|
"make-coverage-badge": "^1.2.0",
|
||||||
"nock": "^13.4.0",
|
"nock": "^13.4.0",
|
||||||
"prettier": "^3.1.0",
|
"prettier": "^3.1.0",
|
||||||
"undici": "^6.0.0"
|
"undici": "^6.2.1"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"all": "npm run format && npm run lint && npm run prepare && npm run test && npm run coverage-badge",
|
"all": "npm run format && npm run lint && npm run prepare && npm run test && npm run coverage-badge",
|
||||||
|
|||||||
@@ -4,9 +4,7 @@ const path = require('path')
|
|||||||
|
|
||||||
describe('with all environment variables set', () => {
|
describe('with all environment variables set', () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
process.env.ACTIONS_RUNTIME_URL = 'http://my-url'
|
|
||||||
process.env.GITHUB_RUN_ID = '123'
|
process.env.GITHUB_RUN_ID = '123'
|
||||||
process.env.ACTIONS_RUNTIME_TOKEN = 'a-token'
|
|
||||||
process.env.GITHUB_REPOSITORY = 'actions/is-awesome'
|
process.env.GITHUB_REPOSITORY = 'actions/is-awesome'
|
||||||
process.env.GITHUB_TOKEN = 'gha-token'
|
process.env.GITHUB_TOKEN = 'gha-token'
|
||||||
process.env.GITHUB_SHA = '123abc'
|
process.env.GITHUB_SHA = '123abc'
|
||||||
@@ -26,7 +24,7 @@ describe('with all environment variables set', () => {
|
|||||||
|
|
||||||
describe('with variables missing', () => {
|
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.GITHUB_RUN_ID
|
||||||
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('')
|
||||||
|
|||||||
@@ -9,20 +9,24 @@ const { Deployment, MAX_TIMEOUT, ONE_GIGABYTE, SIZE_LIMIT_DESCRIPTION } = requir
|
|||||||
const fakeJwt =
|
const fakeJwt =
|
||||||
'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiJiNjllMWIxOC1jOGFiLTRhZGQtOGYxOC03MzVlMzVjZGJhZjAiLCJzdWIiOiJyZXBvOnBhcGVyLXNwYS9taW55aTplbnZpcm9ubWVudDpQcm9kdWN0aW9uIiwiYXVkIjoiaHR0cHM6Ly9naXRodWIuY29tL3BhcGVyLXNwYSIsInJlZiI6InJlZnMvaGVhZHMvbWFpbiIsInNoYSI6ImEyODU1MWJmODdiZDk3NTFiMzdiMmM0YjM3M2MxZjU3NjFmYWM2MjYiLCJyZXBvc2l0b3J5IjoicGFwZXItc3BhL21pbnlpIiwicmVwb3NpdG9yeV9vd25lciI6InBhcGVyLXNwYSIsInJ1bl9pZCI6IjE1NDY0NTkzNjQiLCJydW5fbnVtYmVyIjoiMzQiLCJydW5fYXR0ZW1wdCI6IjIiLCJhY3RvciI6IllpTXlzdHkiLCJ3b3JrZmxvdyI6IkNJIiwiaGVhZF9yZWYiOiIiLCJiYXNlX3JlZiI6IiIsImV2ZW50X25hbWUiOiJwdXNoIiwicmVmX3R5cGUiOiJicmFuY2giLCJlbnZpcm9ubWVudCI6IlByb2R1Y3Rpb24iLCJqb2Jfd29ya2Zsb3dfcmVmIjoicGFwZXItc3BhL21pbnlpLy5naXRodWIvd29ya2Zsb3dzL2JsYW5rLnltbEByZWZzL2hlYWRzL21haW4iLCJpc3MiOiJodHRwczovL3Rva2VuLmFjdGlvbnMuZ2l0aHVidXNlcmNvbnRlbnQuY29tIiwibmJmIjoxNjM4ODI4MDI4LCJleHAiOjE2Mzg4Mjg5MjgsImlhdCI6MTYzODgyODYyOH0.1wyupfxu1HGoTyIqatYg0hIxy2-0bMO-yVlmLSMuu2w'
|
'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiJiNjllMWIxOC1jOGFiLTRhZGQtOGYxOC03MzVlMzVjZGJhZjAiLCJzdWIiOiJyZXBvOnBhcGVyLXNwYS9taW55aTplbnZpcm9ubWVudDpQcm9kdWN0aW9uIiwiYXVkIjoiaHR0cHM6Ly9naXRodWIuY29tL3BhcGVyLXNwYSIsInJlZiI6InJlZnMvaGVhZHMvbWFpbiIsInNoYSI6ImEyODU1MWJmODdiZDk3NTFiMzdiMmM0YjM3M2MxZjU3NjFmYWM2MjYiLCJyZXBvc2l0b3J5IjoicGFwZXItc3BhL21pbnlpIiwicmVwb3NpdG9yeV9vd25lciI6InBhcGVyLXNwYSIsInJ1bl9pZCI6IjE1NDY0NTkzNjQiLCJydW5fbnVtYmVyIjoiMzQiLCJydW5fYXR0ZW1wdCI6IjIiLCJhY3RvciI6IllpTXlzdHkiLCJ3b3JrZmxvdyI6IkNJIiwiaGVhZF9yZWYiOiIiLCJiYXNlX3JlZiI6IiIsImV2ZW50X25hbWUiOiJwdXNoIiwicmVmX3R5cGUiOiJicmFuY2giLCJlbnZpcm9ubWVudCI6IlByb2R1Y3Rpb24iLCJqb2Jfd29ya2Zsb3dfcmVmIjoicGFwZXItc3BhL21pbnlpLy5naXRodWIvd29ya2Zsb3dzL2JsYW5rLnltbEByZWZzL2hlYWRzL21haW4iLCJpc3MiOiJodHRwczovL3Rva2VuLmFjdGlvbnMuZ2l0aHVidXNlcmNvbnRlbnQuY29tIiwibmJmIjoxNjM4ODI4MDI4LCJleHAiOjE2Mzg4Mjg5MjgsImlhdCI6MTYzODgyODYyOH0.1wyupfxu1HGoTyIqatYg0hIxy2-0bMO-yVlmLSMuu2w'
|
||||||
|
|
||||||
|
const LIST_ARTIFACTS_TWIRP_PATH = '/twirp/github.actions.results.api.v1.ArtifactService/ListArtifacts'
|
||||||
|
|
||||||
describe('Deployment', () => {
|
describe('Deployment', () => {
|
||||||
let mockPool
|
let mockPool
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
jest.clearAllMocks()
|
jest.clearAllMocks()
|
||||||
process.env.ACTIONS_RUNTIME_URL = 'http://my-url/'
|
|
||||||
process.env.GITHUB_RUN_ID = '123'
|
process.env.GITHUB_RUN_ID = '123'
|
||||||
process.env.ACTIONS_RUNTIME_TOKEN = 'a-token'
|
|
||||||
process.env.GITHUB_REPOSITORY = 'actions/is-awesome'
|
process.env.GITHUB_REPOSITORY = 'actions/is-awesome'
|
||||||
process.env.GITHUB_TOKEN = 'gha-token'
|
process.env.GITHUB_TOKEN = 'gha-token'
|
||||||
process.env.GITHUB_SHA = '123abc'
|
process.env.GITHUB_SHA = '123abc'
|
||||||
process.env.GITHUB_ACTOR = 'monalisa'
|
process.env.GITHUB_ACTOR = 'monalisa'
|
||||||
process.env.GITHUB_ACTION = '__monalisa/octocat'
|
process.env.GITHUB_ACTION = '__monalisa/octocat'
|
||||||
process.env.GITHUB_ACTION_PATH = 'something'
|
process.env.GITHUB_ACTION_PATH = 'something'
|
||||||
|
// A valid actions token must have an 'scp' field whose value is a space-delimited list of strings
|
||||||
|
process.env.ACTIONS_RUNTIME_TOKEN =
|
||||||
|
'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzY3AiOiJBY3Rpb25zLkV4YW1wbGVTY29wZSBBY3Rpb25zLlJlc3VsdHM6Y2U3ZjU0YzctNjFjNy00YWFlLTg4N2YtMzBkYTQ3NWY1ZjFhOmNhMzk1MDg1LTA0MGEtNTI2Yi0yY2U4LWJkYzg1ZjY5Mjc3NCJ9.l-VcBU1PeNk_lWpOhjWehQlYyjCcY2dp_EMt7Rf06io'
|
||||||
|
process.env.ACTIONS_RESULTS_URL = 'https://actions-results-url.biz'
|
||||||
|
|
||||||
jest.spyOn(core, 'getInput').mockImplementation(param => {
|
jest.spyOn(core, 'getInput').mockImplementation(param => {
|
||||||
switch (param) {
|
switch (param) {
|
||||||
@@ -52,7 +56,7 @@ describe('Deployment', () => {
|
|||||||
jest.spyOn(core, 'debug').mockImplementation(jest.fn())
|
jest.spyOn(core, 'debug').mockImplementation(jest.fn())
|
||||||
|
|
||||||
// Set up Fetch mocking
|
// Set up Fetch mocking
|
||||||
const mockAgent = new MockAgent()
|
let mockAgent = new MockAgent()
|
||||||
mockAgent.disableNetConnect()
|
mockAgent.disableNetConnect()
|
||||||
setGlobalDispatcher(mockAgent)
|
setGlobalDispatcher(mockAgent)
|
||||||
mockPool = mockAgent.get('https://api.github.com')
|
mockPool = mockAgent.get('https://api.github.com')
|
||||||
@@ -67,14 +71,15 @@ describe('Deployment', () => {
|
|||||||
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 artifactExchangeScope = nock(`http://my-url`)
|
const twirpScope = nock(process.env.ACTIONS_RESULTS_URL)
|
||||||
.get('/_apis/pipelines/workflows/123/artifacts?api-version=6.0-preview')
|
.post(LIST_ARTIFACTS_TWIRP_PATH)
|
||||||
.reply(200, {
|
.reply(
|
||||||
value: [
|
200,
|
||||||
{ url: 'https://another-artifact.com', name: 'another-artifact' },
|
{
|
||||||
{ url: 'https://fake-artifact.com', name: 'github-pages' }
|
artifacts: [{ databaseId: 11, name: 'github-pages', size: 221 }]
|
||||||
]
|
},
|
||||||
})
|
{ headers: { 'content-type': 'application/json' } }
|
||||||
|
)
|
||||||
|
|
||||||
mockPool
|
mockPool
|
||||||
.intercept({
|
.intercept({
|
||||||
@@ -85,10 +90,10 @@ describe('Deployment', () => {
|
|||||||
const keys = Object.keys(body).sort()
|
const keys = Object.keys(body).sort()
|
||||||
return (
|
return (
|
||||||
keys.length === 3 &&
|
keys.length === 3 &&
|
||||||
keys[0] === 'artifact_url' &&
|
keys[0] === 'artifact_id' &&
|
||||||
keys[1] === 'oidc_token' &&
|
keys[1] === 'oidc_token' &&
|
||||||
keys[2] === 'pages_build_version' &&
|
keys[2] === 'pages_build_version' &&
|
||||||
body.artifact_url === 'https://fake-artifact.com&%24expand=SignedContent' &&
|
body.artifact_id === 11 &&
|
||||||
body.pages_build_version === process.env.GITHUB_SHA &&
|
body.pages_build_version === process.env.GITHUB_SHA &&
|
||||||
body.oidc_token === fakeJwt
|
body.oidc_token === fakeJwt
|
||||||
)
|
)
|
||||||
@@ -113,21 +118,21 @@ describe('Deployment', () => {
|
|||||||
expect(core.info).toHaveBeenLastCalledWith(
|
expect(core.info).toHaveBeenLastCalledWith(
|
||||||
expect.stringMatching(new RegExp(`^Created deployment for ${process.env.GITHUB_SHA}`))
|
expect.stringMatching(new RegExp(`^Created deployment for ${process.env.GITHUB_SHA}`))
|
||||||
)
|
)
|
||||||
|
twirpScope.done()
|
||||||
artifactExchangeScope.done()
|
|
||||||
})
|
})
|
||||||
|
|
||||||
it('can successfully create a preview deployment', async () => {
|
it('can successfully create a preview deployment', async () => {
|
||||||
process.env.GITHUB_SHA = 'valid-build-version'
|
process.env.GITHUB_SHA = 'valid-build-version'
|
||||||
|
|
||||||
const artifactExchangeScope = nock(`http://my-url`)
|
const twirpScope = nock(process.env.ACTIONS_RESULTS_URL)
|
||||||
.get('/_apis/pipelines/workflows/123/artifacts?api-version=6.0-preview')
|
.post(LIST_ARTIFACTS_TWIRP_PATH)
|
||||||
.reply(200, {
|
.reply(
|
||||||
value: [
|
200,
|
||||||
{ url: 'https://another-artifact.com', name: 'another-artifact' },
|
{
|
||||||
{ url: 'https://fake-artifact.com', name: 'github-pages' }
|
artifacts: [{ databaseId: 11, name: 'github-pages', size: 221 }]
|
||||||
]
|
},
|
||||||
})
|
{ headers: { 'content-type': 'application/json' } }
|
||||||
|
)
|
||||||
|
|
||||||
mockPool
|
mockPool
|
||||||
.intercept({
|
.intercept({
|
||||||
@@ -138,11 +143,11 @@ describe('Deployment', () => {
|
|||||||
const keys = Object.keys(body).sort()
|
const keys = Object.keys(body).sort()
|
||||||
return (
|
return (
|
||||||
keys.length === 4 &&
|
keys.length === 4 &&
|
||||||
keys[0] === 'artifact_url' &&
|
keys[0] === 'artifact_id' &&
|
||||||
keys[1] === 'oidc_token' &&
|
keys[1] === 'oidc_token' &&
|
||||||
keys[2] === 'pages_build_version' &&
|
keys[2] === 'pages_build_version' &&
|
||||||
keys[3] === 'preview' &&
|
keys[3] === 'preview' &&
|
||||||
body.artifact_url === 'https://fake-artifact.com&%24expand=SignedContent' &&
|
body.artifact_id === 11 &&
|
||||||
body.pages_build_version === process.env.GITHUB_SHA &&
|
body.pages_build_version === process.env.GITHUB_SHA &&
|
||||||
body.oidc_token === fakeJwt &&
|
body.oidc_token === fakeJwt &&
|
||||||
body.preview === true
|
body.preview === true
|
||||||
@@ -172,32 +177,45 @@ describe('Deployment', () => {
|
|||||||
expect(core.info).toHaveBeenLastCalledWith(
|
expect(core.info).toHaveBeenLastCalledWith(
|
||||||
expect.stringMatching(new RegExp(`^Created deployment for ${process.env.GITHUB_SHA}`))
|
expect.stringMatching(new RegExp(`^Created deployment for ${process.env.GITHUB_SHA}`))
|
||||||
)
|
)
|
||||||
|
twirpScope.done()
|
||||||
artifactExchangeScope.done()
|
|
||||||
})
|
})
|
||||||
|
|
||||||
it('reports errors with failed artifact exchange', async () => {
|
it('reports errors with failed artifact metadata exchange', async () => {
|
||||||
process.env.GITHUB_SHA = 'invalid-build-version'
|
process.env.GITHUB_SHA = 'invalid-build-version'
|
||||||
const artifactExchangeScope = nock(`http://my-url`)
|
|
||||||
.get('/_apis/pipelines/workflows/123/artifacts?api-version=6.0-preview')
|
const twirpScope = nock(process.env.ACTIONS_RESULTS_URL)
|
||||||
.reply(400, {})
|
.post(LIST_ARTIFACTS_TWIRP_PATH)
|
||||||
|
.reply(400, { msg: 'yikes!' }, { 'content-type': 'application/json' })
|
||||||
|
|
||||||
// Create the deployment
|
// Create the deployment
|
||||||
const deployment = new Deployment()
|
const deployment = new Deployment()
|
||||||
await expect(deployment.create()).rejects.toEqual(
|
await expect(deployment.create()).rejects.toThrow(
|
||||||
new Error(
|
`Failed to create deployment (status: 400) with build version ${process.env.GITHUB_SHA}.`
|
||||||
`Failed to create deployment (status: 400) with build version ${process.env.GITHUB_SHA}. Responded with: Bad Request`
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
|
expect(core.error).toHaveBeenNthCalledWith(
|
||||||
artifactExchangeScope.done()
|
1,
|
||||||
|
'Listing artifact metadata failed',
|
||||||
|
new Error('Failed to ListArtifacts: Received non-retryable error: Failed request: (400) null: yikes!')
|
||||||
|
)
|
||||||
|
expect(core.error).toHaveBeenNthCalledWith(
|
||||||
|
2,
|
||||||
|
'Fetching artifact metadata failed. Is githubstatus.com reporting issues with API requests, Pages, or Actions? Please re-run the deployment at a later time.',
|
||||||
|
expect.any(Error)
|
||||||
|
)
|
||||||
|
twirpScope.done()
|
||||||
})
|
})
|
||||||
|
|
||||||
it('reports errors with a failed 500 in a deployment', async () => {
|
it('reports errors with a failed 500 in a deployment', async () => {
|
||||||
process.env.GITHUB_SHA = 'build-version'
|
process.env.GITHUB_SHA = 'build-version'
|
||||||
const artifactExchangeScope = nock(`http://my-url`)
|
const twirpScope = nock(process.env.ACTIONS_RESULTS_URL)
|
||||||
.get('/_apis/pipelines/workflows/123/artifacts?api-version=6.0-preview')
|
.post(LIST_ARTIFACTS_TWIRP_PATH)
|
||||||
.reply(200, { value: [{ url: 'https://invalid-artifact.com', name: 'github-pages' }] })
|
.reply(
|
||||||
|
200,
|
||||||
|
{
|
||||||
|
artifacts: [{ databaseId: 11, name: 'github-pages', size: 221 }]
|
||||||
|
},
|
||||||
|
{ headers: { 'content-type': 'application/json' } }
|
||||||
|
)
|
||||||
|
|
||||||
mockPool
|
mockPool
|
||||||
.intercept({
|
.intercept({
|
||||||
@@ -208,9 +226,9 @@ describe('Deployment', () => {
|
|||||||
const keys = Object.keys(body).sort()
|
const keys = Object.keys(body).sort()
|
||||||
return (
|
return (
|
||||||
keys.length === 2 &&
|
keys.length === 2 &&
|
||||||
keys[0] === 'artifact_url' &&
|
keys[0] === 'artifact_id' &&
|
||||||
keys[1] === 'pages_build_version' &&
|
keys[1] === 'pages_build_version' &&
|
||||||
body.artifact_url === 'https://invalid-artifact.com&%24expand=SignedContent' &&
|
body.artifact_id === 11 &&
|
||||||
body.pages_build_version === process.env.GITHUB_SHA
|
body.pages_build_version === process.env.GITHUB_SHA
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -224,15 +242,20 @@ describe('Deployment', () => {
|
|||||||
`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.`
|
`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.`
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
twirpScope.done()
|
||||||
artifactExchangeScope.done()
|
|
||||||
})
|
})
|
||||||
|
|
||||||
it('reports errors with an unexpected 403 during deployment', async () => {
|
it('reports errors with an unexpected 403 during deployment', async () => {
|
||||||
process.env.GITHUB_SHA = 'build-version'
|
process.env.GITHUB_SHA = 'build-version'
|
||||||
const artifactExchangeScope = nock(`http://my-url`)
|
const twirpScope = nock(process.env.ACTIONS_RESULTS_URL)
|
||||||
.get('/_apis/pipelines/workflows/123/artifacts?api-version=6.0-preview')
|
.post(LIST_ARTIFACTS_TWIRP_PATH)
|
||||||
.reply(200, { value: [{ url: 'https://invalid-artifact.com', name: 'github-pages' }] })
|
.reply(
|
||||||
|
200,
|
||||||
|
{
|
||||||
|
artifacts: [{ databaseId: 11, name: 'github-pages', size: 221 }]
|
||||||
|
},
|
||||||
|
{ headers: { 'content-type': 'application/json' } }
|
||||||
|
)
|
||||||
|
|
||||||
mockPool
|
mockPool
|
||||||
.intercept({
|
.intercept({
|
||||||
@@ -243,9 +266,9 @@ describe('Deployment', () => {
|
|||||||
const keys = Object.keys(body).sort()
|
const keys = Object.keys(body).sort()
|
||||||
return (
|
return (
|
||||||
keys.length === 2 &&
|
keys.length === 2 &&
|
||||||
keys[0] === 'artifact_url' &&
|
keys[0] === 'artifact_id' &&
|
||||||
keys[1] === 'pages_build_version' &&
|
keys[1] === 'pages_build_version' &&
|
||||||
body.artifact_url === 'https://invalid-artifact.com&%24expand=SignedContent' &&
|
body.artifact_id === 11 &&
|
||||||
body.pages_build_version === process.env.GITHUB_SHA
|
body.pages_build_version === process.env.GITHUB_SHA
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -259,15 +282,20 @@ describe('Deployment', () => {
|
|||||||
`Failed to create deployment (status: 403) with build version ${process.env.GITHUB_SHA}. Ensure GITHUB_TOKEN has permission "pages: write".`
|
`Failed to create deployment (status: 403) with build version ${process.env.GITHUB_SHA}. Ensure GITHUB_TOKEN has permission "pages: write".`
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
twirpScope.done()
|
||||||
artifactExchangeScope.done()
|
|
||||||
})
|
})
|
||||||
|
|
||||||
it('reports errors with an unexpected 404 during deployment', async () => {
|
it('reports errors with an unexpected 404 during deployment', async () => {
|
||||||
process.env.GITHUB_SHA = 'build-version'
|
process.env.GITHUB_SHA = 'build-version'
|
||||||
const artifactExchangeScope = nock(`http://my-url`)
|
const twirpScope = nock(process.env.ACTIONS_RESULTS_URL)
|
||||||
.get('/_apis/pipelines/workflows/123/artifacts?api-version=6.0-preview')
|
.post(LIST_ARTIFACTS_TWIRP_PATH)
|
||||||
.reply(200, { value: [{ url: 'https://invalid-artifact.com', name: 'github-pages' }] })
|
.reply(
|
||||||
|
200,
|
||||||
|
{
|
||||||
|
artifacts: [{ databaseId: 11, name: 'github-pages', size: 221 }]
|
||||||
|
},
|
||||||
|
{ headers: { 'content-type': 'application/json' } }
|
||||||
|
)
|
||||||
|
|
||||||
mockPool
|
mockPool
|
||||||
.intercept({
|
.intercept({
|
||||||
@@ -278,9 +306,9 @@ describe('Deployment', () => {
|
|||||||
const keys = Object.keys(body).sort()
|
const keys = Object.keys(body).sort()
|
||||||
return (
|
return (
|
||||||
keys.length === 2 &&
|
keys.length === 2 &&
|
||||||
keys[0] === 'artifact_url' &&
|
keys[0] === 'artifact_id' &&
|
||||||
keys[1] === 'pages_build_version' &&
|
keys[1] === 'pages_build_version' &&
|
||||||
body.artifact_url === 'https://invalid-artifact.com&%24expand=SignedContent' &&
|
body.artifact_id === 11 &&
|
||||||
body.pages_build_version === process.env.GITHUB_SHA
|
body.pages_build_version === process.env.GITHUB_SHA
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -294,15 +322,20 @@ describe('Deployment', () => {
|
|||||||
`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`
|
`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`
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
twirpScope.done()
|
||||||
artifactExchangeScope.done()
|
|
||||||
})
|
})
|
||||||
|
|
||||||
it('reports errors with failed deployments', async () => {
|
it('reports errors with failed deployments', async () => {
|
||||||
process.env.GITHUB_SHA = 'invalid-build-version'
|
process.env.GITHUB_SHA = 'invalid-build-version'
|
||||||
const artifactExchangeScope = nock(`http://my-url`)
|
const twirpScope = nock(process.env.ACTIONS_RESULTS_URL)
|
||||||
.get('/_apis/pipelines/workflows/123/artifacts?api-version=6.0-preview')
|
.post(LIST_ARTIFACTS_TWIRP_PATH)
|
||||||
.reply(200, { value: [{ url: 'https://invalid-artifact.com', name: 'github-pages' }] })
|
.reply(
|
||||||
|
200,
|
||||||
|
{
|
||||||
|
artifacts: [{ databaseId: 11, name: 'github-pages', size: 221 }]
|
||||||
|
},
|
||||||
|
{ headers: { 'content-type': 'application/json' } }
|
||||||
|
)
|
||||||
|
|
||||||
mockPool
|
mockPool
|
||||||
.intercept({
|
.intercept({
|
||||||
@@ -313,9 +346,9 @@ describe('Deployment', () => {
|
|||||||
const keys = Object.keys(body).sort()
|
const keys = Object.keys(body).sort()
|
||||||
return (
|
return (
|
||||||
keys.length === 2 &&
|
keys.length === 2 &&
|
||||||
keys[0] === 'artifact_url' &&
|
keys[0] === 'artifact_id' &&
|
||||||
keys[1] === 'pages_build_version' &&
|
keys[1] === 'pages_build_version' &&
|
||||||
body.artifact_url === 'https://invalid-artifact.com&%24expand=SignedContent' &&
|
body.artifact_id === 11 &&
|
||||||
body.pages_build_version === process.env.GITHUB_SHA
|
body.pages_build_version === process.env.GITHUB_SHA
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -329,22 +362,90 @@ describe('Deployment', () => {
|
|||||||
`Failed to create deployment (status: 400) with build version ${process.env.GITHUB_SHA}. Responded with: Bad request`
|
`Failed to create deployment (status: 400) with build version ${process.env.GITHUB_SHA}. Responded with: Bad request`
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
twirpScope.done()
|
||||||
|
})
|
||||||
|
|
||||||
artifactExchangeScope.done()
|
it('fails if there are multiple artifacts with the same name', async () => {
|
||||||
|
process.env.GITHUB_SHA = 'valid-build-version'
|
||||||
|
|
||||||
|
const twirpScope = nock(process.env.ACTIONS_RESULTS_URL)
|
||||||
|
.post(LIST_ARTIFACTS_TWIRP_PATH)
|
||||||
|
.reply(
|
||||||
|
200,
|
||||||
|
{
|
||||||
|
artifacts: [
|
||||||
|
{ databaseId: 13, name: 'github-pages', size: 1400 },
|
||||||
|
{ databaseId: 14, name: 'github-pages', size: 1620 }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{ headers: { 'content-type': 'application/json' } }
|
||||||
|
)
|
||||||
|
|
||||||
|
const deployment = new Deployment()
|
||||||
|
await expect(deployment.create(fakeJwt)).rejects.toThrow(
|
||||||
|
`Multiple artifacts named "github-pages" were unexpectedly found for this workflow run. Artifact count is 2.`
|
||||||
|
)
|
||||||
|
twirpScope.done()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('fails if there are no artifacts found', async () => {
|
||||||
|
process.env.GITHUB_SHA = 'valid-build-version'
|
||||||
|
|
||||||
|
const twirpScope = nock(process.env.ACTIONS_RESULTS_URL)
|
||||||
|
.post(LIST_ARTIFACTS_TWIRP_PATH)
|
||||||
|
.reply(
|
||||||
|
200,
|
||||||
|
{
|
||||||
|
artifacts: []
|
||||||
|
},
|
||||||
|
{ headers: { 'content-type': 'application/json' } }
|
||||||
|
)
|
||||||
|
|
||||||
|
const deployment = new Deployment()
|
||||||
|
await expect(deployment.create(fakeJwt)).rejects.toThrow(
|
||||||
|
`No artifacts named "github-pages" were found for this workflow run. Ensure artifacts are uploaded with actions/artifact@v4 or later.`
|
||||||
|
)
|
||||||
|
twirpScope.done()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('fails with error message if list artifact endpoint returns 501', async () => {
|
||||||
|
process.env.GITHUB_SHA = 'valid-build-version'
|
||||||
|
|
||||||
|
const twirpScope = nock(process.env.ACTIONS_RESULTS_URL)
|
||||||
|
.post(LIST_ARTIFACTS_TWIRP_PATH)
|
||||||
|
.reply(501, { msg: 'oh no' }, { headers: { 'content-type': 'application/json' } })
|
||||||
|
|
||||||
|
const deployment = new Deployment()
|
||||||
|
await expect(deployment.create(fakeJwt)).rejects.toThrow(
|
||||||
|
`Failed to create deployment (status: 501) 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.`
|
||||||
|
)
|
||||||
|
expect(core.error).toHaveBeenNthCalledWith(
|
||||||
|
1,
|
||||||
|
'Listing artifact metadata failed',
|
||||||
|
new Error('Failed to ListArtifacts: Received non-retryable error: Failed request: (501) null: oh no')
|
||||||
|
)
|
||||||
|
expect(core.error).toHaveBeenNthCalledWith(
|
||||||
|
2,
|
||||||
|
'Fetching artifact metadata failed. Is githubstatus.com reporting issues with API requests, Pages, or Actions? Please re-run the deployment at a later time.',
|
||||||
|
expect.any(Error)
|
||||||
|
)
|
||||||
|
|
||||||
|
twirpScope.done()
|
||||||
})
|
})
|
||||||
|
|
||||||
it('warns if the artifact size is bigger than maximum', async () => {
|
it('warns if the artifact size is bigger than maximum', async () => {
|
||||||
process.env.GITHUB_SHA = 'valid-build-version'
|
process.env.GITHUB_SHA = 'valid-build-version'
|
||||||
const artifactSize = ONE_GIGABYTE + 1
|
const artifactSize = ONE_GIGABYTE + 1
|
||||||
|
|
||||||
const artifactExchangeScope = nock(`http://my-url`)
|
const twirpScope = nock(process.env.ACTIONS_RESULTS_URL)
|
||||||
.get('/_apis/pipelines/workflows/123/artifacts?api-version=6.0-preview')
|
.post(LIST_ARTIFACTS_TWIRP_PATH)
|
||||||
.reply(200, {
|
.reply(
|
||||||
value: [
|
200,
|
||||||
{ url: 'https://fake-artifact.com', name: 'github-pages', size: `${artifactSize}` },
|
{
|
||||||
{ url: 'https://another-artifact.com', name: 'another-artifact' }
|
artifacts: [{ databaseId: 12, name: 'github-pages', size: artifactSize }]
|
||||||
]
|
},
|
||||||
})
|
{ headers: { 'content-type': 'application/json' } }
|
||||||
|
)
|
||||||
|
|
||||||
mockPool
|
mockPool
|
||||||
.intercept({
|
.intercept({
|
||||||
@@ -355,10 +456,10 @@ describe('Deployment', () => {
|
|||||||
const keys = Object.keys(body).sort()
|
const keys = Object.keys(body).sort()
|
||||||
return (
|
return (
|
||||||
keys.length === 3 &&
|
keys.length === 3 &&
|
||||||
keys[0] === 'artifact_url' &&
|
keys[0] === 'artifact_id' &&
|
||||||
keys[1] === 'oidc_token' &&
|
keys[1] === 'oidc_token' &&
|
||||||
keys[2] === 'pages_build_version' &&
|
keys[2] === 'pages_build_version' &&
|
||||||
body.artifact_url === 'https://fake-artifact.com&%24expand=SignedContent' &&
|
body.artifact_id === 12 &&
|
||||||
body.oidc_token === fakeJwt &&
|
body.oidc_token === fakeJwt &&
|
||||||
body.pages_build_version === process.env.GITHUB_SHA
|
body.pages_build_version === process.env.GITHUB_SHA
|
||||||
)
|
)
|
||||||
@@ -383,21 +484,21 @@ describe('Deployment', () => {
|
|||||||
expect(core.info).toHaveBeenLastCalledWith(
|
expect(core.info).toHaveBeenLastCalledWith(
|
||||||
expect.stringMatching(new RegExp(`^Created deployment for ${process.env.GITHUB_SHA}`))
|
expect.stringMatching(new RegExp(`^Created deployment for ${process.env.GITHUB_SHA}`))
|
||||||
)
|
)
|
||||||
|
twirpScope.done()
|
||||||
artifactExchangeScope.done()
|
|
||||||
})
|
})
|
||||||
|
|
||||||
it('warns when the timeout is greater than the maximum allowed', async () => {
|
it('warns when the timeout is greater than the maximum allowed', async () => {
|
||||||
process.env.GITHUB_SHA = 'valid-build-version'
|
process.env.GITHUB_SHA = 'valid-build-version'
|
||||||
|
|
||||||
const artifactExchangeScope = nock(`http://my-url`)
|
const twirpScope = nock(process.env.ACTIONS_RESULTS_URL)
|
||||||
.get('/_apis/pipelines/workflows/123/artifacts?api-version=6.0-preview')
|
.post(LIST_ARTIFACTS_TWIRP_PATH)
|
||||||
.reply(200, {
|
.reply(
|
||||||
value: [
|
200,
|
||||||
{ url: 'https://another-artifact.com', name: 'another-artifact' },
|
{
|
||||||
{ url: 'https://fake-artifact.com', name: 'github-pages' }
|
artifacts: [{ databaseId: 11, name: 'github-pages', size: 221 }]
|
||||||
]
|
},
|
||||||
})
|
{ headers: { 'content-type': 'application/json' } }
|
||||||
|
)
|
||||||
|
|
||||||
mockPool
|
mockPool
|
||||||
.intercept({
|
.intercept({
|
||||||
@@ -408,10 +509,10 @@ describe('Deployment', () => {
|
|||||||
const keys = Object.keys(body).sort()
|
const keys = Object.keys(body).sort()
|
||||||
return (
|
return (
|
||||||
keys.length === 3 &&
|
keys.length === 3 &&
|
||||||
keys[0] === 'artifact_url' &&
|
keys[0] === 'artifact_id' &&
|
||||||
keys[1] === 'oidc_token' &&
|
keys[1] === 'oidc_token' &&
|
||||||
keys[2] === 'pages_build_version' &&
|
keys[2] === 'pages_build_version' &&
|
||||||
body.artifact_url === 'https://fake-artifact.com&%24expand=SignedContent' &&
|
body.artifact_id === 11 &&
|
||||||
body.oidc_token === fakeJwt &&
|
body.oidc_token === fakeJwt &&
|
||||||
body.pages_build_version === process.env.GITHUB_SHA
|
body.pages_build_version === process.env.GITHUB_SHA
|
||||||
)
|
)
|
||||||
@@ -450,8 +551,7 @@ describe('Deployment', () => {
|
|||||||
expect(core.warning).toBeCalledWith(
|
expect(core.warning).toBeCalledWith(
|
||||||
`Warning: timeout value is greater than the allowed maximum - timeout set to the maximum of ${MAX_TIMEOUT} milliseconds.`
|
`Warning: timeout value is greater than the allowed maximum - timeout set to the maximum of ${MAX_TIMEOUT} milliseconds.`
|
||||||
)
|
)
|
||||||
|
twirpScope.done()
|
||||||
artifactExchangeScope.done()
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -459,14 +559,15 @@ describe('Deployment', () => {
|
|||||||
it('sets output to success when deployment is successful', async () => {
|
it('sets output to success when deployment is successful', async () => {
|
||||||
process.env.GITHUB_SHA = 'valid-build-version'
|
process.env.GITHUB_SHA = 'valid-build-version'
|
||||||
|
|
||||||
const artifactExchangeScope = nock(`http://my-url`)
|
const twirpScope = nock(process.env.ACTIONS_RESULTS_URL)
|
||||||
.get('/_apis/pipelines/workflows/123/artifacts?api-version=6.0-preview')
|
.post(LIST_ARTIFACTS_TWIRP_PATH)
|
||||||
.reply(200, {
|
.reply(
|
||||||
value: [
|
200,
|
||||||
{ url: 'https://another-artifact.com', name: 'another-artifact' },
|
{
|
||||||
{ url: 'https://fake-artifact.com', name: 'github-pages' }
|
artifacts: [{ databaseId: 11, name: 'github-pages', size: 221 }]
|
||||||
]
|
},
|
||||||
})
|
{ headers: { 'content-type': 'application/json' } }
|
||||||
|
)
|
||||||
|
|
||||||
mockPool
|
mockPool
|
||||||
.intercept({
|
.intercept({
|
||||||
@@ -477,10 +578,10 @@ describe('Deployment', () => {
|
|||||||
const keys = Object.keys(body).sort()
|
const keys = Object.keys(body).sort()
|
||||||
return (
|
return (
|
||||||
keys.length === 3 &&
|
keys.length === 3 &&
|
||||||
keys[0] === 'artifact_url' &&
|
keys[0] === 'artifact_id' &&
|
||||||
keys[1] === 'oidc_token' &&
|
keys[1] === 'oidc_token' &&
|
||||||
keys[2] === 'pages_build_version' &&
|
keys[2] === 'pages_build_version' &&
|
||||||
body.artifact_url === 'https://fake-artifact.com&%24expand=SignedContent' &&
|
body.artifact_id === 11 &&
|
||||||
body.oidc_token === fakeJwt &&
|
body.oidc_token === fakeJwt &&
|
||||||
body.pages_build_version === process.env.GITHUB_SHA
|
body.pages_build_version === process.env.GITHUB_SHA
|
||||||
)
|
)
|
||||||
@@ -511,8 +612,7 @@ describe('Deployment', () => {
|
|||||||
|
|
||||||
expect(core.setOutput).toBeCalledWith('status', 'succeed')
|
expect(core.setOutput).toBeCalledWith('status', 'succeed')
|
||||||
expect(core.info).toHaveBeenLastCalledWith('Reported success!')
|
expect(core.info).toHaveBeenLastCalledWith('Reported success!')
|
||||||
|
twirpScope.done()
|
||||||
artifactExchangeScope.done()
|
|
||||||
})
|
})
|
||||||
|
|
||||||
it('fails check when no deployment is found', async () => {
|
it('fails check when no deployment is found', async () => {
|
||||||
@@ -525,14 +625,15 @@ describe('Deployment', () => {
|
|||||||
it('exits early when deployment is not in progress', async () => {
|
it('exits early when deployment is not in progress', async () => {
|
||||||
process.env.GITHUB_SHA = 'valid-build-version'
|
process.env.GITHUB_SHA = 'valid-build-version'
|
||||||
|
|
||||||
const artifactExchangeScope = nock(`http://my-url`)
|
const twirpScope = nock(process.env.ACTIONS_RESULTS_URL)
|
||||||
.get('/_apis/pipelines/workflows/123/artifacts?api-version=6.0-preview')
|
.post(LIST_ARTIFACTS_TWIRP_PATH)
|
||||||
.reply(200, {
|
.reply(
|
||||||
value: [
|
200,
|
||||||
{ url: 'https://another-artifact.com', name: 'another-artifact' },
|
{
|
||||||
{ url: 'https://fake-artifact.com', name: 'github-pages' }
|
artifacts: [{ databaseId: 11, name: 'github-pages', size: 221 }]
|
||||||
]
|
},
|
||||||
})
|
{ headers: { 'content-type': 'application/json' } }
|
||||||
|
)
|
||||||
|
|
||||||
mockPool
|
mockPool
|
||||||
.intercept({
|
.intercept({
|
||||||
@@ -543,10 +644,10 @@ describe('Deployment', () => {
|
|||||||
const keys = Object.keys(body).sort()
|
const keys = Object.keys(body).sort()
|
||||||
return (
|
return (
|
||||||
keys.length === 3 &&
|
keys.length === 3 &&
|
||||||
keys[0] === 'artifact_url' &&
|
keys[0] === 'artifact_id' &&
|
||||||
keys[1] === 'oidc_token' &&
|
keys[1] === 'oidc_token' &&
|
||||||
keys[2] === 'pages_build_version' &&
|
keys[2] === 'pages_build_version' &&
|
||||||
body.artifact_url === 'https://fake-artifact.com&%24expand=SignedContent' &&
|
body.artifact_id === 11 &&
|
||||||
body.oidc_token === fakeJwt &&
|
body.oidc_token === fakeJwt &&
|
||||||
body.pages_build_version === process.env.GITHUB_SHA
|
body.pages_build_version === process.env.GITHUB_SHA
|
||||||
)
|
)
|
||||||
@@ -568,21 +669,21 @@ describe('Deployment', () => {
|
|||||||
deployment.deploymentInfo.pending = false
|
deployment.deploymentInfo.pending = false
|
||||||
await deployment.check()
|
await deployment.check()
|
||||||
expect(core.setFailed).toBeCalledWith('Unable to get deployment status.')
|
expect(core.setFailed).toBeCalledWith('Unable to get deployment status.')
|
||||||
|
twirpScope.done()
|
||||||
artifactExchangeScope.done()
|
|
||||||
})
|
})
|
||||||
|
|
||||||
it('enforces max timeout', async () => {
|
it('enforces max timeout', async () => {
|
||||||
process.env.GITHUB_SHA = 'valid-build-version'
|
process.env.GITHUB_SHA = 'valid-build-version'
|
||||||
|
|
||||||
const artifactExchangeScope = nock(`http://my-url`)
|
const twirpScope = nock(process.env.ACTIONS_RESULTS_URL)
|
||||||
.get('/_apis/pipelines/workflows/123/artifacts?api-version=6.0-preview')
|
.post(LIST_ARTIFACTS_TWIRP_PATH)
|
||||||
.reply(200, {
|
.reply(
|
||||||
value: [
|
200,
|
||||||
{ url: 'https://another-artifact.com', name: 'another-artifact' },
|
{
|
||||||
{ url: 'https://fake-artifact.com', name: 'github-pages' }
|
artifacts: [{ databaseId: 11, name: 'github-pages', size: 221 }]
|
||||||
]
|
},
|
||||||
})
|
{ headers: { 'content-type': 'application/json' } }
|
||||||
|
)
|
||||||
|
|
||||||
mockPool
|
mockPool
|
||||||
.intercept({
|
.intercept({
|
||||||
@@ -593,10 +694,10 @@ describe('Deployment', () => {
|
|||||||
const keys = Object.keys(body).sort()
|
const keys = Object.keys(body).sort()
|
||||||
return (
|
return (
|
||||||
keys.length === 3 &&
|
keys.length === 3 &&
|
||||||
keys[0] === 'artifact_url' &&
|
keys[0] === 'artifact_id' &&
|
||||||
keys[1] === 'oidc_token' &&
|
keys[1] === 'oidc_token' &&
|
||||||
keys[2] === 'pages_build_version' &&
|
keys[2] === 'pages_build_version' &&
|
||||||
body.artifact_url === 'https://fake-artifact.com&%24expand=SignedContent' &&
|
body.artifact_id === 11 &&
|
||||||
body.oidc_token === fakeJwt &&
|
body.oidc_token === fakeJwt &&
|
||||||
body.pages_build_version === process.env.GITHUB_SHA
|
body.pages_build_version === process.env.GITHUB_SHA
|
||||||
)
|
)
|
||||||
@@ -664,21 +765,21 @@ describe('Deployment', () => {
|
|||||||
expect(deployment.timeout).toEqual(MAX_TIMEOUT)
|
expect(deployment.timeout).toEqual(MAX_TIMEOUT)
|
||||||
expect(core.error).toBeCalledWith('Timeout reached, aborting!')
|
expect(core.error).toBeCalledWith('Timeout reached, aborting!')
|
||||||
expect(core.setFailed).toBeCalledWith('Timeout reached, aborting!')
|
expect(core.setFailed).toBeCalledWith('Timeout reached, aborting!')
|
||||||
|
twirpScope.done()
|
||||||
artifactExchangeScope.done()
|
|
||||||
})
|
})
|
||||||
|
|
||||||
it('sets timeout to user timeout if user timeout is less than max timeout', async () => {
|
it('sets timeout to user timeout if user timeout is less than max timeout', async () => {
|
||||||
process.env.GITHUB_SHA = 'valid-build-version'
|
process.env.GITHUB_SHA = 'valid-build-version'
|
||||||
|
|
||||||
const artifactExchangeScope = nock(`http://my-url`)
|
const twirpScope = nock(process.env.ACTIONS_RESULTS_URL)
|
||||||
.get('/_apis/pipelines/workflows/123/artifacts?api-version=6.0-preview')
|
.post(LIST_ARTIFACTS_TWIRP_PATH)
|
||||||
.reply(200, {
|
.reply(
|
||||||
value: [
|
200,
|
||||||
{ url: 'https://another-artifact.com', name: 'another-artifact' },
|
{
|
||||||
{ url: 'https://fake-artifact.com', name: 'github-pages' }
|
artifacts: [{ databaseId: 11, name: 'github-pages', size: 221 }]
|
||||||
]
|
},
|
||||||
})
|
{ headers: { 'content-type': 'application/json' } }
|
||||||
|
)
|
||||||
|
|
||||||
mockPool
|
mockPool
|
||||||
.intercept({
|
.intercept({
|
||||||
@@ -689,10 +790,10 @@ describe('Deployment', () => {
|
|||||||
const keys = Object.keys(body).sort()
|
const keys = Object.keys(body).sort()
|
||||||
return (
|
return (
|
||||||
keys.length === 3 &&
|
keys.length === 3 &&
|
||||||
keys[0] === 'artifact_url' &&
|
keys[0] === 'artifact_id' &&
|
||||||
keys[1] === 'oidc_token' &&
|
keys[1] === 'oidc_token' &&
|
||||||
keys[2] === 'pages_build_version' &&
|
keys[2] === 'pages_build_version' &&
|
||||||
body.artifact_url === 'https://fake-artifact.com&%24expand=SignedContent' &&
|
body.artifact_id === 11 &&
|
||||||
body.oidc_token === fakeJwt &&
|
body.oidc_token === fakeJwt &&
|
||||||
body.pages_build_version === process.env.GITHUB_SHA
|
body.pages_build_version === process.env.GITHUB_SHA
|
||||||
)
|
)
|
||||||
@@ -749,21 +850,21 @@ describe('Deployment', () => {
|
|||||||
expect(deployment.timeout).toEqual(42)
|
expect(deployment.timeout).toEqual(42)
|
||||||
expect(core.error).toBeCalledWith('Timeout reached, aborting!')
|
expect(core.error).toBeCalledWith('Timeout reached, aborting!')
|
||||||
expect(core.setFailed).toBeCalledWith('Timeout reached, aborting!')
|
expect(core.setFailed).toBeCalledWith('Timeout reached, aborting!')
|
||||||
|
twirpScope.done()
|
||||||
artifactExchangeScope.done()
|
|
||||||
})
|
})
|
||||||
|
|
||||||
it('sets output to success when timeout is set but not reached', async () => {
|
it('sets output to success when timeout is set but not reached', async () => {
|
||||||
process.env.GITHUB_SHA = 'valid-build-version'
|
process.env.GITHUB_SHA = 'valid-build-version'
|
||||||
|
|
||||||
const artifactExchangeScope = nock(`http://my-url`)
|
const twirpScope = nock(process.env.ACTIONS_RESULTS_URL)
|
||||||
.get('/_apis/pipelines/workflows/123/artifacts?api-version=6.0-preview')
|
.post(LIST_ARTIFACTS_TWIRP_PATH)
|
||||||
.reply(200, {
|
.reply(
|
||||||
value: [
|
200,
|
||||||
{ url: 'https://another-artifact.com', name: 'another-artifact' },
|
{
|
||||||
{ url: 'https://fake-artifact.com', name: 'github-pages' }
|
artifacts: [{ databaseId: 11, name: 'github-pages', size: 221 }]
|
||||||
]
|
},
|
||||||
})
|
{ headers: { 'content-type': 'application/json' } }
|
||||||
|
)
|
||||||
|
|
||||||
mockPool
|
mockPool
|
||||||
.intercept({
|
.intercept({
|
||||||
@@ -774,10 +875,10 @@ describe('Deployment', () => {
|
|||||||
const keys = Object.keys(body).sort()
|
const keys = Object.keys(body).sort()
|
||||||
return (
|
return (
|
||||||
keys.length === 3 &&
|
keys.length === 3 &&
|
||||||
keys[0] === 'artifact_url' &&
|
keys[0] === 'artifact_id' &&
|
||||||
keys[1] === 'oidc_token' &&
|
keys[1] === 'oidc_token' &&
|
||||||
keys[2] === 'pages_build_version' &&
|
keys[2] === 'pages_build_version' &&
|
||||||
body.artifact_url === 'https://fake-artifact.com&%24expand=SignedContent' &&
|
body.artifact_id === 11 &&
|
||||||
body.oidc_token === fakeJwt &&
|
body.oidc_token === fakeJwt &&
|
||||||
body.pages_build_version === process.env.GITHUB_SHA
|
body.pages_build_version === process.env.GITHUB_SHA
|
||||||
)
|
)
|
||||||
@@ -835,8 +936,7 @@ describe('Deployment', () => {
|
|||||||
expect(core.error).not.toBeCalled()
|
expect(core.error).not.toBeCalled()
|
||||||
expect(core.setOutput).toBeCalledWith('status', 'succeed')
|
expect(core.setOutput).toBeCalledWith('status', 'succeed')
|
||||||
expect(core.info).toHaveBeenLastCalledWith('Reported success!')
|
expect(core.info).toHaveBeenLastCalledWith('Reported success!')
|
||||||
|
twirpScope.done()
|
||||||
artifactExchangeScope.done()
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -844,14 +944,15 @@ describe('Deployment', () => {
|
|||||||
it('can successfully cancel a deployment', async () => {
|
it('can successfully cancel a deployment', async () => {
|
||||||
process.env.GITHUB_SHA = 'valid-build-version'
|
process.env.GITHUB_SHA = 'valid-build-version'
|
||||||
|
|
||||||
const artifactExchangeScope = nock(`http://my-url`)
|
const twirpScope = nock(process.env.ACTIONS_RESULTS_URL)
|
||||||
.get('/_apis/pipelines/workflows/123/artifacts?api-version=6.0-preview')
|
.post(LIST_ARTIFACTS_TWIRP_PATH)
|
||||||
.reply(200, {
|
.reply(
|
||||||
value: [
|
200,
|
||||||
{ url: 'https://another-artifact.com', name: 'another-artifact' },
|
{
|
||||||
{ url: 'https://fake-artifact.com', name: 'github-pages' }
|
artifacts: [{ databaseId: 11, name: 'github-pages', size: 221 }]
|
||||||
]
|
},
|
||||||
})
|
{ headers: { 'content-type': 'application/json' } }
|
||||||
|
)
|
||||||
|
|
||||||
mockPool
|
mockPool
|
||||||
.intercept({
|
.intercept({
|
||||||
@@ -862,10 +963,10 @@ describe('Deployment', () => {
|
|||||||
const keys = Object.keys(body).sort()
|
const keys = Object.keys(body).sort()
|
||||||
return (
|
return (
|
||||||
keys.length === 3 &&
|
keys.length === 3 &&
|
||||||
keys[0] === 'artifact_url' &&
|
keys[0] === 'artifact_id' &&
|
||||||
keys[1] === 'oidc_token' &&
|
keys[1] === 'oidc_token' &&
|
||||||
keys[2] === 'pages_build_version' &&
|
keys[2] === 'pages_build_version' &&
|
||||||
body.artifact_url === 'https://fake-artifact.com&%24expand=SignedContent' &&
|
body.artifact_id === 11 &&
|
||||||
body.oidc_token === fakeJwt &&
|
body.oidc_token === fakeJwt &&
|
||||||
body.pages_build_version === process.env.GITHUB_SHA
|
body.pages_build_version === process.env.GITHUB_SHA
|
||||||
)
|
)
|
||||||
@@ -897,8 +998,7 @@ describe('Deployment', () => {
|
|||||||
await deployment.cancel()
|
await deployment.cancel()
|
||||||
|
|
||||||
expect(core.info).toHaveBeenLastCalledWith(`Canceled deployment with ID ${process.env.GITHUB_SHA}`)
|
expect(core.info).toHaveBeenLastCalledWith(`Canceled deployment with ID ${process.env.GITHUB_SHA}`)
|
||||||
|
twirpScope.done()
|
||||||
artifactExchangeScope.done()
|
|
||||||
})
|
})
|
||||||
|
|
||||||
it('can exit if a pages deployment was not created and none need to be cancelled', async () => {
|
it('can exit if a pages deployment was not created and none need to be cancelled', async () => {
|
||||||
@@ -917,14 +1017,15 @@ describe('Deployment', () => {
|
|||||||
it('catches an error when trying to cancel a deployment', async () => {
|
it('catches an error when trying to cancel a deployment', async () => {
|
||||||
process.env.GITHUB_SHA = 'valid-build-version'
|
process.env.GITHUB_SHA = 'valid-build-version'
|
||||||
|
|
||||||
const artifactExchangeScope = nock(`http://my-url`)
|
const twirpScope = nock(process.env.ACTIONS_RESULTS_URL)
|
||||||
.get('/_apis/pipelines/workflows/123/artifacts?api-version=6.0-preview')
|
.post(LIST_ARTIFACTS_TWIRP_PATH)
|
||||||
.reply(200, {
|
.reply(
|
||||||
value: [
|
200,
|
||||||
{ url: 'https://another-artifact.com', name: 'another-artifact' },
|
{
|
||||||
{ url: 'https://fake-artifact.com', name: 'github-pages' }
|
artifacts: [{ databaseId: 11, name: 'github-pages', size: 221 }]
|
||||||
]
|
},
|
||||||
})
|
{ headers: { 'content-type': 'application/json' } }
|
||||||
|
)
|
||||||
|
|
||||||
mockPool
|
mockPool
|
||||||
.intercept({
|
.intercept({
|
||||||
@@ -935,10 +1036,10 @@ describe('Deployment', () => {
|
|||||||
const keys = Object.keys(body).sort()
|
const keys = Object.keys(body).sort()
|
||||||
return (
|
return (
|
||||||
keys.length === 3 &&
|
keys.length === 3 &&
|
||||||
keys[0] === 'artifact_url' &&
|
keys[0] === 'artifact_id' &&
|
||||||
keys[1] === 'oidc_token' &&
|
keys[1] === 'oidc_token' &&
|
||||||
keys[2] === 'pages_build_version' &&
|
keys[2] === 'pages_build_version' &&
|
||||||
body.artifact_url === 'https://fake-artifact.com&%24expand=SignedContent' &&
|
body.artifact_id === 11 &&
|
||||||
body.oidc_token === fakeJwt &&
|
body.oidc_token === fakeJwt &&
|
||||||
body.pages_build_version === process.env.GITHUB_SHA
|
body.pages_build_version === process.env.GITHUB_SHA
|
||||||
)
|
)
|
||||||
@@ -970,8 +1071,7 @@ describe('Deployment', () => {
|
|||||||
await deployment.cancel()
|
await deployment.cancel()
|
||||||
|
|
||||||
expect(core.error).toHaveBeenCalledWith(`Canceling Pages deployment failed`, expect.anything())
|
expect(core.error).toHaveBeenCalledWith(`Canceling Pages deployment failed`, expect.anything())
|
||||||
|
twirpScope.done()
|
||||||
artifactExchangeScope.done()
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,119 +1,118 @@
|
|||||||
const core = require('@actions/core')
|
const core = require('@actions/core')
|
||||||
const github = require('@actions/github')
|
const github = require('@actions/github')
|
||||||
const hc = require('@actions/http-client')
|
const { DefaultArtifactClient } = require('@actions/artifact')
|
||||||
const { RequestError } = require('@octokit/request-error')
|
const { RequestError } = require('@octokit/request-error')
|
||||||
const HttpStatusMessages = require('http-status-messages')
|
const HttpStatusMessages = require('http-status-messages')
|
||||||
|
|
||||||
// All variables we need from the runtime are loaded here
|
function wrapTwirpResponseLikeOctokit(twirpResponse, requestOptions) {
|
||||||
const getContext = require('./context')
|
|
||||||
|
|
||||||
async function processRuntimeResponse(res, requestOptions) {
|
|
||||||
// Parse the response body as JSON
|
|
||||||
let obj = null
|
|
||||||
try {
|
|
||||||
const contents = await res.readBody()
|
|
||||||
if (contents && contents.length > 0) {
|
|
||||||
obj = JSON.parse(contents)
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
// Invalid resource (contents not json); leaving resulting obj as null
|
|
||||||
}
|
|
||||||
|
|
||||||
// Specific response shape aligned with Octokit
|
// Specific response shape aligned with Octokit
|
||||||
const response = {
|
const response = {
|
||||||
url: res.message?.url || requestOptions.url,
|
url: requestOptions.url,
|
||||||
status: res.message?.statusCode || 0,
|
status: 200,
|
||||||
headers: {
|
headers: {
|
||||||
...res.message?.headers
|
...requestOptions.headers
|
||||||
},
|
},
|
||||||
data: obj
|
data: twirpResponse
|
||||||
}
|
}
|
||||||
|
|
||||||
// Forcibly throw errors for negative HTTP status codes!
|
|
||||||
// @actions/http-client doesn't do this by default.
|
|
||||||
// Mimic the errors thrown by Octokit for consistency.
|
|
||||||
if (response.status >= 400) {
|
|
||||||
// Try to get an error message from the response body
|
|
||||||
const errorMsg =
|
|
||||||
(typeof response.data === 'string' && response.data) ||
|
|
||||||
response.data?.error ||
|
|
||||||
response.data?.message ||
|
|
||||||
// Try the Node HTTP IncomingMessage's statusMessage property
|
|
||||||
res.message?.statusMessage ||
|
|
||||||
// Fallback to the HTTP status message based on the status code
|
|
||||||
HttpStatusMessages[response.status] ||
|
|
||||||
// Or if the status code is unexpected...
|
|
||||||
`Unknown error (${response.status})`
|
|
||||||
|
|
||||||
throw new RequestError(errorMsg, response.status, {
|
|
||||||
response,
|
|
||||||
request: requestOptions
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
return response
|
return response
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getSignedArtifactMetadata({ runtimeToken, workflowRunId, artifactName }) {
|
// Mimic the errors thrown by Octokit for consistency.
|
||||||
const { runTimeUrl: RUNTIME_URL } = getContext()
|
function wrapTwirpErrorLikeOctokit(twirpError, requestOptions) {
|
||||||
const artifactExchangeUrl = `${RUNTIME_URL}_apis/pipelines/workflows/${workflowRunId}/artifacts?api-version=6.0-preview`
|
const rawErrorMsg = twirpError?.message || twirpError?.toString() || ''
|
||||||
|
const statusCodeMatch = rawErrorMsg.match(/Failed request: \((?<statusCode>\d+)\)/)
|
||||||
|
const statusCode = statusCodeMatch?.groups?.statusCode ?? 500
|
||||||
|
|
||||||
const httpClient = new hc.HttpClient()
|
// Try to provide the best error message
|
||||||
let data = null
|
const errorMsg =
|
||||||
|
rawErrorMsg ||
|
||||||
|
// Fallback to the HTTP status message based on the status code
|
||||||
|
HttpStatusMessages[statusCode] ||
|
||||||
|
// Or if the status code is unexpected...
|
||||||
|
`Unknown error (${statusCode})`
|
||||||
|
|
||||||
|
// RequestError is an Octokit-specific class
|
||||||
|
return new RequestError(errorMsg, statusCode, {
|
||||||
|
response: {
|
||||||
|
url: requestOptions.url,
|
||||||
|
status: statusCode,
|
||||||
|
headers: {
|
||||||
|
...requestOptions.headers
|
||||||
|
},
|
||||||
|
data: rawErrorMsg ? { message: rawErrorMsg } : ''
|
||||||
|
},
|
||||||
|
request: requestOptions
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function getArtifactsServiceOrigin() {
|
||||||
|
const resultsUrl = process.env.ACTIONS_RESULTS_URL
|
||||||
|
return resultsUrl ? new URL(resultsUrl).origin : ''
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getArtifactMetadata({ artifactName }) {
|
||||||
|
const artifactClient = new DefaultArtifactClient()
|
||||||
|
|
||||||
|
// Primarily for debugging purposes, accuracy is not critical
|
||||||
|
const requestOptions = {
|
||||||
|
method: 'POST',
|
||||||
|
url: `${getArtifactsServiceOrigin()}/twirp/github.actions.results.api.v1.ArtifactService/ListArtifacts`,
|
||||||
|
headers: {
|
||||||
|
'content-type': 'application/json'
|
||||||
|
},
|
||||||
|
body: {}
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const requestHeaders = {
|
core.info(`Fetching artifact metadata for "${artifactName}" in this workflow run`)
|
||||||
accept: 'application/json',
|
|
||||||
authorization: `Bearer ${runtimeToken}`
|
let response
|
||||||
}
|
try {
|
||||||
const requestOptions = {
|
const twirpResponse = await artifactClient.listArtifacts()
|
||||||
method: 'GET',
|
response = wrapTwirpResponseLikeOctokit(twirpResponse, requestOptions)
|
||||||
url: artifactExchangeUrl,
|
} catch (twirpError) {
|
||||||
headers: {
|
core.error('Listing artifact metadata failed', twirpError)
|
||||||
...requestHeaders
|
const octokitError = wrapTwirpErrorLikeOctokit(twirpError, requestOptions)
|
||||||
},
|
throw octokitError
|
||||||
body: null
|
|
||||||
}
|
}
|
||||||
|
|
||||||
core.info(`Artifact exchange URL: ${artifactExchangeUrl}`)
|
const filteredArtifacts = response.data.artifacts.filter(artifact => artifact.name === artifactName)
|
||||||
const res = await httpClient.get(artifactExchangeUrl, requestHeaders)
|
|
||||||
|
|
||||||
// May throw a RequestError (HttpError)
|
const artifactCount = filteredArtifacts.length
|
||||||
const response = await processRuntimeResponse(res, requestOptions)
|
core.debug(`List artifact count: ${artifactCount}`)
|
||||||
|
|
||||||
data = response.data
|
if (artifactCount === 0) {
|
||||||
core.debug(JSON.stringify(data))
|
throw new Error(
|
||||||
|
`No artifacts named "${artifactName}" were found for this workflow run. Ensure artifacts are uploaded with actions/artifact@v4 or later.`
|
||||||
|
)
|
||||||
|
} else if (artifactCount > 1) {
|
||||||
|
throw new Error(
|
||||||
|
`Multiple artifacts named "${artifactName}" were unexpectedly found for this workflow run. Artifact count is ${artifactCount}.`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const artifact = filteredArtifacts[0]
|
||||||
|
core.debug(`Artifact: ${JSON.stringify(artifact)}`)
|
||||||
|
|
||||||
|
if (!artifact.size) {
|
||||||
|
core.warning('Artifact size was not found. Unable to verify if artifact size exceeds the allowed size.')
|
||||||
|
}
|
||||||
|
|
||||||
|
return artifact
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
core.error('Getting signed artifact URL failed', error)
|
core.error(
|
||||||
throw error
|
'Fetching artifact metadata failed. Is githubstatus.com reporting issues with API requests, Pages, or Actions? Please re-run the deployment at a later time.',
|
||||||
}
|
error
|
||||||
|
|
||||||
const artifact = data?.value?.find(artifact => artifact.name === artifactName)
|
|
||||||
const artifactRawUrl = artifact?.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.'
|
|
||||||
)
|
)
|
||||||
}
|
throw error
|
||||||
|
|
||||||
const signedArtifactUrl = `${artifactRawUrl}&%24expand=SignedContent`
|
|
||||||
|
|
||||||
const artifactSize = artifact?.size
|
|
||||||
if (!artifactSize) {
|
|
||||||
core.warning('Artifact size was not found. Unable to verify if artifact size exceeds the allowed size.')
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
url: signedArtifactUrl,
|
|
||||||
size: artifactSize
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function createPagesDeployment({ githubToken, artifactUrl, buildVersion, idToken, isPreview = false }) {
|
async function createPagesDeployment({ githubToken, artifactId, buildVersion, idToken, isPreview = false }) {
|
||||||
const octokit = github.getOctokit(githubToken)
|
const octokit = github.getOctokit(githubToken)
|
||||||
|
|
||||||
const payload = {
|
const payload = {
|
||||||
artifact_url: artifactUrl,
|
artifact_id: artifactId,
|
||||||
pages_build_version: buildVersion,
|
pages_build_version: buildVersion,
|
||||||
oidc_token: idToken
|
oidc_token: idToken
|
||||||
}
|
}
|
||||||
@@ -173,7 +172,7 @@ async function cancelPagesDeployment({ githubToken, deploymentId }) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
getSignedArtifactMetadata,
|
getArtifactMetadata,
|
||||||
createPagesDeployment,
|
createPagesDeployment,
|
||||||
getPagesDeploymentStatus,
|
getPagesDeploymentStatus,
|
||||||
cancelPagesDeployment
|
cancelPagesDeployment
|
||||||
|
|||||||
@@ -3,9 +3,7 @@ const core = require('@actions/core')
|
|||||||
// Load variables from Actions runtime
|
// Load variables from Actions runtime
|
||||||
function getRequiredVars() {
|
function getRequiredVars() {
|
||||||
return {
|
return {
|
||||||
runTimeUrl: process.env.ACTIONS_RUNTIME_URL,
|
|
||||||
workflowRun: process.env.GITHUB_RUN_ID,
|
workflowRun: process.env.GITHUB_RUN_ID,
|
||||||
runTimeToken: process.env.ACTIONS_RUNTIME_TOKEN,
|
|
||||||
repositoryNwo: process.env.GITHUB_REPOSITORY,
|
repositoryNwo: process.env.GITHUB_REPOSITORY,
|
||||||
buildVersion: process.env.GITHUB_SHA,
|
buildVersion: process.env.GITHUB_SHA,
|
||||||
buildActor: process.env.GITHUB_ACTOR,
|
buildActor: process.env.GITHUB_ACTOR,
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ const core = require('@actions/core')
|
|||||||
// All variables we need from the runtime are loaded here
|
// All variables we need from the runtime are loaded here
|
||||||
const getContext = require('./context')
|
const getContext = require('./context')
|
||||||
const {
|
const {
|
||||||
getSignedArtifactMetadata,
|
getArtifactMetadata,
|
||||||
createPagesDeployment,
|
createPagesDeployment,
|
||||||
getPagesDeploymentStatus,
|
getPagesDeploymentStatus,
|
||||||
cancelPagesDeployment
|
cancelPagesDeployment
|
||||||
@@ -31,9 +31,7 @@ const SIZE_LIMIT_DESCRIPTION = '1 GB'
|
|||||||
class Deployment {
|
class Deployment {
|
||||||
constructor() {
|
constructor() {
|
||||||
const context = getContext()
|
const context = getContext()
|
||||||
this.runTimeUrl = context.runTimeUrl
|
|
||||||
this.repositoryNwo = context.repositoryNwo
|
this.repositoryNwo = context.repositoryNwo
|
||||||
this.runTimeToken = context.runTimeToken
|
|
||||||
this.buildVersion = context.buildVersion
|
this.buildVersion = context.buildVersion
|
||||||
this.buildActor = context.buildActor
|
this.buildActor = context.buildActor
|
||||||
this.actionsId = context.actionsId
|
this.actionsId = context.actionsId
|
||||||
@@ -48,8 +46,8 @@ class Deployment {
|
|||||||
this.startTime = null
|
this.startTime = null
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ask the runtime for the unsigned artifact URL and deploy to GitHub Pages
|
// Call GitHub api to fetch artifacts matching the provided name and deploy to GitHub Pages
|
||||||
// by creating a deployment with that artifact
|
// by creating a deployment with that artifact id
|
||||||
async create(idToken) {
|
async create(idToken) {
|
||||||
if (Number(core.getInput('timeout')) > MAX_TIMEOUT) {
|
if (Number(core.getInput('timeout')) > MAX_TIMEOUT) {
|
||||||
core.warning(
|
core.warning(
|
||||||
@@ -65,11 +63,7 @@ class Deployment {
|
|||||||
core.debug(`Action ID: ${this.actionsId}`)
|
core.debug(`Action ID: ${this.actionsId}`)
|
||||||
core.debug(`Actions Workflow Run ID: ${this.workflowRun}`)
|
core.debug(`Actions Workflow Run ID: ${this.workflowRun}`)
|
||||||
|
|
||||||
const artifactData = await getSignedArtifactMetadata({
|
const artifactData = await getArtifactMetadata({ artifactName: this.artifactName })
|
||||||
runtimeToken: this.runTimeToken,
|
|
||||||
workflowRunId: this.workflowRun,
|
|
||||||
artifactName: this.artifactName
|
|
||||||
})
|
|
||||||
|
|
||||||
if (artifactData?.size > ONE_GIGABYTE) {
|
if (artifactData?.size > ONE_GIGABYTE) {
|
||||||
core.warning(
|
core.warning(
|
||||||
@@ -79,7 +73,7 @@ class Deployment {
|
|||||||
|
|
||||||
const deployment = await createPagesDeployment({
|
const deployment = await createPagesDeployment({
|
||||||
githubToken: this.githubToken,
|
githubToken: this.githubToken,
|
||||||
artifactUrl: artifactData.url,
|
artifactId: artifactData.id,
|
||||||
buildVersion: this.buildVersion,
|
buildVersion: this.buildVersion,
|
||||||
idToken,
|
idToken,
|
||||||
isPreview: this.isPreview
|
isPreview: this.isPreview
|
||||||
@@ -104,14 +98,14 @@ class Deployment {
|
|||||||
|
|
||||||
// build customized error message based on server response
|
// build customized error message based on server response
|
||||||
if (error.response) {
|
if (error.response) {
|
||||||
let errorMessage = `Failed to create deployment (status: ${error.status}) with build version ${this.buildVersion}. `
|
let errorMessage = `Failed to create deployment (status: ${error.status}) with build version ${this.buildVersion}.`
|
||||||
if (error.status === 400) {
|
if (error.status === 400) {
|
||||||
errorMessage += `Responded with: ${error.message}`
|
errorMessage += ` Responded with: ${error.message}`
|
||||||
} else if (error.status === 403) {
|
} else if (error.status === 403) {
|
||||||
errorMessage += 'Ensure GITHUB_TOKEN has permission "pages: write".'
|
errorMessage += ' Ensure GITHUB_TOKEN has permission "pages: write".'
|
||||||
} else if (error.status === 404) {
|
} else if (error.status === 404) {
|
||||||
const pagesSettingsUrl = `${this.githubServerUrl}/${this.repositoryNwo}/settings/pages`
|
const pagesSettingsUrl = `${this.githubServerUrl}/${this.repositoryNwo}/settings/pages`
|
||||||
errorMessage += `Ensure GitHub Pages has been enabled: ${pagesSettingsUrl}`
|
errorMessage += ` Ensure GitHub Pages has been enabled: ${pagesSettingsUrl}`
|
||||||
// If using GHES, add a special note about compatibility
|
// If using GHES, add a special note about compatibility
|
||||||
if (new URL(this.githubServerUrl).hostname.toLowerCase() !== 'github.com') {
|
if (new URL(this.githubServerUrl).hostname.toLowerCase() !== 'github.com') {
|
||||||
errorMessage +=
|
errorMessage +=
|
||||||
@@ -119,7 +113,7 @@ class Deployment {
|
|||||||
}
|
}
|
||||||
} else if (error.status >= 500) {
|
} else if (error.status >= 500) {
|
||||||
errorMessage +=
|
errorMessage +=
|
||||||
'Server error, is githubstatus.com reporting a Pages outage? Please re-run the deployment at a later time.'
|
' Server error, is githubstatus.com reporting a Pages outage? Please re-run the deployment at a later time.'
|
||||||
}
|
}
|
||||||
throw new Error(errorMessage)
|
throw new Error(errorMessage)
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
Reference in New Issue
Block a user