37 Commits

Author SHA1 Message Date
James M. Greene
f71d3d08f0 Merge pull request #16 from AndrewLester/ssg-sveltekit
Add SvelteKit as an option for static_site_generator setting
2022-08-17 14:42:52 -05:00
James M. Greene
9ff7f29195 Update dist map 2022-08-17 14:41:47 -05:00
James M. Greene
9b7553ef7f Change environment variable data type to explicit string 2022-08-17 14:34:23 -05:00
AndrewLester
42451665cc Run prepare script 2022-08-10 16:28:32 -04:00
AndrewLester
adc528a6d8 Export GITHUB_PAGES env variable 2022-08-10 16:28:32 -04:00
AndrewLester
789c331a21 Support new features from #15 2022-08-10 16:28:32 -04:00
AndrewLester
ff1182a56a Add SvelteKit to action yml 2022-08-10 16:28:32 -04:00
AndrewLester
c872edcdfb Update config parser to support export default with identifier and add SvelteKit code
Co-authored-by: NatoBoram <natoboram@users.noreply.github.com>
2022-08-10 16:28:31 -04:00
James M. Greene
c61e34fb27 Merge pull request #12 from actions/better-docs
Improve a few contribution notes in the README
2022-08-10 14:19:56 -05:00
James M. Greene
a220556ffe Merge branch 'main' into better-docs 2022-08-10 14:10:38 -05:00
James M. Greene
491169de17 Revise release procedure 2022-08-10 14:10:15 -05:00
James M. Greene
f19391002a Merge pull request #17 from actions/marketplace-action-rename
Rename to include "GitHub" in "GitHub Pages" for Marketplace
2022-08-10 13:58:37 -05:00
James M. Greene
742be05113 Update action.yml 2022-08-10 12:52:41 -05:00
James M. Greene
90b7c04b80 Merge branch 'main' into better-docs 2022-08-10 10:00:39 -05:00
James M. Greene
15f519fab9 Merge pull request #15 from actions/ssg-config-file-input
Add support for specifying the SSG configuration file path
2022-08-10 09:18:00 -05:00
James M. Greene
f5b4063a62 Update distributables properly 2022-08-10 09:02:07 -05:00
James M. Greene
d06799dbbe Fix typo in dist 2022-08-10 08:57:37 -05:00
James M. Greene
fad78054b6 Fix typo in src 2022-08-10 08:56:12 -05:00
James M. Greene
64fa685553 Rebuild distributables 2022-08-09 11:23:03 -05:00
James M. Greene
891eba7f6e Update src/config-parser.js
Co-authored-by: Yoann Chaudet <yoannchaudet@github.com>
2022-08-09 11:22:14 -05:00
James M. Greene
9f6ed02477 Tweak the title and description in README 2022-08-08 11:15:41 -05:00
James M. Greene
68595d0746 Update distributables 2022-08-05 17:47:09 -05:00
James M. Greene
4f27d51853 Add support for indirect default export declarations 2022-08-05 17:44:40 -05:00
James M. Greene
1395534a78 Hoist important arrays to top-level constants 2022-08-05 17:37:00 -05:00
James M. Greene
7c3932ff89 Add support for specifying the target generator config file 2022-08-05 17:35:23 -05:00
James M. Greene
404d23c4a6 Merge pull request #13 from actions/prettier
Prettier formatting
2022-08-05 17:29:38 -05:00
James M. Greene
06406d74b2 Merge branch 'main' into prettier 2022-08-05 17:28:54 -05:00
James M. Greene
cc95980c79 Merge pull request #14 from actions/workflow-audit
Workflow audit
2022-08-05 17:28:32 -05:00
James M. Greene
4f84ed2a14 Add concurrency settings to PR-based workflows 2022-08-05 15:54:53 -05:00
James M. Greene
f19d25133d Ensure minimal permissions are explicit on all workflows 2022-08-05 15:54:15 -05:00
James M. Greene
f24e879a69 Add concurrency and permissions to workflow 2022-08-05 15:44:58 -05:00
James M. Greene
da85ca493f Update fixtures with Prettier formatting 2022-08-05 15:40:25 -05:00
James M. Greene
d949e1515f Rename Prettier config file extension for consistency 2022-08-05 15:39:17 -05:00
James M. Greene
c69bbc2c2c Fix one expected test fixture given Prettier configuration 2022-08-05 15:35:48 -05:00
James M. Greene
8441c1b1dc Improve a few contribution notes in the README 2022-08-05 15:29:09 -05:00
James M. Greene
4036d0f035 Add a workflow to verify Prettier formatting 2022-08-05 15:28:22 -05:00
James M. Greene
5c1535b807 Update all source files to match expected Prettier formatting 2022-08-05 15:26:05 -05:00
55 changed files with 741 additions and 244 deletions

View File

@@ -18,6 +18,11 @@ on:
permissions: permissions:
contents: read 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: jobs:
check-dist: check-dist:
runs-on: ubuntu-latest runs-on: ubuntu-latest

34
.github/workflows/check-formatting.yml vendored Normal file
View File

@@ -0,0 +1,34 @@
name: Checking 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
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: Verify formatting
run: npm run format:check

View File

@@ -4,6 +4,9 @@ on:
branches: branches:
- main - main
permissions:
contents: write
jobs: jobs:
draft-release: draft-release:
runs-on: ubuntu-latest runs-on: ubuntu-latest

View File

@@ -6,6 +6,14 @@ on:
- main - main
pull_request: 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: jobs:
test: test:
runs-on: ubuntu-latest runs-on: ubuntu-latest

View File

@@ -1,10 +1,10 @@
# Prettier (formatter) configuration # Prettier (formatter) configuration
--- ---
printWidth: 80 printWidth: 120
tabWidth: 2 tabWidth: 2
useTabs: false useTabs: false
semi: false semi: false
singleQuote: true singleQuote: true
trailingComma: none trailingComma: none
bracketSpacing: false bracketSpacing: true
arrowParens: avoid arrowParens: avoid

View File

