#!/usr/bin/bash
#
# Copyright (C) 2022-2026 Red Hat, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.

PID=
PID2=
RET=0
KILLED=
ERROR=
FORCE_CHECK=
NO_CHECK=
declare -A ALL_DIRS
declare -A NAME_TO_PIPELINE
declare -A NAME_TO_QUEUE

PROJECTS=(
    ansible-collection-ansible-posix
    ansible-collection-community-general
    ansible-collection-community-libvirt
    ansible-collection-containers-podman
    ansible-collection-kubernetes-core
    ansible-collection-redhatci-ocp
    ansible-role-dci-podman
    ansible-role-dci-sync-registry
    dci-ansible
    dci-openshift-agent
    dci-openshift-app-agent
    python-dciauth
    python-dciclient
    python-kubernetes
)
PROJECTS_REGEX=$(printf '%s|' "${PROJECTS[@]}")
PROJECTS_REGEX=${PROJECTS_REGEX%|}

error() {
    ERROR="$1"
    RET=2
    $BASEDIR/send_status "$DIR" error "ERROR Unable to start a job on distributed-ci.io: $ERROR"
    exit $RET
}

finish() {
    echo "finish $*"

    if [ -n "$PID" ]; then
        kill $PID

        wait $PID
        RET=$?
    fi

    if [ -n "$PID2" ]; then
        kill $PID2
    fi

    if [ -z "$NO_CHECK" ] && [ -z "$ERROR" ]; then
        # Same regex as in dci-queue dci-job command
        job_regex='^.*running jobdef: ([0-9a-z.-]+) with.*/([0-9a-f-]+) .*$'

        JOBIDS=($(sed -n -r 's,'"${job_regex}"',\1:\2,ip' < output))
        LENGTH=${#JOBIDS[@]}

        # Get the exit code of the last job
        if [ $RET = 0 ]; then
            LAST_RESULT="SUCCESS"
            STATUS=success
        elif [ $RET -gt 128 ]; then
            LAST_RESULT="KILLED"
            STATUS=cancelled
            KILLED=1
        elif [ $RET = 2 ]; then
            LAST_RESULT="ERROR"
            STATUS=error
        else
            LAST_RESULT="FAILURE"
            STATUS=failure
        fi

        RESULT=
        if [ ${LENGTH} -ge 1 ]; then
            for JOBID in ${JOBIDS[@]}; do
                job_result=$(sed -n -r 's/^.*Jobdef '"${JOBID%:*}"' status=(\w+)$/\1/p' < output )
                # If the job does not have a status, use the last result
                if [[ -z "${job_result}" ]]; then
                    job_result=${LAST_RESULT}
                fi
                DCI_URL="https://www.distributed-ci.io/jobs/${JOBID##*:}/jobStates"
                RESULT+="- ${job_result^^} $DCI_URL\n"
            done
        elif [ ${LENGTH} -eq 0 ]; then
            SAVEDIR="$(mktemp -d /tmp/test-runner-$(date --iso-8601=seconds).XXXXXXXXXX)"
            cp -a . "${SAVEDIR}"
            DCI_URL=
            RESULT+="- ERROR no DCI job found"
        fi

        $BASEDIR/send_status "$DIR" "$STATUS" "$LAST_RESULT" $DCI_URL

        if [ -z "$KILLED" ]; then
            # Send alert for unsuccessful jobs in github repos
            if [[ " ERROR FAILURE " =~ "${LAST_RESULT} " ]] &&
               [[ -n "${REPO}" ]]; then
                $BASEDIR/alert "${REPO}" "${RESULT} from ${URL}"
            fi
            # Send comment
            $BASEDIR/send_comment "$DIR" "from change $URL:\n$RESULT"
        fi
    fi

    cd

    # Workaround to delete any temporary directory created without u+w
    find "${DIR}" -type d -not -perm -u=w -exec chmod u+w {} \;
    [ -f "$DIR"/.keep ] || rm -rf "$DIR"

    exit $RET
}

get_project() {
    local path="$1"
    local dir
    local project
    if [ ! -d "$path" ]; then
        dir="$(dirname "$path")"
        if [ "$dir" = "$path" ]; then
            return
        fi
        get_project "$dir"
        return
    else
        dir="$path"
    fi
    project=$(cd "$dir"; basename $(git config --local remote.origin.url 2> /dev/null) .git)
    if [ -n "$project" ] && [ "$project" != .git ]; then
        ALL_DIRS["$project"]=$(cd "$dir"; git rev-parse --show-toplevel)
    fi
}

extract_dirs() {
    for path in $(grep -vP "^s*#.*" "$@" |
            grep -Po "[\s,[\"']/[\w/._-]+" |
            sed -e "s#[ ,[\"']##g" |
            sort -u); do
        get_project "$path"
    done
}

TOPDIR=$(cd $(dirname $0); pwd)

if [[ $0 =~ .*-podman$ ]]; then
    SUFFIX=-podman
else
    SUFFIX=
fi

if [ -r "$TOPDIR/common$SUFFIX" ]; then
    BASEDIR="$TOPDIR"
else
    BASEDIR=/usr/share/dci-pipeline
fi

source "$BASEDIR/common$SUFFIX"

PIPELINES_REPO=$(cd "$PIPELINES_DIR" && basename $(git config --local remote.origin.url) .git)

if [ -n "$DCI_QUEUE_RESOURCE" ]; then
    if [ $# -lt 2 ]; then
        echo "Usage: $0 <change directory> [<kubeconfig path>] <pipeline name> [(<pipeline name2>|<pipeline var>)*]" 1>&2
        exit 1
    fi

    DIR="$1"
    RES="$DCI_QUEUE_RESOURCE"
    shift 1
else
    if [ $# -lt 3 ]; then
        echo "Usage: $0 <change directory> <resource> [<kubeconfig path>] <pipeline name> [(<pipeline name2>|<pipeline var>)*]" 1>&2
        exit 1
    fi

    DIR=$1
    RES=$2
    shift 2
fi

if [ ! -d $DIR ]; then
    echo "No such directory $DIR" 1>&2
    exit 1
fi

trap finish 0

# check that the KUBECONFIG is working
if [[ "$1" =~ .*/kubeconfig ]]; then
    export KUBECONFIG="$1"
    OCPVERS=$(oc version -o json|jq -r .openshiftVersion)
    OCPVERS=${OCPVERS%%-*}
    # extract the DCI topic
    case $OCPVERS in
        *.*.*)
            OCP_TOPIC=OCP-${OCPVERS%.*}
            ;;
        *.*)
            OCP_TOPIC=OCP-$OCPVERS
            ;;
        *)
            error "Unsupported OCP version scheme: $OCPVERS"
            ;;
    esac
    shift
