devu 1.2.0 → 1.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (4) hide show
  1. checksums.yaml +4 -4
  2. data/lib/devu/version.rb +1 -1
  3. data/lib/devu.sh +700 -0
  4. metadata +2 -1
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d95cc13d312ff76346aa65c5887aa943a800277c3b8a150ba981efbb2354a8ba
4
- data.tar.gz: 206b24b17175605d4561a383d297c64f89b5a7672c07298506f7c9dae07aa8aa
3
+ metadata.gz: b0d277a4062da520c86ad08694a749ea3c2d2cde4039de4c6d531295b007472d
4
+ data.tar.gz: 371bf4f1a908a3a361679d18d8f85288c72e35b087502fa96cb115829a15c305
5
5
  SHA512:
6
- metadata.gz: 01ce4f675e753af55b060ad18ef358a3c2516ef250bcf4429650424a2d73c8477ca79c2325edadfbf92705275acf013bd3ae3243bc3aef70cac0c0a0563bd402
7
- data.tar.gz: 4c9b85e554dcbec3292b707d1ba8f6d079e211a7d7364ccf6e88712e42d9935f54af80dcd6d2312e2e69fbc447a1d1a4f960d0bc92205791d50ecdf663e4b14b
6
+ metadata.gz: 818b3f05cf91e7c6ab30fd7d2f88cf435041b9777a3f0d6c045d0bd0f9c0c926a9250a7155c4e6316b15c9dd1a391b1899766a14b0062784f17fde786d6c8e0f
7
+ data.tar.gz: fada6ea8f7e9822bf7a37288cf91475bf9c6b1c585d306d330499a515138b46754ee5675c14c23fb1b5aa250eb0a5b2529eaa9003e5a23ce1373e89f60811c06
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.2.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,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: devu
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.0
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