devu 1.2.0 → 1.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/devu/version.rb +1 -1
- data/lib/devu.sh +700 -0
- metadata +2 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b0d277a4062da520c86ad08694a749ea3c2d2cde4039de4c6d531295b007472d
|
4
|
+
data.tar.gz: 371bf4f1a908a3a361679d18d8f85288c72e35b087502fa96cb115829a15c305
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 818b3f05cf91e7c6ab30fd7d2f88cf435041b9777a3f0d6c045d0bd0f9c0c926a9250a7155c4e6316b15c9dd1a391b1899766a14b0062784f17fde786d6c8e0f
|
7
|
+
data.tar.gz: fada6ea8f7e9822bf7a37288cf91475bf9c6b1c585d306d330499a515138b46754ee5675c14c23fb1b5aa250eb0a5b2529eaa9003e5a23ce1373e89f60811c06
|
data/lib/devu/version.rb
CHANGED
data/lib/devu.sh
ADDED
@@ -0,0 +1,700 @@
|
|
1
|
+
#!/usr/bin/env bash
|
2
|
+
|
3
|
+
#=======================================================================
|
4
|
+
# Developer Utilities (DEVU)
|
5
|
+
# Convenient functions for developers and utility.
|
6
|
+
#
|
7
|
+
# INSTALLATION
|
8
|
+
# - Copy this file to some directory (recommended: ~/devu.sh)
|
9
|
+
# - Source this file in your shell profile (e.g. ~/.bashrc, ~/.zshrc)
|
10
|
+
# `source ~/devu.sh`
|
11
|
+
# - (optional) Create a `.devu` config file in your project directory
|
12
|
+
# to override default values. See config section for keys.
|
13
|
+
# - Run `devu` to see the available commands.
|
14
|
+
#=======================================================================
|
15
|
+
|
16
|
+
# Config (default values)
|
17
|
+
# Add '.devu' file to override these values for a single project.
|
18
|
+
# Add '~/.devu' file to override these values globally.
|
19
|
+
#-----------------------------------------------------------------------
|
20
|
+
|
21
|
+
BRANCH_DESCRIPTION_WORD_SEPARATOR="-"
|
22
|
+
BRANCH_ISSUE_ID_SEPARATOR="/"
|
23
|
+
COMMITS_REQUIRE_ISSUE_KEY=false
|
24
|
+
ISSUE_ID_REGEX="[0-9]+"
|
25
|
+
PROJECT_KEY="DEVU"
|
26
|
+
PROTECTED_BRANCHES=(main master development)
|
27
|
+
|
28
|
+
# DEVU functions
|
29
|
+
#-----------------------------------------------------------------------
|
30
|
+
|
31
|
+
function devu() {
|
32
|
+
util.echo
|
33
|
+
util.echo "$(devu.version)"
|
34
|
+
util.echo
|
35
|
+
util.echo "Shell functions useful for developers."
|
36
|
+
util.echo
|
37
|
+
util.echo "Run <command> without args to see the usage (if applicable)."
|
38
|
+
util.echo "Use 'which <command>' to see the implementation."
|
39
|
+
util.echo
|
40
|
+
util.echo "HELP" "${RED}"
|
41
|
+
util.echo " devu | devu.help # Show this help message"
|
42
|
+
util.echo " devu.config # Show the configuration"
|
43
|
+
util.echo " devu.version # Show the DEVU version"
|
44
|
+
util.echo
|
45
|
+
util.echo "COMMANDS (alias)" "${RED}"
|
46
|
+
util.echo " branch.create <branch> # Create a new branch"
|
47
|
+
util.echo " branch.current # Show the current branch"
|
48
|
+
util.echo " branch.delete <branch> (dlb) # Delete a local branch"
|
49
|
+
util.echo " branch.default # Show the default branch"
|
50
|
+
util.echo " branches (b) # Show local branches"
|
51
|
+
util.echo " commits [<number>] (glo) # Show commits (defaults to all)"
|
52
|
+
util.echo " checkout <branch> (co) # Checkout a branch"
|
53
|
+
util.echo " checkout.file <file> (cf) # Checkout a single file from the default branch"
|
54
|
+
util.echo " checkout.issue <issue_id> (ci) # Checkout a branch prefixed with the issue ID"
|
55
|
+
util.echo " commit <message> # Commit changes and push to remote"
|
56
|
+
util.echo " force-push # Force push changes to remote (with lease)"
|
57
|
+
util.echo " gd # Git diff"
|
58
|
+
util.echo " gl [<number>] # Git log (defaults to all)"
|
59
|
+
util.echo " gp # Git pull latest changes"
|
60
|
+
util.echo " gs # Git status"
|
61
|
+
util.echo " issue <issue_id> <branch> # Create a branch for the given issue ID"
|
62
|
+
util.echo " ll # List files in long format"
|
63
|
+
util.echo " log.cleanup # Remove '/log/*.log' files"
|
64
|
+
util.echo " main-pull (mp) # Switch to default branch and pull changes"
|
65
|
+
util.echo " pull-request (pr) # Display the URL to create a pre-filled pull request"
|
66
|
+
util.echo " sha # Show the SHA of the current commit"
|
67
|
+
util.echo " uncommit [<number=1>] # Soft uncommit/undo last number of commits"
|
68
|
+
util.echo
|
69
|
+
util.echo "SUPPORT NAMESPACES (TAB-complete to see list)" "${RED}"
|
70
|
+
util.echo " array.* # Array functions"
|
71
|
+
util.echo " file.* # File functions"
|
72
|
+
util.echo " git.* # Git functions"
|
73
|
+
util.echo " is.* # Boolean test functions"
|
74
|
+
util.echo " util.* # Utility functions"
|
75
|
+
util.echo
|
76
|
+
}
|
77
|
+
|
78
|
+
function devu.help() {
|
79
|
+
devu
|
80
|
+
}
|
81
|
+
|
82
|
+
function devu.config() {
|
83
|
+
file.exists $(devu.config_file) && source $(devu.config_file)
|
84
|
+
|
85
|
+
if file.exists $(devu.config_file); then
|
86
|
+
util.echo "Config file: $(devu.config_file)"
|
87
|
+
else
|
88
|
+
util.echo "No .devu config file, using defaults."
|
89
|
+
fi
|
90
|
+
util.echo "----"
|
91
|
+
util.echo "BRANCH_DESCRIPTION_WORD_SEPARATOR=${BRANCH_DESCRIPTION_WORD_SEPARATOR}"
|
92
|
+
util.echo "BRANCH_ISSUE_ID_SEPARATOR=${BRANCH_ISSUE_ID_SEPARATOR}"
|
93
|
+
util.echo "COMMITS_REQUIRE_ISSUE_KEY=${COMMITS_REQUIRE_ISSUE_KEY}"
|
94
|
+
util.echo "ISSUE_ID_REGEX=${ISSUE_ID_REGEX}"
|
95
|
+
util.echo "PROJECT_KEY=${PROJECT_KEY}"
|
96
|
+
util.echo "PROTECTED_BRANCHES=(${PROTECTED_BRANCHES})"
|
97
|
+
}
|
98
|
+
|
99
|
+
# Used to override default values for a project.
|
100
|
+
# Falls back to global config if no project config is found.
|
101
|
+
function devu.config_file() {
|
102
|
+
if file.exists .devu; then
|
103
|
+
echo .devu
|
104
|
+
elif file.exists ~/.devu; then
|
105
|
+
echo $HOME/.devu
|
106
|
+
fi
|
107
|
+
}
|
108
|
+
|
109
|
+
function devu.version() {
|
110
|
+
echo "DEVU Developer Utilities 1.1.0 (2024-05-18)"
|
111
|
+
}
|
112
|
+
|
113
|
+
# DEVU functions
|
114
|
+
# Commonly used functions for development
|
115
|
+
#-----------------------------------------------------------------------
|
116
|
+
|
117
|
+
# Create a new branch. The branch name can include spaces.
|
118
|
+
function branch.create() {
|
119
|
+
if is.blank "${1}"; then
|
120
|
+
util.echo
|
121
|
+
util.echo "Create a new branch."
|
122
|
+
util.echo
|
123
|
+
util.echo "USAGE (spaces allowed in name)" "${RED}"
|
124
|
+
util.echo " branch.create <branch>"
|
125
|
+
util.echo
|
126
|
+
util.echo "EXAMPLES" "${RED}"
|
127
|
+
util.echo " branch.create feature/branch_name"
|
128
|
+
util.echo " branch.create 123-branch_name"
|
129
|
+
util.echo " branch.create new branch name"
|
130
|
+
util.echo
|
131
|
+
return
|
132
|
+
fi
|
133
|
+
|
134
|
+
# $@ is an array of args, $* is a single string of combined args. Need array.
|
135
|
+
local branch_name=$(array.join "${BRANCH_DESCRIPTION_WORD_SEPARATOR}" ${@})
|
136
|
+
|
137
|
+
util.echo.execute "git checkout -b ${branch_name}"
|
138
|
+
}
|
139
|
+
|
140
|
+
function branch.delete() {
|
141
|
+
if is.blank "${1}"; then
|
142
|
+
util.echo
|
143
|
+
util.echo "Delete a local branch."
|
144
|
+
util.echo
|
145
|
+
util.echo "Cannot deleted protected branches:"
|
146
|
+
array.to.bullet-list ${PROTECTED_BRANCHES}
|
147
|
+
util.echo
|
148
|
+
util.echo "USAGE" "${RED}"
|
149
|
+
util.echo " branch.delete <branch>"
|
150
|
+
util.echo
|
151
|
+
util.echo "EXAMPLES" "${RED}"
|
152
|
+
util.echo " branch.delete feature/branch_name"
|
153
|
+
util.echo " branch.delete 123-branch_name"
|
154
|
+
util.echo
|
155
|
+
return
|
156
|
+
fi
|
157
|
+
|
158
|
+
local branch="${1}"
|
159
|
+
|
160
|
+
if array.includes "$branch" ${PROTECTED_BRANCHES}; then
|
161
|
+
util.echo "Cannot delete protected branch '$branch'" "${RED}"
|
162
|
+
return
|
163
|
+
fi
|
164
|
+
|
165
|
+
util.echo "Deleting local branch only..." "${YELLOW}"
|
166
|
+
# -D (uppercase D) forces deletion even if branch is not merged
|
167
|
+
util.echo.execute "git branch -D ${branch}"
|
168
|
+
}
|
169
|
+
|
170
|
+
# "dlb" => "delete local branch"
|
171
|
+
function dlb() {
|
172
|
+
branch.delete "${*}"
|
173
|
+
}
|
174
|
+
|
175
|
+
function branches() {
|
176
|
+
util.echo.execute "git branch"
|
177
|
+
}
|
178
|
+
|
179
|
+
function b() {
|
180
|
+
branches
|
181
|
+
}
|
182
|
+
|
183
|
+
# Checkout a branch.
|
184
|
+
function checkout() {
|
185
|
+
local branch="$1"
|
186
|
+
|
187
|
+
if is.blank "${branch}"; then
|
188
|
+
util.echo
|
189
|
+
util.echo "Checkout a branch."
|
190
|
+
util.echo
|
191
|
+
util.echo "USAGE" "${RED}"
|
192
|
+
util.echo " checkout <branch>"
|
193
|
+
util.echo
|
194
|
+
util.echo "EXAMPLES" "${RED}"
|
195
|
+
util.echo " checkout main"
|
196
|
+
util.echo " checkout 123-branch_name"
|
197
|
+
util.echo " checkout 456/another_branch_name"
|
198
|
+
util.echo
|
199
|
+
util.echo "ALIASES" "${RED}"
|
200
|
+
util.echo " co"
|
201
|
+
util.echo
|
202
|
+
return
|
203
|
+
fi
|
204
|
+
|
205
|
+
util.echo.execute "git checkout ${branch}"
|
206
|
+
}
|
207
|
+
|
208
|
+
function co() {
|
209
|
+
checkout "${*}"
|
210
|
+
}
|
211
|
+
|
212
|
+
# Checkout a single file from the main/default branch.
|
213
|
+
function checkout.file() {
|
214
|
+
local file="${1}"
|
215
|
+
|
216
|
+
if is.blank "${file}"; then
|
217
|
+
util.echo
|
218
|
+
util.echo "Checkout a single file from the default branch."
|
219
|
+
util.echo
|
220
|
+
util.echo "USAGE" "${RED}"
|
221
|
+
util.echo " checkout.file <file>"
|
222
|
+
util.echo
|
223
|
+
util.echo "EXAMPLES" "${RED}"
|
224
|
+
util.echo " checkout.file README.md"
|
225
|
+
util.echo
|
226
|
+
return
|
227
|
+
fi
|
228
|
+
|
229
|
+
util.echo.execute "git restore --source $(git.branch.default) ${file}"
|
230
|
+
}
|
231
|
+
|
232
|
+
function cf() {
|
233
|
+
checkout.file "${*}"
|
234
|
+
}
|
235
|
+
|
236
|
+
# Checkout a branch that is prefixed with the issue ID.
|
237
|
+
# e.g. `checkout.issue 1234` will checkout the branch `1234-branch_name`
|
238
|
+
function checkout.issue() {
|
239
|
+
file.exists $(devu.config_file) && source $(devu.config_file)
|
240
|
+
|
241
|
+
local issue_id="$1"
|
242
|
+
|
243
|
+
if is.blank "${issue_id}"; then
|
244
|
+
util.echo
|
245
|
+
util.echo "Checkout branch prefixed with the issue ID."
|
246
|
+
util.echo
|
247
|
+
util.echo "If there are more than one branch with the"
|
248
|
+
util.echo "same issue ID, you will be asked to clarify"
|
249
|
+
util.echo "which branch you want to checkout."
|
250
|
+
util.echo
|
251
|
+
util.echo "USAGE" "${RED}"
|
252
|
+
util.echo " checkout.issue <issue_id>"
|
253
|
+
util.echo
|
254
|
+
util.echo "EXAMPLES" "${RED}"
|
255
|
+
util.echo " checkout.issue 1234"
|
256
|
+
util.echo
|
257
|
+
util.echo "ALIASES" "${RED}"
|
258
|
+
util.echo " ci"
|
259
|
+
util.echo
|
260
|
+
return
|
261
|
+
fi
|
262
|
+
|
263
|
+
local issue_id="$1"
|
264
|
+
local matched_branches_count=$(git branch | grep -c "${issue_id}${BRANCH_ISSUE_ID_SEPARATOR}")
|
265
|
+
|
266
|
+
if [[ $matched_branches_count -eq 0 ]]; then
|
267
|
+
util.echo "No local branches found for issue ID: $issue_id" "${RED}"
|
268
|
+
elif [[ $matched_branches_count -eq 1 ]]; then
|
269
|
+
checkout $(git for-each-ref --format='%(refname:short)' refs/heads/ | grep "${issue_id}${BRANCH_ISSUE_ID_SEPARATOR}")
|
270
|
+
else
|
271
|
+
local matched_branches=($(git for-each-ref --format='%(refname:short)' refs/heads/ | grep "${issue_id}${BRANCH_ISSUE_ID_SEPARATOR}"))
|
272
|
+
|
273
|
+
local i=1
|
274
|
+
for branch in $matched_branches; do
|
275
|
+
util.echo "[$i] $branch"
|
276
|
+
i=$((i + 1))
|
277
|
+
done
|
278
|
+
|
279
|
+
local branch_number
|
280
|
+
# ZSH shell has its own way of reading input
|
281
|
+
if [[ -n "$ZSH_VERSION" ]]; then
|
282
|
+
read branch_number\?"Enter [number] to checkout: "
|
283
|
+
else # Normal bash/shell
|
284
|
+
read -p "Enter [number] to checkout: " branch_number
|
285
|
+
fi
|
286
|
+
|
287
|
+
if [[ $branch_number -gt 0 && $branch_number -le $matched_branches_count ]]; then
|
288
|
+
checkout $(git for-each-ref --format='%(refname:short)' refs/heads/ | grep -m ${branch_number} ${issue_id}${BRANCH_ISSUE_ID_SEPARATOR} | tail -n 1)
|
289
|
+
else
|
290
|
+
util.echo "Invalid number." "${RED}"
|
291
|
+
fi
|
292
|
+
fi
|
293
|
+
}
|
294
|
+
|
295
|
+
function ci() {
|
296
|
+
checkout.issue "${*}"
|
297
|
+
}
|
298
|
+
|
299
|
+
function commit() {
|
300
|
+
file.exists $(devu.config_file) && source $(devu.config_file)
|
301
|
+
|
302
|
+
if [[ $# -eq 0 ]]; then
|
303
|
+
util.echo
|
304
|
+
util.echo "Commit changes and push to remote."
|
305
|
+
util.echo
|
306
|
+
util.echo "Quotes are optional unless the <message> contains"
|
307
|
+
util.echo "quote or special characters."
|
308
|
+
util.echo
|
309
|
+
util.echo "USAGE" "${RED}"
|
310
|
+
util.echo " commit <message>"
|
311
|
+
util.echo
|
312
|
+
util.echo "EXAMPLES" "${RED}"
|
313
|
+
util.echo " commit Fix issue #1234"
|
314
|
+
util.echo " commit \"Fix issue #1234\""
|
315
|
+
util.echo
|
316
|
+
return
|
317
|
+
fi
|
318
|
+
|
319
|
+
local message="$*"
|
320
|
+
|
321
|
+
# In case the default value isn't there, set it to false.
|
322
|
+
local require_issue_key_prefix="false"
|
323
|
+
if [[ -v COMMITS_REQUIRE_ISSUE_KEY ]]; then
|
324
|
+
require_issue_key_prefix=$COMMITS_REQUIRE_ISSUE_KEY
|
325
|
+
fi
|
326
|
+
|
327
|
+
if is.true $require_issue_key_prefix; then
|
328
|
+
if [[ ! ("$message" =~ "^${PROJECT_KEY}-${ISSUE_ID_REGEX}.*") ]]; then
|
329
|
+
util.echo "Prepending issue key to commit message." $YELLOW
|
330
|
+
local issue_id=$(util.extract_issue_id_from_branch_name)
|
331
|
+
local issue_key="${PROJECT_KEY}-${issue_id}"
|
332
|
+
message="${issue_key} - ${message}"
|
333
|
+
fi
|
334
|
+
else
|
335
|
+
util.echo "Commits do not require issue key." $YELLOW
|
336
|
+
fi
|
337
|
+
|
338
|
+
util.echo.execute "git add ."
|
339
|
+
util.echo.execute "git commit -m \"${message}\""
|
340
|
+
util.echo.execute "git push --set-upstream origin $(git.branch.current)"
|
341
|
+
}
|
342
|
+
|
343
|
+
function commits() {
|
344
|
+
local number_of_commits="${1}"
|
345
|
+
|
346
|
+
if is.blank "${number_of_commits}"; then
|
347
|
+
util.echo.execute "git log --oneline"
|
348
|
+
else
|
349
|
+
util.echo.execute "git log --oneline -n ${number_of_commits}"
|
350
|
+
fi
|
351
|
+
}
|
352
|
+
|
353
|
+
function gl() {
|
354
|
+
local number_of_commits="${1}"
|
355
|
+
|
356
|
+
if is.blank "${number_of_commits}"; then
|
357
|
+
util.echo.execute "git log"
|
358
|
+
else
|
359
|
+
util.echo.execute "git log -n ${number_of_commits}"
|
360
|
+
fi
|
361
|
+
}
|
362
|
+
|
363
|
+
function glo() {
|
364
|
+
commits "${*}"
|
365
|
+
}
|
366
|
+
|
367
|
+
function force-push() {
|
368
|
+
util.echo.execute "git push --force-with-lease origin $(git.branch.current)"
|
369
|
+
}
|
370
|
+
|
371
|
+
function gd() {
|
372
|
+
util.echo.execute "git diff"
|
373
|
+
}
|
374
|
+
|
375
|
+
function gp() {
|
376
|
+
util.echo.execute "git pull"
|
377
|
+
}
|
378
|
+
|
379
|
+
function gs() {
|
380
|
+
util.echo.execute "git status"
|
381
|
+
}
|
382
|
+
|
383
|
+
# Create a branch for the given issue ID. Putting the issue ID in the
|
384
|
+
# branch name makes it easier to track the issue associated with the
|
385
|
+
# branch.
|
386
|
+
function issue() {
|
387
|
+
file.exists $(devu.config_file) && source $(devu.config_file)
|
388
|
+
|
389
|
+
if [[ $# -lt 2 ]]; then
|
390
|
+
util.echo
|
391
|
+
util.echo "Create a branch for the issue ID."
|
392
|
+
util.echo
|
393
|
+
util.echo "USAGE" "${RED}"
|
394
|
+
util.echo " issue <issue_id> <branch>"
|
395
|
+
util.echo
|
396
|
+
util.echo "ARGUMENTS" "${RED}"
|
397
|
+
util.echo " <issue_id> # Must follow format: ${ISSUE_ID_REGEX}"
|
398
|
+
util.echo " <branch> # May include spaces between words"
|
399
|
+
util.echo
|
400
|
+
util.echo "EXAMPLES" "${RED}"
|
401
|
+
util.echo " issue 1234 branch_name"
|
402
|
+
util.echo " issue 1234 branch name"
|
403
|
+
util.echo
|
404
|
+
return
|
405
|
+
fi
|
406
|
+
|
407
|
+
local issue_id="$1"; shift
|
408
|
+
# $@ is an array of args, $* is a single string of combined args. Need array.
|
409
|
+
local branch_name=$(array.join "${BRANCH_DESCRIPTION_WORD_SEPARATOR}" ${@})
|
410
|
+
|
411
|
+
if [[ ! "${issue_id}" =~ "${ISSUE_ID_REGEX}" ]]; then
|
412
|
+
util.echo "<issue_id> must follow format: ${ISSUE_ID_REGEX}" "${RED}"
|
413
|
+
return
|
414
|
+
fi
|
415
|
+
|
416
|
+
branch.create "${issue_id}${BRANCH_ISSUE_ID_SEPARATOR}${branch_name}"
|
417
|
+
}
|
418
|
+
|
419
|
+
function ll() {
|
420
|
+
util.echo.execute "ls -al"
|
421
|
+
}
|
422
|
+
|
423
|
+
function log.cleanup() {
|
424
|
+
if is.a-directory "log"; then
|
425
|
+
util.echo.execute "rm log/*.log*"
|
426
|
+
else
|
427
|
+
util.echo "No logs directory found at /log" "${RED}"
|
428
|
+
fi
|
429
|
+
}
|
430
|
+
|
431
|
+
function main-pull() {
|
432
|
+
checkout "$(git.branch.default)"
|
433
|
+
gp
|
434
|
+
}
|
435
|
+
|
436
|
+
function mp() {
|
437
|
+
main-pull "${*}"
|
438
|
+
}
|
439
|
+
|
440
|
+
# Display the PR URL to create a pull request that can be copied/pasted.
|
441
|
+
# Pre-fills the TITLE and DESCRIPTION for the PR.
|
442
|
+
function pull-request() {
|
443
|
+
local to_branch="$(git.branch.default)"
|
444
|
+
|
445
|
+
if is.present "${1}"; then
|
446
|
+
to_branch="${1}"
|
447
|
+
fi
|
448
|
+
|
449
|
+
if [[ "${to_branch}" == "$(git.branch.current)" ]]; then
|
450
|
+
util.echo "Cannot create a PR to the same branch." "${RED}"
|
451
|
+
return
|
452
|
+
fi
|
453
|
+
|
454
|
+
util.echo "From: $(git.branch.current)"
|
455
|
+
util.echo "To: ${to_branch}"
|
456
|
+
|
457
|
+
local url="$(git.pr_url)/${to_branch}...$(git.branch.current)?expand=1&title=$(git.branch.current)"
|
458
|
+
open "${url}"
|
459
|
+
}
|
460
|
+
|
461
|
+
function pr() {
|
462
|
+
pull-request "${*}"
|
463
|
+
}
|
464
|
+
|
465
|
+
# Show first 7 characters of sha by default, or full sha if argument provided.
|
466
|
+
function sha() {
|
467
|
+
local full="${1}"
|
468
|
+
|
469
|
+
if [[ "${full}" == "full" ]]; then
|
470
|
+
util.echo.execute "git rev-parse HEAD"
|
471
|
+
else
|
472
|
+
util.echo.execute "git rev-parse --short=7 HEAD"
|
473
|
+
fi
|
474
|
+
}
|
475
|
+
|
476
|
+
function uncommit() {
|
477
|
+
local number="$1"
|
478
|
+
|
479
|
+
if is.blank "$number"; then
|
480
|
+
number=1
|
481
|
+
fi
|
482
|
+
|
483
|
+
is.numeric "${number}" || {
|
484
|
+
util.echo "Argument must be a number." "${RED}"
|
485
|
+
return
|
486
|
+
}
|
487
|
+
|
488
|
+
util.echo.execute "git reset --soft HEAD~${number}"
|
489
|
+
}
|
490
|
+
|
491
|
+
# Utility functions
|
492
|
+
#-----------------------------------------------------------------------
|
493
|
+
|
494
|
+
GREEN=32; RED=31; BLUE=34; YELLOW=33;
|
495
|
+
function util.echo() {
|
496
|
+
echo -e "\033[0;$2m$1\033[0m"
|
497
|
+
}
|
498
|
+
|
499
|
+
# Show the command and the execute it. Not as useful as it sounds,
|
500
|
+
# because you can do 'which <command>' to see a command's implementation.
|
501
|
+
function util.echo.execute() {
|
502
|
+
util.echo "=> ${@}" "${YELLOW}"
|
503
|
+
eval "${@}"
|
504
|
+
}
|
505
|
+
|
506
|
+
# 123-branch_name => 123
|
507
|
+
function util.extract_issue_id_from_branch_name() {
|
508
|
+
echo $(git.branch.current) | grep -oE "^${ISSUE_ID_REGEX}"
|
509
|
+
}
|
510
|
+
|
511
|
+
# 123-branch_name => "branch name"
|
512
|
+
function util.extract_description_from_branch_name() {
|
513
|
+
local issue_id=$(util.extract_issue_id_from_branch_name)
|
514
|
+
echo $(git.branch.current) | sed "s/^${issue_id}-//" | tr "_" " "
|
515
|
+
}
|
516
|
+
|
517
|
+
# Git functions
|
518
|
+
#-----------------------------------------------------------------------
|
519
|
+
|
520
|
+
function git.branch.current() {
|
521
|
+
git branch --show-current
|
522
|
+
}
|
523
|
+
|
524
|
+
# Technically git does not have a "default" branch, but this is the
|
525
|
+
# branch that is typically used as the main branch.
|
526
|
+
function git.branch.default() {
|
527
|
+
local default_branch=$(git symbolic-ref refs/remotes/origin/HEAD | sed 's@^refs/remotes/origin/@@')
|
528
|
+
|
529
|
+
if is.blank "$default_branch"; then
|
530
|
+
util.echo "You do not seem to have a default REMOTE branch." "${RED}"
|
531
|
+
util.echo "Set one with: git remote set-head origin --auto"
|
532
|
+
else
|
533
|
+
echo $default_branch
|
534
|
+
fi
|
535
|
+
}
|
536
|
+
|
537
|
+
function git.config.get() {
|
538
|
+
local location="global"
|
539
|
+
|
540
|
+
if [[ $# -eq 0 ]] && {
|
541
|
+
util.echo
|
542
|
+
util.echo "Get a git configuration value."
|
543
|
+
util.echo
|
544
|
+
util.echo "USAGE" "${RED}"
|
545
|
+
util.echo " git.config.get <location> <key>"
|
546
|
+
util.echo " git.config.get --list"
|
547
|
+
util.echo
|
548
|
+
util.echo "ARGUMENTS" "${RED}"
|
549
|
+
util.echo " <location> # global (default), local"
|
550
|
+
util.echo " <key> # e.g. user.name, user.email"
|
551
|
+
util.echo
|
552
|
+
util.echo "EXAMPLES" "${RED}"
|
553
|
+
util.echo " git.config.get global user.name"
|
554
|
+
util.echo " git.config.get user.name # default to global"
|
555
|
+
util.echo
|
556
|
+
return
|
557
|
+
}
|
558
|
+
|
559
|
+
# Overwrite default location if provided
|
560
|
+
if [[ "$1" == "global" || "$1" == "local" ]]; then
|
561
|
+
location="$1"
|
562
|
+
shift
|
563
|
+
fi
|
564
|
+
|
565
|
+
local key="$1"
|
566
|
+
|
567
|
+
util.echo.execute "git config --${location} ${key}"
|
568
|
+
}
|
569
|
+
|
570
|
+
# Is the current directory a valid git repo?
|
571
|
+
function git.is-valid-repo() {
|
572
|
+
if git rev-parse --git-dir > /dev/null 2>&1; then
|
573
|
+
return 0 # success
|
574
|
+
else
|
575
|
+
util.echo "Not in a git directory." "${RED}"
|
576
|
+
return 1 # failure
|
577
|
+
fi
|
578
|
+
}
|
579
|
+
|
580
|
+
# GitHub URL to create a pull request.
|
581
|
+
function git.pr_url() {
|
582
|
+
echo "https://$(git.repo.host)/$(git.repo.owner)/$(git.repo.name)/compare"
|
583
|
+
}
|
584
|
+
|
585
|
+
# `git@<host>:<owner>/<repo>.git` => <host>
|
586
|
+
function git.repo.host() {
|
587
|
+
echo $(git.repo.url) | cut -d '@' -f2 | cut -d ':' -f1
|
588
|
+
}
|
589
|
+
|
590
|
+
# `git@<host>:<owner>/<repo>.git` => <repo>
|
591
|
+
function git.repo.name() {
|
592
|
+
echo $(git.repo.url) | cut -d '/' -f 2 | cut -d '.' -f 1
|
593
|
+
}
|
594
|
+
|
595
|
+
# `git@<host>:<owner>/<repo>.git` => <owner>
|
596
|
+
function git.repo.owner() {
|
597
|
+
echo $(git.repo.url) | cut -d '@' -f2 | cut -d ':' -f2 | cut -d '/' -f1
|
598
|
+
}
|
599
|
+
|
600
|
+
# Absolute URL of git repo `git@<host>:<owner>/<repo>.git`
|
601
|
+
function git.repo.url() {
|
602
|
+
# git config --get remote.origin.url
|
603
|
+
git ls-remote --get-url
|
604
|
+
}
|
605
|
+
|
606
|
+
# File functions
|
607
|
+
#-----------------------------------------------------------------------
|
608
|
+
|
609
|
+
function file.exists() {
|
610
|
+
[[ -f "$1" ]]
|
611
|
+
}
|
612
|
+
|
613
|
+
# IS boolean test functions
|
614
|
+
#-----------------------------------------------------------------------
|
615
|
+
|
616
|
+
function is.a-directory() {
|
617
|
+
[[ -d "${1}" ]]
|
618
|
+
}
|
619
|
+
|
620
|
+
function is.blank() {
|
621
|
+
[[ -z "${1}" ]]
|
622
|
+
}
|
623
|
+
|
624
|
+
# Check if variable is set. Do not pass in the "value" of the
|
625
|
+
# variable as $1, just the variable name.
|
626
|
+
function is.defined() {
|
627
|
+
[[ -v $1 ]]
|
628
|
+
}
|
629
|
+
|
630
|
+
# Check if a string is a number, including negatives, floats, and integers.
|
631
|
+
function is.numeric() {
|
632
|
+
[[ $1 =~ ^[+-]?([0-9]+([.][0-9]*)?|\.[0-9]+)$ ]]
|
633
|
+
}
|
634
|
+
|
635
|
+
function is.present() {
|
636
|
+
[[ -n "${1}" ]]
|
637
|
+
}
|
638
|
+
|
639
|
+
# Any of these values are considered true.
|
640
|
+
function is.true() {
|
641
|
+
array.includes "$1" true "true" "TRUE" "yes" "YES" "y" "Y" "1"
|
642
|
+
}
|
643
|
+
|
644
|
+
# Array functions
|
645
|
+
#-----------------------------------------------------------------------
|
646
|
+
|
647
|
+
# Does not print anything, just returns 0 if includes, 1 if not.
|
648
|
+
function array.includes() {
|
649
|
+
local search="$1";
|
650
|
+
is.blank "$search" && return 1
|
651
|
+
shift
|
652
|
+
|
653
|
+
[[ "$*" =~ "${search}" ]] || return 1
|
654
|
+
|
655
|
+
for e in "${@}"; do
|
656
|
+
[[ "$e" == "${search}" ]] && {
|
657
|
+
return 0
|
658
|
+
}
|
659
|
+
done
|
660
|
+
|
661
|
+
return 1
|
662
|
+
}
|
663
|
+
|
664
|
+
# Combine $2* elements with $1 separator between each item.
|
665
|
+
function array.join() {
|
666
|
+
local delimiter="$1"; shift
|
667
|
+
echo -n "$1"; shift
|
668
|
+
# ZSH prints out ending "%" if no endline
|
669
|
+
printf "%s" "${@/#/$delimiter}"; echo
|
670
|
+
}
|
671
|
+
|
672
|
+
# Print array of $2* items one per line with $1 prefix.
|
673
|
+
function array.print-per-line() {
|
674
|
+
if [[ $# -lt 2 ]]; then
|
675
|
+
util.echo
|
676
|
+
util.echo "Print array of items one per line with a prefix."
|
677
|
+
util.echo
|
678
|
+
util.echo "USAGE" "${RED}"
|
679
|
+
util.echo " array.print-per-line <prefix> <item1> <item2> ..."
|
680
|
+
util.echo
|
681
|
+
util.echo "EXAMPLES" "${RED}"
|
682
|
+
util.echo " array.print-per-line '- ' item1 item2 item3"
|
683
|
+
util.echo
|
684
|
+
return
|
685
|
+
fi
|
686
|
+
|
687
|
+
local prefix="$1"; shift
|
688
|
+
|
689
|
+
for item in "${@}"; do
|
690
|
+
printf "%s%s\n" "$prefix" "$item"
|
691
|
+
done
|
692
|
+
}
|
693
|
+
|
694
|
+
function array.to.csv() {
|
695
|
+
array.join ", " $*
|
696
|
+
}
|
697
|
+
|
698
|
+
function array.to.bullet-list() {
|
699
|
+
array.print-per-line "- " $*
|
700
|
+
}
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: devu
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Dan LeGrand
|
@@ -40,6 +40,7 @@ files:
|
|
40
40
|
- Rakefile
|
41
41
|
- devu.gemspec
|
42
42
|
- lib/devu.rb
|
43
|
+
- lib/devu.sh
|
43
44
|
- lib/devu/version.rb
|
44
45
|
- sig/devu.rbs
|
45
46
|
homepage: https://github.com/dlegr250/devu
|