Загрузка данных
#!/usr/bin/env bash
#
# Example:
# ./scripts/runners/noir_runner.sh \
# --config-file-path ./apa_analyzer_config.yaml \
# --code-root-git-dir-path "$PWD/build_src/auth-proxy" \
# --code-root-git-dir-path "$PWD/build_src/auth-proxy-extra" \
# --repo-snaps-json ./repo-snaps.json \
# --oakb-tool-report-dir-path-no-ts ./.oakb_reports/noir \
# --component-code AUTH \
# --component-version D-3.3.3-b333
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd -P)"
REPO_ROOT_DIR="$(cd "$SCRIPT_DIR/../.." && pwd -P)"
SHARED_DIR="$REPO_ROOT_DIR/shared"
# shellcheck source=shared/lib/common.sh
source "$SHARED_DIR/lib/common.sh"
# shellcheck source=shared/use_config.sh
source "$SHARED_DIR/use_config.sh"
usage() {
cat <<'EOF'
Usage:
./scripts/runners/noir_runner.sh [options]
Required:
--config-file-path PATH
--code-root-git-dir-path PATH
--repo-snaps-json PATH
--oakb-tool-report-dir-path-no-ts PATH
Optional:
--component-code CODE
--component-version VERSION
--swagger-file-path PATH
--jenkins-job-name NAME
--jenkins-job-invoke-id ID
--analyzer-repo-url URL
--analyzer-repo-branch BRANCH
--analyzer-repo-commit HASH
--publish-manifest-path PATH
--tools-root-dir-path PATH
--debug
--help
EOF
}
# Read one KEY=value entry from simple env-like files without sourcing them.
# This is used for two safe scalar lookups:
#
# 1. /etc/os-release, to detect the current Jenkins agent OS.
# 2. .oakb_bundle_source.env, to decide whether an already-unzipped Noir
# bundle matches the selected bundle URL/platform and can be reused.
#
# The function intentionally supports only plain one-line KEY=value records with
# optional single or double quotes around the value; it is not a full shell
# parser.
key_value_file_value() {
local file_path="$1"
local key="$2"
[[ -f "$file_path" ]] || return 0
local line
local value
while IFS= read -r line || [[ -n "$line" ]]; do
[[ "$line" == "$key="* ]] || continue
value="${line#*=}"
case "$value" in
\"*\")
value="${value#\"}"
value="${value%\"}"
;;
\'*\')
value="${value#\'}"
value="${value%\'}"
;;
esac
printf '%s\n' "$value"
return 0
done < "$file_path"
}
os_version_major() {
local version_id="$1"
if [[ "$version_id" =~ ^([0-9]+) ]]; then
printf '%s\n' "${BASH_REMATCH[1]}"
fi
}
noir_bundle_variant_key() {
local os_id="$1"
local os_version_major_value="$2"
if [[ "$os_id" == "altlinux" && "$os_version_major_value" == "10" ]]; then
printf 'altlinux_10\n'
fi
}
normalize_bundle_variant_label() {
local value="$1"
case "$value" in
default_rocky9|default_rocky|rocky9)
printf 'default_el9\n'
;;
*)
printf '%s\n' "$value"
;;
esac
}
resolve_bundle_zip_url() {
local default_bundle_zip_url="$1"
local variant_key="$2"
local os_id="$3"
local os_version_id="$4"
local os_version_major_value="$5"
local os_release_file="$6"
common::log INFO "Noir bundle OS detection: os_release_file=$os_release_file id=${os_id:-unknown} version_id=${os_version_id:-unknown} version_major=${os_version_major_value:-unknown} variant_key=${variant_key:-default}"
if [[ -n "${OAKB_NOIR_BUNDLE_ZIP_URL:-}" ]]; then
common::log INFO "Using Noir bundle URL from OAKB_NOIR_BUNDLE_ZIP_URL"
printf '%s\n' "$OAKB_NOIR_BUNDLE_ZIP_URL"
return 0
fi
if [[ -n "$variant_key" ]]; then
local variant_bundle_zip_url
variant_bundle_zip_url="$(use_config::value ".data.oakb_tools.noir.bundle_zip_url_by_os.$variant_key")"
if [[ -n "$variant_bundle_zip_url" ]]; then
common::log INFO "Using Noir bundle URL for OS variant $variant_key: $variant_bundle_zip_url"
printf '%s\n' "$variant_bundle_zip_url"
return 0
fi
common::log INFO "No Noir bundle URL configured for OS variant $variant_key; using default bundle URL"
fi
common::log INFO "Using default Noir bundle URL: $default_bundle_zip_url"
printf '%s\n' "$default_bundle_zip_url"
}
write_bundle_stamp() {
local stamp_path="$1"
local bundle_zip_url="$2"
local bundle_platform_id="$3"
local prepared_at_utc
prepared_at_utc="$(common::timestamp_utc_rfc3339)"
{
printf 'bundle_zip_url=%s\n' "$bundle_zip_url"
printf 'bundle_platform_id=%s\n' "$bundle_platform_id"
printf 'prepared_at_utc=%s\n' "$prepared_at_utc"
} > "$stamp_path"
}
prepare_bundle() {
local tool_dir="$1"
local bundle_zip_url="$2"
local activation_script_rel="$3"
local run_executable_rel="$4"
local bundle_platform_id="$5"
local activation_script_abs
local run_executable_abs
local stamp_path="$tool_dir/noir-bundle/.oakb_bundle_source.env"
activation_script_abs="$(common::join_path "$tool_dir" "$activation_script_rel")"
run_executable_abs="$(common::join_path "$tool_dir" "$run_executable_rel")"
# Noir is shipped as a bundle declared in apa_analyzer_config.yaml. Reuse the
# prepared bundle between builds unless OAKB_FORCE_TOOL_REFRESH=1 is set or
# the selected bundle URL/platform differs from the prepared bundle stamp.
if [[ "${OAKB_FORCE_TOOL_REFRESH:-0}" != "1" && -f "$activation_script_abs" && -f "$run_executable_abs" ]]; then
local stamped_bundle_zip_url
local stamped_bundle_platform_id
stamped_bundle_zip_url="$(key_value_file_value "$stamp_path" "bundle_zip_url")"
stamped_bundle_platform_id="$(key_value_file_value "$stamp_path" "bundle_platform_id")"
if [[ "$stamped_bundle_zip_url" == "$bundle_zip_url" && "$stamped_bundle_platform_id" == "$bundle_platform_id" ]]; then
common::log INFO "Reusing prepared noir bundle in $tool_dir"
return 0
fi
common::log INFO "Refreshing prepared noir bundle in $tool_dir because selected bundle changed or stamp is missing"
fi
common::ensure_dir "$tool_dir"
rm -rf "$tool_dir/noir-bundle"
common::log INFO "Downloading noir bundle from $bundle_zip_url"
common::run curl -ks --user "$TUZ_NAME_FOR_ACCESS_ANALYZER_BINS:$TUZ_PWD_FOR_ACCESS_ANALYZER_BINS" --http1.1 --fail --location --retry 3 --output "$tool_dir/noir-bundle.zip" "$bundle_zip_url"
# --retry-connrefused <- unsupported by curl on some agents
common::run unzip -oq "$tool_dir/noir-bundle.zip" -d "$tool_dir"
[[ -f "$activation_script_abs" ]] || common::die "Activation script missing after unzip: $activation_script_abs"
[[ -f "$run_executable_abs" ]] || common::die "Noir executable missing after unzip: $run_executable_abs"
write_bundle_stamp "$stamp_path" "$bundle_zip_url" "$bundle_platform_id"
}
detect_tool_version() {
local run_executable_abs="$1"
local version_output
version_output="$("$run_executable_abs" --version 2>/dev/null | sed -n '1p' || true)"
if [[ -n "$version_output" ]]; then
printf '%s\n' "$version_output"
else
printf 'unknown\n'
fi
}
write_meta_file() {
local meta_path="$1"
local report_datetime_utc="$2"
local tool_version="$3"
local repo_snaps_json_path="$4"
local component_code="$5"
local component_version="$6"
local report_dir_name="${7}"
local report_main_file="${8}"
local jenkins_job_name="${9}"
local jenkins_job_invoke_id="${10}"
local analyzer_repo_url="${11}"
local analyzer_repo_branch="${12}"
local analyzer_repo_commit="${13}"
local bundle_variant="${14}"
local bundle_zip_url="${15}"
local bundle_platform_id="${16}"
bundle_variant="$(normalize_bundle_variant_label "$bundle_variant")"
# noir_meta.yaml is the contract consumed by TTR. Important matching fields:
#
# data.report_info.repo_snaps[] with every repo snapshot included in this Noir run
# data.component.component_code / component_version
# data.report_info.report_main_file: noir-report.json
# data.report_generation.analyzer.* for analyzer repo provenance
# data.tool.bundle.* for selected Noir bundle provenance
#
# TTR later uses those values to decide whether a report satisfies a ticket's
# Virtual Requested Tuple.
jq -n \
--slurpfile repo_snaps "$repo_snaps_json_path" \
--arg report_datetime_utc "$report_datetime_utc" \
--arg tool_version "$tool_version" \
--arg component_code "$component_code" \
--arg component_version "$component_version" \
--arg report_dir_name "$report_dir_name" \
--arg report_main_file "$report_main_file" \
--arg jenkins_job_name "$jenkins_job_name" \
--arg jenkins_job_invoke_id "$jenkins_job_invoke_id" \
--arg analyzer_repo_url "$analyzer_repo_url" \
--arg analyzer_repo_branch "$analyzer_repo_branch" \
--arg analyzer_repo_commit "$analyzer_repo_commit" \
--arg bundle_variant "$bundle_variant" \
--arg bundle_zip_url "$bundle_zip_url" \
--arg bundle_platform_id "$bundle_platform_id" \
'
def empty_to_null: if . == "" then null else . end;
{
schema: 1,
kind: "noir_report_meta",
data: {
report_schema_version: 1,
tool: {
name: "noir",
version: $tool_version,
bundle: {
variant: $bundle_variant,
zip_url: $bundle_zip_url,
platform_id: $bundle_platform_id
}
},
report_info: {
report_directory_name: $report_dir_name,
report_datetime_utc: $report_datetime_utc,
report_main_file: $report_main_file,
repo_snaps: $repo_snaps[0]
},
report_generation: {
jenkins_job: {
job_name: $jenkins_job_name,
job_invoke_id: $jenkins_job_invoke_id
},
analyzer: {
repo_url: ($analyzer_repo_url | empty_to_null),
repo_branch: ($analyzer_repo_branch | empty_to_null),
repo_commit: ($analyzer_repo_commit | empty_to_null)
}
},
component: {
component_code: ($component_code | empty_to_null),
component_version: ($component_version | empty_to_null)
}
}
}
' | yq eval -P -o=yaml '.' - > "$meta_path"
}
pretty_print_json_file() {
local json_path="$1"
local pretty_path
pretty_path="$(common::mktemp_file "oakb-noir-json.XXXXXX.json")"
jq '.' "$json_path" > "$pretty_path"
mv "$pretty_path" "$json_path"
}
validate_main_json_report_file() {
local json_path="$1"
[[ -s "$json_path" ]] || common::die "Noir did not produce main JSON report: $json_path"
jq -e type "$json_path" >/dev/null || common::die "Noir produced invalid main JSON report: $json_path"
}
validate_swagger_file_path() {
local swagger_file_path="$1"
[[ -n "$swagger_file_path" ]] || return 0
[[ -e "$swagger_file_path" ]] || common::die "SWAGGER_FILE_PATH points to a missing file: $swagger_file_path"
[[ -f "$swagger_file_path" ]] || common::die "SWAGGER_FILE_PATH is not a regular file: $swagger_file_path"
[[ -r "$swagger_file_path" ]] || common::die "SWAGGER_FILE_PATH is not readable: $swagger_file_path"
}
write_swagger_candidate_meta_file() {
local meta_path="$1"
local component_code="$2"
local component_version="$3"
local source_report_dir_path="$4"
local jenkins_job_name="$5"
local jenkins_job_invoke_id="$6"
local created_at_utc="$7"
jq -n \
--arg component_code "$component_code" \
--arg component_version "$component_version" \
--arg source_report_dir_path "$source_report_dir_path" \
--arg jenkins_job_name "$jenkins_job_name" \
--arg jenkins_job_invoke_id "$jenkins_job_invoke_id" \
--arg created_at_utc "$created_at_utc" \
'
def empty_to_null: if . == "" then null else . end;
{
schema: 1,
kind: "tuple_artifact_candidate_meta",
data: {
artifact: {
artifact_type: "swagger",
file_name: "swagger.json"
},
tuple: {
component_code: $component_code,
component_version: $component_version
},
source: {
producer_family: "noir",
source_report_dir_path: $source_report_dir_path,
producer_job_name: ($jenkins_job_name | empty_to_null),
producer_job_invoke_id: ($jenkins_job_invoke_id | empty_to_null),
created_at_utc: $created_at_utc
}
}
}
' | yq eval -P -o=yaml '.' - > "$meta_path"
}
publish_swagger_candidate() {
local swagger_file_path="$1"
local candidate_dir_path="$2"
local component_code="$3"
local component_version="$4"
local source_report_dir_path="$5"
local jenkins_job_name="$6"
local jenkins_job_invoke_id="$7"
local created_at_utc="$8"
[[ -n "$swagger_file_path" ]] || return 0
[[ -n "$component_code" ]] || common::die "SWAGGER_FILE_PATH requires --component-code so the Swagger tuple artifact can be identified"
[[ -n "$component_version" ]] || common::die "SWAGGER_FILE_PATH requires --component-version so the Swagger tuple artifact can be identified"
common::ensure_dir "$candidate_dir_path"
common::log INFO "Publishing Swagger tuple artifact candidate: $swagger_file_path -> $candidate_dir_path/swagger.json"
common::run cp "$swagger_file_path" "$candidate_dir_path/swagger.json"
write_swagger_candidate_meta_file \
"$candidate_dir_path/artifact_meta.yaml" \
"$component_code" \
"$component_version" \
"$source_report_dir_path" \
"$jenkins_job_name" \
"$jenkins_job_invoke_id" \
"$created_at_utc"
}
run_noir_json_report_with_stdout_fallback() {
local run_executable_abs="$1"
local output_path="$2"
local fallback_json_path="$3"
shift 3
local stdout_path
stdout_path="$(common::mktemp_file "oakb-noir-stdout.XXXXXX.json")"
rm -f "$output_path"
# Noir bundle versions do not all handle "-o" consistently for the secondary
# JSON report. Some write the report file, while v0.29.1 can print the JSON
# to stderr/stdout even when "-o" is present. For no-tech fixture repos, it can
# also produce no secondary output at all. Capture the no-log command output,
# then fall back to the main JSON report so the published report shape remains
# stable for downstream tools and operators.
if ! common::run "$run_executable_abs" "$@" -o "$output_path" > "$stdout_path" 2>&1; then
cat "$stdout_path" >&2 || true
common::die "Noir command failed while producing JSON report: $output_path"
fi
if [[ ! -s "$output_path" && -s "$stdout_path" ]]; then
cp "$stdout_path" "$output_path"
fi
if [[ ! -s "$output_path" && -s "$fallback_json_path" ]]; then
cp "$fallback_json_path" "$output_path"
fi
rm -f "$stdout_path"
[[ -s "$output_path" ]] || common::die "Noir did not produce JSON report: $output_path"
}
push_report_to_repo() {
local report_dir="$1"
local report_rel_path="$2"
local reports_repo_url="$3"
local reports_repo_branch="$4"
local code_repo_refs="$5"
local swagger_candidate_dir="${6:-}"
local swagger_candidate_rel_path="${7:-}"
local report_dir_name
report_dir_name="$(basename "$report_rel_path")"
local push_temp_dir
push_temp_dir="$(common::mktemp_dir "oakb-noir-push.XXXXXX")"
local worktree="$push_temp_dir/worktree"
stage_noir_single_report_commit() {
[[ -n "$report_dir_name" ]] || common::die "Report directory name is empty"
rm -rf -- "$worktree/${report_rel_path:?}" || return $?
common::run mkdir -p "$(dirname "$worktree/$report_rel_path")" || return $?
common::run mkdir -p "$worktree/$report_rel_path" || return $?
common::run cp -a "$report_dir"/. "$worktree/$report_rel_path"/ || return $?
common::run git -C "$worktree" add "$report_rel_path" || return $?
if [[ -n "$swagger_candidate_dir" || -n "$swagger_candidate_rel_path" ]]; then
[[ -n "$swagger_candidate_dir" ]] || common::die "Swagger candidate manifest entry is missing local directory"
[[ -n "$swagger_candidate_rel_path" ]] || common::die "Swagger candidate manifest entry is missing repo path"
[[ -d "$swagger_candidate_dir" ]] || common::die "Swagger candidate directory not found: $swagger_candidate_dir"
rm -rf -- "$worktree/${swagger_candidate_rel_path:?}" || return $?
common::run mkdir -p "$(dirname "$worktree/$swagger_candidate_rel_path")" || return $?
common::run mkdir -p "$worktree/$swagger_candidate_rel_path" || return $?
common::run cp -a "$swagger_candidate_dir"/. "$worktree/$swagger_candidate_rel_path"/ || return $?
common::run git -C "$worktree" add "$swagger_candidate_rel_path" || return $?
fi
if git -C "$worktree" diff --cached --quiet; then
return 2
fi
common::run git -C "$worktree" commit -m "Add noir report $report_dir_name" -m "$code_repo_refs" >/dev/null || return $?
}
common::checkout_branch_for_push "$worktree" "$reports_repo_url" "$reports_repo_branch"
local stage_status=0
if stage_noir_single_report_commit; then
:
else
stage_status=$?
if [[ "$stage_status" -eq 2 ]]; then
common::log INFO "No report changes to push for $report_dir_name"
rm -rf -- "$push_temp_dir"
return 0
fi
rm -rf -- "$push_temp_dir"
common::die "Failed to stage report commit for $report_dir_name"
fi
local attempt
local push_output=""
for attempt in 1 2 3 4 5; do
if push_output="$(git -C "$worktree" push origin HEAD:"$reports_repo_branch" 2>&1)"; then
common::log INFO "Pushed $report_dir_name to $reports_repo_url"
rm -rf -- "$push_temp_dir"
return 0
fi
common::log INFO "Push attempt $attempt failed for $report_dir_name"
common::log INFO "$push_output"
if [[ "$attempt" -eq 5 ]]; then
break
fi
common::log INFO "Refreshing $reports_repo_branch and rebasing report commit before retry"
if ! common::rebase_branch_for_push_retry "$worktree" "$reports_repo_branch"; then
common::log INFO "Rebase failed; rebuilding report commit on the current remote branch"
git -C "$worktree" rebase --abort >/dev/null 2>&1 || true
common::checkout_branch_for_push "$worktree" "$reports_repo_url" "$reports_repo_branch"
if stage_noir_single_report_commit; then
:
else
stage_status=$?
if [[ "$stage_status" -eq 2 ]]; then
common::log INFO "No report changes to push after refresh for $report_dir_name"
rm -rf -- "$push_temp_dir"
return 0
fi
rm -rf -- "$push_temp_dir"
common::die "Failed to restage report commit for $report_dir_name"
fi
fi
common::sleep_for_push_retry "$attempt"
done
rm -rf -- "$push_temp_dir"
common::die "Failed to push $report_dir_name after 5 attempts"
}
append_publish_manifest() {
local manifest_path="$1"
local report_dir="$2"
local report_rel_path="$3"
local reports_repo_url="$4"
local reports_repo_branch="$5"
local code_repo_refs="$6"
local swagger_candidate_dir="${7:-}"
local swagger_candidate_rel_path="${8:-}"
[[ -n "$manifest_path" ]] || return 0
common::ensure_dir "$(dirname "$manifest_path")"
printf '%s\t%s\t%s\t%s\t%s\t%s\t%s\n' \
"$report_dir" \
"$report_rel_path" \
"$reports_repo_url" \
"$reports_repo_branch" \
"$code_repo_refs" \
"$swagger_candidate_dir" \
"$swagger_candidate_rel_path" >> "$manifest_path"
}
main() {
local config_file_path=""
local repo_snaps_json_path=""
local -a code_root_git_dir_paths=()
local oakb_tool_report_dir_path_no_ts=""
local component_code=""
local component_version=""
local swagger_file_path=""
local jenkins_job_name=""
local jenkins_job_invoke_id=""
local analyzer_repo_url="${APA_ANALYZER_REPO_URL:-}"
local analyzer_repo_branch="${APA_ANALYZER_REPO_BRANCH:-}"
local analyzer_repo_commit="${APA_ANALYZER_REPO_COMMIT:-}"
local publish_manifest_path=""
local tools_root_dir_path="./.oakb_tools"
while [[ $# -gt 0 ]]; do
case "$1" in
--config-file-path)
[[ $# -ge 2 ]] || common::die "--config-file-path requires a value"
config_file_path="$2"
shift 2
;;
--repo-snaps-json)
[[ $# -ge 2 ]] || common::die "--repo-snaps-json requires a value"
repo_snaps_json_path="$2"
shift 2
;;
--code-root-git-dir-path)
[[ $# -ge 2 ]] || common::die "--code-root-git-dir-path requires a value"
code_root_git_dir_paths+=("$2")
shift 2
;;
--oakb-tool-report-dir-path-no-ts)
[[ $# -ge 2 ]] || common::die "--oakb-tool-report-dir-path-no-ts requires a value"
oakb_tool_report_dir_path_no_ts="$2"
shift 2
;;
--component-code)
[[ $# -ge 2 ]] || common::die "--component-code requires a value"
component_code="$2"
shift 2
;;
--component-version)
[[ $# -ge 2 ]] || common::die "--component-version requires a value"
component_version="$2"
shift 2
;;
--swagger-file-path)
[[ $# -ge 2 ]] || common::die "--swagger-file-path requires a value"
swagger_file_path="$2"
shift 2
;;
--jenkins-job-name)
[[ $# -ge 2 ]] || common::die "--jenkins-job-name requires a value"
jenkins_job_name="$2"
shift 2
;;
--jenkins-job-invoke-id)
[[ $# -ge 2 ]] || common::die "--jenkins-job-invoke-id requires a value"
jenkins_job_invoke_id="$2"
shift 2
;;
--analyzer-repo-url)
[[ $# -ge 2 ]] || common::die "--analyzer-repo-url requires a value"
analyzer_repo_url="$2"
shift 2
;;
--analyzer-repo-branch)
[[ $# -ge 2 ]] || common::die "--analyzer-repo-branch requires a value"
analyzer_repo_branch="$2"
shift 2
;;
--analyzer-repo-commit)
[[ $# -ge 2 ]] || common::die "--analyzer-repo-commit requires a value"
analyzer_repo_commit="$2"
shift 2
;;
--publish-manifest-path)
[[ $# -ge 2 ]] || common::die "--publish-manifest-path requires a value"
publish_manifest_path="$2"
shift 2
;;
--tools-root-dir-path)
[[ $# -ge 2 ]] || common::die "--tools-root-dir-path requires a value"
tools_root_dir_path="$2"
shift 2
;;
--debug)
export DEBUG=1
shift
;;
--help|-h)
usage
exit 0
;;
*)
common::die "Unknown argument: $1"
;;
esac
done
common::require_commands curl git jq yq unzip
common::enable_debug_if_requested
common::export_tmp_env
[[ -n "$config_file_path" ]] || common::die "--config-file-path is required"
[[ -n "$repo_snaps_json_path" ]] || common::die "--repo-snaps-json is required"
((${#code_root_git_dir_paths[@]} > 0)) || common::die "At least one --code-root-git-dir-path is required"
[[ -n "$oakb_tool_report_dir_path_no_ts" ]] || common::die "--oakb-tool-report-dir-path-no-ts is required"
[[ -f "$repo_snaps_json_path" ]] || common::die "Repo snaps JSON file does not exist: $repo_snaps_json_path"
jq -e 'type == "array" and length > 0 and all(.[]; ((.repo_url // "") != "") and ((.repo_commit // "") != ""))' "$repo_snaps_json_path" >/dev/null || common::die "Repo snaps JSON must be a non-empty array with repo_url and repo_commit"
local code_root_git_dir_path
for code_root_git_dir_path in "${code_root_git_dir_paths[@]}"; do
[[ -d "$code_root_git_dir_path" ]] || common::die "Code root Git directory does not exist: $code_root_git_dir_path"
done
validate_swagger_file_path "$swagger_file_path"
use_config::init --config-file-path "$config_file_path"
local default_bundle_zip_url
local bundle_zip_url
local activation_script_rel
local run_executable_rel
local reports_repo_url
local reports_repo_branch
default_bundle_zip_url="$(use_config::must_value '.data.oakb_tools.noir.bundle_zip_url' 'data.oakb_tools.noir.bundle_zip_url')"
activation_script_rel="$(use_config::must_value '.data.oakb_tools.noir.how2run.activation_script_path' 'data.oakb_tools.noir.how2run.activation_script_path')"
run_executable_rel="$(use_config::must_value '.data.oakb_tools.noir.how2run.run_executable_path' 'data.oakb_tools.noir.how2run.run_executable_path')"
reports_repo_url="$(use_config::must_value '.data.oakb_tools.noir.send_reports_to_repo.repo_url' 'data.oakb_tools.noir.send_reports_to_repo.repo_url')"
reports_repo_branch="$(use_config::must_value '.data.oakb_tools.noir.send_reports_to_repo.repo_branch' 'data.oakb_tools.noir.send_reports_to_repo.repo_branch')"
local os_release_file="${OAKB_OS_RELEASE_FILE:-/etc/os-release}"
local os_id
local os_version_id
local os_version_major_value
local bundle_variant_key
os_id="$(key_value_file_value "$os_release_file" "ID")"
os_version_id="$(key_value_file_value "$os_release_file" "VERSION_ID")"
os_version_major_value="$(os_version_major "$os_version_id")"
bundle_variant_key="$(noir_bundle_variant_key "$os_id" "$os_version_major_value")"
bundle_zip_url="$(resolve_bundle_zip_url "$default_bundle_zip_url" "$bundle_variant_key" "$os_id" "$os_version_id" "$os_version_major_value" "$os_release_file")"
local bundle_platform_id
local bundle_variant_label
bundle_platform_id="os_id=${os_id:-unknown};os_version_id=${os_version_id:-unknown};os_version_major=${os_version_major_value:-unknown};variant_key=${bundle_variant_key:-default}"
if [[ -n "${OAKB_NOIR_BUNDLE_ZIP_URL:-}" ]]; then
bundle_variant_label="override"
elif [[ "$bundle_zip_url" == "$default_bundle_zip_url" ]]; then
bundle_variant_label="default_el9"
else
bundle_variant_label="$bundle_variant_key"
fi
bundle_variant_label="$(normalize_bundle_variant_label "$bundle_variant_label")"
local tools_root_abs
tools_root_abs="$(common::target_path_abs "$tools_root_dir_path")"
local tool_dir="$tools_root_abs/noir"
prepare_bundle "$tool_dir" "$bundle_zip_url" "$activation_script_rel" "$run_executable_rel" "$bundle_platform_id"
local activation_script_abs
local run_executable_abs
activation_script_abs="$(common::join_path "$tool_dir" "$activation_script_rel")"
run_executable_abs="$(common::join_path "$tool_dir" "$run_executable_rel")"
local report_dir_base_abs
report_dir_base_abs="$(common::target_path_abs "$oakb_tool_report_dir_path_no_ts")"
common::ensure_dir "$report_dir_base_abs"
local report_timestamp_compact
local report_timestamp_rfc3339
local report_dir_name
local report_rel_path
local report_dir_path
report_timestamp_compact="$(common::timestamp_utc_compact)"
report_timestamp_rfc3339="$(common::timestamp_utc_rfc3339)"
report_dir_name="noir_${report_timestamp_compact}_$$"
report_rel_path="$(common::report_rel_path_from_dir_name "$report_timestamp_compact" "$report_dir_name")"
report_dir_path="$report_dir_base_abs/$report_rel_path"
local report_data_dir="$report_dir_path/report_data"
local meta_dir="$report_dir_path/report_meta"
common::ensure_dir "$report_dir_path"
common::ensure_dir "$report_data_dir"
common::ensure_dir "$meta_dir"
common::log INFO "Running noir against ${#code_root_git_dir_paths[@]} root(s)"
# shellcheck disable=SC1090
source "$activation_script_abs"
local -a noir_base_args=()
for code_root_git_dir_path in "${code_root_git_dir_paths[@]}"; do
noir_base_args+=(-b "$code_root_git_dir_path")
done
if ! common::run "$run_executable_abs" "${noir_base_args[@]}" -u https://example.com -f json --include-path -o "$report_data_dir/noir-report.json" --exclude-techs oas_2_0,oas_3_0; then
common::die "Noir command failed while producing main JSON report: $report_data_dir/noir-report.json"
fi
validate_main_json_report_file "$report_data_dir/noir-report.json"
run_noir_json_report_with_stdout_fallback "$run_executable_abs" "$report_data_dir/interfaces.json" "$report_data_dir/noir-report.json" "${noir_base_args[@]}" -f json --include-path --include-techs --no-log
pretty_print_json_file "$report_data_dir/interfaces.json"
common::run "$run_executable_abs" "${noir_base_args[@]}" --include-path --include-techs --no-log --no-color > "$report_data_dir/interfaces.plain.txt"
local swagger_candidate_dir_path=""
local swagger_candidate_rel_path=""
if [[ -n "$swagger_file_path" ]]; then
swagger_candidate_rel_path="tuple_artifact_candidates/swagger/$report_rel_path"
swagger_candidate_dir_path="$report_dir_base_abs/$swagger_candidate_rel_path"
publish_swagger_candidate \
"$swagger_file_path" \
"$swagger_candidate_dir_path" \
"$component_code" \
"$component_version" \
"$report_rel_path" \
"$jenkins_job_name" \
"$jenkins_job_invoke_id" \
"$report_timestamp_rfc3339"
fi
local tool_version
tool_version="$(detect_tool_version "$run_executable_abs")"
write_meta_file \
"$meta_dir/noir_meta.yaml" \
"$report_timestamp_rfc3339" \
"$tool_version" \
"$repo_snaps_json_path" \
"$component_code" \
"$component_version" \
"$report_dir_name" \
"noir-report.json" \
"$jenkins_job_name" \
"$jenkins_job_invoke_id" \
"$analyzer_repo_url" \
"$analyzer_repo_branch" \
"$analyzer_repo_commit" \
"$bundle_variant_label" \
"$bundle_zip_url" \
"$bundle_platform_id"
if [[ -n "$publish_manifest_path" ]]; then
local code_repo_refs
code_repo_refs="$(jq -r 'map((.repo_url // "") + "@" + (.repo_commit // "")) | join(", ")' "$repo_snaps_json_path")"
append_publish_manifest \
"$publish_manifest_path" \
"$report_dir_path" \
"$report_rel_path" \
"$reports_repo_url" \
"$reports_repo_branch" \
"$code_repo_refs" \
"$swagger_candidate_dir_path" \
"$swagger_candidate_rel_path"
else
local code_repo_refs
code_repo_refs="$(jq -r 'map((.repo_url // "") + "@" + (.repo_commit // "")) | join(", ")' "$repo_snaps_json_path")"
push_report_to_repo \
"$report_dir_path" \
"$report_rel_path" \
"$reports_repo_url" \
"$reports_repo_branch" \
"$code_repo_refs" \
"$swagger_candidate_dir_path" \
"$swagger_candidate_rel_path"
fi
}
main "$@"