@@ -12,7 +12,14 @@ import writePackage from 'write-pkg';
1212import yargs from 'yargs-parser' ;
1313
1414const 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 ;
1623const log = getLog ( { brand : '@dot' , name : '\u001b[1D/versioner' } ) ;
1724const 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+ / (?: h t t p s : \/ \/ g i t h u b \. c o m \/ | g i t @ g i t h u b \. c o m : ) (?< owner > [ ^ / ] + ) \/ (?< repo > [ ^ . ] + ) (?: \. g i t ) ? /
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+
123148const 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