diff --git a/action.yml b/action.yml index 7e1cdfa..97b9deb 100644 --- a/action.yml +++ b/action.yml @@ -6,7 +6,10 @@ runs: 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", or "gatsby"' + required: false + generator_config_file: + description: 'Optional file path to static site generator configuration file' required: false token: description: 'GitHub token' diff --git a/src/config-parser.js b/src/config-parser.js index 8b779ec..51e5e4c 100644 --- a/src/config-parser.js +++ b/src/config-parser.js @@ -171,7 +171,7 @@ class ConfigParser { var depth = 0 const properties = propertyName.split('.') var lastNode = configurationObject - while (1) { + while (true) { // Find the node for the current property var propertyNode = this.findProperty(lastNode, properties[depth]) diff --git a/src/config-parser.test.js b/src/config-parser.test.js index d7433f0..830a88e 100644 --- a/src/config-parser.test.js +++ b/src/config-parser.test.js @@ -1,4 +1,5 @@ const fs = require('fs') +const core = require('@actions/core') const { ConfigParser } = require('./config-parser') const { getTempFolder, compareFiles } = require('./test-helpers') @@ -134,8 +135,18 @@ const cases = [ ] 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 }, index) => { - it(`Inject path properly for case #${index}`, () => { + it(`injects path properly for case #${index}`, () => { // Write the source file const sourceFile = `${tempFolder}/source.js` fs.writeFileSync(sourceFile, source, { encoding: 'utf8' }) diff --git a/src/context.js b/src/context.js index d036c37..6dc0787 100644 --- a/src/context.js +++ b/src/context.js @@ -6,6 +6,7 @@ function getRequiredVars() { repositoryNwo: process.env.GITHUB_REPOSITORY, githubToken: core.getInput('token'), staticSiteGenerator: core.getInput('static_site_generator'), + generatorConfigFile: core.getInput('generator_config_file'), enablement: core.getInput('enablement') !== 'false' } } diff --git a/src/fixtures/gatsby/default.cjs b/src/fixtures/gatsby/default.cjs new file mode 100644 index 0000000..48f3a6f --- /dev/null +++ b/src/fixtures/gatsby/default.cjs @@ -0,0 +1,7 @@ +module.exports = { + siteMetadata: { + title: `My Gatsby Site`, + siteUrl: `https://www.yourdomain.tld`, + }, + plugins: [], +} \ No newline at end of file diff --git a/src/fixtures/gatsby/default.expected.cjs b/src/fixtures/gatsby/default.expected.cjs new file mode 100644 index 0000000..6de9670 --- /dev/null +++ b/src/fixtures/gatsby/default.expected.cjs @@ -0,0 +1,8 @@ +module.exports = { + pathPrefix: "/docs/", + siteMetadata: { + title: `My Gatsby Site`, + siteUrl: `https://www.yourdomain.tld`, + }, + plugins: [], +} \ No newline at end of file diff --git a/src/fixtures/gatsby/default.expected.mjs b/src/fixtures/gatsby/default.expected.mjs new file mode 100644 index 0000000..05c44d4 --- /dev/null +++ b/src/fixtures/gatsby/default.expected.mjs @@ -0,0 +1,8 @@ +export default { + pathPrefix: "/docs/", + siteMetadata: { + title: `My Gatsby Site`, + siteUrl: `https://www.yourdomain.tld`, + }, + plugins: [], +} \ No newline at end of file diff --git a/src/fixtures/gatsby/default.mjs b/src/fixtures/gatsby/default.mjs new file mode 100644 index 0000000..1535a65 --- /dev/null +++ b/src/fixtures/gatsby/default.mjs @@ -0,0 +1,7 @@ +export default { + siteMetadata: { + title: `My Gatsby Site`, + siteUrl: `https://www.yourdomain.tld`, + }, + plugins: [], +} \ No newline at end of file diff --git a/src/fixtures/next/default.cjs b/src/fixtures/next/default.cjs new file mode 100644 index 0000000..ae88795 --- /dev/null +++ b/src/fixtures/next/default.cjs @@ -0,0 +1,7 @@ +/** @type {import('next').NextConfig} */ +const nextConfig = { + reactStrictMode: true, + swcMinify: true, +} + +module.exports = nextConfig diff --git a/src/fixtures/next/default.expected.cjs b/src/fixtures/next/default.expected.cjs new file mode 100644 index 0000000..de677b8 --- /dev/null +++ b/src/fixtures/next/default.expected.cjs @@ -0,0 +1,9 @@ +/** @type {import('next').NextConfig} */ +const nextConfig = { + experimental: {images: {unoptimized: true}}, + basePath: '/docs', + reactStrictMode: true, + swcMinify: true +} + +module.exports = nextConfig diff --git a/src/fixtures/next/default.expected.mjs b/src/fixtures/next/default.expected.mjs new file mode 100644 index 0000000..b081c74 --- /dev/null +++ b/src/fixtures/next/default.expected.mjs @@ -0,0 +1,9 @@ +/** @type {import('next').NextConfig} */ +const nextConfig = { + experimental: {images: {unoptimized: true}}, + basePath: '/docs', + reactStrictMode: true, + swcMinify: true +} + +export default nextConfig diff --git a/src/fixtures/next/default.mjs b/src/fixtures/next/default.mjs new file mode 100644 index 0000000..07e1aaf --- /dev/null +++ b/src/fixtures/next/default.mjs @@ -0,0 +1,7 @@ +/** @type {import('next').NextConfig} */ +const nextConfig = { + reactStrictMode: true, + swcMinify: true, +} + +export default nextConfig diff --git a/src/fixtures/nuxt/async.cjs b/src/fixtures/nuxt/async.cjs new file mode 100644 index 0000000..d934c1c --- /dev/null +++ b/src/fixtures/nuxt/async.cjs @@ -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(); + } + } +}; diff --git a/src/fixtures/nuxt/async.expected.cjs b/src/fixtures/nuxt/async.expected.cjs new file mode 100644 index 0000000..e07a51f --- /dev/null +++ b/src/fixtures/nuxt/async.expected.cjs @@ -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(); + } + } +}; diff --git a/src/fixtures/nuxt/async.expected.mjs b/src/fixtures/nuxt/async.expected.mjs new file mode 100644 index 0000000..50c2e4f --- /dev/null +++ b/src/fixtures/nuxt/async.expected.mjs @@ -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(); + } + } +}; diff --git a/src/fixtures/nuxt/async.mjs b/src/fixtures/nuxt/async.mjs new file mode 100644 index 0000000..00b6057 --- /dev/null +++ b/src/fixtures/nuxt/async.mjs @@ -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(); + } + } +}; diff --git a/src/fixtures/nuxt/default.cjs b/src/fixtures/nuxt/default.cjs new file mode 100644 index 0000000..d3645cf --- /dev/null +++ b/src/fixtures/nuxt/default.cjs @@ -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: { + } +} \ No newline at end of file diff --git a/src/fixtures/nuxt/default.expected.cjs b/src/fixtures/nuxt/default.expected.cjs new file mode 100644 index 0000000..bcac94c --- /dev/null +++ b/src/fixtures/nuxt/default.expected.cjs @@ -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: { + } +} \ No newline at end of file diff --git a/src/fixtures/nuxt/default.expected.mjs b/src/fixtures/nuxt/default.expected.mjs new file mode 100644 index 0000000..a7ae19f --- /dev/null +++ b/src/fixtures/nuxt/default.expected.mjs @@ -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: { + } +} \ No newline at end of file diff --git a/src/fixtures/nuxt/default.mjs b/src/fixtures/nuxt/default.mjs new file mode 100644 index 0000000..bf60eee --- /dev/null +++ b/src/fixtures/nuxt/default.mjs @@ -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: { + } +} \ No newline at end of file diff --git a/src/index.js b/src/index.js index 062fcb5..a9c24a9 100644 --- a/src/index.js +++ b/src/index.js @@ -9,13 +9,13 @@ const outputPagesBaseUrl = require('./output-pages-base-url') async function main() { try { - const { repositoryNwo, githubToken, enablement, staticSiteGenerator } = getContext() + const { repositoryNwo, githubToken, enablement, staticSiteGenerato, generatorConfigFile } = getContext() const pageObject = await findOrCreatePagesSite({ repositoryNwo, githubToken, enablement }) const siteUrl = new URL(pageObject.html_url) if (staticSiteGenerator) { - setPagesPath({ staticSiteGenerator, path: siteUrl.pathname }) + setPagesPath({ staticSiteGenerator, generatorConfigFile, path: siteUrl.pathname }) } outputPagesBaseUrl(siteUrl) } catch (error) { diff --git a/src/set-pages-path.js b/src/set-pages-path.js index 2ad5ab9..4561bba 100644 --- a/src/set-pages-path.js +++ b/src/set-pages-path.js @@ -1,13 +1,13 @@ const core = require('@actions/core') const { ConfigParser } = require('./config-parser') -// Return the settings to be passed to a {ConfigParser} for a given -// static site generator and a Pages path value to inject -function getConfigParserSettings(staticSiteGenerator, path) { +// Return the settings to be passed to a {ConfigParser} for a given static site generator, +// optional configuration file path, and a Pages path value to inject +function getConfigParserSettings({ staticSiteGenerator, generatorConfigFile, path }) { switch (staticSiteGenerator) { case 'nuxt': return { - configurationFile: './nuxt.config.js', + configurationFile: generatorConfigFile || './nuxt.config.js', blankConfigurationFile: `${__dirname}/blank-configurations/nuxt.js`, properties: { // Configure a base path on the router @@ -25,7 +25,7 @@ function getConfigParserSettings(staticSiteGenerator, path) { } return { - configurationFile: './next.config.js', + configurationFile: generatorConfigFile || './next.config.js', blankConfigurationFile: `${__dirname}/blank-configurations/next.js`, properties: { // Configure a base path @@ -38,7 +38,7 @@ function getConfigParserSettings(staticSiteGenerator, path) { } case 'gatsby': return { - configurationFile: './gatsby-config.js', + configurationFile: generatorConfigFile || './gatsby-config.js', blankConfigurationFile: `${__dirname}/blank-configurations/gatsby.js`, properties: { // Configure a path prefix @@ -51,10 +51,10 @@ function getConfigParserSettings(staticSiteGenerator, path) { } // Inject Pages configuration in a given static site generator's configuration file -function setPagesPath({ staticSiteGenerator, path }) { +function setPagesPath({ staticSiteGenerator, generatorConfigFile, path }) { try { // 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() } catch (error) { // Logging diff --git a/src/set-pages-path.test.js b/src/set-pages-path.test.js index 97243b7..d363f91 100644 --- a/src/set-pages-path.test.js +++ b/src/set-pages-path.test.js @@ -1,5 +1,6 @@ const fs = require('fs') const path = require('path') +const core = require('@actions/core') const { getConfigParserSettings } = require('./set-pages-path') const { ConfigParser } = require('./config-parser') @@ -10,41 +11,91 @@ const tempFolder = getTempFolder() // 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 ;['next', 'nuxt', 'gatsby'].forEach(staticSiteGenerator => { // Folder containing the fixtures for a given static site generator const fixtureFolder = `${__dirname}/fixtures/${staticSiteGenerator}` - // Iterate over the fixtures - fs.readdirSync(fixtureFolder).forEach(configurationFile => { - // Ignore expectation - if (configurationFile.endsWith('.expected.js')) { - return - } + // Get fixture files, excluding expected results + const configurationFiles = fs.readdirSync(fixtureFolder).filter(filename => !filename.includes('.expected.')) - it(`Inject path properly for ${staticSiteGenerator} in ${configurationFile}`, async () => { - // Get settings for the static site generator - const settings = getConfigParserSettings(staticSiteGenerator, '/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 (configurationFile !== 'blank.js') { + fs.copyFileSync(fixtureSourceFile, fixtureTargetFile) + } else if (fs.existsSync(fixtureTargetFile)) { + fs.rmSync(fixtureTargetFile) + } - // 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, path: '/docs/' }) + // Update the settings + settings.configurationFile = fixtureTargetFile + // Do the injection + new ConfigParser(settings).injectAll() - // Update the settings and do the injection - settings.configurationFile = fixtureTargetFile - new ConfigParser(settings).injectAll() + // Read the expected file + const expectedFile = `${fixtureFolder}/${path.basename( + configurationFile, + defaultFileExtension + )}.expected${defaultFileExtension}` - // Read the expected file - const expectedFile = `${fixtureFolder}/${path.basename(configurationFile, '.js')}.expected.js` - - // Compare the actual and expected files - compareFiles(settings.configurationFile, expectedFile) + // Compare the actual and expected files + compareFiles(settings.configurationFile, expectedFile) + }) }) + ;['.js', '.cjs', '.mjs'].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) + }) + }) }) }) })