@@ -20,6 +20,9 @@ export default class Publish {
2020 #repeatOnError;
2121
2222 #currentRelease;
23+ #isMajorRelease;
24+ #currentBranch;
25+ #previousBranch;
2326 #changelog;
2427 #changelogMarkdown;
2528 #changelogText;
@@ -68,30 +71,35 @@ export default class Publish {
6871 if ( ! res . ok ) return res ;
6972 const status = res . data ;
7073
74+ this . #previousBranch = `v${ this . #changelog. previousRelease ?. majorNumber || "0" } .branch` ;
75+
7176 // check branch
7277 if ( ! status . head . isBranchHead ) {
7378 return result ( [ 500 , "Release on tbe detached head is not possible" ] ) ;
7479 }
75-
76- if ( this . #pkg. cliConfig . release . versionBranch ) {
77- if ( ! SemanticVersion . isValid ( status . head . branch ) ) {
78- return result ( [ 500 , "Release on not version branch is not possible" ] ) ;
80+ else {
81+ if ( status . head . branch !== this . #previousBranch ) {
82+ return result ( [ 500 , `You should be on the release branch "${ this . #previousBranch } " to make this release` ] ) ;
7983 }
8084 }
81- else if ( status . head . branch !== this . #pkg. cliConfig . release . releaseBranch ) {
82- return result ( [ 500 , `Release on not "${ this . #pkg. cliConfig . release . releaseBranch } " branch is not possible` ] ) ;
83- }
8485
8586 // check for uncommited changes
8687 if ( status . isDirty ) return result ( [ 500 , "working copy or sub-repositories has uncommited changes or untracked files" ] ) ;
8788
88- // define new version
89+ // create new version
8990 res = this . #changelog. getNextVersion ( this . #stable
9091 ? false
9192 : this . #preReleaseTag ) ;
9293 if ( ! res . ok ) return res ;
9394 this . #currentRelease = res . data ;
9495
96+ this . #currentBranch = `v${ this . #currentRelease. majorNumber } .branch` ;
97+
98+ // detect major release
99+ if ( this . #currentRelease. isMajor && this . #changelog. previousRelease && this . #currentRelease. majorNumber !== this . #changelog. previousRelease . majorNumber ) {
100+ this . #isMajorRelease = true ;
101+ }
102+
95103 // check version can be released
96104 res = status . releases . canRelease ( this . #currentRelease ) ;
97105 if ( ! res . ok ) return res ;
@@ -148,6 +156,10 @@ export default class Publish {
148156
149157 console . log ( `New version: ${ ansi . underline ( this . #currentRelease. versionString ) } , tags: ${ this . #createTagsText( ) || "-" } ` ) ;
150158 console . log ( `Previous version: ${ this . #changelog. previousRelease ?. versionString || "-" } ` ) ;
159+
160+ if ( this . #isMajorRelease ) {
161+ console . log ( `New release branch "${ this . #currentBranch } " will be created` ) ;
162+ }
151163 console . log ( ) ;
152164
153165 if ( subPackages . length ) {
@@ -193,6 +205,27 @@ export default class Publish {
193205 }
194206 }
195207
208+ // major release
209+ if ( this . #isMajorRelease ) {
210+
211+ // create and switch major release branch
212+ res = await this . #pkg. git . exec ( [ "switch" , "--create" , this . #currentBranch ] ) ;
213+ if ( ! res . ok ) return res ;
214+
215+ // move previous release branch head
216+ if ( this . #changelog. previousRelease ) {
217+ res = await this . #pkg. git . exec ( [
218+
219+ //
220+ "branch" ,
221+ "--force" ,
222+ this . #previousBranch,
223+ this . #changelog. previousRelease . versionString ,
224+ ] ) ;
225+ if ( ! res . ok ) return res ;
226+ }
227+ }
228+
196229 // update documentation
197230 res = await this . #updateDocs( ) ;
198231 if ( ! res . ok ) return res ;
@@ -238,37 +271,85 @@ export default class Publish {
238271
239272 // set version tag
240273 res = await this . #setTag( this . #currentRelease. versionString , {
274+ "force" : false ,
241275 "annotation" : `Release ${ this . #currentRelease. versionString } \n\n${ this . #changelogText } \n` ,
242276 } ) ;
243277 if ( ! res . ok ) return res ;
244278
245- // set "latest" tag
246- res = await this . #setTag( this . #latestTag, { "force" : true } ) ;
247- if ( ! res . ok ) return res ;
248-
249- // set next tag
250- res = await this . #setTag( this . #nextTag, { "force" : true } ) ;
251- if ( ! res . ok ) return res ;
279+ // set tags
280+ for ( const tag of [ this . #latestTag, this . #nextTag, this . #majorTag, this . #majorLatestTag, this . #majorNextTag ] ) {
281+ if ( ! tag ) continue ;
252282
253- // set major tag
254- res = await this . #setTag( this . #majorTag, { "force" : true } ) ;
255- if ( ! res . ok ) return res ;
256-
257- // set major.latest tag
258- res = await this . #setTag( this . #majorLatestTag, { "force" : true } ) ;
259- if ( ! res . ok ) return res ;
283+ res = await this . #setTag( tag , {
284+ "force" : true ,
285+ "annotation" : this . #pkg. createReleaseTagAnnotation ( tag ) ,
286+ } ) ;
260287
261- // set major.next tag
262- res = await this . #setTag( this . #majorNextTag, { "force" : true } ) ;
263- if ( ! res . ok ) return res ;
288+ if ( ! res . ok ) return res ;
289+ }
264290
265291 // push, if has upstream
266292 if ( this . #pkg. git . upstream ) {
293+
294+ // track current branch
295+ if ( this . #isMajorRelease ) {
296+ res = await repeatAction (
297+ async ( ) => {
298+ process . stdout . write ( `Setting upstream for branch "${ this . #currentBranch } " ... ` ) ;
299+
300+ const params = [
301+
302+ //
303+ "push" ,
304+ "--set-upstream" ,
305+ "origin" ,
306+ this . #currentBranch,
307+ ] ;
308+
309+ const res = await this . #pkg. git . exec ( params ) ;
310+
311+ console . log ( res + "" ) ;
312+
313+ // repeat
314+ if ( ! res . ok ) {
315+ throw res ;
316+ }
317+ else {
318+ return res ;
319+ }
320+ } ,
321+ {
322+ "repeatOnError" : this . #repeatOnError,
323+ }
324+ ) ;
325+ if ( ! res . ok ) return res ;
326+ }
327+
328+ // push references
267329 res = await repeatAction (
268330 async ( ) => {
269331 process . stdout . write ( "Pushing ... " ) ;
270332
271- const params = [ "push" , "--atomic" , "--force" , "origin" , status . head . branch , this . #currentRelease. versionString , this . #latestTag, this . #nextTag, this . #majorTag, this . #majorLatestTag, this . #majorNextTag ] . filter ( param => param != null && param !== "" ) ;
333+ const params = [
334+
335+ //
336+ "push" ,
337+ "--atomic" ,
338+ "--force" ,
339+ "origin" ,
340+ ...new Set ( [
341+
342+ //
343+ this . #currentBranch,
344+ this . #previousBranch,
345+ this . #currentRelease. versionString ,
346+ this . #latestTag,
347+ this . #nextTag,
348+ this . #majorTag,
349+ this . #majorLatestTag,
350+ this . #majorNextTag,
351+ ] . filter ( param => param != null && param !== "" ) ) ,
352+ ] ;
272353
273354 const res = await this . #pkg. git . exec ( params ) ;
274355
@@ -503,7 +584,7 @@ ${ this.#changelog.linkifyMarkdown( changelogMarkdown ) }
503584` . trim ( ) + "\n" ;
504585
505586 // append CHANGELOG.md
506- if ( ! this . #currentRelease . isMajor ) {
587+ if ( ! this . #isMajorRelease ) {
507588 if ( await pathExists ( this . #pkg. root + "/CHANGELOG.md" ) ) {
508589 fullChangelog +=
509590 fs
@@ -541,8 +622,6 @@ ${ this.#changelog.linkifyMarkdown( changelogMarkdown ) }
541622 async #setTag ( tag , { annotation, force } = { } ) {
542623 if ( ! tag ) return result ( 200 ) ;
543624
544- annotation ||= this . #pkg. createReleaseTagAnnotation ( tag ) ;
545-
546625 return repeatAction (
547626 async ( ) => {
548627 process . stdout . write ( `Adding "${ tag } " tag ... ` ) ;
0 commit comments