Skip to content

Commit 28a4fc1

Browse files
committed
fix(versioner): catch missing version property, add --short-name, add ref links to changelog
1 parent 09bf6b4 commit 28a4fc1

File tree

3 files changed

+4554
-5805
lines changed

3 files changed

+4554
-5805
lines changed

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
"husky": "^8.0.3",
2626
"lint-staged": "13.2.2",
2727
"nyc": "^15.1.0",
28+
"prettier": "^3.4.2",
2829
"sinon": "15.1.0",
2930
"ts-node": "^10.9.1",
3031
"typescript": "^5.1.3"
@@ -64,4 +65,4 @@
6465
]
6566
}
6667
}
67-
}
68+
}

packages/versioner/src/versioner.ts

Lines changed: 45 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,14 @@ import writePackage from 'write-pkg';
1212
import yargs from 'yargs-parser';
1313

1414
const argv = yargs(process.argv.slice(2));
15-
const { commitScopes = true, dry: dryRun, publish: doPublish, push: doPush, tag: doTag } = argv;
15+
const {
16+
commitScopes = true,
17+
dry: dryRun,
18+
publish: doPublish,
19+
push: doPush,
20+
shortName: shortNameOverride,
21+
tag: doTag
22+
} = argv;
1623
const log = getLog({ brand: '@dot', name: '\u001b[1D/versioner' });
1724
const parserOptions = {
1825
noteKeywords: ['BREAKING CHANGE', 'Breaking Change']
@@ -120,6 +127,24 @@ const getNewVersion = (version: string, commits: Commit[]): string | null => {
120127
return semver.inc(version, level);
121128
};
122129

130+
const getRepoUrls = async () => {
131+
try {
132+
const { stdout: remoteUrl } = await execa('git', ['config', '--get', 'remote.origin.url']);
133+
const match = remoteUrl.match(
134+
/(?:https:\/\/github\.com\/|git@github\.com:)(?<owner>[^/]+)\/(?<repo>[^.]+)(?:\.git)?/
135+
);
136+
if (!match?.groups) return null;
137+
const { owner, repo } = match.groups;
138+
return {
139+
commit: `https://github.com/${owner}/${repo}/commit`,
140+
// Note: github has a redirect from /issues to /pull for pull requests
141+
issue: `https://github.com/${owner}/${repo}/issues`
142+
};
143+
} catch (error) {
144+
return null;
145+
}
146+
};
147+
123148
const publish = async (cwd: string) => {
124149
if (dryRun || doPublish === false) {
125150
log.warn(chalk`{yellow Skipping Publish}`);
@@ -174,7 +199,7 @@ const tag = async (cwd: string, shortName: string, version: string) => {
174199
await execa('git', ['tag', tagName], { cwd, stdio: 'inherit' });
175200
};
176201

177-
const updateChangelog = (
202+
const updateChangelog = async (
178203
commits: Commit[],
179204
cwd: string,
180205
targetName: string,
@@ -191,23 +216,17 @@ const updateChangelog = (
191216
const notes: Notes = { breaking: [], features: [], fixes: [], updates: [] };
192217
const individuals = `(([\\w-]+,)+)?${shortName}((,[\\w-]+)+)?`;
193218
const reScope = new RegExp(`^[\\w\\!]+\\((${individuals}|\\*)\\)`, 'i');
219+
const reIssue = /\(#\d+\)/;
220+
const repoUrls = await getRepoUrls();
194221

195222
for (const { breaking, hash, header, type } of commits) {
196-
const ref = /\(#\d+\)/.test(header as string) ? '' : ` (${hash?.substring(0, 7)})`;
197-
const message = header?.trim().replace(reScope, '$1') + ref;
198-
199-
// TODO: changelog links
200-
// GITHUB_REPOSITORY;
201-
// GITHUB_SERVER_URL;
202-
203-
// const ref = /\(#\d+\)/.test(header as string)
204-
// ? ''
205-
// : ` ([${hash?.substring(0, 7)}](https://github.com/rollup/plugins/commit/${hash}))`;
206-
// const message =
207-
// header
208-
// ?.trim()
209-
// .replace(/\(.+\)!?:/, ':')
210-
// .replace(/\((#(\d+))\)/, '[$1](https://github.com/rollup/plugins/pull/$2)') + ref;
223+
const ref = header?.match(reIssue)?.[0] || `(${hash?.substring(0, 7)})`;
224+
const cleaned = header?.trim().replace(reScope, '$1').replace(ref, '').trim();
225+
const linkRef = ref.replace(/\([#]?(.+?)\)/, '$1');
226+
const link = repoUrls
227+
? `([${linkRef}](${reIssue.test(ref) ? repoUrls.issue : repoUrls.commit}/${linkRef}))`
228+
: ref;
229+
const message = `${cleaned} ${link}`;
211230

212231
if (breaking) {
213232
notes.breaking.push(message);
@@ -259,17 +278,21 @@ const updatePackage = async (cwd: string, pkg: RepoPackage, version: string) =>
259278
const stripScope: string[] = argv.stripScope?.split(',') || ['^@.+/'];
260279

261280
const { name: targetName }: { name: string } = await import(join(cwd, 'package.json'));
262-
const shortName = stripScope.reduce(
263-
(prev, strip) => prev.replace(new RegExp(strip), ''),
264-
targetName
265-
);
281+
const shortName =
282+
shortNameOverride ||
283+
stripScope.reduce((prev, strip) => prev.replace(new RegExp(strip), ''), targetName);
266284
const parentDirName = dirname(resolve(cwd, '..'));
267285

268286
if (!cwd || !existsSync(cwd)) {
269287
throw new RangeError(`Could not find directory for package: ${targetName}${cwd}`);
270288
}
271289

272-
const { default: pkg }: RepoPackage = await import(join(cwd, 'package.json'));
290+
const pkgPath = join(cwd, 'package.json');
291+
const { default: pkg }: RepoPackage = await import(pkgPath);
292+
293+
if (!pkg?.version) {
294+
throw new RangeError(`${pkgPath} doesn't contain a "version" property. please add one.`);
295+
}
273296

274297
if (dryRun) {
275298
log.warn(chalk`{magenta DRY RUN}: No files will be modified`);

0 commit comments

Comments
 (0)