显示最后编辑的人

This commit is contained in:
lilingfeng 2024-08-13 13:06:32 +08:00
parent 762005f942
commit 7c47fc1e0b
5 changed files with 306 additions and 24 deletions

View File

@ -10,18 +10,12 @@ jobs:
# 拉取代码
- name: Checkout
uses: actions/checkout@v4
- name: Use Node.js 20
uses: actions/setup-node@v3
- name: "setup pnpm"
uses: "pnpm/action-setup@v4"
- name: "setup node"
uses: "actions/setup-node@v4"
with:
cache: "pnpm"
node-version: 20
# 启用缓存加速
- name: Cache
uses: actions/cache@v4
with:
path: ~/.npm
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
# 安装 Npm 并构建
- name: Install and Build
run: npm install && npm run build
run: pnpm install && pnpm run build

View File

@ -27,21 +27,16 @@ jobs:
# 拉取代码
- name: Checkout
uses: actions/checkout@v4
- name: Use Node.js 20
uses: actions/setup-node@v3
- name: "setup pnpm"
uses: "pnpm/action-setup@v4"
- name: "setup node"
uses: "actions/setup-node@v4"
with:
cache: "pnpm"
node-version: 20
# 启用缓存加速部署
- name: Cache
uses: actions/cache@v4
with:
path: ~/.npm
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
# 安装 Npm 并构建
- name: Install and Build
run: npm install && npm run build
run: pnpm install && pnpm run build
# 部署
- name: Deploy
uses: JamesIves/github-pages-deploy-action@v4

174
package-lock.json generated
View File

