mj 0.9.2 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile.lock +1 -1
- data/README.md +6 -0
- data/lib/mj/git/branches.rb +5 -0
- data/lib/mj/git/commands/delete_stale_branches_command.rb +38 -0
- data/lib/mj/git/commands/delete_stale_branches_command_handler.rb +79 -0
- data/lib/mj/git/pull_request.rb +23 -0
- data/lib/mj/git/remote_branch.rb +45 -1
- data/lib/mj/git/thor_command.rb +25 -0
- data/lib/mj/version.rb +1 -1
- metadata +9 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3ae71fd8808a2f04a8cfb7838d347f529a5df0aa9b5a3d6eb3618b089c9724c3
|
4
|
+
data.tar.gz: e8f7c0778fc83b5fe2e5206b14a84ba297f85c5337d3248d48ff36e5099bfa7b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 33aafd4dc0b0bc9910442c625b04da211b71fb86d82d2f2b13282fb3a3ded0a081ea3877d98eac8fc5c6b18a0532d90f6d59926c108b5c0b753a672d35d4ffe2
|
7
|
+
data.tar.gz: d9dfd28ccbdc9aa8e615d2fa1ef81d57ccc33707ea8c519fe0cfce55e2fc17b8fc1345d43da241e929da05a70c70fa11bf89376fd1e14beae6d4f895569ca44a
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -33,6 +33,12 @@ mj help
|
|
33
33
|
```
|
34
34
|
bundle exec mj git checkout partial-branch-name # it will create a local branch if that is remote only
|
35
35
|
bundle exec mj git checkout partial-branch-name --dry-run # if you want to see the command before executing
|
36
|
+
|
37
|
+
bundle exec mj git delete_stale_branches \
|
38
|
+
[--dry-run] \
|
39
|
+
[--only-with-prs] \
|
40
|
+
[--only-with-closed-prs] \
|
41
|
+
[--before-date=2021-01-01]
|
36
42
|
```
|
37
43
|
|
38
44
|
```
|
data/lib/mj/git/branches.rb
CHANGED
@@ -2,6 +2,7 @@
|
|
2
2
|
|
3
3
|
require_relative "local_branch"
|
4
4
|
require_relative "remote_branch"
|
5
|
+
require_relative "pull_request"
|
5
6
|
|
6
7
|
module Mj
|
7
8
|
module Git
|
@@ -43,6 +44,10 @@ module Mj
|
|
43
44
|
@branches.each(&block)
|
44
45
|
end
|
45
46
|
|
47
|
+
def sort_by(&block)
|
48
|
+
self.class.new(@branches.sort_by(&block))
|
49
|
+
end
|
50
|
+
|
46
51
|
def length
|
47
52
|
@branches.length
|
48
53
|
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Mj
|
4
|
+
module Git
|
5
|
+
module Commands
|
6
|
+
class DeleteStaleBranchesCommand
|
7
|
+
def initialize(options: {})
|
8
|
+
@options = options
|
9
|
+
end
|
10
|
+
|
11
|
+
def dry_run?
|
12
|
+
@options[:dry_run]
|
13
|
+
end
|
14
|
+
|
15
|
+
def before_date
|
16
|
+
if @before_date
|
17
|
+
return @before_date
|
18
|
+
end
|
19
|
+
|
20
|
+
if @options[:before_date]
|
21
|
+
@before_date ||= DateTime.parse(@options[:before_date])
|
22
|
+
end
|
23
|
+
|
24
|
+
# Default to now, because all things happened before now.
|
25
|
+
@before_date ||= DateTime.now
|
26
|
+
end
|
27
|
+
|
28
|
+
def only_with_prs
|
29
|
+
@options[:only_with_prs]
|
30
|
+
end
|
31
|
+
|
32
|
+
def only_with_closed_prs
|
33
|
+
@options[:only_with_closed_prs]
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Mj
|
4
|
+
module Git
|
5
|
+
module Commands
|
6
|
+
class DeleteStaleBranchesCommandHandler
|
7
|
+
def initialize(stdout:, command_executer: CommandExecuter.new)
|
8
|
+
@stdout = stdout
|
9
|
+
@command_executer = command_executer
|
10
|
+
end
|
11
|
+
|
12
|
+
def handle(command)
|
13
|
+
puts("Deleting stale branches", color: :blue)
|
14
|
+
|
15
|
+
list_command = "git branch -a"
|
16
|
+
list_command += " | grep remotes/ | grep -v '/HEAD'"
|
17
|
+
|
18
|
+
branches = Git::Branches
|
19
|
+
.from_branch_names(@command_executer.execute(list_command))
|
20
|
+
.sort_by(&:last_commit_date)
|
21
|
+
|
22
|
+
branches.each do |branch|
|
23
|
+
delete_branch(branch, command: command)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def delete_branch(branch, command:)
|
30
|
+
if delete?(branch, command: command)
|
31
|
+
puts("Deleting branch #{branch.name}", color: :green)
|
32
|
+
|
33
|
+
unless command.dry_run?
|
34
|
+
delete(branch)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def delete?(branch, command:) # rubocop:disable Metrics/AbcSize,Metrics/MethodLength
|
40
|
+
if %w[master main].include?(branch.to_local.name)
|
41
|
+
puts("Skipping #{branch.name}. No, no, no, no.", color: :red)
|
42
|
+
return false
|
43
|
+
end
|
44
|
+
|
45
|
+
if branch.last_commit_date >= command.before_date
|
46
|
+
puts("Skipping #{branch.name}. Not before #{command.before_date}", color: :yellow)
|
47
|
+
return false
|
48
|
+
end
|
49
|
+
|
50
|
+
if (command.only_with_prs || command.only_with_closed_prs) && branch.pr.nil?
|
51
|
+
puts("Skipping #{branch.name}. Does not have PR.", color: :yellow)
|
52
|
+
return false
|
53
|
+
end
|
54
|
+
|
55
|
+
if command.only_with_closed_prs && !branch.pr.closed?
|
56
|
+
puts("Skipping #{branch.name}. PR not closed - state: #{branch.pr.state}.", color: :yellow)
|
57
|
+
return false
|
58
|
+
end
|
59
|
+
|
60
|
+
true
|
61
|
+
end
|
62
|
+
|
63
|
+
def delete(branch)
|
64
|
+
branch.delete
|
65
|
+
rescue StandardError => exception
|
66
|
+
log("Could not delete branch #{branch.name}: #{exception.message}", color: :red)
|
67
|
+
end
|
68
|
+
|
69
|
+
def puts(string, color: nil)
|
70
|
+
if color
|
71
|
+
string = string.colorize(color)
|
72
|
+
end
|
73
|
+
|
74
|
+
@stdout.puts(string)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Mj
|
4
|
+
module Git
|
5
|
+
class PullRequest
|
6
|
+
attr_reader :number
|
7
|
+
attr_reader :title
|
8
|
+
attr_reader :state
|
9
|
+
attr_reader :updated_at
|
10
|
+
|
11
|
+
def initialize(number:, title:, state:, updated_at:)
|
12
|
+
@number = number
|
13
|
+
@title = title
|
14
|
+
@state = state
|
15
|
+
@updated_at = updated_at
|
16
|
+
end
|
17
|
+
|
18
|
+
def closed?
|
19
|
+
state == "MERGED" || state == "CLOSED"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
data/lib/mj/git/remote_branch.rb
CHANGED
@@ -5,14 +5,19 @@ module Mj
|
|
5
5
|
class RemoteBranch
|
6
6
|
attr_reader :name
|
7
7
|
|
8
|
-
def initialize(name)
|
8
|
+
def initialize(name, command_executer: CommandExecuter.new)
|
9
9
|
@name = name
|
10
|
+
@command_executer = command_executer
|
10
11
|
end
|
11
12
|
|
12
13
|
def checkout_command
|
13
14
|
"git checkout -b #{local_branch_name} #{name}"
|
14
15
|
end
|
15
16
|
|
17
|
+
def last_commit_date
|
18
|
+
@last_commit_date ||= DateTime.parse(@command_executer.execute("git log -1 --format=%cd #{name}").first)
|
19
|
+
end
|
20
|
+
|
16
21
|
def length
|
17
22
|
@name.length
|
18
23
|
end
|
@@ -21,12 +26,51 @@ module Mj
|
|
21
26
|
LocalBranch.new(local_branch_name)
|
22
27
|
end
|
23
28
|
|
29
|
+
def has_pr?
|
30
|
+
!pr.nil?
|
31
|
+
end
|
32
|
+
|
33
|
+
# @return [Git::PullRequest]
|
34
|
+
def pr
|
35
|
+
if defined?(@pr)
|
36
|
+
return @pr
|
37
|
+
end
|
38
|
+
|
39
|
+
@pr ||= fetch_pr
|
40
|
+
end
|
41
|
+
|
42
|
+
def delete
|
43
|
+
@command_executer.execute("git push origin :#{local_branch_name}")
|
44
|
+
end
|
45
|
+
|
24
46
|
private
|
25
47
|
|
26
48
|
def local_branch_name
|
27
49
|
pattern = %r{^remotes/\w+/}
|
28
50
|
name.sub(pattern, "")
|
29
51
|
end
|
52
|
+
|
53
|
+
def fetch_pr # rubocop:disable Metrics/MethodLength
|
54
|
+
data = @command_executer.execute(
|
55
|
+
"gh pr list --head #{local_branch_name} --state=all --json=number,state,title,updatedAt"
|
56
|
+
)
|
57
|
+
|
58
|
+
data = JSON.parse(data.join("")).first
|
59
|
+
|
60
|
+
if data.nil?
|
61
|
+
return
|
62
|
+
end
|
63
|
+
|
64
|
+
# I.E. ["14", "WIP on packer", "handle-packer-files", "DRAFT", "2022-03-14T20:14:17Z"]
|
65
|
+
Git::PullRequest.new(
|
66
|
+
number: data['number'],
|
67
|
+
title: data['title'],
|
68
|
+
state: data['state'],
|
69
|
+
updated_at: DateTime.parse(data['updatedAt'])
|
70
|
+
)
|
71
|
+
rescue StandardError
|
72
|
+
nil
|
73
|
+
end
|
30
74
|
end
|
31
75
|
end
|
32
76
|
end
|
data/lib/mj/git/thor_command.rb
CHANGED
@@ -2,6 +2,8 @@
|
|
2
2
|
|
3
3
|
require_relative "commands/checkout_command_handler"
|
4
4
|
require_relative "commands/checkout_command"
|
5
|
+
require_relative "commands/delete_stale_branches_command_handler"
|
6
|
+
require_relative "commands/delete_stale_branches_command"
|
5
7
|
require_relative "command_executer"
|
6
8
|
|
7
9
|
module Mj
|
@@ -14,6 +16,29 @@ module Mj
|
|
14
16
|
handler = Commands::CheckoutCommandHandler.new(stdout: $stdout)
|
15
17
|
handler.handle(command)
|
16
18
|
end
|
19
|
+
|
20
|
+
desc "delete_stale_branches", "Delete remote stale branches"
|
21
|
+
option :dry_run,
|
22
|
+
type: :boolean,
|
23
|
+
banner: "Just outputs, does not delete",
|
24
|
+
aliases: :d
|
25
|
+
option :only_with_prs,
|
26
|
+
type: :boolean,
|
27
|
+
banner: "Only branches that have PRs (Branch can be restored from PR page)",
|
28
|
+
aliases: :p
|
29
|
+
option :only_with_closed_prs,
|
30
|
+
type: :boolean,
|
31
|
+
banner: "Do not delete if PRs are in DRAFT or OPEN - will they maybe be merged?",
|
32
|
+
aliases: :c
|
33
|
+
option :before_date,
|
34
|
+
type: :string,
|
35
|
+
banner: "Formatted date YYY-MM-DD",
|
36
|
+
aliases: :b
|
37
|
+
def delete_stale_branches
|
38
|
+
command = Commands::DeleteStaleBranchesCommand.new(options: options)
|
39
|
+
handler = Commands::DeleteStaleBranchesCommandHandler.new(stdout: $stdout)
|
40
|
+
handler.handle(command)
|
41
|
+
end
|
17
42
|
end
|
18
43
|
end
|
19
44
|
end
|
data/lib/mj/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mj
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 1.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Marcelo Jacobus
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-
|
11
|
+
date: 2024-12-05 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: colorize
|
@@ -137,7 +137,10 @@ files:
|
|
137
137
|
- lib/mj/git/command_executer.rb
|
138
138
|
- lib/mj/git/commands/checkout_command.rb
|
139
139
|
- lib/mj/git/commands/checkout_command_handler.rb
|
140
|
+
- lib/mj/git/commands/delete_stale_branches_command.rb
|
141
|
+
- lib/mj/git/commands/delete_stale_branches_command_handler.rb
|
140
142
|
- lib/mj/git/local_branch.rb
|
143
|
+
- lib/mj/git/pull_request.rb
|
141
144
|
- lib/mj/git/remote_branch.rb
|
142
145
|
- lib/mj/git/thor_command.rb
|
143
146
|
- lib/mj/graphql/client.rb
|
@@ -159,7 +162,7 @@ metadata:
|
|
159
162
|
source_code_uri: https://github.com/mjacobus/mj
|
160
163
|
changelog_uri: https://github.com/mjacobus/mj/blob/main/CHANGELOG.md
|
161
164
|
rubygems_mfa_required: 'true'
|
162
|
-
post_install_message:
|
165
|
+
post_install_message:
|
163
166
|
rdoc_options: []
|
164
167
|
require_paths:
|
165
168
|
- lib
|
@@ -174,8 +177,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
174
177
|
- !ruby/object:Gem::Version
|
175
178
|
version: '0'
|
176
179
|
requirements: []
|
177
|
-
rubygems_version: 3.
|
178
|
-
signing_key:
|
180
|
+
rubygems_version: 3.4.10
|
181
|
+
signing_key:
|
179
182
|
specification_version: 4
|
180
183
|
summary: My personal CLI
|
181
184
|
test_files: []
|