Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
81 commits
Select commit Hold shift + click to select a range
bb85b80
add VcsConfig + default retro-compatible implementation + config opti…
slorber Oct 24, 2025
adad517
make readLastUpdateData() use the new VcsConfig APIs
slorber Oct 24, 2025
c0cf617
add missing test snapshots
slorber Oct 24, 2025
86b0d0e
wire VSC api to blog creation date logic
slorber Oct 24, 2025
48098cc
wire VCS api in readLastUpdateData util
slorber Oct 24, 2025
2adad8d
wire VCS api to the sitemap plugin
slorber Oct 24, 2025
23b422a
implement website strategy to read from full git history
slorber Oct 24, 2025
834785b
refactor: apply lint autofix
slorber Oct 24, 2025
45551e7
use v5 semver range for execa
slorber Oct 30, 2025
927b0c7
use execa for website VCS + improve implementation
slorber Oct 30, 2025
b80ee31
minor refactor
slorber Oct 30, 2025
7dc89e0
Add API to initialize the VCS config
slorber Oct 30, 2025
bc9e135
wire VCS initialize()
slorber Oct 30, 2025
acfb173
VCS initialize could allow 0 arity functions
slorber Oct 30, 2025
86f792d
site vcs cleanup
slorber Oct 31, 2025
09749f3
add DOCUSAURUS_PERF_LOGGER to more CI jobs
slorber Oct 31, 2025
677c854
update snapshots
slorber Oct 31, 2025
1d44ebc
re-enable showLastUpdate for localized sites
slorber Oct 31, 2025
ce49aa0
do not output GPG signature
slorber Oct 31, 2025
66cc809
fix showSignature
slorber Oct 31, 2025
9443d5f
refactor site VCS + implement file creation info logic
slorber Oct 31, 2025
7e6a4e0
Move VCS code in dedicated subfolder
slorber Oct 31, 2025
67317a9
Move VCS code in dedicated subfolder
slorber Oct 31, 2025
bf56b8b
Add VCS fixtures
slorber Oct 31, 2025
42d0d96
refactor a bit vcs unit tests
slorber Oct 31, 2025
2366ca1
Refactor blog tests using former VCS hardcoded values
slorber Oct 31, 2025
cf016c6
refactor LAST_UPDATE_UNTRACKED_GIT_FILEPATH
slorber Oct 31, 2025
1bc1bcf
add git eager VCS preset
slorber Nov 6, 2025
ab79070
Merge branch 'main' into slorber/last-update-api
slorber Nov 6, 2025
acf5f38
Refactor VCS preset + config validation
slorber Nov 6, 2025
a42682d
fix all tests
slorber Nov 6, 2025
2a9e227
cleanup lastUpdateUtils from useless hardcoded things, in favor of ne…
slorber Nov 6, 2025
87291b3
cleanup lastUpdateUtils from useless hardcoded things, in favor of ne…
slorber Nov 6, 2025
8af8aab
add file to git
slorber Nov 6, 2025
4fa2e09
move getGitLastUpdate fn to gitUtils
slorber Nov 6, 2025
2491491
add more gitUtils tests
slorber Nov 6, 2025
ee7137e
cleanup VcsGitAdHoc
slorber Nov 6, 2025
4127963
refactor: apply lint autofix
slorber Nov 6, 2025
0eedbcc
refactor test from shelljs to execa
slorber Nov 7, 2025
1e195a2
refactor test from shelljs to execa
slorber Nov 7, 2025
0623b00
Merge remote-tracking branch 'origin/slorber/last-update-api' into sl…
slorber Nov 7, 2025
7a4d3f7
add bad CWD case for getGitRepoRoot API
slorber Nov 7, 2025
85b3903
add case for Docusaurus repo
slorber Nov 7, 2025
c9d9b5c
try to fix windows issue with fs.realpath.native() call
slorber Nov 7, 2025
87b6fba
fix lockfile
slorber Nov 7, 2025
3b0abf4
fs.realpath.native() impl
slorber Nov 7, 2025
e5f6771
add getGitSuperProjectRoot API
slorber Nov 7, 2025
2b146cc
refactor: apply lint autofix
slorber Nov 7, 2025
2bccea1
refactor a bit tests
slorber Nov 7, 2025
9162f1b
Merge remote-tracking branch 'origin/slorber/last-update-api' into sl…
slorber Nov 7, 2025
d243079
add getGitSubmodulePaths API
slorber Nov 7, 2025
0497473
refactor: apply lint autofix
slorber Nov 7, 2025
df56892
add getGitAllRepoRoots API
slorber Nov 7, 2025
84dcf6b
Merge remote-tracking branch 'origin/slorber/last-update-api' into sl…
slorber Nov 7, 2025
143ad04
replace method
slorber Nov 7, 2025
688d125
add tests for getGitRepositoryFilesInfo
slorber Nov 7, 2025
7c596ba
optimize gitUtils speed, avoid creating useless temp git repositories…
slorber Nov 7, 2025
fd270c9
Add new VSC Git Eager strategy with support for git submodules
slorber Nov 7, 2025
9bd6db2
add missing fs.realpath.native for windows tests
slorber Nov 7, 2025
6bf515d
minor refactor
slorber Nov 7, 2025
01e1663
almost working VCS integration, adding default v1/v2 strategy
slorber Nov 7, 2025
30be8c5
Enable new VCS strategy on our own website
slorber Nov 7, 2025
8c669cf
Merge branch 'main' into slorber/last-update-api
slorber Nov 14, 2025
287cf7c
Better Git eager integration
slorber Nov 14, 2025
89263d2
Merge branch 'main' into slorber/last-update-api
slorber Nov 14, 2025
e355c1b
remove useless jest git utils
slorber Nov 14, 2025
5868a92
remove useless package.json change
slorber Nov 14, 2025
f259f4f
improve DEFAULT_TEST_VCS_CONFIG, cleanup tests
slorber Nov 14, 2025
c4ac8fb
improve DEFAULT_TEST_VCS_CONFIG, cleanup tests
slorber Nov 14, 2025
c8712f0
rename DEFAULT_TEST_VCS_CONFIG to TEST_VCS
slorber Nov 14, 2025
257b6fd
add gitEagerVcs future flag
slorber Nov 14, 2025
1b801d7
wire the Docusaurus Faster "gitEagerVcs" future flag to the default-v…
slorber Nov 14, 2025
93b4893
wire the Docusaurus Faster "gitEagerVcs" future flag to the default-v…
slorber Nov 14, 2025
83de4e0
Git Eager VCS: only init once per all locales instead of once per locale
slorber Nov 14, 2025
077966d
update a bit the site config, turn on git VCS future flag
slorber Nov 14, 2025
cc9e07d
rename misleading i18n method name to getLocaleList
slorber Nov 14, 2025
c3c12db
Git Eager strategy should only initialize once, and not for all locales
slorber Nov 14, 2025
1174897
add --no-pager git option
slorber Nov 14, 2025
fa69fb7
add DOCUSAURUS_RETURN_AFTER_LOADING to test loading speed on i18n builds
slorber Nov 14, 2025
541a0ac
update snapshots with future flag
slorber Nov 14, 2025
2584288
add VCS documentation
slorber Nov 14, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/workflows/build-blog-only.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,5 @@ jobs:
run: yarn || yarn || yarn
- name: Build blog-only
run: yarn workspace website build:blogOnly
env:
DOCUSAURUS_PERF_LOGGER: 'true'
1 change: 1 addition & 0 deletions .github/workflows/build-hash-router.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ jobs:
- name: Build Hash Router
run: yarn build:website:fast
env:
DOCUSAURUS_PERF_LOGGER: 'true'
DOCUSAURUS_ROUTER: 'hash'
# Note: hash router + baseUrl do not play well together
# This would host at https://facebook.github.io/docusaurus/#/docusaurus/
Expand Down
3 changes: 3 additions & 0 deletions .github/workflows/build-perf.yml
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ jobs:
comment-key: DOCUSAURUS_INFRA_${{ matrix.DOCUSAURUS_INFRA }}
env:
DOCUSAURUS_SLOWER: ${{ matrix.DOCUSAURUS_INFRA == 'SLOWER' && 'true' || 'false' }}
DOCUSAURUS_PERF_LOGGER: 'true'

