mirror of
https://github.com/actions/configure-pages.git
synced 2026-03-29 17:34:52 +00:00
Compare commits
208 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
37538b280c | ||
|
|
8d642d8eae | ||
|
|
9b8d2f4ab2 | ||
|
|
e2f34b1f92 | ||
|
|
7aebbf763e | ||
|
|
6a2b91eafe | ||
|
|
939d05ad85 | ||
|
|
0ca1df54d4 | ||
|
|
5c42783e5b | ||
|
|
13d4de8a28 | ||
|
|
5aa8bf5ac6 | ||
|
|
1d79de2fe7 | ||
|
|
5a80553d12 | ||
|
|
7eb7a15548 | ||
|
|
b8c94fdc9e | ||
|
|
9b358e73bb | ||
|
|
13e6bc7a20 | ||
|
|
3c444c051b | ||
|
|
12fd9a085c | ||
|
|
a8216d627c | ||
|
|
5992ce8fd5 | ||
|
|
c8deda3832 | ||
|
|
5d8963e8a5 | ||
|
|
529ba710d5 | ||
|
|
29e9dd5abe | ||
|
|
c450a282d7 | ||
|
|
6567d4c154 | ||
|
|
aba1aa6bab | ||
|
|
6a80311a73 | ||
|
|
380c12d4cc | ||
|
|
c5a3e1159e | ||
|
|
a069fede0c | ||
|
|
2f460cfbe0 | ||
|
|
e5c1ee9f14 | ||
|
|
7fea7010df | ||
|
|
34521f23a5 | ||
|
|
d84b27279d | ||
|
|
5650def507 | ||
|
|
0c2178e929 | ||
|
|
948e60fb96 | ||
|
|
1305a1ba92 | ||
|
|
b94e9adb36 | ||
|
|
fc8c2c4e6e | ||
|
|
e978eba337 | ||
|
|
343cb08233 | ||
|
|
f87a94c875 | ||
|
|
7eb40247a7 | ||
|
|
86f141f32d | ||
|
|
76b6a8292e | ||
|
|
8e221f24db | ||
|
|
d897860efd | ||
|
|
24270f0cca | ||
|
|
0c3c14948a | ||
|
|
b0c19d0de9 | ||
|
|
51323db177 | ||
|
|
3d9811d6e2 | ||
|
|
9c3b6344a2 | ||
|
|
97fb35057c | ||
|
|
c917d1c3cd | ||
|
|
ffa824f004 | ||
|
|
d4a76d1ee1 | ||
|
|
bd8a5da49f | ||
|
|
5cb77813a2 | ||
|
|
2094727a1b | ||
|
|
d875fa8dc1 | ||
|
|
67f329fcfd | ||
|
|
2ce6d5eaa1 | ||
|
|
bb6976f8d1 | ||
|
|
f2098a32c3 | ||
|
|
7fa35a05fd | ||
|
|
c3113876b0 | ||
|
|
af5f3c3f72 | ||
|
|
ad83b485e7 | ||
|
|
a84400a87f | ||
|
|
7a0a617c8a | ||
|
|
062df390be | ||
|
|
7619de7040 | ||
|
|
66e9ac3c2e | ||
|
|
4012a9fa87 | ||
|
|
4a12ff50fb | ||
|
|
a07391ec25 | ||
|
|
2491ca8488 | ||
|
|
875ec87ff9 | ||
|
|
4eadc891b5 | ||
|
|
c4feb8d01e | ||
|
|
1f9ca39237 | ||
|
|
1cefe6fc7c | ||
|
|
25a1ec8799 | ||
|
|
b9c4ac6c14 | ||
|
|
6e4f93b15d | ||
|
|
069c984c5e | ||
|
|
b030b061cb | ||
|
|
45efe60937 | ||
|
|
35c001ded6 | ||
|
|
27457957e6 | ||
|
|
7ec0edaa8e | ||
|
|
d48340abcd | ||
|
|
f53b57ff56 | ||
|
|
6d1d650751 | ||
|
|
61fd3a3cc1 | ||
|
|
0ec542a837 | ||
|
|
3a90973fd3 | ||
|
|
dc5b850bfd | ||
|
|
9a141972ca | ||
|
|
7d9bb68583 | ||
|
|
ec022f4ae9 | ||
|
|
f71d3d08f0 | ||
|
|
9ff7f29195 | ||
|
|
9b7553ef7f | ||
|
|
42451665cc | ||
|
|
adc528a6d8 | ||
|
|
789c331a21 | ||
|
|
ff1182a56a | ||
|
|
c872edcdfb | ||
|
|
c61e34fb27 | ||
|
|
a220556ffe | ||
|
|
491169de17 | ||
|
|
f19391002a | ||
|
|
742be05113 | ||
|
|
90b7c04b80 | ||
|
|
15f519fab9 | ||
|
|
f5b4063a62 | ||
|
|
d06799dbbe | ||
|
|
fad78054b6 | ||
|
|
64fa685553 | ||
|
|
891eba7f6e | ||
|
|
9f6ed02477 | ||
|
|
68595d0746 | ||
|
|
4f27d51853 | ||
|
|
1395534a78 | ||
|
|
7c3932ff89 | ||
|
|
404d23c4a6 | ||
|
|
06406d74b2 | ||
|
|
cc95980c79 | ||
|
|
4f84ed2a14 | ||
|
|
f19d25133d | ||
|
|
f24e879a69 | ||
|
|
da85ca493f | ||
|
|
d949e1515f | ||
|
|
c69bbc2c2c | ||
|
|
8441c1b1dc | ||
|
|
4036d0f035 | ||
|
|
5c1535b807 | ||
|
|
e22fa7ebed | ||
|
|
635cafe472 | ||
|
|
7c6340377c | ||
|
|
542786ddbc | ||
|
|
c4a801b850 | ||
|
|
fcc627b194 | ||
|
|
2fc7b604aa | ||
|
|
bcfa2c863c | ||
|
|
c95cb0d322 | ||
|
|
d2f9056bbc | ||
|
|
b619d6bb2a | ||
|
|
1f779755f8 | ||
|
|
bce63914b1 | ||
|
|
0a94d4c3bb | ||
|
|
d868d5fe4e | ||
|
|
d8dd1327a1 | ||
|
|
2a2b0fadb6 | ||
|
|
e2ea66d572 | ||
|
|
55225928a1 | ||
|
|
62a7d4f2dc | ||
|
|
929a1c7425 | ||
|
|
17536ca11a | ||
|
|
d801b818b5 | ||
|
|
fc0fb71264 | ||
|
|
af945d6133 | ||
|
|
b2561d383d | ||
|
|
bb42d7b1cb | ||
|
|
0455a16aca | ||
|
|
677bce1797 | ||
|
|
49843a9170 | ||
|
|
86288138eb | ||
|
|
98aa330a29 | ||
|
|
e993237306 | ||
|
|
1fb9ba6653 | ||
|
|
1457a09e2b | ||
|
|
3480141499 | ||
|
|
8981dbcb59 | ||
|
|
7875e4af8a | ||
|
|
844ceaff5a | ||
|
|
398adf731a | ||
|
|
dddd39c6b9 | ||
|
|
084dc5123d | ||
|
|
3d51fe705a | ||
|
|
3d2f0e5994 | ||
|
|
ad121920a0 | ||
|
|
53eec1a8cc | ||
|
|
69fea3d62e | ||
|
|
05829a2e3d | ||
|
|
33fad13833 | ||
|
|
931e155079 | ||
|
|
250c4fb989 | ||
|
|
a774891038 | ||
|
|
5941f86157 | ||
|
|
8f29fe2748 | ||
|
|
ba4576e776 | ||
|
|
43a5456c3f | ||
|
|
2d3e762f19 | ||
|
|
f830cbcb66 | ||
|
|
3efd613ed2 | ||
|
|
cf1ab90e59 | ||
|
|
e2bf7f26fb | ||
|
|
df54bc901b | ||
|
|
61e591d3b5 | ||
|
|
bfe36bc062 | ||
|
|
cb174c0f85 |
17
.eslintrc.json
Normal file
17
.eslintrc.json
Normal file
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"env": {
|
||||
"commonjs": true,
|
||||
"es2021": true,
|
||||
"node": true,
|
||||
"jest": true
|
||||
},
|
||||
"plugins": ["github"],
|
||||
"extends": ["eslint:recommended", "prettier", "plugin:github/internal"],
|
||||
"parserOptions": {
|
||||
"ecmaVersion": 12
|
||||
},
|
||||
"rules": {
|
||||
"semi": ["error", "never"]
|
||||
},
|
||||
"ignorePatterns": ["/dist/", "/src/fixtures/", "/src/blank-configurations/"]
|
||||
}
|
||||
11
.github/dependabot.yml
vendored
Normal file
11
.github/dependabot.yml
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: 'github-actions'
|
||||
directory: '/'
|
||||
schedule:
|
||||
interval: 'weekly'
|
||||
|
||||
- package-ecosystem: 'npm'
|
||||
directory: '/'
|
||||
schedule:
|
||||
interval: 'weekly'
|
||||
42
.github/release-drafter.yml
vendored
42
.github/release-drafter.yml
vendored
@@ -1,6 +1,6 @@
|
||||
---
|
||||
name-template: "v$RESOLVED_VERSION"
|
||||
tag-template: "v$RESOLVED_VERSION"
|
||||
name-template: 'v$RESOLVED_VERSION'
|
||||
tag-template: 'v$RESOLVED_VERSION'
|
||||
template: |
|
||||
# Changelog
|
||||
|
||||
@@ -8,33 +8,33 @@ template: |
|
||||
|
||||
See details of [all code changes](https://github.com/$OWNER/$REPOSITORY/compare/$PREVIOUS_TAG...v$RESOLVED_VERSION) since previous release.
|
||||
categories:
|
||||
- title: "🚀 Features"
|
||||
- title: '🚀 Features'
|
||||
labels:
|
||||
- "feature"
|
||||
- "enhancement"
|
||||
- title: "🐛 Bug Fixes"
|
||||
- 'feature'
|
||||
- 'enhancement'
|
||||
- title: '🐛 Bug Fixes'
|
||||
labels:
|
||||
- "fix"
|
||||
- "bugfix"
|
||||
- "bug"
|
||||
- title: "🧰 Maintenance"
|
||||
- 'fix'
|
||||
- 'bugfix'
|
||||
- 'bug'
|
||||
- title: '🧰 Maintenance'
|
||||
labels:
|
||||
- "infrastructure"
|
||||
- "automation"
|
||||
- "documentation"
|
||||
- title: "🏎 Performance"
|
||||
label: "performance"
|
||||
change-template: "- $TITLE @$AUTHOR (#$NUMBER)"
|
||||
- 'infrastructure'
|
||||
- 'automation'
|
||||
- 'documentation'
|
||||
- title: '🏎 Performance'
|
||||
label: 'performance'
|
||||
change-template: '- $TITLE @$AUTHOR (#$NUMBER)'
|
||||
version-resolver:
|
||||
major:
|
||||
labels:
|
||||
- "type: breaking"
|
||||
- 'type: breaking'
|
||||
minor:
|
||||
labels:
|
||||
- "type: enhancement"
|
||||
- 'type: enhancement'
|
||||
patch:
|
||||
labels:
|
||||
- "type: bug"
|
||||
- "type: maintenance"
|
||||
- "type: documentation"
|
||||
- 'type: bug'
|
||||
- 'type: maintenance'
|
||||
- 'type: documentation'
|
||||
default: patch
|
||||
|
||||
52
.github/workflows/check-dist.yml
vendored
Normal file
52
.github/workflows/check-dist.yml
vendored
Normal file
@@ -0,0 +1,52 @@
|
||||
# When you reference this Action with `uses:` in a workflow,
|
||||
# `dist/index.js` is the code that will run.
|
||||
# For our project, we generate this file using `ncc`.
|
||||
# We need to make sure the checked-in `dist/index.js` actually matches what we expect it to be.
|
||||
name: Check dist/
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
paths-ignore:
|
||||
- '**.md'
|
||||
pull_request:
|
||||
paths-ignore:
|
||||
- '**.md'
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
# This allows a subsequently queued workflow run to interrupt previous runs
|
||||
concurrency:
|
||||
group: '${{ github.workflow }} @ ${{ github.event.pull_request.head.label || github.head_ref || github.ref }}'
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
check-dist:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 16.x
|
||||
cache: 'npm'
|
||||
|
||||
- name: Install dependencies
|
||||
run: npm ci
|
||||
|
||||
- name: Rebuild the dist/ directory
|
||||
run: npm run prepare
|
||||
|
||||
- name: Compare the expected and actual dist/ directories
|
||||
run: |
|
||||
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:"
|
||||
git diff
|
||||
exit 1
|
||||
fi
|
||||
35
.github/workflows/check-formatting.yml
vendored
Normal file
35
.github/workflows/check-formatting.yml
vendored
Normal file
@@ -0,0 +1,35 @@
|
||||
name: Check formatting
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
pull_request:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
# This allows a subsequently queued workflow run to interrupt previous runs
|
||||
concurrency:
|
||||
group: '${{ github.workflow }} @ ${{ github.event.pull_request.head.label || github.head_ref || github.ref }}'
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 2
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Setup Node
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 16.x
|
||||
cache: 'npm'
|
||||
|
||||
- name: Install dependencies
|
||||
run: npm ci
|
||||
|
||||
- name: Verify formatting
|
||||
run: npm run format:check
|
||||
5
.github/workflows/draft-release.yml
vendored
5
.github/workflows/draft-release.yml
vendored
@@ -4,11 +4,14 @@ on:
|
||||
branches:
|
||||
- main
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
jobs:
|
||||
draft-release:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
- uses: release-drafter/release-drafter@v5
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
35
.github/workflows/lint.yml
vendored
Normal file
35
.github/workflows/lint.yml
vendored
Normal file
@@ -0,0 +1,35 @@
|
||||
name: Lint code
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
pull_request:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
# This allows a subsequently queued workflow run to interrupt previous runs
|
||||
concurrency:
|
||||
group: '${{ github.workflow }} @ ${{ github.event.pull_request.head.label || github.head_ref || github.ref }}'
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
lint:
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 2
|
||||
steps:
|
||||
- name: Check out repo
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Setup Node
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 16.x
|
||||
cache: npm
|
||||
|
||||
- name: Install dependencies
|
||||
run: npm ci
|
||||
|
||||
- name: Run linter
|
||||
run: npm run lint:check
|
||||
6
.github/workflows/release.yml
vendored
6
.github/workflows/release.yml
vendored
@@ -1,11 +1,11 @@
|
||||
name: Release
|
||||
on:
|
||||
release:
|
||||
types: [edited]
|
||||
types: [released]
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
TAG_NAME:
|
||||
description: "Tag name that the major tag will point to"
|
||||
description: 'Tag name that the major tag will point to'
|
||||
required: true
|
||||
|
||||
env:
|
||||
@@ -24,7 +24,7 @@ jobs:
|
||||
steps:
|
||||
- name: Update the ${{ env.TAG_NAME }} tag
|
||||
id: update-major-tag
|
||||
uses: actions/publish-action@v0.1.0
|
||||
uses: actions/publish-action@v0.2.2
|
||||
with:
|
||||
source-tag: ${{ env.TAG_NAME }}
|
||||
slack-webhook: ${{ secrets.SLACK_WEBHOOK }}
|
||||
|
||||
31
.github/workflows/test.yml
vendored
31
.github/workflows/test.yml
vendored
@@ -6,20 +6,29 @@ on:
|
||||
- main
|
||||
pull_request:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
# This allows a subsequently queued workflow run to interrupt previous runs
|
||||
concurrency:
|
||||
group: '${{ github.workflow }} @ ${{ github.event.pull_request.head.label || github.head_ref || github.ref }}'
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Set Node.JS
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 16.x
|
||||
- name: Setup Node.JS
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 16.x
|
||||
cache: 'npm'
|
||||
|
||||
- name: Install dependencies
|
||||
run: npm ci
|
||||
|
||||
- name: Run tests
|
||||
run: npm test
|
||||
- name: Install dependencies
|
||||
run: npm ci
|
||||
|
||||
- name: Run tests
|
||||
run: npm test
|
||||
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,4 +1,5 @@
|
||||
node_modules/
|
||||
/src/fixtures/tmp
|
||||
|
||||
# Editors
|
||||
.vscode/
|
||||
|
||||
5
.prettierignore
Normal file
5
.prettierignore
Normal file
@@ -0,0 +1,5 @@
|
||||
# Ignore build artifacts
|
||||
/dist/
|
||||
|
||||
# Ignore all Markdown files
|
||||
*.md
|
||||
10
.prettierrc.yml
Normal file
10
.prettierrc.yml
Normal file
@@ -0,0 +1,10 @@
|
||||
# Prettier (formatter) configuration
|
||||
---
|
||||
printWidth: 120
|
||||
tabWidth: 2
|
||||
useTabs: false
|
||||
semi: false
|
||||
singleQuote: true
|
||||
trailingComma: none
|
||||
bracketSpacing: true
|
||||
arrowParens: avoid
|
||||
23
README.md
23
README.md
@@ -1,6 +1,8 @@
|
||||
# Configure-Pages
|
||||
# configure-pages
|
||||
|
||||
An action to enable Pages and extract various metadata about a site. It can also be used to configure various static site generators we support as [starter workflows][starter-workflows].
|
||||
A GitHub Action to enable Pages and extract various metadata about a site. It can also be used to configure various static site generators we support as [starter workflows][starter-workflows].
|
||||
|
||||
See [`set-pages-config.js`](src/set-pages-config.js) for more details on how we configure static site generators to work "out of the box" with GitHub Pages.
|
||||
|
||||
# Usage
|
||||
|
||||
@@ -10,18 +12,13 @@ See [action.yml](action.yml) and the [Pages starter workflows][starter-workflows
|
||||
|
||||
In order to release a new version of this Action:
|
||||
|
||||
1. Locate the semantic version of the upcoming release (a draft is maintained by the [`draft-release` workflow][draft-release])
|
||||
1. Locate the semantic version of the [upcoming release][release-list] (a draft is maintained by the [`draft-release` workflow][draft-release]).
|
||||
|
||||
2. Push a matching tag, for instance for `v0.1.0`:
|
||||
2. Publish the draft release from the `main` branch with semantic version as the tag name, _with_ the checkbox to publish to the GitHub Marketplace checked. :ballot_box_with_check:
|
||||
|
||||
```bash
|
||||
git tag v0.1.0
|
||||
git push origin v0.1.0
|
||||
```
|
||||
3. After publishing the release, the [`release` workflow][release] will automatically run to create/update the corresponding the major version tag such as `v0`.
|
||||
|
||||
3. Publish the draft release (the major tag such as `v0` will be created/updated by the [`release` workflow][release])
|
||||
|
||||
⚠️ Environment approval is required.
|
||||
⚠️ Environment approval is required. Check the [Release workflow run list][release-workflow-runs].
|
||||
|
||||
# License
|
||||
|
||||
@@ -29,5 +26,7 @@ The scripts and documentation in this project are released under the [MIT Licens
|
||||
|
||||
<!-- references -->
|
||||
[starter-workflows]: https://github.com/actions/starter-workflows/tree/main/pages
|
||||
[release-list]: https://github.com/actions/configure-pages/releases
|
||||
[draft-release]: .github/workflows/draft-release.yml
|
||||
[release]: .github/workflows/release.yml
|
||||
[release]: .github/workflows/release.yml
|
||||
[release-workflow-runs]: https://github.com/actions/configure-pages/actions/workflows/release.yml
|
||||
|
||||
24
action.yml
24
action.yml
@@ -1,22 +1,30 @@
|
||||
name: "Configure Pages"
|
||||
description: "An action to enable Pages and extract various metadata about a site. It can also be used to configure various static site generators we support as starter workflows."
|
||||
name: 'Configure GitHub Pages'
|
||||
description: 'A GitHub Action to enable Pages, extract various metadata about a site, and configure some supported static site generators.'
|
||||
author: 'GitHub'
|
||||
runs:
|
||||
using: "node16"
|
||||
main: "dist/index.js"
|
||||
using: 'node16'
|
||||
main: 'dist/index.js'
|
||||
inputs:
|
||||
static_site_generator:
|
||||
description: "Optional static site generator to attempt to configure (nuxt, next or gatsby)"
|
||||
description: 'Optional static site generator to attempt to configure: "nuxt", "next", "gatsby", or "sveltekit"'
|
||||
required: false
|
||||
generator_config_file:
|
||||
description: 'Optional file path to static site generator configuration file'
|
||||
required: false
|
||||
token:
|
||||
description: "GitHub token"
|
||||
description: 'GitHub token'
|
||||
default: ${{ github.token }}
|
||||
required: true
|
||||
enablement:
|
||||
description: 'Should a Pages site be enabled for the repository if not so already? This will only work with user-to-server tokens.'
|
||||
default: 'false'
|
||||
required: false
|
||||
outputs:
|
||||
base_url:
|
||||
description: 'GitHub Pages site full base URL. Examples: "https://octocat.github.io/my-repo/", "https://octocat.github.io/", "https://www.example.com/"'
|
||||
description: 'GitHub Pages site full base URL. Examples: "https://octocat.github.io/my-repo", "https://octocat.github.io", "https://www.example.com"'
|
||||
origin:
|
||||
description: 'GitHub Pages site origin. Examples: "https://octocat.github.io", "https://www.example.com"'
|
||||
host:
|
||||
description: 'GitHub Pages site host. Examples: "octocat.github.io", "www.example.com"'
|
||||
base_path:
|
||||
description: 'GitHub Pages site full base path. Examples: "/my-repo/" or "/"'
|
||||
description: 'GitHub Pages site full base path. Examples: "/my-repo" or ""'
|
||||
|
||||
2
dist/gatsby.js
vendored
Normal file
2
dist/gatsby.js
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
// Default Pages configuration for Gatsby
|
||||
module.exports = {}
|
||||
8934
dist/index.js
vendored
8934
dist/index.js
vendored
File diff suppressed because it is too large
Load Diff
2
dist/index.js.map
vendored
2
dist/index.js.map
vendored
File diff suppressed because one or more lines are too long
63
dist/licenses.txt
vendored
63
dist/licenses.txt
vendored
@@ -110,25 +110,13 @@ SOFTWARE.
|
||||
|
||||
axios
|
||||
MIT
|
||||
Copyright (c) 2014-present Matt Zabriskie
|
||||
# Copyright (c) 2014-present Matt Zabriskie & Collaborators
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
|
||||
combined-stream
|
||||
@@ -572,22 +560,28 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
|
||||
string-format
|
||||
(WTFPL OR MIT)
|
||||
proxy-from-env
|
||||
MIT
|
||||
The MIT License
|
||||
|
||||
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
||||
Version 2, December 2004
|
||||
Copyright (C) 2016-2018 Rob Wu <rob@robwu.nl>
|
||||
|
||||
Copyright (c) 2018 David Chambers <dc@davidchambers.me>
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
Everyone is permitted to copy and distribute verbatim or modified
|
||||
copies of this license document, and changing it is allowed as long
|
||||
as the name is changed.
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. You just DO WHAT THE FUCK YOU WANT TO.
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
|
||||
supports-color
|
||||
@@ -626,3 +620,16 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
|
||||
uuid
|
||||
MIT
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2010-2020 Robert Kieffer and other contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
3
dist/next.js
vendored
Normal file
3
dist/next.js
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
// Default Pages configuration for Next
|
||||
const nextConfig = {}
|
||||
module.exports = nextConfig
|
||||
2
dist/nuxt.js
vendored
Normal file
2
dist/nuxt.js
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
// Default Pages configuration for Nuxt
|
||||
export default {}
|
||||
8
dist/sveltekit.js
vendored
Normal file
8
dist/sveltekit.js
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
// Default Pages configuration for SvelteKit
|
||||
import adapter from '@sveltejs/adapter-auto'
|
||||
|
||||
export default {
|
||||
kit: {
|
||||
adapter: adapter()
|
||||
}
|
||||
}
|
||||
6490
package-lock.json
generated
6490
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
30
package.json
30
package.json
@@ -1,31 +1,39 @@
|
||||
{
|
||||
"private": true,
|
||||
"name": "configure-pages",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "src/index.js",
|
||||
"description": "A GitHub Action to enable Pages and extract various metadata about a site. It can also be used to configure various static site generators we support as starter workflows.",
|
||||
"main": "./dist/index.js",
|
||||
"scripts": {
|
||||
"all": "npm run format && npm run lint && npm run prepare && npm run test",
|
||||
"format": "prettier --write .",
|
||||
"format:check": "prettier --check .",
|
||||
"lint": "DEBUG=eslint:cli-engine eslint --fix .",
|
||||
"lint:check": "DEBUG=eslint:cli-engine eslint .",
|
||||
"prepare": "ncc build src/index.js -o dist --source-map --license licenses.txt",
|
||||
"test": "jest"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/paper-spa/configure-pages.git"
|
||||
"url": "git+https://github.com/actions/configure-pages.git"
|
||||
},
|
||||
"author": "GitHub",
|
||||
"license": "MIT",
|
||||
"bugs": {
|
||||
"url": "https://github.com/paper-spa/configure-pages/issues"
|
||||
"url": "https://github.com/actions/configure-pages/issues"
|
||||
},
|
||||
"homepage": "https://github.com/paper-spa/configure-pages#readme",
|
||||
"homepage": "https://github.com/actions/configure-pages#readme",
|
||||
"dependencies": {
|
||||
"@actions/core": "^1.8.2",
|
||||
"axios": "^0.27.2",
|
||||
"axios-retry": "^3.2.5",
|
||||
"espree": "^9.3.2",
|
||||
"string-format": "^1.0.0"
|
||||
"@actions/core": "^1.10.0",
|
||||
"axios": "^1.3.0",
|
||||
"espree": "^9.3.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@vercel/ncc": "^0.34.0",
|
||||
"jest": "^28.1.1"
|
||||
"eslint": "^8.33.0",
|
||||
"eslint-config-prettier": "^8.6.0",
|
||||
"eslint-plugin-github": "^4.6.0",
|
||||
"jest": "^29.4.1",
|
||||
"prettier": "^2.7.1"
|
||||
}
|
||||
}
|
||||
|
||||
87
src/api-client.js
Normal file
87
src/api-client.js
Normal file
@@ -0,0 +1,87 @@
|
||||
const axios = require('axios')
|
||||
const core = require('@actions/core')
|
||||
|
||||
function getApiBaseUrl() {
|
||||
return process.env.GITHUB_API_URL || 'https://api.github.com'
|
||||
}
|
||||
|
||||
async function enablePagesSite({ repositoryNwo, githubToken }) {
|
||||
const pagesEndpoint = `${getApiBaseUrl()}/repos/${repositoryNwo}/pages`
|
||||
|
||||
try {
|
||||
const response = await axios.post(
|
||||
pagesEndpoint,
|
||||
{ build_type: 'workflow' },
|
||||
{
|
||||
headers: {
|
||||
Accept: 'application/vnd.github.v3+json',
|
||||
Authorization: `Bearer ${githubToken}`,
|
||||
'Content-type': 'application/json'
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
const pageObject = response.data
|
||||
return pageObject
|
||||
} catch (error) {
|
||||
if (error.response && error.response.status === 409) {
|
||||
return null
|
||||
}
|
||||
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
async function getPagesSite({ repositoryNwo, githubToken }) {
|
||||
const pagesEndpoint = `${getApiBaseUrl()}/repos/${repositoryNwo}/pages`
|
||||
|
||||
const response = await axios.get(pagesEndpoint, {
|
||||
headers: {
|
||||
Accept: 'application/vnd.github.v3+json',
|
||||
Authorization: `Bearer ${githubToken}`
|
||||
}
|
||||
})
|
||||
|
||||
const pageObject = response.data
|
||||
return pageObject
|
||||
}
|
||||
|
||||
async function findOrCreatePagesSite({ repositoryNwo, githubToken, enablement = true }) {
|
||||
let pageObject
|
||||
|
||||
// Try to find an existing Pages site first
|
||||
try {
|
||||
pageObject = await getPagesSite({ repositoryNwo, githubToken })
|
||||
} catch (error) {
|
||||
if (!enablement) {
|
||||
core.error('Get Pages site failed', error)
|
||||
throw error
|
||||
}
|
||||
core.warning('Get Pages site failed', error)
|
||||
}
|
||||
|
||||
if (!pageObject && enablement) {
|
||||
// Create a new Pages site if one doesn't exist
|
||||
try {
|
||||
pageObject = await enablePagesSite({ repositoryNwo, githubToken })
|
||||
} catch (error) {
|
||||
core.error('Create Pages site failed', error)
|
||||
throw error
|
||||
}
|
||||
|
||||
// This somehow implies that the Pages site was already created but initially failed to be retrieved.
|
||||
// Try one more time for this extreme edge case!
|
||||
if (pageObject == null) {
|
||||
try {
|
||||
pageObject = await getPagesSite({ repositoryNwo, githubToken })
|
||||
} catch (error) {
|
||||
core.error('Get Pages site still failed', error)
|
||||
throw error
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return pageObject
|
||||
}
|
||||
|
||||
module.exports = { findOrCreatePagesSite, enablePagesSite, getPagesSite, getApiBaseUrl }
|
||||
215
src/api-client.test.js
Normal file
215
src/api-client.test.js
Normal file
@@ -0,0 +1,215 @@
|
||||
const core = require('@actions/core')
|
||||
const axios = require('axios')
|
||||
|
||||
const apiClient = require('./api-client')
|
||||
|
||||
describe('apiClient', () => {
|
||||
const GITHUB_REPOSITORY = 'actions/is-awesome'
|
||||
const GITHUB_TOKEN = 'gha-token'
|
||||
const PAGE_OBJECT = { html_url: 'https://actions.github.io/is-awesome/' }
|
||||
|
||||
beforeEach(() => {
|
||||
jest.restoreAllMocks()
|
||||
|
||||
// Mock error/warning/info/debug
|
||||
jest.spyOn(core, 'error').mockImplementation(jest.fn())
|
||||
jest.spyOn(core, 'warning').mockImplementation(jest.fn())
|
||||
jest.spyOn(core, 'info').mockImplementation(jest.fn())
|
||||
jest.spyOn(core, 'debug').mockImplementation(jest.fn())
|
||||
})
|
||||
|
||||
describe('getApiBaseUrl', () => {
|
||||
it('returns GITHUB_API_URL environment variable when set', async () => {
|
||||
const expectedBaseUrl = 'https://api.ghe.com'
|
||||
process.env.GITHUB_API_URL = expectedBaseUrl
|
||||
const result = apiClient.getApiBaseUrl()
|
||||
delete process.env.GITHUB_API_URL
|
||||
expect(result).toEqual(expectedBaseUrl)
|
||||
})
|
||||
|
||||
it('defaults to GitHub API if GITHUB_API_URL environment variable is empty', async () => {
|
||||
process.env.GITHUB_API_URL = ''
|
||||
const result = apiClient.getApiBaseUrl()
|
||||
delete process.env.GITHUB_API_URL
|
||||
expect(result).toEqual('https://api.github.com')
|
||||
})
|
||||
|
||||
it('defaults to GitHub API if GITHUB_API_URL environment variable is not set', async () => {
|
||||
delete process.env.GITHUB_API_URL
|
||||
const result = apiClient.getApiBaseUrl()
|
||||
expect(result).toEqual('https://api.github.com')
|
||||
})
|
||||
})
|
||||
|
||||
describe('enablePagesSite', () => {
|
||||
it('makes a request to create a page', async () => {
|
||||
jest.spyOn(axios, 'post').mockImplementationOnce(() => Promise.resolve({ status: 201, data: PAGE_OBJECT }))
|
||||
|
||||
const result = await apiClient.enablePagesSite({
|
||||
repositoryNwo: GITHUB_REPOSITORY,
|
||||
githubToken: GITHUB_TOKEN
|
||||
})
|
||||
expect(result).toEqual(PAGE_OBJECT)
|
||||
})
|
||||
|
||||
it('handles a 409 response when the page already exists', async () => {
|
||||
jest.spyOn(axios, 'post').mockImplementationOnce(() => Promise.reject({ response: { status: 409 } }))
|
||||
|
||||
// Simply assert that no error is raised
|
||||
const result = await apiClient.enablePagesSite({
|
||||
repositoryNwo: GITHUB_REPOSITORY,
|
||||
githubToken: GITHUB_TOKEN
|
||||
})
|
||||
|
||||
expect(result).toBe(null)
|
||||
})
|
||||
|
||||
it('re-raises errors on failure status codes', async () => {
|
||||
jest.spyOn(axios, 'post').mockImplementationOnce(() => Promise.reject({ response: { status: 404 } }))
|
||||
|
||||
let erred = false
|
||||
try {
|
||||
await apiClient.enablePagesSite({
|
||||
repositoryNwo: GITHUB_REPOSITORY,
|
||||
githubToken: GITHUB_TOKEN
|
||||
})
|
||||
} catch (error) {
|
||||
erred = true
|
||||
expect(error.response.status).toEqual(404)
|
||||
}
|
||||
expect(erred).toBe(true)
|
||||
})
|
||||
})
|
||||
|
||||
describe('getPagesSite', () => {
|
||||
it('makes a request to get a page', async () => {
|
||||
const PAGE_OBJECT = { html_url: 'https://actions.github.io/is-awesome/' }
|
||||
jest.spyOn(axios, 'get').mockImplementationOnce(() => Promise.resolve({ status: 200, data: PAGE_OBJECT }))
|
||||
|
||||
const result = await apiClient.getPagesSite({
|
||||
repositoryNwo: GITHUB_REPOSITORY,
|
||||
githubToken: GITHUB_TOKEN
|
||||
})
|
||||
expect(result).toEqual(PAGE_OBJECT)
|
||||
})
|
||||
|
||||
it('re-raises errors on failure status codes', async () => {
|
||||
jest.spyOn(axios, 'get').mockImplementationOnce(() => Promise.reject({ response: { status: 404 } }))
|
||||
|
||||
let erred = false
|
||||
try {
|
||||
await apiClient.getPagesSite({
|
||||
repositoryNwo: GITHUB_REPOSITORY,
|
||||
githubToken: GITHUB_TOKEN
|
||||
})
|
||||
} catch (error) {
|
||||
erred = true
|
||||
expect(error.response.status).toEqual(404)
|
||||
}
|
||||
expect(erred).toBe(true)
|
||||
})
|
||||
})
|
||||
|
||||
describe('findOrCreatePagesSite', () => {
|
||||
it('does not make a request to create a page if it already exists', async () => {
|
||||
const PAGE_OBJECT = { html_url: 'https://actions.github.io/is-awesome/' }
|
||||
jest.spyOn(axios, 'get').mockImplementationOnce(() => Promise.resolve({ status: 200, data: PAGE_OBJECT }))
|
||||
jest.spyOn(axios, 'post').mockImplementationOnce(() => Promise.reject({ response: { status: 404 } }))
|
||||
|
||||
const result = await apiClient.findOrCreatePagesSite({
|
||||
repositoryNwo: GITHUB_REPOSITORY,
|
||||
githubToken: GITHUB_TOKEN
|
||||
})
|
||||
expect(result).toEqual(PAGE_OBJECT)
|
||||
expect(axios.get).toHaveBeenCalledTimes(1)
|
||||
expect(axios.post).toHaveBeenCalledTimes(0)
|
||||
})
|
||||
|
||||
it('makes request to create a page by default if it does not exist', async () => {
|
||||
const PAGE_OBJECT = { html_url: 'https://actions.github.io/is-awesome/' }
|
||||
jest.spyOn(axios, 'get').mockImplementationOnce(() => Promise.reject({ response: { status: 404 } }))
|
||||
jest.spyOn(axios, 'post').mockImplementationOnce(() => Promise.resolve({ status: 201, data: PAGE_OBJECT }))
|
||||
|
||||
const result = await apiClient.findOrCreatePagesSite({
|
||||
repositoryNwo: GITHUB_REPOSITORY,
|
||||
githubToken: GITHUB_TOKEN
|
||||
})
|
||||
expect(result).toEqual(PAGE_OBJECT)
|
||||
expect(axios.get).toHaveBeenCalledTimes(1)
|
||||
expect(axios.post).toHaveBeenCalledTimes(1)
|
||||
})
|
||||
|
||||
it('makes a request to create a page when explicitly enabled if it does not exist', async () => {
|
||||
const PAGE_OBJECT = { html_url: 'https://actions.github.io/is-awesome/' }
|
||||
jest.spyOn(axios, 'get').mockImplementationOnce(() => Promise.reject({ response: { status: 404 } }))
|
||||
jest.spyOn(axios, 'post').mockImplementationOnce(() => Promise.resolve({ status: 201, data: PAGE_OBJECT }))
|
||||
|
||||
const result = await apiClient.findOrCreatePagesSite({
|
||||
repositoryNwo: GITHUB_REPOSITORY,
|
||||
githubToken: GITHUB_TOKEN,
|
||||
enablement: true
|
||||
})
|
||||
expect(result).toEqual(PAGE_OBJECT)
|
||||
expect(axios.get).toHaveBeenCalledTimes(1)
|
||||
expect(axios.post).toHaveBeenCalledTimes(1)
|
||||
})
|
||||
|
||||
it('does not make a request to create a page when explicitly disabled even if it does not exist', async () => {
|
||||
jest.spyOn(axios, 'get').mockImplementationOnce(() => Promise.reject({ response: { status: 404 } }))
|
||||
jest.spyOn(axios, 'post').mockImplementationOnce(() => Promise.reject({ response: { status: 500 } })) // just so they both aren't 404
|
||||
|
||||
let erred = false
|
||||
try {
|
||||
await apiClient.findOrCreatePagesSite({
|
||||
repositoryNwo: GITHUB_REPOSITORY,
|
||||
githubToken: GITHUB_TOKEN,
|
||||
enablement: false
|
||||
})
|
||||
} catch (error) {
|
||||
erred = true
|
||||
// re-raised error
|
||||
expect(error.response.status).toEqual(404)
|
||||
}
|
||||
expect(erred).toBe(true)
|
||||
expect(axios.get).toHaveBeenCalledTimes(1)
|
||||
expect(axios.post).toHaveBeenCalledTimes(0)
|
||||
})
|
||||
|
||||
it('does not make a second request to get page if create fails for reason other than existence', async () => {
|
||||
jest.spyOn(axios, 'get').mockImplementationOnce(() => Promise.reject({ response: { status: 404 } }))
|
||||
jest.spyOn(axios, 'post').mockImplementationOnce(() => Promise.reject({ response: { status: 500 } })) // just so they both aren't 404
|
||||
|
||||
let erred = false
|
||||
try {
|
||||
await apiClient.findOrCreatePagesSite({
|
||||
repositoryNwo: GITHUB_REPOSITORY,
|
||||
githubToken: GITHUB_TOKEN
|
||||
})
|
||||
} catch (error) {
|
||||
erred = true
|
||||
// re-raised error
|
||||
expect(error.response.status).toEqual(500)
|
||||
}
|
||||
expect(erred).toBe(true)
|
||||
expect(axios.get).toHaveBeenCalledTimes(1)
|
||||
expect(axios.post).toHaveBeenCalledTimes(1)
|
||||
})
|
||||
|
||||
it('makes second request to get page if create fails because of existence', async () => {
|
||||
const PAGE_OBJECT = { html_url: 'https://actions.github.io/is-awesome/' }
|
||||
jest
|
||||
.spyOn(axios, 'get')
|
||||
.mockImplementationOnce(() => Promise.reject({ response: { status: 404 } }))
|
||||
.mockImplementationOnce(() => Promise.resolve({ status: 200, data: PAGE_OBJECT }))
|
||||
jest.spyOn(axios, 'post').mockImplementationOnce(() => Promise.reject({ response: { status: 409 } }))
|
||||
|
||||
const result = await apiClient.findOrCreatePagesSite({
|
||||
repositoryNwo: GITHUB_REPOSITORY,
|
||||
githubToken: GITHUB_TOKEN
|
||||
})
|
||||
expect(result).toEqual(PAGE_OBJECT)
|
||||
expect(axios.get).toHaveBeenCalledTimes(2)
|
||||
expect(axios.post).toHaveBeenCalledTimes(1)
|
||||
})
|
||||
})
|
||||
})
|
||||
2
src/blank-configurations/gatsby.js
Normal file
2
src/blank-configurations/gatsby.js
Normal file
@@ -0,0 +1,2 @@
|
||||
// Default Pages configuration for Gatsby
|
||||
module.exports = {}
|
||||
3
src/blank-configurations/next.js
Normal file
3
src/blank-configurations/next.js
Normal file
@@ -0,0 +1,3 @@
|
||||
// Default Pages configuration for Next
|
||||
const nextConfig = {}
|
||||
module.exports = nextConfig
|
||||
2
src/blank-configurations/nuxt.js
Normal file
2
src/blank-configurations/nuxt.js
Normal file
@@ -0,0 +1,2 @@
|
||||
// Default Pages configuration for Nuxt
|
||||
export default {}
|
||||
8
src/blank-configurations/sveltekit.js
Normal file
8
src/blank-configurations/sveltekit.js
Normal file
@@ -0,0 +1,8 @@
|
||||
// Default Pages configuration for SvelteKit
|
||||
import adapter from '@sveltejs/adapter-auto'
|
||||
|
||||
export default {
|
||||
kit: {
|
||||
adapter: adapter()
|
||||
}
|
||||
}
|
||||
@@ -1,156 +1,436 @@
|
||||
const fs = require("fs")
|
||||
const espree = require("espree")
|
||||
const format = require("string-format")
|
||||
const fs = require('fs')
|
||||
const espree = require('espree')
|
||||
const core = require('@actions/core')
|
||||
|
||||
// Parse the AST
|
||||
const espreeOptions = {
|
||||
ecmaVersion: 6,
|
||||
sourceType: "module",
|
||||
range: true,
|
||||
}
|
||||
/*
|
||||
Parse a JavaScript based configuration file and inject arbitrary key/value in it.
|
||||
This is used to make sure most static site generators can automatically handle
|
||||
Pages's path based routing (and work).
|
||||
|
||||
Supported configuration initializations:
|
||||
|
||||
(1) Direct default export:
|
||||
|
||||
export default {
|
||||
// configuration object here
|
||||
}
|
||||
|
||||
(2) Direct module export:
|
||||
|
||||
module.exports = {
|
||||
// configuration object here
|
||||
}
|
||||
|
||||
(3) Indirect default export:
|
||||
|
||||
const config = {
|
||||
// configuration object here
|
||||
}
|
||||
export default config
|
||||
|
||||
(4) Indirect module export:
|
||||
|
||||
const config = {
|
||||
// configuration object here
|
||||
}
|
||||
module.exports = config
|
||||
|
||||
(5) Direct default export with wrapping call:
|
||||
|
||||
export default defineConfig({
|
||||
// configuration object here
|
||||
})
|
||||
|
||||
(6) Direct module export with wrapping call:
|
||||
|
||||
module.exports = defineConfig({
|
||||
// configuration object here
|
||||
})
|
||||
|
||||
(7) Indirect default export with wrapping call at the definition:
|
||||
|
||||
const config = defineConfig({
|
||||
// configuration object here
|
||||
})
|
||||
export default config
|
||||
|
||||
(8) Indirect default export with wrapping call at the export:
|
||||
|
||||
const config = {
|
||||
// configuration object here
|
||||
}
|
||||
export default defineConfig(config)
|
||||
|
||||
(9) Indirect module export with wrapping call at the definition:
|
||||
|
||||
const config = defineConfig({
|
||||
// configuration object here
|
||||
})
|
||||
module.exports = config
|
||||
|
||||
(10) Indirect module export with wrapping call at the export:
|
||||
|
||||
const config = {
|
||||
// configuration object here
|
||||
}
|
||||
module.exports = defineConfig(config)
|
||||
*/
|
||||
|
||||
class ConfigParser {
|
||||
constructor(staticSiteConfig) {
|
||||
this.pathPropertyNuxt = `router: {\n base: '{0}'\n }`
|
||||
this.pathPropertyNext = `basePath: '{0}'`
|
||||
this.pathPropertyGatsby = `pathPrefix: '{0}'`
|
||||
this.configskeleton = `export default {\n {0}\n}`
|
||||
this.staticSiteConfig = staticSiteConfig
|
||||
this.config = fs.existsSync(this.staticSiteConfig.filePath) ? fs.readFileSync(this.staticSiteConfig.filePath, "utf8") : null
|
||||
this.validate()
|
||||
}
|
||||
// Ctor
|
||||
// - configurationFile: path to the configuration file
|
||||
// - blankConfigurationFile: a blank configuration file to use if non was previously found
|
||||
constructor({ configurationFile, blankConfigurationFile, allowWrappingCall = false, properties }) {
|
||||
// Save field
|
||||
this.configurationFile = configurationFile
|
||||
this.allowWrappingCall = allowWrappingCall === true
|
||||
this.properties = properties
|
||||
|
||||
validate() {
|
||||
if (!this.config) {
|
||||
core.info(`original raw configuration was empty:\n${this.config}`)
|
||||
core.info('Generating a default configuration to start from...')
|
||||
|
||||
// Update the `config` property with a default configuration file
|
||||
this.config = this.generateConfigFile()
|
||||
}
|
||||
}
|
||||
|
||||
generateConfigFile() {
|
||||
switch (this.staticSiteConfig.type) {
|
||||
case "nuxt":
|
||||
return format(this.configskeleton, format(this.pathPropertyNuxt, this.staticSiteConfig.newPath))
|
||||
break
|
||||
case "next":
|
||||
return format(this.configskeleton, format(this.pathPropertyNext, this.staticSiteConfig.newPath))
|
||||
break
|
||||
case "gatsby":
|
||||
return format(this.configskeleton, format(this.pathPropertyGatsby, this.staticSiteConfig.newPath))
|
||||
break
|
||||
default:
|
||||
throw "Unknown config type"
|
||||
}
|
||||
}
|
||||
|
||||
generateConfigProperty() {
|
||||
switch (this.staticSiteConfig.type) {
|
||||
case "nuxt":
|
||||
return format(this.pathPropertyNuxt, this.staticSiteConfig.newPath)
|
||||
break
|
||||
case "next":
|
||||
return format(this.pathPropertyNext, this.staticSiteConfig.newPath)
|
||||
break
|
||||
case "gatsby":
|
||||
return format(this.pathPropertyGatsby, this.staticSiteConfig.newPath)
|
||||
break
|
||||
default:
|
||||
throw "Unknown config type"
|
||||
}
|
||||
}
|
||||
|
||||
parse() {
|
||||
core.info(`original configuration:\n${this.config}`)
|
||||
const ast = espree.parse(this.config, espreeOptions);
|
||||
|
||||
// Find the default export declaration node
|
||||
var exportNode = ast.body.find(node => node.type === 'ExpressionStatement')
|
||||
if (exportNode) {
|
||||
var property = this.getPropertyModuleExport(exportNode)
|
||||
|
||||
} else {
|
||||
exportNode = ast.body.find(node => node.type === 'ExportDefaultDeclaration')
|
||||
if (!exportNode) throw "Unable to find default export"
|
||||
var property = this.getPropertyExportDefault(exportNode)
|
||||
// If the configuration file does not exist, initialize it with the blank configuration file
|
||||
if (!fs.existsSync(this.configurationFile)) {
|
||||
core.info('Using default blank configuration')
|
||||
const blankConfiguration = fs.readFileSync(blankConfigurationFile, 'utf8')
|
||||
fs.writeFileSync(this.configurationFile, blankConfiguration, {
|
||||
encoding: 'utf8'
|
||||
})
|
||||
}
|
||||
|
||||
// Read the configuration file
|
||||
this.configuration = fs.readFileSync(this.configurationFile, 'utf8')
|
||||
}
|
||||
|
||||
findTopLevelVariableDeclarator(ast, identifierName) {
|
||||
let targetDeclarator
|
||||
ast.body.find(
|
||||
node =>
|
||||
node.type === 'VariableDeclaration' &&
|
||||
node.declarations &&
|
||||
node.declarations.length > 0 &&
|
||||
node.declarations.find(declarator => {
|
||||
if (
|
||||
declarator.type === 'VariableDeclarator' &&
|
||||
declarator.id &&
|
||||
declarator.id.type === 'Identifier' &&
|
||||
declarator.id.name === identifierName
|
||||
) {
|
||||
targetDeclarator = declarator
|
||||
return true
|
||||
}
|
||||
})
|
||||
)
|
||||
return targetDeclarator
|
||||
}
|
||||
|
||||
// Find the configuration object in an AST.
|
||||
// Look for, in order:
|
||||
// - a direct default export
|
||||
// - a direct default export with a wrapping call
|
||||
// - an indirect default export
|
||||
// - an indirect default export with a wrapping call at the definition
|
||||
// - an indirect default export with a wrapping call at the export
|
||||
// - a direct module export
|
||||
// - a direct module export with a wrapping call
|
||||
// - an indirect module export
|
||||
// - an indirect module export with a wrapping call at the definition
|
||||
// - an indirect module export with a wrapping call at the export
|
||||
//
|
||||
// Return the configuration object or null.
|
||||
findConfigurationObject(ast, allowWrappingCall = false) {
|
||||
// Try to find a default export
|
||||
var defaultExport = ast.body.find(node => node.type === 'ExportDefaultDeclaration')
|
||||
|
||||
// Direct default export
|
||||
if (defaultExport && defaultExport.declaration.type === 'ObjectExpression') {
|
||||
core.info('Found configuration object in direct default export declaration')
|
||||
return defaultExport.declaration
|
||||
}
|
||||
|
||||
// Direct default export with a wrapping call
|
||||
else if (
|
||||
allowWrappingCall &&
|
||||
defaultExport &&
|
||||
defaultExport.declaration.type === 'CallExpression' &&
|
||||
defaultExport.declaration.arguments.length > 0 &&
|
||||
defaultExport.declaration.arguments[0] &&
|
||||
defaultExport.declaration.arguments[0].type === 'ObjectExpression'
|
||||
) {
|
||||
core.info('Found configuration object in direct default export declaration with a wrapping call')
|
||||
return defaultExport.declaration.arguments[0]
|
||||
}
|
||||
|
||||
// Indirect default export
|
||||
else if (defaultExport && defaultExport.declaration.type === 'Identifier') {
|
||||
const identifierName = defaultExport.declaration.name
|
||||
const identifierDeclarator = this.findTopLevelVariableDeclarator(ast, identifierName)
|
||||
const identifierInitialization = identifierDeclarator && identifierDeclarator.init
|
||||
if (identifierInitialization && identifierInitialization.type === 'ObjectExpression') {
|
||||
core.info('Found configuration object in indirect default export declaration')
|
||||
return identifierInitialization
|
||||
}
|
||||
// Indirect default export with a wrapping call at the definition
|
||||
else if (
|
||||
allowWrappingCall &&
|
||||
identifierInitialization &&
|
||||
identifierInitialization.type === 'CallExpression' &&
|
||||
identifierInitialization.arguments.length > 0 &&
|
||||
identifierInitialization.arguments[0] &&
|
||||
identifierInitialization.arguments[0].type === 'ObjectExpression'
|
||||
) {
|
||||
core.info(
|
||||
'Found configuration object in indirect default export declaration with a wrapping call at the definition'
|
||||
)
|
||||
return identifierInitialization.arguments[0]
|
||||
}
|
||||
}
|
||||
|
||||
// Indirect default export with a wrapping call at the export
|
||||
else if (
|
||||
allowWrappingCall &&
|
||||
defaultExport &&
|
||||
defaultExport.declaration.type === 'CallExpression' &&
|
||||
defaultExport.declaration.arguments.length > 0 &&
|
||||
defaultExport.declaration.arguments[0] &&
|
||||
defaultExport.declaration.arguments[0].type === 'Identifier'
|
||||
) {
|
||||
const identifierName = defaultExport.declaration.arguments[0].name
|
||||
const identifierDeclarator = this.findTopLevelVariableDeclarator(ast, identifierName)
|
||||
const identifierInitialization = identifierDeclarator && identifierDeclarator.init
|
||||
if (identifierInitialization && identifierInitialization.type === 'ObjectExpression') {
|
||||
core.info(
|
||||
'Found configuration object in indirect default export declaration with a wrapping call at the export'
|
||||
)
|
||||
return identifierInitialization
|
||||
}
|
||||
}
|
||||
|
||||
// Try to find a module export
|
||||
var moduleExport = ast.body.find(
|
||||
node =>
|
||||
node.type === 'ExpressionStatement' &&
|
||||
node.expression.type === 'AssignmentExpression' &&
|
||||
node.expression.operator === '=' &&
|
||||
node.expression.left.type === 'MemberExpression' &&
|
||||
node.expression.left.object.type === 'Identifier' &&
|
||||
node.expression.left.object.name === 'module' &&
|
||||
node.expression.left.property.type === 'Identifier' &&
|
||||
node.expression.left.property.name === 'exports'
|
||||
)
|
||||
|
||||
// Direct module export
|
||||
if (moduleExport && moduleExport.expression.right.type === 'ObjectExpression') {
|
||||
core.info('Found configuration object in direct module export')
|
||||
return moduleExport.expression.right
|
||||
}
|
||||
|
||||
// Direct default export with a wrapping call
|
||||
else if (
|
||||
allowWrappingCall &&
|
||||
moduleExport &&
|
||||
moduleExport.expression.right.type === 'CallExpression' &&
|
||||
moduleExport.expression.right.arguments.length > 0 &&
|
||||
moduleExport.expression.right.arguments[0] &&
|
||||
moduleExport.expression.right.arguments[0].type === 'ObjectExpression'
|
||||
) {
|
||||
core.info('Found configuration object in direct module export with a wrapping call')
|
||||
return moduleExport.expression.right.arguments[0]
|
||||
}
|
||||
|
||||
// Indirect module export
|
||||
else if (moduleExport && moduleExport.expression.right.type === 'Identifier') {
|
||||
const identifierName = moduleExport && moduleExport.expression.right.name
|
||||
const identifierDeclarator = this.findTopLevelVariableDeclarator(ast, identifierName)
|
||||
const identifierInitialization = identifierDeclarator && identifierDeclarator.init
|
||||
if (identifierInitialization && identifierInitialization.type === 'ObjectExpression') {
|
||||
core.info('Found configuration object in indirect module export')
|
||||
return identifierInitialization
|
||||
}
|
||||
// Indirect module export with a wrapping call at the definition
|
||||
else if (
|
||||
allowWrappingCall &&
|
||||
identifierInitialization &&
|
||||
identifierInitialization.type === 'CallExpression' &&
|
||||
identifierInitialization.arguments.length > 0 &&
|
||||
identifierInitialization.arguments[0] &&
|
||||
identifierInitialization.arguments[0].type === 'ObjectExpression'
|
||||
) {
|
||||
core.info('Found configuration object in indirect module export with a wrapping call at the definition')
|
||||
return identifierInitialization.arguments[0]
|
||||
}
|
||||
}
|
||||
|
||||
// Indirect module export with a wrapping call at the export
|
||||
else if (
|
||||
allowWrappingCall &&
|
||||
moduleExport &&
|
||||
moduleExport.expression.right.type === 'CallExpression' &&
|
||||
moduleExport.expression.right.arguments.length > 0 &&
|
||||
moduleExport.expression.right.arguments[0] &&
|
||||
moduleExport.expression.right.arguments[0].type === 'Identifier'
|
||||
) {
|
||||
const identifierName = moduleExport.expression.right.arguments[0].name
|
||||
const identifierDeclarator = this.findTopLevelVariableDeclarator(ast, identifierName)
|
||||
const identifierInitialization = identifierDeclarator && identifierDeclarator.init
|
||||
if (identifierInitialization && identifierInitialization.type === 'ObjectExpression') {
|
||||
core.info('Found configuration object in indirect module export declaration with a wrapping call at the export')
|
||||
return identifierInitialization
|
||||
}
|
||||
}
|
||||
|
||||
// No configuration object found
|
||||
return null
|
||||
}
|
||||
|
||||
// Find a property with a given name on a given object.
|
||||
//
|
||||
// Return the matching property or null.
|
||||
findProperty(object, name) {
|
||||
// Try to find a property matching a given name
|
||||
const property =
|
||||
object.type === 'ObjectExpression' &&
|
||||
object.properties.find(node => node.key.type === 'Identifier' && node.key.name === name)
|
||||
|
||||
// Return the property's value (if found) or null
|
||||
if (property) {
|
||||
switch (this.staticSiteConfig.type) {
|
||||
case "nuxt":
|
||||
this.parseNuxt(property)
|
||||
break
|
||||
case "next":
|
||||
case "gatsby":
|
||||
this.parseNextGatsby(property)
|
||||
break
|
||||
default:
|
||||
throw "Unknown config type"
|
||||
}
|
||||
return property.value
|
||||
}
|
||||
core.info(`parsed configuration:\n${this.config}`)
|
||||
fs.writeFileSync(this.staticSiteConfig.filePath, this.config)
|
||||
return this.config
|
||||
return null
|
||||
}
|
||||
|
||||
getPropertyModuleExport(exportNode) {
|
||||
var propertyNode = exportNode.expression.right.properties.find(
|
||||
node => node.key.type === 'Identifier' && node.key.name === this.staticSiteConfig.pathName
|
||||
)
|
||||
|
||||
if (!propertyNode) {
|
||||
|
||||
core.info("Unable to find property, insert it : " + this.staticSiteConfig.pathName)
|
||||
if (exportNode.expression.right.properties.length > 0) {
|
||||
this.config = this.config.slice(0, exportNode.expression.right.properties[0].range[0]) + this.generateConfigProperty() + ',\n' + this.config.slice(exportNode.expression.right.properties[0].range[0])
|
||||
core.info("new config = \n" + this.config)
|
||||
} else {
|
||||
this.config = this.config.slice(0, exportNode.expression.right.range[0] + 1) + '\n ' + this.generateConfigProperty() + '\n' + this.config.slice(exportNode.expression.right.range[1] - 1)
|
||||
core.info("new config = \n" + this.config)
|
||||
}
|
||||
}
|
||||
return propertyNode
|
||||
}
|
||||
|
||||
getPropertyExportDefault(exportNode) {
|
||||
var propertyNode = exportNode.declaration.properties.find(
|
||||
node => node.key.type === 'Identifier' && node.key.name === this.staticSiteConfig.pathName
|
||||
)
|
||||
|
||||
if (!propertyNode) {
|
||||
|
||||
core.info("Unable to find property, insert it " + this.staticSiteConfig.pathName)
|
||||
if (exportNode.declaration.properties.length > 0) {
|
||||
this.config = this.config.slice(0, exportNode.declaration.properties[0].range[0]) + this.generateConfigProperty() + ',\n' + this.config.slice(exportNode.declaration.properties[0].range[0])
|
||||
core.info("new config = \n" + this.config)
|
||||
} else {
|
||||
this.config = this.config.slice(0, exportNode.declaration.range[0] + 1) + '\n ' + this.generateConfigProperty() + '\n' + this.config.slice(exportNode.declaration.range[1] - 1)
|
||||
core.info("new config = \n" + this.config)
|
||||
}
|
||||
}
|
||||
|
||||
return propertyNode
|
||||
}
|
||||
|
||||
parseNuxt(propertyNode) {
|
||||
// Find the base node
|
||||
if (propertyNode && propertyNode.value.type === 'ObjectExpression') {
|
||||
var baseNode = propertyNode.value.properties.find(node => node.key.type === 'Identifier' && node.key.name === this.staticSiteConfig.subPathName)//'base')
|
||||
if (baseNode) {
|
||||
// Swap the base value by a hardcoded string and print it
|
||||
this.config = this.config.slice(0, baseNode.value.range[0]) + `'${this.staticSiteConfig.newPath}'` + this.config.slice(baseNode.value.range[1])
|
||||
}
|
||||
// Generate a (nested) property declaration.
|
||||
// - properties: list of properties to generate
|
||||
// - startIndex: the index at which to start in the declaration
|
||||
// - propertyValue: the value of the property
|
||||
//
|
||||
// Return a nested property declaration as a string.
|
||||
getPropertyDeclaration(properties, startIndex, propertyValue) {
|
||||
if (startIndex === properties.length - 1) {
|
||||
return `${properties[startIndex]}: ${JSON.stringify(propertyValue)}`
|
||||
} else {
|
||||
return (
|
||||
`${properties[startIndex]}: {` + this.getPropertyDeclaration(properties, startIndex + 1, propertyValue) + '}'
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
parseNextGatsby(pathNode) {
|
||||
if (pathNode) {
|
||||
this.config = this.config.slice(0, pathNode.value.range[0]) + `'${this.staticSiteConfig.newPath}'` + this.config.slice(pathNode.value.range[1])
|
||||
// Inject all properties into the configuration
|
||||
injectAll() {
|
||||
for (var [propertyName, propertyValue] of Object.entries(this.properties)) {
|
||||
this.inject(propertyName, propertyValue)
|
||||
}
|
||||
}
|
||||
|
||||
// Inject an arbitrary property into the configuration
|
||||
// - propertyName: the name of the property (may use . to target nested objects)
|
||||
// - propertyValue: the value of the property
|
||||
inject(propertyName, propertyValue) {
|
||||
// Logging
|
||||
core.info(`Injecting property=${propertyName} and value=${propertyValue} in:`)
|
||||
core.info(this.configuration)
|
||||
|
||||
// Parse the AST out of the configuration file
|
||||
const espreeOptions = {
|
||||
ecmaVersion: 'latest',
|
||||
sourceType: 'module',
|
||||
range: true
|
||||
}
|
||||
const ast = espree.parse(this.configuration, espreeOptions)
|
||||
|
||||
// Find the configuration object
|
||||
var configurationObject = this.findConfigurationObject(ast, this.allowWrappingCall)
|
||||
if (!configurationObject) {
|
||||
throw 'Could not find a configuration object in the configuration file'
|
||||
}
|
||||
|
||||
// A property may be nested in the configuration file. Split the property name with '.'
|
||||
// then walk the configuration object one property at a time.
|
||||
var depth = 0
|
||||
const properties = propertyName.split('.')
|
||||
var lastNode = configurationObject
|
||||
// eslint-disable-next-line no-constant-condition
|
||||
while (true) {
|
||||
// Find the node for the current property
|
||||
var propertyNode = this.findProperty(lastNode, properties[depth])
|
||||
|
||||
// Update last node
|
||||
if (propertyNode != null) {
|
||||
lastNode = propertyNode
|
||||
depth++
|
||||
}
|
||||
|
||||
// Exit when exiting the current configuration object
|
||||
if (propertyNode == null || depth >= properties.length) {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// If the configuration file is defining the property we are after, update it.
|
||||
if (depth == properties.length) {
|
||||
// The last node identified is an object expression, so do the assignment
|
||||
if (lastNode.type === 'ObjectExpression') {
|
||||
this.configuration =
|
||||
this.configuration.slice(0, lastNode.range[0]) +
|
||||
JSON.stringify(propertyValue) +
|
||||
this.configuration.slice(lastNode.range[1])
|
||||
}
|
||||
|
||||
// A misc object was found in the configuration file (e.g. an array, a string, a boolean,
|
||||
// a number, etc.), just replace the whole range by our declaration
|
||||
else {
|
||||
this.configuration =
|
||||
this.configuration.slice(0, lastNode.range[0]) +
|
||||
JSON.stringify(propertyValue) +
|
||||
this.configuration.slice(lastNode.range[1])
|
||||
}
|
||||
}
|
||||
|
||||
// Create nested properties in the configuration file
|
||||
else {
|
||||
// Build the declaration to inject
|
||||
const declaration = this.getPropertyDeclaration(properties, depth, propertyValue)
|
||||
|
||||
// The last node identified is an object expression, so do the assignment
|
||||
if (lastNode.type === 'ObjectExpression') {
|
||||
// The object is blank (no properties) so replace the whole range by a new object containing the declaration
|
||||
if (lastNode.properties.length === 0) {
|
||||
this.configuration =
|
||||
this.configuration.slice(0, lastNode.range[0]) +
|
||||
'{' +
|
||||
declaration +
|
||||
'}' +
|
||||
this.configuration.slice(lastNode.range[1])
|
||||
}
|
||||
|
||||
// The object contains other properties, prepend our new one at the beginning
|
||||
else {
|
||||
this.configuration =
|
||||
this.configuration.slice(0, lastNode.properties[0].range[0]) +
|
||||
declaration +
|
||||
',' +
|
||||
this.configuration.slice(lastNode.properties[0].range[0])
|
||||
}
|
||||
}
|
||||
|
||||
// A misc object was found in the configuration file (e.g. an array, a string, a boolean,
|
||||
// a number, etc.), just replace the whole range by our declaration
|
||||
else {
|
||||
this.configuration =
|
||||
this.configuration.slice(0, lastNode.range[0]) +
|
||||
'{' +
|
||||
declaration +
|
||||
'}' +
|
||||
this.configuration.slice(lastNode.range[1])
|
||||
}
|
||||
}
|
||||
|
||||
// Logging
|
||||
core.info('Injection successful, new configuration:')
|
||||
core.info(this.configuration)
|
||||
|
||||
// Finally write the new configuration in the file
|
||||
fs.writeFileSync(this.configurationFile, this.configuration, {
|
||||
encoding: 'utf8'
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {ConfigParser}
|
||||
module.exports = { ConfigParser }
|
||||
|
||||
@@ -1,83 +1,298 @@
|
||||
const fs = require('fs')
|
||||
const core = require('@actions/core')
|
||||
|
||||
const { ConfigParser } = require('./config-parser')
|
||||
const fs = require("fs")
|
||||
const assert = require('assert')
|
||||
const { getTempFolder, compareFiles } = require('./test-helpers')
|
||||
|
||||
const srcFolder = `${process.cwd()}/src/fixtures`
|
||||
const tmpFolder = `${process.cwd()}/src/fixtures/tmp`
|
||||
const expectedFolder = `${process.cwd()}/src/fixtures/expected`
|
||||
|
||||
const repoPath = "/amazing-new-repo/"
|
||||
// Get the temp folder
|
||||
const tempFolder = getTempFolder()
|
||||
|
||||
// Cases to test
|
||||
const cases = [
|
||||
["next.config.js", {
|
||||
filePath: `${tmpFolder}/next.config.js`,
|
||||
type: "next",
|
||||
pathName: "basePath",
|
||||
newPath: repoPath
|
||||
}],
|
||||
["next.config.old.js", {
|
||||
filePath: `${tmpFolder}/next.config.old.js`,
|
||||
type: "next",
|
||||
pathName: "basePath",
|
||||
newPath: repoPath
|
||||
}],
|
||||
["next.config.old.missing.js", {
|
||||
filePath: `${tmpFolder}/next.config.old.missing.js`,
|
||||
type: "next",
|
||||
pathName: "basePath",
|
||||
newPath: repoPath
|
||||
}],
|
||||
["gatsby-config.js", {
|
||||
filePath: `${tmpFolder}/gatsby-config.js`,
|
||||
type: "gatsby",
|
||||
pathName: "pathPrefix",
|
||||
newPath: repoPath
|
||||
}],
|
||||
["gatsby-config.old.js", {
|
||||
filePath: `${tmpFolder}/gatsby-config.old.js`,
|
||||
type: "gatsby",
|
||||
pathName: "pathPrefix",
|
||||
newPath: repoPath
|
||||
}],
|
||||
["nuxt.config.js", {
|
||||
filePath:`${tmpFolder}/nuxt.config.js`,
|
||||
type: "nuxt",
|
||||
pathName: "router",
|
||||
subPathName: "base",
|
||||
newPath: repoPath
|
||||
}],
|
||||
["nuxt.config.missing.js", {
|
||||
filePath:`${tmpFolder}/nuxt.config.missing.js`,
|
||||
type: "nuxt",
|
||||
pathName: "router",
|
||||
subPathName: "base",
|
||||
newPath: repoPath
|
||||
}],
|
||||
["nuxt.config.old.js", {
|
||||
filePath:`${tmpFolder}/nuxt.config.old.js`,
|
||||
type: "nuxt",
|
||||
pathName: "router",
|
||||
subPathName: "base",
|
||||
newPath: repoPath
|
||||
}],
|
||||
];
|
||||
//
|
||||
// Direct default export
|
||||
//
|
||||
{
|
||||
property: 'property',
|
||||
source: 'export default {}',
|
||||
expected: 'export default { property: "value" }'
|
||||
},
|
||||
{
|
||||
property: 'property',
|
||||
source: 'export default { property: 0 }', // property exists and is a number
|
||||
expected: 'export default { property: "value" }'
|
||||
},
|
||||
{
|
||||
property: 'property',
|
||||
source: 'export default { property: false }', // property exists and is a boolean
|
||||
expected: 'export default { property: "value" }'
|
||||
},
|
||||
{
|
||||
property: 'property',
|
||||
source: 'export default { property: "test" }', // property exists and is a string
|
||||
expected: 'export default { property: "value" }'
|
||||
},
|
||||
{
|
||||
property: 'property',
|
||||
source: 'export default { property: [1,2] }', // property exists and is an array
|
||||
expected: 'export default { property: "value" }'
|
||||
},
|
||||
{
|
||||
property: 'property',
|
||||
source: 'export default { property: null }', // property exists and is null
|
||||
expected: 'export default { property: "value" }'
|
||||
},
|
||||
{
|
||||
property: 'property',
|
||||
source: 'export default { property: { } }', // property exists and is an object
|
||||
expected: 'export default { property: "value" }'
|
||||
},
|
||||
|
||||
describe('configParser', () => {
|
||||
test.each(cases)(
|
||||
"%p parsed correctly",
|
||||
(fileName, configuration) => {
|
||||
srcFileName = `${srcFolder}/${fileName}`
|
||||
tmpFileName = `${tmpFolder}/${fileName}`
|
||||
expectedFileName = `${expectedFolder}/${fileName}`
|
||||
fs.mkdirSync(tmpFolder, {recursive: true})
|
||||
fs.copyFileSync(srcFileName, tmpFileName)
|
||||
const parser = new ConfigParser(configuration)
|
||||
parser.parse()
|
||||
// Deep properties (injection 1)
|
||||
{
|
||||
property: 'property.b.c',
|
||||
source: 'export default {}',
|
||||
expected: 'export default { property: { b: { c: "value" } } }'
|
||||
},
|
||||
{
|
||||
property: 'property.b.c',
|
||||
source: 'export default { property: 0 }', // property exists and is a number
|
||||
expected: 'export default { property: { b: { c: "value" } } }'
|
||||
},
|
||||
{
|
||||
property: 'property.b.c',
|
||||
source: 'export default { property: { } }', // property exists and is an object
|
||||
expected: 'export default { property: { b: { c: "value" } } }'
|
||||
},
|
||||
|
||||
var expectedContent = fs.readFileSync(expectedFileName).toString()
|
||||
var actualContent = fs.readFileSync(tmpFileName).toString()
|
||||
assert.equal(actualContent, expectedContent)
|
||||
fs.rmSync(tmpFileName)
|
||||
}
|
||||
)
|
||||
// Deep properties (injection 2)
|
||||
{
|
||||
property: 'property.b.c',
|
||||
source: 'export default { property: { b: 0 } }', // property exists and is a number
|
||||
expected: 'export default { property: { b: { c: "value" } } }'
|
||||
},
|
||||
{
|
||||
property: 'property.b.c',
|
||||
source: 'export default { property: { b: { } } }', // property exists and is an object
|
||||
expected: 'export default { property: { b: { c: "value" } } }'
|
||||
},
|
||||
{
|
||||
property: 'property.b.c',
|
||||
source: 'export default { property: { b: { hello: 123 } } }', // property exists and is a non-empty object
|
||||
expected: 'export default { property: { b: { c: "value", hello: 123 } } }'
|
||||
},
|
||||
|
||||
// Deep properties (existing properties)
|
||||
{
|
||||
property: 'a1.a2',
|
||||
source: 'export default { a2: false, a1: { a3: [12] } }', // property exists and is a non-empty object
|
||||
expected: 'export default { a2: false, a1: { a2: "value", a3: [12] } }'
|
||||
},
|
||||
|
||||
//
|
||||
// Indirect default export
|
||||
//
|
||||
{
|
||||
property: 'property',
|
||||
source: 'const config = {}; export default config',
|
||||
expected: 'const config = { property: "value"}; export default config'
|
||||
},
|
||||
// with more than 1 declaration chained together
|
||||
{
|
||||
property: 'property',
|
||||
source: 'var temp = {}, config = {}; export default config',
|
||||
expected: 'var temp = {}, config = { property: "value"}; export default config'
|
||||
},
|
||||
// deeper
|
||||
{
|
||||
property: 'a.b.c',
|
||||
source: 'var config = {}; export default config',
|
||||
expected: 'var config = { a: { b: { c: "value" } } }; export default config'
|
||||
},
|
||||
{
|
||||
property: 'a.b.c',
|
||||
source: 'var config = { a: { b: [], c: "hello" } }; export default config',
|
||||
expected: 'var config = { a: { b: { c: "value"}, c: "hello" } }; export default config'
|
||||
},
|
||||
|
||||
//
|
||||
// Direct module exports
|
||||
//
|
||||
{
|
||||
property: 'property',
|
||||
source: 'module.exports = {}',
|
||||
expected: 'module.exports = { property: "value"}'
|
||||
},
|
||||
{
|
||||
property: 'property',
|
||||
source: 'module.exports = { p1: 0}',
|
||||
expected: 'module.exports = { property: "value", p1: 0}'
|
||||
},
|
||||
{
|
||||
property: 'a.b.c',
|
||||
source: 'module.exports = { p1: 0}',
|
||||
expected: 'module.exports = { a: { b: { c: "value" } }, p1: 0}'
|
||||
},
|
||||
|
||||
//
|
||||
// Indirect module exports
|
||||
//
|
||||
{
|
||||
property: 'property',
|
||||
source: 'const config = {}; module.exports = config',
|
||||
expected: 'const config = { property: "value"}; module.exports = config'
|
||||
},
|
||||
// with more than 1 declaration chained together
|
||||
{
|
||||
property: 'property',
|
||||
source: 'var temp = {}, config = {}; module.exports = config',
|
||||
expected: 'var temp = {}, config = { property: "value"}; module.exports = config'
|
||||
},
|
||||
// deeper
|
||||
{
|
||||
property: 'a.b.c',
|
||||
source: 'var config = {}; module.exports = config',
|
||||
expected: 'var config = { a: { b: { c: "value" } } }; module.exports = config'
|
||||
},
|
||||
{
|
||||
property: 'a.b.c',
|
||||
source: 'var config = { a: { b: [], c: "hello" } }; module.exports = config',
|
||||
expected: 'var config = { a: { b: { c: "value"}, c: "hello" } }; module.exports = config'
|
||||
},
|
||||
|
||||
//
|
||||
// Direct default export with wrapping call
|
||||
//
|
||||
{
|
||||
property: 'property',
|
||||
source: 'import { defineConfig } from "astro/config"; export default defineConfig({ p1: 0 })',
|
||||
expected: 'import { defineConfig } from "astro/config"; export default defineConfig({ property: "value", p1: 0 })',
|
||||
allowWrappingCall: true
|
||||
},
|
||||
|
||||
//
|
||||
// Direct module exports with wrapping call
|
||||
//
|
||||
{
|
||||
property: 'property',
|
||||
source: 'const { defineConfig } = require("astro/config"); module.exports = defineConfig({ p1: 0 })',
|
||||
expected:
|
||||
'const { defineConfig } = require("astro/config"); module.exports = defineConfig({ property: "value", p1: 0 })',
|
||||
allowWrappingCall: true
|
||||
},
|
||||
|
||||
//
|
||||
// Indirect default export with wrapping call at the definition
|
||||
//
|
||||
{
|
||||
property: 'property',
|
||||
source: 'import { defineConfig } from "astro/config"; const config = defineConfig({}); export default config',
|
||||
expected:
|
||||
'import { defineConfig } from "astro/config"; const config = defineConfig({ property: "value" }); export default config',
|
||||
allowWrappingCall: true
|
||||
},
|
||||
// with more than 1 declaration chained together
|
||||
{
|
||||
property: 'property',
|
||||
source:
|
||||
'import { defineConfig } from "astro/config"; const temp = {}, config = defineConfig({}); export default config',
|
||||
expected:
|
||||
'import { defineConfig } from "astro/config"; const temp = {}, config = defineConfig({ property: "value" }); export default config',
|
||||
allowWrappingCall: true
|
||||
},
|
||||
|
||||
//
|
||||
// Indirect default export with wrapping call at the export
|
||||
//
|
||||
{
|
||||
property: 'property',
|
||||
source: 'import { defineConfig } from "astro/config"; const config = {}; export default defineConfig(config)',
|
||||
expected:
|
||||
'import { defineConfig } from "astro/config"; const config = { property: "value" }; export default defineConfig(config)',
|
||||
allowWrappingCall: true
|
||||
},
|
||||
// with more than 1 declaration chained together
|
||||
{
|
||||
property: 'property',
|
||||
source:
|
||||
'import { defineConfig } from "astro/config"; const temp = {}, config = {}; export default defineConfig(config)',
|
||||
expected:
|
||||
'import { defineConfig } from "astro/config"; const temp = {}, config = { property: "value" }; export default defineConfig(config)',
|
||||
allowWrappingCall: true
|
||||
},
|
||||
|
||||
//
|
||||
// Indirect module exports with wrapping call at the definition
|
||||
//
|
||||
{
|
||||
property: 'property',
|
||||
source:
|
||||
'const { defineConfig } = require("astro/config"); const config = defineConfig({}); module.exports = config',
|
||||
expected:
|
||||
'const { defineConfig } = require("astro/config"); const config = defineConfig({ property: "value"}); module.exports = config',
|
||||
allowWrappingCall: true
|
||||
},
|
||||
// with more than 1 declaration chained together
|
||||
{
|
||||
property: 'property',
|
||||
source:
|
||||
'const { defineConfig } = require("astro/config"); const temp = {}, config = defineConfig({}); module.exports = config',
|
||||
expected:
|
||||
'const { defineConfig } = require("astro/config"); const temp = {}, config = defineConfig({ property: "value"}); module.exports = config',
|
||||
allowWrappingCall: true
|
||||
},
|
||||
|
||||
//
|
||||
// Indirect module exports with wrapping call at the export
|
||||
//
|
||||
{
|
||||
property: 'property',
|
||||
source:
|
||||
'const { defineConfig } = require("astro/config"); const config = {}; module.exports = defineConfig(config)',
|
||||
expected:
|
||||
'const { defineConfig } = require("astro/config"); const config = { property: "value"}; module.exports = defineConfig(config)',
|
||||
allowWrappingCall: true
|
||||
},
|
||||
// with more than 1 declaration chained together
|
||||
{
|
||||
property: 'property',
|
||||
source:
|
||||
'const { defineConfig } = require("astro/config"); const temp = {}, config = {}; module.exports = defineConfig(config)',
|
||||
expected:
|
||||
'const { defineConfig } = require("astro/config"); const temp = {}, config = { property: "value"}; module.exports = defineConfig(config)',
|
||||
allowWrappingCall: true
|
||||
}
|
||||
]
|
||||
|
||||
describe('config-parser', () => {
|
||||
beforeEach(() => {
|
||||
jest.restoreAllMocks()
|
||||
|
||||
// Mock error/warning/info/debug to silence their output
|
||||
jest.spyOn(core, 'error').mockImplementation(jest.fn())
|
||||
jest.spyOn(core, 'warning').mockImplementation(jest.fn())
|
||||
jest.spyOn(core, 'info').mockImplementation(jest.fn())
|
||||
jest.spyOn(core, 'debug').mockImplementation(jest.fn())
|
||||
})
|
||||
|
||||
cases.forEach(({ property, source, expected, allowWrappingCall = false }, index) => {
|
||||
it(`injects path properly for case #${index}`, () => {
|
||||
// Write the source file
|
||||
const sourceFile = `${tempFolder}/source.js`
|
||||
fs.writeFileSync(sourceFile, source, { encoding: 'utf8' })
|
||||
|
||||
// Write the expected file
|
||||
const expectedFile = `${tempFolder}/expected.js`
|
||||
fs.writeFileSync(expectedFile, expected, { encoding: 'utf8' })
|
||||
|
||||
// Update the settings and do the injection
|
||||
new ConfigParser({
|
||||
configurationFile: sourceFile,
|
||||
allowWrappingCall
|
||||
}).inject(property, 'value')
|
||||
|
||||
// Compare the files
|
||||
compareFiles(sourceFile, expectedFile)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -5,11 +5,14 @@ function getRequiredVars() {
|
||||
return {
|
||||
repositoryNwo: process.env.GITHUB_REPOSITORY,
|
||||
githubToken: core.getInput('token'),
|
||||
staticSiteGenerator: core.getInput('static_site_generator')
|
||||
staticSiteGenerator: core.getInput('static_site_generator'),
|
||||
generatorConfigFile: core.getInput('generator_config_file'),
|
||||
enablement: core.getInput('enablement') === 'true'
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = function getContext() {
|
||||
// Return the context object
|
||||
function getContext() {
|
||||
const requiredVars = getRequiredVars()
|
||||
for (const variable in requiredVars) {
|
||||
if (requiredVars[variable] === undefined) {
|
||||
@@ -19,3 +22,5 @@ module.exports = function getContext() {
|
||||
core.debug('all variables are set')
|
||||
return requiredVars
|
||||
}
|
||||
|
||||
module.exports = { getContext }
|
||||
|
||||
@@ -1,31 +0,0 @@
|
||||
const core = require('@actions/core')
|
||||
const axios = require('axios')
|
||||
|
||||
async function enablePages({ repositoryNwo, githubToken }) {
|
||||
const pagesEndpoint = `https://api.github.com/repos/${repositoryNwo}/pages`
|
||||
|
||||
try {
|
||||
const response = await axios.post(
|
||||
pagesEndpoint,
|
||||
{ build_type: 'workflow' },
|
||||
{
|
||||
headers: {
|
||||
Accept: 'application/vnd.github.v3+json',
|
||||
Authorization: `Bearer ${githubToken}`,
|
||||
'Content-type': 'application/json',
|
||||
},
|
||||
}
|
||||
)
|
||||
core.info('Created pages site')
|
||||
} catch (error) {
|
||||
if (error.response && error.response.status === 409) {
|
||||
core.info('Pages site exists')
|
||||
return
|
||||
}
|
||||
|
||||
core.error('Couldn\'t create pages site', error)
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = enablePages
|
||||
@@ -1,48 +0,0 @@
|
||||
const core = require('@actions/core')
|
||||
const axios = require('axios')
|
||||
|
||||
const enablePages = require('./enable-pages')
|
||||
|
||||
describe('enablePages', () => {
|
||||
const GITHUB_REPOSITORY = 'paper-spa/is-awesome'
|
||||
const GITHUB_TOKEN = 'gha-token'
|
||||
|
||||
beforeEach(() => {
|
||||
jest.restoreAllMocks()
|
||||
|
||||
// Mock error/warning/info/debug
|
||||
jest.spyOn(core, 'error').mockImplementation(jest.fn())
|
||||
jest.spyOn(core, 'warning').mockImplementation(jest.fn())
|
||||
jest.spyOn(core, 'info').mockImplementation(jest.fn())
|
||||
jest.spyOn(core, 'debug').mockImplementation(jest.fn())
|
||||
})
|
||||
|
||||
it('makes a request to create a page', async () => {
|
||||
jest
|
||||
.spyOn(axios, 'post')
|
||||
.mockImplementationOnce(() => Promise.resolve({ }))
|
||||
|
||||
await enablePages({ repositoryNwo: GITHUB_REPOSITORY, githubToken: GITHUB_TOKEN })
|
||||
})
|
||||
|
||||
it('handles a 409 response when the page already exists', async () => {
|
||||
jest
|
||||
.spyOn(axios, 'post')
|
||||
.mockImplementationOnce(() => Promise.reject({ response: { status: 409 } }))
|
||||
|
||||
// Simply assert that no error is raised
|
||||
await enablePages({ repositoryNwo: GITHUB_REPOSITORY, githubToken: GITHUB_TOKEN })
|
||||
})
|
||||
|
||||
it('re-raises errors on failure status codes', async () => {
|
||||
jest
|
||||
.spyOn(axios, 'post')
|
||||
.mockImplementationOnce(() => Promise.reject({ response: { status: 404 } }))
|
||||
|
||||
try {
|
||||
await enablePages({ repositoryNwo: GITHUB_REPOSITORY, githubToken: GITHUB_TOKEN })
|
||||
} catch (error) {
|
||||
expect(error.response.status).toEqual(404)
|
||||
}
|
||||
})
|
||||
})
|
||||
@@ -1,8 +0,0 @@
|
||||
import { resolve } from 'path'
|
||||
|
||||
export default {
|
||||
alias: {
|
||||
'style': resolve(__dirname, './assets/style')
|
||||
},
|
||||
pathPrefix: '/amazing-new-repo/',/* test */
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
module.exports = {
|
||||
pathPrefix: '/amazing-new-repo/'
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
|
||||
import { resolve } from 'path'
|
||||
|
||||
export default {
|
||||
alias: {
|
||||
'style': resolve(__dirname, './assets/style')
|
||||
},
|
||||
basePath: '/amazing-new-repo/'/* test */,
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
module.exports={
|
||||
basePath: '/amazing-new-repo/'/* test */,
|
||||
}
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
module.exports={
|
||||
basePath: '/amazing-new-repo/'
|
||||
}
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
import { resolve } from 'path'
|
||||
|
||||
export default {
|
||||
alias: {
|
||||
'style': resolve(__dirname, './assets/style')
|
||||
},
|
||||
target: 'static',
|
||||
router: {
|
||||
base: '/amazing-new-repo/'
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
import { resolve } from 'path'
|
||||
|
||||
export default {
|
||||
router: {
|
||||
base: '/amazing-new-repo/'
|
||||
},
|
||||
alias: {
|
||||
'style': resolve(__dirname, './assets/style')
|
||||
},
|
||||
target: 'static'
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
|
||||
module.exports={
|
||||
alias: {
|
||||
'style': resolve(__dirname, './assets/style')
|
||||
},
|
||||
target: 'static',
|
||||
router: {
|
||||
base: '/amazing-new-repo/'
|
||||
}
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
import { resolve } from 'path'
|
||||
|
||||
export default {
|
||||
alias: {
|
||||
'style': resolve(__dirname, './assets/style')
|
||||
},
|
||||
pathPrefix: '/prefix',/* test */
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
module.exports = {
|
||||
pathPrefix: '/prefix'
|
||||
}
|
||||
2
src/fixtures/gatsby/blank.expected.js
Normal file
2
src/fixtures/gatsby/blank.expected.js
Normal file
@@ -0,0 +1,2 @@
|
||||
// Default Pages configuration for Gatsby
|
||||
module.exports = { siteMetadata: { siteUrl: 'https://configure-pages.github.io' }, pathPrefix: '/docs/' }
|
||||
1
src/fixtures/gatsby/blank.js
Normal file
1
src/fixtures/gatsby/blank.js
Normal file
@@ -0,0 +1 @@
|
||||
// This file is not read by the test suite
|
||||
6
src/fixtures/gatsby/default.cjs
Normal file
6
src/fixtures/gatsby/default.cjs
Normal file
@@ -0,0 +1,6 @@
|
||||
module.exports = {
|
||||
siteMetadata: {
|
||||
title: 'My Gatsby Site'
|
||||
},
|
||||
plugins: []
|
||||
}
|
||||
8
src/fixtures/gatsby/default.expected.cjs
Normal file
8
src/fixtures/gatsby/default.expected.cjs
Normal file
@@ -0,0 +1,8 @@
|
||||
module.exports = {
|
||||
pathPrefix: '/docs/',
|
||||
siteMetadata: {
|
||||
siteUrl: 'https://configure-pages.github.io',
|
||||
title: 'My Gatsby Site'
|
||||
},
|
||||
plugins: []
|
||||
}
|
||||
8
src/fixtures/gatsby/default.expected.js
Normal file
8
src/fixtures/gatsby/default.expected.js
Normal file
@@ -0,0 +1,8 @@
|
||||
module.exports = {
|
||||
pathPrefix: '/docs/',
|
||||
siteMetadata: {
|
||||
siteUrl: 'https://configure-pages.github.io',
|
||||
title: 'My Gatsby Site'
|
||||
},
|
||||
plugins: []
|
||||
}
|
||||
8
src/fixtures/gatsby/default.expected.mjs
Normal file
8
src/fixtures/gatsby/default.expected.mjs
Normal file
@@ -0,0 +1,8 @@
|
||||
export default {
|
||||
pathPrefix: '/docs/',
|
||||
siteMetadata: {
|
||||
siteUrl: 'https://configure-pages.github.io',
|
||||
title: 'My Gatsby Site'
|
||||
},
|
||||
plugins: []
|
||||
}
|
||||
6
src/fixtures/gatsby/default.js
Normal file
6
src/fixtures/gatsby/default.js
Normal file
@@ -0,0 +1,6 @@
|
||||
module.exports = {
|
||||
siteMetadata: {
|
||||
title: 'My Gatsby Site'
|
||||
},
|
||||
plugins: []
|
||||
}
|
||||
6
src/fixtures/gatsby/default.mjs
Normal file
6
src/fixtures/gatsby/default.mjs
Normal file
@@ -0,0 +1,6 @@
|
||||
export default {
|
||||
siteMetadata: {
|
||||
title: 'My Gatsby Site'
|
||||
},
|
||||
plugins: []
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
|
||||
import { resolve } from 'path'
|
||||
|
||||
export default {
|
||||
alias: {
|
||||
'style': resolve(__dirname, './assets/style')
|
||||
},
|
||||
basePath: '/gh-pages-test'/* test */,
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
module.exports={
|
||||
basePath: '/gh-pages-test'/* test */,
|
||||
}
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
module.exports={
|
||||
|
||||
}
|
||||
|
||||
3
src/fixtures/next/blank.expected.js
Normal file
3
src/fixtures/next/blank.expected.js
Normal file
@@ -0,0 +1,3 @@
|
||||
// Default Pages configuration for Next
|
||||
const nextConfig = { images: { unoptimized: true }, experimental: { images: { unoptimized: true } }, basePath: '/docs' }
|
||||
module.exports = nextConfig
|
||||
1
src/fixtures/next/blank.js
Normal file
1
src/fixtures/next/blank.js
Normal file
@@ -0,0 +1 @@
|
||||
// This file is not read by the test suite
|
||||
7
src/fixtures/next/default.cjs
Normal file
7
src/fixtures/next/default.cjs
Normal file
@@ -0,0 +1,7 @@
|
||||
/** @type {import('next').NextConfig} */
|
||||
const nextConfig = {
|
||||
reactStrictMode: true,
|
||||
swcMinify: true
|
||||
}
|
||||
|
||||
module.exports = nextConfig
|
||||
10
src/fixtures/next/default.expected.cjs
Normal file
10
src/fixtures/next/default.expected.cjs
Normal file
@@ -0,0 +1,10 @@
|
||||
/** @type {import('next').NextConfig} */
|
||||
const nextConfig = {
|
||||
images: { unoptimized: true },
|
||||
experimental: { images: { unoptimized: true } },
|
||||
basePath: '/docs',
|
||||
reactStrictMode: true,
|
||||
swcMinify: true
|
||||
}
|
||||
|
||||
module.exports = nextConfig
|
||||
10
src/fixtures/next/default.expected.js
Normal file
10
src/fixtures/next/default.expected.js
Normal file
@@ -0,0 +1,10 @@
|
||||
/** @type {import('next').NextConfig} */
|
||||
const nextConfig = {
|
||||
images: { unoptimized: true },
|
||||
experimental: { images: { unoptimized: true } },
|
||||
basePath: '/docs',
|
||||
reactStrictMode: true,
|
||||
swcMinify: true
|
||||
}
|
||||
|
||||
module.exports = nextConfig
|
||||
10
src/fixtures/next/default.expected.mjs
Normal file
10
src/fixtures/next/default.expected.mjs
Normal file
@@ -0,0 +1,10 @@
|
||||
/** @type {import('next').NextConfig} */
|
||||
const nextConfig = {
|
||||
images: { unoptimized: true },
|
||||
experimental: { images: { unoptimized: true } },
|
||||
basePath: '/docs',
|
||||
reactStrictMode: true,
|
||||
swcMinify: true
|
||||
}
|
||||
|
||||
export default nextConfig
|
||||
7
src/fixtures/next/default.js
Normal file
7
src/fixtures/next/default.js
Normal file
@@ -0,0 +1,7 @@
|
||||
/** @type {import('next').NextConfig} */
|
||||
const nextConfig = {
|
||||
reactStrictMode: true,
|
||||
swcMinify: true
|
||||
}
|
||||
|
||||
module.exports = nextConfig
|
||||
7
src/fixtures/next/default.mjs
Normal file
7
src/fixtures/next/default.mjs
Normal file
@@ -0,0 +1,7 @@
|
||||
/** @type {import('next').NextConfig} */
|
||||
const nextConfig = {
|
||||
reactStrictMode: true,
|
||||
swcMinify: true
|
||||
}
|
||||
|
||||
export default nextConfig
|
||||
@@ -1,11 +0,0 @@
|
||||
import { resolve } from 'path'
|
||||
|
||||
export default {
|
||||
alias: {
|
||||
'style': resolve(__dirname, './assets/style')
|
||||
},
|
||||
target: 'static',
|
||||
router: {
|
||||
base: 'some/path'
|
||||
}
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
import { resolve } from 'path'
|
||||
|
||||
export default {
|
||||
alias: {
|
||||
'style': resolve(__dirname, './assets/style')
|
||||
},
|
||||
target: 'static'
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
|
||||
module.exports={
|
||||
alias: {
|
||||
'style': resolve(__dirname, './assets/style')
|
||||
},
|
||||
target: 'static',
|
||||
router: {
|
||||
base: 'some/path'
|
||||
}
|
||||
}
|
||||
15
src/fixtures/nuxt/async.cjs
Normal file
15
src/fixtures/nuxt/async.cjs
Normal file
@@ -0,0 +1,15 @@
|
||||
const getAllDynamicRoute = async function () {
|
||||
const routes = await (async () => {
|
||||
return ['/posts/hello-world', '/posts/hello-again']
|
||||
})()
|
||||
return routes
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
mode: 'universal',
|
||||
generate: {
|
||||
async routes() {
|
||||
return getAllDynamicRoute()
|
||||
}
|
||||
}
|
||||
}
|
||||
17
src/fixtures/nuxt/async.expected.cjs
Normal file
17
src/fixtures/nuxt/async.expected.cjs
Normal file
@@ -0,0 +1,17 @@
|
||||
const getAllDynamicRoute = async function () {
|
||||
const routes = await (async () => {
|
||||
return ['/posts/hello-world', '/posts/hello-again']
|
||||
})()
|
||||
return routes
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
target: 'static',
|
||||
router: { base: '/docs/' },
|
||||
mode: 'universal',
|
||||
generate: {
|
||||
async routes() {
|
||||
return getAllDynamicRoute()
|
||||
}
|
||||
}
|
||||
}
|
||||
17
src/fixtures/nuxt/async.expected.js
Normal file
17
src/fixtures/nuxt/async.expected.js
Normal file
@@ -0,0 +1,17 @@
|
||||
const getAllDynamicRoute = async function () {
|
||||
const routes = await (async () => {
|
||||
return ['/posts/hello-world', '/posts/hello-again']
|
||||
})()
|
||||
return routes
|
||||
}
|
||||
|
||||
export default {
|
||||
target: 'static',
|
||||
router: { base: '/docs/' },
|
||||
mode: 'universal',
|
||||
generate: {
|
||||
async routes() {
|
||||
return getAllDynamicRoute()
|
||||
}
|
||||
}
|
||||
}
|
||||
17
src/fixtures/nuxt/async.expected.mjs
Normal file
17
src/fixtures/nuxt/async.expected.mjs
Normal file
@@ -0,0 +1,17 @@
|
||||
const getAllDynamicRoute = async function () {
|
||||
const routes = await (async () => {
|
||||
return ['/posts/hello-world', '/posts/hello-again']
|
||||
})()
|
||||
return routes
|
||||
}
|
||||
|
||||
export default {
|
||||
target: 'static',
|
||||
router: { base: '/docs/' },
|
||||
mode: 'universal',
|
||||
generate: {
|
||||
async routes() {
|
||||
return getAllDynamicRoute()
|
||||
}
|
||||
}
|
||||
}
|
||||
15
src/fixtures/nuxt/async.js
Normal file
15
src/fixtures/nuxt/async.js
Normal file
@@ -0,0 +1,15 @@
|
||||
const getAllDynamicRoute = async function () {
|
||||
const routes = await (async () => {
|
||||
return ['/posts/hello-world', '/posts/hello-again']
|
||||
})()
|
||||
return routes
|
||||
}
|
||||
|
||||
export default {
|
||||
mode: 'universal',
|
||||
generate: {
|
||||
async routes() {
|
||||
return getAllDynamicRoute()
|
||||
}
|
||||
}
|
||||
}
|
||||
15
src/fixtures/nuxt/async.mjs
Normal file
15
src/fixtures/nuxt/async.mjs
Normal file
@@ -0,0 +1,15 @@
|
||||
const getAllDynamicRoute = async function () {
|
||||
const routes = await (async () => {
|
||||
return ['/posts/hello-world', '/posts/hello-again']
|
||||
})()
|
||||
return routes
|
||||
}
|
||||
|
||||
export default {
|
||||
mode: 'universal',
|
||||
generate: {
|
||||
async routes() {
|
||||
return getAllDynamicRoute()
|
||||
}
|
||||
}
|
||||
}
|
||||
2
src/fixtures/nuxt/blank.expected.js
Normal file
2
src/fixtures/nuxt/blank.expected.js
Normal file
@@ -0,0 +1,2 @@
|
||||
// Default Pages configuration for Nuxt
|
||||
export default { target: 'static', router: { base: '/docs/' } }
|
||||
1
src/fixtures/nuxt/blank.js
Normal file
1
src/fixtures/nuxt/blank.js
Normal file
@@ -0,0 +1 @@
|
||||
// This file is not read by the test suite
|
||||
37
src/fixtures/nuxt/default.cjs
Normal file
37
src/fixtures/nuxt/default.cjs
Normal file
@@ -0,0 +1,37 @@
|
||||
module.exports = {
|
||||
// Disable server-side rendering: https://go.nuxtjs.dev/ssr-mode
|
||||
ssr: false,
|
||||
|
||||
// Global page headers: https://go.nuxtjs.dev/config-head
|
||||
head: {
|
||||
title: 'nuxt',
|
||||
htmlAttrs: {
|
||||
lang: 'en'
|
||||
},
|
||||
meta: [
|
||||
{ charset: 'utf-8' },
|
||||
{ name: 'viewport', content: 'width=device-width, initial-scale=1' },
|
||||
{ hid: 'description', name: 'description', content: '' },
|
||||
{ name: 'format-detection', content: 'telephone=no' }
|
||||
],
|
||||
link: [{ rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' }]
|
||||
},
|
||||
|
||||
// Global CSS: https://go.nuxtjs.dev/config-css
|
||||
css: [],
|
||||
|
||||
// Plugins to run before rendering page: https://go.nuxtjs.dev/config-plugins
|
||||
plugins: [],
|
||||
|
||||
// Auto import components: https://go.nuxtjs.dev/config-components
|
||||
components: true,
|
||||
|
||||
// Modules for dev and build (recommended): https://go.nuxtjs.dev/config-modules
|
||||
buildModules: [],
|
||||
|
||||
// Modules: https://go.nuxtjs.dev/config-modules
|
||||
modules: [],
|
||||
|
||||
// Build Configuration: https://go.nuxtjs.dev/config-build
|
||||
build: {}
|
||||
}
|
||||
39
src/fixtures/nuxt/default.expected.cjs
Normal file
39
src/fixtures/nuxt/default.expected.cjs
Normal file
@@ -0,0 +1,39 @@
|
||||
module.exports = {
|
||||
// Disable server-side rendering: https://go.nuxtjs.dev/ssr-mode
|
||||
target: 'static',
|
||||
router: { base: '/docs/' },
|
||||
ssr: false,
|
||||
|
||||
// Global page headers: https://go.nuxtjs.dev/config-head
|
||||
head: {
|
||||
title: 'nuxt',
|
||||
htmlAttrs: {
|
||||
lang: 'en'
|
||||
},
|
||||
meta: [
|
||||
{ charset: 'utf-8' },
|
||||
{ name: 'viewport', content: 'width=device-width, initial-scale=1' },
|
||||
{ hid: 'description', name: 'description', content: '' },
|
||||
{ name: 'format-detection', content: 'telephone=no' }
|
||||
],
|
||||
link: [{ rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' }]
|
||||
},
|
||||
|
||||
// Global CSS: https://go.nuxtjs.dev/config-css
|
||||
css: [],
|
||||
|
||||
// Plugins to run before rendering page: https://go.nuxtjs.dev/config-plugins
|
||||
plugins: [],
|
||||
|
||||
// Auto import components: https://go.nuxtjs.dev/config-components
|
||||
components: true,
|
||||
|
||||
// Modules for dev and build (recommended): https://go.nuxtjs.dev/config-modules
|
||||
buildModules: [],
|
||||
|
||||
// Modules: https://go.nuxtjs.dev/config-modules
|
||||
modules: [],
|
||||
|
||||
// Build Configuration: https://go.nuxtjs.dev/config-build
|
||||
build: {}
|
||||
}
|
||||
39
src/fixtures/nuxt/default.expected.js
Normal file
39
src/fixtures/nuxt/default.expected.js
Normal file
@@ -0,0 +1,39 @@
|
||||
export default {
|
||||
// Disable server-side rendering: https://go.nuxtjs.dev/ssr-mode
|
||||
target: 'static',
|
||||
router: { base: '/docs/' },
|
||||
ssr: false,
|
||||
|
||||
// Global page headers: https://go.nuxtjs.dev/config-head
|
||||
head: {
|
||||
title: 'nuxt',
|
||||
htmlAttrs: {
|
||||
lang: 'en'
|
||||
},
|
||||
meta: [
|
||||
{ charset: 'utf-8' },
|
||||
{ name: 'viewport', content: 'width=device-width, initial-scale=1' },
|
||||
{ hid: 'description', name: 'description', content: '' },
|
||||
{ name: 'format-detection', content: 'telephone=no' }
|
||||
],
|
||||
link: [{ rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' }]
|
||||
},
|
||||
|
||||
// Global CSS: https://go.nuxtjs.dev/config-css
|
||||
css: [],
|
||||
|
||||
// Plugins to run before rendering page: https://go.nuxtjs.dev/config-plugins
|
||||
plugins: [],
|
||||
|
||||
// Auto import components: https://go.nuxtjs.dev/config-components
|
||||
components: true,
|
||||
|
||||
// Modules for dev and build (recommended): https://go.nuxtjs.dev/config-modules
|
||||
buildModules: [],
|
||||
|
||||
// Modules: https://go.nuxtjs.dev/config-modules
|
||||
modules: [],
|
||||
|
||||
// Build Configuration: https://go.nuxtjs.dev/config-build
|
||||
build: {}
|
||||
}
|
||||
39
src/fixtures/nuxt/default.expected.mjs
Normal file
39
src/fixtures/nuxt/default.expected.mjs
Normal file
@@ -0,0 +1,39 @@
|
||||
export default {
|
||||
// Disable server-side rendering: https://go.nuxtjs.dev/ssr-mode
|
||||
target: 'static',
|
||||
router: { base: '/docs/' },
|
||||
ssr: false,
|
||||
|
||||
// Global page headers: https://go.nuxtjs.dev/config-head
|
||||
head: {
|
||||
title: 'nuxt',
|
||||
htmlAttrs: {
|
||||
lang: 'en'
|
||||
},
|
||||
meta: [
|
||||
{ charset: 'utf-8' },
|
||||
{ name: 'viewport', content: 'width=device-width, initial-scale=1' },
|
||||
{ hid: 'description', name: 'description', content: '' },
|
||||
{ name: 'format-detection', content: 'telephone=no' }
|
||||
],
|
||||
link: [{ rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' }]
|
||||
},
|
||||
|
||||
// Global CSS: https://go.nuxtjs.dev/config-css
|
||||
css: [],
|
||||
|
||||
// Plugins to run before rendering page: https://go.nuxtjs.dev/config-plugins
|
||||
plugins: [],
|
||||
|
||||
// Auto import components: https://go.nuxtjs.dev/config-components
|
||||
components: true,
|
||||
|
||||
// Modules for dev and build (recommended): https://go.nuxtjs.dev/config-modules
|
||||
buildModules: [],
|
||||
|
||||
// Modules: https://go.nuxtjs.dev/config-modules
|
||||
modules: [],
|
||||
|
||||
// Build Configuration: https://go.nuxtjs.dev/config-build
|
||||
build: {}
|
||||
}
|
||||
37
src/fixtures/nuxt/default.js
Normal file
37
src/fixtures/nuxt/default.js
Normal file
@@ -0,0 +1,37 @@
|
||||
export default {
|
||||
// Disable server-side rendering: https://go.nuxtjs.dev/ssr-mode
|
||||
ssr: false,
|
||||
|
||||
// Global page headers: https://go.nuxtjs.dev/config-head
|
||||
head: {
|
||||
title: 'nuxt',
|
||||
htmlAttrs: {
|
||||
lang: 'en'
|
||||
},
|
||||
meta: [
|
||||
{ charset: 'utf-8' },
|
||||
{ name: 'viewport', content: 'width=device-width, initial-scale=1' },
|
||||
{ hid: 'description', name: 'description', content: '' },
|
||||
{ name: 'format-detection', content: 'telephone=no' }
|
||||
],
|
||||
link: [{ rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' }]
|
||||
},
|
||||
|
||||
// Global CSS: https://go.nuxtjs.dev/config-css
|
||||
css: [],
|
||||
|
||||
// Plugins to run before rendering page: https://go.nuxtjs.dev/config-plugins
|
||||
plugins: [],
|
||||
|
||||
// Auto import components: https://go.nuxtjs.dev/config-components
|
||||
components: true,
|
||||
|
||||
// Modules for dev and build (recommended): https://go.nuxtjs.dev/config-modules
|
||||
buildModules: [],
|
||||
|
||||
// Modules: https://go.nuxtjs.dev/config-modules
|
||||
modules: [],
|
||||
|
||||
// Build Configuration: https://go.nuxtjs.dev/config-build
|
||||
build: {}
|
||||
}
|
||||
37
src/fixtures/nuxt/default.mjs
Normal file
37
src/fixtures/nuxt/default.mjs
Normal file
@@ -0,0 +1,37 @@
|
||||
export default {
|
||||
// Disable server-side rendering: https://go.nuxtjs.dev/ssr-mode
|
||||
ssr: false,
|
||||
|
||||
// Global page headers: https://go.nuxtjs.dev/config-head
|
||||
head: {
|
||||
title: 'nuxt',
|
||||
htmlAttrs: {
|
||||
lang: 'en'
|
||||
},
|
||||
meta: [
|
||||
{ charset: 'utf-8' },
|
||||
{ name: 'viewport', content: 'width=device-width, initial-scale=1' },
|
||||
{ hid: 'description', name: 'description', content: '' },
|
||||
{ name: 'format-detection', content: 'telephone=no' }
|
||||
],
|
||||
link: [{ rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' }]
|
||||
},
|
||||
|
||||
// Global CSS: https://go.nuxtjs.dev/config-css
|
||||
css: [],
|
||||
|
||||
// Plugins to run before rendering page: https://go.nuxtjs.dev/config-plugins
|
||||
plugins: [],
|
||||
|
||||
// Auto import components: https://go.nuxtjs.dev/config-components
|
||||
components: true,
|
||||
|
||||
// Modules for dev and build (recommended): https://go.nuxtjs.dev/config-modules
|
||||
buildModules: [],
|
||||
|
||||
// Modules: https://go.nuxtjs.dev/config-modules
|
||||
modules: [],
|
||||
|
||||
// Build Configuration: https://go.nuxtjs.dev/config-build
|
||||
build: {}
|
||||
}
|
||||
10
src/fixtures/sveltekit/blank.expected.js
Normal file
10
src/fixtures/sveltekit/blank.expected.js
Normal file
@@ -0,0 +1,10 @@
|
||||
// Default Pages configuration for SvelteKit
|
||||
import adapter from '@sveltejs/adapter-auto'
|
||||
|
||||
export default {
|
||||
kit: {
|
||||
prerender: { origin: 'https://configure-pages.github.io' },
|
||||
paths: { base: '/docs' },
|
||||
adapter: adapter()
|
||||
}
|
||||
}
|
||||
1
src/fixtures/sveltekit/blank.js
Normal file
1
src/fixtures/sveltekit/blank.js
Normal file
@@ -0,0 +1 @@
|
||||
// This file is not read by the test suite
|
||||
12
src/fixtures/sveltekit/default.expected.js
Normal file
12
src/fixtures/sveltekit/default.expected.js
Normal file
@@ -0,0 +1,12 @@
|
||||
import adapter from '@sveltejs/adapter-auto'
|
||||
|
||||
/** @type {import('@sveltejs/kit').Config} */
|
||||
const config = {
|
||||
kit: {
|
||||
prerender: { origin: 'https://configure-pages.github.io' },
|
||||
paths: { base: '/docs' },
|
||||
adapter: adapter()
|
||||
}
|
||||
}
|
||||
|
||||
export default config
|
||||
10
src/fixtures/sveltekit/default.js
Normal file
10
src/fixtures/sveltekit/default.js
Normal file
@@ -0,0 +1,10 @@
|
||||
import adapter from '@sveltejs/adapter-auto'
|
||||
|
||||
/** @type {import('@sveltejs/kit').Config} */
|
||||
const config = {
|
||||
kit: {
|
||||
adapter: adapter()
|
||||
}
|
||||
}
|
||||
|
||||
export default config
|
||||
@@ -1,37 +0,0 @@
|
||||
const core = require('@actions/core')
|
||||
const axios = require('axios')
|
||||
const setPagesPath = require('./set-pages-path')
|
||||
|
||||
async function getPagesBaseUrl({ repositoryNwo, githubToken, staticSiteGenerator}) {
|
||||
try {
|
||||
const pagesEndpoint = `https://api.github.com/repos/${repositoryNwo}/pages`
|
||||
|
||||
core.info(`Get the Base URL to the page with endpoint ${pagesEndpoint}`)
|
||||
const response = await axios.get(
|
||||
pagesEndpoint,
|
||||
{
|
||||
headers: {
|
||||
Accept: 'application/vnd.github.v3+json',
|
||||
Authorization: `Bearer ${githubToken}`
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
pageObject = response.data
|
||||
core.info(JSON.stringify(pageObject))
|
||||
|
||||
const siteUrl = new URL(pageObject.html_url)
|
||||
if ( staticSiteGenerator ) {
|
||||
setPagesPath({staticSiteGenerator, path: siteUrl.pathname})
|
||||
}
|
||||
core.setOutput('base_url', siteUrl.href)
|
||||
core.setOutput('origin', siteUrl.origin)
|
||||
core.setOutput('host', siteUrl.host)
|
||||
core.setOutput('base_path', siteUrl.pathname)
|
||||
} catch (error) {
|
||||
core.error('Get on the Page failed', error)
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = getPagesBaseUrl
|
||||
23
src/index.js
23
src/index.js
@@ -1,22 +1,29 @@
|
||||
const core = require('@actions/core')
|
||||
|
||||
const enablePages = require('./enable-pages')
|
||||
const getPagesBaseUrl = require('./get-pages-base-url')
|
||||
|
||||
// All variables we need from the runtime are loaded here
|
||||
const getContext = require('./context')
|
||||
const { getContext } = require('./context')
|
||||
|
||||
const { findOrCreatePagesSite } = require('./api-client')
|
||||
const { setPagesConfig } = require('./set-pages-config')
|
||||
const outputPagesBaseUrl = require('./output-pages-base-url')
|
||||
|
||||
async function main() {
|
||||
try {
|
||||
const context = getContext()
|
||||
await enablePages(context)
|
||||
await getPagesBaseUrl(context)
|
||||
const { repositoryNwo, githubToken, enablement, staticSiteGenerator, generatorConfigFile } = getContext()
|
||||
|
||||
const pageObject = await findOrCreatePagesSite({ repositoryNwo, githubToken, enablement })
|
||||
const siteUrl = new URL(pageObject.html_url)
|
||||
|
||||
if (staticSiteGenerator) {
|
||||
setPagesConfig({ staticSiteGenerator, generatorConfigFile, siteUrl })
|
||||
}
|
||||
outputPagesBaseUrl(siteUrl)
|
||||
core.exportVariable('GITHUB_PAGES', 'true')
|
||||
} catch (error) {
|
||||
core.setFailed(error)
|
||||
process.exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Main
|
||||
main()
|
||||
|
||||
15
src/output-pages-base-url.js
Normal file
15
src/output-pages-base-url.js
Normal file
@@ -0,0 +1,15 @@
|
||||
const core = require('@actions/core')
|
||||
const removeTrailingSlash = require('./remove-trailing-slash')
|
||||
|
||||
function outputPagesBaseUrl(siteUrl) {
|
||||
// Many static site generators do not want the trailing slash, and it is much easier to add than remove in a workflow
|
||||
const baseUrl = removeTrailingSlash(siteUrl.href)
|
||||
const basePath = removeTrailingSlash(siteUrl.pathname)
|
||||
|
||||
core.setOutput('base_url', baseUrl)
|
||||
core.setOutput('origin', siteUrl.origin)
|
||||
core.setOutput('host', siteUrl.host)
|
||||
core.setOutput('base_path', basePath)
|
||||
}
|
||||
|
||||
module.exports = outputPagesBaseUrl
|
||||
@@ -1,17 +1,14 @@
|
||||
const core = require('@actions/core')
|
||||
const axios = require('axios')
|
||||
//const { expect, jest } = require('@jest/globals')
|
||||
|
||||
const getPagesBaseUrl = require('./get-pages-base-url')
|
||||
|
||||
describe('getPagesBaseUrl', () => {
|
||||
const GITHUB_REPOSITORY = 'paper-spa/is-awesome'
|
||||
const GITHUB_TOKEN = 'gha-token'
|
||||
const outputPagesBaseUrl = require('./output-pages-base-url')
|
||||
|
||||
describe('outputPagesBaseUrl', () => {
|
||||
beforeEach(() => {
|
||||
jest.restoreAllMocks()
|
||||
|
||||
jest.spyOn(core, 'setOutput').mockImplementation((key, value) => { key, value })
|
||||
jest.spyOn(core, 'setOutput').mockImplementation((key, value) => {
|
||||
key, value
|
||||
})
|
||||
jest.spyOn(core, 'setFailed').mockImplementation(param => param)
|
||||
|
||||
// Mock error/warning/info/debug
|
||||
@@ -24,45 +21,33 @@ describe('getPagesBaseUrl', () => {
|
||||
it('gets expected outputs for profile site', async () => {
|
||||
const baseUrl = 'https://octocat.github.io/'
|
||||
|
||||
jest
|
||||
.spyOn(axios, 'get')
|
||||
.mockImplementationOnce(() => Promise.resolve({ data: { html_url: baseUrl } }))
|
||||
outputPagesBaseUrl(new URL(baseUrl))
|
||||
|
||||
await getPagesBaseUrl({ repositoryNwo: GITHUB_REPOSITORY, githubToken: GITHUB_TOKEN })
|
||||
|
||||
expect(core.setOutput).toHaveBeenCalledWith('base_url', baseUrl)
|
||||
expect(core.setOutput).toHaveBeenCalledWith('base_url', 'https://octocat.github.io')
|
||||
expect(core.setOutput).toHaveBeenCalledWith('origin', 'https://octocat.github.io')
|
||||
expect(core.setOutput).toHaveBeenCalledWith('host', 'octocat.github.io')
|
||||
expect(core.setOutput).toHaveBeenCalledWith('base_path', '/')
|
||||
expect(core.setOutput).toHaveBeenCalledWith('base_path', '')
|
||||
})
|
||||
|
||||
it('gets expected outputs for project site', async () => {
|
||||
const baseUrl = 'https://octocat.github.io/my-repo/'
|
||||
|
||||
jest
|
||||
.spyOn(axios, 'get')
|
||||
.mockImplementationOnce(() => Promise.resolve({ data: { html_url: baseUrl } }))
|
||||
outputPagesBaseUrl(new URL(baseUrl))
|
||||
|
||||
await getPagesBaseUrl({ repositoryNwo: GITHUB_REPOSITORY, githubToken: GITHUB_TOKEN })
|
||||
|
||||
expect(core.setOutput).toHaveBeenCalledWith('base_url', baseUrl)
|
||||
expect(core.setOutput).toHaveBeenCalledWith('base_url', 'https://octocat.github.io/my-repo')
|
||||
expect(core.setOutput).toHaveBeenCalledWith('origin', 'https://octocat.github.io')
|
||||
expect(core.setOutput).toHaveBeenCalledWith('host', 'octocat.github.io')
|
||||
expect(core.setOutput).toHaveBeenCalledWith('base_path', '/my-repo/')
|
||||
expect(core.setOutput).toHaveBeenCalledWith('base_path', '/my-repo')
|
||||
})
|
||||
|
||||
it('gets expected outputs for site with custom domain name', async () => {
|
||||
const baseUrl = 'https://www.example.com/'
|
||||
|
||||
jest
|
||||
.spyOn(axios, 'get')
|
||||
.mockImplementationOnce(() => Promise.resolve({ data: { html_url: baseUrl } }))
|
||||
outputPagesBaseUrl(new URL(baseUrl))
|
||||
|
||||
await getPagesBaseUrl({ repositoryNwo: GITHUB_REPOSITORY, githubToken: GITHUB_TOKEN })
|
||||
|
||||
expect(core.setOutput).toHaveBeenCalledWith('base_url', baseUrl)
|
||||
expect(core.setOutput).toHaveBeenCalledWith('base_url', 'https://www.example.com')
|
||||
expect(core.setOutput).toHaveBeenCalledWith('origin', 'https://www.example.com')
|
||||
expect(core.setOutput).toHaveBeenCalledWith('host', 'www.example.com')
|
||||
expect(core.setOutput).toHaveBeenCalledWith('base_path', '/')
|
||||
expect(core.setOutput).toHaveBeenCalledWith('base_path', '')
|
||||
})
|
||||
})
|
||||
3
src/remove-trailing-slash.js
Normal file
3
src/remove-trailing-slash.js
Normal file
@@ -0,0 +1,3 @@
|
||||
module.exports = function removeTrailingSlash(str) {
|
||||
return str.endsWith('/') ? str.slice(0, -1) : str
|
||||
}
|
||||
100
src/set-pages-config.js
Normal file
100
src/set-pages-config.js
Normal file
@@ -0,0 +1,100 @@
|
||||
const core = require('@actions/core')
|
||||
const { ConfigParser } = require('./config-parser')
|
||||
const removeTrailingSlash = require('./remove-trailing-slash')
|
||||
|
||||
const SUPPORTED_FILE_EXTENSIONS = ['.js', '.cjs', '.mjs']
|
||||
|
||||
// Return the settings to be passed to a {ConfigParser} for a given static site generator,
|
||||
// optional configuration file path, and a Pages siteUrl value to inject
|
||||
function getConfigParserSettings({ staticSiteGenerator, generatorConfigFile, siteUrl }) {
|
||||
let { pathname: path, origin } = siteUrl
|
||||
|
||||
switch (staticSiteGenerator) {
|
||||
case 'nuxt':
|
||||
return {
|
||||
configurationFile: generatorConfigFile || './nuxt.config.js',
|
||||
blankConfigurationFile: `${__dirname}/blank-configurations/nuxt.js`,
|
||||
properties: {
|
||||
// Configure a base path on the router
|
||||
'router.base': path,
|
||||
|
||||
// Set the target to static too
|
||||
// https://nuxtjs.org/docs/configuration-glossary/configuration-target/
|
||||
target: 'static'
|
||||
}
|
||||
}
|
||||
case 'next':
|
||||
// Next does not want a trailing slash
|
||||
path = removeTrailingSlash(path)
|
||||
|
||||
return {
|
||||
configurationFile: generatorConfigFile || './next.config.js',
|
||||
blankConfigurationFile: `${__dirname}/blank-configurations/next.js`,
|
||||
properties: {
|
||||
// Configure a base path
|
||||
basePath: path,
|
||||
|
||||
// Disable server side image optimization too
|
||||
// https://nextjs.org/docs/api-reference/next/image#unoptimized
|
||||
'experimental.images.unoptimized': true,
|
||||
// No longer experimental as of Next.js v12.3.0
|
||||
'images.unoptimized': true
|
||||
}
|
||||
}
|
||||
case 'gatsby':
|
||||
return {
|
||||
configurationFile: generatorConfigFile || './gatsby-config.js',
|
||||
blankConfigurationFile: `${__dirname}/blank-configurations/gatsby.js`,
|
||||
properties: {
|
||||
// Configure a path prefix
|
||||
pathPrefix: path,
|
||||
// Configure a site url
|
||||
'siteMetadata.siteUrl': origin
|
||||
}
|
||||
}
|
||||
case 'sveltekit':
|
||||
// SvelteKit does not want a trailing slash
|
||||
path = removeTrailingSlash(path)
|
||||
|
||||
return {
|
||||
configurationFile: generatorConfigFile || './svelte.config.js',
|
||||
blankConfigurationFile: `${__dirname}/blank-configurations/sveltekit.js`,
|
||||
properties: {
|
||||
// Configure a base path
|
||||
'kit.paths.base': path,
|
||||
// Configure a prerender origin
|
||||
'kit.prerender.origin': origin
|
||||
}
|
||||
}
|
||||
default:
|
||||
throw `Unsupported static site generator: ${staticSiteGenerator}`
|
||||
}
|
||||
}
|
||||
|
||||
// Inject Pages configuration in a given static site generator's configuration file
|
||||
function setPagesConfig({ staticSiteGenerator, generatorConfigFile, siteUrl }) {
|
||||
try {
|
||||
// Parse the configuration file and try to inject the Pages configuration in it
|
||||
const settings = getConfigParserSettings({ staticSiteGenerator, generatorConfigFile, siteUrl })
|
||||
new ConfigParser(settings).injectAll()
|
||||
} catch (error) {
|
||||
const isSupportedFileExtension = SUPPORTED_FILE_EXTENSIONS.some(ext => generatorConfigFile.endsWith(ext))
|
||||
|
||||
// Logging
|
||||
if (!isSupportedFileExtension) {
|
||||
core.warning(
|
||||
`Unsupported configuration file extension. Currently supported extensions: ${SUPPORTED_FILE_EXTENSIONS.map(
|
||||
ext => JSON.stringify(ext)
|
||||
).join(', ')}`,
|
||||
error
|
||||
)
|
||||
} else {
|
||||
core.warning(
|
||||
`We were unable to determine how to inject the site metadata into your config. Generated URLs may be incorrect. The base URL for this site should be ${siteUrl}. Please ensure your framework is configured to generate relative links appropriately.`,
|
||||
error
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = { getConfigParserSettings, setPagesConfig }
|
||||
111
src/set-pages-config.test.js
Normal file
111
src/set-pages-config.test.js
Normal file
@@ -0,0 +1,111 @@
|
||||
const fs = require('fs')
|
||||
const path = require('path')
|
||||
const core = require('@actions/core')
|
||||
|
||||
const { setPagesConfig } = require('./set-pages-config')
|
||||
const { getTempFolder, compareFiles } = require('./test-helpers')
|
||||
|
||||
// Get the temp folder
|
||||
const tempFolder = getTempFolder()
|
||||
|
||||
const SUPPORTED_GENERATORS = ['next', 'nuxt', 'gatsby', 'sveltekit']
|
||||
const SUPPORTED_FILE_EXTENSIONS = ['.js', '.cjs', '.mjs']
|
||||
const IS_BLANK_CONFIG_FILE_REGEX = new RegExp(
|
||||
'^blank\\.(' + SUPPORTED_FILE_EXTENSIONS.map(ext => ext.slice(1)).join('|') + ')$'
|
||||
)
|
||||
|
||||
function isBlankConfigFileName(fileName) {
|
||||
return IS_BLANK_CONFIG_FILE_REGEX.test(fileName)
|
||||
}
|
||||
|
||||
// Test suite
|
||||
describe('configParser', () => {
|
||||
beforeEach(() => {
|
||||
jest.restoreAllMocks()
|
||||
|
||||
// Mock error/warning/info/debug to silence their output
|
||||
jest.spyOn(core, 'error').mockImplementation(jest.fn())
|
||||
jest.spyOn(core, 'warning').mockImplementation(jest.fn())
|
||||
jest.spyOn(core, 'info').mockImplementation(jest.fn())
|
||||
jest.spyOn(core, 'debug').mockImplementation(jest.fn())
|
||||
})
|
||||
|
||||
// Iterate over the static site generators
|
||||
SUPPORTED_GENERATORS.forEach(staticSiteGenerator => {
|
||||
// Folder containing the fixtures for a given static site generator
|
||||
const fixtureFolder = `${__dirname}/fixtures/${staticSiteGenerator}`
|
||||
|
||||
// Get fixture files, excluding expected results
|
||||
const configurationFiles = fs.readdirSync(fixtureFolder).filter(filename => !filename.includes('.expected.'))
|
||||
|
||||
// Create test siteUrl
|
||||
const siteUrl = new URL('https://configure-pages.github.io/docs/')
|
||||
|
||||
// Iterate over the fixtures, outputting to default configuration file path
|
||||
const defaultFileExtension = '.js'
|
||||
configurationFiles
|
||||
.filter(filename => filename.endsWith(defaultFileExtension))
|
||||
.forEach(configurationFile => {
|
||||
it(`injects path properly for ${staticSiteGenerator} in ${configurationFile} to default configuration file`, async () => {
|
||||
// Copy the source fixture to a temp file
|
||||
const fixtureSourceFile = `${fixtureFolder}/${configurationFile}`
|
||||
const fixtureTargetFile = `${tempFolder}/${configurationFile}`
|
||||
if (!isBlankConfigFileName(configurationFile)) {
|
||||
fs.copyFileSync(fixtureSourceFile, fixtureTargetFile)
|
||||
} else if (fs.existsSync(fixtureTargetFile)) {
|
||||
fs.rmSync(fixtureTargetFile)
|
||||
}
|
||||
|
||||
// Do the injections for the static site generator
|
||||
setPagesConfig({
|
||||
staticSiteGenerator,
|
||||
generatorConfigFile: fixtureTargetFile,
|
||||
siteUrl
|
||||
})
|
||||
|
||||
// Read the expected file
|
||||
const expectedFile = `${fixtureFolder}/${path.basename(
|
||||
configurationFile,
|
||||
defaultFileExtension
|
||||
)}.expected${defaultFileExtension}`
|
||||
|
||||
// Compare the actual and expected files
|
||||
compareFiles(fixtureTargetFile, expectedFile)
|
||||
})
|
||||
})
|
||||
|
||||
SUPPORTED_FILE_EXTENSIONS.forEach(fileExtension => {
|
||||
// Iterate over the fixtures, outputting to specified configuration file path
|
||||
configurationFiles
|
||||
.filter(filename => filename.endsWith(fileExtension))
|
||||
.forEach(configurationFile => {
|
||||
it(`injects path properly for ${staticSiteGenerator} in ${configurationFile} to specified *${fileExtension} configuration file`, async () => {
|
||||
// Copy the source fixture to a temp file
|
||||
const fixtureSourceFile = `${fixtureFolder}/${configurationFile}`
|
||||
const fixtureTargetFile = `${tempFolder}/${configurationFile}`
|
||||
if (!isBlankConfigFileName(configurationFile)) {
|
||||
fs.copyFileSync(fixtureSourceFile, fixtureTargetFile)
|
||||
} else if (fs.existsSync(fixtureTargetFile)) {
|
||||
fs.rmSync(fixtureTargetFile)
|
||||
}
|
||||
|
||||
// Do the injections for the static site generator
|
||||
setPagesConfig({
|
||||
staticSiteGenerator,
|
||||
generatorConfigFile: fixtureTargetFile,
|
||||
siteUrl
|
||||
})
|
||||
|
||||
// Read the expected file
|
||||
const expectedFile = `${fixtureFolder}/${path.basename(
|
||||
configurationFile,
|
||||
fileExtension
|
||||
)}.expected${fileExtension}`
|
||||
|
||||
// Compare the actual and expected files
|
||||
compareFiles(fixtureTargetFile, expectedFile)
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -1,46 +0,0 @@
|
||||
const core = require('@actions/core')
|
||||
const axios = require('axios')
|
||||
const { ConfigParser } = require('./config-parser')
|
||||
|
||||
async function setPagesPath({staticSiteGenerator, path}) {
|
||||
try {
|
||||
switch(staticSiteGenerator)
|
||||
{
|
||||
case 'nuxt':
|
||||
var ssConfig = {
|
||||
filePath:"./nuxt.config.js",
|
||||
type: "nuxt",
|
||||
pathName: "router",
|
||||
subPathName: "base",
|
||||
newPath: path
|
||||
}
|
||||
break;
|
||||
case 'next':
|
||||
var ssConfig = {
|
||||
filePath:"./next.config.js",
|
||||
type: "next",
|
||||
pathName: "basePath",
|
||||
newPath: path
|
||||
}
|
||||
break;
|
||||
case 'gatsby':
|
||||
var ssConfig = {
|
||||
filePath: "./gatsby-config.js",
|
||||
type: "gatsby",
|
||||
pathName: "pathPrefix",
|
||||
newPath: path
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw "Unknown config type"
|
||||
}
|
||||
|
||||
let configParser = new ConfigParser(ssConfig)
|
||||
configParser.parse()
|
||||
|
||||
} catch (error) {
|
||||
core.warning(`We were unable to determine how to inject the site metadata into your config. Generated URLs may be incorrect. The base URL for this site should be ${path}. Please ensure your framework is configured to generate relative links appropriately.`, error)
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = setPagesPath
|
||||
39
src/test-helpers.js
Normal file
39
src/test-helpers.js
Normal file
@@ -0,0 +1,39 @@
|
||||
const fs = require('fs')
|
||||
const prettier = require('prettier')
|
||||
const assert = require('assert')
|
||||
|
||||
// Create and return the path to a temp folder
|
||||
function getTempFolder() {
|
||||
const tmpFolder = `${__dirname}/fixtures/tmp`
|
||||
if (!fs.existsSync(tmpFolder)) {
|
||||
fs.mkdirSync(tmpFolder, { recursive: true })
|
||||
}
|
||||
return tmpFolder
|
||||
}
|
||||
|
||||
// Read a JavaScript file and return it formatted
|
||||
function formatFile(file) {
|
||||
const fileContent = fs.readFileSync(file, 'utf8')
|
||||
return prettier
|
||||
.format(fileContent, {
|
||||
parser: 'espree',
|
||||
|
||||
// Prettier options
|
||||
printWidth: 120,
|
||||
tabWidth: 2,
|
||||
useTabs: false,
|
||||
semi: false,
|
||||
singleQuote: true,
|
||||
trailingComma: 'none',
|
||||
bracketSpacing: true,
|
||||
arrowParens: 'avoid'
|
||||
})
|
||||
.trim()
|
||||
}
|
||||
|
||||
// Compare two JavaScript files
|
||||
function compareFiles(actualFile, expectedFile) {
|
||||
assert.equal(formatFile(actualFile), formatFile(expectedFile))
|
||||
}
|
||||
|
||||
module.exports = { getTempFolder, formatFile, compareFiles }
|
||||
Reference in New Issue
Block a user