@@ -1,8 +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-path.js`](./src/set-pages-path.js) for more details on how we configure static site generators to work "out of the box" with GitHub Pages. See [`set-pages-path.js`](src/set-pages-path.js) for more details on how we configure static site generators to work "out of the box" with GitHub Pages.
# Usage # Usage
@@ -12,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: 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 3. After publishing the release, the [`release` workflow][release] will automatically run to create/update the corresponding the major version tag such as `v0`.
git tag v0.1.0
git push origin v0.1.0
```
3. Publish the draft release (the major tag such as `v0` will be created/updated by the [`release` workflow][release]) ⚠️ Environment approval is required. Check the [Release workflow run list][release-workflow-runs].
⚠️ Environment approval is required.
# License # License
@@ -31,5 +26,7 @@ The scripts and documentation in this project are released under the [MIT Licens
<!-- references --> <!-- references -->
[starter-workflows]: https://github.com/actions/starter-workflows/tree/main/pages [starter-workflows]: https://github.com/actions/starter-workflows/tree/main/pages
[release-list]: /releases
[draft-release]: .github/workflows/draft-release.yml [draft-release]: .github/workflows/draft-release.yml
[release]: .github/workflows/release.yml [release]: .github/workflows/release.yml
[release-workflow-runs]: /actions/workflows/release.yml

View File

@@ -1,4 +1,4 @@
name: 'Configure Pages' name: 'Configure GitHub Pages'
description: 'A GitHub Action to enable Pages, extract various metadata about a site, and configure some supported static site generators.' description: 'A GitHub Action to enable Pages, extract various metadata about a site, and configure some supported static site generators.'
author: 'GitHub' author: 'GitHub'
runs: runs:
@@ -6,7 +6,10 @@ runs:
main: 'dist/index.js' main: 'dist/index.js'
inputs: inputs:
static_site_generator: 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 required: false
token: token:
description: 'GitHub token' description: 'GitHub token'

102
dist/index.js vendored
View File

@@ -14559,7 +14559,7 @@ class ConfigParser {
// Ctor // Ctor
// - configurationFile: path to the configuration file // - configurationFile: path to the configuration file
// - blankConfigurationFile: a blank configuration file to use if non was previously found // - blankConfigurationFile: a blank configuration file to use if non was previously found
constructor({configurationFile, blankConfigurationFile, properties}) { constructor({ configurationFile, blankConfigurationFile, properties }) {
// Save field // Save field
this.configurationFile = configurationFile this.configurationFile = configurationFile
this.properties = properties this.properties = properties
@@ -14584,16 +14584,32 @@ class ConfigParser {
// Return the configuration object or null. // Return the configuration object or null.
findConfigurationObject(ast) { findConfigurationObject(ast) {
// Try to find a default export // Try to find a default export
var defaultExport = ast.body.find( var defaultExport = ast.body.find(node => node.type === 'ExportDefaultDeclaration')
node =>
node.type === 'ExportDefaultDeclaration' && // Direct default export
node.declaration.type === 'ObjectExpression' if (defaultExport && defaultExport.declaration.type === 'ObjectExpression') {
) core.info('Found configuration object in direct default export declaration')
if (defaultExport) {
core.info('Found configuration object in default export declaration')
return defaultExport.declaration return defaultExport.declaration
} }
// Indirect default export
else if (defaultExport && defaultExport.declaration.type === 'Identifier') {
const identifierName = defaultExport.declaration.name
const identifierDefinition = ast.body.find(
node =>
node.type === 'VariableDeclaration' &&
node.declarations.length == 1 &&
node.declarations[0].type === 'VariableDeclarator' &&
node.declarations[0].id.type === 'Identifier' &&
node.declarations[0].id.name === identifierName &&
node.declarations[0].init.type === 'ObjectExpression'
)
if (identifierDefinition) {
core.info('Found configuration object in indirect default export declaration')
return identifierDefinition.declarations[0].init
}
}
// Try to find a module export // Try to find a module export
var moduleExport = ast.body.find( var moduleExport = ast.body.find(
node => node =>
@@ -14608,19 +14624,13 @@ class ConfigParser {
) )
// Direct module export // Direct module export
if ( if (moduleExport && moduleExport.expression.right.type === 'ObjectExpression') {
moduleExport &&
moduleExport.expression.right.type === 'ObjectExpression'
) {
core.info('Found configuration object in direct module export') core.info('Found configuration object in direct module export')
return moduleExport.expression.right return moduleExport.expression.right
} }
// Indirect module export // Indirect module export
else if ( else if (moduleExport && moduleExport.expression.right.type === 'Identifier') {
moduleExport &&
moduleExport.expression.right.type === 'Identifier'
) {
const identifierName = moduleExport && moduleExport.expression.right.name const identifierName = moduleExport && moduleExport.expression.right.name
const identifierDefinition = ast.body.find( const identifierDefinition = ast.body.find(
node => node =>
@@ -14648,9 +14658,7 @@ class ConfigParser {
// Try to find a property matching a given name // Try to find a property matching a given name
const property = const property =
object.type === 'ObjectExpression' && object.type === 'ObjectExpression' &&
object.properties.find( object.properties.find(node => node.key.type === 'Identifier' && node.key.name === name)
node => node.key.type === 'Identifier' && node.key.name === name
)
// Return the property's value (if found) or null // Return the property's value (if found) or null
if (property) { if (property) {
@@ -14670,9 +14678,7 @@ class ConfigParser {
return `${properties[startIndex]}: ${JSON.stringify(propertyValue)}` return `${properties[startIndex]}: ${JSON.stringify(propertyValue)}`
} else { } else {
return ( return (
`${properties[startIndex]}: {` + `${properties[startIndex]}: {` + this.getPropertyDeclaration(properties, startIndex + 1, propertyValue) + '}'
this.getPropertyDeclaration(properties, startIndex + 1, propertyValue) +
'}'
) )
} }
} }
@@ -14711,7 +14717,7 @@ class ConfigParser {
var depth = 0 var depth = 0
const properties = propertyName.split('.') const properties = propertyName.split('.')
var lastNode = configurationObject var lastNode = configurationObject
while (1) { while (true) {
// Find the node for the current property // Find the node for the current property
var propertyNode = this.findProperty(lastNode, properties[depth]) var propertyNode = this.findProperty(lastNode, properties[depth])
@@ -14750,11 +14756,7 @@ class ConfigParser {
// Create nested properties in the configuration file // Create nested properties in the configuration file
else { else {
// Build the declaration to inject // Build the declaration to inject
const declaration = this.getPropertyDeclaration( const declaration = this.getPropertyDeclaration(properties, depth, propertyValue)
properties,
depth,
propertyValue
)
// The last node identified is an object expression, so do the assignment // The last node identified is an object expression, so do the assignment
if (lastNode.type === 'ObjectExpression') { if (lastNode.type === 'ObjectExpression') {
@@ -14801,7 +14803,7 @@ class ConfigParser {
} }
} }
module.exports = {ConfigParser} module.exports = { ConfigParser }
/***/ }), /***/ }),
@@ -14817,6 +14819,7 @@ function getRequiredVars() {
repositoryNwo: process.env.GITHUB_REPOSITORY, repositoryNwo: process.env.GITHUB_REPOSITORY,
githubToken: core.getInput('token'), 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') !== 'false' enablement: core.getInput('enablement') !== 'false'
} }
} }
@@ -14833,7 +14836,7 @@ function getContext() {
return requiredVars return requiredVars
} }
module.exports = {getContext} module.exports = { getContext }
/***/ }), /***/ }),
@@ -14859,15 +14862,15 @@ module.exports = outputPagesBaseUrl
/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { /***/ ((module, __unused_webpack_exports, __nccwpck_require__) => {
const core = __nccwpck_require__(2186) const core = __nccwpck_require__(2186)
const {ConfigParser} = __nccwpck_require__(8395) const { ConfigParser } = __nccwpck_require__(8395)
// Return the settings to be passed to a {ConfigParser} for a given // Return the settings to be passed to a {ConfigParser} for a given static site generator,
// static site generator and a Pages path value to inject // optional configuration file path, and a Pages path value to inject
function getConfigParserSettings(staticSiteGenerator, path) { function getConfigParserSettings({ staticSiteGenerator, generatorConfigFile, path }) {
switch (staticSiteGenerator) { switch (staticSiteGenerator) {
case 'nuxt': case 'nuxt':
return { return {
configurationFile: './nuxt.config.js', configurationFile: generatorConfigFile || './nuxt.config.js',
blankConfigurationFile: __nccwpck_require__.ab + "nuxt.js", blankConfigurationFile: __nccwpck_require__.ab + "nuxt.js",
properties: { properties: {
// Configure a base path on the router // Configure a base path on the router
@@ -14885,7 +14888,7 @@ function getConfigParserSettings(staticSiteGenerator, path) {
} }
return { return {
configurationFile: './next.config.js', configurationFile: generatorConfigFile || './next.config.js',
blankConfigurationFile: __nccwpck_require__.ab + "next.js", blankConfigurationFile: __nccwpck_require__.ab + "next.js",
properties: { properties: {
// Configure a base path // Configure a base path
@@ -14898,23 +14901,37 @@ function getConfigParserSettings(staticSiteGenerator, path) {
} }
case 'gatsby': case 'gatsby':
return { return {
configurationFile: './gatsby-config.js', configurationFile: generatorConfigFile || './gatsby-config.js',
blankConfigurationFile: __nccwpck_require__.ab + "gatsby.js", blankConfigurationFile: __nccwpck_require__.ab + "gatsby.js",
properties: { properties: {
// Configure a path prefix // Configure a path prefix
pathPrefix: path pathPrefix: path
} }
} }
case 'sveltekit':
// SvelteKit does not want a trailing slash
if (path.endsWith('/')) {
path = path.slice(0, -1)
}
return {
configurationFile: generatorConfigFile || './svelte.config.js',
blankConfigurationFile: __nccwpck_require__.ab + "sveltekit.js",
properties: {
// Configure a base path
'kit.paths.base': path
}
}
default: default:
throw `Unsupported static site generator: ${staticSiteGenerator}` throw `Unsupported static site generator: ${staticSiteGenerator}`
} }
} }
// Inject Pages configuration in a given static site generator's configuration file // Inject Pages configuration in a given static site generator's configuration file
function setPagesPath({staticSiteGenerator, path}) { function setPagesPath({ staticSiteGenerator, generatorConfigFile, path }) {
try { try {
// Parse the configuration file and try to inject the Pages configuration in it // Parse the configuration file and try to inject the Pages configuration in it
const settings = getConfigParserSettings(staticSiteGenerator, path) const settings = getConfigParserSettings({ staticSiteGenerator, generatorConfigFile, path })
new ConfigParser(settings).injectAll() new ConfigParser(settings).injectAll()
} catch (error) { } catch (error) {
// Logging // Logging
@@ -14925,7 +14942,7 @@ function setPagesPath({staticSiteGenerator, path}) {
} }
} }
module.exports = {getConfigParserSettings, setPagesPath} module.exports = { getConfigParserSettings, setPagesPath }
/***/ }), /***/ }),
@@ -16417,15 +16434,16 @@ const outputPagesBaseUrl = __nccwpck_require__(7527)
async function main() { async function main() {
try { try {
const { repositoryNwo, githubToken, enablement, staticSiteGenerator } = getContext() const { repositoryNwo, githubToken, enablement, staticSiteGenerator, generatorConfigFile } = getContext()
const pageObject = await findOrCreatePagesSite({ repositoryNwo, githubToken, enablement }) const pageObject = await findOrCreatePagesSite({ repositoryNwo, githubToken, enablement })
const siteUrl = new URL(pageObject.html_url) const siteUrl = new URL(pageObject.html_url)
if (staticSiteGenerator) { if (staticSiteGenerator) {
setPagesPath({ staticSiteGenerator, path: siteUrl.pathname }) setPagesPath({ staticSiteGenerator, generatorConfigFile, path: siteUrl.pathname })
} }
outputPagesBaseUrl(siteUrl) outputPagesBaseUrl(siteUrl)
core.exportVariable('GITHUB_PAGES', 'true')
} catch (error) { } catch (error) {
core.setFailed(error) core.setFailed(error)
process.exit(1) process.exit(1)

2
dist/index.js.map vendored

File diff suppressed because one or more lines are too long

8
dist/sveltekit.js vendored Normal file
View File

@@ -0,0 +1,8 @@
// Default Pages configuration for SvelteKit
import adapter from '@sveltejs/adapter-auto'
export default {
kit: {
adapter: adapter()
}
}

View File

@@ -5,7 +5,9 @@
"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.", "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", "main": "./dist/index.js",
"scripts": { "scripts": {
"prepare": "ncc build src/index.js -o dist --source-map --license licenses.txt", "format": "prettier --write 'src/**/*.js'",
"format:check": "prettier --check 'src/**/*.js'",
"prepare": "npm run format && ncc build src/index.js -o dist --source-map --license licenses.txt",
"test": "jest" "test": "jest"
}, },
"repository": { "repository": {

View File

@@ -53,9 +53,7 @@ describe('apiClient', () => {
}) })
it('handles a 409 response when the page already exists', async () => { it('handles a 409 response when the page already exists', async () => {
jest jest.spyOn(axios, 'post').mockImplementationOnce(() => Promise.reject({ response: { status: 409 } }))
.spyOn(axios, 'post')
.mockImplementationOnce(() => Promise.reject({ response: { status: 409 } }))
// Simply assert that no error is raised // Simply assert that no error is raised
const result = await apiClient.enablePagesSite({ const result = await apiClient.enablePagesSite({
@@ -67,9 +65,7 @@ describe('apiClient', () => {
}) })
it('re-raises errors on failure status codes', async () => { it('re-raises errors on failure status codes', async () => {
jest jest.spyOn(axios, 'post').mockImplementationOnce(() => Promise.reject({ response: { status: 404 } }))
.spyOn(axios, 'post')
.mockImplementationOnce(() => Promise.reject({ response: { status: 404 } }))
let erred = false let erred = false
try { try {
@@ -98,9 +94,7 @@ describe('apiClient', () => {
}) })
it('re-raises errors on failure status codes', async () => { it('re-raises errors on failure status codes', async () => {
jest jest.spyOn(axios, 'get').mockImplementationOnce(() => Promise.reject({ response: { status: 404 } }))
.spyOn(axios, 'get')
.mockImplementationOnce(() => Promise.reject({ response: { status: 404 } }))
let erred = false let erred = false
try { try {
@@ -203,7 +197,8 @@ describe('apiClient', () => {
it('makes second request to get page if create fails because of existence', async () => { 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/' } const PAGE_OBJECT = { html_url: 'https://actions.github.io/is-awesome/' }
jest.spyOn(axios, 'get') jest
.spyOn(axios, 'get')
.mockImplementationOnce(() => Promise.reject({ response: { status: 404 } })) .mockImplementationOnce(() => Promise.reject({ response: { status: 404 } }))
.mockImplementationOnce(() => Promise.resolve({ status: 200, data: PAGE_OBJECT })) .mockImplementationOnce(() => Promise.resolve({ status: 200, data: PAGE_OBJECT }))
jest.spyOn(axios, 'post').mockImplementationOnce(() => Promise.reject({ response: { status: 409 } })) jest.spyOn(axios, 'post').mockImplementationOnce(() => Promise.reject({ response: { status: 409 } }))
@@ -217,5 +212,4 @@ describe('apiClient', () => {
expect(axios.post).toHaveBeenCalledTimes(1) expect(axios.post).toHaveBeenCalledTimes(1)
}) })
}) })
}) })

View File

@@ -0,0 +1,8 @@
// Default Pages configuration for SvelteKit
import adapter from '@sveltejs/adapter-auto'
export default {
kit: {
adapter: adapter()
}
}

View File

@@ -31,7 +31,7 @@ class ConfigParser {
// Ctor // Ctor
// - configurationFile: path to the configuration file // - configurationFile: path to the configuration file
// - blankConfigurationFile: a blank configuration file to use if non was previously found // - blankConfigurationFile: a blank configuration file to use if non was previously found
constructor({configurationFile, blankConfigurationFile, properties}) { constructor({ configurationFile, blankConfigurationFile, properties }) {
// Save field // Save field
this.configurationFile = configurationFile this.configurationFile = configurationFile
this.properties = properties this.properties = properties
@@ -56,16 +56,32 @@ class ConfigParser {
// Return the configuration object or null. // Return the configuration object or null.
findConfigurationObject(ast) { findConfigurationObject(ast) {
// Try to find a default export // Try to find a default export
var defaultExport = ast.body.find( var defaultExport = ast.body.find(node => node.type === 'ExportDefaultDeclaration')
node =>
node.type === 'ExportDefaultDeclaration' && // Direct default export
node.declaration.type === 'ObjectExpression' if (defaultExport && defaultExport.declaration.type === 'ObjectExpression') {
) core.info('Found configuration object in direct default export declaration')
if (defaultExport) {
core.info('Found configuration object in default export declaration')
return defaultExport.declaration return defaultExport.declaration
} }
// Indirect default export
else if (defaultExport && defaultExport.declaration.type === 'Identifier') {
const identifierName = defaultExport.declaration.name
const identifierDefinition = ast.body.find(
node =>
node.type === 'VariableDeclaration' &&
node.declarations.length == 1 &&
node.declarations[0].type === 'VariableDeclarator' &&
node.declarations[0].id.type === 'Identifier' &&
node.declarations[0].id.name === identifierName &&
node.declarations[0].init.type === 'ObjectExpression'
)
if (identifierDefinition) {
core.info('Found configuration object in indirect default export declaration')
return identifierDefinition.declarations[0].init
}
}
// Try to find a module export // Try to find a module export
var moduleExport = ast.body.find( var moduleExport = ast.body.find(
node => node =>
@@ -80,19 +96,13 @@ class ConfigParser {
) )
// Direct module export // Direct module export
if ( if (moduleExport && moduleExport.expression.right.type === 'ObjectExpression') {
moduleExport &&
moduleExport.expression.right.type === 'ObjectExpression'
) {
core.info('Found configuration object in direct module export') core.info('Found configuration object in direct module export')
return moduleExport.expression.right return moduleExport.expression.right
} }
// Indirect module export // Indirect module export
else if ( else if (moduleExport && moduleExport.expression.right.type === 'Identifier') {
moduleExport &&
moduleExport.expression.right.type === 'Identifier'
) {
const identifierName = moduleExport && moduleExport.expression.right.name const identifierName = moduleExport && moduleExport.expression.right.name
const identifierDefinition = ast.body.find( const identifierDefinition = ast.body.find(
node => node =>
@@ -120,9 +130,7 @@ class ConfigParser {
// Try to find a property matching a given name // Try to find a property matching a given name
const property = const property =
object.type === 'ObjectExpression' && object.type === 'ObjectExpression' &&
object.properties.find( object.properties.find(node => node.key.type === 'Identifier' && node.key.name === name)
node => node.key.type === 'Identifier' && node.key.name === name
)
// Return the property's value (if found) or null // Return the property's value (if found) or null
if (property) { if (property) {
@@ -142,9 +150,7 @@ class ConfigParser {
return `${properties[startIndex]}: ${JSON.stringify(propertyValue)}` return `${properties[startIndex]}: ${JSON.stringify(propertyValue)}`
} else { } else {
return ( return (
`${properties[startIndex]}: {` + `${properties[startIndex]}: {` + this.getPropertyDeclaration(properties, startIndex + 1, propertyValue) + '}'
this.getPropertyDeclaration(properties, startIndex + 1, propertyValue) +
'}'
) )
} }
} }
@@ -183,7 +189,7 @@ class ConfigParser {
var depth = 0 var depth = 0
const properties = propertyName.split('.') const properties = propertyName.split('.')
var lastNode = configurationObject var lastNode = configurationObject
while (1) { while (true) {
// Find the node for the current property // Find the node for the current property
var propertyNode = this.findProperty(lastNode, properties[depth]) var propertyNode = this.findProperty(lastNode, properties[depth])
@@ -222,11 +228,7 @@ class ConfigParser {
// Create nested properties in the configuration file // Create nested properties in the configuration file
else { else {
// Build the declaration to inject // Build the declaration to inject
const declaration = this.getPropertyDeclaration( const declaration = this.getPropertyDeclaration(properties, depth, propertyValue)
properties,
depth,
propertyValue
)
// The last node identified is an object expression, so do the assignment // The last node identified is an object expression, so do the assignment
if (lastNode.type === 'ObjectExpression') { if (lastNode.type === 'ObjectExpression') {
@@ -273,4 +275,4 @@ class ConfigParser {
} }
} }
module.exports = {ConfigParser} module.exports = { ConfigParser }

View File

@@ -1,7 +1,8 @@
const fs = require('fs') const fs = require('fs')
const core = require('@actions/core')
const {ConfigParser} = require('./config-parser') const { ConfigParser } = require('./config-parser')
const {getTempFolder, compareFiles} = require('./test-helpers') const { getTempFolder, compareFiles } = require('./test-helpers')
// Get the temp folder // Get the temp folder
const tempFolder = getTempFolder() const tempFolder = getTempFolder()
@@ -11,7 +12,6 @@ const cases = [
// //
// Default export // Default export
// //
{ {
property: 'property', property: 'property',
source: `export default {}`, source: `export default {}`,
@@ -89,6 +89,30 @@ const cases = [
expected: `export default { a2: false, a1: { a2: "value", a3: [12]}}` 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`
},
{
property: 'property',
source: `var config = {}; export default config`,
expected: `var config = { property: "value"}; export default config`
},
{
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 // Direct module exports
// //
@@ -134,15 +158,25 @@ const cases = [
] ]
describe('config-parser', () => { describe('config-parser', () => {
cases.forEach(({property, source, expected}, index) => { beforeEach(() => {
it(`Inject path properly for case #${index}`, () => { 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 }, index) => {
it(`injects path properly for case #${index}`, () => {
// Write the source file // Write the source file
const sourceFile = `${tempFolder}/source.js` const sourceFile = `${tempFolder}/source.js`
fs.writeFileSync(sourceFile, source, {encoding: 'utf8'}) fs.writeFileSync(sourceFile, source, { encoding: 'utf8' })
// Write the expected file // Write the expected file
const expectedFile = `${tempFolder}/expected.js` const expectedFile = `${tempFolder}/expected.js`
fs.writeFileSync(expectedFile, expected, {encoding: 'utf8'}) fs.writeFileSync(expectedFile, expected, { encoding: 'utf8' })
// Update the settings and do the injection // Update the settings and do the injection
new ConfigParser({ new ConfigParser({

View File

@@ -6,6 +6,7 @@ function getRequiredVars() {
repositoryNwo: process.env.GITHUB_REPOSITORY, repositoryNwo: process.env.GITHUB_REPOSITORY,
githubToken: core.getInput('token'), 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') !== 'false' enablement: core.getInput('enablement') !== 'false'
} }
} }
@@ -22,4 +23,4 @@ function getContext() {
return requiredVars return requiredVars
} }
module.exports = {getContext} module.exports = { getContext }

View File

@@ -1,2 +1,2 @@
// Default Pages configuration for Gatsby // Default Pages configuration for Gatsby
module.exports = { pathPrefix: "/docs/" } module.exports = { pathPrefix: '/docs/' }

View File

@@ -0,0 +1,7 @@
module.exports = {
siteMetadata: {
title: `My Gatsby Site`,
siteUrl: `https://www.yourdomain.tld`,
},
plugins: [],
}

View File

@@ -0,0 +1,8 @@
module.exports = {
pathPrefix: "/docs/",
siteMetadata: {
title: `My Gatsby Site`,
siteUrl: `https://www.yourdomain.tld`,
},
plugins: [],
}

View File

@@ -1,8 +1,8 @@
module.exports = { module.exports = {
pathPrefix: "/docs/", pathPrefix: '/docs/',
siteMetadata: { siteMetadata: {
title: `My Gatsby Site`, title: `My Gatsby Site`,
siteUrl: `https://www.yourdomain.tld`, siteUrl: `https://www.yourdomain.tld`
}, },
plugins: [], plugins: []
} }

View File

@@ -0,0 +1,8 @@
export default {
pathPrefix: "/docs/",
siteMetadata: {
title: `My Gatsby Site`,
siteUrl: `https://www.yourdomain.tld`,
},
plugins: [],
}

View File

@@ -1,7 +1,7 @@
module.exports = { module.exports = {
siteMetadata: { siteMetadata: {
title: `My Gatsby Site`, title: `My Gatsby Site`,
siteUrl: `https://www.yourdomain.tld`, siteUrl: `https://www.yourdomain.tld`
}, },
plugins: [], plugins: []
} }

View File

@@ -0,0 +1,7 @@
export default {
siteMetadata: {
title: `My Gatsby Site`,
siteUrl: `https://www.yourdomain.tld`,
},
plugins: [],
}

View File

@@ -1,6 +1,3 @@
// Default Pages configuration for Next // Default Pages configuration for Next
const nextConfig = { const nextConfig = { experimental: { images: { unoptimized: true } }, basePath: '/docs' }
experimental: {images: {unoptimized: true}},
basePath: '/docs'
}
module.exports = nextConfig module.exports = nextConfig

View File

@@ -0,0 +1,7 @@
/** @type {import('next').NextConfig} */
const nextConfig = {
reactStrictMode: true,
swcMinify: true,
}
module.exports = nextConfig

View File

@@ -0,0 +1,9 @@
/** @type {import('next').NextConfig} */
const nextConfig = {
experimental: {images: {unoptimized: true}},
basePath: '/docs',
reactStrictMode: true,
swcMinify: true
}
module.exports = nextConfig

View File

@@ -1,6 +1,6 @@
/** @type {import('next').NextConfig} */ /** @type {import('next').NextConfig} */
const nextConfig = { const nextConfig = {
experimental: {images: {unoptimized: true}}, experimental: { images: { unoptimized: true } },
basePath: '/docs', basePath: '/docs',
reactStrictMode: true, reactStrictMode: true,
swcMinify: true swcMinify: true

View File

@@ -0,0 +1,9 @@
/** @type {import('next').NextConfig} */
const nextConfig = {
experimental: {images: {unoptimized: true}},
basePath: '/docs',
reactStrictMode: true,
swcMinify: true
}
export default nextConfig

View File

@@ -1,7 +1,7 @@
/** @type {import('next').NextConfig} */ /** @type {import('next').NextConfig} */
const nextConfig = { const nextConfig = {
reactStrictMode: true, reactStrictMode: true,
swcMinify: true, swcMinify: true
} }
module.exports = nextConfig module.exports = nextConfig

View File

@@ -0,0 +1,7 @@
/** @type {import('next').NextConfig} */
const nextConfig = {
reactStrictMode: true,
swcMinify: true,
}
export default nextConfig

View 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();
}
}
};

View 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();
}
}
};

View File

@@ -1,17 +1,17 @@
const getAllDynamicRoute = async function() { const getAllDynamicRoute = async function () {
const routes = await (async () => { const routes = await (async () => {
return ['/posts/hello-world', '/posts/hello-again']; return ['/posts/hello-world', '/posts/hello-again']
})(); })()
return routes; return routes
}; }
export default { export default {
target: 'static', target: 'static',
router: {base: '/docs/'}, router: { base: '/docs/' },
mode: 'universal', mode: 'universal',
generate: { generate: {
async routes () { async routes() {
return getAllDynamicRoute(); return getAllDynamicRoute()
} }
} }
}; }

View 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();
}
}
};

View File

@@ -1,15 +1,15 @@
const getAllDynamicRoute = async function() { const getAllDynamicRoute = async function () {
const routes = await (async () => { const routes = await (async () => {
return ['/posts/hello-world', '/posts/hello-again']; return ['/posts/hello-world', '/posts/hello-again']
})(); })()
return routes; return routes
}; }
export default { export default {
mode: 'universal', mode: 'universal',
generate: { generate: {
async routes () { async routes() {
return getAllDynamicRoute(); return getAllDynamicRoute()
} }
} }
}; }

View 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();
}
}
};

View File

@@ -1,2 +1,2 @@
// Default Pages configuration for Nuxt // Default Pages configuration for Nuxt
export default {target: 'static', router: {base: '/docs/'}} export default { target: 'static', router: { base: '/docs/' } }

View File

@@ -0,0 +1,44 @@
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: {
}
}

View File

@@ -0,0 +1,46 @@
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: {
}
}

View File

@@ -1,7 +1,7 @@
export default { export default {
// Disable server-side rendering: https://go.nuxtjs.dev/ssr-mode // Disable server-side rendering: https://go.nuxtjs.dev/ssr-mode
target: 'static', target: 'static',
router: { base: "/docs/" }, router: { base: '/docs/' },
ssr: false, ssr: false,
// Global page headers: https://go.nuxtjs.dev/config-head // Global page headers: https://go.nuxtjs.dev/config-head
@@ -16,31 +16,24 @@ export default {
{ hid: 'description', name: 'description', content: '' }, { hid: 'description', name: 'description', content: '' },
{ name: 'format-detection', content: 'telephone=no' } { name: 'format-detection', content: 'telephone=no' }
], ],
link: [ link: [{ rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' }]
{ rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' }
]
}, },
// Global CSS: https://go.nuxtjs.dev/config-css // Global CSS: https://go.nuxtjs.dev/config-css
css: [ css: [],
],
// Plugins to run before rendering page: https://go.nuxtjs.dev/config-plugins // Plugins to run before rendering page: https://go.nuxtjs.dev/config-plugins
plugins: [ plugins: [],
],
// Auto import components: https://go.nuxtjs.dev/config-components // Auto import components: https://go.nuxtjs.dev/config-components
components: true, components: true,
// Modules for dev and build (recommended): https://go.nuxtjs.dev/config-modules // Modules for dev and build (recommended): https://go.nuxtjs.dev/config-modules
buildModules: [ buildModules: [],
],
// Modules: https://go.nuxtjs.dev/config-modules // Modules: https://go.nuxtjs.dev/config-modules
modules: [ modules: [],
],
// Build Configuration: https://go.nuxtjs.dev/config-build // Build Configuration: https://go.nuxtjs.dev/config-build
build: { build: {}
}
} }

View File

@@ -0,0 +1,46 @@
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: {
}
}

View File

@@ -14,31 +14,24 @@ export default {
{ hid: 'description', name: 'description', content: '' }, { hid: 'description', name: 'description', content: '' },
{ name: 'format-detection', content: 'telephone=no' } { name: 'format-detection', content: 'telephone=no' }
], ],
link: [ link: [{ rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' }]
{ rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' }
]
}, },
// Global CSS: https://go.nuxtjs.dev/config-css // Global CSS: https://go.nuxtjs.dev/config-css
css: [ css: [],
],
// Plugins to run before rendering page: https://go.nuxtjs.dev/config-plugins // Plugins to run before rendering page: https://go.nuxtjs.dev/config-plugins
plugins: [ plugins: [],
],
// Auto import components: https://go.nuxtjs.dev/config-components // Auto import components: https://go.nuxtjs.dev/config-components
components: true, components: true,
// Modules for dev and build (recommended): https://go.nuxtjs.dev/config-modules // Modules for dev and build (recommended): https://go.nuxtjs.dev/config-modules
buildModules: [ buildModules: [],
],
// Modules: https://go.nuxtjs.dev/config-modules // Modules: https://go.nuxtjs.dev/config-modules
modules: [ modules: [],
],
// Build Configuration: https://go.nuxtjs.dev/config-build // Build Configuration: https://go.nuxtjs.dev/config-build
build: { build: {}
}
} }

View File

@@ -0,0 +1,44 @@
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: {
}
}

View File

@@ -0,0 +1,9 @@
// Default Pages configuration for SvelteKit
import adapter from '@sveltejs/adapter-auto'
export default {
kit: {
paths: { base: '/docs' },
adapter: adapter()
}
}

View File

@@ -0,0 +1 @@
// This file is not read by the test suite

View File

@@ -0,0 +1,11 @@
import adapter from '@sveltejs/adapter-auto'
/** @type {import('@sveltejs/kit').Config} */
const config = {
kit: {
paths: { base: '/docs' },
adapter: adapter()
}
}
export default config

View File

@@ -0,0 +1,10 @@
import adapter from '@sveltejs/adapter-auto'
/** @type {import('@sveltejs/kit').Config} */
const config = {
kit: {
adapter: adapter()
}
}
export default config

View File

@@ -9,15 +9,16 @@ const outputPagesBaseUrl = require('./output-pages-base-url')
async function main() { async function main() {
try { try {
const { repositoryNwo, githubToken, enablement, staticSiteGenerator } = getContext() const { repositoryNwo, githubToken, enablement, staticSiteGenerator, generatorConfigFile } = getContext()
const pageObject = await findOrCreatePagesSite({ repositoryNwo, githubToken, enablement }) const pageObject = await findOrCreatePagesSite({ repositoryNwo, githubToken, enablement })
const siteUrl = new URL(pageObject.html_url) const siteUrl = new URL(pageObject.html_url)
if (staticSiteGenerator) { if (staticSiteGenerator) {
setPagesPath({ staticSiteGenerator, path: siteUrl.pathname }) setPagesPath({ staticSiteGenerator, generatorConfigFile, path: siteUrl.pathname })
} }
outputPagesBaseUrl(siteUrl) outputPagesBaseUrl(siteUrl)
core.exportVariable('GITHUB_PAGES', 'true')
} catch (error) { } catch (error) {
core.setFailed(error) core.setFailed(error)
process.exit(1) process.exit(1)

View File

@@ -24,10 +24,7 @@ describe('outputPagesBaseUrl', () => {
outputPagesBaseUrl(new URL(baseUrl)) outputPagesBaseUrl(new URL(baseUrl))
expect(core.setOutput).toHaveBeenCalledWith('base_url', baseUrl) expect(core.setOutput).toHaveBeenCalledWith('base_url', baseUrl)
expect(core.setOutput).toHaveBeenCalledWith( expect(core.setOutput).toHaveBeenCalledWith('origin', 'https://octocat.github.io')
'origin',
'https://octocat.github.io'
)
expect(core.setOutput).toHaveBeenCalledWith('host', 'octocat.github.io') expect(core.setOutput).toHaveBeenCalledWith('host', 'octocat.github.io')
expect(core.setOutput).toHaveBeenCalledWith('base_path', '/') expect(core.setOutput).toHaveBeenCalledWith('base_path', '/')
}) })
@@ -38,10 +35,7 @@ describe('outputPagesBaseUrl', () => {
outputPagesBaseUrl(new URL(baseUrl)) outputPagesBaseUrl(new URL(baseUrl))
expect(core.setOutput).toHaveBeenCalledWith('base_url', baseUrl) expect(core.setOutput).toHaveBeenCalledWith('base_url', baseUrl)
expect(core.setOutput).toHaveBeenCalledWith( expect(core.setOutput).toHaveBeenCalledWith('origin', 'https://octocat.github.io')
'origin',
'https://octocat.github.io'
)
expect(core.setOutput).toHaveBeenCalledWith('host', '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/')
}) })
@@ -52,10 +46,7 @@ describe('outputPagesBaseUrl', () => {
outputPagesBaseUrl(new URL(baseUrl)) outputPagesBaseUrl(new URL(baseUrl))
expect(core.setOutput).toHaveBeenCalledWith('base_url', baseUrl) expect(core.setOutput).toHaveBeenCalledWith('base_url', baseUrl)
expect(core.setOutput).toHaveBeenCalledWith( expect(core.setOutput).toHaveBeenCalledWith('origin', 'https://www.example.com')
'origin',
'https://www.example.com'
)
expect(core.setOutput).toHaveBeenCalledWith('host', 'www.example.com') expect(core.setOutput).toHaveBeenCalledWith('host', 'www.example.com')
expect(core.setOutput).toHaveBeenCalledWith('base_path', '/') expect(core.setOutput).toHaveBeenCalledWith('base_path', '/')
}) })

View File

@@ -1,13 +1,13 @@
const core = require('@actions/core') const core = require('@actions/core')
const {ConfigParser} = require('./config-parser') const { ConfigParser } = require('./config-parser')
// Return the settings to be passed to a {ConfigParser} for a given // Return the settings to be passed to a {ConfigParser} for a given static site generator,
// static site generator and a Pages path value to inject // optional configuration file path, and a Pages path value to inject
function getConfigParserSettings(staticSiteGenerator, path) { function getConfigParserSettings({ staticSiteGenerator, generatorConfigFile, path }) {
switch (staticSiteGenerator) { switch (staticSiteGenerator) {
case 'nuxt': case 'nuxt':
return { return {
configurationFile: './nuxt.config.js', configurationFile: generatorConfigFile || './nuxt.config.js',
blankConfigurationFile: `${__dirname}/blank-configurations/nuxt.js`, blankConfigurationFile: `${__dirname}/blank-configurations/nuxt.js`,
properties: { properties: {
// Configure a base path on the router // Configure a base path on the router
@@ -25,7 +25,7 @@ function getConfigParserSettings(staticSiteGenerator, path) {
} }
return { return {
configurationFile: './next.config.js', configurationFile: generatorConfigFile || './next.config.js',
blankConfigurationFile: `${__dirname}/blank-configurations/next.js`, blankConfigurationFile: `${__dirname}/blank-configurations/next.js`,
properties: { properties: {
// Configure a base path // Configure a base path
@@ -38,23 +38,37 @@ function getConfigParserSettings(staticSiteGenerator, path) {
} }
case 'gatsby': case 'gatsby':
return { return {
configurationFile: './gatsby-config.js', configurationFile: generatorConfigFile || './gatsby-config.js',
blankConfigurationFile: `${__dirname}/blank-configurations/gatsby.js`, blankConfigurationFile: `${__dirname}/blank-configurations/gatsby.js`,
properties: { properties: {
// Configure a path prefix // Configure a path prefix
pathPrefix: path pathPrefix: path
} }
} }
case 'sveltekit':
// SvelteKit does not want a trailing slash
if (path.endsWith('/')) {
path = path.slice(0, -1)
}
return {
configurationFile: generatorConfigFile || './svelte.config.js',
blankConfigurationFile: `${__dirname}/blank-configurations/sveltekit.js`,
properties: {
// Configure a base path
'kit.paths.base': path
}
}
default: default:
throw `Unsupported static site generator: ${staticSiteGenerator}` throw `Unsupported static site generator: ${staticSiteGenerator}`
} }
} }
// Inject Pages configuration in a given static site generator's configuration file // Inject Pages configuration in a given static site generator's configuration file
function setPagesPath({staticSiteGenerator, path}) { function setPagesPath({ staticSiteGenerator, generatorConfigFile, path }) {
try { try {
// Parse the configuration file and try to inject the Pages configuration in it // Parse the configuration file and try to inject the Pages configuration in it
const settings = getConfigParserSettings(staticSiteGenerator, path) const settings = getConfigParserSettings({ staticSiteGenerator, generatorConfigFile, path })
new ConfigParser(settings).injectAll() new ConfigParser(settings).injectAll()
} catch (error) { } catch (error) {
// Logging // Logging
@@ -65,4 +79,4 @@ function setPagesPath({staticSiteGenerator, path}) {
} }
} }
module.exports = {getConfigParserSettings, setPagesPath} module.exports = { getConfigParserSettings, setPagesPath }

View File

@@ -1,53 +1,105 @@
const fs = require('fs') const fs = require('fs')
const path = require('path') const path = require('path')
const core = require('@actions/core')
const {getConfigParserSettings} = require('./set-pages-path') const { getConfigParserSettings } = require('./set-pages-path')
const {ConfigParser} = require('./config-parser') const { ConfigParser } = require('./config-parser')
const {getTempFolder, compareFiles} = require('./test-helpers') const { getTempFolder, compareFiles } = require('./test-helpers')
// Get the temp folder // Get the temp folder
const tempFolder = getTempFolder() const tempFolder = getTempFolder()
const SUPPORTED_GENERATORS = ['next', 'nuxt', 'gatsby', 'sveltekit']
const SUPPORTED_FILE_EXTENSIONS = ['.js', '.cjs', '.mjs']
// Test suite // Test suite
describe('configParser', () => { 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 // Iterate over the static site generators
;['next', 'nuxt', 'gatsby'].forEach(staticSiteGenerator => { SUPPORTED_GENERATORS.forEach(staticSiteGenerator => {
// Folder containing the fixtures for a given static site generator // Folder containing the fixtures for a given static site generator
const fixtureFolder = `${__dirname}/fixtures/${staticSiteGenerator}` const fixtureFolder = `${__dirname}/fixtures/${staticSiteGenerator}`
// Iterate over the fixtures // Get fixture files, excluding expected results
fs.readdirSync(fixtureFolder).forEach(configurationFile => { const configurationFiles = fs.readdirSync(fixtureFolder).filter(filename => !filename.includes('.expected.'))
// Ignore expectation
if (configurationFile.endsWith('.expected.js')) {
return
}
it(`Inject path properly for ${staticSiteGenerator} in ${configurationFile}`, async () => { // Iterate over the fixtures, outputting to default configuration file path
// Get settings for the static site generator const defaultFileExtension = '.js'
const settings = getConfigParserSettings(staticSiteGenerator, '/docs/') 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 (configurationFile !== 'blank.js') {
fs.copyFileSync(fixtureSourceFile, fixtureTargetFile)
} else if (fs.existsSync(fixtureTargetFile)) {
fs.rmSync(fixtureTargetFile)
}
// Copy the source fixture to a temp file // Get settings for the static site generator
const fixtureSourceFile = `${fixtureFolder}/${configurationFile}` const settings = getConfigParserSettings({ staticSiteGenerator, path: '/docs/' })
const fixtureTargetFile = `${tempFolder}/${configurationFile}` // Update the settings
if (configurationFile != 'blank.js') { settings.configurationFile = fixtureTargetFile
fs.copyFileSync(fixtureSourceFile, fixtureTargetFile) // Do the injection
} else if (fs.existsSync(fixtureTargetFile)) { new ConfigParser(settings).injectAll()
fs.rmSync(fixtureTargetFile)
}
// Update the settings and do the injection // Read the expected file
settings.configurationFile = fixtureTargetFile const expectedFile = `${fixtureFolder}/${path.basename(
new ConfigParser(settings).injectAll() configurationFile,
defaultFileExtension
)}.expected${defaultFileExtension}`
// Read the expected file // Compare the actual and expected files
const expectedFile = `${fixtureFolder}/${path.basename( compareFiles(settings.configurationFile, expectedFile)
configurationFile, })
'.js'
)}.expected.js`
// Compare the actual and expected files
compareFiles(settings.configurationFile, 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 (configurationFile !== 'blank.js') {
fs.copyFileSync(fixtureSourceFile, fixtureTargetFile)
} else if (fs.existsSync(fixtureTargetFile)) {
fs.rmSync(fixtureTargetFile)
}
// Get settings for the static site generator
const settings = getConfigParserSettings({
staticSiteGenerator,
generatorConfigFile: fixtureTargetFile,
path: '/docs/'
})
// Do the injection
new ConfigParser(settings).injectAll()
// Read the expected file
const expectedFile = `${fixtureFolder}/${path.basename(
configurationFile,
fileExtension
)}.expected${fileExtension}`
// Compare the actual and expected files
compareFiles(settings.configurationFile, expectedFile)
})
})
}) })
}) })
}) })

View File

@@ -6,7 +6,7 @@ const assert = require('assert')
function getTempFolder() { function getTempFolder() {
const tmpFolder = `${__dirname}/fixtures/tmp` const tmpFolder = `${__dirname}/fixtures/tmp`
if (!fs.existsSync(tmpFolder)) { if (!fs.existsSync(tmpFolder)) {
fs.mkdirSync(tmpFolder, {recursive: true}) fs.mkdirSync(tmpFolder, { recursive: true })
} }
return tmpFolder return tmpFolder
} }
@@ -14,19 +14,21 @@ function getTempFolder() {
// Read a JavaScript file and return it formatted // Read a JavaScript file and return it formatted
function formatFile(file) { function formatFile(file) {
const fileContent = fs.readFileSync(file, 'utf8') const fileContent = fs.readFileSync(file, 'utf8')
return prettier.format(fileContent, { return prettier
parser: 'espree', .format(fileContent, {
parser: 'espree',
// Prettier options // Prettier options
printWidth: 80, printWidth: 120,
tabWidth: 2, tabWidth: 2,
useTabs: false, useTabs: false,
semi: false, semi: false,
singleQuote: true, singleQuote: true,
trailingComma: 'none', trailingComma: 'none',
bracketSpacing: false, bracketSpacing: true,
arrowParens: 'avoid' arrowParens: 'avoid'
}).trim() })
.trim()
} }
// Compare two JavaScript files // Compare two JavaScript files
@@ -34,4 +36,4 @@ function compareFiles(actualFile, expectedFile) {
assert.equal(formatFile(actualFile), formatFile(expectedFile)) assert.equal(formatFile(actualFile), formatFile(expectedFile))
} }
module.exports = {getTempFolder, formatFile, compareFiles} module.exports = { getTempFolder, formatFile, compareFiles }