Skip to content

Commit 75876bd

Browse files
committed
feat($core): init
1 parent 8017ec5 commit 75876bd

File tree

10 files changed

+285
-7
lines changed

10 files changed

+285
-7
lines changed

README.md

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,71 @@ Please consider starring the project to show your ❤️ and support.
1010
[![License](https://badgen.net/npm/license/git-delete-tag)](./LICENSE)
1111
[![donate](https://badgen.net/badge/support%20me/donate/f2a)](https://donate.evila.me)
1212

13+
## Features
14+
15+
- Support delete matched tags. e.g.`v1*`
16+
17+
<p align="center">
18+
<img src="https://unpkg.com/@evillt/media@latest/projects/git-delete-tag/main.svg">
19+
</p>
20+
21+
## Prerequisites
22+
23+
- git
24+
- node.js
25+
26+
## Usage
27+
28+
One-off usage via `npx`:
29+
30+
```sh
31+
$ npx git-delete-tag [...tags]
32+
33+
# Example
34+
$ npx git-delete-tag dev test-*
35+
```
36+
37+
Using it globally:
38+
39+
```sh
40+
$ npm i -g git-delete-tag
41+
42+
# Or using yarn
43+
$ yarn global add git-delete-tag
44+
45+
$ git-dt [...tags]
46+
$ git-delete-tag [...tags]
47+
48+
# Or using git external commands
49+
$ git dt [...tags]
50+
$ git delete-tag [...tags]
51+
```
52+
53+
## CLI
54+
55+
`git-delete-tag [...tags] [options]`
56+
57+
### `tags`
58+
59+
Delete tags
60+
61+
### `options`
62+
63+
#### `-r, --remotes`
64+
65+
Delete remotes tags
66+
67+
#### `--scope <scope>`
68+
69+
- Default: `origin`
70+
- When: `-r, --remotes`
71+
72+
Branches scope name
73+
74+
## Relates
75+
76+
- [git-delete-branch](https://github.com/evillt/git-delete-branch)
77+
1378
## Contributing
1479

1580
1. Fork it!

bin/cli.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
#!/usr/bin/env node
2+
3+
const GitDeleteTag = require('..')
4+
5+
const app = new GitDeleteTag()
6+
7+
app.run()

circle.yml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,9 @@ jobs:
1818
key: dependency-cache-{{ checksum "yarn.lock" }}
1919
paths:
2020
- ./node_modules
21+
- run:
22+
name: test
23+
command: yarn test
24+
- run:
25+
name: release
26+
command: npx semantic-release

index.js

Lines changed: 0 additions & 1 deletion
This file was deleted.

lib/index.js

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
const path = require('path')
2+
const fs = require('fs')
3+
const cac = require('cac')
4+
const spawn = require('cross-spawn')
5+
const ora = require('ora')
6+
const matcher = require('multimatch')
7+
const kleur = require('kleur')
8+
const logger = require('../utils/logger')
9+
const parseArgs = require('../utils/parseArgs')
10+
11+
module.exports = class Core {
12+
constructor() {
13+
this.cwd = process.cwd()
14+
this.rawArgs = process.argv
15+
this.args = parseArgs(this.rawArgs)
16+
this.isRemotes = this.args.has('r') || this.args.has('remotes')
17+
18+
this.isGitProject()
19+
20+
this.initCli()
21+
}
22+
23+
initCli() {
24+
const cli = (this.cli = cac())
25+
this.command = cli
26+
.command('[...tags]')
27+
.usage('[...tags] [options]')
28+
.option('-r, --remotes', 'Delete remotes tags')
29+
.action((tags, options) => {
30+
if (tags.length === 0) cli.outputHelp()
31+
32+
this.deleteTag(tags, options)
33+
})
34+
35+
if (this.isRemotes) {
36+
cli.option('--scope <scope>', 'Remote tag scope', {
37+
default: 'origin'
38+
})
39+
}
40+
41+
cli.version(require('../package.json').version).help()
42+
43+
this.cli.parse(this.rawArgs, { run: false })
44+
}
45+
46+
isGitProject() {
47+
if (!fs.existsSync(path.join(this.cwd, '.git'))) {
48+
throw new Error(
49+
logger.error('Current working directory is not a git project!')
50+
)
51+
}
52+
return true
53+
}
54+
55+
getTag(options) {
56+
const { stdout } = spawn.sync(
57+
'git',
58+
this.isRemotes ? ['ls-remote', '--tags'] : ['tag']
59+
)
60+
61+
let tags = []
62+
63+
tags = stdout
64+
.toString()
65+
.trimRight()
66+
.split('\n')
67+
68+
if (this.isRemotes && options.scope) {
69+
tags = tags
70+
.map(tag => tag.match(/refs\/tags\/([\S]*)/)[1])
71+
.filter(tag => !tag.includes('^{}'))
72+
}
73+
74+
return tags
75+
}
76+
77+
deleteTag(tags, options) {
78+
const matched = matcher(this.getTag(options), tags)
79+
80+
matched.forEach(tag => {
81+
const spinner = ora(`Deleting${this.text(tag)}`)
82+
spinner.start()
83+
const args = this.isRemotes
84+
? ['push', options.scope, `:refs/tags/${tag}`]
85+
: ['tag', tag, '-d']
86+
const ps = spawn.sync('git', args)
87+
if (ps.status === 0) {
88+
spinner.succeed(`Deleted${this.text(tag)}`)
89+
}
90+
})
91+
}
92+
93+
text(tag) {
94+
return `${this.isRemotes ? ' remotes' : ''} tag ` + kleur.magenta(tag)
95+
}
96+
97+
run() {
98+
this.cli.runMatchedCommand()
99+
}
100+
}

package.json

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,29 @@
77
"type": "git",
88
"url": "evillt/git-delete-tag"
99
},
10+
"bin": {
11+
"git-dt": "bin/cli.js",
12+
"git-delete-tag": "bin/cli.js"
13+
},
1014
"author": "evillt <[email protected]> (https://evila.me)",
11-
"main": "index.js",
15+
"main": "lib/index.js",
16+
"files": [
17+
"bin",
18+
"lib",
19+
"utils"
20+
],
1221
"scripts": {
1322
"lint": "xo",
1423
"test": "npm run lint && ava --verbose"
1524
},
16-
"dependencies": {},
25+
"dependencies": {
26+
"cac": "^6.5.2",
27+
"cross-spawn": "^6.0.5",
28+
"kleur": "^3.0.3",
29+
"mri": "^1.1.4",
30+
"multimatch": "^4.0.0",
31+
"ora": "^3.4.0"
32+
},
1733
"devDependencies": {
1834
"ava": "^2.1.0",
1935
"eslint-config-prettier": "^3.3.0",
@@ -28,7 +44,11 @@
2844
"extends": [
2945
"rem",
3046
"plugin:prettier/recommended"
31-
]
47+
],
48+
"rules": {
49+
"unicorn/filename-case": false,
50+
"no-multi-assign": 0
51+
}
3252
},
3353
"husky": {
3454
"hooks": {

test.js

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,14 @@
11
import test from 'ava'
2+
import spawn from 'cross-spawn'
23

3-
test('main', t => {
4-
t.pass()
4+
test('delete tag', t => {
5+
const ps = spawn.sync('./bin/cli.js', ['test'])
6+
const stdout = ps.stdout.toString()
7+
t.is(stdout, '')
8+
})
9+
10+
test('delete remotes tag', t => {
11+
const ps = spawn.sync('./bin/cli.js', ['test', '-r'])
12+
const stdout = ps.stdout.toString()
13+
t.is(stdout, '')
514
})

utils/logger.js

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
const kleur = require('kleur')
2+
3+
class Logger {
4+
log(...args) {
5+
console.log(...args)
6+
}
7+
8+
success(...args) {
9+
this.log(kleur.green('success'), ...args)
10+
}
11+
12+
error(...args) {
13+
this.log(kleur.red('error'), ...args)
14+
}
15+
16+
done(...args) {
17+
this.log(kleur.green(process.platform === 'win32' ? '√' : '✔'), ...args)
18+
}
19+
}
20+
21+
module.exports = new Logger()

utils/parseArgs.js

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
const cac = require('cac')
2+
3+
module.exports = _args => {
4+
const cli = cac()
5+
const { args, options } = cli.parse(_args)
6+
7+
return {
8+
get(name) {
9+
return options[name]
10+
},
11+
12+
has(name) {
13+
return this.get(name) !== undefined
14+
},
15+
16+
options,
17+
18+
args
19+
}
20+
}

yarn.lock

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -318,7 +318,7 @@
318318
"@types/minimatch" "*"
319319
"@types/node" "*"
320320

321-
"@types/minimatch@*":
321+
"@types/minimatch@*", "@types/minimatch@^3.0.3":
322322
version "3.0.3"
323323
resolved "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz#3dca0e3f33b200fc7d1139c0cd96c1268cadfd9d"
324324
integrity sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==
@@ -453,6 +453,11 @@ array-differ@^1.0.0:
453453
resolved "https://registry.npmjs.org/array-differ/-/array-differ-1.0.0.tgz#eff52e3758249d33be402b8bb8e564bb2b5d4031"
454454
integrity sha1-7/UuN1gknTO+QCuLuOVkuytdQDE=
455455

456+
array-differ@^3.0.0:
457+
version "3.0.0"
458+
resolved "https://registry.npmjs.org/array-differ/-/array-differ-3.0.0.tgz#3cbb3d0f316810eafcc47624734237d6aee4ae6b"
459+
integrity sha512-THtfYS6KtME/yIAhKjZ2ul7XI96lQGHRputJQHO80LAWQnuGP4iCIN8vdMRboGbIEYBwU33q8Tch1os2+X0kMg==
460+
456461
array-find-index@^1.0.1:
457462
version "1.0.2"
458463
resolved "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz#df010aa1287e164bbda6f9723b0a96a1ec4187a1"
@@ -719,6 +724,11 @@ buffer-from@^1.0.0:
719724
resolved "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef"
720725
integrity sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==
721726

727+
cac@^6.5.2:
728+
version "6.5.2"
729+
resolved "https://registry.npmjs.org/cac/-/cac-6.5.2.tgz#92ef1490b9ffde5f0be7eeadec5ea926f0e78ef6"
730+
integrity sha512-8JdiD9/ZLsG418j/chyZQ3VWuhFELSGlH4EUxzNKgIH8wK8dO0j5Pqu6Pk7B/RP3kX9aasyQhPrrUjYO5e0w7w==
731+
722732
cache-base@^1.0.1:
723733
version "1.0.1"
724734
resolved "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz#0a7f46416831c8b662ee36fe4e7c59d76f666ab2"
@@ -2883,6 +2893,11 @@ kind-of@^6.0.0, kind-of@^6.0.2:
28832893
resolved "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz#01146b36a6218e64e58f3a8d66de5d7fc6f6d051"
28842894
integrity sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==
28852895

2896+
kleur@^3.0.3:
2897+
version "3.0.3"
2898+
resolved "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz#a79c9ecc86ee1ce3fa6206d1216c501f147fc07e"
2899+
integrity sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==
2900+
28862901
latest-version@^3.0.0:
28872902
version "3.1.0"
28882903
resolved "https://registry.npmjs.org/latest-version/-/latest-version-3.1.0.tgz#a205383fea322b33b5ae3b18abee0dc2f356ee15"
@@ -3332,6 +3347,11 @@ mkdirp@^0.5.1:
33323347
dependencies:
33333348
minimist "0.0.8"
33343349

3350+
mri@^1.1.4:
3351+
version "1.1.4"
3352+
resolved "https://registry.npmjs.org/mri/-/mri-1.1.4.tgz#7cb1dd1b9b40905f1fac053abe25b6720f44744a"
3353+
integrity sha512-6y7IjGPm8AzlvoUrwAaw1tLnUBudaS3752vcd8JtrpGGQn+rXIe63LFVHm/YMwtqAuh+LJPCFdlLYPWM1nYn6w==
3354+
33353355
33363356
version "2.0.0"
33373357
resolved "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
@@ -3352,6 +3372,17 @@ multimatch@^2.1.0:
33523372
arrify "^1.0.0"
33533373
minimatch "^3.0.0"
33543374

3375+
multimatch@^4.0.0:
3376+
version "4.0.0"
3377+
resolved "https://registry.npmjs.org/multimatch/-/multimatch-4.0.0.tgz#8c3c0f6e3e8449ada0af3dd29efb491a375191b3"
3378+
integrity sha512-lDmx79y1z6i7RNx0ZGCPq1bzJ6ZoDDKbvh7jxr9SJcWLkShMzXrHbYVpTdnhNM5MXpDUxCQ4DgqVttVXlBgiBQ==
3379+
dependencies:
3380+
"@types/minimatch" "^3.0.3"
3381+
array-differ "^3.0.0"
3382+
array-union "^2.1.0"
3383+
arrify "^2.0.1"
3384+
minimatch "^3.0.4"
3385+
33553386
33563387
version "0.0.7"
33573388
resolved "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz#3075ce93bc21b8fab43e1bc4da7e8115ed1e7bab"

0 commit comments

Comments
 (0)