blob: 03614d149c0093af35f208af0bf0478d5aca6aff [file] [log] [blame]
garciadeblas70461c52024-07-03 09:17:56 +02001#!/bin/bash
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7# http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14#
15
16# Convert input string to a safe name for K8s resources
17function safe_name() {
18 local INPUT="$1"
19
20 echo "${INPUT,,}" | \
21 sed '/\.\// s|./||' | \
22 sed 's|\.|-|g' | \
23 sed 's|/|-|g' | \
24 sed 's|_|-|g' | \
25 sed 's| |-|g'
26}
27
28
29# Helper function to create a new age key pair
30function create_age_keypair() {
31 local AGE_KEY_NAME="$1"
32 local CREDENTIALS_DIR="${2:-"${CREDENTIALS_DIR}"}"
33
34 # Delete the keys in case they existed already
35 rm -f "${CREDENTIALS_DIR}/${AGE_KEY_NAME}.key" "${CREDENTIALS_DIR}/${AGE_KEY_NAME}.pub"
36
37 # Private key
38 age-keygen -o "${CREDENTIALS_DIR}/${AGE_KEY_NAME}.key"
39
40 # Public key (extracted from comment at private key)
41 age-keygen -y "${CREDENTIALS_DIR}/${AGE_KEY_NAME}.key" > "${CREDENTIALS_DIR}/${AGE_KEY_NAME}.pub"
42}
43
44
45# Helper function to in-place encrypt secrets in manifest
46function encrypt_secret_inplace() {
47 local FILE="$1"
48 local PUBLIC_KEY="$2"
49
50 sops \
51 --age=${PUBLIC_KEY} \
52 --encrypt \
53 --encrypted-regex '^(data|stringData)$' \
54 --in-place "${FILE}"
55}
56
57
58# Helper function to encrypt secrets from stdin
59function encrypt_secret_from_stdin() {
60 local PUBLIC_KEY="$1"
61
62 # Save secret manifest to temporary file
63 local TMPFILE=$(mktemp /tmp/secret.XXXXXXXXXX) || exit 1
64 cat > "${TMPFILE}"
65 # NOTE: Required workaround for busybox's version of `mktemp`, which is quite limited and does not support temporary files with extensions.
66 # `.yaml` is required for proper `sops` behaviour.
67 mv "${TMPFILE}" "${TMPFILE}.yaml"
68
69 # Encrypt
70 sops \
71 --age=${PUBLIC_KEY} \
72 --encrypt \
73 --encrypted-regex '^(data|stringData)$' \
74 --in-place "${TMPFILE}.yaml"
75
76 # Outputs the result and removes the temporary file
77 cat "${TMPFILE}.yaml" && rm -f "${TMPFILE}.yaml"
78}
79
80
81# Helper function to create secret manifest and encrypt with public key
82function kubectl_encrypt() {
83 local PUBLIC_KEY="$1"
84
85 # Gathers all optional parameters for transformer funcion (if any) and puts them into an array for further use
86 local ALL_PARAMS=( "${@}" )
87 local PARAMS=( "${ALL_PARAMS[@]:1}" )
88
89 kubectl \
90 "${PARAMS[@]}" | \
91 encrypt_secret_from_stdin \
92 "${PUBLIC_KEY}"
93}
94
95
96# Generator function to convert source folder to `ResourceList`
97function folder2list_generator() {
98 local FOLDER="${1:-}"
99 local SUBSTENV="${2:-"false"}"
100 local FILTER="${3:-""}"
101
102 if [[ "${SUBSTENV,,}" == "true" ]];
103 then
104 # Mix input with new generated manifests and replace environment variables
105 join_lists \
106 <(cat) \
107 <(
108 kpt fn source "${FOLDER}" | \
109 replace_env_vars "${FILTER}"
110 )
111 else
112 # Mix input with new generated manifests
113 join_lists \
114 <(cat) \
115 <(
116 kpt fn source "${FOLDER}"
117 )
118 fi
119
120}
121
122
123# Function to convert source folder to `ResourceList` (no generator)
124function folder2list() {
125 local FOLDER="${1:-}"
126
127 kpt fn source "${FOLDER}"
128}
129
130
131# Helper function to convert manifest to `ResourceList`
132function manifest2list() {
133 kustomize cfg cat --wrap-kind ResourceList
134}
135
136
137# Helper function to convert `ResourceList` to manifests in folder structure.
138# - New folder must be created to render the manifests.
139function list2folder() {
140 local FOLDER="${1:-}"
141 local DRY_RUN="${2:-${DRY_RUN:-false}}"
142
143 if [[ "${DRY_RUN,,}" == "true" ]];
144 then
145 cat
146 else
147 kpt fn sink "${FOLDER}"
148 fi
149}
150
151
152# Helper function to convert `ResourceList` to manifests in folder structure.
153# - It copies (cp) the generated files/subfolders over the target folder.
154# - Pre-existing files and subfolder structure in target folder is preserved.
155function list2folder_cp_over() {
156 local FOLDER="${1:-}"
157 local DRY_RUN="${2:-${DRY_RUN:-false}}"
158
159 if [[ "${DRY_RUN,,}" == "true" ]];
160 then
161 cat
162 else
163 local TMPFOLDER=$(mktemp -d) || exit 1
164 kpt fn sink "${TMPFOLDER}/manifests"
165
166 # Copy the generated files over the target folder
167 mkdir -p "${FOLDER}/"
168 cp -r "${TMPFOLDER}/manifests/"* "${FOLDER}/"
169
170 # Delete temporary folder
171 rm -rf "${TMPFOLDER}"
172 fi
173}
174
175
176# Helper function to convert `ResourceList` to manifests in folder structure.
177# - It syncs the generated files/subfolders over the target folder.
178# - Pre-existing files and subfolder structure in target folder is deleted if not present in `ResourceList`.
179function list2folder_sync_replace() {
180 local FOLDER="${1:-}"
181 local DRY_RUN="${2:-${DRY_RUN:-false}}"
182
183 if [[ "${DRY_RUN,,}" == "true" ]];
184 then
185 cat
186 else
187 local TMPFOLDER=$(mktemp -d) || exit 1
188 kpt fn sink "${TMPFOLDER}/manifests"
189
190 # Copy the generated files over the target folder
191 mkdir -p "${FOLDER}/"
192 rsync -arh --exclude ".git" --exclude ".*" --delete \
193 "${TMPFOLDER}/manifests/" "${FOLDER}/"
194
195 # Delete temporary folder
196 rm -rf "${TMPFOLDER}"
197 fi
198}
199
200
201# Helper function to render **SAFELY** a single manifest coming from stdin into a profile, with a proper KSU subfolder
202function render_manifest_over_ksu() {
203 local KSU_NAME="$1"
204 local TARGET_PROFILE_FOLDER="$2"
205 local MANIFEST_FILENAME="$3"
206
207 manifest2list | \
208 set_filename_to_items \
209 "${MANIFEST_FILENAME}" | \
210 prepend_folder_path \
211 "${KSU_NAME}/" | \
212 list2folder_cp_over \
213 "${TARGET_PROFILE_FOLDER}"
214}
215
216
217# Set filename to `ResourceList` item
218function set_filename_to_items() {
219 local FILENAME="$1"
220
221 yq "(.items[]).metadata.annotations.\"config.kubernetes.io/path\" |= \"${FILENAME}\"" | \
222 yq "(.items[]).metadata.annotations.\"internal.config.kubernetes.io/path\" |= \"${FILENAME}\""
223}
224
225
226# Prepend folder path to `ResourceList`
227function prepend_folder_path() {
228 local PREFIX="$1"
229
230 if [[ (-z "${PREFIX}") || ("${PREFIX}" == ".") ]];
231 then
232 cat
233 else
234 yq "(.items[]).metadata.annotations.\"config.kubernetes.io/path\" |= \"${PREFIX}\" + ." | \
235 yq "(.items[]).metadata.annotations.\"internal.config.kubernetes.io/path\" |= \"${PREFIX}\" + ."
236 fi
237}
238
239
240# Rename file in `ResourceList`
241function rename_file_in_items() {
242 local SOURCE_NAME="$1"
243 local DEST_NAME="$2"
244
245 yq "(.items[].metadata.annotations | select (.\"config.kubernetes.io/path\" == \"${SOURCE_NAME}\")).\"config.kubernetes.io/path\" = \"${DEST_NAME}\"" | \
246 yq "(.items[].metadata.annotations | select (.\"internal.config.kubernetes.io/path\" == \"${SOURCE_NAME}\")).\"internal.config.kubernetes.io/path\" = \"${DEST_NAME}\""
247}
248
249
250# Get value from key in object in `ResourceList`
251function get_value_from_resourcelist() {
252 local KEY_PATH="$1"
253 local TARGET_FILTERS="${2:-}"
254 # Example: To get a specific kind ("ProviderConfig") with a specific name ("default"). (TIP: Note the escaped double quotes).
255 # TARGET_FILTERS="| select(.kind == \"ProviderConfig\") | select(.metadata.name == \"default\")"
256
257 yq "(.items[]${TARGET_FILTERS})${KEY_PATH}"
258}
259
260
261# Patch "replace" to item in `ResourceList`
262function patch_replace() {
263 local KEY_PATH="$1"
264 local VALUE="$2"
265 local TARGET_FILTERS="${3:-}"
266 # Example: To only patch a specific kind ("ProviderConfig") with a specific name ("default"). (TIP: Note the escaped double quotes).
267 # TARGET_FILTERS="| select(.kind == \"ProviderConfig\") | select(.metadata.name == \"default\")"
268
269 yq "(.items[]${TARGET_FILTERS})${KEY_PATH} = \"${VALUE}\""
270}
271
272
273# Add label to item in `ResourceList`
274function set_label() {
275 local KEY="$1"
276 local VALUE="$2"
277 local TARGET_FILTERS="${3:-}"
278 # Example: To only patch a specific kind ("ProviderConfig") with a specific name ("default"). (TIP: Note the escaped double quotes).
279 # TARGET_FILTERS="| select(.kind == \"ProviderConfig\") | select(.metadata.name == \"default\")"
280
281 yq "(.items[]${TARGET_FILTERS}).metadata.labels.${KEY} = \"${VALUE}\""
282}
283
284
285# Patch which "appends" to list existing in item in `ResourceList`
286function patch_add_to_list() {
287 local KEY_PATH="$1"
288 local VALUE="$2"
289 local TARGET_FILTERS="${3:-}"
290 # Example: To only patch a specific kind ("ProviderConfig") with a specific name ("default"). (TIP: Note the escaped double quotes).
291 # TARGET_FILTERS="| select(.kind == \"ProviderConfig\") | select(.metadata.name == \"default\")"
292
293 local VALUE_AS_JSON="$(echo "${VALUE}" | yq -o json -I0)"
294
295 yq "(.items[]${TARGET_FILTERS})${KEY_PATH} += ${VALUE_AS_JSON}"
296}
297
298
299# Patch which removes from list, existing in item in `ResourceList`
300function patch_delete_from_list() {
301 local KEY_PATH="$1"
302 local TARGET_FILTERS="${2:-}"
303
304 # local VALUE_AS_JSON="$(echo "${VALUE}" | yq -o json -I0)"
305
306 yq "del((.items[]${TARGET_FILTERS})${KEY_PATH})"
307}
308
309
310# Check if an element/value is in a given list, existing in item in `ResourceList`
311function is_element_on_list() {
312 local KEY_PATH="$1"
313 local VALUE="$2"
314 local TARGET_FILTERS="${3:-}"
315 # Example: To only patch a specific kind ("ProviderConfig") with a specific name ("default"). (TIP: Note the escaped double quotes).
316 # TARGET_FILTERS="| select(.kind == \"ProviderConfig\") | select(.metadata.name == \"default\")"
317
318 TEST_RESULT=$(
319 cat | \
320 yq "(.items[]${TARGET_FILTERS})${KEY_PATH} == \"${VALUE}\"" | grep "true"
321 )
322
323 if [[ "${TEST_RESULT}" != "true" ]]
324 then
325 echo "false"
326 else
327 echo "true"
328 fi
329}
330
331
332# Patch "replace" to item in `ResourceList` using a JSON as value
333function patch_replace_inline_json() {
334 local KEY_PATH="$1"
335 local VALUE="$2"
336 local TARGET_FILTERS="${3:-}"
337 # Example: To only patch a specific kind ("ProviderConfig") with a specific name ("default"). (TIP: Note the escaped double quotes).
338 # TARGET_FILTERS="| select(.kind == \"ProviderConfig\") | select(.metadata.name == \"default\")"
339
340 VALUE_AS_JSON="$(echo "${VALUE}" | yq -o=json)" yq "(.items[]${TARGET_FILTERS})${KEY_PATH} = strenv(VALUE_AS_JSON)"
341}
342
343
344# Delete full object from `ResourceList`
345function delete_object() {
346 local OBJECT_NAME="$1"
347 local KIND_NAME="$2"
348 local API_VERSION="${3:-""}"
349
350 # Calculated inputs
351 if [[ -z "${API_VERSION}" ]]
352 then
353 # If `apiVersion` is not specified
354 local TARGET_FILTER="| select(.kind == \"${KIND_NAME}\") | select(.metadata.name == \"${OBJECT_NAME}\")"
355 else
356 # Otherwise, it is taken into account
357 local TARGET_FILTER="| select(.kind == \"${KIND_NAME}\") | select(.apiVersion == \"${API_VERSION}\") | select(.metadata.name == \"${OBJECT_NAME}\")"
358 fi
359
360 # Delete object
361 yq "del((.items[]${TARGET_FILTER}))"
362}
363
364
365# Empty transformer function
366function noop_transformer() {
367 cat
368}
369
370
371# Add patch to `Kustomization` item in `ResourceList`
372function add_patch_to_kustomization() {
373 local KUSTOMIZATION_NAME="$1"
374 local FULL_PATCH_CONTENT="$2"
375
376 patch_add_to_list \
377 ".spec.patches" \
378 "${FULL_PATCH_CONTENT}" \
379 "| select(.kind == \"Kustomization\") | select(.metadata.name == \"${KUSTOMIZATION_NAME}\")"
380}
381
rshri4240a7d2025-06-13 11:30:35 +0000382function patch_add_value_as_list() {
383 local KEY_PATH="$1"
384 local VALUE="$2"
385 local TARGET_FILTERS="${3:-}"
386
387 yq "(.items[]${TARGET_FILTERS})${KEY_PATH} += [${VALUE}]"
388}
389
390function add_patch_to_kustomization_as_list() {
391 local KUSTOMIZATION_NAME="$1"
392 local PATCH_VALUE="$2"
393
394 local VALUE_AS_JSON=$(echo "$PATCH_VALUE" | yq -o json -I0)
395
396 patch_add_value_as_list \
397 ".spec.patches" \
398 "${VALUE_AS_JSON}" \
399 "| select(.kind == \"Kustomization\") | select(.metadata.name == \"${KUSTOMIZATION_NAME}\")"
400}
401
402function add_component_to_kustomization_as_list() {
403 local KUSTOMIZATION_NAME="$1"
404 shift
405 local COMPONENT=("$@")
406
407 local COMPONENT_JSON=$(printf '"%s",' "${COMPONENT[@]}" | sed 's/,$//')
408
409 patch_add_value_as_list \
410 ".spec.components" \
411 "${COMPONENT_JSON}" \
412 "| select(.kind == \"Kustomization\") | select(.metadata.name == \"${KUSTOMIZATION_NAME}\")"
413}
414
415function add_config_to_kustomization() {
416 local KUSTOMIZATION_NAME="$1"
417
418 yq '
419 (.items[] | select(.kind == "Kustomization") | select(.metadata.name == "'"${KUSTOMIZATION_NAME}"'"))
420 .spec.postBuild.substituteFrom = [{"kind": "ConfigMap", "name": "'"${KUSTOMIZATION_NAME}"'-parameters"}]
421 '
422}
garciadeblas70461c52024-07-03 09:17:56 +0200423
424# Helper function to produce a JSON Patch as specified in RFC 6902
425function as_json_patch() {
426 local OPERATION="$1"
427 local PATCH_PATH="$2"
428 local VALUES="$3"
429
430 # Convert to JSON dictionary to insert as map instead of string
431 local VALUES_AS_DICT=$(echo "${VALUES}" | yq -o=json)
432
433 # Generate a patch list
434 cat <<EOF | yq ".[0].value = ${VALUES_AS_DICT}"
435- op: ${OPERATION}
436 path: ${PATCH_PATH}
437EOF
438}
439
440
441# Helper function to produce a full patch, with target object + JSON Patch RFC 6902
442function full_json_patch() {
443 local TARGET_KIND="$1"
444 local TARGET_NAME="$2"
445 local OPERATION="$3"
446 local PATCH_PATH="$4"
garciadeblasc4afd542025-06-18 17:37:59 +0200447 # Gathers all optional parameters for transformer function (if any) and puts them into an array for further use
garciadeblas70461c52024-07-03 09:17:56 +0200448 local ALL_PARAMS=( "${@}" )
449 local VALUES=( "${ALL_PARAMS[@]:4}" )
450
451 # Accumulates value items into the patch
452 local PATCH_CONTENT=""
453 for VAL in "${VALUES[@]}"
454 do
455 local VAL_AS_DICT=$(echo "${VAL}" | yq -o=json)
456
457 ITEM=$(
458 yq --null-input ".op = \"${OPERATION}\", .path = \"${PATCH_PATH}\"" | \
459 yq ".value = ${VAL_AS_DICT}" | \
460 yq "[ . ]"
461 )
462
463 PATCH_CONTENT="$(echo -e "${PATCH_CONTENT}\n${ITEM}")"
464 done
465
466 # Wrap a full patch around, adding target specification
467 local PATCH_FULL=$(
468 yq --null-input ".target.kind = \"${TARGET_KIND}\", .target.name = \"${TARGET_NAME}\"" | \
garciadeblas62453242025-07-18 18:12:40 +0200469 yq eval-all 'select(fileIndex == 0) * select(fileIndex == 1)' - \
470 <(printf "patch: |-\n%s\n" "$(echo "${PATCH_CONTENT}" | sed 's/^/ /')" ) | \
471 yq "[.]"
garciadeblas70461c52024-07-03 09:17:56 +0200472 )
473
474 echo "${PATCH_FULL}"
475}
476
477
478# Add values to `HelmRelease` by patch into `Kustomization` item in `ResourceList`
479function add_values_to_helmrelease_via_ks() {
480 local KUSTOMIZATION_NAME="$1"
481 local HELMRELEASE_NAME="$2"
482 local VALUES="$3"
483
484 # Embed into patch list
485 local FULL_PATCH_CONTENT="$(
486 full_json_patch \
487 "HelmRelease" \
488 "${HELMRELEASE_NAME}" \
489 "add" \
490 "/spec/values" \
491 "${VALUES}"
492 )"
493
494 # Path via intermediate Kustomization object
495 add_patch_to_kustomization \
496 "${KUSTOMIZATION_NAME}" \
497 "${FULL_PATCH_CONTENT}"
498}
499
500
501# Add values from Secret/ConfigMap to `HelmRelease` by patch into `Kustomization` item in `ResourceList`
502function add_referenced_values_to_helmrelease_via_ks() {
503 local KUSTOMIZATION_NAME="$1"
504 local HELMRELEASE_NAME="$2"
505 local VALUES_FROM="$3"
506
507 # Embed into patch list
508 local FULL_PATCH_CONTENT="$(
509 full_json_patch \
510 "HelmRelease" \
511 "${HELMRELEASE_NAME}" \
512 "add" \
513 "/spec/valuesFrom" \
514 "${VALUES_FROM}"
515 )"
516
517 # Path via intermediate Kustomization object
518 add_patch_to_kustomization \
519 "${KUSTOMIZATION_NAME}" \
520 "${FULL_PATCH_CONTENT}"
521}
522
523
524# High level function to add values from Secret, ConfigMap or both to `HelmRelease` by patch into `Kustomization` item in `ResourceList`
525function add_ref_values_to_hr_via_ks() {
526 local KUSTOMIZATION_NAME="$1"
527 local HELMRELEASE_NAME="$2"
528 local VALUES_SECRET_NAME="${3:-""}"
529 local VALUES_CM_NAME="${4:-""}"
530
531 local YAML_VALUES_FROM_BOTH=$(cat <<EOF
532- kind: Secret
533 name: "${VALUES_SECRET_NAME}"
534- kind: ConfigMap
535 name: "${VALUES_CM_NAME}"
536EOF
537 )
538 local YAML_VALUES_FROM_SECRET=$(cat <<EOF
539- kind: Secret
540 name: "${VALUES_SECRET_NAME}"
541EOF
542 )
543 local YAML_VALUES_FROM_CM=$(cat <<EOF
544- kind: ConfigMap
545 name: "${VALUES_CM_NAME}"
546EOF
547 )
548
549 # Chooses the appropriate YAML
550 VALUES_FROM=""
551 if [[ ( -n "${VALUES_SECRET_NAME}" ) && ( -n "${VALUES_CM_NAME}" ) ]];
552 then
553 VALUES_FROM="${YAML_VALUES_FROM_BOTH}"
554 elif [[ -n "${VALUES_SECRET_NAME}" ]];
555 then
556 VALUES_FROM="${YAML_VALUES_FROM_SECRET}"
557 elif [[ -n "${VALUES_CM_NAME}" ]];
558 then
559 VALUES_FROM="${YAML_VALUES_FROM_CM}"
560 else
561 # If none is set, it must be an error
562 return 1
563 fi
564
565 # Calls the low-level function
566 add_referenced_values_to_helmrelease_via_ks \
567 "${KUSTOMIZATION_NAME}" \
568 "${HELMRELEASE_NAME}" \
569 "${VALUES_FROM}"
570}
571
572# Substitute environment variables from stdin
573function replace_env_vars() {
574 # Optional parameter to filter environment variables that can be replaced
575 local FILTER=${1:-}
576
577 if [[ -n "${FILTER}" ]];
578 then
579 envsubst "${FILTER}"
580 else
581 envsubst
582 fi
583}
584
585
586# Join two `ResourceList` **files**
587#
588# Examples of use:
589# $ join_lists list_file1.yaml list_file2.yaml
590# $ join_lists <(manifest2list < manifest_file1.yaml) <(manifest2list < manifest_file2.yaml)
591# $ cat prueba1.yaml | manifest2list | join_lists - <(manifest2list < prueba2.yaml)
592#
593# NOTE: Duplicated keys and arrays may be overwritten by the latest file.
594# See: https://stackoverflow.com/questions/66694238/merging-two-yaml-documents-while-concatenating-arrays
595function join_lists() {
596 local FILE1="$1"
597 local FILE2="$2"
598
599 yq eval-all '. as $item ireduce ({}; . *+ $item)' \
600 "${FILE1}" \
601 "${FILE2}"
602}
603
604
605# Helper function to create a generator from a function that creates manifests
606function make_generator() {
607 local MANIFEST_FILENAME="$1"
608 local SOURCER_FUNCTION="$2"
609 # Gathers all optional parameters for the funcion (if any) and puts them into an array for further use
610 local ALL_PARAMS=( "${@}" )
611 local PARAMS=( "${ALL_PARAMS[@]:2}" )
612
613 # Mix input with new generated manifests
614 join_lists \
615 <(cat) \
616 <(
617 "${SOURCER_FUNCTION}" \
618 "${PARAMS[@]}" | \
619 manifest2list | \
620 set_filename_to_items "${MANIFEST_FILENAME}"
621 )
622}
623
624
625function transform_if() {
626 local TEST_RESULT=$1
627
628 # Gathers all optional parameters for transformer funcion (if any) and puts them into an array for further use
629 local ALL_PARAMS=( "${@}" )
630 local PARAMS=( "${ALL_PARAMS[@]:1}" )
631
632 # If test result is true (==0), then runs the transformation normally
633 if [[ "${TEST_RESULT}" == "0" ]];
634 then
635 "${PARAMS[@]}"
636 # Otherwise, just pass through
637 else
638 cat
639 fi
640}
641
642
643# Helper function to convert multiline input from stdin to comma-separed output
644function multiline2commalist() {
645 mapfile -t TMP_ARRAY < <(cat)
646 printf -v TMP_LIST '%s,' "${TMP_ARRAY[@]}"
647 echo "${TMP_LIST}" | sed 's/,$//g'
648}
649
650
651# Helper function to check pending changes in workdir to `fleet` repo
652function check_fleet_workdir_status() {
653 local FLEET_REPO_DIR="${1:-${FLEET_REPO_DIR}}"
654
655 pushd "${FLEET_REPO_DIR}"
656 git status
657 popd
658}
659
660
661# Helper function to commit changes in workdir to `fleet` repo
662function commit_and_push_to_fleet() {
663 local DEFAULT_COMMIT_MESSAGE="Committing latest changes to fleet repo at $(date +'%Y-%m-%d %H:%M:%S')"
664 local COMMIT_MESSAGE="${1:-${DEFAULT_COMMIT_MESSAGE}}"
665 local FLEET_REPO_DIR="${2:-${FLEET_REPO_DIR}}"
666
667 pushd "${FLEET_REPO_DIR}"
668 git status
669 git add -A
670 git commit -m "${COMMIT_MESSAGE}"
671 echo "${COMMIT_MESSAGE}"
672 git push
673 popd
674}