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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 35af7e7109ca3ae8a388f075ab5a2de3f66f691372bed9b0f7102b70d8e24e40
4
- data.tar.gz: 6fc1d4e6d77ccec69d4c5011a82f63acc6866a222e30d84f3e7643f247948f1d
3
+ metadata.gz: b0d277a4062da520c86ad08694a749ea3c2d2cde4039de4c6d531295b007472d
4
+ data.tar.gz: 371bf4f1a908a3a361679d18d8f85288c72e35b087502fa96cb115829a15c305
5
5
  SHA512:
6
- metadata.gz: e824797477d74b5ed462f7e193c7d31abc63892d0a334e6696420ab36acd1720faa3d3616557b70558a8a1e2773c5602d21b2f9eb7ea51eeb6445c43b08a4e4e
7
- data.tar.gz: bbefe5fe254cdf81da4895c1be7de01a28c9fe02f4a1a0e8b8273f47f1b6e3b75404141224f21af8895259b1162ade1b5986d050e88a598f925bfb0c7d85c493
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 `bin/devu.sh`
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>/bin/devu.sh ~/devu.sh
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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Devu
4
- VERSION = "1.1.0"
4
+ VERSION = "1.3.0"
5
5
  end
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.1.0
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-18 00:00:00.000000000 Z
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