@itcase/config 1.7.7 → 1.7.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +20 -0
- package/package.json +2 -1
- package/semantic-release/common.js +5 -5
- package/semantic-release/releaseNotesFromCommits.js +116 -0
- package/semantic-release/semanticReleaseApp.js +3 -3
- package/semantic-release/semanticReleaseMonorepo.js +3 -2
- package/semantic-release/semanticReleaseProject.js +2 -2
- /package/semantic-release/{issuesReleaseNotes.js → releaseNotesFromIssues.js} +0 -0
package/README.md
CHANGED
|
@@ -168,6 +168,26 @@ CLI ставится в `~/.local/bin`. Логин в Cursor IDE этот CLI н
|
|
|
168
168
|
|
|
169
169
|
> **Важно:** в npm есть одноимённый пакет `smart-commit`. Используйте `npm run smart-commit` из проекта с `@itcase/config` — bin берётся из `node_modules`. `npx smart-commit` без локальной установки может подтянуть чужой пакет; CLI перед запуском проверяет, что выполняется именно `@itcase/config`.
|
|
170
170
|
|
|
171
|
+
## Подключение Semantic Release
|
|
172
|
+
|
|
173
|
+
Обычный пакет:
|
|
174
|
+
|
|
175
|
+
```js
|
|
176
|
+
import { semanticReleasePackage } from '@itcase/config/semantic-release/index.js'
|
|
177
|
+
|
|
178
|
+
export default semanticReleasePackage
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
Монорепозиторий:
|
|
182
|
+
|
|
183
|
+
```js
|
|
184
|
+
import { semanticReleaseMonorepo } from '@itcase/config/semantic-release/index.js'
|
|
185
|
+
|
|
186
|
+
export default semanticReleaseMonorepo
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
Заметки монорепозитория печатает `conventional-changelog-writer` 9 из этого пакета. Writer 8, который ставит semantic-release, для `conventional-changelog-conventionalcommits` 10 оставляет в `CHANGELOG.md` только заголовок версии. Отдельный `overrides` в репозитории не нужен. Уже опубликованный релиз сам не перепишется.
|
|
190
|
+
|
|
171
191
|
## Подключение Husky
|
|
172
192
|
|
|
173
193
|
В git кладите только `.husky/config`. Обёртки хуков и `_run.sh` создаёт `itcase-config-husky-install` при `npm i`. Логика хуков живёт в `@itcase/config/husky-hooks`.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@itcase/config",
|
|
3
|
-
"version": "1.7.
|
|
3
|
+
"version": "1.7.9",
|
|
4
4
|
"author": "ITCase",
|
|
5
5
|
"description": "ITCase Config",
|
|
6
6
|
"engines": {
|
|
@@ -67,6 +67,7 @@
|
|
|
67
67
|
"chokidar-cli": "^3.0.0",
|
|
68
68
|
"commitizen": "^4.3.2",
|
|
69
69
|
"conventional-changelog-conventionalcommits": "9.3.1",
|
|
70
|
+
"conventional-changelog-writer": "9.2.1",
|
|
70
71
|
"cssnano": "^9.0.5",
|
|
71
72
|
"cssnano-preset-default": "^9.0.5",
|
|
72
73
|
"inquirer": "^14.2.2",
|
|
@@ -12,17 +12,17 @@ import {
|
|
|
12
12
|
releaseRules,
|
|
13
13
|
} from './config.js'
|
|
14
14
|
|
|
15
|
-
const
|
|
15
|
+
const releaseNotesFromIssuesScript = join(
|
|
16
16
|
dirname(fileURLToPath(import.meta.url)),
|
|
17
|
-
'
|
|
17
|
+
'releaseNotesFromIssues.js',
|
|
18
18
|
)
|
|
19
19
|
|
|
20
20
|
// Ссылки на задачи из PR. Репозиторий задач и токен приходят из CI:
|
|
21
21
|
// RELEASE_NOTES_ISSUES_REPO, RELEASE_NOTES_GH_TOKEN.
|
|
22
|
-
const
|
|
22
|
+
const releaseNotesFromIssuesPlugin = [
|
|
23
23
|
'@semantic-release/exec',
|
|
24
24
|
{
|
|
25
|
-
generateNotesCmd: `node ${JSON.stringify(
|
|
25
|
+
generateNotesCmd: `node ${JSON.stringify(releaseNotesFromIssuesScript)} "\${lastRelease.gitTag}" "\${nextRelease.gitTag}"`,
|
|
26
26
|
},
|
|
27
27
|
]
|
|
28
28
|
|
|
@@ -132,6 +132,6 @@ function createSemanticReleaseConfig({
|
|
|
132
132
|
export {
|
|
133
133
|
commonPlugins,
|
|
134
134
|
createSemanticReleaseConfig,
|
|
135
|
-
|
|
135
|
+
releaseNotesFromIssuesPlugin,
|
|
136
136
|
releaseNotesGeneratorConfig,
|
|
137
137
|
}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { existsSync, readFileSync } from 'node:fs'
|
|
2
|
+
import { dirname, join } from 'node:path'
|
|
3
|
+
import { format, pathToFileURL } from 'node:url'
|
|
4
|
+
|
|
5
|
+
import { writeChangelogString } from 'conventional-changelog-writer'
|
|
6
|
+
import { filterRevertedCommitsSync } from 'conventional-commits-filter'
|
|
7
|
+
import { CommitParser } from 'conventional-commits-parser'
|
|
8
|
+
|
|
9
|
+
import { releaseNotesGeneratorConfig } from './common.js'
|
|
10
|
+
|
|
11
|
+
// Импорт из этого файла резолвит writer 9, зависимость @itcase/config.
|
|
12
|
+
// Writer 8, который semantic-release поднимает в корень монорепозитория,
|
|
13
|
+
// для preset 10 печатает только заголовок версии.
|
|
14
|
+
|
|
15
|
+
function resolvePackageEntry(cwd, packageName) {
|
|
16
|
+
let directory = cwd
|
|
17
|
+
|
|
18
|
+
while (true) {
|
|
19
|
+
const packageDir = join(directory, 'node_modules', packageName)
|
|
20
|
+
const packageJsonPath = join(packageDir, 'package.json')
|
|
21
|
+
|
|
22
|
+
if (existsSync(packageJsonPath)) {
|
|
23
|
+
const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf8'))
|
|
24
|
+
const exportEntry = packageJson.exports
|
|
25
|
+
const relativeEntry =
|
|
26
|
+
exportEntry?.import ||
|
|
27
|
+
exportEntry?.['.']?.import ||
|
|
28
|
+
packageJson.module ||
|
|
29
|
+
packageJson.main
|
|
30
|
+
|
|
31
|
+
return pathToFileURL(join(packageDir, relativeEntry)).href
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const parentDirectory = dirname(directory)
|
|
35
|
+
if (parentDirectory === directory) {
|
|
36
|
+
break
|
|
37
|
+
}
|
|
38
|
+
directory = parentDirectory
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
throw new Error(`Cannot resolve "${packageName}" from "${cwd}"`)
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
async function loadPreset(cwd, presetConfig) {
|
|
45
|
+
const presetUrl = resolvePackageEntry(
|
|
46
|
+
cwd,
|
|
47
|
+
'conventional-changelog-conventionalcommits',
|
|
48
|
+
)
|
|
49
|
+
const presetModule = await import(presetUrl)
|
|
50
|
+
|
|
51
|
+
return presetModule.default(presetConfig)
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
async function generateReleaseNotes(pluginConfig, context) {
|
|
55
|
+
const { commits, cwd, lastRelease, nextRelease, options } = context
|
|
56
|
+
const repositoryUrl = options.repositoryUrl.replace(/\.git$/i, '')
|
|
57
|
+
const loadedPreset = await loadPreset(cwd, pluginConfig.presetConfig)
|
|
58
|
+
const parser = new CommitParser({
|
|
59
|
+
referenceActions: [
|
|
60
|
+
'close',
|
|
61
|
+
'closes',
|
|
62
|
+
'closed',
|
|
63
|
+
'fix',
|
|
64
|
+
'fixes',
|
|
65
|
+
'fixed',
|
|
66
|
+
'resolve',
|
|
67
|
+
'resolves',
|
|
68
|
+
'resolved',
|
|
69
|
+
],
|
|
70
|
+
issuePrefixes: ['#', 'gh-'],
|
|
71
|
+
...loadedPreset.parser,
|
|
72
|
+
...pluginConfig.parserOpts,
|
|
73
|
+
})
|
|
74
|
+
const parsedCommits = filterRevertedCommitsSync(
|
|
75
|
+
commits
|
|
76
|
+
.filter((commit) => commit.message?.trim())
|
|
77
|
+
.map((rawCommit) => ({
|
|
78
|
+
...rawCommit,
|
|
79
|
+
...parser.parse(rawCommit.message),
|
|
80
|
+
})),
|
|
81
|
+
)
|
|
82
|
+
const previousTag = lastRelease.gitTag || lastRelease.gitHead
|
|
83
|
+
const currentTag = nextRelease.gitTag || nextRelease.gitHead
|
|
84
|
+
const repository = new URL(repositoryUrl)
|
|
85
|
+
const protocol = repository.protocol === 'http:' ? 'http' : 'https'
|
|
86
|
+
const [, owner, repositoryName] =
|
|
87
|
+
/^\/(?<owner>[^/]+)?\/?(?<repository>.+)?$/.exec(repository.pathname) || []
|
|
88
|
+
|
|
89
|
+
return writeChangelogString(
|
|
90
|
+
parsedCommits,
|
|
91
|
+
{
|
|
92
|
+
commit: 'commit',
|
|
93
|
+
currentTag,
|
|
94
|
+
host: format({
|
|
95
|
+
hostname: repository.hostname,
|
|
96
|
+
port: repository.port,
|
|
97
|
+
protocol: `${protocol}:`,
|
|
98
|
+
}),
|
|
99
|
+
linkCompare: Boolean(currentTag && previousTag),
|
|
100
|
+
owner,
|
|
101
|
+
previousTag,
|
|
102
|
+
repository: repositoryName,
|
|
103
|
+
version: nextRelease.version,
|
|
104
|
+
issue: 'issues',
|
|
105
|
+
},
|
|
106
|
+
{ ...loadedPreset.writer, ...pluginConfig.writerOpts },
|
|
107
|
+
)
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
const releaseNotesFromCommitsPlugin = {
|
|
111
|
+
async generateNotes(_pluginConfig, context) {
|
|
112
|
+
return generateReleaseNotes(releaseNotesGeneratorConfig, context)
|
|
113
|
+
},
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
export { releaseNotesFromCommitsPlugin }
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
createSemanticReleaseConfig,
|
|
3
|
-
|
|
3
|
+
releaseNotesFromIssuesPlugin,
|
|
4
4
|
} from './common.js'
|
|
5
5
|
|
|
6
6
|
const DEFAULT_VERSION_ASSETS = [
|
|
@@ -18,7 +18,7 @@ const DEFAULT_RELEASE_ASSETS = ['builds/*.apk']
|
|
|
18
18
|
* - Не публикует в npm
|
|
19
19
|
* - Коммитит package + Android version-файлы
|
|
20
20
|
* - Прикрепляет к GitHub release APK из `builds/` (если есть; отсутствующие пропускаются)
|
|
21
|
-
* - Заметки релиза: сначала задачи из
|
|
21
|
+
* - Заметки релиза: сначала задачи из releaseNotesFromIssues.js, если они есть, потом обычные коммиты
|
|
22
22
|
*
|
|
23
23
|
* Сборку APK делайте в prepare проекта или отдельным CI job до publish.
|
|
24
24
|
*
|
|
@@ -39,7 +39,7 @@ function createSemanticReleaseApp({
|
|
|
39
39
|
versionAssets = DEFAULT_VERSION_ASSETS,
|
|
40
40
|
} = {}) {
|
|
41
41
|
return createSemanticReleaseConfig({
|
|
42
|
-
additionalPlugins: [
|
|
42
|
+
additionalPlugins: [releaseNotesFromIssuesPlugin],
|
|
43
43
|
branches: branches,
|
|
44
44
|
gitConfig: {
|
|
45
45
|
message:
|
|
@@ -4,6 +4,7 @@ import { readFile, writeFile } from 'node:fs/promises'
|
|
|
4
4
|
import { resolve } from 'node:path'
|
|
5
5
|
|
|
6
6
|
import { createSemanticReleaseConfig } from './common.js'
|
|
7
|
+
import { releaseNotesFromCommitsPlugin } from './releaseNotesFromCommits.js'
|
|
7
8
|
|
|
8
9
|
const RELEASE_ASSETS = [
|
|
9
10
|
'lerna.json',
|
|
@@ -41,14 +42,14 @@ const semanticReleaseMonorepo = createSemanticReleaseConfig({
|
|
|
41
42
|
[
|
|
42
43
|
'semantic-release-lerna',
|
|
43
44
|
{
|
|
44
|
-
// Заметки lerna для монорепо выходят пустыми. Их пишет
|
|
45
|
-
// @semantic-release/release-notes-generator, как в обычных пакетах.
|
|
46
45
|
generateNotes: false,
|
|
47
46
|
latch: false,
|
|
48
47
|
},
|
|
49
48
|
],
|
|
49
|
+
releaseNotesFromCommitsPlugin,
|
|
50
50
|
],
|
|
51
51
|
preparePlugins: [keepLernaIndependentPlugin],
|
|
52
|
+
skipReleaseNotesGenerator: true,
|
|
52
53
|
})
|
|
53
54
|
|
|
54
55
|
export { semanticReleaseMonorepo }
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import {
|
|
2
2
|
createSemanticReleaseConfig,
|
|
3
|
-
|
|
3
|
+
releaseNotesFromIssuesPlugin,
|
|
4
4
|
} from './common.js'
|
|
5
5
|
|
|
6
6
|
const semanticReleaseProject = createSemanticReleaseConfig({
|
|
7
|
-
additionalPlugins: [
|
|
7
|
+
additionalPlugins: [releaseNotesFromIssuesPlugin],
|
|
8
8
|
branches: ['docker/master'],
|
|
9
9
|
gitConfig: {
|
|
10
10
|
message: 'release: publishing new version ${nextRelease.version} [skip ci]',
|
|
File without changes
|