Compare commits

..

2 Commits
v2.0.1 ... v1

Author SHA1 Message Date
James M. Greene
f27bcc1584 Backporting PR #197 to the v1.x release line 2023-08-09 15:50:48 -05:00
James M. Greene
eb68e76f70 Backporting PR #187 to the v1.x release line 2023-08-09 15:48:55 -05:00
27 changed files with 1584 additions and 1713 deletions

View File

@@ -13,5 +13,5 @@
"rules": { "rules": {
"semi": ["error", "never"] "semi": ["error", "never"]
}, },
"ignorePatterns": ["/dist/"] "ignorePatterns": ["/dist/", "/pre/"]
} }

1
.gitattributes vendored
View File

@@ -1 +0,0 @@
dist/** -diff linguist-generated=true

View File

@@ -21,13 +21,12 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout - uses: actions/checkout@v3
uses: actions/checkout@v3
- name: Setup Node.JS - name: Set Node.js 16.x
uses: actions/setup-node@v3 uses: actions/setup-node@v3
with: with:
node-version-file: '.node-version' node-version: 16.x
cache: npm cache: npm
- name: Install dependencies - name: Install dependencies
@@ -37,17 +36,9 @@ jobs:
run: npm run prepare run: npm run prepare
- name: Compare the expected and actual dist/ directories - name: Compare the expected and actual dist/ directories
id: diff
run: | run: |
if [ "$(git diff --ignore-space-at-eol dist/ | wc -l)" -gt "0" ]; then if [ "$(git diff --ignore-space-at-eol dist/ | wc -l)" -gt "0" ]; then
echo "Detected uncommitted changes after build in dist folder. See status below:" echo "Detected uncommitted changes after build in dist folder. See status below:"
git diff git diff
exit 1 exit 1
fi fi
# If index.js was different than expected, upload the expected version as an artifact
- uses: actions/upload-artifact@v3
if: ${{ failure() && steps.diff.conclusion == 'failure' }}
with:
name: dist
path: dist/

View File

@@ -1,4 +1,4 @@
name: Check formatting name: Checking formatting
on: on:
push: push:
@@ -24,8 +24,8 @@ jobs:
- name: Setup Node.JS - name: Setup Node.JS
uses: actions/setup-node@v3 uses: actions/setup-node@v3
with: with:
node-version-file: '.node-version' node-version: 16.x
cache: npm cache: 'npm'
- name: Install dependencies - name: Install dependencies
run: npm ci run: npm ci

View File

@@ -1,4 +1,4 @@
name: Check linting name: Check linter
on: on:
push: push:
@@ -24,8 +24,8 @@ jobs:
- name: Setup Node.JS - name: Setup Node.JS
uses: actions/setup-node@v3 uses: actions/setup-node@v3
with: with:
node-version-file: '.node-version' node-version: 16.x
cache: npm cache: 'npm'
- name: Install dependencies - name: Install dependencies
run: npm ci run: npm ci

View File

@@ -9,7 +9,7 @@
# the `language` matrix defined below to confirm you have the correct set of # the `language` matrix defined below to confirm you have the correct set of
# supported CodeQL languages. # supported CodeQL languages.
# #
name: CodeQL name: 'CodeQL'
on: on:
push: push:
@@ -37,7 +37,7 @@ jobs:
# Learn more about CodeQL language support at https://git.io/codeql-language-support # Learn more about CodeQL language support at https://git.io/codeql-language-support
steps: steps:
- name: Checkout - name: Checkout repository
uses: actions/checkout@v3 uses: actions/checkout@v3
# Initializes the CodeQL tools for scanning. # Initializes the CodeQL tools for scanning.

View File

@@ -11,6 +11,7 @@ jobs:
draft-release: draft-release:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: release-drafter/release-drafter@569eb7ee3a85817ab916c8f8ff03a5bd96c9c83e # v5.23.0 - uses: actions/checkout@v3
- uses: release-drafter/release-drafter@v5
env: env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

View File

@@ -29,8 +29,8 @@ jobs:
- name: Setup Node.JS - name: Setup Node.JS
uses: actions/setup-node@v3 uses: actions/setup-node@v3
with: with:
node-version-file: '.node-version' node-version: 16.x
cache: npm cache: 'npm'
- name: Install dependencies - name: Install dependencies
run: npm ci run: npm ci

View File

@@ -1,4 +1,4 @@
name: Run tests name: Run Tests
on: on:
push: push:
@@ -19,8 +19,8 @@ jobs:
- name: Setup Node.JS - name: Setup Node.JS
uses: actions/setup-node@v3 uses: actions/setup-node@v3
with: with:
node-version-file: '.node-version' node-version: 16.x
cache: npm cache: 'npm'
- name: Install dependencies - name: Install dependencies
run: npm ci run: npm ci

2
.gitignore vendored
View File

@@ -64,4 +64,4 @@ typings/
.env .env
# next.js build output # next.js build output
.next .next

View File

@@ -1 +0,0 @@
18.9.0

1
CODEOWNERS Normal file
View File

@@ -0,0 +1 @@
* @actions/pages

View File

@@ -1,29 +0,0 @@
# Contributing 💻
All contributions are welcome and greatly appreciated!
## Steps to Contribute 💡
> Check the `.node-version` file in the root of this repo so see what version of Node.js is required for local development - note, this can be different from the version of Node.js which runs the Action on GitHub runners. It is suggested to download [nodenv](https://github.com/nodenv/nodenv) which uses this file and manages your Node.js versions for you
1. Fork this repository
2. Make your changes
3. [Test](#testing-) your changes locally
4. Before opening a pull request, please run `npm run all` to verify formatting, linting, tests, generated files, etc.
5. Commit and push your changes to your fork
6. Open a pull request back to this repository
7. Wait for an approval or changes requested from the maintainers of this repository
After merging the pull request, the maintainers of this repository will create a new release with those changes included. After that, everyone can utilize the newly integrated changes in their own Actions workflows and enjoy your awesome improvements!
## Testing 🧪
### Running the test suite (required)
Simply run the following command to execute the entire test suite:
```bash
npm test
```
> Note: This requires that you have already run `npm install`.

View File

@@ -1,8 +1,10 @@
# deploy-pages 🚀 # deploy-pages
[![Release](https://img.shields.io/github/v/release/actions/deploy-pages?label=Release&logo=github)](https://github.com/actions/deploy-pages/releases/latest) [![Linting](https://img.shields.io/github/actions/workflow/status/actions/deploy-pages/check-linter.yml?label=Linting&logo=github)](https://github.com/actions/deploy-pages/actions/workflows/check-linter.yml) [![Formatting](https://img.shields.io/github/actions/workflow/status/actions/deploy-pages/check-formatting.yml?label=Formatting&logo=github)](https://github.com/actions/deploy-pages/actions/workflows/check-formatting.yml) [![Tests](https://img.shields.io/github/actions/workflow/status/actions/deploy-pages/test.yml?label=Tests&logo=github)](https://github.com/actions/deploy-pages/actions/workflows/test.yml) ![Coverage](./coverage_badge.svg) [![Distributables](https://img.shields.io/github/actions/workflow/status/actions/deploy-pages/check-dist.yml?label=Distributables&logo=github)](https://github.com/actions/deploy-pages/actions/workflows/check-dist.yml) [![CodeQL](https://img.shields.io/github/actions/workflow/status/actions/deploy-pages/codeql-analysis.yml?label=CodeQL&logo=github)](https://github.com/actions/deploy-pages/actions/workflows/codeql-analysis.yml) This action is used to deploy [Actions artifacts][artifacts] to GitHub Pages.
This action is used to deploy [Actions artifacts][artifacts] to [GitHub Pages](https://pages.github.com/). ## Scope
⚠️ Official support for building Pages with Actions is in public beta at the moment.
## Usage ## Usage
@@ -10,7 +12,7 @@ See [action.yml](action.yml) for the various `inputs` this action supports.
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 expects an artifact named `github-pages` to have been created prior to execution. This is done automatically 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,37 +43,10 @@ jobs:
steps: steps:
- name: Deploy to GitHub Pages - name: Deploy to GitHub Pages
id: deployment id: deployment
uses: actions/deploy-pages@v2 # or the latest "vX.X.X" version tag for this action uses: actions/deploy-pages@v1
``` ```
### Inputs 📥 ## Security considerations
| Input | Required? | Default | Description |
| ----- | --------- | ------- | ----------- |
| `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"` | Time in milliseconds between two deployment status report (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!) |
### Outputs 📤
| Output | Description |
| ------ | ----------- |
| `page_url` | The URL of the deployed Pages site |
### Environment Variables 🌎
| Variable | Description |
| -------- | ----------- |
| `GITHUB_PAGES` | This environment variable is created and set to the string value `"true"` so that framework build tools may choose to differentiate their output based on the intended target hosting platform. |
## Scope
⚠️ Official support for building Pages with Actions is in public beta at the moment.
## Security Considerations
There are a few important considerations to be aware of: There are a few important considerations to be aware of:
@@ -85,9 +60,9 @@ There are a few important considerations to be aware of:
4. If your Pages site is using a source branch, the deployment must originate from this source branch unless [your environment is protected][environment-protection] in which case the environment protection rules take precedence over the source branch rule 4. If your Pages site is using a source branch, the deployment must originate from this source branch unless [your environment is protected][environment-protection] in which case the environment protection rules take precedence over the source branch rule
5. If your Pages site is using GitHub Actions as the source, while not required we highly recommend you also [protect your environment][environment-protection] (we will configure it by default for you). 5. If your Pages site is using GitHub Actions as the source, while not required we highly recommend you also [protect your environment][environment-protection] (we do it by default for you)
## Release Instructions # Release instructions
In order to release a new version of this Action: In order to release a new version of this Action:

View File

@@ -5,6 +5,15 @@ runs:
using: 'node16' using: 'node16'
main: 'dist/index.js' main: 'dist/index.js'
inputs: inputs:
emit_telemetry:
deprecationMessage: 'Use of this input causes the action to do nothing. You should remove this build step from your workflow.'
description: 'Should this action only emit build telemetry instead of deploying the build artifact?'
required: false
default: 'false'
conclusion:
deprecationMessage: 'Use of this input does nothing as it was part of the deprecated `emit_telemetry` flow. You should remove this parameter from your workflow.'
description: 'The status of the previous build.'
required: false
token: token:
description: 'GitHub token' description: 'GitHub token'
default: ${{ github.token }} default: ${{ github.token }}

View File

@@ -1 +0,0 @@
<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: 73.13%"><title>Coverage: 73.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="#e05d44"/><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">73.13%</text><text x="885" y="140" transform="scale(.1)" fill="#fff" textLength="430">73.13%</text></g></svg>

Before

Width:  |  Height:  |  Size: 1.1 KiB

204
dist/index.js vendored

File diff suppressed because one or more lines are too long

2
dist/index.js.map vendored

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

2612
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
{ {
"name": "deploy-pages", "name": "deploy-pages",
"version": "0.0.0", "version": "0.0.1",
"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": {
@@ -11,18 +11,16 @@
"http-status-messages": "^1.1.0" "http-status-messages": "^1.1.0"
}, },
"devDependencies": { "devDependencies": {
"@vercel/ncc": "^0.36.1", "@vercel/ncc": "^0.31.1",
"eslint": "^8.36.0", "eslint": "^8.36.0",
"eslint-config-prettier": "^8.8.0", "eslint-config-prettier": "^8.7.0",
"eslint-plugin-github": "^4.7.0", "eslint-plugin-github": "^4.6.1",
"jest": "^29.5.0", "jest": "^29.5.0",
"nock": "^13.3.0", "nock": "^13.3.0",
"prettier": "^2.8.7", "prettier": "^2.8.4"
"make-coverage-badge": "^1.2.0"
}, },
"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",
"coverage-badge": "make-coverage-badge --output-path ./coverage_badge.svg",
"format": "prettier --write .", "format": "prettier --write .",
"format:check": "prettier --check .", "format:check": "prettier --check .",
"lint": "DEBUG=eslint:cli-engine eslint --fix .", "lint": "DEBUG=eslint:cli-engine eslint --fix .",
@@ -43,22 +41,5 @@
"bugs": { "bugs": {
"url": "https://github.com/actions/deploy-pages/issues" "url": "https://github.com/actions/deploy-pages/issues"
}, },
"homepage": "https://github.com/actions/deploy-pages#readme", "homepage": "https://github.com/actions/deploy-pages#readme"
"jest": {
"coverageReporters": [
"json-summary",
"text",
"lcov"
],
"collectCoverage": true,
"collectCoverageFrom": [
"./src/**"
],
"coverageThreshold": {
"global": {
"lines": 70,
"statements": 70
}
}
}
} }

View File

@@ -1,38 +0,0 @@
const process = require('process')
const cp = require('child_process')
const path = require('path')
describe('with all environment variables set', () => {
beforeEach(() => {
process.env.ACTIONS_RUNTIME_URL = 'http://my-url'
process.env.GITHUB_RUN_ID = '123'
process.env.ACTIONS_RUNTIME_TOKEN = 'a-token'
process.env.GITHUB_REPOSITORY = 'actions/is-awesome'
process.env.GITHUB_TOKEN = 'gha-token'
process.env.GITHUB_SHA = '123abc'
process.env.GITHUB_ACTOR = 'monalisa'
process.env.GITHUB_ACTION = '__monalisa/octocat'
process.env.GITHUB_ACTION_PATH = 'something'
})
it('executes cleanly', done => {
const ip = path.join(__dirname, '../index.js')
cp.exec(`node ${ip}`, { env: process.env }, (err, stdout) => {
expect(stdout).toMatch(/::debug::all variables are set/)
done()
})
})
})
describe('with variables missing', () => {
it('execution fails if there are missing variables', done => {
delete process.env.ACTIONS_RUNTIME_URL
const ip = path.join(__dirname, '../index.js')
cp.exec(`node ${ip}`, { env: process.env }, (err, stdout) => {
expect(stdout).toBe('')
expect(err).toBeTruthy()
expect(err.code).toBe(1)
done()
})
})
})

View File

@@ -113,7 +113,7 @@ async function createPagesDeployment({ githubToken, artifactUrl, buildVersion, i
core.info(`Creating Pages deployment with payload:\n${JSON.stringify(payload, null, '\t')}`) core.info(`Creating Pages deployment with payload:\n${JSON.stringify(payload, null, '\t')}`)
try { try {
const response = await octokit.request('POST /repos/{owner}/{repo}/pages/deployments', { const response = await octokit.request('POST /repos/{owner}/{repo}/pages/deployment', {
owner: github.context.repo.owner, owner: github.context.repo.owner,
repo: github.context.repo.repo, repo: github.context.repo.repo,
...payload ...payload
@@ -131,7 +131,7 @@ async function getPagesDeploymentStatus({ githubToken, deploymentId }) {
core.info('Getting Pages deployment status...') core.info('Getting Pages deployment status...')
try { try {
const response = await octokit.request('GET /repos/{owner}/{repo}/pages/deployments/{deploymentId}', { const response = await octokit.request('GET /repos/{owner}/{repo}/pages/deployment/status/{deploymentId}', {
owner: github.context.repo.owner, owner: github.context.repo.owner,
repo: github.context.repo.repo, repo: github.context.repo.repo,
deploymentId deploymentId
@@ -149,7 +149,7 @@ async function cancelPagesDeployment({ githubToken, deploymentId }) {
core.info('Canceling Pages deployment...') core.info('Canceling Pages deployment...')
try { try {
const response = await octokit.request('POST /repos/{owner}/{repo}/pages/deployments/{deploymentId}/cancel', { const response = await octokit.request('PUT /repos/{owner}/{repo}/pages/deployment/cancel/{deploymentId}', {
owner: github.context.repo.owner, owner: github.context.repo.owner,
repo: github.context.repo.repo, repo: github.context.repo.repo,
deploymentId deploymentId

View File

@@ -17,6 +17,7 @@ const temporaryErrorStatus = {
const finalErrorStatus = { const finalErrorStatus = {
deployment_failed: 'Deployment failed, try again later.', deployment_failed: 'Deployment failed, try again later.',
deployment_perms_error: 'Deployment failed. Please ensure that the file permissions are correct.',
deployment_content_failed: deployment_content_failed:
'Artifact could not be deployed. Please ensure the content does not contain any hard links, symlinks and total size is less than 10GB.', 'Artifact could not be deployed. Please ensure the content does not contain any hard links, symlinks and total size is less than 10GB.',
deployment_cancelled: 'Deployment cancelled.', deployment_cancelled: 'Deployment cancelled.',
@@ -79,9 +80,6 @@ class Deployment {
} catch (error) { } catch (error) {
core.error(error.stack) core.error(error.stack)
// output raw error in debug mode.
core.debug(JSON.stringify(error))
// 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}. `
@@ -98,7 +96,6 @@ class Deployment {
} }
throw new Error(errorMessage) throw new Error(errorMessage)
} else { } else {
// istanbul ignore next
throw error throw error
} }
} }
@@ -163,9 +160,6 @@ class Deployment {
} catch (error) { } catch (error) {
core.error(error.stack) core.error(error.stack)
// output raw error in debug mode.
core.debug(JSON.stringify(error))
// build customized error message based on server response // build customized error message based on server response
if (error.response) { if (error.response) {
errorStatus = error.status || error.response.status errorStatus = error.status || error.response.status
@@ -203,7 +197,6 @@ class Deployment {
async cancel() { async cancel() {
// Don't attempt to cancel if no deployment was created // Don't attempt to cancel if no deployment was created
if (!this.deploymentInfo || this.deploymentInfo.pending !== true) { if (!this.deploymentInfo || this.deploymentInfo.pending !== true) {
core.debug('No deployment to cancel')
return return
} }

View File

@@ -4,8 +4,8 @@
const core = require('@actions/core') const core = require('@actions/core')
const { Deployment } = require('./internal/deployment') const { Deployment } = require('./deployment')
const getContext = require('./internal/context') const getContext = require('./context')
const deployment = new Deployment() const deployment = new Deployment()
@@ -48,4 +48,9 @@ process.on('SIGINT', cancelHandler)
process.on('SIGTERM', cancelHandler) process.on('SIGTERM', cancelHandler)
// Main // Main
main() const emitTelemetry = core.getInput('emit_telemetry')
if (emitTelemetry === 'true') {
// For compatibility, treat the use of this deprecated input as a no-op
} else {
main()
}

View File

@@ -1,14 +1,51 @@
const core = require('@actions/core') const core = require('@actions/core')
const process = require('process')
const cp = require('child_process')
const path = require('path')
const nock = require('nock') const nock = require('nock')
const { Deployment } = require('../../internal/deployment') const { Deployment } = require('./deployment')
const fakeJwt = const fakeJwt =
'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiJiNjllMWIxOC1jOGFiLTRhZGQtOGYxOC03MzVlMzVjZGJhZjAiLCJzdWIiOiJyZXBvOnBhcGVyLXNwYS9taW55aTplbnZpcm9ubWVudDpQcm9kdWN0aW9uIiwiYXVkIjoiaHR0cHM6Ly9naXRodWIuY29tL3BhcGVyLXNwYSIsInJlZiI6InJlZnMvaGVhZHMvbWFpbiIsInNoYSI6ImEyODU1MWJmODdiZDk3NTFiMzdiMmM0YjM3M2MxZjU3NjFmYWM2MjYiLCJyZXBvc2l0b3J5IjoicGFwZXItc3BhL21pbnlpIiwicmVwb3NpdG9yeV9vd25lciI6InBhcGVyLXNwYSIsInJ1bl9pZCI6IjE1NDY0NTkzNjQiLCJydW5fbnVtYmVyIjoiMzQiLCJydW5fYXR0ZW1wdCI6IjIiLCJhY3RvciI6IllpTXlzdHkiLCJ3b3JrZmxvdyI6IkNJIiwiaGVhZF9yZWYiOiIiLCJiYXNlX3JlZiI6IiIsImV2ZW50X25hbWUiOiJwdXNoIiwicmVmX3R5cGUiOiJicmFuY2giLCJlbnZpcm9ubWVudCI6IlByb2R1Y3Rpb24iLCJqb2Jfd29ya2Zsb3dfcmVmIjoicGFwZXItc3BhL21pbnlpLy5naXRodWIvd29ya2Zsb3dzL2JsYW5rLnltbEByZWZzL2hlYWRzL21haW4iLCJpc3MiOiJodHRwczovL3Rva2VuLmFjdGlvbnMuZ2l0aHVidXNlcmNvbnRlbnQuY29tIiwibmJmIjoxNjM4ODI4MDI4LCJleHAiOjE2Mzg4Mjg5MjgsImlhdCI6MTYzODgyODYyOH0.1wyupfxu1HGoTyIqatYg0hIxy2-0bMO-yVlmLSMuu2w' 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiJiNjllMWIxOC1jOGFiLTRhZGQtOGYxOC03MzVlMzVjZGJhZjAiLCJzdWIiOiJyZXBvOnBhcGVyLXNwYS9taW55aTplbnZpcm9ubWVudDpQcm9kdWN0aW9uIiwiYXVkIjoiaHR0cHM6Ly9naXRodWIuY29tL3BhcGVyLXNwYSIsInJlZiI6InJlZnMvaGVhZHMvbWFpbiIsInNoYSI6ImEyODU1MWJmODdiZDk3NTFiMzdiMmM0YjM3M2MxZjU3NjFmYWM2MjYiLCJyZXBvc2l0b3J5IjoicGFwZXItc3BhL21pbnlpIiwicmVwb3NpdG9yeV9vd25lciI6InBhcGVyLXNwYSIsInJ1bl9pZCI6IjE1NDY0NTkzNjQiLCJydW5fbnVtYmVyIjoiMzQiLCJydW5fYXR0ZW1wdCI6IjIiLCJhY3RvciI6IllpTXlzdHkiLCJ3b3JrZmxvdyI6IkNJIiwiaGVhZF9yZWYiOiIiLCJiYXNlX3JlZiI6IiIsImV2ZW50X25hbWUiOiJwdXNoIiwicmVmX3R5cGUiOiJicmFuY2giLCJlbnZpcm9ubWVudCI6IlByb2R1Y3Rpb24iLCJqb2Jfd29ya2Zsb3dfcmVmIjoicGFwZXItc3BhL21pbnlpLy5naXRodWIvd29ya2Zsb3dzL2JsYW5rLnltbEByZWZzL2hlYWRzL21haW4iLCJpc3MiOiJodHRwczovL3Rva2VuLmFjdGlvbnMuZ2l0aHVidXNlcmNvbnRlbnQuY29tIiwibmJmIjoxNjM4ODI4MDI4LCJleHAiOjE2Mzg4Mjg5MjgsImlhdCI6MTYzODgyODYyOH0.1wyupfxu1HGoTyIqatYg0hIxy2-0bMO-yVlmLSMuu2w'
describe('with all environment variables set', () => {
beforeEach(() => {
process.env.ACTIONS_RUNTIME_URL = 'http://my-url'
process.env.GITHUB_RUN_ID = '123'
process.env.ACTIONS_RUNTIME_TOKEN = 'a-token'
process.env.GITHUB_REPOSITORY = 'actions/is-awesome'
process.env.GITHUB_TOKEN = 'gha-token'
process.env.GITHUB_SHA = '123abc'
process.env.GITHUB_ACTOR = 'monalisa'
process.env.GITHUB_ACTION = '__monalisa/octocat'
process.env.GITHUB_ACTION_PATH = 'something'
})
it('executes cleanly', done => {
const ip = path.join(__dirname, './index.js')
cp.exec(`node ${ip}`, { env: process.env }, (err, stdout) => {
expect(stdout).toMatch(/::debug::all variables are set/)
done()
})
})
})
describe('with variables missing', () => {
it('execution fails if there are missing variables', done => {
delete process.env.ACTIONS_RUNTIME_URL
const ip = path.join(__dirname, './index.js')
cp.exec(`node ${ip}`, { env: process.env }, (err, stdout) => {
expect(stdout).toBe('')
expect(err).toBeTruthy()
expect(err.code).toBe(1)
done()
})
})
})
describe('Deployment', () => { describe('Deployment', () => {
beforeEach(() => { beforeEach(() => {
jest.clearAllMocks()
process.env.ACTIONS_RUNTIME_URL = 'http://my-url/' 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.ACTIONS_RUNTIME_TOKEN = 'a-token'
@@ -63,13 +100,13 @@ describe('Deployment', () => {
}) })
const createDeploymentScope = nock('https://api.github.com') const createDeploymentScope = nock('https://api.github.com')
.post(`/repos/${process.env.GITHUB_REPOSITORY}/pages/deployments`, { .post(`/repos/${process.env.GITHUB_REPOSITORY}/pages/deployment`, {
artifact_url: 'https://fake-artifact.com&%24expand=SignedContent', artifact_url: 'https://fake-artifact.com&%24expand=SignedContent',
pages_build_version: process.env.GITHUB_SHA, pages_build_version: process.env.GITHUB_SHA,
oidc_token: fakeJwt oidc_token: fakeJwt
}) })
.reply(200, { .reply(200, {
status_url: `https://api.github.com/repos/${process.env.GITHUB_REPOSITORY}/pages/deployments/${process.env.GITHUB_SHA}`, status_url: `https://api.github.com/repos/${process.env.GITHUB_REPOSITORY}/pages/deployment/status/${process.env.GITHUB_SHA}`,
page_url: 'https://actions.github.io/is-awesome' page_url: 'https://actions.github.io/is-awesome'
}) })
@@ -101,14 +138,14 @@ describe('Deployment', () => {
}) })
const createDeploymentScope = nock('https://api.github.com') const createDeploymentScope = nock('https://api.github.com')
.post(`/repos/${process.env.GITHUB_REPOSITORY}/pages/deployments`, { .post(`/repos/${process.env.GITHUB_REPOSITORY}/pages/deployment`, {
artifact_url: 'https://fake-artifact.com&%24expand=SignedContent', artifact_url: 'https://fake-artifact.com&%24expand=SignedContent',
pages_build_version: process.env.GITHUB_SHA, pages_build_version: process.env.GITHUB_SHA,
oidc_token: fakeJwt, oidc_token: fakeJwt,
preview: true preview: true
}) })
.reply(200, { .reply(200, {
status_url: `https://api.github.com/repos/${process.env.GITHUB_REPOSITORY}/pages/deployments/${process.env.GITHUB_SHA}`, status_url: `https://api.github.com/repos/${process.env.GITHUB_REPOSITORY}/pages/deployment/status/${process.env.GITHUB_SHA}`,
page_url: 'https://actions.github.io/is-awesome', page_url: 'https://actions.github.io/is-awesome',
preview_url: 'https://actions.drafts.github.io/is-awesome' preview_url: 'https://actions.drafts.github.io/is-awesome'
}) })
@@ -148,81 +185,6 @@ describe('Deployment', () => {
artifactExchangeScope.done() artifactExchangeScope.done()
}) })
it('reports errors with a failed 500 in a deployment', async () => {
process.env.GITHUB_SHA = 'build-version'
const artifactExchangeScope = nock(`http://my-url`)
.get('/_apis/pipelines/workflows/123/artifacts?api-version=6.0-preview')
.reply(200, { value: [{ url: 'https://invalid-artifact.com', name: 'github-pages' }] })
const createDeploymentScope = nock('https://api.github.com')
.post(`/repos/${process.env.GITHUB_REPOSITORY}/pages/deployments`, {
artifact_url: 'https://invalid-artifact.com&%24expand=SignedContent',
pages_build_version: process.env.GITHUB_SHA
})
.reply(500, { message: 'oh no' })
// Create the deployment
const deployment = new Deployment()
await expect(deployment.create()).rejects.toEqual(
new Error(
`Failed to create deployment (status: 500) with build version ${process.env.GITHUB_SHA}. Server error, is githubstatus.com reporting a Pages outage? Please re-run the deployment at a later time.`
)
)
artifactExchangeScope.done()
createDeploymentScope.done()
})
it('reports errors with an unexpected 403 during deployment', async () => {
process.env.GITHUB_SHA = 'build-version'
const artifactExchangeScope = nock(`http://my-url`)
.get('/_apis/pipelines/workflows/123/artifacts?api-version=6.0-preview')
.reply(200, { value: [{ url: 'https://invalid-artifact.com', name: 'github-pages' }] })
const createDeploymentScope = nock('https://api.github.com')
.post(`/repos/${process.env.GITHUB_REPOSITORY}/pages/deployments`, {
artifact_url: 'https://invalid-artifact.com&%24expand=SignedContent',
pages_build_version: process.env.GITHUB_SHA
})
.reply(403, { message: 'You are forbidden' })
// Create the deployment
const deployment = new Deployment()
await expect(deployment.create()).rejects.toEqual(
new Error(
`Failed to create deployment (status: 403) with build version ${process.env.GITHUB_SHA}. Ensure GITHUB_TOKEN has permission "pages: write".`
)
)
artifactExchangeScope.done()
createDeploymentScope.done()
})
it('reports errors with an unexpected 404 during deployment', async () => {
process.env.GITHUB_SHA = 'build-version'
const artifactExchangeScope = nock(`http://my-url`)
.get('/_apis/pipelines/workflows/123/artifacts?api-version=6.0-preview')
.reply(200, { value: [{ url: 'https://invalid-artifact.com', name: 'github-pages' }] })
const createDeploymentScope = nock('https://api.github.com')
.post(`/repos/${process.env.GITHUB_REPOSITORY}/pages/deployments`, {
artifact_url: 'https://invalid-artifact.com&%24expand=SignedContent',
pages_build_version: process.env.GITHUB_SHA
})
.reply(404, { message: 'Not found' })
// Create the deployment
const deployment = new Deployment()
await expect(deployment.create()).rejects.toEqual(
new Error(
`Failed to create deployment (status: 404) with build version ${process.env.GITHUB_SHA}. Ensure GitHub Pages has been enabled: https://github.com/actions/is-awesome/settings/pages`
)
)
artifactExchangeScope.done()
createDeploymentScope.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 artifactExchangeScope = nock(`http://my-url`)
@@ -230,7 +192,7 @@ describe('Deployment', () => {
.reply(200, { value: [{ url: 'https://invalid-artifact.com', name: 'github-pages' }] }) .reply(200, { value: [{ url: 'https://invalid-artifact.com', name: 'github-pages' }] })
const createDeploymentScope = nock('https://api.github.com') const createDeploymentScope = nock('https://api.github.com')
.post(`/repos/${process.env.GITHUB_REPOSITORY}/pages/deployments`, { .post(`/repos/${process.env.GITHUB_REPOSITORY}/pages/deployment`, {
artifact_url: 'https://invalid-artifact.com&%24expand=SignedContent', artifact_url: 'https://invalid-artifact.com&%24expand=SignedContent',
pages_build_version: process.env.GITHUB_SHA pages_build_version: process.env.GITHUB_SHA
}) })
@@ -263,18 +225,18 @@ describe('Deployment', () => {
}) })
const createDeploymentScope = nock('https://api.github.com') const createDeploymentScope = nock('https://api.github.com')
.post(`/repos/${process.env.GITHUB_REPOSITORY}/pages/deployments`, { .post(`/repos/${process.env.GITHUB_REPOSITORY}/pages/deployment`, {
artifact_url: 'https://fake-artifact.com&%24expand=SignedContent', artifact_url: 'https://fake-artifact.com&%24expand=SignedContent',
pages_build_version: process.env.GITHUB_SHA, pages_build_version: process.env.GITHUB_SHA,
oidc_token: fakeJwt oidc_token: fakeJwt
}) })
.reply(200, { .reply(200, {
status_url: `https://api.github.com/repos/${process.env.GITHUB_REPOSITORY}/pages/deployments/${process.env.GITHUB_SHA}`, status_url: `https://api.github.com/repos/${process.env.GITHUB_REPOSITORY}/pages/deployment/status/${process.env.GITHUB_SHA}`,
page_url: 'https://actions.github.io/is-awesome' page_url: 'https://actions.github.io/is-awesome'
}) })
const deploymentStatusScope = nock('https://api.github.com') const deploymentStatusScope = nock('https://api.github.com')
.get(`/repos/${process.env.GITHUB_REPOSITORY}/pages/deployments/${process.env.GITHUB_SHA}`) .get(`/repos/${process.env.GITHUB_REPOSITORY}/pages/deployment/status/${process.env.GITHUB_SHA}`)
.reply(200, { .reply(200, {
status: 'succeed' status: 'succeed'
}) })
@@ -301,56 +263,6 @@ describe('Deployment', () => {
createDeploymentScope.done() createDeploymentScope.done()
deploymentStatusScope.done() deploymentStatusScope.done()
}) })
it('fails check when no deployment is found', async () => {
process.env.GITHUB_SHA = 'valid-build-version'
const deployment = new Deployment()
await deployment.check()
expect(core.setFailed).toBeCalledWith('Deployment not found.')
})
it('exits early when deployment is not in progress', async () => {
process.env.GITHUB_SHA = 'valid-build-version'
const artifactExchangeScope = nock(`http://my-url`)
.get('/_apis/pipelines/workflows/123/artifacts?api-version=6.0-preview')
.reply(200, {
value: [
{ url: 'https://another-artifact.com', name: 'another-artifact' },
{ url: 'https://fake-artifact.com', name: 'github-pages' }
]
})
const createDeploymentScope = nock('https://api.github.com')
.post(`/repos/${process.env.GITHUB_REPOSITORY}/pages/deployments`, {
artifact_url: 'https://fake-artifact.com&%24expand=SignedContent',
pages_build_version: process.env.GITHUB_SHA,
oidc_token: fakeJwt
})
.reply(200, {
status_url: `https://api.github.com/repos/${process.env.GITHUB_REPOSITORY}/pages/deployments/${process.env.GITHUB_SHA}`,
page_url: 'https://actions.github.io/is-awesome'
})
core.getIDToken = jest.fn().mockResolvedValue(fakeJwt)
core.GetInput = jest.fn(input => {
switch (input) {
case 'timeout':
return 10 * 1000
case 'reporting_interval':
return 0
}
})
const deployment = new Deployment()
await deployment.create(fakeJwt)
deployment.deploymentInfo.pending = false
await deployment.check()
expect(core.setFailed).toBeCalledWith('Unable to get deployment status.')
artifactExchangeScope.done()
createDeploymentScope.done()
})
}) })
describe('#cancel', () => { describe('#cancel', () => {
@@ -367,18 +279,18 @@ describe('Deployment', () => {
}) })
const createDeploymentScope = nock('https://api.github.com') const createDeploymentScope = nock('https://api.github.com')
.post(`/repos/${process.env.GITHUB_REPOSITORY}/pages/deployments`, { .post(`/repos/${process.env.GITHUB_REPOSITORY}/pages/deployment`, {
artifact_url: 'https://fake-artifact.com&%24expand=SignedContent', artifact_url: 'https://fake-artifact.com&%24expand=SignedContent',
pages_build_version: process.env.GITHUB_SHA, pages_build_version: process.env.GITHUB_SHA,
oidc_token: fakeJwt oidc_token: fakeJwt
}) })
.reply(200, { .reply(200, {
status_url: `https://api.github.com/repos/${process.env.GITHUB_REPOSITORY}/pages/deployments/${process.env.GITHUB_SHA}`, status_url: `https://api.github.com/repos/${process.env.GITHUB_REPOSITORY}/pages/deployment/status/${process.env.GITHUB_SHA}`,
page_url: 'https://actions.github.io/is-awesome' page_url: 'https://actions.github.io/is-awesome'
}) })
const cancelDeploymentScope = nock('https://api.github.com') const cancelDeploymentScope = nock('https://api.github.com')
.post(`/repos/${process.env.GITHUB_REPOSITORY}/pages/deployments/${process.env.GITHUB_SHA}/cancel`) .put(`/repos/${process.env.GITHUB_REPOSITORY}/pages/deployment/cancel/${process.env.GITHUB_SHA}`)
.reply(200, {}) .reply(200, {})
core.getIDToken = jest.fn().mockResolvedValue(fakeJwt) core.getIDToken = jest.fn().mockResolvedValue(fakeJwt)
@@ -396,62 +308,5 @@ describe('Deployment', () => {
createDeploymentScope.done() createDeploymentScope.done()
cancelDeploymentScope.done() cancelDeploymentScope.done()
}) })
it('can exit if a pages deployment was not created and none need to be cancelled', async () => {
process.env.GITHUB_SHA = 'valid-build-version'
// Create the deployment
const deployment = new Deployment()
// Cancel it
await deployment.cancel()
expect(core.debug).toHaveBeenCalledWith('all variables are set')
expect(core.debug).toHaveBeenCalledWith(`No deployment to cancel`)
})
it('catches an error when trying to cancel a deployment', async () => {
process.env.GITHUB_SHA = 'valid-build-version'
const artifactExchangeScope = nock(`http://my-url`)
.get('/_apis/pipelines/workflows/123/artifacts?api-version=6.0-preview')
.reply(200, {
value: [
{ url: 'https://another-artifact.com', name: 'another-artifact' },
{ url: 'https://fake-artifact.com', name: 'github-pages' }
]
})
const createDeploymentScope = nock('https://api.github.com')
.post(`/repos/${process.env.GITHUB_REPOSITORY}/pages/deployments`, {
artifact_url: 'https://fake-artifact.com&%24expand=SignedContent',
pages_build_version: process.env.GITHUB_SHA,
oidc_token: fakeJwt
})
.reply(200, {
status_url: `https://api.github.com/repos/${process.env.GITHUB_REPOSITORY}/pages/deployments/${process.env.GITHUB_SHA}`,
page_url: 'https://actions.github.io/is-awesome'
})
// nock will throw an error every time it tries to cancel the deployment
const cancelDeploymentScope = nock('https://api.github.com')
.post(`/repos/${process.env.GITHUB_REPOSITORY}/pages/deployments/${process.env.GITHUB_SHA}/cancel`)
.reply(500, {})
core.getIDToken = jest.fn().mockResolvedValue(fakeJwt)
// Create the deployment
const deployment = new Deployment()
await deployment.create(fakeJwt)
// Cancel it
await deployment.cancel()
expect(core.error).toHaveBeenCalledWith(`Canceling Pages deployment failed`, expect.anything())
artifactExchangeScope.done()
createDeploymentScope.done()
cancelDeploymentScope.done()
})
}) })
}) })