fi

set -x

CHANGEID="$(basename $DIR)"
CHANGEID=${CHANGEID%%-*}

# extract github or gerrit from the path
KIND="$(basename $(dirname $DIR))"
cd "$DIR" || exit 1

$BASEDIR/send_status "$DIR" pending "DCI pipeline started"

if [ "$KIND" = gerrit ]; then
    PROJECT="$(jq -r .project $CHANGEID.json)"
    NUMBER="$(jq -r ._number $CHANGEID.json)"
    TAGS="ansible_extravars=dci_tags:debug,gerrit:$PROJECT-$CHANGEID"
    URL="https://softwarefactory-project.io/r/#/c/$CHANGEID/"
    PIPELINENAME=gr-$PROJECT-$NUMBER
    BODY="$(cd $PROJECT || exit 1; git log -1)"
else
    REPO=$(jq -r .head.repo.name github.json)
    NUMBER=$(jq -r .number github.json)
    TAGS="ansible_extravars=dci_tags:debug,github:$REPO-$NUMBER"
    URL=$(jq -r .html_url github.json)
    PIPELINENAME=pr-$REPO-$NUMBER
    BODY="$(jq -r .body github.json)"

    if [ -n "$REV_PROXY_URL" ]; then
        URL=${URL/$REV_PROXY_URL/https://github.com}
    fi
fi

# check Test-Hints: force-check string in the description of the change
if grep -iqP '^\s*Test-Hints?:\s*force-check' <<< "${BODY}"; then
    FORCE_CHECK=1
fi

# check Test-Hints: no-check string in the description of the change
if grep -iqP '^\s*Test-Hints?:\s*no-check' <<< "${BODY}"; then
    NO_CHECK=1
fi

# make sure the change is only on dci-openshift-(app-)?agent or it was passed Test-Hins: no-check
if [ -n "$NO_CHECK" ] ||
       { [ -d dci-openshift-agent -o \
           -d dci-openshift-app-agent ] &&
         [ $(ls|grep -E "${PROJECTS_REGEX}"|wc -l) -eq 1 ];
       } ||
       { [ -d dci-openshift-agent -a \
           -d dci-openshift-app-agent ] &&
         [ $(ls|grep -E "${PROJECTS_REGEX}"|wc -l) -eq 2 ];
       }; then
    if [ -n "$NO_CHECK" ]; then
        NUMBER_CODE_FILES=0
    elif [ -z "$FORCE_CHECK" ]; then
        CODE_FILES=(
            'ansible.cfg'
            'group_vars/all'
            'plays'
            'plays/scripts'
            '\.(yml|j2|py)'
        )
        CODE_FILES_REGEX=$(printf '%s|' "${CODE_FILES[@]}")
        NUMBER_CODE_FILES=$(
        (for d in dci-openshift-*agent; do
             cd $d
             git diff-tree --no-commit-id --name-only -r HEAD
             cd ..
         done
        ) |
        grep -E "(${CODE_FILES_REGEX%|})" |
        grep -Ev 'requirements.yml|.github' |
        wc -l
        )
    fi
    if [ "$NUMBER_CODE_FILES" -eq 0 ]; then
        $BASEDIR/send_status "$DIR" "success" "SUCCESS"
        $BASEDIR/send_comment "$DIR" "from change $URL:\n- no check (not a code change)"
        exit 0
    fi
fi

# compute the command line arguments according to the extracted
# directories
if [ -d "$PIPELINES_REPO" ]; then
    PIPELINES_PATH=$(cd "$PIPELINES_DIR" && git rev-parse --show-prefix)
    PIPELINES="$PWD/$PIPELINES_REPO/$PIPELINES_PATH"
else
    PIPELINES=$PIPELINES_DIR
fi

# compute pipelines and args
OCP_PIPELINES=
CNF_PIPELINES=
ZTP_NAMES=
ALL_PIPELINES=
ARGS=("@pipeline:name=$PIPELINENAME")
num=1
for arg in "$@"; do
    case "$arg" in
        -p*)
            # support multiple queues and resources by passing -p<num>
            num=${arg#-p}
            ;;
        *:*=*)
            ARGS+=("$arg")
            ;;
        *)
            # Verify if the pipeline file exists
            pipeline="$PIPELINES/${arg}-pipeline.yml"
            if [ ! -r $pipeline ]; then
                error "Unable to find $arg pipeline"
            fi
            # remove succes_tag and change fallback_last_success lines from
            # the pipelines to be sure the jobs will not tag the
            # components and launch fallback jobs
            sed -e '/success_tag/d' -e 's/fallback_last_success/allback_last_success/' < $pipeline > $PWD/$(basename $pipeline)
            pipeline="$PWD/$(basename $pipeline)"
            if grep -q -E "^\s*-?\s*ansible_playbook\s*:\s*[\"']?/usr/share/dci-openshift-app-agent/dci-openshift-app-agent.yml[\"']?" $pipeline; then
                CNF_PIPELINES="$CNF_PIPELINES $pipeline"
            else
                OCP_PIPELINES="$OCP_PIPELINES $pipeline"
                if "$BASEDIR"/yaml2json "$pipeline"|jq -r '.[].ansible_extravars.acm_cluster_type'|grep -q '^ztp-spoke$'; then
                    ZTP_NAME=$("$BASEDIR"/yaml2json "$pipeline"|jq -r '.[].name')
                    ZTP_NAMES="$ZTP_NAMES $ZTP_NAME"
                fi
            fi
            ALL_PIPELINES="$ALL_PIPELINES $pipeline"
            for NAME in $("$BASEDIR"/yaml2json "$pipeline"|jq -r '.[].name'); do
                NAME_TO_PIPELINE[$NAME]="$pipeline"
                NAME_TO_QUEUE[$NAME]="$num"
            done
            ;;
    esac
