cob 0.0.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 698e8f72857d8052c532614332d07903b44e4b4da52a85debfcaf46745a3109d
4
+ data.tar.gz: c88940d9ac79e2bbdce31572d53ab1bb1b465ab680bd835fd69d34e15ac49161
5
+ SHA512:
6
+ metadata.gz: 3d084dc142c8613fe784d70507705390538a3472271e747212f26699779e8b11656298e03227931be9ad55b0cdf00c52535f7eaf25ff479d8ac1f7a0c922c54b
7
+ data.tar.gz: 877eb16d44a54f1221d221d6d7e7f3f69347d125be7af500002c0e6093be8bba64212a8a5453bcbd6b2a59f408b7cd9fe2f7f8bfe92bafe5b902ab0b2a1e6cc7
data/bin/cob ADDED
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require 'cob'
5
+
6
+ Cob.run(ARGV)
@@ -0,0 +1,62 @@
1
+ # !/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ #
5
+ # _________ ________ __________
6
+ # \_ ___ \ \_____ \\______ \
7
+ # / \ \/ / | \| | _/
8
+ # \ \____/ | \ | \
9
+ # \______ /\_______ /______ /
10
+ # \/ \/ \/
11
+ #
12
+ # The ULTIMATE "cob" tool with a total of 3 distinct usages.
13
+ # examples:
14
+ # $ cob # queries github and gives you a list of issues to pick from
15
+ # $ cob 2837 # queries github and checks out the matching issue using "cob" style formating
16
+ # $ cob "my string with #hashes and, other: . punctuations" # instant cob
17
+ # $ cob some sentence without special characters # instant cob
18
+ #
19
+
20
+ require_relative './git.rb'
21
+ require_relative './local_cob.rb'
22
+ require_relative './string_refinements.rb'
23
+
24
+ using StringRefinements
25
+
26
+ module Cob
27
+ class << self
28
+ def run(args)
29
+ @args = args
30
+
31
+ if (@args.length == 1 && !@args[0].all_digits?) || @args.length > 1
32
+ run_local
33
+ exit 0
34
+ end
35
+
36
+ run_remote
37
+ rescue Interrupt
38
+ exit 1
39
+ end
40
+
41
+ private
42
+
43
+ def run_local
44
+ LocalCOB.run
45
+ end
46
+
47
+ def run_remote
48
+ require 'json'
49
+ require 'fileutils'
50
+ require 'tty-prompt'
51
+ require_relative './credentials.rb'
52
+ require_relative './paginator.rb'
53
+ require_relative './navigator.rb'
54
+ require_relative './remote_cob.rb'
55
+
56
+ RemoteCOB::Selection.run && exit(0) if @args.empty?
57
+ RemoteCOB::Fire.run && exit(0) if @args.length == 1
58
+ rescue Interrupt
59
+ exit 1
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,83 @@
1
+ # frozen_string_literal: true
2
+
3
+ #
4
+ # class to handle the credentials
5
+ #
6
+ # usage:
7
+ #
8
+ # c = Credentials.new
9
+ # c.username
10
+ # c.pa_token
11
+ #
12
+ class Credentials
13
+ def initialize
14
+ @config_file = ENV['GITHUB_CREDENTIALS_FILE'] ||
15
+ "#{ENV['HOME']}/.cob/github_credentials.json"
16
+ @config = parse_config
17
+ end
18
+
19
+ def username
20
+ # USERNAME
21
+ @config['username'] || prompt_username
22
+ end
23
+
24
+ def pa_token
25
+ # PA_TOKEN
26
+ @config['paToken'] || prompt_pa_token
27
+ end
28
+
29
+ def overwrite_config
30
+ File.write(@config_file, @config.to_json)
31
+ end
32
+
33
+ def prompt_username
34
+ prompt = TTY::Prompt.new(active_color: :cyan)
35
+ username = prompt.ask('What is your github username?') do |q|
36
+ q.required true
37
+ q.modify :lowercase
38
+ end
39
+
40
+ @config['username'] = username
41
+ overwrite_config
42
+
43
+ username
44
+ end
45
+
46
+ def prompt_pa_token
47
+ prompt = TTY::Prompt.new(active_color: :cyan)
48
+ token = prompt.ask('What is your github personal access token? You can get one from here: https://github.com/settings/tokens') do |q|
49
+ q.required true
50
+ end
51
+
52
+ @config['paToken'] = token
53
+ overwrite_config
54
+
55
+ token
56
+ end
57
+
58
+ def reset_config_file
59
+ File.write(@config_file, '{}')
60
+ end
61
+
62
+ def ensure_config_file_is_created
63
+ return if File.exist?(@config_file)
64
+
65
+ segments = @config_file.split('/')
66
+ paths = segments[0..-2]
67
+ file = segments[-1]
68
+ dir = paths.join('/')
69
+ FileUtils.mkdir_p(dir)
70
+ FileUtils.touch(dir + '/' + file)
71
+
72
+ reset_config_file
73
+ end
74
+
75
+ private
76
+
77
+ def parse_config
78
+ JSON.parse(File.read(@config_file))
79
+ rescue StandardError => e
80
+ puts "Couldn't parse config file. Make sure the JSON is correct:\n#{@config_file}"
81
+ raise e
82
+ end
83
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ # this class interfaces with the local `git` command
4
+ module Git
5
+ class << self
6
+ def remote
7
+ `git config --list | grep remote.origin.url`&.strip&.split(':')&.last
8
+ end
9
+
10
+ def repository
11
+ remote.split('/').last.chomp('.git')
12
+ end
13
+
14
+ def repository_owner
15
+ remote.split('/').first
16
+ end
17
+
18
+ def checkout_branch(text)
19
+ branch = text.downcase.gsub(/[^a-zA-Z0-9#]+/, '_')
20
+ output = `git checkout -b #{branch} 2>&1`
21
+
22
+ if output.match?(/A branch named '#{branch}' already exists/)
23
+ `git checkout #{branch}`
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ # _ _ ___ ___ ___
4
+ # | | ___ __ __ _| | / __/ _ \| _ )
5
+ # | |__/ _ \/ _/ _` | | | (_| (_) | _ \
6
+ # |____\___/\__\__,_|_| \___\___/|___/
7
+ #
8
+ #
9
+ # This is the original COB
10
+ #
11
+ module LocalCOB
12
+ def self.run
13
+ Git.checkout_branch(ARGV.join(' '))
14
+ end
15
+ end
@@ -0,0 +1,64 @@
1
+ # frozen_string_literal: true
2
+
3
+ # this class prompts the user for selection and shows "next..." and "prev..."
4
+ # when the user can navigate to the next/prev pages.
5
+ class Navigator
6
+ def initialize(paginator)
7
+ @paginator = paginator
8
+ @active_index = 1
9
+ end
10
+
11
+ def prompt_for_issue_selection
12
+ prompt = TTY::Prompt.new(active_color: :cyan)
13
+
14
+ if @paginator.no_issues?
15
+ puts 'No issues found.'
16
+ exit 0
17
+ end
18
+
19
+ @selected_index = prompt.select('Select issue:') do |menu|
20
+ menu.default @active_index
21
+
22
+ items.each.with_index(1) do |item, i|
23
+ menu.choice item.to_s, i
24
+ end
25
+ end
26
+
27
+ handle_selection
28
+ end
29
+
30
+ def items
31
+ ii = @paginator.formatted_issues
32
+ ii = ['prev...'] + ii if show_prev?
33
+ ii += ['next...'] if show_next?
34
+ ii
35
+ end
36
+
37
+ private
38
+
39
+ def show_prev?
40
+ @paginator.prev?
41
+ end
42
+
43
+ def show_next?
44
+ @paginator.next?
45
+ end
46
+
47
+ def handle_selection
48
+ choice = items[@selected_index - 1]
49
+
50
+ return choice unless ['next...', 'prev...'].include? choice
51
+
52
+ if choice == 'next...'
53
+ @paginator.inc
54
+ @active_index = 1
55
+ end
56
+
57
+ if choice == 'prev...'
58
+ @paginator.dec
59
+ @active_index = [items.count, 1].max
60
+ end
61
+
62
+ prompt_for_issue_selection
63
+ end
64
+ end
@@ -0,0 +1,74 @@
1
+ # frozen_string_literal: true
2
+
3
+ # this class fetches and paginates the issues from github.com
4
+ class Paginator
5
+ attr_reader :page
6
+
7
+ def initialize(credentials)
8
+ @credentials = credentials
9
+ @page = 1
10
+ @cache = {}
11
+ @next = {}
12
+ end
13
+
14
+ def issues
15
+ @cache[@page] ||= begin
16
+ issues = fetch_issues
17
+ @next[@page] = issues.count.positive?
18
+ issues
19
+ end
20
+ end
21
+
22
+ def no_issues?
23
+ @page == 1 && issues.empty?
24
+ end
25
+
26
+ def next?
27
+ issues && @next[@page]
28
+ end
29
+
30
+ def prev?
31
+ @page > 1
32
+ end
33
+
34
+ def format_issue(issue)
35
+ "#{issue['number']} --- #{issue['title']}"
36
+ end
37
+
38
+ def formatted_issues
39
+ issues.map { |i| format_issue(i) }
40
+ end
41
+
42
+ def dec
43
+ @page = [@page - 1, 1].max
44
+ end
45
+
46
+ def inc
47
+ @page += 1
48
+ end
49
+
50
+ private
51
+
52
+ def fetch_issues
53
+ _header, body = http_get_issues.split("\r\n\r\n")
54
+ data = JSON.parse(body)
55
+
56
+ # TODO: move elsewhere
57
+ if data.is_a?(Hash) && data['message'] == 'Bad credentials'
58
+ puts 'Your github credentials are wrong.'
59
+
60
+ @credentials.reset_config_file
61
+ exit 1
62
+ end
63
+
64
+ data.select { |i| i['pull_request'].nil? } # ignore pull requests
65
+ end
66
+
67
+ def http_get_issues
68
+ uname = @credentials.username
69
+ token = @credentials.pa_token
70
+ `curl -sS -i https://api.github.com/repos/#{Git.repository_owner}/#{Git.repository}/issues?page=#{@page} \
71
+ -u "#{uname}:#{token}" \
72
+ -H "Content-Type: application/json"`
73
+ end
74
+ end
@@ -0,0 +1,61 @@
1
+ # frozen_string_literal: true
2
+
3
+ #
4
+ # ___ _ ___ ___ ___
5
+ # | _ \___ _ __ ___| |_ ___ / __/ _ \| _ )
6
+ # | / -_) ' \/ _ \ _/ -_) | (_| (_) | _ \
7
+ # |_|_\___|_|_|_\___/\__\___| \___\___/|___/
8
+ #
9
+ #
10
+ # this module contain the remote commands
11
+ module RemoteCOB
12
+ def self.ensure_credentials_and_remote
13
+ Credentials.new.ensure_config_file_is_created
14
+
15
+ unless Git.remote
16
+ puts 'could not find remote git repository'
17
+ exit 1
18
+ end
19
+
20
+ unless Git.repository_owner && Git.repository
21
+ puts "couldn't retreive repo and owner from remote: #{remote}"
22
+ exit 1
23
+ end
24
+ end
25
+
26
+ # This is the code for querying github issues and displaying
27
+ # a select prompt to the user
28
+ module Selection
29
+ def self.run
30
+ RemoteCOB.ensure_credentials_and_remote
31
+ paginator = Paginator.new(Credentials.new)
32
+ issue = Navigator.new(paginator).prompt_for_issue_selection
33
+ Git.checkout_branch(issue)
34
+ end
35
+ end
36
+
37
+ # This is the code for automatically checking out the matching issue in github
38
+ module Fire
39
+ def self.run
40
+ RemoteCOB.ensure_credentials_and_remote
41
+ issue_number = ARGV[0].to_i
42
+ paginator = Paginator.new(Credentials.new)
43
+
44
+ while paginator.next?
45
+ issue = paginator.issues.detect { |i| i['number'] == issue_number }
46
+
47
+ if issue
48
+ Git.checkout_branch(paginator.format_issue(issue))
49
+ exit 0
50
+ end
51
+
52
+ puts "couldn't find issue on page: #{paginator.page}, fetching next..."
53
+
54
+ paginator.inc
55
+ end
56
+
57
+ puts "couldn't find issue on github."
58
+ exit 1
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module StringRefinements
4
+ refine String do
5
+ def all_digits?
6
+ scan(/\D/).empty?
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Cob
4
+ VERSION = '0.0.15'
5
+ end
metadata ADDED
@@ -0,0 +1,95 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: cob
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.15
5
+ platform: ruby
6
+ authors:
7
+ - Yan
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2019-09-03 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: fileutils
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: json
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '2.2'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '2.2'
41
+ - !ruby/object:Gem::Dependency
42
+ name: tty-prompt
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: 0.19.0
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: 0.19.0
55
+ description: Format and checkout your branches
56
+ email: yan@shiyason.com
57
+ executables:
58
+ - cob
59
+ extensions: []
60
+ extra_rdoc_files: []
61
+ files:
62
+ - bin/cob
63
+ - lib/cob.rb
64
+ - lib/credentials.rb
65
+ - lib/git.rb
66
+ - lib/local_cob.rb
67
+ - lib/navigator.rb
68
+ - lib/paginator.rb
69
+ - lib/remote_cob.rb
70
+ - lib/string_refinements.rb
71
+ - lib/version.rb
72
+ homepage: https://github.com/yanshiyason/cob
73
+ licenses:
74
+ - MIT
75
+ metadata: {}
76
+ post_install_message:
77
+ rdoc_options: []
78
+ require_paths:
79
+ - lib
80
+ required_ruby_version: !ruby/object:Gem::Requirement
81
+ requirements:
82
+ - - ">="
83
+ - !ruby/object:Gem::Version
84
+ version: '0'
85
+ required_rubygems_version: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ requirements: []
91
+ rubygems_version: 3.0.3
92
+ signing_key:
93
+ specification_version: 4
94
+ summary: Checkout github branches with style
95
+ test_files: []