devu 1.1.0 → 1.3.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 +4 -4
- data/README.md +2 -2
- data/lib/devu/version.rb +1 -1
- data/lib/devu.sh +700 -0
- metadata +3 -3
- data/devu-1.0.0.gem +0 -0
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/README.md
CHANGED
@@ -4,13 +4,13 @@ DEVU Developer Utilities - useful shell functions.
|
|
4
4
|
|
5
5
|
## Installation
|
6
6
|
|
7
|
-
This `1.0.0` release just includes a collection of shell functions defined in `
|
7
|
+
This `1.0.0` release just includes a collection of shell functions defined in `lib/devu.sh`
|
8
8
|
|
9
9
|
Later version will create a more robust gem with executables and the power of Ruby, but for now it is just a shell script.
|
10
10
|
|
11
11
|
```
|
12
12
|
gem install devu
|
13
|
-
cp <install_dir>/
|
13
|
+
cp <install_dir>/lib/devu.sh ~/devu.sh
|
14
14
|
|
15
15
|
# In .bashrc, .zshrc, etc...
|
16
16
|
source ~/devu.sh
|
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,14 +1,14 @@
|
|
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
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-05-
|
11
|
+
date: 2024-05-28 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: zeitwerk
|
@@ -38,9 +38,9 @@ files:
|
|
38
38
|
- LICENSE.txt
|
39
39
|
- README.md
|
40
40
|
- Rakefile
|
41
|
-
- devu-1.0.0.gem
|
42
41
|
- devu.gemspec
|
43
42
|
- lib/devu.rb
|
43
|
+
- lib/devu.sh
|
44
44
|
- lib/devu/version.rb
|
45
45
|
- sig/devu.rbs
|
46
46
|
homepage: https://github.com/dlegr250/devu
|
data/devu-1.0.0.gem
DELETED
Binary file
|