# Ensures build times stay under reasonable thresholds
build-time:
Expand All @@ -88,6 +89,7 @@ jobs:
timeout-minutes: ${{ matrix.DOCUSAURUS_INFRA == 'SLOWER' && 3 || 2 }}
env:
DOCUSAURUS_SLOWER: ${{ matrix.DOCUSAURUS_INFRA == 'SLOWER' && 'true' || 'false' }}
DOCUSAURUS_PERF_LOGGER: 'true'

# Ensure build with a warm cache does not increase too much
- name: Build (warm cache)
Expand All @@ -96,5 +98,6 @@ jobs:
timeout-minutes: ${{ matrix.DOCUSAURUS_INFRA == 'SLOWER' && 1 || 2 }}
env:
DOCUSAURUS_SLOWER: ${{ matrix.DOCUSAURUS_INFRA == 'SLOWER' && 'true' || 'false' }}
DOCUSAURUS_PERF_LOGGER: 'true'

# TODO post a GitHub comment with build with perf warnings?
2 changes: 2 additions & 0 deletions .github/workflows/tests-windows.yml
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ jobs:
run: yarn workspace website test:swizzle:wrap:ts
- name: Docusaurus Build
run: yarn build:website:fast
env:
DOCUSAURUS_PERF_LOGGER: 'true'

