From 1d4d811718db4e5131924a79cc7ad681f02ac83d Mon Sep 17 00:00:00 2001
From: Volker Schukai <volker.schukai@schukai.com>
Date: Sat, 16 Sep 2023 17:17:30 +0200
Subject: [PATCH] fix: setting the paths does not always work smoothly #9

---
 .gitlab-ci.yml                                |   9 +-
 Taskfile.yml                                  |  44 +-
 configuration.iml                             |  15 +-
 devenv.nix                                    | 731 +++++++++++++++---
 go.mod                                        |   2 +-
 go.sum                                        |  20 +
 import.go                                     | 122 ++-
 import_test.go                                |  85 +-
 integration_test.go                           |   2 -
 issue-7_test.go                               |  12 +-
 .../github.com/pelletier/go-toml/v2/LICENSE   |   3 +-
 11 files changed, 813 insertions(+), 232 deletions(-)

diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 7b2885e..4339280 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -1,9 +1,15 @@
+
+# THIS FILE IS AUTOGENERATED BY THE DEVENVSHELL
+# DO NOT EDIT THIS FILE MANUALLY
+# INSTEAD EDIT THE DEVENVSHELL CONFIGURATION FILE devenv.nix
+# AND OPEN A SHELL WITH THE COMMAND devenv shell
+#
+
 image: docker-registry.schukai.com:443/nixos-ci-devenv:latest
 
 services:
   - docker:dind
 
-
 variables:
   # The repo name as used in
   # https://github.com/nix-community/NUR/blob/master/repos.json
@@ -13,7 +19,6 @@ variables:
   DOCKER_DRIVER: overlay2
   GIT_DEPTH: 10
 
-
 stages:
   - test
   - deploy 
diff --git a/Taskfile.yml b/Taskfile.yml
index 8fd6c58..b7313f4 100644
--- a/Taskfile.yml
+++ b/Taskfile.yml
@@ -1,3 +1,10 @@
+
+# THIS FILE IS AUTOGENERATED BY THE DEVENVSHELL
+# DO NOT EDIT THIS FILE MANUALLY
+# INSTEAD EDIT THE DEVENVSHELL CONFIGURATION FILE devenv.nix 
+# AND OPEN A SHELL WITH THE COMMAND devenv shell
+#
+# Information about the task runner can be found here:
 # https://taskfile.dev
 
 version: '3'
@@ -5,29 +12,36 @@ version: '3'
 tasks:
   default:
     cmds:
-      - task --list-all
+      - task --list
     silent: true
-
+    
   test:
     desc: Execute unit tests in Go.
-    cmds:  
+    cmds:
       - echo "Execute unit tests in Go."
       - go test -cover -v ./...
-      - go test -bench .
-      - go test -race .
+      - go test -bench -v ./...
+      - go test -race -v ./...
 
   test-fuzz:
     desc: Conduct fuzzing tests.#
     cmds:  
       - echo "Conduct fuzzing tests."
-      - go test -v -fuzztime=10s -fuzz=Fuzz ./...
+      - go test -v -fuzztime=30s -fuzz=Fuzz ./...
 
   add-licenses:
     desc: Attach license headers to Go files.
     cmds:
       - echo "Attach license headers to Go files."
