abtion-scripts 1.1.1
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.
- checksums.yaml +7 -0
- data/.document +5 -0
- data/.pairs +11 -0
- data/.rspec +2 -0
- data/.ruby-version +1 -0
- data/Gemfile +11 -0
- data/Gemfile.lock +116 -0
- data/LICENSE.txt +20 -0
- data/README.md +113 -0
- data/Rakefile +53 -0
- data/VERSION +1 -0
- data/abtion.yml +5 -0
- data/bin/abtion +26 -0
- data/lib/abtion_scripts.rb +7 -0
- data/lib/abtion_scripts/base.rb +135 -0
- data/lib/abtion_scripts/begin.rb +195 -0
- data/lib/abtion_scripts/colorize.rb +39 -0
- data/lib/abtion_scripts/diff.rb +29 -0
- data/lib/abtion_scripts/doctor.rb +200 -0
- data/lib/abtion_scripts/help.rb +53 -0
- data/lib/abtion_scripts/heroku_doctor.rb +71 -0
- data/lib/abtion_scripts/kill_db_sessions.rb +22 -0
- data/lib/abtion_scripts/levenstein.rb +40 -0
- data/lib/abtion_scripts/promote.rb +15 -0
- data/lib/abtion_scripts/pushit.rb +23 -0
- data/lib/abtion_scripts/rspec.rb +19 -0
- data/lib/abtion_scripts/test.rb +17 -0
- data/lib/abtion_scripts/todayi.rb +29 -0
- data/lib/abtion_scripts/update.rb +77 -0
- data/spec/passing_spec.rb +5 -0
- data/spec/spec_helper.rb +62 -0
- metadata +173 -0
@@ -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
|