-
Notifications
You must be signed in to change notification settings - Fork 0
/
gitnoob.rb
executable file
·258 lines (210 loc) · 9.03 KB
/
gitnoob.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
#!/usr/bin/env ruby
require 'optparse'
require 'colorize'
# helps adopting good practices and pushing clean code
# features :
# - prevents from coding directly into dev
# - prevents from pushing breaking code into dev
# - helps you setting up a standardised workflow
FEATURE_COMMIT_PREFIX = 'feature-'
REFERENCE_BRANCH_NAME = 'dev'
CURRENT_BRANCH = `git rev-parse --abbrev-ref HEAD`.delete("\n")
#-------------- START HELPERS ----------------
class String
def is_integer?
self.to_i.to_s == self
end
def is_positive_integer?
self.is_integer? && self.to_i >= 0
end
end
def error(isSuccess, message)
unless isSuccess then
puts "ERROR: #{message}".red
exit
end
end
def success(message)
puts message.green
end
def generateFullCommitMessage(currentBranch, message)
"#{CURRENT_BRANCH}: #{message}"
end
def generateFullFeatureBranchName(name)
"#{FEATURE_COMMIT_PREFIX}#{name}"
end
def isWorkingDirectoryClean
`git status --porcelain`.empty?
end
def isCurrentBranchFeature
#TODO: also check if it descends directly from REFERENCE_BRANCH_NAME branch
CURRENT_BRANCH.start_with?(FEATURE_COMMIT_PREFIX)
end
def isCurrentBranchReferenceBranch
#TODO: also check if it descends directly from REFERENCE_BRANCH_NAME branch
CURRENT_BRANCH == REFERENCE_BRANCH_NAME
end
def isCurrentDirectoryAGitRepository
system("[ -d .git ] || git rev-parse --git-dir > /dev/null 2>&1")
end
#-------------- END HELPERS ----------------
#-------------- START OPTIONS LOGIC ----------------
def optionInit
# create repo if needed
if(isCurrentDirectoryAGitRepository)
error(isWorkingDirectoryClean, 'Working directory is not clean')
else
error(system("git init"), 'failed to create repository')
end
# create branches
error(system("git checkout master"), 'failed to create repository')
error(system("git branch #{REFERENCE_BRANCH_NAME}"), 'failed to create repository')
error(system("git checkout #{REFERENCE_BRANCH_NAME}"), 'failed to create repository')
success "Gitnoob is ready to be used"
end
def optionPrune
# check if current branch is a feature
error(isCurrentBranchFeature, 'You cannot commit from something else than a feature branch')
# check if working directory clean
error(isWorkingDirectoryClean, 'Working directory is not clean')
# update the reference branch
error(system("git checkout #{REFERENCE_BRANCH_NAME}"), "Failed to checkout #{REFERENCE_BRANCH_NAME}")
error(system('git pull'), "Error pulling changes on #{REFERENCE_BRANCH_NAME}")
# test your modifications with the changes of the reference branch
error(system("git checkout #{CURRENT_BRANCH}"), "Failed to checkout #{CURRENT_BRANCH}")
error(system("git merge #{REFERENCE_BRANCH_NAME} -m \"Applying finished feature #{CURRENT_BRANCH}\""), 'Error merging')
error(system('rake test'), 'The tests are not passing, please fix and try again')
# apply your modifications and remove the feature branch
error(system("git checkout #{REFERENCE_BRANCH_NAME}"), "Failed to checkout #{REFERENCE_BRANCH_NAME}")
error(system("git merge #{CURRENT_BRANCH}"), "Failed to merge your work on #{REFERENCE_BRANCH_NAME}")
error(system("git branch -d #{CURRENT_BRANCH}"), "Failed to remove your feature branch")
error(system("git push"), "Failed to push the changes")
success "Feature successfully applied to #{REFERENCE_BRANCH_NAME}"
end
def optionUpdate#check if working directory clean?
# check if current branch is a feature
error(isCurrentBranchFeature, 'You cannot update something else than a feature branch')
# integrate changes from the remote same feature first
error(system("git pull"), 'Error pulling changes from remote')
# integrate changes from the reference branch
error(system("git merge #{REFERENCE_BRANCH_NAME} -m \"feature updated with #{REFERENCE_BRANCH_NAME} changes\""), 'Error merging, abort it or fix the issues')
success "Feature successfully updated with #{REFERENCE_BRANCH_NAME} changes"
end
def optionFeature
def isfeatureNameValid(name)
!name.start_with? FEATURE_COMMIT_PREFIX
end
def createNewFeature(name)
# validate branch name
error(isfeatureNameValid(name), "Feature name is invalid (#{name}), it should not start with #{FEATURE_COMMIT_PREFIX}")
# create the new branch with an appropriate name
error(system("git checkout -b #{generateFullFeatureBranchName(name)}"), 'Failed to create branch')
end
# ensure that we are on reference branch NOTE: should we try to checkout reference branch?
error(CURRENT_BRANCH == REFERENCE_BRANCH_NAME, "Feature must branch from #{REFERENCE_BRANCH_NAME} (currently #{CURRENT_BRANCH})")
# check if working directory clean
error(isWorkingDirectoryClean, 'Working directory is not clean')
# update remotes
error(system('git remote update'), 'Error updating remotes')
branches = `git for-each-ref --format='%(refname)' refs/heads/`.to_s.split("\n")
featureBranches = branches.select{|branchName| branchName.start_with?('refs/heads/feature-')}
featureBranches.collect! {|fullName| fullName['refs/heads/'.length..-1]}
featureBranches.insert(0, 'créer une nouvelle feature')
featureBranches.each_with_index do |featureBranchName, index|
puts(index.to_s + ' ' + featureBranchName)
end
puts 'choix?'
choice = gets.strip
error(choice.is_positive_integer?, 'Veuillez rentrer un nombre entier')
choice_i = choice.to_i
error((0..featureBranches.length-1).cover?(choice_i) , 'Choix non valide')
if choice_i == 0
# créer nouvelle feature
puts 'Quel est le nom de la nouvelle feature?'
name = gets.strip
createNewFeature name
success "Feature #{generateFullFeatureBranchName(name)} successfully created"
else
# basculer sur la feature existante
error(system("git checkout #{featureBranches[choice_i]}"), "Failed to switch to feature #{featureBranches[choice_i]}")
success "Switched to feature #{featureBranches[choice_i]}"
end
end
def optionCommit(message)
# check if current branch is a feature
error(isCurrentBranchFeature, 'You cannot commit from something else than a feature branch')
# check if directory is not clean
error(!isWorkingDirectoryClean, 'Working directory is clean')
# add all and commit
system 'git add -A'
error(system("git commit -m \"#{generateFullCommitMessage(CURRENT_BRANCH, message)}\""), 'Failed to commit')
success "Changes successfully commited"
end
def optionVersion
# ensure being in reference branch
error(isCurrentBranchReferenceBranch, 'You are not in the reference branch')
# check if working directory clean
error(isWorkingDirectoryClean, 'Working directory is not clean')
# test again your modifications with the changes of the master branch
error(system('git fetch'), 'Error fetching from origin')
error(system("git merge master"), 'Error merging')
error(system('rake test'), 'The tests are not passing, please fix and try again')
# apply your modifications and go back to dev
error(system("git checkout master"), "Failed to checkout master")
error(system("git merge #{REFERENCE_BRANCH_NAME}"), "Failed to merge your work on master")
error(system("git push"), "Failed to push the changes")
error(system("git checkout #{REFERENCE_BRANCH_NAME}"), "Failed to checkout #{REFERENCE_BRANCH_NAME}")
success "Successfully updated master"
end
def optionReference
# ensure being in a branch feature
error(isCurrentBranchFeature, 'You are not in a feature branch')
# add all changes
system 'git add -A'
# check if directory is clean
error(isWorkingDirectoryClean, 'Working directory is not clean, please stash or commit')
# move to reference branch
error(system("git checkout #{REFERENCE_BRANCH_NAME}"), "Failed to checkout reference branch (#{REFERENCE_BRANCH_NAME})")
# pull latest changes
error(system('git fetch'), 'Failed to fetch changes')
success "Back to reference branch"
end
def optionHelp(options)
puts options
end
#-------------- END OPTIONS LOGIC ----------------
optionParser = OptionParser.new do|options|
options.on('-i', '--init', 'create necessary branches for gitnoob, create the local repo if necessary. If repo exists, it should be "empty"') do
optionInit
exit
end
options.on('-p', '--prune', 'Try to merge and push the current branch into the reference branch (! the feature branch get deleted after this operation)') do# check if working directory clean
optionPrune
exit
end
options.on('-u', '--update', 'Update feature with latest changes from the reference branche') do
optionUpdate
exit
end
options.on('-f', '--feature', 'Start developping a new or existing feature' ) do
optionFeature
exit
end
options.on('-c', '--commit MESSAGE', 'Stag and commit all changes to your current feature branch' ) do |message|
optionCommit message
exit
end
options.on('-r', '--reference', 'go back to reference branch') do
optionReference
exit
end
options.on('-v', '--version', 'publish reference branch to master') do
optionVersion
exit
end
options.on_tail( '-h', '--help', 'Display this screen' ) do
optionHelp options
exit
end
end
optionParser.parse!