Skip to content

Commit 69909d5

Browse files
feat(git-changelog): support git submodule (nolebase#189)
* chore: tweak * fix: replace srcDir * fix: build error * fix: rewritePaths * refactor: mv GitChangelogOptions types * fix: get srcDir from vitepress config * test: remove useless test code * fix: remove rewritePaths map * chore: remove useless import * docs: modify config guide and fix typo * chore: add comment and tweaks * docs: update en docs * refactor: rewritePaths -> rewritePathsBy * chore: update packages/vitepress-plugin-git-changelog/src/vite/helpers.ts * fix: git log body and co-author * Revert "test: remove useless test code" This reverts commit 5ec8f6f. * test: fix test * test: use example author info * chore: modify comment * fix: multipleAuthorsRegex breaks when email has `[], {}, ()` * feat: allow gather logs only in PROD mode * Revert "feat: allow gather logs only in PROD mode" This reverts commit a8ba8cf. --------- Co-authored-by: Neko Ayaka <[email protected]>
1 parent adf30c0 commit 69909d5

File tree

17 files changed

+617
-698
lines changed

17 files changed

+617
-698
lines changed

docs/pages/en/integrations/vitepress-plugin-git-changelog/configure-vite-plugins.md

+40-32
Original file line numberDiff line numberDiff line change
@@ -40,60 +40,73 @@ But the options don't stop there. We have more options to configure the plugin t
4040

4141
```typescript twoslash
4242
import type {
43-
Commit, RewritePathsBy
43+
Commit, CommitToStringHandler, CommitToStringsHandler, RewritePathsBy
4444
} from '@nolebase/vitepress-plugin-git-changelog/vite'
4545
// ---cut---
4646
interface Options {
47+
/**
48+
* The current working directory in which to search files.
49+
*
50+
* @default process.cwd()
51+
*/
52+
cwd?: string
4753
/**
48-
* When fetching git logs, what directories should be included?
54+
* When fetching git logs, what files should be included?
55+
*
56+
* @default ['** /*.md', '!node_modules']
4957
*/
50-
includeDirs?: string[]
58+
include?: string[]
5159
/**
5260
* Your repository URL.
5361
* Yes, you can dynamically generate it.
5462
*
5563
* @default 'https://github.com/example/example'
5664
*/
57-
repoURL?: string | ((commit: Commit) => string)
65+
repoURL?: string | CommitToStringHandler
5866
/**
5967
* A function to get the release tag URL.
6068
*
6169
* @default (commit) => `${commit.repo_url}/releases/tag/${commit.tag}`
6270
*/
63-
getReleaseTagURL?: (commit: Commit) => string
71+
getReleaseTagURL?: CommitToStringHandler
72+
/**
73+
* A function to get the release tags URL.
74+
*
75+
* @default (commit) => commit.tags?.map(tag => `${commit.repo_url}/releases/tag/${tag}`)
76+
*/
77+
getReleaseTagsURL?: CommitToStringsHandler
6478
/**
6579
* A function to get the commit URL.
6680
*
6781
* @default (commit) => `${commit.repo_url}/commit/${commit.hash}`
6882
*/
69-
getCommitURL?: (commit: Commit) => string
83+
getCommitURL?: CommitToStringHandler
7084
/**
71-
* A map that contains rewrite rules of paths.
72-
*
73-
* This is quite useful when you have your pages in a different directory than the base url after deployed since the
74-
* data will be calculated again on the client side.
85+
* Rules to rewrite paths by patterns.
7586
*
76-
* For example:
77-
* - We have a page at `docs/pages/en/integrations/page.md`
78-
* - And we will deploy it to `https://example.com/en/integrations/page`
87+
* This can be quite useful when your pages are in different directories,
88+
* or when they are generated at runtime according to path.ts.
7989
*
80-
* Then you can set the rewrite paths like this:
81-
* ```json
82-
* {
83-
* "docs/": ""
84-
* }
85-
* ```
90+
* Since the plugin matches the git information for each page by comparing the local path,
91+
* you can override the local file path to `vitepress.useData.page.value.filePath` with this option.
8692
*
87-
* This will rewrite the path to `en/integrations/page.md`
88-
* Which is the correct path for the deployed page and runtime scripts to work properly.
93+
* @example
8994
*
90-
* Note: in runtime, which is client side, the final extension will be replaced with `.md` if the extension is `.html`.
91-
*/
92-
rewritePaths?: Record<string, string>
93-
/**
94-
* Rules to rewrite paths by patterns.
95+
* ```typescript
96+
* GitChangelog({
97+
* rewritePathsBy: {
98+
* handler: (_commit, path) => {
99+
* if (path) {
100+
* // path: packages/characters/src/lib1.ts
101+
* if (path.startsWith('packages/characters/src/') && !path.includes('index.ts'))
102+
* return `${path.replace('packages/characters/src/', '').slice(0, -3)}.md`
103+
* }
104+
* return path
105+
* },
106+
* },
107+
* })
108+
* ```
95109
*
96-
* Same as `rewritePaths`, but it can be a function that returns a promise or plain value.
97110
* Besides that, we offer some built-in handlers to rewrite paths by patterns:
98111
*
99112
* - `rewritePathsByRewritingExtension(from: string, to: string)`: to rewrite paths by rewriting the extension.
@@ -112,17 +125,12 @@ interface Options {
112125
* ```
113126
*
114127
* @see rewritePathsByRewritingExtension
115-
*
116128
*/
117129
rewritePathsBy?: RewritePathsBy
118130
/**
119131
* The maximum number of git logs to fetch.
120132
*/
121133
maxGitLogCount?: number
122-
/**
123-
* The maximum number of concurrent processes to fetch git logs.
124-
*/
125-
maxConcurrentProcesses?: number
126134
}
127135
```
128136

docs/pages/zh-CN/integrations/vitepress-plugin-git-changelog/configure-vite-plugins.md

+40-32
Original file line numberDiff line numberDiff line change
@@ -40,60 +40,73 @@ export default defineConfig(() => {
4040

4141
```typescript twoslash
4242
import type {
43-
Commit, RewritePathsBy
43+
Commit, CommitToStringHandler, CommitToStringsHandler, RewritePathsBy
4444
} from '@nolebase/vitepress-plugin-git-changelog/vite'
4545
// ---cut---
4646
interface Options {
47+
/**
48+
* The current working directory in which to search files.
49+
*
50+
* @default process.cwd()
51+
*/
52+
cwd?: string
4753
/**
48-
* When fetching git logs, what directories should be included?
54+
* When fetching git logs, what files should be included?
55+
*
56+
* @default ['** /*.md', '!node_modules']
4957
*/
50-
includeDirs?: string[]
58+
include?: string[]
5159
/**
5260
* Your repository URL.
5361
* Yes, you can dynamically generate it.
5462
*
5563
* @default 'https://github.com/example/example'
5664
*/
57-
repoURL?: string | ((commit: Commit) => string)
65+
repoURL?: string | CommitToStringHandler
5866
/**
5967
* A function to get the release tag URL.
6068
*
6169
* @default (commit) => `${commit.repo_url}/releases/tag/${commit.tag}`
6270
*/
63-
getReleaseTagURL?: (commit: Commit) => string
71+
getReleaseTagURL?: CommitToStringHandler
72+
/**
73+
* A function to get the release tags URL.
74+
*
75+
* @default (commit) => commit.tags?.map(tag => `${commit.repo_url}/releases/tag/${tag}`)
76+
*/
77+
getReleaseTagsURL?: CommitToStringsHandler
6478
/**
6579
* A function to get the commit URL.
6680
*
6781
* @default (commit) => `${commit.repo_url}/commit/${commit.hash}`
6882
*/
69-
getCommitURL?: (commit: Commit) => string
83+
getCommitURL?: CommitToStringHandler
7084
/**
71-
* A map that contains rewrite rules of paths.
72-
*
73-
* This is quite useful when you have your pages in a different directory than the base url after deployed since the
74-
* data will be calculated again on the client side.
85+
* Rules to rewrite paths by patterns.
7586
*
76-
* For example:
77-
* - We have a page at `docs/pages/en/integrations/page.md`
78-
* - And we will deploy it to `https://example.com/en/integrations/page`
87+
* This can be quite useful when your pages are in different directories,
88+
* or when they are generated at runtime according to path.ts.
7989
*
80-
* Then you can set the rewrite paths like this:
81-
* ```json
82-
* {
83-
* "docs/": ""
84-
* }
85-
* ```
90+
* Since the plugin matches the git information for each page by comparing the local path,
91+
* you can override the local file path to `vitepress.useData.page.value.filePath` with this option.
8692
*
87-
* This will rewrite the path to `en/integrations/page.md`
88-
* Which is the correct path for the deployed page and runtime scripts to work properly.
93+
* @example
8994
*
90-
* Note: in runtime, which is client side, the final extension will be replaced with `.md` if the extension is `.html`.
91-
*/
92-
rewritePaths?: Record<string, string>
93-
/**
94-
* Rules to rewrite paths by patterns.
95+
* ```typescript
96+
* GitChangelog({
97+
* rewritePathsBy: {
98+
* handler: (_commit, path) => {
99+
* if (path) {
100+
* // path: packages/characters/src/lib1.ts
101+
* if (path.startsWith('packages/characters/src/') && !path.includes('index.ts'))
102+
* return `${path.replace('packages/characters/src/', '').slice(0, -3)}.md`
103+
* }
104+
* return path
105+
* },
106+
* },
107+
* })
108+
* ```
95109
*
96-
* Same as `rewritePaths`, but it can be a function that returns a promise or plain value.
97110
* Besides that, we offer some built-in handlers to rewrite paths by patterns:
98111
*
99112
* - `rewritePathsByRewritingExtension(from: string, to: string)`: to rewrite paths by rewriting the extension.
@@ -112,17 +125,12 @@ interface Options {
112125
* ```
113126
*
114127
* @see rewritePathsByRewritingExtension
115-
*
116128
*/
117129
rewritePathsBy?: RewritePathsBy
118130
/**
119131
* The maximum number of git logs to fetch.
120132
*/
121133
maxGitLogCount?: number
122-
/**
123-
* The maximum number of concurrent processes to fetch git logs.
124-
*/
125-
maxConcurrentProcesses?: number
126134
}
127135
```
128136

docs/pages/zh-CN/integrations/vitepress-plugin-git-changelog/getting-started.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ yarn add @nolebase/vitepress-plugin-git-changelog -D
4141

4242
有两种将基于 Git 的页面历史 Vite 插件集成到您的 VitePress 项目中的方法:
4343

44-
1. [**推荐**:在 VitePress 的主要配置文件中使用 `vite` 选项(通常位于 `docs/.vitepress/config.ts`,文件路径和扩展名可能会有所不同)](#在-vitepresss-配置文件中配置-vite-插件)
44+
1. [**推荐**:在 VitePress 的主要配置文件中使用 `vite` 选项(通常位于 `docs/.vitepress/config.ts`,文件路径和扩展名可能会有所不同)](#在-vitepress-的配置文件中配置-vite-插件)
4545
2. [在 VitePress 项目的根目录中创建一个单独的 Vite 配置文件(例如 `vite.config.ts`](#在单独的-vite-配置文件中配置-vite-插件)
4646

4747
#### 在 VitePress 的配置文件中配置 Vite 插件

docs/vite.config.ts

-3
Original file line numberDiff line numberDiff line change
@@ -154,9 +154,6 @@ export default defineConfig({
154154
GitChangelog({
155155
maxGitLogCount: 2000,
156156
repoURL: () => 'https://github.com/nolebase/integrations',
157-
rewritePaths: {
158-
'docs/': '',
159-
},
160157
}),
161158
GitChangelogMarkdownSection({
162159
locales: {

packages/vitepress-plugin-git-changelog/build.config.ts

-1
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@ export default defineBuildConfig({
3232
declaration: true,
3333
externals: [
3434
'vite',
35-
'simple-git',
3635
'uncrypto',
3736
// builtins
3837
...builtins,

packages/vitepress-plugin-git-changelog/package.json

+5-2
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,9 @@
2727
"vitepress-plugin",
2828
"nolebase-integration"
2929
],
30-
"sideEffects": ["**/*.css"],
30+
"sideEffects": [
31+
"**/*.css"
32+
],
3133
"exports": {
3234
".": {
3335
"types": "./dist/vite/index.d.ts",
@@ -73,10 +75,11 @@
7375
"@nolebase/ui": "workspace:^",
7476
"colorette": "^2.0.20",
7577
"date-fns": "^3.3.1",
78+
"execa": "^8.0.1",
79+
"globby": "^14.0.1",
7680
"gray-matter": "^4.0.3",
7781
"less": "^4.2.0",
7882
"ora": "^8.0.1",
79-
"simple-git": "^3.22.0",
8083
"uncrypto": "^0.1.3"
8184
},
8285
"devDependencies": {

packages/vitepress-plugin-git-changelog/src/client/components/Changelog.vue

+1-1
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@ const toggleViewMore = ref(false)
2121
const options = inject(InjectionKey, { locales: defaultLocales })
2222
2323
const { lang } = useData()
24-
const { t } = useI18n()
2524
const rawPath = useRawPath()
25+
const { t } = useI18n()
2626
const commits = useCommits(Changelog.commits, rawPath)
2727
2828
const lastChangeDate = ref<Date>(toDate(commits.value[0]?.date_timestamp))

packages/vitepress-plugin-git-changelog/src/client/components/Contributors.vue

+11-5
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import { inject, onMounted, onServerPrefetch, ref } from 'vue'
33
44
import Changelog from 'virtual:nolebase-git-changelog'
5+
import type { Commit } from 'virtual:nolebase-git-changelog'
56
67
import { useRawPath } from '../composables/path'
78
import { useCommits } from '../composables/commits'
@@ -45,8 +46,14 @@ onMounted(async () => {
4546
const findRegisteredCreatorByName = (author_name: string) => options.mapContributors?.find(item => item.nameAliases && Array.isArray(item.nameAliases) && item.nameAliases.includes(author_name))
4647
const findRegisteredCreatorByEmail = (author_email: string) => options.mapContributors?.find(item => item.emailAliases && Array.isArray(item.emailAliases) && item.emailAliases.includes(author_email))
4748
48-
// This regular expression is used to match and parse commit messages that contain multiple author information.
49-
const multipleAuthorsRegex = /^ *?Co-authored-by:(.*)(?:<|\(|\[|\{)(.*)(?:>|\)|\]|\}) *?$/gmi
49+
/**
50+
* This regular expression is used to match and parse commit messages that contain multiple author information.
51+
*
52+
* @see {@link https://regex101.com/r/q5YB8m/1 | Regexp demo}
53+
* @see {@link https://en.wikipedia.org/wiki/Email_address#Local-part | Email addres}
54+
* @see {@link https://docs.github.com/en/pull-requests/committing-changes-to-your-project/creating-and-editing-commits/creating-a-commit-with-multiple-authors | Creating a commit with multiple authors in GitHub}
55+
*/
56+
const multipleAuthorsRegex = /^ *?Co-authored-by: ?(.*) ?(?:<)(.*)(?:>) *?/gmi
5057
5158
// This function handles multiple authors in a commit.
5259
// It uses the regular expression to extract the name and email of each author from the commit message.
@@ -58,9 +65,8 @@ async function handleMultipleAuthors(map: Record<string, ContributorInfo>, c: Co
5865
multipleAuthorsRegex.lastIndex = 0
5966
// eslint-disable-next-line no-cond-assign
6067
while (result = multipleAuthorsRegex.exec(c.body)) {
61-
let [, name, email] = result
62-
email = email.trim()
63-
handleCommitAuthors(map, name.trim(), email, await digestStringAsSHA256(email))
68+
const [, name, email] = result
69+
handleCommitAuthors(map, name.trim(), email.trim(), await digestStringAsSHA256(email))
6470
}
6571
}
6672

packages/vitepress-plugin-git-changelog/src/client/composables/commits.ts

+2-14
Original file line numberDiff line numberDiff line change
@@ -5,22 +5,10 @@ import type { Commit } from '../../types'
55

66
export function useCommits(allCommits: Commit[], path: MaybeRefOrGetter<string>) {
77
return computed<Commit[]>(() => {
8-
let currentPath = toValue(path)
8+
const currentPath = toValue(path)
99

1010
// filter the commits that either have a tag, or directly equal the current path, or renamed to the current path
11-
const commits = allCommits.filter((c) => {
12-
return c.tag || c.paths?.find((p) => {
13-
const action = p[0]
14-
const path1 = p[1]?.toLowerCase()
15-
const path2 = p[2]?.toLowerCase()
16-
17-
const res = currentPath === path1 || currentPath === path2
18-
if (res && action.startsWith('R'))
19-
currentPath = path1
20-
21-
return res
22-
})
23-
})
11+
const commits = allCommits.filter(c => c.path === currentPath) || []
2412

2513
return commits.filter((commit, index) => {
2614
if (commit.tag && (!commits[index + 1] || commits[index + 1]?.tag))
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,5 @@
1-
import { computed } from 'vue'
2-
import { useRoute } from 'vitepress'
1+
import { useData } from 'vitepress'
32

43
export function useRawPath() {
5-
const route = useRoute()
6-
7-
return computed(() => {
8-
let path = decodeURIComponent(route.path).toLowerCase()
9-
if (path.startsWith('/'))
10-
path = path.slice(1)
11-
12-
if (path.endsWith('/'))
13-
path += 'index.md'
14-
else
15-
path = path.replace(/^(.+?)(\.html)?$/s, '$1.md')
16-
17-
return path.toLowerCase()
18-
})
4+
return useData().page.value.filePath
195
}

0 commit comments

Comments
 (0)