Some checks failed
Main Confidence / confidence (push) Failing after 46s
## Summary - implement Spec 211 runtime trend reporting with bounded lane history, drift classification, hotspot trend output, and recalibration evidence handling - extend the repo-truth governance seams and workflow wrappers for comparable-bundle hydration, trend artifact publication, and contract-backed reporting - add the Spec 211 planning artifacts, data model, quickstart, tasks, and repository contract documents ## Validation - parsed `specs/211-runtime-trend-recalibration/contracts/test-runtime-trend-history.schema.json` - parsed `specs/211-runtime-trend-recalibration/contracts/test-runtime-trend.logical.openapi.yaml` - re-ran cross-artifact consistency analysis for the Spec 211 artifact set until no material findings remained - no application test suite was re-run as part of this final commit/push/PR step Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de> Reviewed-on: #244
360 lines
8.1 KiB
Bash
Executable File
360 lines
8.1 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
|
|
set -euo pipefail
|
|
|
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
ROOT_DIR="$(cd "${SCRIPT_DIR}/.." && pwd)"
|
|
APP_DIR="${ROOT_DIR}/apps/platform"
|
|
LANE="${1:-fast-feedback}"
|
|
CAPTURE_BASELINE=false
|
|
WORKFLOW_ID=""
|
|
TRIGGER_CLASS=""
|
|
HISTORY_FILE=""
|
|
HISTORY_BUNDLE=""
|
|
FETCH_LATEST_HISTORY=auto
|
|
|
|
copy_heavy_baseline_artifacts() {
|
|
local artifact_root="${APP_DIR}/storage/logs/test-lanes"
|
|
local suffix
|
|
|
|
for suffix in summary.md budget.json report.json trend-history.json; do
|
|
local latest_path="${artifact_root}/heavy-governance-latest.${suffix}"
|
|
local baseline_path="${artifact_root}/heavy-governance-baseline.${suffix}"
|
|
|
|
if [[ -f "${latest_path}" ]]; then
|
|
cp "${latest_path}" "${baseline_path}"
|
|
fi
|
|
done
|
|
}
|
|
|
|
case "${LANE}" in
|
|
fast-feedback|fast|default)
|
|
COMPOSER_SCRIPT="test:report"
|
|
;;
|
|
confidence)
|
|
COMPOSER_SCRIPT="test:report:confidence"
|
|
;;
|
|
browser)
|
|
COMPOSER_SCRIPT="test:report:browser"
|
|
;;
|
|
heavy-governance|heavy)
|
|
COMPOSER_SCRIPT="test:report:heavy"
|
|
;;
|
|
profiling|profile)
|
|
COMPOSER_SCRIPT="test:report:profile"
|
|
;;
|
|
junit)
|
|
COMPOSER_SCRIPT="test:report:junit"
|
|
;;
|
|
*)
|
|
echo "Unknown test lane: ${LANE}" >&2
|
|
exit 1
|
|
;;
|
|
esac
|
|
|
|
shift || true
|
|
|
|
for arg in "$@"; do
|
|
if [[ "${arg}" == "--capture-baseline" ]]; then
|
|
CAPTURE_BASELINE=true
|
|
continue
|
|
fi
|
|
|
|
if [[ "${arg}" == --workflow-id=* ]]; then
|
|
WORKFLOW_ID="${arg#--workflow-id=}"
|
|
continue
|
|
fi
|
|
|
|
if [[ "${arg}" == --trigger-class=* ]]; then
|
|
TRIGGER_CLASS="${arg#--trigger-class=}"
|
|
continue
|
|
fi
|
|
|
|
if [[ "${arg}" == --history-file=* ]]; then
|
|
HISTORY_FILE="${arg#--history-file=}"
|
|
continue
|
|
fi
|
|
|
|
if [[ "${arg}" == --history-bundle=* ]]; then
|
|
HISTORY_BUNDLE="${arg#--history-bundle=}"
|
|
continue
|
|
fi
|
|
|
|
if [[ "${arg}" == "--fetch-latest-history" ]]; then
|
|
FETCH_LATEST_HISTORY=true
|
|
continue
|
|
fi
|
|
|
|
if [[ "${arg}" == "--skip-latest-history" ]]; then
|
|
FETCH_LATEST_HISTORY=false
|
|
continue
|
|
fi
|
|
|
|
echo "Unknown option: ${arg}" >&2
|
|
exit 1
|
|
done
|
|
|
|
if [[ "${CAPTURE_BASELINE}" == true && "${LANE}" != "heavy-governance" && "${LANE}" != "heavy" ]]; then
|
|
echo "--capture-baseline is only supported for heavy-governance" >&2
|
|
exit 1
|
|
fi
|
|
|
|
if [[ -n "${WORKFLOW_ID}" ]]; then
|
|
export TENANTATLAS_CI_WORKFLOW_ID="${WORKFLOW_ID}"
|
|
fi
|
|
|
|
if [[ -n "${TRIGGER_CLASS}" ]]; then
|
|
export TENANTATLAS_CI_TRIGGER_CLASS="${TRIGGER_CLASS}"
|
|
fi
|
|
|
|
trend_history_target_path() {
|
|
echo "${APP_DIR}/storage/logs/test-lanes/${LANE}-latest.trend-history.json"
|
|
}
|
|
|
|
resolve_input_path() {
|
|
local path="${1:-}"
|
|
|
|
if [[ -z "${path}" ]]; then
|
|
return 1
|
|
fi
|
|
|
|
if [[ "${path}" = /* ]]; then
|
|
echo "${path}"
|
|
return 0
|
|
fi
|
|
|
|
echo "${ROOT_DIR}/${path#./}"
|
|
}
|
|
|
|
hydrate_trend_history_from_file() {
|
|
local source_path="${1:-}"
|
|
local target_path
|
|
|
|
target_path="$(trend_history_target_path)"
|
|
|
|
if [[ -z "${source_path}" || ! -f "${source_path}" ]]; then
|
|
return 1
|
|
fi
|
|
|
|
mkdir -p "$(dirname "${target_path}")"
|
|
cp "${source_path}" "${target_path}"
|
|
return 0
|
|
}
|
|
|
|
hydrate_trend_history_from_bundle() {
|
|
local bundle_path="${1:-}"
|
|
local target_path
|
|
local candidate
|
|
|
|
target_path="$(trend_history_target_path)"
|
|
|
|
if [[ -z "${bundle_path}" ]]; then
|
|
return 1
|
|
fi
|
|
|
|
if [[ -d "${bundle_path}" ]]; then
|
|
for candidate in \
|
|
"${bundle_path}/${LANE}.trend-history.json" \
|
|
"${bundle_path}/${LANE}-latest.trend-history.json"
|
|
do
|
|
if [[ -f "${candidate}" ]]; then
|
|
mkdir -p "$(dirname "${target_path}")"
|
|
cp "${candidate}" "${target_path}"
|
|
return 0
|
|
fi
|
|
done
|
|
|
|
candidate="$(find "${bundle_path}" -type f \( -name "${LANE}.trend-history.json" -o -name "${LANE}-latest.trend-history.json" \) | head -n 1)"
|
|
|
|
if [[ -n "${candidate}" && -f "${candidate}" ]]; then
|
|
mkdir -p "$(dirname "${target_path}")"
|
|
cp "${candidate}" "${target_path}"
|
|
return 0
|
|
fi
|
|
fi
|
|
|
|
if [[ -f "${bundle_path}" && "${bundle_path,,}" == *.zip ]]; then
|
|
candidate="$(python3 - "${bundle_path}" "${LANE}" <<'PY'
|
|
import sys
|
|
import zipfile
|
|
|
|
bundle_path, lane = sys.argv[1], sys.argv[2]
|
|
candidates = [f"{lane}.trend-history.json", f"{lane}-latest.trend-history.json"]
|
|
|
|
with zipfile.ZipFile(bundle_path) as archive:
|
|
for name in archive.namelist():
|
|
if any(name.endswith(candidate) for candidate in candidates):
|
|
print(name)
|
|
break
|
|
PY
|
|
)"
|
|
|
|
if [[ -n "${candidate}" ]]; then
|
|
mkdir -p "$(dirname "${target_path}")"
|
|
unzip -p "${bundle_path}" "${candidate}" > "${target_path}"
|
|
return 0
|
|
fi
|
|
fi
|
|
|
|
return 1
|
|
}
|
|
|
|
parse_remote_origin() {
|
|
local origin_url
|
|
|
|
origin_url="$(git -C "${ROOT_DIR}" config --get remote.origin.url 2>/dev/null || true)"
|
|
|
|
if [[ -z "${origin_url}" ]]; then
|
|
return 1
|
|
fi
|
|
|
|
python3 - "${origin_url}" <<'PY'
|
|
import re
|
|
import sys
|
|
|
|
origin = sys.argv[1].strip()
|
|
patterns = [
|
|
re.compile(r'^(https?://[^/]+)/([^/]+)/([^/]+?)(?:\.git)?$'),
|
|
re.compile(r'^git@([^:]+):([^/]+)/([^/]+?)(?:\.git)?$'),
|
|
re.compile(r'^ssh://git@([^/]+)/([^/]+)/([^/]+?)(?:\.git)?$'),
|
|
]
|
|
|
|
for pattern in patterns:
|
|
match = pattern.match(origin)
|
|
if not match:
|
|
continue
|
|
|
|
groups = match.groups()
|
|
|
|
if origin.startswith("http://") or origin.startswith("https://"):
|
|
host, owner, repo = groups
|
|
else:
|
|
host, owner, repo = groups
|
|
host = f"https://{host}"
|
|
|
|
print(host)
|
|
print(owner)
|
|
print(repo)
|
|
sys.exit(0)
|
|
|
|
sys.exit(1)
|
|
PY
|
|
}
|
|
|
|
download_latest_history_bundle() {
|
|
local token
|
|
local artifact_name
|
|
local remote_parts
|
|
local host
|
|
local owner
|
|
local repo
|
|
local listing_path
|
|
local artifact_id
|
|
local bundle_dir
|
|
local bundle_path
|
|
|
|
token="${TENANTATLAS_GITEA_TOKEN:-${GITEA_TOKEN:-}}"
|
|
|
|
if [[ -z "${token}" ]]; then
|
|
return 1
|
|
fi
|
|
|
|
mapfile -t remote_parts < <(parse_remote_origin) || return 1
|
|
|
|
if [[ "${#remote_parts[@]}" -ne 3 ]]; then
|
|
return 1
|
|
fi
|
|
|
|
host="${remote_parts[0]}"
|
|
owner="${remote_parts[1]}"
|
|
repo="${remote_parts[2]}"
|
|
artifact_name="${LANE}-artifacts"
|
|
listing_path="${ROOT_DIR}/.gitea-artifacts/_history/${LANE}-artifacts.json"
|
|
|
|
mkdir -p "${ROOT_DIR}/.gitea-artifacts/_history"
|
|
|
|
curl --fail --silent --show-error \
|
|
-H "Authorization: token ${token}" \
|
|
-H "Accept: application/json" \
|
|
"${host}/api/v1/repos/${owner}/${repo}/actions/artifacts?name=${artifact_name}" \
|
|
-o "${listing_path}" || return 1
|
|
|
|
artifact_id="$(php -r '
|
|
$data = json_decode((string) file_get_contents($argv[1]), true);
|
|
$currentRunId = getenv("GITEA_RUN_ID") ?: getenv("GITHUB_RUN_ID") ?: "";
|
|
foreach (($data["artifacts"] ?? []) as $artifact) {
|
|
if (($artifact["expired"] ?? false) === true) {
|
|
continue;
|
|
}
|
|
|
|
$artifactRunId = (string) ($artifact["workflow_run"]["id"] ?? "");
|
|
|
|
if ($currentRunId !== "" && $artifactRunId === (string) $currentRunId) {
|
|
continue;
|
|
}
|
|
|
|
echo (string) ($artifact["id"] ?? "");
|
|
break;
|
|
}
|
|
' "${listing_path}")"
|
|
|
|
if [[ -z "${artifact_id}" ]]; then
|
|
return 1
|
|
fi
|
|
|
|
bundle_dir="${ROOT_DIR}/.gitea-artifacts/_history/${LANE}"
|
|
bundle_path="${bundle_dir}/artifact.zip"
|
|
rm -rf "${bundle_dir}"
|
|
mkdir -p "${bundle_dir}"
|
|
|
|
curl --fail --silent --show-error --location \
|
|
-H "Authorization: token ${token}" \
|
|
"${host}/api/v1/repos/${owner}/${repo}/actions/artifacts/${artifact_id}/zip" \
|
|
-o "${bundle_path}" || return 1
|
|
|
|
echo "${bundle_path}"
|
|
return 0
|
|
}
|
|
|
|
hydrate_trend_history() {
|
|
local resolved_history_file=""
|
|
local resolved_history_bundle=""
|
|
local downloaded_bundle=""
|
|
|
|
if [[ -n "${HISTORY_FILE}" ]]; then
|
|
resolved_history_file="$(resolve_input_path "${HISTORY_FILE}")"
|
|
fi
|
|
|
|
if [[ -n "${HISTORY_BUNDLE}" ]]; then
|
|
resolved_history_bundle="$(resolve_input_path "${HISTORY_BUNDLE}")"
|
|
fi
|
|
|
|
if [[ -n "${resolved_history_file}" ]] && hydrate_trend_history_from_file "${resolved_history_file}"; then
|
|
return 0
|
|
fi
|
|
|
|
if [[ -n "${resolved_history_bundle}" ]] && hydrate_trend_history_from_bundle "${resolved_history_bundle}"; then
|
|
return 0
|
|
fi
|
|
|
|
if [[ "${FETCH_LATEST_HISTORY}" == true || ( "${FETCH_LATEST_HISTORY}" == auto && -n "${WORKFLOW_ID}" ) ]]; then
|
|
downloaded_bundle="$(download_latest_history_bundle || true)"
|
|
|
|
if [[ -n "${downloaded_bundle}" ]] && hydrate_trend_history_from_bundle "${downloaded_bundle}"; then
|
|
return 0
|
|
fi
|
|
fi
|
|
|
|
return 0
|
|
}
|
|
|
|
cd "${APP_DIR}"
|
|
|
|
hydrate_trend_history
|
|
|
|
./vendor/bin/sail composer run --timeout=0 "${COMPOSER_SCRIPT}"
|
|
|
|
if [[ "${CAPTURE_BASELINE}" == true ]]; then
|
|
copy_heavy_baseline_artifacts
|
|
fi
|