Skip to content

Commit c98ddac

Browse files
committed
refactor: refactor release tags
1 parent a352806 commit c98ddac

6 files changed

Lines changed: 227 additions & 108 deletions

File tree

lib/git.js

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import CoreGit from "#core/api/git";
2+
import SemanticVersion from "#core/semantic-version";
23
import GitChangelog from "./git/changelog.js";
34

45
export default class Git extends CoreGit {
@@ -59,4 +60,117 @@ export default class Git extends CoreGit {
5960

6061
return res;
6162
}
63+
64+
async getReleaseTags ( { allowMajorTag } = {} ) {
65+
const res = await this.getTags();
66+
if ( !res.ok ) return res;
67+
68+
const tags = {};
69+
70+
if ( res.data ) {
71+
for ( const [ tag, commit ] of Object.entries( res.data ) ) {
72+
const isMajorTag = /^v\d+$/.test( tag );
73+
74+
// release tag
75+
if ( /^v\d+\.\d+\.\d+/.test( tag ) ) {
76+
if ( !SemanticVersion.isValid( tag ) ) continue;
77+
78+
const releaseVersion = new SemanticVersion( tag );
79+
80+
// next
81+
tags.next ??= {};
82+
tags.next.version ??= releaseVersion;
83+
if ( releaseVersion.gt( tags.next.version ) ) {
84+
tags.next.version = releaseVersion;
85+
}
86+
87+
// major.next
88+
const majorNextTag = `v${ releaseVersion.majorNumber }.next`;
89+
tags[ majorNextTag ] ??= {};
90+
tags[ majorNextTag ].version ??= releaseVersion;
91+
if ( releaseVersion.gt( tags[ majorNextTag ].version ) ) {
92+
tags[ majorNextTag ].version = releaseVersion;
93+
}
94+
95+
// stable release
96+
if ( releaseVersion.isStableRelease ) {
97+
98+
// latest
99+
tags.latest ??= {};
100+
tags.latest.version ??= releaseVersion;
101+
if ( releaseVersion.gt( tags.latest.version ) ) {
102+
tags.latest.version = releaseVersion;
103+
}
104+
105+
// major.latest
106+
const majorLatestTag = `v${ releaseVersion.majorNumber }.latest`;
107+
tags[ majorLatestTag ] ??= {};
108+
tags[ majorLatestTag ].version ??= releaseVersion;
109+
if ( releaseVersion.gt( tags[ majorLatestTag ].version ) ) {
110+
tags[ majorLatestTag ].version = releaseVersion;
111+
}
112+
113+
// major
114+
const majorTag = `v${ releaseVersion.majorNumber }`;
115+
tags[ majorTag ] ??= {
116+
"isMajorTag": true,
117+
};
118+
tags[ majorTag ].version = tags[ majorLatestTag ].version;
119+
}
120+
}
121+
else if ( tag === "latest" || tag === "next" || /^v\d+\.(?:latest|next)$/.test( tag ) || isMajorTag ) {
122+
tags[ tag ] ??= {
123+
isMajorTag,
124+
};
125+
126+
if ( commit.isRelease ) {
127+
tags[ tag ].current = commit.releaseVersion.version;
128+
}
129+
else {
130+
tags[ tag ].current = false;
131+
}
132+
}
133+
}
134+
}
135+
136+
const releaseTags = {};
137+
138+
for ( const tag in tags ) {
139+
releaseTags[ tag ] = {
140+
"version": tags[ tag ].version?.version,
141+
"action": null,
142+
};
143+
144+
// tag is not set
145+
if ( tags[ tag ].current == null ) {
146+
if ( tags[ tag ].version ) {
147+
if ( !tags[ tag ].isMajorTag || allowMajorTag ) {
148+
releaseTags[ tag ].action = "update";
149+
}
150+
}
151+
}
152+
153+
// major tag is set, but not allowed
154+
else if ( tags[ tag ].isMajorTag && !allowMajorTag ) {
155+
releaseTags[ tag ].action = "delete";
156+
}
157+
158+
// tag is set, but has no version
159+
else if ( !tags[ tag ].version ) {
160+
releaseTags[ tag ].action = "delete";
161+
}
162+
163+
// tag is set incorrectly
164+
else if ( tags[ tag ].current === false ) {
165+
releaseTags[ tag ].action = "update";
166+
}
167+
168+
// tag is set, but version is not valid
169+
else if ( tags[ tag ].current !== tags[ tag ].version.version ) {
170+
releaseTags[ tag ].action = "update";
171+
}
172+
}
173+
174+
return result( 200, releaseTags );
175+
}
62176
}

