diff --git a/.github/workflows/audit-docs-version.yml b/.github/workflows/audit-docs-version.yml new file mode 100644 index 0000000..079e56d --- /dev/null +++ b/.github/workflows/audit-docs-version.yml @@ -0,0 +1,61 @@ +name: Audit Docs Version + +on: + workflow_dispatch: + schedule: + - cron: '0 17 * * *' + +permissions: {} + +jobs: + audit_docs_version: + name: Audit Docs Version + runs-on: ubuntu-latest + steps: + - run: npm install @electron/fiddle-core + - name: Confirm latest version + uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1 + with: + script: | + const { setTimeout } = await import('node:timers/promises'); + const { ElectronVersions } = await import('${{ github.workspace }}/node_modules/@electron/fiddle-core/dist/index.js'); + + const DOCS_SHA_REGEX = //m; + const DELTA_THRESHOLD_MS = 1000*60*20; + + const resp = await fetch('https://electronjs.org'); + + if (!resp.ok) { + core.setFailed('Could not fetch website'); + return; + } + + const latestDocsSHA = (await resp.text()).match(DOCS_SHA_REGEX)?.[1]; + + const versions = await ElectronVersions.create(undefined, { ignoreCache: true }); + + const { data } = await github.rest.repos.getBranch({ + owner: 'electron', + repo: 'electron', + branch: `${versions.latestStable.major}-x-y`, + }); + + const { date } = data.commit.commit.committer; + const delta = Date.now() - new Date(date).getTime(); + + // If the commit happened recently, wait a bit for the site + // to deploy before checking so we don't get a false positive + if (delta < DELTA_THRESHOLD_MS) { + await setTimeout(DELTA_THRESHOLD_MS - delta); + } + + if (data.commit.sha !== latestDocsSHA) { + core.summary.addRaw('🚨 Docs are NOT up-to-date'); + + // Set this as failed so it's easy to scan runs to find failures + process.exitCode = 1; + } else { + core.summary.addRaw('🎉 Docs are up-to-date'); + } + + await core.summary.write(); diff --git a/docs/latest/.sha b/docs/latest/.sha new file mode 100644 index 0000000..62e103b --- /dev/null +++ b/docs/latest/.sha @@ -0,0 +1 @@ +72115c1948ebe8c31525654440dc4d35d0dbb6b9 \ No newline at end of file diff --git a/docusaurus.config.ts b/docusaurus.config.ts index cfb79c3..a69ed20 100644 --- a/docusaurus.config.ts +++ b/docusaurus.config.ts @@ -1,4 +1,6 @@ +import fs from 'fs'; import path from 'path'; + import { Config } from '@docusaurus/types'; import npm2yarn from '@docusaurus/remark-plugin-npm2yarn'; import { themes as prismThemes } from 'prism-react-renderer'; @@ -15,6 +17,17 @@ import jsCodeBlocks from './src/transformers/js-code-blocks'; import fiddleEmbedder from './src/transformers/fiddle-embedder'; import apiHistory from './src/transformers/api-history'; +let docsSHA = undefined; + +try { + docsSHA = fs.readFileSync( + path.resolve(__dirname, './docs/latest/.sha'), + 'utf-8' + ); +} catch { + console.warn('No .sha file found in docs/latest directory'); +} + const config: Config = { title: 'Electron', tagline: 'Build cross-platform desktop apps with JavaScript, HTML, and CSS', @@ -24,6 +37,17 @@ const config: Config = { favicon: 'assets/img/favicon.ico', organizationName: 'electron', projectName: 'electron', + headTags: docsSHA + ? [ + { + tagName: 'meta', + attributes: { + name: 'docs-sha', + content: docsSHA, + }, + }, + ] + : [], markdown: { mermaid: true, }, diff --git a/scripts/pre-build.ts b/scripts/pre-build.ts index 78c5a0d..13aa881 100644 --- a/scripts/pre-build.ts +++ b/scripts/pre-build.ts @@ -3,9 +3,10 @@ * right places, and transform it to make it ready to * be used by docusaurus. */ +import { existsSync } from 'fs'; +import fs from 'fs/promises'; import path from 'path'; -import { existsSync, remove } from 'fs-extra'; import latestVersion from 'latest-version'; import logger from '@docusaurus/logger'; @@ -26,7 +27,7 @@ const DOCS_FOLDER = path.join(__dirname, '..', 'docs', 'latest'); const start = async (source: string): Promise => { logger.info(`Running ${logger.green('electronjs.org')} pre-build scripts...`); logger.info(`Deleting previous content at ${logger.green(DOCS_FOLDER)}`); - await remove(DOCS_FOLDER); + await fs.rm(DOCS_FOLDER, { recursive: true, force: true }); const localElectron = source && (source.includes('/') || source.includes('\\')); @@ -52,6 +53,8 @@ const start = async (source: string): Promise => { destination: DOCS_FOLDER, downloadMatch: '/docs/', }); + + await fs.writeFile(path.join(DOCS_FOLDER, '.sha'), source); } else if (existsSync(source)) { await copy({ target: source,