@@ -4,7 +4,7 @@ import { promises as fs } from 'node:fs';
4
4
import semver from 'semver' ;
5
5
import { replaceInFile } from 'replace-in-file' ;
6
6
7
- import { runAsync , runSync } from './run.js' ;
7
+ import { forceRunAsync , runAsync , runSync } from './run.js' ;
8
8
import { writeJson , readJson } from './file.js' ;
9
9
import Request from './request.js' ;
10
10
import auth from './auth.js' ;
@@ -171,7 +171,7 @@ export default class ReleasePreparation extends Session {
171
171
// Check the branch diff to determine if the releaser
172
172
// wants to backport any more commits before proceeding.
173
173
cli . startSpinner ( 'Fetching branch-diff' ) ;
174
- const raw = this . getBranchDiff ( {
174
+ const raw = await this . getBranchDiff ( {
175
175
onlyNotableChanges : false ,
176
176
comparisonBranch : newVersion
177
177
} ) ;
@@ -335,18 +335,8 @@ export default class ReleasePreparation extends Session {
335
335
return missing ;
336
336
}
337
337
338
- async calculateNewVersion ( major ) {
339
- const { cli } = this ;
340
-
341
- cli . startSpinner ( `Parsing CHANGELOG for most recent release of v${ major } .x` ) ;
342
- const data = await fs . readFile (
343
- path . resolve ( `doc/changelogs/CHANGELOG_V${ major } .md` ) ,
344
- 'utf8'
345
- ) ;
346
- const [ , , minor , patch ] = / < a h r e f = " # ( \d + ) \. ( \d + ) \. ( \d + ) " > \1\. \2\. \3< \/ a > < b r \/ > / . exec ( data ) ;
347
-
348
- cli . stopSpinner ( `Latest release on ${ major } .x line is ${ major } .${ minor } .${ patch } ` ) ;
349
- const changelog = this . getChangelog ( `v${ major } .${ minor } .${ patch } ` ) ;
338
+ async calculateNewVersion ( { tagName, major, minor, patch } ) {
339
+ const changelog = this . getChangelog ( tagName ) ;
350
340
351
341
const newVersion = { major, minor, patch } ;
352
342
if ( changelog . includes ( 'SEMVER-MAJOR' ) ) {
@@ -478,7 +468,7 @@ export default class ReleasePreparation extends Session {
478
468
const data = await fs . readFile ( majorChangelogPath , 'utf8' ) ;
479
469
const arr = data . split ( '\n' ) ;
480
470
const allCommits = this . getChangelog ( ) ;
481
- const notableChanges = this . getBranchDiff ( { onlyNotableChanges : true } ) ;
471
+ const notableChanges = await this . getBranchDiff ( { onlyNotableChanges : true } ) ;
482
472
let releaseHeader = `## ${ date } , Version ${ newVersion } ` +
483
473
` ${ releaseInfo } , @${ username } \n` ;
484
474
if ( isSecurityRelease ) {
@@ -614,7 +604,7 @@ export default class ReleasePreparation extends Session {
614
604
messageBody . push ( 'This is a security release.\n\n' ) ;
615
605
}
616
606
617
- const notableChanges = this . getBranchDiff ( {
607
+ const notableChanges = await this . getBranchDiff ( {
618
608
onlyNotableChanges : true ,
619
609
format : 'plaintext'
620
610
} ) ;
@@ -641,8 +631,9 @@ export default class ReleasePreparation extends Session {
641
631
return useMessage ;
642
632
}
643
633
644
- getBranchDiff ( opts ) {
634
+ async getBranchDiff ( opts ) {
645
635
const {
636
+ cli,
646
637
versionComponents = { } ,
647
638
upstream,
648
639
newVersion,
@@ -670,6 +661,7 @@ export default class ReleasePreparation extends Session {
670
661
'semver-minor'
671
662
] ;
672
663
664
+ await forceRunAsync ( 'git' , [ 'fetch' , upstream , releaseBranch ] , { ignoreFailures : false } ) ;
673
665
branchDiffOptions = [
674
666
`${ upstream } /${ releaseBranch } ` ,
675
667
proposalBranch ,
@@ -688,20 +680,43 @@ export default class ReleasePreparation extends Session {
688
680
'baking-for-lts'
689
681
] ;
690
682
691
- let comparisonBranch = 'main' ;
683
+ let comparisonBranch = this . config . branch || 'main' ;
692
684
const isSemverMinor = versionComponents . patch === 0 ;
693
685
if ( isLTS ) {
686
+ const res = await fetch ( 'https://nodejs.org/dist/index.json' ) ;
687
+ if ( ! res . ok ) throw new Error ( 'Failed to fetch' , { cause : res } ) ;
688
+ const [ latest ] = await res . json ( ) ;
694
689
// Assume Current branch matches tag with highest semver value.
695
- const tags = runSync ( 'git' ,
696
- [ 'tag' , '-l' , '--sort' , '-version:refname' ] ) . trim ( ) ;
697
- const highestVersionTag = tags . split ( '\n' ) [ 0 ] ;
698
- comparisonBranch = `v${ semver . coerce ( highestVersionTag ) . major } .x` ;
690
+ comparisonBranch = `v${ semver . coerce ( latest . version ) . major } .x` ;
699
691
700
692
if ( ! isSemverMinor ) {
701
693
excludeLabels . push ( 'semver-minor' ) ;
702
694
}
703
695
}
704
696
697
+ await forceRunAsync ( 'git' , [ 'fetch' , upstream , comparisonBranch ] , { ignoreFailures : false } ) ;
698
+ const commits = await forceRunAsync ( 'git' , [ 'rev-parse' , 'FETCH_HEAD' , comparisonBranch ] , {
699
+ captureStdout : 'lines' ,
700
+ ignoreFailures : true
701
+ } ) ;
702
+ if ( commits == null ) {
703
+ const shouldCreateCompareBranch = await cli . prompt (
704
+ `No local branch ${ comparisonBranch } , do you want to create it?` ) ;
705
+ if ( shouldCreateCompareBranch ) {
706
+ await forceRunAsync ( 'git' , [ 'branch' , comparisonBranch , 'FETCH_HEAD' ] , {
707
+ ignoreFailures : false
708
+ } ) ;
709
+ }
710
+ } else if ( commits [ 0 ] !== commits [ 1 ] ) {
711
+ const shouldUpBranch = cli . prompt ( `Local ${ comparisonBranch } branch is not in sync with ${
712
+ upstream } /${ comparisonBranch } , do you want to update it?`) ;
713
+ if ( shouldUpBranch ) {
714
+ await forceRunAsync ( 'git' , [ 'branch' , '-f' , comparisonBranch , 'FETCH_HEAD' ] , {
715
+ ignoreFailures : false
716
+ } ) ;
717
+ }
718
+ }
719
+
705
720
branchDiffOptions = [
706
721
stagingBranch ,
707
722
comparisonBranch ,
@@ -718,6 +733,27 @@ export default class ReleasePreparation extends Session {
718
733
return runSync ( branchDiff , branchDiffOptions ) ;
719
734
}
720
735
736
+ async getLastRelease ( major ) {
737
+ const { cli } = this ;
738
+
739
+ cli . startSpinner ( `Parsing CHANGELOG for most recent release of v${ major } .x` ) ;
740
+ const data = await fs . readFile (
741
+ path . resolve ( `doc/changelogs/CHANGELOG_V${ major } .md` ) ,
742
+ 'utf8'
743
+ ) ;
744
+ const [ , , minor , patch ] = / < a h r e f = " # ( \d + ) \. ( \d + ) \. ( \d + ) " > \1\. \2\. \3< \/ a > < b r \/ > / . exec ( data ) ;
745
+ this . isLTS = data . includes ( '<th>LTS ' ) ;
746
+
747
+ cli . stopSpinner ( `Latest release on ${ major } .x line is ${ major } .${ minor } .${ patch } ${
748
+ this . isLTS ? ' (LTS)' : ''
749
+ } `) ;
750
+
751
+ return {
752
+ tagName : await this . getLastRef ( `v${ major } .${ minor } .${ patch } ` ) ,
753
+ major, minor, patch
754
+ } ;
755
+ }
756
+
721
757
async prepareLocalBranch ( ) {
722
758
const { cli } = this ;
723
759
if ( this . newVersion ) {
@@ -736,6 +772,7 @@ export default class ReleasePreparation extends Session {
736
772
this . stagingBranch = `v${ newVersion . major } .x-staging` ;
737
773
this . releaseBranch = `v${ newVersion . major } .x` ;
738
774
await this . tryResetBranch ( ) ;
775
+ await this . getLastRelease ( newVersion . major ) ;
739
776
return ;
740
777
}
741
778
@@ -751,7 +788,7 @@ export default class ReleasePreparation extends Session {
751
788
}
752
789
this . stagingBranch = currentBranch ;
753
790
await this . tryResetBranch ( ) ;
754
- this . versionComponents = await this . calculateNewVersion ( match [ 1 ] ) ;
791
+ this . versionComponents = await this . calculateNewVersion ( await this . getLastRelease ( match [ 1 ] ) ) ;
755
792
const { major, minor, patch } = this . versionComponents ;
756
793
this . newVersion = `${ major } .${ minor } .${ patch } ` ;
757
794
this . releaseBranch = `v${ major } .x` ;
0 commit comments