diff --git a/docs/api-commands.md b/docs/api-commands.md index cf592fcf4164..1468d8d92d2b 100644 --- a/docs/api-commands.md +++ b/docs/api-commands.md @@ -59,6 +59,7 @@ Alias: `build`. | Options | Default | Description | | -------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------- | | `--skip-image-compression` | `false` | Skip compression of image assets. You usually won't want to skip this unless your images have already been optimized. | +| `--skip-next-release` | `false` | Skip the next release documents when versioning is enabled. This will not build HTML files for documents in `/docs` directory.| Generates the static website, applying translations if necessary. Useful for building the website prior to deployment. diff --git a/packages/docusaurus-1.x/lib/__tests__/build-files.test.js b/packages/docusaurus-1.x/lib/__tests__/build-files.test.js index d307cf813d69..589d433a1749 100644 --- a/packages/docusaurus-1.x/lib/__tests__/build-files.test.js +++ b/packages/docusaurus-1.x/lib/__tests__/build-files.test.js @@ -94,3 +94,20 @@ describe('Build files', () => { }); }); }); + +describe('Build files but skip next release', () => { + beforeAll(() => { + shell.cd('website-1.x'); + shell.exec('yarn build --skip-next-release', {silent: true}); + }); + + afterAll(() => { + clearBuildFolder(); + }); + + test('Did not generate HTML files from markdown files for next release', () => { + expect( + glob.sync(`${buildDir}/${siteConfig.projectName}/docs/**/next`).length, + ).toBe(0); + }); +}); diff --git a/packages/docusaurus-1.x/lib/server/__tests__/start.test.js b/packages/docusaurus-1.x/lib/server/__tests__/start.test.js index c394a5081c6f..5453207d92d6 100644 --- a/packages/docusaurus-1.x/lib/server/__tests__/start.test.js +++ b/packages/docusaurus-1.x/lib/server/__tests__/start.test.js @@ -18,7 +18,7 @@ const siteConfig = require(`${process.cwd()}/siteConfig.js`); // siteConfig virtually. jest.mock(`${process.cwd()}/siteConfig.js`, () => jest.fn(), {virtual: true}); -jest.mock('commander'); +jest.genMockFromModule('commander'); jest.mock('react-dev-utils/openBrowser'); jest.mock('portfinder'); jest.mock('../liveReloadServer.js'); diff --git a/packages/docusaurus-1.x/lib/server/readMetadata.js b/packages/docusaurus-1.x/lib/server/readMetadata.js index 7c2048dd44af..6878583d5ae8 100644 --- a/packages/docusaurus-1.x/lib/server/readMetadata.js +++ b/packages/docusaurus-1.x/lib/server/readMetadata.js @@ -10,6 +10,7 @@ const CWD = process.cwd(); const path = require('path'); const fs = require('fs'); const glob = require('glob'); +const program = require('commander'); const metadataUtils = require('./metadataUtils'); @@ -37,6 +38,8 @@ const SupportedHeaderFields = new Set([ 'custom_edit_url', ]); +program.option('--skip-next-release').parse(process.argv); + let allSidebars; if (fs.existsSync(`${CWD}/sidebars.json`)) { allSidebars = require(`${CWD}/sidebars.json`); @@ -54,6 +57,14 @@ function getDocsPath() { return siteConfig.customDocsPath ? siteConfig.customDocsPath : 'docs'; } +function shouldGenerateNextReleaseDocs() { + return !( + env.versioning.enabled && + program.name() === 'docusaurus-build' && + program.skipNextRelease + ); +} + // returns map from id to object containing sidebar ordering info function readSidebar(sidebars = {}) { Object.assign(sidebars, versionFallback.sidebarData()); @@ -220,74 +231,76 @@ function generateMetadataDocs() { const metadatas = {}; const defaultMetadatas = {}; - // metadata for english files - const docsDir = path.join(CWD, '../', getDocsPath()); - let files = glob.sync(`${docsDir}/**`); - files.forEach(file => { - const extension = path.extname(file); + if (shouldGenerateNextReleaseDocs()) { + // metadata for english files + const docsDir = path.join(CWD, '../', getDocsPath()); + let files = glob.sync(`${docsDir}/**`); + files.forEach(file => { + const extension = path.extname(file); - if (extension === '.md' || extension === '.markdown') { - const res = processMetadata(file, docsDir); + if (extension === '.md' || extension === '.markdown') { + const res = processMetadata(file, docsDir); - if (!res) { - return; - } - const metadata = res.metadata; - metadatas[metadata.id] = metadata; - - // create a default list of documents for each enabled language based on docs in English - // these will get replaced if/when the localized file is downloaded from crowdin - enabledLanguages - .filter(currentLanguage => currentLanguage !== 'en') - .forEach(currentLanguage => { - const baseMetadata = Object.assign({}, metadata); - baseMetadata.id = baseMetadata.id - .toString() - .replace(/^en-/, `${currentLanguage}-`); - if (baseMetadata.permalink) { - baseMetadata.permalink = baseMetadata.permalink - .toString() - .replace( - new RegExp(`^${docsPart}en/`), - `${docsPart}${currentLanguage}/`, - ); - } - if (baseMetadata.next) { - baseMetadata.next = baseMetadata.next - .toString() - .replace(/^en-/, `${currentLanguage}-`); - } - if (baseMetadata.previous) { - baseMetadata.previous = baseMetadata.previous + if (!res) { + return; + } + const metadata = res.metadata; + metadatas[metadata.id] = metadata; + + // create a default list of documents for each enabled language based on docs in English + // these will get replaced if/when the localized file is downloaded from crowdin + enabledLanguages + .filter(currentLanguage => currentLanguage !== 'en') + .forEach(currentLanguage => { + const baseMetadata = Object.assign({}, metadata); + baseMetadata.id = baseMetadata.id .toString() .replace(/^en-/, `${currentLanguage}-`); - } - baseMetadata.language = currentLanguage; - defaultMetadatas[baseMetadata.id] = baseMetadata; - }); - Object.assign(metadatas, defaultMetadatas); - } - }); + if (baseMetadata.permalink) { + baseMetadata.permalink = baseMetadata.permalink + .toString() + .replace( + new RegExp(`^${docsPart}en/`), + `${docsPart}${currentLanguage}/`, + ); + } + if (baseMetadata.next) { + baseMetadata.next = baseMetadata.next + .toString() + .replace(/^en-/, `${currentLanguage}-`); + } + if (baseMetadata.previous) { + baseMetadata.previous = baseMetadata.previous + .toString() + .replace(/^en-/, `${currentLanguage}-`); + } + baseMetadata.language = currentLanguage; + defaultMetadatas[baseMetadata.id] = baseMetadata; + }); + Object.assign(metadatas, defaultMetadatas); + } + }); - // metadata for non-english docs - const translatedDir = path.join(CWD, 'translated_docs'); - files = glob.sync(`${CWD}/translated_docs/**`); - files.forEach(file => { - if (!utils.getLanguage(file, translatedDir)) { - return; - } + // metadata for non-english docs + const translatedDir = path.join(CWD, 'translated_docs'); + files = glob.sync(`${CWD}/translated_docs/**`); + files.forEach(file => { + if (!utils.getLanguage(file, translatedDir)) { + return; + } - const extension = path.extname(file); + const extension = path.extname(file); - if (extension === '.md' || extension === '.markdown') { - const res = processMetadata(file, translatedDir); - if (!res) { - return; + if (extension === '.md' || extension === '.markdown') { + const res = processMetadata(file, translatedDir); + if (!res) { + return; + } + const metadata = res.metadata; + metadatas[metadata.id] = metadata; } - const metadata = res.metadata; - metadatas[metadata.id] = metadata; - } - }); + }); + } // metadata for versioned docs const versionData = versionFallback.docData(); diff --git a/packages/docusaurus/bin/docusaurus.js b/packages/docusaurus/bin/docusaurus.js index 49d68f003240..e50412652c69 100755 --- a/packages/docusaurus/bin/docusaurus.js +++ b/packages/docusaurus/bin/docusaurus.js @@ -45,8 +45,12 @@ program '-sic, --skip-image-compression ', 'Skip compression of image assets (default: false)', ) - .action((siteDir = '.', {skipImageCompression}) => { - wrapCommand(build)(path.resolve(siteDir), {skipImageCompression}); + .option('--skip-next-release', 'Skip documents from next release') + .action((siteDir = '.', {skipImageCompression, skipNextRelease}) => { + wrapCommand(build)(path.resolve(siteDir), { + skipImageCompression, + skipNextRelease, + }); }); program diff --git a/packages/docusaurus/lib/commands/build.js b/packages/docusaurus/lib/commands/build.js index f7f989f4c1a5..b3e9d9b5f7c1 100644 --- a/packages/docusaurus/lib/commands/build.js +++ b/packages/docusaurus/lib/commands/build.js @@ -38,11 +38,11 @@ function compile(config) { }); } -module.exports = async function build(siteDir) { +module.exports = async function build(siteDir, options) { process.env.NODE_ENV = 'production'; console.log('Build command invoked ...'); - const props = await load(siteDir); + const props = await load(siteDir, options.skipNextRelease); // Apply user webpack config. const {outDir, plugins} = props; diff --git a/packages/docusaurus/lib/load/docs/index.js b/packages/docusaurus/lib/load/docs/index.js index 88b976816430..0b3757cacacf 100644 --- a/packages/docusaurus/lib/load/docs/index.js +++ b/packages/docusaurus/lib/load/docs/index.js @@ -12,7 +12,10 @@ const createOrder = require('./order'); const loadSidebars = require('./sidebars'); const processMetadata = require('./metadata'); -async function loadDocs({siteDir, docsDir, env, siteConfig}) { +async function loadDocs( + {siteDir, docsDir, env, siteConfig}, + skipNextRelease = false, +) { // @tested - load all sidebars including versioned sidebars const docsSidebars = loadSidebars({siteDir, env}); @@ -33,30 +36,34 @@ async function loadDocs({siteDir, docsDir, env, siteConfig}) { // Prepare metadata container. const docsMetadatas = {}; - // Metadata for default docs files. - const docsFiles = await globby(['**/*.md'], { - cwd: docsDir, - }); - await Promise.all( - docsFiles.map(async source => { - // Do not allow reserved version/ translated folder name in 'docs' - // e.g: 'docs/version-1.0.0/' should not be allowed as it can cause unwanted bug - const subFolder = getSubFolder(path.resolve(docsDir, source), docsDir); - const versionsFolders = versions.map(version => `version-${version}`); - if ([...enabledLangTags, ...versionsFolders].includes(subFolder)) { - throw new Error(`You cannot have a folder named 'docs/${subFolder}/'`); - } + if (!(versioningEnabled && skipNextRelease)) { + // Metadata for default docs files. + const docsFiles = await globby(['**/*.md'], { + cwd: docsDir, + }); + await Promise.all( + docsFiles.map(async source => { + // Do not allow reserved version/ translated folder name in 'docs' + // e.g: 'docs/version-1.0.0/' should not be allowed as it can cause unwanted bug + const subFolder = getSubFolder(path.resolve(docsDir, source), docsDir); + const versionsFolders = versions.map(version => `version-${version}`); + if ([...enabledLangTags, ...versionsFolders].includes(subFolder)) { + throw new Error( + `You cannot have a folder named 'docs/${subFolder}/'`, + ); + } - const metadata = await processMetadata( - source, - docsDir, - env, - order, - siteConfig, - ); - docsMetadatas[metadata.id] = metadata; - }), - ); + const metadata = await processMetadata( + source, + docsDir, + env, + order, + siteConfig, + ); + docsMetadatas[metadata.id] = metadata; + }), + ); + } // Metadata for non-default-language docs. if (translationEnabled) { diff --git a/packages/docusaurus/lib/load/index.js b/packages/docusaurus/lib/load/index.js index 5f8d9a14c7ca..bbd7f92f0f4d 100644 --- a/packages/docusaurus/lib/load/index.js +++ b/packages/docusaurus/lib/load/index.js @@ -17,7 +17,7 @@ const loadRoutes = require('./routes'); const loadPlugins = require('./plugins'); const constants = require('../constants'); -module.exports = async function load(siteDir) { +module.exports = async function load(siteDir, skipNextRelease = false) { const generatedFilesDir = path.resolve( siteDir, constants.GENERATED_FILES_DIR_NAME, @@ -42,12 +42,15 @@ module.exports = async function load(siteDir) { // Docs const docsDir = path.resolve(siteDir, '..', siteConfig.customDocsPath); - const {docsMetadatas, docsSidebars} = await loadDocs({ - siteDir, - docsDir, - env, - siteConfig, - }); + const {docsMetadatas, docsSidebars} = await loadDocs( + { + siteDir, + docsDir, + env, + siteConfig, + }, + skipNextRelease, + ); await generate( generatedFilesDir, 'docsMetadatas.js', diff --git a/packages/docusaurus/test/load/docs/index.test.js b/packages/docusaurus/test/load/docs/index.test.js index 5d5d8f606358..d5113336f3bf 100644 --- a/packages/docusaurus/test/load/docs/index.test.js +++ b/packages/docusaurus/test/load/docs/index.test.js @@ -173,4 +173,28 @@ describe('loadDocs', () => { version: null, }); }); + + test('versioned website with skip next release', async () => { + const props = await loadSetup('versioned'); + const {siteDir, docsDir, versionedDir, env, siteConfig} = props; + const {docsMetadatas} = await loadDocs( + {siteDir, docsDir, env, siteConfig}, + true, + ); + expect(docsMetadatas['version-1.0.0-foo/bar']).toEqual({ + category: 'Test', + id: 'version-1.0.0-foo/bar', + language: null, + localized_id: 'version-1.0.0-foo/bar', + next: 'version-1.0.0-foo/baz', + next_id: 'version-1.0.0-foo/baz', + next_title: 'Baz', + permalink: '/docs/1.0.0/foo/bar', + sidebar: 'version-1.0.0-docs', + source: path.join(versionedDir, 'version-1.0.0/foo/bar.md'), + title: 'Bar', + version: '1.0.0', + }); + expect(docsMetadatas['foo/bar']).toBeUndefined(); + }); });