+      - go install github.com/google/addlicense@latest
       - addlicense -c "schukai GmbH" -s -l "AGPL-3.0" ./*.go
     silent: true
+    
+  check-licenses:
+    desc: Check license headers of Go files.
+    silent: true
+    cmds:
+      - go-licenses save "$(get-go-default-packages)"  --ignore "gitlab.schukai.com"  --force --save_path ${DEVENV_ROOT}/licenses/
 
   check:
     desc: Confirm repository status.
@@ -35,17 +49,11 @@ tasks:
       - git diff-index --quiet HEAD || (echo "There are uncommitted changes after running make. Please commit or stash them before running make."; exit 1)
     silent: true
 
-  build:
-    desc: Compile the application,
+  commit:
+    desc: Commit changes to the repository.
     aliases:
-      - b
-    vars:
-      DEVENV_ROOT:
-        sh: echo "$DEVENV_ROOT"
-    
+      - c
+      - ci
+      - git-commit
     cmds:
-      - devenv shell build-app
-    sources:
-      - source/**/*.go
-      - source/**/*.mod
-      - dist/**      
+      - do-git-commit
diff --git a/configuration.iml b/configuration.iml
index 11dced7..5f86599 100644
--- a/configuration.iml
+++ b/configuration.iml
@@ -1,18 +1,11 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<module type="WEB_MODULE" version="4">
-  <component name="Go" enabled="true">
-    <buildTags>
-      <option name="customFlags">
-        <array>
-          <option value="" />
-        </array>
-      </option>
-    </buildTags>
-  </component>
+<module type="JAVA_MODULE" version="4">
+  <component name="Go" enabled="true" />
   <component name="NewModuleRootManager" inherit-compiler-output="true">
     <exclude-output />
     <content url="file://$MODULE_DIR$">
-      <excludeFolder url="file://$MODULE_DIR$/licenses" />
+      <sourceFolder url="file://$MODULE_DIR$/.devenv/state/go/pkg/mod/github.com/google/addlicense@v1.1.1/testdata/expected" isTestSource="false" />
+      <sourceFolder url="file://$MODULE_DIR$/.devenv/state/go/pkg/mod/github.com/google/addlicense@v1.1.1/testdata/initial" isTestSource="false" />
     </content>
     <orderEntry type="inheritedJdk" />
     <orderEntry type="sourceFolder" forTests="false" />
diff --git a/devenv.nix b/devenv.nix
index 0eb76b3..efd4d9b 100644
--- a/devenv.nix
+++ b/devenv.nix
@@ -1,149 +1,638 @@
-{ pkgs, inputs, phps, lib, config, modulesPath,... }:
+{ pkgs, inputs, phps, lib, config, modulesPath, ... }:
 
 {
-
   # https://devenv.sh/packages/
   packages = with pkgs; [
     inputs.version.defaultPackage."${builtins.currentSystem}"
-    git
-    gcc12
-    go-task
+    appimage-run
     blackbox
     blackbox-terminal
-    jq
+    coreutils-full
+    dbeaver
     delve
+    dialog
+    drill
+    exa
+    fd
+    fd
+    gcc12
     gdlv
-    wget
+    git
     glab
-    unixtools.xxd
-    libffi
-    zlib
-    procps
-    php81Extensions.xdebug
-    ranger
-    meld
-    gnused
-    coreutils-full
     gnugrep
     gnumake
-    util-linux
+    gnused
+    go-licenses
+    go-task
+    gum
     httpie
-    netcat
+    hurl
+    jq
+    libffi
+    logrotate
+    meld
     memcached
-    fd    
+    netcat
+    nixfmt
+    procps
+    ranger
+    unixtools.xxd
+    unzip
+    util-linux
+    wget
+    zlib
   ];
 
-
   # https://devenv.sh/languages/
   # languages.nix.enable = true;
-  languages = {
-    go = { enable = true; };
-  };
-  
-   difftastic.enable = true;
+  languages = { go = { enable = true; }; };
+
+  difftastic.enable = true;
+
+  scripts.get-go-default-packages.exec = ''
+    #!${pkgs.bash}/bin/bash
+    echo $(awk -F ' ' '/^module / { print $2 }' go.mod)
+  '';
 
-    
   # This script is executed when the app is built
   # You can use it to build the app  
-  scripts.test-lib.exec =  ''
-#!${pkgs.bash}/bin/bash
-#set -euo pipefail
-set -x
-
-PATH="''${PATH}":${pkgs.coreutils}/bin
-PATH="''${PATH}":${pkgs.findutils}/bin
-PATH="''${PATH}":${pkgs.jq}/bin/
-PATH="''${PATH}":${pkgs.rsync}/bin/
-PATH="''${PATH}":${pkgs.bash}/bin/
-PATH="''${PATH}":${pkgs.curl}/bin/
-PATH="''${PATH}":${pkgs.moreutils}/bin/
-PATH="''${PATH}":${pkgs.gnutar}/bin
-PATH="''${PATH}":${pkgs.gzip}/bin/
-PATH="''${PATH}":${pkgs.procps}/bin/
-PATH="''${PATH}":${pkgs.exa}/bin/
-PATH="''${PATH}":${pkgs.git}/bin/
-PATH="''${PATH}":${pkgs.gnugrep}/bin/
-PATH="''${PATH}":${inputs.version.defaultPackage."${builtins.currentSystem}"}/bin/
-
-export PATH
-
-task test
-
-'';
+  scripts.test-lib.exec = ''
+    #!${pkgs.bash}/bin/bash
+    #set -euo pipefail
+    set -x
+
+    PATH="''${PATH}":${pkgs.coreutils}/bin
+    PATH="''${PATH}":${pkgs.findutils}/bin
+    PATH="''${PATH}":${pkgs.jq}/bin/
+    PATH="''${PATH}":${pkgs.rsync}/bin/
+    PATH="''${PATH}":${pkgs.bash}/bin/
+    PATH="''${PATH}":${pkgs.curl}/bin/
+    PATH="''${PATH}":${pkgs.moreutils}/bin/
+    PATH="''${PATH}":${pkgs.gnutar}/bin
+    PATH="''${PATH}":${pkgs.gzip}/bin/
+    PATH="''${PATH}":${pkgs.procps}/bin/
+    PATH="''${PATH}":${pkgs.exa}/bin/
+    PATH="''${PATH}":${pkgs.git}/bin/
+    PATH="''${PATH}":${pkgs.gnugrep}/bin/
+    PATH="''${PATH}":${
+      inputs.version.defaultPackage."${builtins.currentSystem}"
+    }/bin/
+
+    export PATH
+
+    task test
+
+  '';
 
   # This scritp is used to deploy the app to the gitlab registry
   # It is used by the gitlab-ci.yml file
   # The environment variables are set in the gitlab project settings
-  scripts.deploy-lib.exec =  ''
-#!${pkgs.bash}/bin/bash
-
-PATH="''${PATH}":${pkgs.coreutils}/bin
-PATH="''${PATH}":${pkgs.jq}/bin/
-PATH="''${PATH}":${pkgs.curl}/bin/
-PATH="''${PATH}":${pkgs.moreutils}/bin/
-PATH="''${PATH}":${pkgs.gnutar}/bin
-PATH="''${PATH}":${pkgs.gzip}/bin/
-PATH="''${PATH}":${pkgs.exa}/bin/
-PATH="''${PATH}":${pkgs.git}/bin/
-PATH="''${PATH}":${inputs.version.defaultPackage."${builtins.currentSystem}"}/bin/
-
-export PATH
-
-if [[ -f .env-gitlab-ci ]]; then
-    source .env-gitlab-ci
-    rm .env-gitlab-ci
-fi
-
-set -x
-## if $HOME not set, set it to current directory
-if [[ -z "''${HOME}" ]]; then
-    HOME=$(pwd)
-fi
-
-export HOME
-
-git config user.email "''${GITLAB_USER_EMAIL}"
-git config user.name "''${GITLAB_USER_NAME:-"Gitlab CI"}"
-git config pull.rebase true
-git config http.sslVerify "false"
-git remote set-url origin https://pad:''${GITLAB_TOKEN}@''${CI_REPOSITORY_URL#*@}
-
-git fetch --all --tags --unshallow
-git reset --hard origin/master
-git checkout $CI_COMMIT_REF_NAME
-git pull origin $CI_COMMIT_REF_NAME
-
-if [ ! -z "''${CI_PROJECT_DIR}" ]; then
-    echo "CI_PROJECT_DIR is set, using it as project root."
-    project_root=$(realpath "''${CI_PROJECT_DIR}")/
-elif [ ! -z "''${DEVENV_ROOT}" ]; then
-    echo "DEVENV_ROOT is set, using it as project root."
-    project_root=$(realpath "''${DEVENV_ROOT}")/
-else
-    echo "Error: DEVENV_ROOT or CI_PROJECT_DIR environment variables are not set."
-    exit 1  
-fi
-
-if [ ! -d "''${project_root}" ]; then
-    echo "Error: Project root directory does not seem to be valid."
-    echo "Check the DEVENV_ROOT or CI_PROJECT_DIR environment variables."
-    exit 1
-fi
-
-if [ -z "'CI_JOB_TOKEN" ]; then
-    echo "Error: CI_JOB_TOKEN variable is not set."
-    exit 1
-fi
-
-git --no-pager log --decorate=short --pretty=oneline
-gitVersion=v$(version predict)
-git tag -a $gitVersion -m"chore: bump version" 
-git --no-pager log --decorate=short --pretty=oneline
-git push -o ci.skip origin ''${CI_COMMIT_REF_NAME} --tags
-
-echo "done"
-
-'';
+  scripts.deploy-lib.exec = ''
+    #!${pkgs.bash}/bin/bash
+
+    PATH="''${PATH}":${pkgs.coreutils}/bin
+    PATH="''${PATH}":${pkgs.jq}/bin/
+    PATH="''${PATH}":${pkgs.curl}/bin/
+    PATH="''${PATH}":${pkgs.moreutils}/bin/
+    PATH="''${PATH}":${pkgs.gnutar}/bin
+    PATH="''${PATH}":${pkgs.gzip}/bin/
+    PATH="''${PATH}":${pkgs.exa}/bin/
+    PATH="''${PATH}":${pkgs.git}/bin/
+    PATH="''${PATH}":${
+      inputs.version.defaultPackage."${builtins.currentSystem}"
+    }/bin/
+
+    export PATH
+
+    if [[ -f .env-gitlab-ci ]]; then
+        source .env-gitlab-ci
+        rm .env-gitlab-ci
+    fi
+
+    set -x
+    ## if $HOME not set, set it to current directory
+    if [[ -z "''${HOME}" ]]; then
+        HOME=$(pwd)
+    fi
+
+    export HOME
+
+    git config user.email "''${GITLAB_USER_EMAIL}"
+    git config user.name "''${GITLAB_USER_NAME:-"Gitlab CI"}"
+    git config pull.rebase true
+    git config http.sslVerify "false"
+    git remote set-url origin https://pad:''${GITLAB_TOKEN}@''${CI_REPOSITORY_URL#*@}
+
+    git fetch --all --tags --unshallow
+    git reset --hard origin/master
+    git checkout $CI_COMMIT_REF_NAME
+    git pull origin $CI_COMMIT_REF_NAME
+
+    if [ ! -z "''${CI_PROJECT_DIR}" ]; then
+        echo "CI_PROJECT_DIR is set, using it as project root."
+        project_root=$(realpath "''${CI_PROJECT_DIR}")/
+    elif [ ! -z "''${DEVENV_ROOT}" ]; then
+        echo "DEVENV_ROOT is set, using it as project root."
+        project_root=$(realpath "''${DEVENV_ROOT}")/
+    else
+        echo "Error: DEVENV_ROOT or CI_PROJECT_DIR environment variables are not set."
+        exit 1  
+    fi
+
+    if [ ! -d "''${project_root}" ]; then
+        echo "Error: Project root directory does not seem to be valid."
+        echo "Check the DEVENV_ROOT or CI_PROJECT_DIR environment variables."
+        exit 1
+    fi
+
+    if [ -z "'CI_JOB_TOKEN" ]; then
+        echo "Error: CI_JOB_TOKEN variable is not set."
+        exit 1
+    fi
+
+    git --no-pager log --decorate=short --pretty=oneline
+    gitVersion=v$(version predict)
+    git tag -a $gitVersion -m"chore: bump version" 
+    git --no-pager log --decorate=short --pretty=oneline
+    git push -o ci.skip origin ''${CI_COMMIT_REF_NAME} --tags
+
+    echo "done"
+
+  '';
+
+  enterShell = ''
+        
+    cat <<'EOF' > Taskfile.yml
+
+    # THIS FILE IS AUTOGENERATED BY THE DEVENVSHELL
+    # DO NOT EDIT THIS FILE MANUALLY
+    # INSTEAD EDIT THE DEVENVSHELL CONFIGURATION FILE devenv.nix 
+    # AND OPEN A SHELL WITH THE COMMAND devenv shell
+    #
+    # Information about the task runner can be found here:
+    # https://taskfile.dev
+
+    version: '3'
+
+    tasks:
+      default:
+        cmds:
+          - task --list
+        silent: true
+        
+      test:
+        desc: Execute unit tests in Go.
+        cmds:
+          - echo "Execute unit tests in Go."
+          - go test -cover -v ./...
+          - go test -bench -v ./...
+          - go test -race -v ./...
+
+      test-fuzz:
+        desc: Conduct fuzzing tests.#
+        cmds:  
+          - echo "Conduct fuzzing tests."
+          - go test -v -fuzztime=30s -fuzz=Fuzz ./...
+
+      add-licenses:
+        desc: Attach license headers to Go files.
+        cmds:
+          - echo "Attach license headers to Go files."
+          - go install github.com/google/addlicense@latest
+          - addlicense -c "schukai GmbH" -s -l "AGPL-3.0" ./*.go
+        silent: true
+        
+      check-licenses:
+        desc: Check license headers of Go files.
+        silent: true
+        cmds:
+          - go-licenses save "$(get-go-default-packages)"  --ignore "gitlab.schukai.com"  --force --save_path ''${DEVENV_ROOT}/licenses/
+
+      check:
+        desc: Confirm repository status.
+        cmds:
+          - git diff-index --quiet HEAD || (echo "There are uncommitted changes after running make. Please commit or stash them before running make."; exit 1)
+        silent: true
+
+      commit:
+        desc: Commit changes to the repository.
+        aliases:
+          - c
+          - ci
+          - git-commit
+        cmds:
+          - do-git-commit
+    EOF
+
+    cat <<'EOF' > .gitlab-ci.yml
+
+    # THIS FILE IS AUTOGENERATED BY THE DEVENVSHELL
+    # DO NOT EDIT THIS FILE MANUALLY
+    # INSTEAD EDIT THE DEVENVSHELL CONFIGURATION FILE devenv.nix
+    # AND OPEN A SHELL WITH THE COMMAND devenv shell
+    #
+
+    image: docker-registry.schukai.com:443/nixos-ci-devenv:latest
+
+    services:
+      - docker:dind
+
+    variables:
+      # The repo name as used in
+      # https://github.com/nix-community/NUR/blob/master/repos.json
+      NIXOS_VERSION: "23.05"
+      NIXPKGS_ALLOW_UNFREE: "1"
+      NIXPKGS_ALLOW_INSECURE: "1"
+      DOCKER_DRIVER: overlay2
+      GIT_DEPTH: 10
+
+    stages:
+      - test
+      - deploy 
+
+    before_script:
+      - nix shell nixpkgs#coreutils-full -c mkdir -p /certs/client/
+      - nix shell nixpkgs#coreutils-full -c ln -fs /etc/ssl/certs/ca-bundle.crt /certs/client/ca.pem
+      - echo > .env-gitlab-ci
+      - variables=("HOME=$HOME" "CI_COMMIT_REF_NAME=$CI_COMMIT_REF_NAME" "CI_REPOSITORY_URL=$CI_REPOSITORY_URL" "GITLAB_TOKEN=$GITLAB_TOKEN" "CI_JOB_TOKEN=$CI_JOB_TOKEN" "GITLAB_USER_EMAIL=$GITLAB_USER_EMAIL" "GITLAB_USER_NAME=\"$GITLAB_USER_NAME\"" "CI_REGISTRY_USER=$CI_REGISTRY_USER" "CI_PROJECT_ID=$CI_PROJECT_ID" "CI_PROJECT_DIR=$CI_PROJECT_DIR" "CI_API_V4_URL=$CI_API_V4_URL" "CI_PROJECT_NAME=$CI_PROJECT_NAME" "CI_COMMIT_SHORT_SHA=$CI_COMMIT_SHORT_SHA"); for var in "''${variables[@]}"; do echo "$var" >> .env-gitlab-ci; done
+      - cat .env-gitlab-ci
+
+    after_script:
+      - if [ -f .env-gitlab-ci ]; then rm .env-gitlab-ci; fi
+
+    test:
+      stage: test
+      tags:
+        - nixos
+      script:
+        - devenv shell test-lib
+
+      cache:
+        - key: nixos
+          paths:
+            - /nix/store
+      
+      artifacts:
+        paths:
+          - dist
+
+    deploy:
+      stage: deploy
+      tags:
+        - nixos
+      script:
+        - devenv shell -c deploy-lib
+
+      when: on_success
+
+      cache:
+        - key: nixos
+          paths:
+            - /nix/store
+
+
+      artifacts:
+        paths:
+          - dist   
+    EOF
+
+       
+        
+  '';
+
+  scripts.do-git-commit.exec = ''
+    #!/usr/bin/env bash
+
+    # Define colors if the terminal supports it
+    if [ -t 1 ]; then
+      RED='\033[0;31m'
+      GREEN='\033[0;32m'
+      RESET='\033[0m'
+      BOLD='\033[1m'
+    else
+      RED=""
+      GREEN=""
+      RESET=""
+    fi
+
+    step=1
+
+    reset
+    clear
+
+    # create random log file
+    LOGFILE="$(mktemp)"
+    if [ $? -ne 0 ]; then
+      echo -e "''${RED}✖ Could not create temporary log file. Exiting.''${RESET}"
+      exit 1
+    fi
+
+    log_and_display() {
+      echo -e "''${GREEN}==> $step. $1''${RESET}" | tee -a $LOGFILE
+      step=$((step + 1))
+    }
+
+    log_error_and_display() {
+      echo -e "''${RED}==> $step. $1''${RESET}" | tee -a $LOGFILE
+    }
+
+    printLogfileAndExit() {
+      exit_code=$1
+      echo -e "\n\n========================================\n\n\n"
+
+      echo -e "\n\n''${BOLD}Git and GitLab Automation Script''${RESET}\n\nI have performed the following actions:\n\n"
+      cat "$LOGFILE"
+
+      # Optional: Remove log file
+      rm -f "$LOGFILE"
+
+      if [ $exit_code -eq 0 ]; then
+        echo -e "\n''${GREEN}✔''${RESET} All actions were successful" | tee -a $LOGFILE
+      elif [ $exit_code -eq -1 ]; then
+        echo -e "\n''${RED}✖''${RESET} The script was manually cancelled" | tee -a $LOGFILE
+        exit_code=0
+      else
+        echo -e "\n''${RED}✖''${RESET} Some actions failed" | tee -a $LOGFILE
+      fi
+
+      exit $exit_code
+    }
+
+    print_headline() {
+      local title=$1
+      local underline=$(printf '─%.0s' $(seq 1 ''${#title}))
+      echo -e "\n\n''${BOLD}''${title}\n''${underline}''${RESET}\n"
+    }
+
+    do_cancel() {
+      echo -e "''${RED}==> ✖ Cancelled.''${RESET}" | tee -a $LOGFILE
+      printLogfileAndExit -1
+    }
+
+    # Function for unified logging and display
+    log_action() {
+      if [ $? -eq 0 ]; then
+        echo -e "    ''${GREEN}✔''${RESET} $1: Successful" | tee -a $LOGFILE
+      else
+        echo -e "    ''${RED}✖''${RESET} $1: Failed" | tee -a $LOGFILE
+        printLogfileAndExit 1
+      fi
+    }
+
+    print_what_to_do() {
+      echo -e "\n\nWhat do you want to do?\n"
+    }
+
+    git_status=$(git status --porcelain)
+    if [[ -z "$git_status" ]]; then
+      log_error_and_display "No changes to commit. Exiting."
+      printLogfileAndExit 0
+    fi
+
+    print_headline "Choose commit type"
+    selection=$(gum choose "feat: (new feature for the user, not a new feature for build script)" "fix: (bug fix for the user, not a fix to a build script)" "chore: (updating grunt tasks etc.; no production code change)" "docs: (changes to the documentation)" "style: (formatting, missing semi colons, etc; no production code change)" "refactor: (refactoring production code, eg. renaming a variable)" "test: (adding missing tests, refactoring tests; no production code change)" "Cancel")
+
+    commit_type=$(echo "$selection" | awk -F':' '{print $1}')
+
+    if [[ "$commit_type" == "Cancel" ]]; then
+      do_cancel
+    fi
+
+    log_and_display "You chose the commit type: $commit_type"
+
+    # NEXT STEP ISSUE HANDLING ############################################################################################################
+    #log_and_display "Issue handling"
+
+    gitlabIssues=()
+    while IFS= read -r line; do
+      if [[ $line =~ ^# ]]; then
+        id=$(echo "$line" | awk '{print substr($1, 2)}')
+        title=$(echo "$line" | awk -F'about' '{print $1}' | awk '{$1=$2=""; print substr($0, 3)}')
+        gitlabIssues+=("$id > $title")
+      fi
+    done < <(gum spin --spinner dot --show-output --title "Ask gitlab ..." -- glab issue list --output-format=details)
+
+    ## if issues are available, ask if user wants to use an existing issue or create a new one
+    createOption="Create new issue"
+    existingOption="Use existing issue"
+    cancelOption="Cancel"
+
+    print_headline "Choose issue handling"
+    if [ ''${#gitlabIssues[@]} -eq 0 ]; then
+      log_and_display "There are no issues available."
+
+      print_what_to_do
+      choice=$(gum choose "$createOption" "$cancelOption")
+
+    else
+      log_and_display "There are ''${#gitlabIssues[@]} issues available."
+      print_what_to_do
+      choice=$(gum choose "$createOption" "$existingOption" "$cancelOption")
+    fi
+
+    if [[ "$choice" == "$cancelOption" ]]; then
+      do_cancel
+    fi
+
+    ## array of issue ids
+    work_on_issue_ids=()
+
+    issue_text=""
+
+    if [[ "$choice" == "$createOption" ]]; then
+      print_headline "Create new issue"
+      issue_text=$(gum input --placeholder "Enter issue title")
+      echo -e "Enter issue description. ''${RED}End with Ctrl+D''${RESET}\n"
+      issue_description=$(gum write --placeholder "Enter issue description. End with Ctrl+D")
+      
+      if [[ -z "$issue_text" ]]; then
+        log_error_and_display "Issue title is empty. Exiting."
+        printLogfileAndExit 1
+      fi
+
+      log_and_display "You entered the issue title: $issue_text"
+      log_and_display "You entered the issue description: $issue_description"
+      echo -e "\n"
+
+      gum confirm "Do you want to create this issue?"
+      # gum confirm exits with status 0 if confirmed and status 1 if cancelled.
+      if [ $? -eq 1 ]; then
+        do_cancel
+      fi
+
+      issue_output=$(glab issue create -t"$issue_text" --no-editor --description "$issue_description")
+      issue_id=$(echo "$issue_output" | grep -oP '(?<=/issues/)\d+')
+
+      work_on_issue_ids+=("$issue_id")
+
+      log_action "glab issue with id $issue_id created"
+
+    else
+
+      print_headline "Use existing issue"
+      echo -e "Select issue with arrow keys and press tab or space to select. Press enter to confirm.\n"
+      issue_ids=$(gum choose --no-limit "''${gitlabIssues[@]}")
+
+      # assign issue_ids to work_on_issue_ids. iterate over lines and take integer from beginning of line
+      while IFS= read -r line; do
+        work_on_issue_ids+=($(echo "$line" | grep -oP '^\d+'))
+      done <<<"$issue_ids"
+
+    fi
+
+    if [ ''${#work_on_issue_ids[@]} -eq 0 ]; then
+      log_and_display "No issue selected. Exiting."
+      printLogfileAndExit 0
+    fi 
+
+    # NEXT STEP COMMIT MESSAGE ############################################################################################################
+    # print work_on_issue_ids
+    work_on_issue_ids_string=""
+    for i in "''${work_on_issue_ids[@]}"; do
+      work_on_issue_ids_string+="#$i "
+    done
+
+    log_and_display "You chose to work on the following issues: ''${work_on_issue_ids_string}"
+
+
+    print_headline "Check for changes to commit"
+
+    # ' ' = unmodified
+    # M = modified
+    # T = file type changed (regular file, symbolic link or submodule)
+    # A = added
+    # D = deleted
+    # R = renamed
+    # C = copied (if config option status.renames is set to "copies")
+    # U = updated but unmerged
+    # https://man.freebsd.org/cgi/man.cgi?query=git-status&sektion=1&manpath=freebsd-release-ports
+
+    count_all_changes=$(echo "$git_status" | wc -l)
+    count_staged_changes=$(echo "$git_status" | grep -c '^M')
+    count_new_staged_files=$(echo "$git_status" | grep -c '^A')
+    count_staged_changes=$((count_staged_changes + count_new_staged_files))
+
+
+
+    git_options_all="All $count_all_changes changes"
+    git_options_staged="Only the $count_staged_changes staged changes"
+    git_options_select_files="Select files"
+    git_options_cancel="Cancel"
+
+    git_options_array=()
+    if [[ $count_all_changes -gt 0 ]]; then
+      git_options_array+=("$git_options_all")
+    fi
+
+    if [[ $count_staged_changes -gt 0 ]]; then
+      git_options_array+=("$git_options_staged")
+    fi
+
+    git_options_array+=( "$git_options_select_files" )
+    git_options_array+=( "$git_options_cancel" )
+
+
+    selection=$(gum choose "''${git_options_array[@]}")
+    if [[ "$selection" == "$git_options_cancel" ]]; then
+      do_cancel
+    fi
+
+    if [[ "$selection" == "$git_options_all" ]]; then
+      git add -A
+      echo "1"
+    elif [[ "$selection" == "$git_options_select_files" ]]; then
+
+      files=()
+      while IFS= read -r line; do
+        files+=("$line")
+      done <<<"$git_status"
+        
+      selected_files=$(gum choose --no-limit "''${files[@]}")
+      
+      # no files selected
+      if [[ -z "$selected_files" ]]; then
+        log_and_display "No files selected. Exiting."
+        printLogfileAndExit 0
+      fi
+
+      # add selected files
+      while IFS= read -r line; do
+        ## git proclimne could have letter, ? or ! at the beginning of the line
+        file=$(echo "$line" | awk '{print $2}')
+        if [[ -z "$file" || ! -f "$file" ]]; then
+          log_and_display "No file found in line: $line"
+          continue
+        fi
+        
+        git add "$file"
+      done <<<"$selected_files"
+      
+    fi
+
+    ## count staged changes again and print
+    count_staged_changes=$(echo "$git_status" | grep -c '^M')
+    count_new_staged_files=$(echo "$git_status" | grep -c '^A')
+    count_staged_changes=$((count_staged_changes + count_new_staged_files))
+
+    log_and_display "You have $count_staged_changes staged changes to commit."
+
+    # NEXT STEP COMMIT MESSAGE ############################################################################################################
+
+    print_headline "Enter commit message"
+    commit_message=$(gum input --placeholder "Enter commit message" --value "$commit_type: $issue_text $work_on_issue_ids_string")
+
+    if [[ -z "$commit_message" ]]; then
+      log_error_and_display "Commit message is empty. Exiting."
+      printLogfileAndExit 1
+    fi
+
+    log_and_display "You entered the commit message: $commit_message"
+
+    gum confirm "Do you want to commit with this message?"
+    if [ $? -eq 1 ]; then
+      do_cancel
+    fi
+
+    # NEXT STEP COMMIT ####################################################################################################################
+    print_headline "Committing changes"
+
+    if ! git commit -m "$commit_message" ; then
+      log_error_and_display "Commit failed. Exiting."
+      printLogfileAndExit 1
+    fi
+
+    log_and_display "Commit successful."
+
+    # NEXT STEP PUSH ######################################################################################################################
+
+    print_headline "Pushing changes"
+
+    if ! git push ; then
+      log_error_and_display "Push failed. Exiting."
+      printLogfileAndExit 1
+    fi
+
+    log_and_display "Push successful."
+
+    # Close issue ######################################################################################################################
+
+    print_headline "Closing issues"
+
+    for issue_id in "''${work_on_issue_ids[@]}"; do
+      
+      gum confirm "Do you want to close issue #$issue_id?"
+      if [ $? -eq 1 ]; then
+        continue
+      fi
+      
+      if ! glab issue close "$issue_id" ; then
+        log_error_and_display "Closing issue $issue_id failed. Exiting."
+      else
+        log_and_display "Closing issue $issue_id successful."  
+      fi
+    done
 
+    printLogfileAndExit 0
+  '';
 
 }
diff --git a/go.mod b/go.mod
index 8b36c5e..caac104 100644
--- a/go.mod
+++ b/go.mod
@@ -12,7 +12,7 @@ require (
 	github.com/stretchr/testify v1.8.4
 	gitlab.schukai.com/oss/libraries/go/application/xflags v1.9.0
 	gitlab.schukai.com/oss/libraries/go/network/http-negotiation v1.3.1
-	gitlab.schukai.com/oss/libraries/go/utilities/pathfinder v0.5.2
+	gitlab.schukai.com/oss/libraries/go/utilities/pathfinder v0.9.1
 	gitlab.schukai.com/oss/libraries/go/utilities/watch v0.3.0
 	golang.org/x/exp v0.0.0-20230905200255-921286631fa9
 	gopkg.in/yaml.v3 v3.0.1
diff --git a/go.sum b/go.sum
index a24095f..30ff20c 100644
--- a/go.sum
+++ b/go.sum
@@ -66,6 +66,26 @@ gitlab.schukai.com/oss/libraries/go/utilities/pathfinder v0.3.1 h1:oyElaqEiyr2Xg
 gitlab.schukai.com/oss/libraries/go/utilities/pathfinder v0.3.1/go.mod h1:UvdD4NAf3gLKYafabJD7e9ZCOetzM9JZ9y4GkZukPVU=
 gitlab.schukai.com/oss/libraries/go/utilities/pathfinder v0.5.2 h1:R+dL2NJCM+AQNPK4DPDmfvx1eomi1Xb1dl0XKEFj7Ek=
 gitlab.schukai.com/oss/libraries/go/utilities/pathfinder v0.5.2/go.mod h1:UvdD4NAf3gLKYafabJD7e9ZCOetzM9JZ9y4GkZukPVU=
+gitlab.schukai.com/oss/libraries/go/utilities/pathfinder v0.5.3 h1:pl5XnGS6lxBCI98pnqNU0D0qt19X7g7/Qf/ycM4Do44=
+gitlab.schukai.com/oss/libraries/go/utilities/pathfinder v0.5.3/go.mod h1:0vlu9GwsHHuFTm49FSOs60UN3KDgcrcfDeCxsG3Ygyg=
+gitlab.schukai.com/oss/libraries/go/utilities/pathfinder v0.6.0 h1:1edcW7HB2VvTqzFUEGnnJih316sJvBvwGxBwMP8m3ho=
+gitlab.schukai.com/oss/libraries/go/utilities/pathfinder v0.6.0/go.mod h1:MqCBFv7DXKoBE2rZDc51LGvl2QI7Kz0D+XkQ0izj+ws=
+gitlab.schukai.com/oss/libraries/go/utilities/pathfinder v0.7.0 h1:ReofKz+Ys4d2l4y4Whwfbtj7CQPEL1ew46QTf1kPW7A=
+gitlab.schukai.com/oss/libraries/go/utilities/pathfinder v0.7.0/go.mod h1:MqCBFv7DXKoBE2rZDc51LGvl2QI7Kz0D+XkQ0izj+ws=
+gitlab.schukai.com/oss/libraries/go/utilities/pathfinder v0.7.1 h1:NRlSHy8DlWhkmZkHzjjdPj7hQMrpL8K8V9an9JW9UAk=
+gitlab.schukai.com/oss/libraries/go/utilities/pathfinder v0.7.1/go.mod h1:MqCBFv7DXKoBE2rZDc51LGvl2QI7Kz0D+XkQ0izj+ws=
+gitlab.schukai.com/oss/libraries/go/utilities/pathfinder v0.7.2 h1:LF9b1UiWpShxld9Re4VnvkRt3oi3KqTqpSaU21F9tKg=
+gitlab.schukai.com/oss/libraries/go/utilities/pathfinder v0.7.2/go.mod h1:MqCBFv7DXKoBE2rZDc51LGvl2QI7Kz0D+XkQ0izj+ws=
+gitlab.schukai.com/oss/libraries/go/utilities/pathfinder v0.8.0 h1:jG/kDUsBgaqIHLoMiF4cJA627neqf9BwaoKFMaMMB6U=
+gitlab.schukai.com/oss/libraries/go/utilities/pathfinder v0.8.0/go.mod h1:MqCBFv7DXKoBE2rZDc51LGvl2QI7Kz0D+XkQ0izj+ws=
+gitlab.schukai.com/oss/libraries/go/utilities/pathfinder v0.8.1 h1:A3KvLvu4rV3OstgEn6xHulhQaXawVvzFzbafYHWHUfs=
+gitlab.schukai.com/oss/libraries/go/utilities/pathfinder v0.8.1/go.mod h1:MqCBFv7DXKoBE2rZDc51LGvl2QI7Kz0D+XkQ0izj+ws=
+gitlab.schukai.com/oss/libraries/go/utilities/pathfinder v0.8.2 h1:Gs06CcP/pvywyO86dAsv2fmJfwPoJrTjN9fX7CqT/54=
+gitlab.schukai.com/oss/libraries/go/utilities/pathfinder v0.8.2/go.mod h1:MqCBFv7DXKoBE2rZDc51LGvl2QI7Kz0D+XkQ0izj+ws=
+gitlab.schukai.com/oss/libraries/go/utilities/pathfinder v0.9.0 h1:YJHX4IDO+1c+AufidfYBcfZA8OlvLsqs8K9Hq4R8icY=
+gitlab.schukai.com/oss/libraries/go/utilities/pathfinder v0.9.0/go.mod h1:MqCBFv7DXKoBE2rZDc51LGvl2QI7Kz0D+XkQ0izj+ws=
+gitlab.schukai.com/oss/libraries/go/utilities/pathfinder v0.9.1 h1:WpM6PcFqQZWPBGDEuMILWHq98dPVBLAxi8ae9QMWWbM=
+gitlab.schukai.com/oss/libraries/go/utilities/pathfinder v0.9.1/go.mod h1:MqCBFv7DXKoBE2rZDc51LGvl2QI7Kz0D+XkQ0izj+ws=
 gitlab.schukai.com/oss/libraries/go/utilities/watch v0.1.0 h1:FAKHmf9p3NKyzuM0cIXYBxmhdQ7zJ+6wj5qqeoIMbGc=
 gitlab.schukai.com/oss/libraries/go/utilities/watch v0.1.0/go.mod h1:tMFl68peRKHgFQLltrTN3JLredofMqvGi3C0SEAj73Y=
 gitlab.schukai.com/oss/libraries/go/utilities/watch v0.2.0 h1:tLjN9Wyv+LJhtiiQDzdzaDelEq2LVCDP3Ndo7ZPIWfQ=
diff --git a/import.go b/import.go
index 8fddd9f..3139764 100644
--- a/import.go
+++ b/import.go
@@ -6,15 +6,16 @@ package configuration
 import (
 	"bytes"
 	"encoding/json"
-	"reflect"
-
+	"fmt"
 	"github.com/imdario/mergo"
 	"github.com/magiconair/properties"
 	"github.com/pelletier/go-toml/v2"
+	"gitlab.schukai.com/oss/libraries/go/utilities/pathfinder"
 	"gopkg.in/yaml.v3"
 	"io"
 	"os"
 	"path"
+	"reflect"
 )
 
 func importJson[C any](config *C, reader io.Reader) error {
@@ -94,87 +95,65 @@ func (s *Settings[C]) importStreams() {
 	}
 }
 
-func replacePath(p string, c interface{}) {
-	cValue := reflect.ValueOf(c)
+var typeOfPathValue PathValue
 
-	// If c is of type PathValue (which implements pathInterface), modify the path
-	if cValue.Type() == reflect.TypeOf(PathValue("")) {
-		pathVal := cValue.Interface().(PathValue)
-		if !path.IsAbs(pathVal.String()) {
-			newPath := PathValue(path.Join(p, pathVal.String()))
-			if cValue.CanSet() {
-				cValue.Set(reflect.ValueOf(newPath))
-			}
-		}
-		return
-	}
+// replacePath replaces all relative paths with absolute paths
+func replacePath[C any](basePath string, c C) error {
 
-	// If c is not a struct, simply return
-	if cValue.Kind() != reflect.Ptr || cValue.Elem().Kind() != reflect.Struct {
-		return
-	}
+	paths := []string{}
 
-	fields := reflect.VisibleFields(cValue.Elem().Type())
-	for _, field := range fields {
-		r := cValue.Elem().FieldByName(field.Name)
-		handleField(p, r)
-	}
-}
+	top := reflect.TypeOf(typeOfPathValue)
+	toc := reflect.ValueOf(c)
+	ptp := &paths
 
-func handleField(p string, r reflect.Value) {
-	switch r.Kind() {
-	case reflect.Struct:
-		if r.CanAddr() {
-			replacePath(p, r.Addr().Interface())
+	pathfinder.FindPaths(toc, top, []string{}, ptp)
+
+	for _, px := range paths {
+
+		p, err := pathfinder.GetValue[C](c, px)
+		if err != nil {
+			return err
 		}
-	case reflect.Slice:
-		for i := 0; i < r.Len(); i++ {
-			elem := r.Index(i)
-			if elem.Type() == reflect.TypeOf(PathValue("")) {
-				pathVal := elem.Interface().(PathValue)
-				if !path.IsAbs(pathVal.String()) {
-					newPath := PathValue(path.Join(p, pathVal.String()))
-					if elem.CanSet() {
-						elem.Set(reflect.ValueOf(newPath))
-					}
-				}
-			} else if elem.CanAddr() {
-				replacePath(p, elem.Addr().Interface())
+
+		switch p.(type) {
+		case PathValue:
+			tp, ok := p.(PathValue)
+			if !ok {
+				return fmt.Errorf("type assertion failed")
 			}
-		}
-	case reflect.Map:
-		for _, k := range r.MapKeys() {
-			elem := r.MapIndex(k)
-			if elem.Type() == reflect.TypeOf(PathValue("")) {
-				pathVal := elem.Interface().(PathValue)
-				if !path.IsAbs(pathVal.String()) {
-					newPath := PathValue(path.Join(p, pathVal.String()))
-					r.SetMapIndex(k, reflect.ValueOf(newPath))
+
+			if !path.IsAbs(p.(PathValue).String()) {
+				newPath := PathValue(path.Join(basePath, tp.String()))
+
+				switch reflect.TypeOf(p).Kind() {
+				case reflect.Ptr:
+					err = pathfinder.SetValue[C](c, px, &newPath)
+
+				case reflect.String:
+					if px == "G.I.key1GI.A" {
+					}
+
+					err = pathfinder.SetValue[C](c, px, newPath.String())
+
+				default:
+					err = pathfinder.SetValue[C](c, px, newPath)
 				}
-			} else if elem.CanAddr() {
-				replacePath(p, elem.Addr().Interface())
-			}
-		}
-	default:
-		// Check for pathInterface
-		if v, ok := r.Interface().(pathInterface); ok {
-			// Check if r is nil
-			if r.Kind() == reflect.Ptr && r.IsNil() {
-				return
-			}
-			currentPath := v.String()
-			if r.CanSet() && !path.IsAbs(currentPath) {
-				if r.Type() == reflect.TypeOf(PathValue("")) {
-					r.Set(reflect.ValueOf(PathValue(path.Join(p, currentPath))))
+
+				if err != nil {
+					return err
 				}
 			}
 		}
+
 	}
+
+	return nil
+
 }
 
 func (s *Settings[C]) importFiles() {
 
-        defer func() {
+	defer func() {
 		s.notifyErrorHooks()
 	}()
 
@@ -190,7 +169,7 @@ func (s *Settings[C]) importFiles() {
 
 		r := (io.Reader)(f)
 		s.importStream(reader{s.files.format, r}, func(c *C) {
-			replacePath(d, c)
+			replacePath[*C](d, c)
 		})
 		_ = f.Close()
 	}
@@ -206,7 +185,10 @@ func (s *Settings[C]) importFiles() {
 
 		s.importStream(reader{f.format, r}, func(c *C) {
 			d := path.Dir(f.path)
-			replacePath(d, c)
+			err := replacePath[*C](d, c)
+			if err != nil {
+				return
+			}
 		})
 
 		_ = r.Close()
diff --git a/import_test.go b/import_test.go
index 490d2e7..98fbd03 100644
--- a/import_test.go
+++ b/import_test.go
@@ -1,10 +1,11 @@
-// Copyright 2022 schukai GmbH
+// Copyright 2023 schukai GmbH
 // SPDX-License-Identifier: AGPL-3.0
 
 package configuration
 
 import (
 	"github.com/stretchr/testify/assert"
+	"path/filepath"
 	"testing"
 )
 
@@ -27,3 +28,85 @@ func TestReadExample3(t *testing.T) {
 	assert.Equal(t, c.Config().Host, "localhost")
 
 }
+
+type TestStruct struct {
+	Path1 PathValue
+	Path2 string
+	Path3 []PathValue
+}
+
+func TestReplacePath2(t *testing.T) {
+	testData := TestStruct{
+		Path1: "relative/path1",
+		Path2: "relative/path2",
+		Path3: []PathValue{"relative/path3", "relative/path4"},
+	}
+	basePath := "/base"
+
+	err := replacePath[*TestStruct](basePath, &testData)
+	assert.Nil(t, err)
+
+	expectedPath1 := PathValue(filepath.Join(basePath, "relative/path1"))
+	if testData.Path1 != expectedPath1 {
+		t.Errorf("Expected %s, got %s", expectedPath1, testData.Path1)
+	}
+
+	// no pathValue
+	expectedPath2 := "relative/path2"
+	if testData.Path2 != expectedPath2 {
+		t.Errorf("Expected %s, got %s", expectedPath2, testData.Path2)
+	}
+
+	expectedPath3 := []PathValue{PathValue(filepath.Join(basePath, "relative/path3")), PathValue(filepath.Join(basePath, "relative/path4"))}
+	if testData.Path3[0] != expectedPath3[0] {
+		t.Errorf("Expected %s, got %s", expectedPath3[0], testData.Path3[0])
+	}
+
+	if testData.Path3[1] != expectedPath3[1] {
+		t.Errorf("Expected %s, got %s", expectedPath3[1], testData.Path3[1])
+	}
+}
+
+type SubTestSubPaths struct {
+	Template    PathValue
+	Definitions []PathValue
+}
+
+type SubTest2Def struct {
+	Paths SubTestSubPaths
+}
+
+type SubTestStruct1 map[string]SubTest2Def
+type MainTestStruct struct {
+	Sub SubTestStruct1
+}
+
+func TestReplacePathForConfig(t *testing.T) {
+	config := MainTestStruct{
+		Sub: SubTestStruct1{
+			"Default": SubTest2Def{
+				Paths: SubTestSubPaths{
+					Template:    "../../../default.html",
+					Definitions: []PathValue{"../../../legacy.yaml"},
+				},
+			},
+		},
+	}
+
+	basePath := "/base/1/2/3/"
+
+	err := replacePath[*MainTestStruct](basePath, &config)
+	if err != nil {
+		t.Error(err)
+	}
+
+	expectedTemplatePath := PathValue(filepath.Join(basePath, "../../../default.html"))
+	if config.Sub["Default"].Paths.Template != expectedTemplatePath {
+		t.Errorf("Expected %s, got %s", expectedTemplatePath, config.Sub["Default"].Paths.Template)
+	}
+
+	expectedDefinitionPath := PathValue(filepath.Join(basePath, "../../../legacy.yaml"))
+	if config.Sub["Default"].Paths.Definitions[0] != expectedDefinitionPath {
+		t.Errorf("Expected %s, got %s", expectedDefinitionPath, config.Sub["Default"].Paths.Definitions[0])
+	}
+}
diff --git a/integration_test.go b/integration_test.go
index c5f1b92..baa0748 100644
--- a/integration_test.go
+++ b/integration_test.go
@@ -4,7 +4,6 @@
 package configuration
 
 import (
-	"fmt"
 	"os"
 	"testing"
 )
@@ -21,7 +20,6 @@ func Fuzz1Test(f *testing.F) {
 
 		s := New(config)
 
-		fmt.Println("A:", a, "B:", b, "F:", f)
 
 		if s == nil {
 			t.Error("Expected not nil")
diff --git a/issue-7_test.go b/issue-7_test.go
index 711714f..33d6437 100644
--- a/issue-7_test.go
+++ b/issue-7_test.go
@@ -5,7 +5,6 @@ package configuration
 
 import (
 	"github.com/stretchr/testify/assert"
-	"io/ioutil"
 	"os"
 	"path"
 	"path/filepath"
@@ -26,7 +25,7 @@ type Issue7Config struct {
 }
 
 func createIssue7TempFile(content string) (string, error) {
-	file, err := ioutil.TempFile("", "tempfile")
+	file, err := os.CreateTemp("", "tempfile")
 	if err != nil {
 		return "", err
 	}
@@ -100,7 +99,8 @@ func TestIssue7ReplacePath(t *testing.T) {
 		C: 42,
 	}
 
-	replacePath(basePath, &ts1)
+	err := replacePath[*Issue7TestStruct1](basePath, &ts1)
+	assert.Nil(t, err)
 
 	if ts1.A != PathValue(path.Join(basePath, "relative/path")) {
 		t.Errorf("Expected '%s', got '%s'", path.Join(basePath, "relative/path"), ts1.A)
@@ -118,7 +118,8 @@ func TestIssue7ReplacePath(t *testing.T) {
 		E: "justastring",
 	}
 
-	replacePath(basePath, &ts2)
+	err = replacePath[*Issue7TestStruct2](basePath, &ts2)
+	assert.Nil(t, err)
 
 	if ts2.A != PathValue(path.Join(basePath, "another/relative/path")) {
 		t.Errorf("Expected '%s', got '%s'", path.Join(basePath, "another/relative/path"), ts2.A)
@@ -220,7 +221,8 @@ func TestReplacePath(t *testing.T) {
 	// Copy the struct to compare later
 	original := *s
 
-	replacePath(basePath, s)
+	err := replacePath[*MyStruct](basePath, s)
+	assert.Nil(t, err)
 
 	// Checking each field to ensure replacePath works as expected
 	if s.A != original.A && !path.IsAbs(s.A.String()) {
diff --git a/licenses/github.com/pelletier/go-toml/v2/LICENSE b/licenses/github.com/pelletier/go-toml/v2/LICENSE
index 6839d51..991e2ae 100644
--- a/licenses/github.com/pelletier/go-toml/v2/LICENSE
+++ b/licenses/github.com/pelletier/go-toml/v2/LICENSE
@@ -1,6 +1,7 @@
 The MIT License (MIT)
 
-Copyright (c) 2013 - 2022 Thomas Pelletier, Eric Anderton
+go-toml v2
+Copyright (c) 2021 - 2023 Thomas Pelletier
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
-- 
GitLab