done

OCP_NAMES=
if [ -n "$OCP_PIPELINES" ]; then
    # compute the names from the ocp pipelines
    for pipeline in $OCP_PIPELINES; do
        NAMES=$("$BASEDIR"/yaml2json "$pipeline"|jq -r '.[].name')
        if [ -z "$NAMES" ]; then
            error "Unable to find ocp pipeline name for $pipeline"
        fi
        OCP_NAMES="$OCP_NAMES $NAMES"
    done
fi

CNF_NAMES=
if [ -n "$CNF_PIPELINES" ]; then
    # compute the names from the cnf pipelines
    for pipeline in $CNF_PIPELINES; do
        NAMES=$("$BASEDIR"/yaml2json "$pipeline"|jq -r '.[].name')
        if [ -z "$NAMES" ]; then
            error "Unable to find cnf pipeline name for $pipeline"
        fi
        CNF_NAMES="$CNF_NAMES $NAMES"
    done
fi

GIT_REPOS=ansible_extravars=dev_gits_to_components:
for repo in $(ls -d */.git);do
    GIT_REPOS="$GIT_REPOS$PWD/${repo%/.git},"
done

if [ -r $PIPELINES/ansible.cfg ]; then
    cp $PIPELINES/ansible.cfg ansible.cfg
else
    if [ -d dci-openshift-agent ]; then
        cp dci-openshift-agent/ansible.cfg ansible.cfg
    else
        cp /usr/share/dci-openshift-agent/ansible.cfg ansible.cfg
    fi
