abtion-scripts 1.1.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,195 @@
1
+ require 'json'
2
+ require 'tempfile'
3
+
4
+ module AbtionScripts
5
+ class Pivotal
6
+ attr_reader :token
7
+
8
+ def initialize(token)
9
+ @token = token
10
+ end
11
+
12
+ def request(url, method: "GET", body: nil)
13
+ cmd = %Q{curl --silent -X #{method} -H "X-TrackerToken: #{token}"}
14
+ cmd += %Q{ -H "Content-Type: application/json"}
15
+
16
+ if body
17
+ cmd += %Q{ -d '#{body}'}
18
+ end
19
+
20
+ cmd += %Q{ "#{url}"}
21
+
22
+ result = `#{cmd}`
23
+
24
+ JSON.parse(result.strip)
25
+ end
26
+ end
27
+
28
+ class Begin < Base
29
+ def self.description
30
+ "Starts your Pivotal Tracker story and opens a new PR on Github"
31
+ end
32
+
33
+ def self.help
34
+ <<-EOF
35
+ abtion begin #{colorize(:light_blue, "[story id] [branch name]")}
36
+
37
+ Example: $ #{colorize(:light_blue, 'abtion begin "#133717234"')}
38
+
39
+ This command will start your Pivotal Tracker story for you, open a pull
40
+ request on Github, and copy over the Pivotal Tracker story description to
41
+ the Github pull request description. As well, any tasks in your
42
+ Pivotal Tracker story will automatically become [x] checkbox tasks on the
43
+ Github PR.
44
+
45
+ * All branch names will be auto-converted to
46
+ kebab-case, lowercase
47
+
48
+ * Passing story id/branch name as arguments are optional - if
49
+ they are missing, you'll be prompted
50
+ EOF
51
+ end
52
+
53
+ def run
54
+ story_id, branch_name = argv
55
+
56
+ if !command?("hub")
57
+ abort <<-EOF
58
+ You need to install `hub` before you can use this program.
59
+
60
+ brew install hub
61
+ EOF
62
+ end
63
+
64
+ pivotal = Pivotal.new(git_config("user.pivotalApiToken"))
65
+ config_abort_if_blank!("user.pivotalApiToken", pivotal.token)
66
+
67
+ project_id = git_config("user.pivotalProjectId")
68
+ config_abort_if_blank!("user.pivotalProjectId", project_id)
69
+
70
+ story_id ||= prompt("Please paste the Pivotal story ID here")
71
+ story_id = story_id.gsub(/[^\d]/, '')
72
+
73
+ story_url = "https://www.pivotaltracker.com/services/v5"\
74
+ "/projects/#{project_id}/stories/#{story_id}"
75
+
76
+ story = pivotal.request(story_url)
77
+
78
+ default_branch_name = normalized_branch_name(story['name'])
79
+
80
+ branch_name ||= prompt("Please enter a branch name (#{default_branch_name})")
81
+
82
+ if branch_name.strip == ""
83
+ branch_name = default_branch_name
84
+ else
85
+ branch_name = normalized_branch_name(branch_name)
86
+ end
87
+
88
+ # Start the story
89
+ pivotal.request(story_url, method: "PUT", body: '{ "current_state":"started" }')
90
+
91
+ silent "git checkout master",
92
+ "git fetch origin",
93
+ "git reset --hard origin/master"
94
+
95
+ puts "==> Checking out #{branch_name}"
96
+
97
+ silent "git checkout -b #{branch_name}",
98
+ 'git commit --allow-empty -m "Initial commit for story #' + story_id + '"',
99
+ "git push origin #{branch_name}",
100
+ "git branch --set-upstream #{branch_name} origin/#{branch_name}"
101
+
102
+ tasks = pivotal.request(
103
+ "https://www.pivotaltracker.com/services/v5"\
104
+ "/projects/#{project_id}/stories/#{story_id}/tasks"
105
+ )
106
+
107
+ story_description = story['description']
108
+
109
+ if story_description.nil?
110
+ story_description = "_No story description given in Pivotal_"
111
+ end
112
+
113
+ description = <<-EOF
114
+ #{story['name']}
115
+
116
+ #{story['url']}
117
+
118
+ # Description
119
+
120
+ #{story_description}
121
+ EOF
122
+
123
+ description.strip!
124
+
125
+ unless tasks.empty?
126
+ description += "\n\n## TODO\n\n"
127
+
128
+ tasks.each do |task|
129
+ description += "- [ ] #{task['description']}\n"
130
+ end
131
+
132
+ description.strip!
133
+ end
134
+
135
+ puts "==> Opening pull request on GitHub"
136
+
137
+ tempfile = Tempfile.new('begin_pull_request')
138
+
139
+ begin
140
+ tempfile.write(description)
141
+ tempfile.close
142
+
143
+ labels = ['WIP', story['story_type']].join(',')
144
+
145
+ url = `hub pull-request -F #{tempfile.path} -l "#{labels}" -a "" -o`
146
+
147
+ # Copy it to your clipboard
148
+ system("echo #{url} | pbcopy")
149
+ puts url
150
+ ensure
151
+ tempfile.unlink
152
+ end
153
+ end
154
+
155
+ private
156
+
157
+ def silent(*cmds)
158
+ cmds.each { |cmd| system("#{cmd} >/dev/null 2>&1") }
159
+ end
160
+
161
+ def command?(name)
162
+ `which #{name}`
163
+ $?.success?
164
+ end
165
+
166
+ def git_config(key)
167
+ `git config --local --get #{key}`.strip
168
+ end
169
+
170
+ def config_abort_if_blank!(key, value)
171
+ if value.strip == ""
172
+ abort <<-EOF
173
+ You need to set the #{key} value in your git config!
174
+
175
+ git config --local --add #{key} [value]
176
+ EOF
177
+ end
178
+ end
179
+
180
+ def prompt(msg)
181
+ print "#{msg} > "
182
+ value = STDIN.gets.strip
183
+ puts
184
+ value
185
+ end
186
+
187
+ def normalized_branch_name(branch_name)
188
+ branch_name
189
+ .gsub(/[^\w\s-]/, '')
190
+ .gsub(/\s+/, '-')
191
+ .downcase
192
+ .gsub(/-*$/, '') # trailing dashes
193
+ end
194
+ end
195
+ end
@@ -0,0 +1,39 @@
1
+ module AbtionScripts::Colorize
2
+ extend self
3
+
4
+ def self.included(base)
5
+ colorize = self
6
+
7
+ base.class_eval do
8
+ extend colorize
9
+ end
10
+ end
11
+
12
+ COLOR_CODES = {
13
+ black: 30,
14
+ blue: 34,
15
+ brown: 33,
16
+ cyan: 36,
17
+ dark_gray: 90,
18
+ green: 32,
19
+ light_blue: 94,
20
+ light_cyan: 96,
21
+ light_gray: 37,
22
+ light_green: 92,
23
+ light_purple: 95,
24
+ light_red: 91,
25
+ light_yellow: 93,
26
+ purple: 35,
27
+ red: 31,
28
+ white: 97,
29
+ yellow: 33,
30
+
31
+ command: 96,
32
+ error: 91,
33
+ info: 93,
34
+ }
35
+
36
+ def colorize(color, string)
37
+ "\e[#{COLOR_CODES[color]}m#{string}\e[0m"
38
+ end
39
+ end
@@ -0,0 +1,29 @@
1
+ class Diff < AbtionScripts::Base
2
+ def self.name
3
+ "diff"
4
+ end
5
+
6
+ DAY = 86400
7
+
8
+ def run
9
+ yesterday = (Time.now - DAY).strftime("%Y-%m-%d")
10
+
11
+ last_sha = `git log --after "#{yesterday} 00:00" --before "#{yesterday} 23:59" --format="format:%H"`
12
+ .strip
13
+ .split("\n")
14
+ .last
15
+
16
+ start_sha = `git log "#{last_sha}^" --format="format:%H"`
17
+ .strip
18
+ .split("\n")
19
+ .first
20
+
21
+ repo = `git remote -v | grep github | awk '{ print $2 }' | head -n 1`.strip
22
+ repo.gsub!(/\.git/, "")
23
+ repo.gsub!(/git@github.com:/, "")
24
+
25
+ github_repo = repo.split("/")[-2..-1].join("/")
26
+
27
+ system("open https://github.com/#{github_repo}/compare/#{start_sha}...master")
28
+ end
29
+ end
@@ -0,0 +1,200 @@
1
+ class AbtionScripts::Doctor < AbtionScripts::Base
2
+ class Check
3
+ include AbtionScripts::Colorize
4
+
5
+ attr_reader :name, :command, :remedy, :problems
6
+
7
+ def initialize(name:, command:, remedy:)
8
+ @name = name
9
+ @command = command
10
+ @remedy = remedy
11
+ @problems = []
12
+ end
13
+
14
+ def run!
15
+ print "Checking: #{name}... "
16
+
17
+ success = if command.respond_to?(:call)
18
+ command.call
19
+ else
20
+ system "#{command} > /dev/null 2>&1"
21
+ end
22
+
23
+ if success
24
+ puts 'OK'
25
+ else
26
+ print colorize(:error, 'F')
27
+ fix = remedy.respond_to?(:join) ? remedy.join(" ") : remedy
28
+ puts "\n To fix: #{fix}\n\n"
29
+
30
+ problems << name
31
+ end
32
+ end
33
+ end
34
+
35
+ def self.description
36
+ "Checks the health of your development environment"
37
+ end
38
+
39
+ def initialize(*args)
40
+ super
41
+ @checks = []
42
+ end
43
+
44
+ def run
45
+ case argv.first
46
+ when "list"
47
+ list_default_checks
48
+ else
49
+ run_doctor
50
+ end
51
+ end
52
+
53
+ def self.help
54
+ "doctor - helps you diagnose any setup issues with this application\n"
55
+ end
56
+
57
+ def self.help_subcommands
58
+ {
59
+ "abtion doctor" => "runs health checks and gives a report",
60
+ "abtion doctor list" => "prints a list of default checks you can use when overriding doctor checks in your app"
61
+ }
62
+ end
63
+
64
+ def run_doctor
65
+ run_checks
66
+ report
67
+ end
68
+
69
+ def list_default_checks
70
+ puts "These default checks are available for use in your overrides:"
71
+ puts
72
+
73
+ default_checks.each do |name|
74
+ puts " - #{colorize(:light_blue, name)}"
75
+ end
76
+
77
+ puts
78
+ end
79
+
80
+ def check(**options)
81
+ check = Check.new(options)
82
+ @checks << check
83
+
84
+ check.run!
85
+ end
86
+
87
+ private
88
+
89
+ def run_checks
90
+ run_default_checks
91
+ end
92
+
93
+ def run_default_checks
94
+ default_checks.each do |check|
95
+ send(check)
96
+ end
97
+ end
98
+
99
+ def default_checks
100
+ %i[
101
+ check_envrc_file_exists
102
+ check_env_file_exists
103
+ check_direnv_installed
104
+ check_gemfile_dependencies
105
+ check_postgres_launchctl
106
+ check_postgres_running
107
+ check_postgres_role
108
+ check_db_exists
109
+ check_db_migrated
110
+ check_phantomjs_installed
111
+ ]
112
+ end
113
+
114
+ def check_postgres_launchctl
115
+ check \
116
+ name: "postgres launchctl script is linked",
117
+ command: "ls -1 ~/Library/LaunchAgents/homebrew.mxcl.postgresql.plist",
118
+ remedy: command("ln -sfv /usr/local/opt/postgresql/*.plist ~/Library/LaunchAgents")
119
+ end
120
+
121
+ def check_postgres_running
122
+ check \
123
+ name: "postgres is running",
124
+ command: "psql -l",
125
+ remedy: command("launchctl load ~/Library/LaunchAgents/homebrew.mxcl.postgresql.plist")
126
+ end
127
+
128
+ def check_postgres_role
129
+ check \
130
+ name: "postgres role exists",
131
+ command: "psql -U postgres -l",
132
+ remedy: command("createuser --superuser postgres")
133
+ end
134
+
135
+ def check_gemfile_dependencies
136
+ check \
137
+ name: "Gemfile dependencies are up to date",
138
+ command: "bundle check",
139
+ remedy: command("bundle")
140
+ end
141
+
142
+ def check_db_exists
143
+ check \
144
+ name: "Development database exists",
145
+ command: "source .envrc && rails runner -e development 'ActiveRecord::Base.connection'",
146
+ remedy: command("rake db:setup")
147
+
148
+ check \
149
+ name: "Test database exists",
150
+ command: "source .envrc && rails runner -e test 'ActiveRecord::Base.connection'",
151
+ remedy: command("rake db:setup")
152
+ end
153
+
154
+ def check_db_migrated
155
+ check \
156
+ name: "DB is migrated",
157
+ command: "source .envrc && rails runner 'ActiveRecord::Migration.check_pending!'",
158
+ remedy: command("rake db:migrate db:test:prepare")
159
+ end
160
+
161
+ def check_direnv_installed
162
+ check \
163
+ name: "direnv installed",
164
+ command: "which direnv",
165
+ remedy: command("brew install direnv")
166
+ end
167
+
168
+ def check_phantomjs_installed
169
+ check \
170
+ name: "PhantomJS installed",
171
+ command: "which phantomjs",
172
+ remedy: command("brew install phantomjs")
173
+ end
174
+
175
+ def check_envrc_file_exists
176
+ check \
177
+ name: ".envrc file exists",
178
+ command: "stat .envrc",
179
+ remedy: command("cp .envrc.sample .envrc")
180
+ end
181
+
182
+ def check_env_file_exists
183
+ check \
184
+ name: ".env file exists (for 'heroku local')",
185
+ command: "stat .env",
186
+ remedy: command("ln -s .envrc .env")
187
+ end
188
+
189
+ def problems
190
+ @checks.map(&:problems).flatten
191
+ end
192
+
193
+ def report
194
+ exit problems.size
195
+ end
196
+
197
+ def command(s)
198
+ "run #{colorize :command, s}"
199
+ end
200
+ end