From 4950e68a9d549d1bff422fd1d08586e30c2c8e89 Mon Sep 17 00:00:00 2001 From: Javier Carrillo Date: Fri, 9 Aug 2024 16:37:54 -0400 Subject: [PATCH 01/19] feat: (MSP-11) Initiate git-terminator scripts --- .gitignore | 1 + .tool-versions | 1 + README.md | 6 +++ bun.lockb | Bin 0 -> 7047 bytes command.js | 43 +++++++++++++++++++ package.json | 14 ++++++ src/config/github.js | 26 +++++++++++ src/utils/delete_tags.js | 90 +++++++++++++++++++++++++++++++++++++++ 8 files changed, 181 insertions(+) create mode 100644 .tool-versions create mode 100755 bun.lockb create mode 100644 command.js create mode 100644 package.json create mode 100644 src/config/github.js create mode 100644 src/utils/delete_tags.js diff --git a/.gitignore b/.gitignore index c6bba59..a5a548a 100644 --- a/.gitignore +++ b/.gitignore @@ -121,6 +121,7 @@ dist # Stores VSCode versions used for testing VSCode extensions .vscode-test +.vscode # yarn v2 .yarn/cache diff --git a/.tool-versions b/.tool-versions new file mode 100644 index 0000000..199cf09 --- /dev/null +++ b/.tool-versions @@ -0,0 +1 @@ +bun 1.1.21 diff --git a/README.md b/README.md index d55ac02..8cc68f3 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,8 @@ # git-tag-terminator Delete Git Tags from the CLI + +Example: + +``` +GITHUB_TOKEN= bun command.js -t time_in_days -o org -r repo -n min_tags +``` diff --git a/bun.lockb b/bun.lockb new file mode 100755 index 0000000000000000000000000000000000000000..3447ccfc610aa57458d351ae0852f928ba894b86 GIT binary patch literal 7047 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', + 'Time until a tag is considered stale in days', + 365 + ) + .requiredOption( + '-o, --organization ', + 'GitHub Organization' + ) + .option( + '-r, --repository ', + 'Minimum number of Tags to preserve', + '' + ) + .option( + '-n, --minimumTags ', + 'Minimum number of Tags to preserve', + 10 + ) + .option('--dry', 'Dry run command', false) + // if option repo array empty run all + .action((options) => { + const daysUntilStale = options.time.trim(); + const org = options.organization.trim(); + const repo = options.repository.trim(); + const minTags = options.minimumTags.trim(); + + terminator(daysUntilStale, org, repo, minTags); + }); + +command.parse(); + +// getTags("time"); diff --git a/package.json b/package.json new file mode 100644 index 0000000..7866462 --- /dev/null +++ b/package.json @@ -0,0 +1,14 @@ +{ + "name": "terminator", + "version": "0.1.0", + "devDependencies": { + "@types/bun": "latest", + "commander": "^12.1.0" + }, + "description": "CLI to terminate stale Git tags", + "private": true, + "type": "module", + "dependencies": { + "@octokit/core": "^6.1.2" + } +} diff --git a/src/config/github.js b/src/config/github.js new file mode 100644 index 0000000..27d28c9 --- /dev/null +++ b/src/config/github.js @@ -0,0 +1,26 @@ +import { Octokit } from "@octokit/core"; + +class GitHubAuth { + constructor(token) { + this.token = token + } + auth() { + // return new Octokit({ auth: process.env.GITHUB_TOKEN }); + // console.log(this.token); + return new Octokit({ auth: this.token }); + } +} + +export class Repository { + constructor(org, repo) { + this.org = org, + this.repo = repo + } +} + +export const githubConfig = new GitHubAuth( + // process.env.GITHUB_TOKEN || '', + // Pass org as a CLI flag?? + process.env.GITHUB_TOKEN , +); + diff --git a/src/utils/delete_tags.js b/src/utils/delete_tags.js new file mode 100644 index 0000000..3e2b197 --- /dev/null +++ b/src/utils/delete_tags.js @@ -0,0 +1,90 @@ +// import { Octokit } from "octokit"; +import { githubConfig, Repository } from "../config/github"; + +export const terminator = async (daysUntilStale, org, repo, minTags) => { + try { + const octokit = githubConfig.auth(); + const gitRepo = new Repository(org, repo); + + const tags = await getTags(octokit, gitRepo); + const tagsSortedByDate = await sortTags(octokit, tags, gitRepo); + await deleteTags(octokit, tagsSortedByDate, daysUntilStale, gitRepo, minTags); + } + catch (error) { + console.error('Eploto:', error); + process.exit(1); + } +} + +// This func could be added as methods of my githubConfig class +// Need test +const getTags = async (octokit, gitRepo) => { + try { + const tags = await octokit.request('GET /repos/{owner}/{repo}/tags', { + owner: gitRepo.org, + repo: gitRepo.repo, + headers: { + 'X-GitHub-Api-Version': '2022-11-28' + } + }); + return tags; + } + catch (error) { + console.error('Could not list tags from repo: %s', error); + process.exit(1); + } +} + +// Need test +const sortTags = async (octokit, tags, gitRepo) => { + try { + let commitTags = [] + for (const tag of tags.data) { + const commit = await octokit.request('GET /repos/{owner}/{repo}/commits/{ref}', { + owner: gitRepo.org, + repo: gitRepo.repo, + ref: tag.commit.sha, + headers: { + 'X-GitHub-Api-Version': '2022-11-28' + } + }) + commitTags.push({tag: tag.name, date: commit.data.commit.committer.date}); + } + return commitTags.sort((a, b) => new Date(b.date) - new Date(a.date)); + } + catch (error) { + console.error('Could not sort tags from repo: %s', error); + process.exit(1); + } +} + +const deleteTags = async (octokit, tagsDate, daysUntilStale, gitRepo, minTags) => { + try { + tagsDate.splice(0, minTags) + tagsDate.forEach(async (tag) => { + var tagDaysSinceCreated = (new Date() - new Date(tag.date))/86400000; + if (tagDaysSinceCreated > daysUntilStale) { + // These console logs are for Testing + console.log(tag) + console.log("Stale\n\n") + // await octokit.request('DELETE /repos/{owner}/{repo}/git/refs/{ref}', { + // owner: gitRepo.name, + // repo: gitRepo.repo, + // ref: 'tags/'+tag.name, + // headers: { + // 'X-GitHub-Api-Version': '2022-11-28' + // } + // }); + // console.log("%s Tag deleted!", tag.name) + // } + } else { + console.log(tag) + } + }); + } + catch(error) { + console.error('Could not delete tags from repo: %s', error); + process.exit(1); + } + +} From 128a31710263cd2afef69a5596502559ab9e4117 Mon Sep 17 00:00:00 2001 From: Javier Carrillo Date: Fri, 9 Aug 2024 16:43:36 -0400 Subject: [PATCH 02/19] chore: (MSP-11) Remove unused comment --- command.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/command.js b/command.js index f92211d..f7d217f 100644 --- a/command.js +++ b/command.js @@ -39,5 +39,3 @@ command }); command.parse(); - -// getTags("time"); From 2fa15ad6014b78e9b0bef49e54b6615cd4720b86 Mon Sep 17 00:00:00 2001 From: Javier Carrillo Date: Fri, 9 Aug 2024 16:44:22 -0400 Subject: [PATCH 03/19] chore: (MSP-11) Remove unused comments --- src/config/github.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/config/github.js b/src/config/github.js index 27d28c9..577fad6 100644 --- a/src/config/github.js +++ b/src/config/github.js @@ -6,7 +6,6 @@ class GitHubAuth { } auth() { // return new Octokit({ auth: process.env.GITHUB_TOKEN }); - // console.log(this.token); return new Octokit({ auth: this.token }); } } @@ -19,8 +18,6 @@ export class Repository { } export const githubConfig = new GitHubAuth( - // process.env.GITHUB_TOKEN || '', - // Pass org as a CLI flag?? process.env.GITHUB_TOKEN , ); From 9b74a8772be9f9cb57a4f6f422f1e674fb152ce3 Mon Sep 17 00:00:00 2001 From: Javier Carrillo Date: Mon, 26 Aug 2024 14:37:41 -0400 Subject: [PATCH 04/19] feat: (MSP-11) Add TS to project --- .gitignore | 61 ++++++++++++++--- README.md | 3 +- bun.lockb | Bin 7047 -> 7493 bytes command.js => command.ts | 10 ++- package.json | 11 +++- src/config/{github.js => github.ts} | 12 ++-- src/utils/{delete_tags.js => delete_tags.ts} | 66 ++++++++++++------- tsconfig.json | 27 ++++++++ 8 files changed, 149 insertions(+), 41 deletions(-) rename command.js => command.ts (86%) rename src/config/{github.js => github.ts} (63%) rename src/utils/{delete_tags.js => delete_tags.ts} (50%) create mode 100644 tsconfig.json diff --git a/.gitignore b/.gitignore index a5a548a..6aefea0 100644 --- a/.gitignore +++ b/.gitignore @@ -1,78 +1,105 @@ +# Based on https://raw.githubusercontent.com/github/gitignore/main/Node.gitignore + # Logs + logs -*.log -npm-debug.log* +_.log +npm-debug.log_ yarn-debug.log* yarn-error.log* lerna-debug.log* .pnpm-debug.log* +# Caches + +.cache + # Diagnostic reports (https://nodejs.org/api/report.html) -report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json + +report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json # Runtime data + pids -*.pid -*.seed +_.pid +_.seed *.pid.lock # Directory for instrumented libs generated by jscoverage/JSCover + lib-cov # Coverage directory used by tools like istanbul + coverage *.lcov # nyc test coverage + .nyc_output # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) + .grunt # Bower dependency directory (https://bower.io/) + bower_components # node-waf configuration + .lock-wscript # Compiled binary addons (https://nodejs.org/api/addons.html) + build/Release # Dependency directories + node_modules/ jspm_packages/ # Snowpack dependency directory (https://snowpack.dev/) + web_modules/ # TypeScript cache + *.tsbuildinfo # Optional npm cache directory + .npm # Optional eslint cache + .eslintcache # Optional stylelint cache + .stylelintcache # Microbundle cache + .rpt2_cache/ .rts2_cache_cjs/ .rts2_cache_es/ .rts2_cache_umd/ # Optional REPL history + .node_repl_history # Output of 'npm pack' + *.tgz # Yarn Integrity file + .yarn-integrity # dotenv environment variable files + .env .env.development.local .env.test.local @@ -80,52 +107,70 @@ web_modules/ .env.local # parcel-bundler cache (https://parceljs.org/) -.cache + .parcel-cache # Next.js build output + .next out # Nuxt.js build / generate output + .nuxt dist # Gatsby files -.cache/ + # Comment in the public line in if your project uses Gatsby and not Next.js + # https://nextjs.org/blog/next-9-1#public-directory-support + # public # vuepress build output + .vuepress/dist # vuepress v2.x temp and cache directory + .temp -.cache # Docusaurus cache and generated files + .docusaurus # Serverless directories + .serverless/ # FuseBox cache + .fusebox/ # DynamoDB Local files + .dynamodb/ # TernJS port file + .tern-port # Stores VSCode versions used for testing VSCode extensions + .vscode-test .vscode # yarn v2 + .yarn/cache .yarn/unplugged .yarn/build-state.yml .yarn/install-state.gz .pnp.* + +# IntelliJ based IDEs +.idea + +# Finder (MacOS) folder config +.DS_Store diff --git a/README.md b/README.md index 8cc68f3..e75d786 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,9 @@ # git-tag-terminator + Delete Git Tags from the CLI Example: -``` +```bash GITHUB_TOKEN= bun command.js -t time_in_days -o org -r repo -n min_tags ``` diff --git a/bun.lockb b/bun.lockb index 3447ccfc610aa57458d351ae0852f928ba894b86..17911124d3e0b60526b75267b2eb2f21cdce327d 100755 GIT binary patch delta 1646 zcmcIkeN0#m&l+?VjAKcFowvj(ub6Zw*HwQPe%# z*S8g_y@t<)P`e&J*8sW!wSZHAEZ`_$FyI76C=75AY>E!RP(UZ+<#qY&-GCbK#{;SW z>8$~Pf6BaefgGX0$G~wIK7s(Z08%2&h!P+FPWknz{>1Af6t^n};@XpwUbpNZ-S}y2 zA}(ykON3+0sys-i5ZE%Zfyu;&NFQUyZsLM9fp9W27Dzd)mr0+@tn!1a&A?TXySFWUDerXcHa91nZLTkEYrG?zUhX3qPEW}5Rw3=O`a@Svam-+2y$600Mk^sJ zfV5JQ$OkTbx_9W%`_ZFi#i74GAnr5Y=bRc!EPHrk%I;Y^;y67sb2H@Rx;MDze)(ac z=WhC?x9i69FaAD%v{bF}EbiGgZg&m^2I5lbY+8Luf&+_HOTClqwU(YLreIcf)IT+#+t+|6)nq%H6Ak+-54}RUG>=&yL#rY0vAjZj4CFQ&84FD! z{{3qKX))-7qR$|gz8R1+G$0nUBuBj~VBY8K4I=Db!gMeC<%>d7lf~9-vAr-C zv%h3#(I0DIme67OT9$DN?+IQhqx}yu6h&rrF|l5w)+(e3)wL;t#rBf5zFKIo2`!D5 zrW%{IQE;y4Tr!+RZg5XAX&EFcVlK#gr}rK*79P1_m90zmI#P5ye4}MgqWPDXv9q-q8pJp?h@uF{z{)Mhb1%&*Jvq~;3f6ZUm%C`C47Y0 zx1tjdGN;fZ(8>Ae7`(*Q2|2uv20+EN4?1~Y!dtwN4}IgIn^zJP%v*wzkx8@xRD;jb zkGcZXVNk;O18Ae!Fh%1n^JpntWU<67bTi}_eY6==T!*34s6ZDrG@(0T9EXfmMrkp! z=q6pykjYpy!J66Y5xgp~BC{BFWJZgT`QvLx{n(2#Swv=p*c4ST;s3daUK+a*jTFUs z3{3;A!db;Xt~yfo@7p9-yGlBze^)A{pG?Ez`W>SWLLE;`=5MQhxE>fhl-IvM*PPTo z6)w$p6d%j@V)jp0wHphhWFdJ05x>UwWC)%=*Y39-crD)QtG+$^YCQk+!8KCB`T9Md z@YyR4Pfpv6ZKd13J0|`*pzfaUCqJeYPPE>FEz^VH2MwmDS87*B%!wu%u_d3Nk@#c_ zFI>dau>NJC~_WSwSR*~nUm)WMux zu-W#dFrlj&?9gX((IoiCCaSTSc$(y`vD&w7iKjc|d`XtvBnwZo>ErJPQV*>BM&Q_o z5vABXwe@^FGMW1@oufMoBsU%*v58ALSl8WNl39Wlk7j9xF}p}FK^d-H(48vM`!I~_ z7#y`b40!Y&yhAZ+a>fRDXw_)8#eaMN!^jvPGyE68Ze*8a$72Dty_QHz5e@Fa;IT*_7?a&)!+7DM`I4B4T>vC%WDi+|{UHevnOo(;?7W&70n%G$sh+*MSo!J68D5UL2~ ig(~-crPfr0YWGG$Y0r4N7RsH)oUFh_=VPcdxBd&6w;IU+ diff --git a/command.js b/command.ts similarity index 86% rename from command.js rename to command.ts index f7d217f..612f359 100644 --- a/command.js +++ b/command.ts @@ -1,3 +1,5 @@ +#!/usr/bin/env bun + import { Command } from 'commander'; import { terminator } from './src/utils/delete_tags'; import { description, version, name } from './package.json'; @@ -11,12 +13,13 @@ command .requiredOption( '-t, --time