fi

for conf in $(ls -d *config 2> /dev/null); do
    sed -i -e "s@\(:\{0,1\}\)[^:]*$conf/@\1$PWD/$conf/@g" ansible.cfg
done

# only do these steps in non podman mode
if [ -z "$SUFFIX" ]; then
    if [ -d dci-ansible ]; then
        sed -i -e "s@/usr/share/dci/\(callback\|modules\|module_utils\|action_plugins\|filter_plugins\)@$PWD/dci-ansible/\1@g" ansible.cfg
        export DCI_ANSIBLE_DIR=$PWD/dci-ansible
    fi

    for d in $(ls -d ansible-role-dci-* 2> /dev/null); do
        if [ -r $d/tasks/main.yml ]; then
            sed -i -e "s@\(roles_path\s*=\s*\)@\1${PWD}:@" ansible.cfg
            break
        fi
    done

    ANSIBLE_COLLECTIONS_PATHS=
    for d in $(find . -maxdepth 1 -name 'ansible-collection-*' -type d -exec basename {} \; 2>/dev/null); do
        mkdir -p collections
        LOCAL_COLLECTIONS=$PWD/collections
        export ANSIBLE_COLLECTIONS_PATHS=$LOCAL_COLLECTIONS:/usr/share/ansible/collections
        cd $d
        rm -f *.tar.gz
        ansible-galaxy collection build
        ansible-galaxy collection install *.tar.gz -p $LOCAL_COLLECTIONS
        cd -
    done
fi

if [ -d dci-openshift-agent ]; then
    if [ -z "$SUFFIX" ]; then
        sed -i -e "s@include_tasks:\s*plays/@include_tasks: $PWD/dci-openshift-agent/plays/@" $PWD/dci-openshift-agent/dci-openshift-agent.yml
    fi
    for pipeline in $OCP_PIPELINES; do
        sed -i -e "s@/var/lib/dci-openshift-agent@$PWD/dci-openshift-agent@g" -e "s@ansible_playbook: /usr/share/dci-openshift-agent/dci-openshift-agent.yml@ansible_playbook: $PWD/dci-openshift-agent/dci-openshift-agent.yml@" $pipeline
    done
fi

if [ -d $PIPELINES_REPO ]; then
    PIPELINES_TOPDIR=$(cd $PIPELINES_DIR && git rev-parse --show-toplevel)
    for pipeline in $ALL_PIPELINES; do
        sed -i -e "s@$PIPELINES_TOPDIR@$PWD/$PIPELINES_REPO@" $pipeline
    done
fi