@ -18,6 +18,7 @@
"@docusaurus/theme-search-algolia": "^3.5.1",
"@mdx-js/react": "^3.0.0",
"clsx": "^2.0.0",
"patch-package": "^8.0.0",
"prism-react-renderer": "^2.3.0",
"react": "^18.0.0",
"react-dom": "^18.0.0"
@ -4005,6 +4006,12 @@
"resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz",
"integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ=="
},
"node_modules/@yarnpkg/lockfile": {
"version": "1.1.0",
"resolved": "https://registry.npmmirror.com/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz",
"integrity": "sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ==",
"license": "BSD-2-Clause"
},
"node_modules/accepts": {
"version": "1.3.8",
"resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz",
@ -7327,6 +7334,15 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/find-yarn-workspace-root": {
"version": "2.0.0",
"resolved": "https://registry.npmmirror.com/find-yarn-workspace-root/-/find-yarn-workspace-root-2.0.0.tgz",
"integrity": "sha512-1IMnbjt4KzsQfnhnzNd8wUEgXZ44IzZaZmnLYx7D5FZlaHt2gW20Cri8Q+E/t5tIj4+epTBub+2Zxu/vNILzqQ==",
"license": "Apache-2.0",
"dependencies": {
"micromatch": "^4.0.2"
}
},
"node_modules/flat": {
"version": "5.0.2",
"resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz",
@ -9283,6 +9299,30 @@
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
"integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug=="
},
"node_modules/json-stable-stringify": {
"version": "1.1.1",
"resolved": "https://registry.npmmirror.com/json-stable-stringify/-/json-stable-stringify-1.1.1.tgz",
"integrity": "sha512-SU/971Kt5qVQfJpyDveVhQ/vya+5hvrjClFOcr8c0Fq5aODJjMwutrOfCU+eCnVD5gpx1Q3fEqkyom77zH1iIg==",
"license": "MIT",
"dependencies": {
"call-bind": "^1.0.5",
"isarray": "^2.0.5",
"jsonify": "^0.0.1",
"object-keys": "^1.1.1"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/json-stable-stringify/node_modules/isarray": {
"version": "2.0.5",
"resolved": "https://registry.npmmirror.com/isarray/-/isarray-2.0.5.tgz",
"integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==",
"license": "MIT"
},
"node_modules/json5": {
"version": "2.2.3",
"resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
@ -9305,6 +9345,15 @@
"graceful-fs": "^4.1.6"
}
},
"node_modules/jsonify": {
"version": "0.0.1",
"resolved": "https://registry.npmmirror.com/jsonify/-/jsonify-0.0.1.tgz",
"integrity": "sha512-2/Ki0GcmuqSrgFyelQq9M05y7PS0mEwuIzrf3f1fPqkVDVRvZrPZtVSMHxdgo8Aq0sxAOb/cr2aqqA3LeWHVPg==",
"license": "Public Domain",
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/jsonpointer": {
"version": "5.0.1",
"resolved": "https://registry.npmmirror.com/jsonpointer/-/jsonpointer-5.0.1.tgz",
@ -9358,6 +9407,15 @@
"node": ">=0.10.0"
}
},
"node_modules/klaw-sync": {
"version": "6.0.0",
"resolved": "https://registry.npmmirror.com/klaw-sync/-/klaw-sync-6.0.0.tgz",
"integrity": "sha512-nIeuVSzdCCs6TDPTqI8w1Yre34sSq7AkZ4B3sfOBbI2CgVSB4Du4aLQijFU2+lhAFCwt9+42Hel6lQNIv6AntQ==",
"license": "MIT",
"dependencies": {
"graceful-fs": "^4.1.11"
}
},
"node_modules/kleur": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz",
@ -12499,6 +12557,15 @@
"opener": "bin/opener-bin.js"
}
},
"node_modules/os-tmpdir": {
"version": "1.0.2",
"resolved": "https://registry.npmmirror.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
"integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==",
"license": "MIT",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/p-cancelable": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-3.0.0.tgz",
@ -12692,6 +12759,101 @@
"tslib": "^2.0.3"
}
},
"node_modules/patch-package": {
"version": "8.0.0",
"resolved": "https://registry.npmmirror.com/patch-package/-/patch-package-8.0.0.tgz",
"integrity": "sha512-da8BVIhzjtgScwDJ2TtKsfT5JFWz1hYoBl9rUQ1f38MC2HwnEIkK8VN3dKMKcP7P7bvvgzNDbfNHtx3MsQb5vA==",
"license": "MIT",
"dependencies": {
"@yarnpkg/lockfile": "^1.1.0",
"chalk": "^4.1.2",
"ci-info": "^3.7.0",
"cross-spawn": "^7.0.3",
"find-yarn-workspace-root": "^2.0.0",
"fs-extra": "^9.0.0",
"json-stable-stringify": "^1.0.2",
"klaw-sync": "^6.0.0",
"minimist": "^1.2.6",
"open": "^7.4.2",
"rimraf": "^2.6.3",
"semver": "^7.5.3",
"slash": "^2.0.0",
"tmp": "^0.0.33",
"yaml": "^2.2.2"
},
"bin": {
"patch-package": "index.js"
},
"engines": {
"node": ">=14",
"npm": ">5"
}
},
"node_modules/patch-package/node_modules/fs-extra": {
"version": "9.1.0",
"resolved": "https://registry.npmmirror.com/fs-extra/-/fs-extra-9.1.0.tgz",
"integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==",
"license": "MIT",
"dependencies": {
"at-least-node": "^1.0.0",
"graceful-fs": "^4.2.0",
"jsonfile": "^6.0.1",
"universalify": "^2.0.0"
},
"engines": {
"node": ">=10"
}
},
"node_modules/patch-package/node_modules/open": {
"version": "7.4.2",
"resolved": "https://registry.npmmirror.com/open/-/open-7.4.2.tgz",
"integrity": "sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q==",
"license": "MIT",
"dependencies": {
"is-docker": "^2.0.0",
"is-wsl": "^2.1.1"
},
"engines": {
"node": ">=8"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/patch-package/node_modules/rimraf": {
"version": "2.7.1",
"resolved": "https://registry.npmmirror.com/rimraf/-/rimraf-2.7.1.tgz",
"integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==",
"deprecated": "Rimraf versions prior to v4 are no longer supported",
"license": "ISC",
"dependencies": {
"glob": "^7.1.3"
},
"bin": {
"rimraf": "bin.js"
}
},
"node_modules/patch-package/node_modules/slash": {
"version": "2.0.0",
"resolved": "https://registry.npmmirror.com/slash/-/slash-2.0.0.tgz",
"integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==",
"license": "MIT",
"engines": {
"node": ">=6"
}
},
"node_modules/patch-package/node_modules/yaml": {
"version": "2.5.0",
"resolved": "https://registry.npmmirror.com/yaml/-/yaml-2.5.0.tgz",
"integrity": "sha512-2wWLbGbYDiSqqIKoPjar3MPgB94ErzCtrNE1FdqGuaO0pi2JGjmE8aW8TDZwzU7vuxcGRdL/4gPQwQ7hD5AMSw==",
"license": "ISC",
"bin": {
"yaml": "bin.mjs"
},
"engines": {
"node": ">= 14"
}
},
"node_modules/path-exists": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-5.0.0.tgz",
@ -15631,6 +15793,18 @@
"resolved": "https://registry.npmjs.org/tiny-warning/-/tiny-warning-1.0.3.tgz",
"integrity": "sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA=="
},
"node_modules/tmp": {
"version": "0.0.33",
"resolved": "https://registry.npmmirror.com/tmp/-/tmp-0.0.33.tgz",
"integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==",
"license": "MIT",
"dependencies": {
"os-tmpdir": "~1.0.2"
},
"engines": {
"node": ">=0.6.0"
}
},
"node_modules/to-fast-properties": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz",

View File

