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,