# configure the ocp playbook to run from the change
if [ -d dci-openshift-app-agent ]; then
    if [ -z "$SUFFIX" ]; then
        sed -i -e "s@include_tasks:\s*plays/@include_tasks: $PWD/dci-openshift-app-agent/plays/@" dci-openshift-app-agent/dci-openshift-app-agent.yml
    fi
    [ -r control-plane-example-pipeline.yml ] && sed -i "s@dci_config_dir: .*@dci_config_dir: $PWD/dci-openshift-app-agent/samples/control_plane_example@" control-plane-example-pipeline.yml
    [ -r control-plane-pipeline.yml ] && sed -i "s@dci_config_dir: .*@dci_config_dir: $PWD/dci-openshift-app-agent/samples/control_plane_example@" control-plane-pipeline.yml
    [ -r preflight-green-pipeline.yml ] && sed -i "s@dci_config_dir: .*@dci_config_dir: $PWD/dci-openshift-app-agent/samples/control_plane_example@" preflight-green-pipeline.yml
    [ -r preflight-pipeline.yml ] && sed -i "s@dci_config_dir: .*@dci_config_dir: $PWD/dci-openshift-app-agent/samples/control_plane_example@" preflight-pipeline.yml
    [ -r operator-sdk-pipeline.yml ] && sed -i "s@dci_config_dir: .*@dci_config_dir: $PWD/dci-openshift-app-agent/samples/control_plane_example@" operator-sdk-pipeline.yml
    [ -r tnf-test-cnf-green-pipeline.yml ] && sed -i "s@dci_config_dir: .*@dci_config_dir: $PWD/dci-openshift-app-agent/samples/tnf_test_example@" tnf-test-cnf-green-pipeline.yml
    [ -r tnf-test-cnf-pipeline.yml ] && sed -i "s@dci_config_dir: .*@dci_config_dir: $PWD/dci-openshift-app-agent/samples/tnf_test_example@" tnf-test-cnf-pipeline.yml
    [ -r tnf-test-pipeline.yml ] && sed -i "s@dci_config_dir: .*@dci_config_dir: $PWD/dci-openshift-app-agent/samples/tnf_test_example@" tnf-test-pipeline.yml
    [ -r ztp-attach-spoke-pipeline.yml ] && sed -i "s@dci_config_dir: .*@dci_config_dir: $PWD/dci-openshift-app-agent/samples/day_2_cluster_operations/attach_spoke_cluster@" ztp-attach-spoke-pipeline.yml
    [ -r ztp-detach-spoke-pipeline.yml ] && sed -i "s@dci_config_dir: .*@dci_config_dir: $PWD/dci-openshift-app-agent/samples/day_2_cluster_operations/detach_ztp_spoke_cluster@" ztp-detach-spoke-pipeline.yml

    # set the playbook on the cnf pipelines
    OCP_APP_OPT=
    for NAME in $CNF_NAMES; do
        OCP_APP_OPT="$OCP_APP_OPT $NAME:ansible_playbook=$PWD/dci-openshift-app-agent/dci-openshift-app-agent.yml"
    done
elif [ -d example-cnf-config ]; then
    # cnfapp hook
    [ -r example-cnf-pipeline.yml ] && sed -i "s@dci_config_dir: .*@dci_config_dir: $PWD/example-cnf-config/cnfapp@" example-cnf-pipeline.yml
    [ -r example-cnf-green-pipeline.yml ] && sed -i "s@dci_config_dir: .*@dci_config_dir: $PWD/example-cnf-config/cnfapp@" example-cnf-green-pipeline.yml
    [ -r example-cnf-continuous-pipeline.yml ] && sed -i "s@dci_config_dir: .*@dci_config_dir: $PWD/example-cnf-config/cnfapp@" example-cnf-continuous-pipeline.yml
    [ -r example-cnf-blue-pipeline.yml ] && sed -i "s@dci_config_dir: .*@dci_config_dir: $PWD/example-cnf-config/cnfapp@" example-cnf-blue-pipeline.yml
    # upgrade_validation hook
    [ -r example-cnf-validation-pipeline.yml ] && sed -i "s@dci_config_dir: .*@dci_config_dir: $PWD/example-cnf-config/upgrade_validation@" example-cnf-validation-pipeline.yml
    # launch_trex_job hook
    [ -r example-cnf-extra-trex-job-pipeline.yml ] && sed -i "s@dci_config_dir: .*@dci_config_dir: $PWD/example-cnf-config/launch_trex_job@" example-cnf-extra-trex-job-pipeline.yml
    # draining_validation hook
    [ -r example-cnf-draining-pipeline.yml ] && sed -i "s@dci_config_dir: .*@dci_config_dir: $PWD/example-cnf-config/draining_validation@" example-cnf-draining-pipeline.yml
    # preflight hook
    [ -r preflight-pipeline.yml ] && sed -i "s@dci_config_dir: .*@dci_config_dir: $PWD/example-cnf-config/preflight@" preflight-pipeline.yml
    [ -r preflight-green-pipeline.yml ] && sed -i "s@dci_config_dir: .*@dci_config_dir: $PWD/example-cnf-config/preflight@" preflight-green-pipeline.yml