lib/package.js

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -482,19 +482,21 @@ export default class Package {
482482
if ( !res.ok ) return res;
483483
}
484484

485-
res = await this.git.getReleaseTags();
485+
res = await this.git.getReleaseTags( { "allowMajorTag": this.cliConfig?.release.allowMajorTag } );
486486
if ( !res.ok ) return res;
487487
const tags = res.data;
488488

489489
for ( const tag in tags ) {
490490

491491
// update tag
492492
if ( tags[ tag ].action === "update" ) {
493-
res = await this.git.exec( [ "tag", "--force", "--annotate", "--message", this.createReleaseTagAnnotation( tag ), tag, tags[ tag ].version ] );
493+
const annotation = this.createReleaseTagAnnotation( tag );
494+
495+
res = await this.git.exec( [ "tag", "--force", "--annotate", "--message", annotation, tag, "v" + tags[ tag ].version ] );
494496
if ( !res.ok ) return res;
495497

496498
if ( this.git.upstream ) {
497-
res = await this.git.exec( [ "push", "--atomic", "--force", "origin", tag ] );
499+
res = await this.git.exec( [ "push", "--force", "origin", tag ] );
498500
if ( !res.ok ) return res;
499501
}
500502

@@ -1181,7 +1183,23 @@ export default class Package {
11811183
}
11821184

11831185
createReleaseTagAnnotation ( tag ) {
1184-
TAG_MESSAGES[ tag ] || `Latest stable release for the branch: ${ tag }`;
1186+
var majorVersion;
1187+
1188+
if ( tag.includes( "." ) ) {
1189+
[ majorVersion, tag ] = tag.split( "." );
1190+
}
1191+
else if ( /^v\d+$/.test( tag ) ) {
1192+
majorVersion = tag;
1193+
tag = "latest";
1194+
}
1195+
1196+
var annotation = TAG_MESSAGES[ tag ];
1197+
1198+
if ( majorVersion != null ) {
1199+
annotation += ` for the branch: ${ majorVersion }`;
1200+
}
1201+
1202+
return annotation;
11851203
}
11861204

11871205
clearCache () {

lib/package/npm.js

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import ansi from "#core/ansi";
22
import NpmApi from "#core/api/npm";
3+
import SemanticVersion from "#core/semantic-version";
34
import { TmpDir } from "#core/tmp";
45
import { repeatAction } from "#core/utils";
56

@@ -222,24 +223,35 @@ export default class Npm {
222223

223224
res = await this.pkg.git.getReleaseTags();
224225
if ( !res.ok ) return res;
226+
const releaseTags = res.data;
225227

226-
const tags = {
227-
"latest": res.data.latest.version,
228-
"next": res.data.next.version,
229-
};
228+
const tags = {};
230229

231230
res = await this.api.getPackageTags( this.pkg.name );
232231
if ( !res.ok ) return res;
233232
const remoteTags = res.data || {};
234233

235-
for ( const [ tag, version ] of Object.entries( tags ) ) {
234+
for ( const [ tag, { version } ] of Object.entries( releaseTags ) ) {
235+
236+
// skip semantic versions
237+
if ( SemanticVersion.isValid( tag ) ) continue;
238+
239+
if ( version ) {
240+
tags[ tag ] = version;
241+
}
236242

237243
// set
238244
if ( version && remoteTags[ tag ] !== version ) {
239245
res = await this.api.setPackageTag( this.pkg.name, version, tag );
240-
if ( !res.ok ) return res;
241246

242-
updated = true;
247+
if ( !res.ok ) {
248+
if ( res.data?.error?.code !== "E404" ) {
249+
return res;
250+
}
251+
}
252+
else {
253+
updated = true;
254+
}
243255
}
244256

245257
// delete

0 commit comments

Comments
 (0)