- name: TypeCheck website
# see https://github.com/facebook/docusaurus/pull/10486
Expand Down
5 changes: 0 additions & 5 deletions jest/deps.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,3 @@ declare module 'to-vfile' {

export function read(path: string, encoding?: string): Promise<VFile>;
}

declare module '@testing-utils/git' {
const createTempRepo: typeof import('./utils/git').createTempRepo;
export {createTempRepo};
}
2 changes: 1 addition & 1 deletion jest/snapshotPathNormalizer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ function normalizePaths<T>(value: T): T {
(val) => val.split(cwdReal).join('<PROJECT_ROOT>'),
(val) => val.split(cwd).join('<PROJECT_ROOT>'),

// Replace home directory with <TEMP_DIR>
// Replace temp directory with <TEMP_DIR>
(val) => val.split(tempDirReal).join('<TEMP_DIR>'),
(val) => val.split(tempDir).join('<TEMP_DIR>'),

Expand Down
63 changes: 0 additions & 63 deletions jest/utils/git.ts

This file was deleted.

2 changes: 1 addition & 1 deletion packages/create-docusaurus/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
"@docusaurus/logger": "3.9.2",
"@docusaurus/utils": "3.9.2",
"commander": "^5.1.0",
"execa": "5.1.1",
"execa": "^5.1.1",
"fs-extra": "^11.1.1",
"lodash": "^4.17.21",
"prompts": "^2.4.2",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,10 @@
import {jest} from '@jest/globals';
import path from 'path';
import fs from 'fs-extra';
import {DEFAULT_PARSE_FRONT_MATTER} from '@docusaurus/utils';
import {
DEFAULT_PARSE_FRONT_MATTER,
DEFAULT_VCS_CONFIG,
} from '@docusaurus/utils';
import {fromPartial} from '@total-typescript/shoehorn';
import {normalizePluginOptions} from '@docusaurus/utils-validation';
import tree from 'tree-node-cli';
Expand Down Expand Up @@ -51,7 +54,7 @@ function getBlogContentPaths(siteDir: string): BlogContentPaths {
}

async function testGenerateFeeds(
context: LoadContext,
contextInput: LoadContext,
optionsInput: Options,
): Promise<void> {
const options = validateOptions({
Expand All @@ -62,6 +65,17 @@ async function testGenerateFeeds(
options: optionsInput,
});

const context: LoadContext = {
...contextInput,
siteConfig: {
...contextInput.siteConfig,
future: {
...contextInput.siteConfig?.future,
experimental_vcs: DEFAULT_VCS_CONFIG,
},
},
};

const contentPaths = getBlogContentPaths(context.siteDir);
const authorsMap = await getAuthorsMap({
contentPaths,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,7 @@
import {jest} from '@jest/globals';
import * as path from 'path';
import {normalizePluginOptions} from '@docusaurus/utils-validation';
import {
posixPath,
getFileCommitDate,
LAST_UPDATE_FALLBACK,
getLocaleConfig,
} from '@docusaurus/utils';
import {posixPath, getLocaleConfig, TEST_VCS} from '@docusaurus/utils';
import {DEFAULT_FUTURE_CONFIG} from '@docusaurus/core/src/server/configValidation';
import pluginContentBlog from '../index';
import {validateOptions} from '../options';
Expand All @@ -32,6 +27,10 @@ import type {
EditUrlFunction,
} from '@docusaurus/plugin-content-blog';

async function getFileCreationDate(filePath: string): Promise<Date> {
return new Date((await TEST_VCS.getFileCreationInfo(filePath)).timestamp);
}

const markdown: MarkdownConfig = {
format: 'mdx',
mermaid: true,
Expand Down Expand Up @@ -561,9 +560,7 @@ describe('blog plugin', () => {
const blogPosts = await getBlogPosts(siteDir);
const noDateSource = path.posix.join('@site', PluginPath, 'no date.md');
const noDateSourceFile = path.posix.join(siteDir, PluginPath, 'no date.md');
// We know the file exists and we know we have git
const result = await getFileCommitDate(noDateSourceFile, {age: 'oldest'});
const noDateSourceTime = result.date;
const noDateSourceTime = await getFileCreationDate(noDateSourceFile);

expect({
...getByTitle(blogPosts, 'no date').metadata,
Expand Down Expand Up @@ -674,29 +671,23 @@ describe('last update', () => {
);
const {blogPosts} = (await plugin.loadContent!())!;

const TestLastUpdate = await TEST_VCS.getFileLastUpdateInfo('any path');

expect(blogPosts[0]?.metadata.lastUpdatedBy).toBe('seb');
expect(blogPosts[0]?.metadata.lastUpdatedAt).toBe(
LAST_UPDATE_FALLBACK.lastUpdatedAt,
lastUpdateFor('2021-01-01'),
);

expect(blogPosts[1]?.metadata.lastUpdatedBy).toBe(
LAST_UPDATE_FALLBACK.lastUpdatedBy,
);
expect(blogPosts[1]?.metadata.lastUpdatedBy).toBe(TestLastUpdate.author);
expect(blogPosts[1]?.metadata.lastUpdatedAt).toBe(
LAST_UPDATE_FALLBACK.lastUpdatedAt,
lastUpdateFor('2021-01-01'),
);

expect(blogPosts[2]?.metadata.lastUpdatedBy).toBe('seb');
expect(blogPosts[2]?.metadata.lastUpdatedAt).toBe(
lastUpdateFor('2021-01-01'),
);
expect(blogPosts[2]?.metadata.lastUpdatedAt).toBe(TestLastUpdate.timestamp);

expect(blogPosts[3]?.metadata.lastUpdatedBy).toBe(
LAST_UPDATE_FALLBACK.lastUpdatedBy,
);
expect(blogPosts[3]?.metadata.lastUpdatedAt).toBe(
lastUpdateFor('2021-01-01'),
);
expect(blogPosts[3]?.metadata.lastUpdatedBy).toBe(TestLastUpdate.author);
expect(blogPosts[3]?.metadata.lastUpdatedAt).toBe(TestLastUpdate.timestamp);
});

it('time only', async () => {
Expand All @@ -710,29 +701,27 @@ describe('last update', () => {
);
const {blogPosts} = (await plugin.loadContent!())!;

expect(blogPosts[0]?.metadata.title).toBe('Author');
const TestLastUpdate = await TEST_VCS.getFileLastUpdateInfo('any path');

expect(blogPosts[0]?.metadata.title).toBe('Both');
expect(blogPosts[0]?.metadata.lastUpdatedBy).toBeUndefined();
expect(blogPosts[0]?.metadata.lastUpdatedAt).toBe(
LAST_UPDATE_FALLBACK.lastUpdatedAt,
lastUpdateFor('2021-01-01'),
);

expect(blogPosts[1]?.metadata.title).toBe('Nothing');
expect(blogPosts[1]?.metadata.title).toBe('Last update date');
expect(blogPosts[1]?.metadata.lastUpdatedBy).toBeUndefined();
expect(blogPosts[1]?.metadata.lastUpdatedAt).toBe(
LAST_UPDATE_FALLBACK.lastUpdatedAt,
lastUpdateFor('2021-01-01'),
);

expect(blogPosts[2]?.metadata.title).toBe('Both');
expect(blogPosts[2]?.metadata.title).toBe('Author');
expect(blogPosts[2]?.metadata.lastUpdatedBy).toBeUndefined();
expect(blogPosts[2]?.metadata.lastUpdatedAt).toBe(
lastUpdateFor('2021-01-01'),
);
expect(blogPosts[2]?.metadata.lastUpdatedAt).toBe(TestLastUpdate.timestamp);

expect(blogPosts[3]?.metadata.title).toBe('Last update date');
expect(blogPosts[3]?.metadata.title).toBe('Nothing');
expect(blogPosts[3]?.metadata.lastUpdatedBy).toBeUndefined();
expect(blogPosts[3]?.metadata.lastUpdatedAt).toBe(
lastUpdateFor('2021-01-01'),
);
expect(blogPosts[3]?.metadata.lastUpdatedAt).toBe(TestLastUpdate.timestamp);
});

it('author only', async () => {
Expand All @@ -746,20 +735,18 @@ describe('last update', () => {
);
const {blogPosts} = (await plugin.loadContent!())!;

const TestLastUpdate = await TEST_VCS.getFileLastUpdateInfo('any path');

expect(blogPosts[0]?.metadata.lastUpdatedBy).toBe('seb');
expect(blogPosts[0]?.metadata.lastUpdatedAt).toBeUndefined();

expect(blogPosts[1]?.metadata.lastUpdatedBy).toBe(
LAST_UPDATE_FALLBACK.lastUpdatedBy,
);
expect(blogPosts[1]?.metadata.lastUpdatedBy).toBe(TestLastUpdate.author);
expect(blogPosts[1]?.metadata.lastUpdatedAt).toBeUndefined();

expect(blogPosts[2]?.metadata.lastUpdatedBy).toBe('seb');
expect(blogPosts[2]?.metadata.lastUpdatedAt).toBeUndefined();

expect(blogPosts[3]?.metadata.lastUpdatedBy).toBe(
LAST_UPDATE_FALLBACK.lastUpdatedBy,
);
expect(blogPosts[3]?.metadata.lastUpdatedBy).toBe(TestLastUpdate.author);
expect(blogPosts[3]?.metadata.lastUpdatedAt).toBeUndefined();
});

Expand Down
15 changes: 5 additions & 10 deletions packages/docusaurus-plugin-content-blog/src/blogUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ import {
Globby,
groupTaggedItems,
getTagVisibility,
getFileCommitDate,
getContentPathList,
isUnlisted,
isDraft,
Expand Down Expand Up @@ -225,6 +224,7 @@ async function processBlogSourceFile(
siteConfig: {
baseUrl,
markdown: {parseFrontMatter},
future: {experimental_vcs: vcs},
},
siteDir,
i18n,
Expand Down Expand Up @@ -257,6 +257,7 @@ async function processBlogSourceFile(
blogSourceAbsolute,
options,
frontMatter.last_update,
vcs,
);

const draft = isDraft({frontMatter});
Expand Down Expand Up @@ -285,17 +286,11 @@ async function processBlogSourceFile(
return parsedBlogFileName.date;
}

try {
const result = await getFileCommitDate(blogSourceAbsolute, {
age: 'oldest',
includeAuthor: false,
});

return result.date;
} catch (err) {
logger.warn(err);
const result = await vcs.getFileCreationInfo(blogSourceAbsolute);
if (result == null) {
return (await fs.stat(blogSourceAbsolute)).birthtime;
}
return new Date(result.timestamp);
}

const date = await getDate();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ import {
createSlugger,
posixPath,
DEFAULT_PLUGIN_ID,
LAST_UPDATE_FALLBACK,
getLocaleConfig,
TEST_VCS,
} from '@docusaurus/utils';
import {getTagsFile} from '@docusaurus/utils-validation';
import {createSidebarsUtils} from '../sidebars/utils';
Expand Down Expand Up @@ -529,8 +529,8 @@ describe('simple site', () => {
custom_edit_url: 'https://github.com/customUrl/docs/lorem.md',
unrelated_front_matter: "won't be part of metadata",
},
lastUpdatedAt: LAST_UPDATE_FALLBACK.lastUpdatedAt,
lastUpdatedBy: LAST_UPDATE_FALLBACK.lastUpdatedBy,
lastUpdatedAt: TEST_VCS.LAST_UPDATE_INFO.timestamp,
lastUpdatedBy: TEST_VCS.LAST_UPDATE_INFO.author,
tags: [],
unlisted: false,
});
Expand Down Expand Up @@ -664,7 +664,7 @@ describe('simple site', () => {
},
title: 'Last Update Author Only',
},
lastUpdatedAt: LAST_UPDATE_FALLBACK.lastUpdatedAt,
lastUpdatedAt: TEST_VCS.LAST_UPDATE_INFO.timestamp,
lastUpdatedBy: 'Custom Author (processed by parseFrontMatter)',
sidebarPosition: undefined,
tags: [],
Expand Down
Loading
Loading