elif [ -d grout-config ]; then
    # grout-config hook
    [ -r grout-test-pipeline.yml ] && sed -i "s@dci_config_dir: .*@dci_config_dir: $PWD/grout-config@" grout-test-pipeline.yml
else
    # use the default from the pipeline
    OCP_APP_OPT=
fi

# extract all git directories from the pipeline files into ALL_DIRS
extract_dirs $ALL_PIPELINES

for key in "${!ALL_DIRS[@]}"; do
    echo "$key => ${ALL_DIRS[$key]}"
done

# edit pipeline files to reflect local changes
for pipeline in $ALL_PIPELINES; do
    # replace the local dirs
    for local_dir in $(ls -d */); do
        local_path=${ALL_DIRS[${local_dir%/}]}
        if [ -n "$local_path" ]; then
            sed -i -e "s@${local_path}@$PWD/${local_dir%/}@g" $pipeline
        fi
    done
    # replace RES by DCI_QUEUE_RES<num> and DCI_QUEUE by DCI_QUEUE<num>
    name=$("$BASEDIR"/yaml2json "$pipeline"|jq -r '.[].name')
    num=${NAME_TO_QUEUE[$name]}
    NEW_RES=$(eval echo \$DCI_QUEUE_RES$num)
    if [ -n "$NEW_RES" ]; then
        RES="$NEW_RES"
    fi
    NEW_DCI_QUEUE=$(eval echo \$DCI_QUEUE$num)
    if [ -n "$NEW_DCI_QUEUE" ]; then
        DCI_QUEUE="$NEW_DCI_QUEUE"
    fi
    # force to use the copy of ansible.cfg and substitute @RESOURCE and @QUEUE
    sed -i -e "s/@RESOURCE/$RES/" -e "s/@QUEUE/$DCI_QUEUE/" -e "s@\(^\s*ansible_cfg:\s*\).*@\1$PWD/ansible.cfg@" $pipeline
done

cat ansible.cfg

