citizen-scripts 1.1.0
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/.rspec +2 -0
- data/.ruby-version +1 -0
- data/Gemfile +12 -0
- data/Gemfile.lock +117 -0
- data/LICENSE.txt +20 -0
- data/README.md +108 -0
- data/Rakefile +53 -0
- data/VERSION +1 -0
- data/bin/citizen +26 -0
- data/citizen.yml +5 -0
- data/citizen_code_scripts.gemspec +90 -0
- data/lib/citizen_code_scripts/base.rb +95 -0
- data/lib/citizen_code_scripts/begin.rb +195 -0
- data/lib/citizen_code_scripts/colorize.rb +39 -0
- data/lib/citizen_code_scripts/doctor.rb +179 -0
- data/lib/citizen_code_scripts/help.rb +53 -0
- data/lib/citizen_code_scripts/heroku_doctor.rb +58 -0
- data/lib/citizen_code_scripts/kill_db_sessions.rb +22 -0
- data/lib/citizen_code_scripts/levenstein.rb +40 -0
- data/lib/citizen_code_scripts/pushit.rb +23 -0
- data/lib/citizen_code_scripts/rspec.rb +19 -0
- data/lib/citizen_code_scripts/test.rb +17 -0
- data/lib/citizen_code_scripts/todayi.rb +29 -0
- data/lib/citizen_code_scripts/update.rb +63 -0
- data/lib/citizen_code_scripts.rb +7 -0
- data/spec/passing_spec.rb +5 -0
- data/spec/spec_helper.rb +62 -0
- metadata +190 -0
@@ -0,0 +1,195 @@
|
|
1
|
+
require 'json'
|
2
|
+
require 'tempfile'
|
3
|
+
|
4
|
+
module CitizenCodeScripts
|
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
|
+
citizen begin #{colorize(:light_blue, "[story id] [branch name]")}
|
36
|
+
|
37
|
+
Example: $ #{colorize(:light_blue, 'citizen 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 CitizenCodeScripts::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,179 @@
|
|
1
|
+
class CitizenCodeScripts::Doctor < CitizenCodeScripts::Base
|
2
|
+
class Check
|
3
|
+
include CitizenCodeScripts::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
|
+
"citizen doctor" => "runs health checks and gives a report",
|
60
|
+
"citizen 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_postgres_launchctl
|
102
|
+
check_postgres_running
|
103
|
+
check_postgres_role
|
104
|
+
check_db_migrated
|
105
|
+
check_direnv_installed
|
106
|
+
check_phantomjs_installed
|
107
|
+
check_gemfile_dependencies
|
108
|
+
check_envrc_file_exists
|
109
|
+
]
|
110
|
+
end
|
111
|
+
|
112
|
+
def check_postgres_launchctl
|
113
|
+
check \
|
114
|
+
name: "postgres launchctl script is linked",
|
115
|
+
command: "ls -1 ~/Library/LaunchAgents/homebrew.mxcl.postgresql.plist",
|
116
|
+
remedy: command("ln -sfv /usr/local/opt/postgresql/*.plist ~/Library/LaunchAgents")
|
117
|
+
end
|
118
|
+
|
119
|
+
def check_postgres_running
|
120
|
+
check \
|
121
|
+
name: "postgres is running",
|
122
|
+
command: "psql -l",
|
123
|
+
remedy: command("launchctl load ~/Library/LaunchAgents/homebrew.mxcl.postgresql.plist")
|
124
|
+
end
|
125
|
+
|
126
|
+
def check_postgres_role
|
127
|
+
check \
|
128
|
+
name: "postgres role exists",
|
129
|
+
command: "psql -U postgres -l",
|
130
|
+
remedy: command("createuser --superuser postgres")
|
131
|
+
end
|
132
|
+
|
133
|
+
def check_gemfile_dependencies
|
134
|
+
check \
|
135
|
+
name: "Gemfile dependencies are up to date",
|
136
|
+
command: "bundle check",
|
137
|
+
remedy: command("bundle")
|
138
|
+
end
|
139
|
+
|
140
|
+
def check_db_migrated
|
141
|
+
check \
|
142
|
+
name: "DB is migrated",
|
143
|
+
command: "source .envrc && rails runner 'ActiveRecord::Migration.check_pending!'",
|
144
|
+
remedy: command("rake db:migrate")
|
145
|
+
end
|
146
|
+
|
147
|
+
def check_direnv_installed
|
148
|
+
check \
|
149
|
+
name: "direnv installed",
|
150
|
+
command: "which direnv",
|
151
|
+
remedy: command("brew install direnv")
|
152
|
+
end
|
153
|
+
|
154
|
+
def check_phantomjs_installed
|
155
|
+
check \
|
156
|
+
name: "PhantomJS installed",
|
157
|
+
command: "which phantomjs",
|
158
|
+
remedy: command("brew install phantomjs")
|
159
|
+
end
|
160
|
+
|
161
|
+
def check_envrc_file_exists
|
162
|
+
check \
|
163
|
+
name: "envrc",
|
164
|
+
command: "stat .envrc",
|
165
|
+
remedy: "get your .envrc file from 1password"
|
166
|
+
end
|
167
|
+
|
168
|
+
def problems
|
169
|
+
@checks.map(&:problems).flatten
|
170
|
+
end
|
171
|
+
|
172
|
+
def report
|
173
|
+
exit problems.size
|
174
|
+
end
|
175
|
+
|
176
|
+
def command(s)
|
177
|
+
"run #{colorize :command, s}"
|
178
|
+
end
|
179
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
class CitizenCodeScripts::Help < CitizenCodeScripts::Base
|
2
|
+
def self.help
|
3
|
+
"Inception was a lame movie"
|
4
|
+
end
|
5
|
+
|
6
|
+
def self.help_subcommands
|
7
|
+
{}
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.description
|
11
|
+
"Prints this message out"
|
12
|
+
end
|
13
|
+
|
14
|
+
def run
|
15
|
+
specific_script = argv[0]
|
16
|
+
|
17
|
+
if CitizenCodeScripts::Base.script_names.include?(specific_script)
|
18
|
+
script = CitizenCodeScripts::Base.scripts[specific_script]
|
19
|
+
puts full_help(script)
|
20
|
+
elsif specific_script
|
21
|
+
puts colorize(:red, "\"#{specific_script}\" does not exist, cannot display help")
|
22
|
+
else
|
23
|
+
basic_usage
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def full_help(script)
|
30
|
+
(script.help || "") + script.help_subcommands.map do |cmd, description|
|
31
|
+
" - #{colorize(:light_blue, cmd)} - #{description}"
|
32
|
+
end.join("\n")
|
33
|
+
end
|
34
|
+
|
35
|
+
def basic_usage
|
36
|
+
puts "Usage: citizen #{colorize(:light_blue, '[script name]')}"
|
37
|
+
puts
|
38
|
+
puts "Specify a specific script to run, options are: "
|
39
|
+
puts
|
40
|
+
|
41
|
+
names_and_descriptions = CitizenCodeScripts::Base.scripts.map do |name, script|
|
42
|
+
[colorize(:light_green, name), colorize(:light_blue, script.description)]
|
43
|
+
end
|
44
|
+
|
45
|
+
padding = names_and_descriptions.map { |name, _| name.length }.max
|
46
|
+
|
47
|
+
names_and_descriptions.each do |name, description|
|
48
|
+
puts " %-#{padding}s %s" % [name, description]
|
49
|
+
end
|
50
|
+
|
51
|
+
puts
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
require_relative './doctor'
|
2
|
+
|
3
|
+
class HerokuDoctor < CitizenCodeScripts::Doctor
|
4
|
+
def self.description
|
5
|
+
"Checks the health of your Heroku config"
|
6
|
+
end
|
7
|
+
|
8
|
+
def self.help
|
9
|
+
<<~TEXT
|
10
|
+
citizen heroku-doctor #{colorize(:light_blue, "environment")} = #{colorize(:yellow, "staging")}
|
11
|
+
TEXT
|
12
|
+
end
|
13
|
+
|
14
|
+
def run_checks
|
15
|
+
@env = argv[0] || "staging"
|
16
|
+
@heroku_app_name = app_names[@env.to_s]
|
17
|
+
|
18
|
+
puts "Environment: #{@env}"
|
19
|
+
puts "Heroku app: #{@heroku_app_name}"
|
20
|
+
puts
|
21
|
+
|
22
|
+
# this one should always be first - it will NEVER pass for the citizen-rails project which is OKAY!
|
23
|
+
check(
|
24
|
+
name: "The citizen.yml file has been configured properly",
|
25
|
+
command: "! grep 'citizen-rails-staging' citizen.yml",
|
26
|
+
remedy: "configure your citizen.yml file to have the correct app names set for all your Heroku environments"
|
27
|
+
)
|
28
|
+
|
29
|
+
check(
|
30
|
+
name: "app #{@heroku_app_name} exists",
|
31
|
+
command: "cat .git/config | grep git@heroku.com:#{@heroku_app_name}.git",
|
32
|
+
remedy: [command("heroku apps:create #{@heroku_app_name}"), "and/or", command("git remote add staging git@heroku.com:#{@heroku_app_name}.git")]
|
33
|
+
)
|
34
|
+
|
35
|
+
check_env("DEPLOY_TASKS", "db:migrate")
|
36
|
+
check_env("RAILS_ENV", "production")
|
37
|
+
check_env("DATABASE_URL", "postgres://", "go to https://dashboard.heroku.com/apps/#{@heroku_app_name}/resources and add the Heroku Postgress add-on")
|
38
|
+
|
39
|
+
check_buildpack("https://github.com/heroku/heroku-buildpack-ruby")
|
40
|
+
check_buildpack("https://github.com/gunpowderlabs/buildpack-ruby-rake-deploy-tasks")
|
41
|
+
end
|
42
|
+
|
43
|
+
def check_env(env_var, value, remedy=nil)
|
44
|
+
check(
|
45
|
+
name: env_var,
|
46
|
+
command: "heroku config:get #{env_var} -a #{@heroku_app_name} | grep '#{value}'",
|
47
|
+
remedy: remedy || command("heroku config:set #{env_var}=#{value} -a #{@heroku_app_name}")
|
48
|
+
)
|
49
|
+
end
|
50
|
+
|
51
|
+
def check_buildpack(url)
|
52
|
+
check(
|
53
|
+
name: url.split("/").last,
|
54
|
+
command: "heroku buildpacks -a #{@heroku_app_name} | grep '#{url}'",
|
55
|
+
remedy: command("heroku buildpacks:add #{url} -a #{@heroku_app_name}")
|
56
|
+
)
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
class CitizenCodeScripts::KillDbSessions < CitizenCodeScripts::Base
|
2
|
+
def self.description
|
3
|
+
"Kills active Postgres sessions"
|
4
|
+
end
|
5
|
+
|
6
|
+
def run
|
7
|
+
print "Loading Rails... "
|
8
|
+
require app_root.join("./config/environment")
|
9
|
+
|
10
|
+
puts "done"
|
11
|
+
|
12
|
+
print "Killing DB sessions... "
|
13
|
+
ActiveRecord::Base.connection.execute(<<-SQL)
|
14
|
+
SELECT pg_terminate_backend(pg_stat_activity.pid)
|
15
|
+
FROM pg_stat_activity
|
16
|
+
WHERE datname = current_database()
|
17
|
+
AND pid <> pg_backend_pid()
|
18
|
+
SQL
|
19
|
+
|
20
|
+
puts "done"
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
class Levenstein
|
2
|
+
def self.edit_distance(s, t)
|
3
|
+
m = s.length
|
4
|
+
n = t.length
|
5
|
+
return m if n == 0
|
6
|
+
return n if m == 0
|
7
|
+
d = Array.new(m+1) { Array.new(n+1) }
|
8
|
+
|
9
|
+
(0..m).each { |i| d[i][0] = i }
|
10
|
+
(0..n).each { |j| d[0][j] = j }
|
11
|
+
(1..n).each do |j|
|
12
|
+
(1..m).each do |i|
|
13
|
+
d[i][j] = if s[i-1] == t[j-1] # adjust index into string
|
14
|
+
d[i-1][j-1] # no operation required
|
15
|
+
else
|
16
|
+
[d[i-1][j]+1, # deletion
|
17
|
+
d[i][j-1]+1, # insertion
|
18
|
+
d[i-1][j-1]+1, # substitution
|
19
|
+
].min
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
d[m][n]
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.closest_match(needle, haystack)
|
27
|
+
min_distance = haystack.map(&:size).max
|
28
|
+
results = nil
|
29
|
+
haystack.each do |value|
|
30
|
+
distance = edit_distance(needle, value)
|
31
|
+
if distance < min_distance
|
32
|
+
min_distance = distance
|
33
|
+
results = [value]
|
34
|
+
elsif distance == min_distance
|
35
|
+
results << value
|
36
|
+
end
|
37
|
+
end
|
38
|
+
results
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
class CitizenCodeScripts::Pushit < CitizenCodeScripts::Base
|
2
|
+
def self.description
|
3
|
+
"Pulls code, runs test, pushes your code"
|
4
|
+
end
|
5
|
+
|
6
|
+
def self.help
|
7
|
+
<<-EOF
|
8
|
+
citizen pushit
|
9
|
+
|
10
|
+
Pulls the latest code, restarts, runs the tests, and pushes
|
11
|
+
your new code up.
|
12
|
+
EOF
|
13
|
+
end
|
14
|
+
|
15
|
+
def run
|
16
|
+
CitizenCodeScripts::Update.run
|
17
|
+
CitizenCodeScripts::Test.run
|
18
|
+
|
19
|
+
step "Pushing" do
|
20
|
+
system('git push')
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
class CitizenCodeScripts::Rspec < CitizenCodeScripts::Base
|
2
|
+
def self.description
|
3
|
+
"Runs your RSpec suite"
|
4
|
+
end
|
5
|
+
|
6
|
+
def run
|
7
|
+
begin
|
8
|
+
load(File.expand_path("./spring", __FILE__))
|
9
|
+
rescue LoadError
|
10
|
+
end
|
11
|
+
|
12
|
+
require 'bundler/setup'
|
13
|
+
|
14
|
+
step "Running RSpec" do
|
15
|
+
command = [Gem.bin_path('rspec-core', 'rspec')] + argv
|
16
|
+
system!(command.join(" "))
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
class CitizenCodeScripts::Test < CitizenCodeScripts::Base
|
2
|
+
def self.description
|
3
|
+
"Runs all test suites for CI/pushit"
|
4
|
+
end
|
5
|
+
|
6
|
+
def run
|
7
|
+
step "Running test suite" do
|
8
|
+
rspec
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
def rspec
|
15
|
+
CitizenCodeScripts::Rspec.run
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
class CitizenCodeScripts::TodayI < CitizenCodeScripts::Base
|
2
|
+
def self.help
|
3
|
+
<<-EOF
|
4
|
+
citizen today-i
|
5
|
+
|
6
|
+
Prints out a list of commit message names that you worked on today.
|
7
|
+
EOF
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.description
|
11
|
+
"Prints a list of commit msgs from today"
|
12
|
+
end
|
13
|
+
|
14
|
+
def run
|
15
|
+
date_string = Time.now.to_s.split(' ')[0]
|
16
|
+
|
17
|
+
lines = %x{
|
18
|
+
git log \
|
19
|
+
--date=local \
|
20
|
+
--oneline \
|
21
|
+
--after="#{date_string} 00:00" \
|
22
|
+
--before="#{date_string} 23:59"
|
23
|
+
}
|
24
|
+
|
25
|
+
lines.each_line do |line|
|
26
|
+
puts line.split(" ", 2)[1]
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|