@ -12,7 +12,8 @@
"serve": "docusaurus serve",
"test": "docusaurus build && docusaurus serve",
"write-translations": "docusaurus write-translations",
"write-heading-ids": "docusaurus write-heading-ids"
"write-heading-ids": "docusaurus write-heading-ids",
"patch": "patch-package"
},
"dependencies": {
"@docusaurus/core": "^3.5.1",
@ -25,6 +26,7 @@
"@docusaurus/theme-search-algolia": "^3.5.1",
"@mdx-js/react": "^3.0.0",
"clsx": "^2.0.0",
"patch-package": "^8.0.0",
"prism-react-renderer": "^2.3.0",
"react": "^18.0.0",
"react-dom": "^18.0.0"
@ -47,5 +49,11 @@
},
"engines": {
"node": ">=18.0"
},
"packageManager": "pnpm@9.5.0+sha512.140036830124618d624a2187b50d04289d5a087f326c9edfc0ccd733d76c4f52c3a313d4fc148794a2a9d81553016004e6742e8cf850670268a7387fc220c903",
"pnpm": {
"patchedDependencies": {
"@docusaurus/utils@3.5.1": "patches/@docusaurus__utils@3.5.1.patch"
}
}
}

View File

@ -0,0 +1,111 @@
diff --git a/src/gitUtils.ts b/src/gitUtils.ts
index 39a3ad754a0c5ab27cfb78c7b44a9f0be3785a62..c3116d7a725d4a5420286baac8147f4e821e5631 100755
--- a/src/gitUtils.ts
+++ b/src/gitUtils.ts
@@ -95,6 +95,13 @@ export async function getFileCommitDate(
timestamp: number;
author?: string;
}> {
+ await throwGitErrors(file);
+ const regex = retrieveCorrectRegex(includeAuthor);
+ const result = await runGitCommandOnFile(file, createArgs('', includeAuthor, age));
+ const match = matchFromRegex(file, regex, result);
+ return matchDateAndTimestamp(match, includeAuthor);
+}
+async function throwGitErrors(file: string) {
if (!hasGit()) {
throw new GitNotFoundError(
`Failed to retrieve git history for "${file}" because git is not installed.`,
@@ -106,19 +113,28 @@ export async function getFileCommitDate(
`Failed to retrieve git history for "${file}" because the file does not exist.`,
);
}
+}
+function createArgs(format: string, includeAuthor?: boolean, age: 'oldest' | 'newest' = 'oldest') {
// We add a "RESULT:" prefix to make parsing easier
// See why: https://mirror.yizhan.wiki/https://github.com/facebook/docusaurus/pull/10022
const resultFormat = includeAuthor ? 'RESULT:%ct,%an' : 'RESULT:%ct';
const args = [
- `--format=${resultFormat}`,
+ `--format=${includeAuthor === undefined ? format : resultFormat}`,
'--max-count=1',
age === 'oldest' ? '--follow --diff-filter=A' : undefined,
]
.filter(Boolean)
.join(' ');
+ return args;
+}
+async function runGitCommandOnFile(file: string, args: string): Promise<{
+ code: number;
+ stdout: string;
+ stderr: string;
+}> {
const command = `git -c log.showSignature=false log ${args} -- "${path.basename(
file,
)}"`;
@@ -147,12 +163,18 @@ export async function getFileCommitDate(
);
}
+ return result;
+}
+function retrieveCorrectRegex(includeAuthor: boolean) {
// We only parse the output line starting with our "RESULT:" prefix
// See why https://mirror.yizhan.wiki/https://github.com/facebook/docusaurus/pull/10022
const regex = includeAuthor
? /(?:^|\n)RESULT:(?<timestamp>\d+),(?<author>.+)(?:$|\n)/
: /(?:^|\n)RESULT:(?<timestamp>\d+)(?:$|\n)/;
+ return regex;
+}
+function matchFromRegex(file: string, regex: RegExp, result: { code: number; stdout: string; stderr: string; }): RegExpMatchArray {
const output = result.stdout.trim();
if (!output) {
@@ -169,6 +191,13 @@ export async function getFileCommitDate(
);
}
+ return match;
+}
+function matchDateAndTimestamp(match: RegExpMatchArray, includeAuthor: boolean): {
+ date: Date;
+ timestamp: number;
+ author?: string;
+} {
const timestampInSeconds = Number(match.groups!.timestamp);
const timestamp = timestampInSeconds * 1_000;
const date = new Date(timestamp);
@@ -178,3 +207,29 @@ export async function getFileCommitDate(
}
return {date, timestamp};
}
+
+/**
+ * Fetches the git history of a file and returns a relevant commit hash.
+ *
+ * @throws {@link GitNotFoundError} If git is not found in `PATH`.
+ * @throws {@link FileNotTrackedError} If the current file is not tracked by git.
+ * @throws Also throws when `git log` exited with non-zero, or when it outputs
+ * unexpected text.
+ */
+export async function getFileCommitHash(
+ /** Absolute path to the file. */
+ file: string,
+): Promise<{
+ /** The author's commit hash, as returned from git. */
+ commit: string;
+}>;
+
+export async function getFileCommitHash(file: string): Promise<{
+ commit: string;
+}> {
+ throwGitErrors(file);
+ const result = await runGitCommandOnFile(file, createArgs('RESULT:%h', undefined, 'newest'))
+ const regex = /(?:^|\n)RESULT:(?<commit>\w+)(?:$|\n)/;
+ const match = matchFromRegex(file, regex, result);
+ return {commit: match.groups!.commit!};
+}