# inject certification variables and topic
for NAME in $CNF_NAMES; do
    # Lookup a topic for CNF jobs if there is no OCP job.
    # If there is an OCP job we let the previous_topic feature do its magic.
    if [ -z "$OCP_PIPELINES" ] && [ -z "$OCP_TOPIC" ]; then
        # lookup kubeconfig_path in the pipeline
        pipeline=${NAME_TO_PIPELINE[$NAME]}
        KUBECONFIG=$("$BASEDIR"/yaml2json "$pipeline"|jq -r '.[0].extra_vars.kubeconfig_path')
        # lookup kubeconfig_path in the inventory if not found in the pipeline
        if [ -z "$KUBECONFIG" ] || [ "$KUBECONFIG" = null ]; then
            inventory=$("$BASEDIR"/yaml2json "$pipeline"|jq -r '.[0].ansible_inventory'|sed -e "s/@RESOURCE/$RES/" -e "s/@QUEUE/$DCI_QUEUE/")
            # only support yaml inventories
            KUBECONFIG=$("$BASEDIR"/yaml2json "$inventory"|jq -r '.all.vars.kubeconfig_path')
        fi
        if [ -n "$KUBECONFIG" ] && [ "$KUBECONFIG" != null ]; then
            # replace {{ lookup('env', 'HOME') }} and ~ by $HOME, and {{ cluster }} by $RES in KUBECONFIG
            KUBECONFIG=$(sed -e "s@{{\s*lookup('env',\s*'HOME')\s*}}@$HOME@" -e "s@~/@$HOME/@" -e "s@{{\s*cluster\s*}}@$RES@" <<< "$KUBECONFIG")
            OCPVERS=$(KUBECONFIG=$KUBECONFIG oc version -o json|jq -r .openshiftVersion)
            OCPVERS=${OCPVERS%%-*}
            # extract the DCI topic
            case $OCPVERS in
                *.*.*)
                    OCP_TOPIC=OCP-${OCPVERS%.*}
                    ;;
                *.*)
                    OCP_TOPIC=OCP-$OCPVERS
                    ;;
                *)
                    error "Unsupported OCP version scheme: $OCPVERS"
                    ;;
            esac
        fi
    fi
    if [ -n "$OCP_TOPIC" ]; then
        OCP_APP_OPT="$OCP_APP_OPT $NAME:topic=$OCP_TOPIC"
    fi
    if [ -d certsuite ]; then
        # export directory where certsuite code from PR is located as variable to be used in the dci-openshift-app-agent
        OCP_APP_OPT="$OCP_APP_OPT $NAME:ansible_extravars=kbpc_code_src_dir:$PWD/certsuite"
        # inject dependencies from other github PR if needed
        for d in $(sed -n -e 's@\s*github.com/[^/]*/\([^/ ]*\).*@\1@p' certsuite/go.mod); do
            if [ -d "$d" ]; then
                ORIGPKG=$(jq -r .base.repo.html_url $d-*.json|sed -e 's@https://@@')
                if [ -n "$ORIGPKG" ]; then
                    GOPKG=$(jq -r .head.repo.html_url $d-*.json|sed -e 's@.*//@@')
                    BRANCH=$(jq -r .head.ref $d-*.json)
                    # inject the replace statement at the top of the file
                    sed -i -e  "s@^\(go .*\)\$@\1\n\nreplace $ORIGPKG => $GOPKG $BRANCH\n@" certsuite/go.mod
                    head -15 certsuite/go.mod
                    # inject a go mod tiny command into the Makefile to create the correct go.sum
                    sed -i -e 's@go.mod)"$@go.mod)" \&\& go mod tidy@' certsuite/Makefile
                fi
            fi
        done
    fi
    if [ -d grout ]; then
        # export directory where grout code from PR is located as variable to be used in the dci-openshift-app-agent
        OCP_APP_OPT="$OCP_APP_OPT $NAME:ansible_extravars=grout_code_src_dir:$PWD/grout"
    fi
    if [ -d openshift-preflight ]; then
        OCP_APP_OPT="$OCP_APP_OPT $NAME:ansible_extravars=preflight_source_dir:$PWD/openshift-preflight"
    fi
    if [ -d operator-sdk ]; then
        OCP_APP_OPT="$OCP_APP_OPT $NAME:ansible_extravars=operator_sdk_source_dir:$PWD/operator-sdk"
    fi
    if [ -d eco-gotests ]; then
        OCP_APP_OPT="$OCP_APP_OPT $NAME:ansible_extravars=eco_gotests_path:$PWD/eco-gotests"
    fi
done

ALL_TAGS=

# If we have a gitops change (directory ending with -gitops) or a
# sub-directory containing gitops, we need to inject the gitops branch
if [ -d *-gitops ]; then
    GITOPS_REPO=$(ls -d *-gitops 2>/dev/null)
elif ls -d */*gitops*/ 2>/dev/null; then
    GITOPS_REPO=$(basename $(cd $(ls -d */*gitops*/..|head -1) && pwd))
else
    GITOPS_REPO=
fi
if [ -n "$GITOPS_REPO" ]; then
    # there are 2 cases: the main change is from the gitops PR or the gitops PR is a depends-on
    # first case: $REPO is the gitops repo and the branch is in github.json
    if [ "$REPO" = "$GITOPS_REPO" ]; then
        GITOPS_BRANCH="$(jq -r .head.ref github.json)"
    else
        # second case: the change is from a dependent PR and the branch is <repo>-<pr number>.json
        # we assume there is only one gitops repo
        GITOPS_BRANCH="$(jq -r .head.ref ${GITOPS_REPO}-*.json)"
    fi
    for NAME in $ZTP_NAMES; do
        ALL_TAGS="$ALL_TAGS $NAME:ansible_extravars={\"dci_gitops_policies_repo\":{\"branch\":\"$GITOPS_BRANCH\"},\"dci_gitops_sites_repo\":{\"branch\":\"$GITOPS_BRANCH\"}}"
    done
fi

