diff --git a/.github/workflows/check_pr.yml b/.github/workflows/check_pr.yml index fec2d819253..93b06ce5e85 100644 --- a/.github/workflows/check_pr.yml +++ b/.github/workflows/check_pr.yml @@ -132,6 +132,9 @@ jobs: steps: - uses: actions/checkout@v6 + with: + # Number of commits to fetch. 0 indicates all history for all branches and tags. Default: 1 + fetch-depth: 0 - uses: actions/setup-node@v6 with: node-version: ${{ env.NODE_VERSION }} @@ -148,6 +151,9 @@ jobs: if: steps.cache.outputs.cache-hit != 'true' run: npm ci working-directory: docs + + - name: Prepare docs versioning + run: node scripts/create-docs-versioning.mjs - name: Build docs run: npm run build diff --git a/.github/workflows/deploy_docs.yml b/.github/workflows/deploy_docs.yml index 1cc6254f65f..6a1d74631e4 100644 --- a/.github/workflows/deploy_docs.yml +++ b/.github/workflows/deploy_docs.yml @@ -29,7 +29,10 @@ jobs: if: steps.cache.outputs.cache-hit != 'true' run: npm ci working-directory: docs - + + - name: Prepare docs versioning + run: node scripts/create-docs-versioning.mjs + - name: Build docs run: npm run build working-directory: docs diff --git a/.github/workflows/release_next.yml b/.github/workflows/release_next.yml index 9f8054dc86b..267cd92489a 100644 --- a/.github/workflows/release_next.yml +++ b/.github/workflows/release_next.yml @@ -152,6 +152,9 @@ jobs: if: steps.cache.outputs.cache-hit != 'true' run: npm ci working-directory: docs + + - name: Prepare docs versioning + run: node scripts/create-docs-versioning.mjs - name: Build docs run: npm run build diff --git a/.gitignore b/.gitignore index c32e2d001f3..4146a43b816 100644 --- a/.gitignore +++ b/.gitignore @@ -74,6 +74,11 @@ docs/build docs/.docusaurus docs/.cache-loader +# Generated versioning files +docs/versioned_docs +docs/versioned_sidebars +docs/versions.json + docs/.DS_Store docs/.env.local docs/.env.development.local diff --git a/docs/docusaurus.config.ts b/docs/docusaurus.config.ts index 4df5912321e..26f6d96206f 100644 --- a/docs/docusaurus.config.ts +++ b/docs/docusaurus.config.ts @@ -1,10 +1,16 @@ import type { Config } from '@docusaurus/types'; import type * as Preset from '@docusaurus/preset-classic'; import type { Options as ClientRedirectsOptions } from '@docusaurus/plugin-client-redirects'; +import { existsSync, readFileSync } from 'node:fs'; import LightCodeTheme from './src/config/lightCodeTheme'; import DarkCodeTheme from './src/config/darkCodeTheme'; import definitionList from './src/remark/definitionLists'; +const hasStableVersion = existsSync('versions.json'); +const stableVersion = hasStableVersion + ? JSON.parse(readFileSync('versions.json', 'utf-8'))[0] + : undefined; + const config: Config = { title: 'CLI for Microsoft 365', titleDelimiter: '-', @@ -68,9 +74,24 @@ const config: Config = { docs: { routeBasePath: '/', sidebarPath: './src/config/sidebars.ts', - editUrl: 'https://github.com/pnp/cli-microsoft365/blob/main/docs', + editUrl: ({ docPath }) => + `https://github.com/pnp/cli-microsoft365/blob/main/docs/docs/${docPath}`, showLastUpdateTime: true, - remarkPlugins: [definitionList] + remarkPlugins: [definitionList], + ...hasStableVersion && { + lastVersion: stableVersion, + versions: { + current: { + label: 'Beta', + path: 'beta', + badge: false, + banner: 'unreleased' + }, + [stableVersion!]: { + badge: false, + }, + }, + }, }, blog: false, theme: { @@ -139,6 +160,10 @@ const config: Config = { sidebarId: 'about', position: 'left' }, + { + type: 'docsVersionDropdown', + position: 'right' + }, { href: 'https://github.com/pnp/cli-microsoft365', label: 'GitHub', diff --git a/docs/package.json b/docs/package.json index a28a79fda56..1a63f304431 100644 --- a/docs/package.json +++ b/docs/package.json @@ -8,7 +8,7 @@ "build": "docusaurus build", "swizzle": "docusaurus swizzle", "deploy": "docusaurus deploy", - "clear": "docusaurus clear", + "clear": "docusaurus clear && node -e \"const fs=require('fs');['versioned_docs','versioned_sidebars','versions.json'].forEach(p=>{if(fs.existsSync(p))fs.rmSync(p,{recursive:true,force:true});})\"", "serve": "docusaurus serve", "write-translations": "docusaurus write-translations", "write-heading-ids": "docusaurus write-heading-ids", diff --git a/scripts/create-docs-versioning.mjs b/scripts/create-docs-versioning.mjs new file mode 100644 index 00000000000..1d728aa757e --- /dev/null +++ b/scripts/create-docs-versioning.mjs @@ -0,0 +1,57 @@ +import { execSync } from 'node:child_process'; +import { existsSync, rmSync } from 'node:fs'; +import { dirname, resolve } from 'node:path'; +import { fileURLToPath } from 'node:url'; + +const __dirname = dirname(fileURLToPath(import.meta.url)); +const repoRoot = resolve(__dirname, '..'); +const docsRoot = resolve(repoRoot, 'docs'); + +// Get the last git tag +let lastTag; +try { + lastTag = execSync('git describe --tags --abbrev=0', { + encoding: 'utf-8', + cwd: repoRoot + }).trim(); +} +catch { + console.log('No git tags found. Skipping stable version preparation.'); + process.exit(0); +} + +console.log(`Creating stable version from tag: ${lastTag}`); + +// Clean any existing versioned files +for (const p of ['versioned_docs', 'versioned_sidebars', 'versions.json']) { + const fullPath = resolve(docsRoot, p); + if (existsSync(fullPath)) { + rmSync(fullPath, { recursive: true, force: true }); + } +} + +try { + // Temporarily replace docs content with the tagged version + rmSync(resolve(docsRoot, 'docs'), { recursive: true }); + execSync(`git restore --source="${lastTag}" -- docs/docs/ docs/src/config/sidebars.ts`, { + cwd: repoRoot + }); + + // Use Docusaurus to create the versioned snapshot + execSync(`npx docusaurus docs:version "${lastTag}"`, { + cwd: docsRoot, + stdio: 'inherit' + }); + + console.log(`Stable version created successfully from tag ${lastTag}`); +} +finally { + // Restore current branch's docs + execSync('git restore -- docs/docs/ docs/src/config/sidebars.ts', { + cwd: repoRoot + }); + // Clean up any files from the tag that don't exist on current branch + execSync('git clean -fd docs/docs/', { + cwd: repoRoot + }); +}