Skip to content
This repository has been archived by the owner on Mar 18, 2024. It is now read-only.

Commit

Permalink
feat(publish): Add new flag to delete Git tags by age and limit (#1275)
Browse files Browse the repository at this point in the history
This feature will reduce the tag proliferation in a dxatscale repository. Additional two flags are provided which will allow users to ensure tags are kept only to certain limits or by days

---------

Co-authored-by: azlam-abdulsalam <[email protected]>
  • Loading branch information
JoeffreyChaucer and azlam-abdulsalam authored Mar 22, 2023
1 parent d6135c0 commit aae62d6
Show file tree
Hide file tree
Showing 4 changed files with 143 additions and 3 deletions.
4 changes: 4 additions & 0 deletions packages/core/src/git/Git.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,10 @@ export default class Git {
}
}

async deleteTags(tags?: string[]) {
if (tags) await this._git.push('origin', '--delete', tags);
}

async addAnnotatedTag(tagName: string, annotation: string, commitId?: string) {
try {
await new GitIdentity(this._git).setUsernameAndEmail();
Expand Down
61 changes: 61 additions & 0 deletions packages/core/src/git/GitTags.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,4 +87,65 @@ export default class GitTags {

return packageVersionNumber;
}


public async limitTags(limit: number): Promise<string[]>{
let rawTags = await this.listTagsOnBranch();

if (rawTags.length <= limit) {
return [];
}

const tags:string [] = rawTags.slice(0, Math.abs(limit) * -1);
return tags;
}


public async filteredOldTags(daysToKeep: number, limit?: number): Promise<string[]> {
const currentTimestamp = Math.floor(Date.now() / 1000);

let rawTags: string[];
if (limit) {
rawTags = await this.limitTags(limit);
} else {
rawTags = await this.listTagsOnBranch();
}

if (rawTags.length < 0) {
return [];
}

let tags: string[] = await this.getTagsWithTimestamps(rawTags);

const filteredTags = tags
.map(tagStr => {
const [name, timestampStr] = tagStr.split(' ');
const timestamp = parseInt(timestampStr, 10);
return { name, timestamp };
})
.filter(tag => {
const daysSinceTag = (currentTimestamp - tag.timestamp) / 86400;
return tag.name && daysSinceTag > daysToKeep;
});

return filteredTags.map(tag => tag.name);
}

private async getTagsWithTimestamps(tags: string[]): Promise<string[]> {
const timestampPromises: Promise<number>[] = [];

// Create an array of promises that will get the tagger date for each tag
tags.forEach((tag: string) => {
timestampPromises.push(
this.git.log(['--format=%at', `refs/tags/${tag}`])
.then((output: string[]) => parseInt(output[0].trim(), 10))
);
});

// Wait for all promises to resolve and format the output
const timestamps: number[] = await Promise.all(timestampPromises);
const tagsWithTimestamp = tags.map((tag: string, index: number) => `${tag} ${timestamps[index]}`);
return tagsWithTimestamp
}

}
4 changes: 3 additions & 1 deletion packages/sfpowerscripts-cli/messages/publish.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,7 @@
"scopeFlagDescription": "(required for NPM) User or Organisation scope of the NPM package",
"npmTagFlagDescription": "Add an optional distribution tag to NPM packages. If not provided, the 'latest' tag is set to the published version.",
"npmrcPathFlagDescription": "Path to .npmrc file used for authentication to registry. If left blank, defaults to home directory",
"logsGroupSymbolFlagDescription": "Symbol used by CICD platform to group/collapse logs in the console. Provide an opening group, and an optional closing group symbol."
"logsGroupSymbolFlagDescription": "Symbol used by CICD platform to group/collapse logs in the console. Provide an opening group, and an optional closing group symbol.",
"gitTagAgeFlagDescription": "Specifies the number of days,for a tag to be retained,any tags older the provided number will be deleted",
"gitTagLimitFlagDescription": "Specifies the minimum number of tags to be retained for a package"
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import PackageVersionLister from '@dxatscale/sfpowerscripts.core/lib/package/ver
import SFPOrg from '@dxatscale/sfpowerscripts.core/lib/org/SFPOrg';
import ExecuteCommand from '@dxatscale/sfdx-process-wrapper/lib/commandExecutor/ExecuteCommand';
import { LoggerLevel } from '@dxatscale/sfp-logger';
import GitTags from '@dxatscale/sfpowerscripts.core/lib/git/GitTags';

Messages.importMessagesDirectory(__dirname);
const messages = Messages.loadMessages('@dxatscale/sfpowerscripts', 'publish');
Expand Down Expand Up @@ -68,6 +69,12 @@ export default class Promote extends SfpowerscriptsCommand {
description: messages.getMessage('gitTagFlagDescription'),
default: false,
}),
gittaglimit: flags.number({
description: messages.getMessage('gitTagLimitFlagDescription'),
}),
gittagage: flags.number({
description: messages.getMessage('gitTagAgeFlagDescription'),
}),
pushgittag: flags.boolean({
description: messages.getMessage('gitPushTagFlagDescription'),
default: false,
Expand Down Expand Up @@ -222,6 +229,17 @@ export default class Promote extends SfpowerscriptsCommand {
await this.createGitTags(succesfullyPublishedPackageNamesForTagging);
await this.pushGitTags(succesfullyPublishedPackageNamesForTagging);
}


if (this.flags.gittagage && this.flags.gittaglimit) {
await this.deleteGitTagsOlderThan(succesfullyPublishedPackageNamesForTagging, this.flags.gittagage, this.flags.gittaglimit);
} else if (this.flags.gittagage) {
await this.deleteGitTagsOlderThan(succesfullyPublishedPackageNamesForTagging, this.flags.gittagage);
} else if (this.flags.gittaglimit) {
await this.deleteExcessGitTags(succesfullyPublishedPackageNamesForTagging, this.flags.gittaglimit);
}


} catch (err) {
SFPLogger.log(err.message);

Expand Down Expand Up @@ -361,7 +379,7 @@ export default class Promote extends SfpowerscriptsCommand {
commitId: string;
}[]
) {

if (this.flags.pushgittag) {
let tagsForPushing:string[]=[];
for (let succesfullyPublishedPackage of sucessfullyPublishedPackages) {
Expand All @@ -381,7 +399,7 @@ export default class Promote extends SfpowerscriptsCommand {
commitId: string;
}[]
) {

for (let sucessFullyPublishedPackage of sucessfullyPublishedPackages) {
SFPLogger.log(COLOR_KEY_MESSAGE(`Creating Git Tags in Repo ${sucessFullyPublishedPackage.tag}`));
await this.git.addAnnotatedTag(
Expand All @@ -392,6 +410,61 @@ export default class Promote extends SfpowerscriptsCommand {
}
}

//Exclude the latest git tag up to a specified number of tags, and then deletes the excess tags that exceed that limit.
private async deleteExcessGitTags( tags: {
name: string;
version: string;
type: string;
tag: string;
commitId: string;
}[], limit: number) {
//const pkgs = ProjectConfig.getAllPackages(this.git.getRepositoryPath());
const tagsToDelete: string[] = [];

await Promise.all(tags.map(async (tag) => {
const gitTags = new GitTags(this.git, tag.name);
const tags = await gitTags.limitTags(limit);
tagsToDelete.push(...tags);
}));

if (tagsToDelete.length > 0) {
SFPLogger.log(COLOR_KEY_MESSAGE('Removing the following Git tag(s):'));
for (let tag of tagsToDelete) {
SFPLogger.log(COLOR_KEY_MESSAGE(tag));
}
await this.git.deleteTags(tagsToDelete);
}
}

//Deletes Git tags that are older than a specified number of days.
private async deleteGitTagsOlderThan( tags: {
name: string;
version: string;
type: string;
tag: string;
commitId: string;
}[], daysToKeep: number
, limit?: number) {

const tagsToDelete: string[] = [];

await Promise.all(tags.map(async (tag) => {
const gitTags = new GitTags(this.git, tag.name);
const tags = await gitTags.filteredOldTags(daysToKeep, limit);
tagsToDelete.push(...tags);
}));

if (tagsToDelete.length > 0) {
SFPLogger.log(COLOR_KEY_MESSAGE('Removing the following Git tag(s):'));
for (let tag of tagsToDelete) {
SFPLogger.log(COLOR_KEY_MESSAGE(tag));
}
await this.git.deleteTags(tagsToDelete);
}

}


private isPackageVersionIdReleased(packageVersionList: any, packageVersionId: string): boolean {
let packageVersion = packageVersionList.find((pkg) => {
return pkg.SubscriberPackageVersionId === packageVersionId;
Expand Down

0 comments on commit aae62d6

Please sign in to comment.