# set the tags, configuration, change_dir and git repos on all the pipelines
for NAME in $OCP_NAMES $CNF_NAMES; do
    QUEUE_OPT=
    CONF=$("$BASEDIR"/yaml2json "${NAME_TO_PIPELINE[$NAME]}" |
        jq -r ".[]|select(.name==\"$NAME\")|.configuration" |
        sed -e "s/@QUEUE/$DCI_QUEUE/" -e "s/@RESOURCE/$RES/")
    if [ -n "$CONF" ] && [ "$CONF" != null ]; then
        QUEUE_OPT="$NAME:configuration=${CONF}"
    fi

    EXTENDED_TAGS=$TAGS
    for ARG in ${ARGS[@]}
    do
        if [[ $ARG == "$NAME:ansible_extravars=dci_tags:"* ]]
        then
            CUSTOM_TAGS=$(echo $ARG | sed -e "s/$NAME:ansible_extravars=dci_tags://g")
            EXTENDED_TAGS="$TAGS,$CUSTOM_TAGS"
        fi
    done

    ALL_TAGS="$ALL_TAGS $NAME:$EXTENDED_TAGS $NAME:url=$URL $NAME:$GIT_REPOS $QUEUE_OPT $NAME:ansible_extravars=dci_change_dir:$PWD"
    if [ -x "$PWD/.venv/bin/python3" ]; then
        ALL_TAGS="$ALL_TAGS $NAME:ansible_extravars=ansible_playbook_python:$PWD/.venv/bin/python3"
    fi
done

if [ -z "$SUFFIX" ]; then
    # activate the virtualenv created by the dci-pipeline-check command if present
    if [ -x "$PWD/.venv/bin/python3" ]; then
        source "$PWD/.venv/bin/activate"
        sed -i -e '/interpreter_python/d' ansible.cfg
    fi

    if [ -d python-dciclient ]; then
        export DCI_VAULT_CLIENT=$PWD/.venv/bin/dci-vault-client
    fi
else
    if [ -d dci-pipeline ]; then
        export PATH=$PWD/dci-pipeline/tools:$PWD/dci-pipeline/container:$PATH
    fi
fi

if [ -n "$SUFFIX" ]; then
    echo "Extracting required projects"
    # distributedci projects
    for proj in dci-packaging python-dciclient python-dciauth dci-ansible dci-openshift-agent dci-openshift-app-agent dci-pipeline ansible-collection-community-crypto ansible-collection-community-general ansible-collection-community-libvirt ansible-collection-containers-podman ansible-role-dci-podman ansible-role-dci-sync-registry; do
        if [ ! -d "$proj" ]; then
            git clone "https://github.com/distributedci/$proj"
        fi
    done
    # redhatci projects
    if [ ! -d ansible-collection-redhatci-ocp ]; then
        git clone https://github.com/redhatci/ansible-collection-redhatci-ocp.git
    fi
    echo "Building container image"
    ./dci-pipeline/container/build.sh "$DCI_PIPELINE_TAG"
    # Make sure we don't fetch from quay
    export DCI_PIPELINE_IMAGE="localhost/$DCI_PIPELINE_TAG"
    export DCI_PIPELINE_TAG=latest
fi

type -p "dci-pipeline$SUFFIX"

"dci-pipeline$SUFFIX" "${ARGS[@]}" $OPTVERS $ALL_TAGS $OCP_APP_OPT $ALL_PIPELINES >& output &

PID=$!

# make everything read-only to mimic what is delivered as rpm or in
# the system
chmod -R a-w $DIR

# Give permissions to all example CNF hooks
if [ -d example-cnf-config ]; then
    chmod ug+w example-cnf-config/cnfapp/hooks
    chmod ug+w example-cnf-config/upgrade_validation/hooks
    chmod ug+w example-cnf-config/launch_trex_job/hooks
    chmod ug+w example-cnf-config/draining_validation/hooks
    chmod ug+w example-cnf-config/preflight/hooks
fi

# dci-openshift-agent exception
if [ -d dci-openshift-agent ]; then
    chmod -R ug+w dci-openshift-agent/samples
fi

# eco-gotests needs to be writable for ginkgo to compile test binaries
if [ -d eco-gotests ]; then
    chmod -R ug+w eco-gotests
fi

tail -f output &

PID2=$!

wait $PID
RET=$?
PID=

# test-runner ends here
