blob: 51959f6e7cae7bc61856470a40c76aeb782c435b [file] [log] [blame]
Joey Armstrong3134bfd2024-02-10 20:51:25 -05001#!/bin/bash
Joey Armstrongcc24b3c2024-03-22 11:12:23 -04002# -----------------------------------------------------------------------
3# Copyright 2023-2024 Open Networking Foundation Contributors
4#
5# Licensed under the Apache License, Version 2.0 (the "License");
6# you may not use this file except in compliance with the License.
7# You may obtain a copy of the License at
8#
9# http:#www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS,
13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14# See the License for the specific language governing permissions and
15# limitations under the License.
16# -----------------------------------------------------------------------
17# SPDX-FileCopyrightText: 2023-2024 Open Networking Foundation Contributors
18# SPDX-License-Identifier: Apache-2.0
Joey Armstrong3134bfd2024-02-10 20:51:25 -050019## --------------------------------------------------------------------
20## Intent: Construct a jira ticket query with attributes
21## --------------------------------------------------------------------
22
Joey Armstrong76f861a2024-03-13 16:01:24 -040023{ # loader
24 declare pgm=''
25 pgm="$(realpath --canonicalize-existing "$0")"
26
Joey Armstrongcc24b3c2024-03-22 11:12:23 -040027 # stack-trace-on-error
28 # interrupt handler
29 # mkdir with auto-cleanup at exit
Joey Armstrong76f861a2024-03-13 16:01:24 -040030 declare root=''
31 root="${pgm%%/jira/bin/jira-search.sh}"
32 source "$root/lf/onf-common/common.sh" '--common-args-begin--'
33
34 pgm_lib="${root}/jira/jira-search"
35 readonly pgm_lib
36
37 pgm_bin="${root}/bin"
38 readonly pgm_bin
Joey Armstrongcc24b3c2024-03-22 11:12:23 -040039
40 pgm_help="${root}/jira/jira-search/help"
41 readonly pgm_help
Joey Armstrong76f861a2024-03-13 16:01:24 -040042}
43
Joey Armstrong3134bfd2024-02-10 20:51:25 -050044# set -euo pipefail
45#source ~/.sandbox/trainlab-common/common.sh '--common-args-begin--'
46
47##-------------------##
48##---] GLOBALS [---##
49##-------------------##
50declare -g -a text=()
51declare -g -a text_and=()
52declare -g -a text_or=()
53
54declare -g -a urls_raw=()
55declare -g -a urls_filt=()
56
57declare -g -a labels_incl=()
58declare -g -a labels_excl=()
59
60declare -g -a projects=()
61
62path="$(realpath $0 --canonicalize-existing)"
Joey Armstrong76f861a2024-03-13 16:01:24 -040063# source "${path%\.sh}/utils.sh"
64source "${pgm_lib}/utils.sh"
65#source "$pgmlib/fixversion.sh"
66#source "$pgmlib/resolved.sh"
67source "${pgm_lib}/fixversion.sh"
68source "${pgm_lib}/resolved.sh"
Joey Armstrongcc24b3c2024-03-22 11:12:23 -040069source "${pgm_lib}/help/utils.sh"
Joey Armstrong3134bfd2024-02-10 20:51:25 -050070
71## --------------------------------------------------------------------
72## --------------------------------------------------------------------
73function error()
74{
Joey Armstrongc5542fa2024-03-25 11:49:47 -040075 cat <<ERROR
76
77** -----------------------------------------------------------------------
78** IAM: ${FUNCNAME[1]}
79** ERROR: $@
80** -----------------------------------------------------------------------
81ERROR
82 echo
Joey Armstrong3134bfd2024-02-10 20:51:25 -050083 exit 1
84}
85
86## -----------------------------------------------------------------------
87## -----------------------------------------------------------------------
88function html_encode()
89{
90 local -n ref=$1; shift
91 local tmp="$ref"
92
93 tmp="${tmp//[[:space:]]/%20}"
94 tmp="${tmp//\"/%22}"
95 tmp="${tmp//\'/%27}"
96
97 ref="$tmp"
98 return
99}
100
101## -----------------------------------------------------------------------
102## Intent: Insert a conjunction into the stream when prior statements exist
103## -----------------------------------------------------------------------
104function conjunction()
105{
106 return
Joey Armstrong76f861a2024-03-13 16:01:24 -0400107
Joey Armstrong3134bfd2024-02-10 20:51:25 -0500108 local -n ref=$1; shift
109 [[ $# -gt 0 ]] && { local literal="$1"; shift; }
110
111 ## -------------------------------
112 ## Conjunction if prior statements
113 ## -------------------------------
114 if [ ${#ref[@]} -gt 0 ]; then
115 if [[ -v literal ]]; then
116 ref+=("$literal")
117 elif [[ -v bool_and ]]; then
118 ref+=('AND')
119 else
120 ref+=('OR')
121 fi
122 fi
123
124 return
125}
126
127## -----------------------------------------------------------------------
128## Intent: Helper method
129## -----------------------------------------------------------------------
130## Usage : local path="$(join_by '/' 'lib' "${fields[@]}")"
131## -----------------------------------------------------------------------
132function join_by()
133{
134 local d=${1-} f=${2-}; if shift 2; then printf %s "$f" "${@/#/$d}"; fi;
135}
136
137## --------------------------------------------------------------------
138## Intent: Query by component name filter
139## --------------------------------------------------------------------
140## Value: helm-charts
141## --------------------------------------------------------------------
142function do_components()
143{
144 declare -n args=$1; shift
145 declare -n ans=$1; shift
146
147 # [ -z ${args+word} ] && { args=(); }
Joey Armstrong76f861a2024-03-13 16:01:24 -0400148
Joey Armstrong3134bfd2024-02-10 20:51:25 -0500149 if [[ ${#args[@]} -gt 0 ]]; then
150
151 local modifier
152 if [[ -v bool_not ]]; then
153 modifier='NOT IN'
154 else
155 modifier='IN'
156 fi
157 ans+=("component ${modifier} (${args[@]})")
158 # alt: comp='foo' OR comp='bar'
159 fi
160
161 return
162}
163
164## --------------------------------------------------------------------
165## Intent: Query filter by labels assigned to a ticket:
166## o pods, failing, testing
167## --------------------------------------------------------------------
168# "project in (UKSCR, COMPRG) AND issuetype = Bug AND labels in (BAT)" and
169## --------------------------------------------------------------------
170function do_labels()
171{
172 declare -n incl=$1; shift # was args=
173 declare -n excl=$1; shift
174 declare -n ans=$1; shift
175
176 ## --------------------------------
177 ## Conjunction if stream tokens > 0
178 ## --------------------------------
179 conjunction ans
180
181 declare -a tokens=()
182
183 ## -----------------------------
184 ## -----------------------------
185 if [[ ${#incl[@]} -gt 0 ]]; then
186
187 local modifier
188 if [[ -v bool_not ]]; then
189 modifier='NOT IN'
190 else
191 modifier='IN'
192 fi
193
194 local labels=$(join_by ',' "${incl[@]}")
195 local -a tmp=(\
196 '('\
197 'label IS EMPTY' \
198 'OR' \
199 "labels ${modifier} ($labels)" \
200 ')'\
201 )
202 tokens+=("${tmp[@]}")
203 fi
204
205 conjunction tokens 'AND'
206
207 ## -----------------------------
208 ## -----------------------------
209 if [[ ${#excl[@]} -gt 0 ]]; then
210 local labels=$(join_by ',' "${excl[@]}")
211 tokens+=('(' "labels NOT IN ($labels)" ')')
212 fi
213
214 ans+=("${tokens[@]}")
215 return
216}
217
218## --------------------------------------------------------------------
219## Intent: Modify search query by project type (SEBA, VOL)
220## --------------------------------------------------------------------
221function do_projects()
222{
223 declare -n ref=$1; shift
224
225 [[ ${#projects[@]} -eq 0 ]] && { return; }
226
227 local terms="$(join_by ',' "${projects[@]}")"
228# local -a buffer=('(' 'project' 'IN' "($terms)" ')')
229# ref+=("$(join_by '%20' "${buffer[@]}")")
230 ref+=("(project IN ($terms))")
231 return
232}
233
234## --------------------------------------------------------------------
235## Intent: Query by compound text filters
236## --------------------------------------------------------------------
237function do_text()
238{
239 local -n ref=$1; shift
240 local -n ans=$1; shift
241 local val
242
243 ## Accumulate
244 if [[ ${#ref[@]} -gt 0 ]]; then
245
246 if [[ -v bool_and ]]; then
247 text_and+=("${ref[@]}")
248 else
249 text_or+=("${ref[@]}")
250 fi
251 fi
252
253 ## Append terms: AND
254 if [[ ${#text_and[@]} -gt 0 ]]; then
255 declare -a term=()
256 for val in "${text_and[@]}";
257 do
258 term+=("text ~ \"$val\"")
259 done
260 val=$(join_by ' AND ' "${term[@]}")
261 ans+=("($val)")
262 fi
263
264 ## Append terms: OR
265 if [[ ${#text_or[@]} -gt 0 ]]; then
266 declare -a term=()
267 for val in "${text_or[@]}";
268 do
269 term+=("text ~ \"$val\"")
270 done
271 val=$(join_by ' OR ' "${term[@]}")
272 ans+=("($val)")
273 fi
274
275 return
276}
277
278## --------------------------------------------------------------------
279## Intent: Query by assigned or requestor
280## --------------------------------------------------------------------
281## Note: Simple for now but support query by a list of suers
282## --------------------------------------------------------------------
283function do_user()
284{
285 declare -n ans=$1; shift
286
287 [[ -v argv_nobody ]] && return
288
289 local user='currentUser()'
290 if [[ -v argv_user ]]; then
291 user="$argv_user"
292 fi
293
294 if [[ -v argv_assigned ]]; then
295 ans+=("assignee=${user}")
296 fi
297
298 if [[ -v argv_reported ]]; then
299 ans+=("reporter=${user}")
300 fi
301
302 return
303}
304
305## --------------------------------------------------------------------
306## Intent: Combine filter arguments into a search query
307## --------------------------------------------------------------------
308function gen_filter()
309{
310 declare -n ans=$1; shift
311 declare -n args=$1; shift
312
313 ## -----------------------------------
314 ## Begin by joining major search terms
315 ## -----------------------------------
316 declare -a _tmp=()
317 local val
318 for val in "${args[@]}";
319 do
320 _tmp+=("$val" 'AND')
321 done
Joey Armstrong76f861a2024-03-13 16:01:24 -0400322
323 if [[ ${#_tmp[@]} -gt 0 ]]; then
324 unset _tmp[-1]
325 fi
Joey Armstrong3134bfd2024-02-10 20:51:25 -0500326
327 ## -----------------------
328 ## Massage with html codes
329 ## -----------------------
330 ans="$(join_by '%20' "${_tmp[@]}")"
331 return
332}
333
334## --------------------------------------------------------------------
335## Intent: Combine filter arguments into a search query
336## --------------------------------------------------------------------
337function gen_url()
338{
339 declare -n ans=$1; shift
340 declare -n args=$1; shift
341
342 ## Which jira server to query (?)
343 [[ ! -v server ]] && declare -g server='jira.opennetworking.org'
344 tmp_url="https://${server}/issues/?jql="
345 tmp="${tmp_url}${args}"
346 ans="${tmp// /%20}"
347 return
348}
349
350## --------------------------------------------------------------------
351## Intent: Dispaly command usage
352## --------------------------------------------------------------------
353function usage()
354{
355 cat <<EOH
356Usage: $0 VOL-xxxx
357 --debug Enable script debug mode
358 --dry-run Simulate
Joey Armstrong76f861a2024-03-13 16:01:24 -0400359 --todo Display future enhancements
Joey Armstrong3134bfd2024-02-10 20:51:25 -0500360
361 VOL-{xxxx} View a jira ticket by ID
362
363[SERVER]
Joey Armstrong76f861a2024-03-13 16:01:24 -0400364 --server {cord,onf}
Joey Armstrongcc24b3c2024-03-22 11:12:23 -0400365 --onf jira.opennetworking.org
Joey Armstrong3134bfd2024-02-10 20:51:25 -0500366 --opencord jira.opencord.org
367
368[WHAT]
369 --component Search by component name assigned to ticket
370 --label Search by label name assigned to ticket.
371 --text Search string(s)
Joey Armstrongcc24b3c2024-03-22 11:12:23 -0400372EOH
Joey Armstrong3134bfd2024-02-10 20:51:25 -0500373
Joey Armstrongcc24b3c2024-03-22 11:12:23 -0400374# declare -a topics=()
375# topics+=('fixversion.switches')
376# topics+=('resolved.switches')
377#
378# help_switch_show "${topics[@]}"#
379 #
380#[USER(s)]
381# --me Tickets assigned to or reported by me.
382# --user [u] Tickets assigned to this user.
383# --nobody Raw query, no filtering by user
Joey Armstrong3134bfd2024-02-10 20:51:25 -0500384
Joey Armstrong3134bfd2024-02-10 20:51:25 -0500385
Joey Armstrongcc24b3c2024-03-22 11:12:23 -0400386 cat <<EOH
Joey Armstrong3134bfd2024-02-10 20:51:25 -0500387
388[BOOL]
389 --and Join terms using 'AND'
390 --or Join terms using 'OR'
391
392[MEMBER]
393 --in (default) Items belong (--component IN)
394 --not-in Negate item set (--component NOT IN)
395
396[Contains]
397 --text [t] (join modifer: --and, --or)
398 --text-and [t] All of these terms
399 --text-or [t] Any of these terms
400
401[RANGE]
Joey Armstrongcc24b3c2024-03-22 11:12:23 -0400402 --newer [d] Search for tickets created < [n] days ago.
403 --older [d] Search for tickets created > [n] days ago.
Joey Armstrong3134bfd2024-02-10 20:51:25 -0500404
405[ALIASES]
Joey Armstrongcc24b3c2024-03-22 11:12:23 -0400406 --all Query for all unresolved tickets
407
408[TOPIC]
409 --fixversion Query by field: fixedversion
410 --resolved Query by field: resolved
411 --user Query by owner, requestor or 'my' jira tickets.
412
413[HELP]
414 --help This message
415 --help-{topic} Display switch help and use case. (--help-resolved)
416 --usage-{topic} Display use cases for a given switch (--usage-user)
Joey Armstrong3134bfd2024-02-10 20:51:25 -0500417
418[USAGE]
Joey Armstrongcc24b3c2024-03-22 11:12:23 -0400419 $0 --opencord --assigned --unresolved
Joey Armstrong3134bfd2024-02-10 20:51:25 -0500420 o Display all tickets assigned to my login
Joey Armstrongcc24b3c2024-03-22 11:12:23 -0400421
Joey Armstrong3134bfd2024-02-10 20:51:25 -0500422 $0 --reported --or --text 'bbsim' --text 'release'
423 o Search for tickets that contain strings bbsim or release
424 $0 --cord --text-and 'release' --text-and 'voltctl'
425 o Search jira.opencord for tickets that contain release and voltctl
426 $0 --text 'bitergia' --text 'Jira' -and
427 o Search jira.opennetworking for tickets containing string bitergia and Jira
428
429 $0 --cord --label failing --label pod
430 o Search jira.opencord for tests failing due to pod/hardware issuses.
431
432 $0 --proj VOL --fixversion "VOLTHA v2.12" --resolved-is-empty
433 o Query for unresolved release tickets
434EOH
435
436 return
437}
438
439## --------------------------------------------------------------------
440# classpath=$(join_by ':' "${mypath[@]}")
441## --------------------------------------------------------------------
442function join_by()
443{
444 local d=${1-} f=${2-}; if shift 2; then printf %s "$f" "${@/#/$d}"; fi;
445}
446
447##----------------##
448##---] MAIN [---##
449##----------------##
450declare -a suffix0=()
451
452# declare -g -i debug=1
453
454while [ $# -gt 0 ]; do
455
456 if [ ${#suffix0[@]} -gt 0 ]; then
457 suffix0+=('AND')
458 fi
459
460 arg="$1"; shift
461 [[ -v debug ]] && echo "** argv=[$arg] [$*]"
462
463 case "$arg" in
464
Joey Armstrongcc24b3c2024-03-22 11:12:23 -0400465 '--help') usage; exit 0 ;;
466 '--help-'*) help_with "${arg/--help-/}" ;;
467 '--usage-'*) help_usage_show "${arg/--usage-/}"
468 ;;
Joey Armstrong3134bfd2024-02-10 20:51:25 -0500469
470 ##-----------------##
471 ##---] MODES [---##
472 ##-----------------##
473 -*debug) declare -g -i debug=1 ;;
474 --dry-run) declare -g -i dry_run=1 ;;
475
Joey Armstrongcc24b3c2024-03-22 11:12:23 -0400476 ##------------------------##
477 ##---] SWITCH ALIAS [---##
478 ##------------------------##
479 --unresolved)
480 declare -a args=()
481 args+=('--resolved-is-empty')
482 [[ $# -gt 0 ]] && { args+=("$@"); }
483 set -- "${args[@]}"
484 ;;
485
Joey Armstrong3134bfd2024-02-10 20:51:25 -0500486 ##-------------------##
487 ##---] BY USER [---##
488 ##-------------------##
489 --assigned) declare -g -i argv_assigned=1 ;;
490 --reported) declare -g -i argv_reported=1 ;;
491 --me) declare -g -i argv_me=1 ;;
492 --nobody) declare -g -i argv_nobody=1 ;;
493 --user)
494 arg="$1"; shift
495 declare -g argv_user="$arg"
496 ;;
497
498 ##------------------##
499 ##---] SERVER [---##
500 ##------------------##
Joey Armstrong76f861a2024-03-13 16:01:24 -0400501 --serv*)
502 arg="$1"; shift
503 case "$arg" in
504 *cord*) server='jira.opencord.org' ;;
505 *onf*) server='jira.opennetworking.org' ;;
506 *) error "--server [$arg] expected opencord or onf" ;;
507 esac
508 ;;
509
Joey Armstrongcc24b3c2024-03-22 11:12:23 -0400510 --onf) declare server='jira.opennetworking.org' ;;
511 --opencord) declare server='jira.opencord.org' ;;
Joey Armstrong3134bfd2024-02-10 20:51:25 -0500512
513 ##---------------------##
514 ##---] SEARCH-BY [---##
515 ##---------------------##
516 --component|--comp*)
517 arg="$1"; shift
518 [[ ! -v components ]] && declare -g -a components=()
519 components+=("$arg")
520 ;;
521
522 --label-excl)
523 arg="$1"; shift
524 labels_excl+=("$arg")
525 ;;
526
527 --label|--label-incl)
528 arg="$1"; shift
529 labels_incl+=("$arg")
530 ;;
531
532 ##-----------------------##
533 ##---] Text Search [---##
534 ##-----------------------##
535 # jsearch.sh --text-and bbsim --text-and release
536 -*text-and) text_and+=("$1"); shift ;;
537 -*text-or) text_or+=("$1"); shift ;;
538
539 # % js --and --text jenkins --text cord
540 # text ~ "Jira Software"
 # [WORDs]
541 # text ~ "\"Jira Software\""
 # [STRING]
542 -*text)
543 arg="$1"; shift
544 if [[ -v bool_and ]]; then
545 text_and+=("$arg")
546 elif [[ -v bool_or ]]; then
547 text_or+=("$arg")
548 else
549 text+=("$arg")
550 fi
551 ;;
552
553 --all) set -- '--resolved-is-none' "$@" ;; # alias: --[un-]resolved
Joey Armstrong76f861a2024-03-13 16:01:24 -0400554 --todo) source "${pgm_lib}/todo.sh" ;;
Joey Armstrong3134bfd2024-02-10 20:51:25 -0500555
556 --proj*) projects+=("$1"); shift ;;
557
558 --fixversion-*)
559 # function get_jql_fixversion()
560 case "$arg" in
561 *excl)
562 [[ ! -v fixversion_excl ]] && { declare -g -a fixversion_excl=(); }
563 val="\"$1\""; shift
564 html_encode val
565 fixversion_excl+=("$val");
566 ;;
567
568 *incl)
569 [[ ! -v fixversion_incl ]] && { declare -g -a fixversion_incl=(); }
570 val="\"$1\""; shift
571 html_encode val
572 fixversion_incl+=("$val");
573 ;;
574
575 *not-empty) declare -g -i fixversion_not_empty=1 ;;
576 *is-empty) declare -g -i fixversion_is_empty=1 ;;
577
578 *) error "Detected invalid --fixversion-* modifier" ;;
579 esac
580 ;;
581
Joey Armstrongcc24b3c2024-03-22 11:12:23 -0400582 '--resolved-'*)
Joey Armstrong3134bfd2024-02-10 20:51:25 -0500583 # function get_jql_reasons()
584 case "$arg" in
585
586 *start) declare -g resolved_start="$1"; shift ;;
587 *end) declare -g resolved_end="$1"; shift ;;
588
589 *not-empty) declare -g resolved_not_empty="$1" ;;
590 *empty) declare -g resolved_is_empty="$1" ;;
591
592 *excl)
593 [[ ! -v resolved_excl ]] && { declare -g -a resolved_excl=(); }
594 val="\"$1\""; shift
595 html_encode val
596 resolved_excl+=("$val");
597 ;;
598 *incl)
599 [[ ! -v resolved_incl ]] && { declare -g -a resolved_incl=(); }
600 val="\"$1\""; shift
601 html_encode val
602 resolved_incl+=("$val");
603 ;;
604 *) ;;
605 *) error "Detected invalid --resolved-* modifier" ;;
606 esac
607 ;;
608
609 -*newer)
610 arg="$1"; shift
611 suffix0+=("created <= '-${arg}d'") ;;
612
613 -*older)
614 arg="$1"; shift
615 suffix0+=("created >= '-${arg}d'") ;;
616
617 ##----------------##
618 ##---] BOOL [---##
619 ##----------------##
620 --[aA][nN][dD]) declare -g -i bool_and=1 ;;
621 --[oO][rR]) declare -g -i bool_or=1 ;;
622
623 ##------------------##
624 ##---] MEMBER [---##
625 ##------------------##
626 --[iI][nN]) declare -g -i bool_in=1 ;;
627 --[nN][oO][tT]) declare -g -i bool_not=1 ;;
628
629 [A-Z][A-Z][A-Z]-[0-9]*)
630 case "$arg" in
631 CORD-[0-9]*)
632 url="https://jira.opencord.org/browse/${arg}"
633 urls_raw+=('--new-window' "$url")
634 ;;
635
636 INF-[0-9]*)
637 url="https://jira.opennetworking.org/browse/${arg}"
638 urls_raw+=('--new-window' "$url")
639 ;;
640
641 VOL-[0-9]*)
642 url="https://jira.opencord.org/browse/${arg}"
643 urls_raw+=('--new-window' "$url")
644 ;;
645
646 *) error "Detected invalid ticket [$arg]" ;;
647
648 esac
649 ;;
650
651 # -----------------------------------------------------------------------
652 # https://support.atlassian.com/jira-software-cloud/docs/search-syntax-for-text-fields/
653 # -----------------------------------------------------------------------
654 # +jira atlassian -- must contain jira, atlassian is optional
655 # -japan -- exclude term
656 # [STEM] summary ~ "customize" -- finds stem 'custom' in the Summary field
657 *)
658 declare -p text_and
659 error "Detected unknown argument $arg"
660 ;;
661 esac
662done
663
Joey Armstrong76f861a2024-03-13 16:01:24 -0400664## --------------
665## Required check
666## --------------
667[[ ! -v server ]] && { error "--server={cord,onf} is required"; }
668
Joey Armstrong3134bfd2024-02-10 20:51:25 -0500669## ----------------------
670## Construct query filter
671## ----------------------
672do_user suffix0
673do_projects suffix0
674[[ -v components ]] && { do_components components suffix0; }
675do_labels labels_incl labels_excl suffix0
676do_text text suffix0
677do_resolved suffix0
678do_fixversion suffix0
679
680filter=''
681gen_filter filter suffix0
682
683if [[ ! -v urls_raw ]]; then
684 url=''
685 gen_url url filter
686 urls_filt+=("$url")
687elif [ ${#urls_raw} -eq 0 ]; then
688 url=''
689 gen_url url filter
690 urls_filt+=("$url")
691fi
692
693[[ -v debug ]] && [[ -v url ]] && echo "URL: $url"
Joey Armstronge4ef06a2024-03-22 11:43:54 -0400694browser="${BROWSER:-firefox}"
Joey Armstrong3134bfd2024-02-10 20:51:25 -0500695echo "$browser ${urls_filt[@]} ${urls_raw[@]}"
696
697if [[ ! -v dry_run ]]; then
698 "$browser" "${urls_filt[@]}" "${urls_raw[@]}" >/dev/null 2>/dev/null &
699fi
700
701# [SEE ALSO]
702# o https://support.atlassian.com/jira-software-cloud/docs/advanced-search-reference-jql-fields/
703
704# [EOF]