loading
Generated 2026-06-22T02:49:45+00:00

All Files ( 49.27% covered at 4.34 hits/line )

9 files in total.
481 relevant lines, 237 lines covered and 244 lines missed. ( 49.27% )
File % covered Lines Relevant Lines Lines covered Lines missed Avg. Hits / Line
scripts/check-version.sh 100.00 % 60 39 39 0 13.59
scripts/ci-report.sh 0.00 % 110 62 0 62 0.00
scripts/ci-validate.sh 95.24 % 31 21 20 1 9.76
scripts/dispatch-workflow.sh 83.33 % 87 60 50 10 9.42
scripts/gitops-update.sh 44.78 % 114 67 30 37 4.64
scripts/poc-dispatch-match.sh 0.00 % 189 107 0 107 0.00
scripts/publish-git-pages.sh 78.05 % 117 82 64 18 2.88
scripts/publish.sh 70.00 % 16 10 7 3 3.50
scripts/report-status.sh 81.82 % 47 33 27 6 6.21

scripts/check-version.sh

100.0% lines covered

39 relevant lines. 39 lines covered and 0 lines missed.
    
  1. #!/usr/bin/env bash
  2. 11 set -e
  3. 11 RAW_VERSION=""
  4. 19 if [ -n "${VERSION_FILE-}" ] && [ -f "${VERSION_FILE-}" ]; then
  5. 36 RAW_VERSION=$(tr -d "$(printf '\xef\xbb\xbf')" < "${VERSION_FILE}" | sed -n 's/^version:[[:space:]]*\([^[:space:]]*\).*/\1/p')
  6. 9 if [ -z "${RAW_VERSION}" ]; then
  7. 12 if echo "${VERSION_FILE}" | grep -q -E '\.json$'; then
  8. 2 RAW_VERSION=$(jq -r '.version' "${VERSION_FILE}")
  9. else
  10. 15 RAW_VERSION=$(cat "${VERSION_FILE}" | tr -d '[:space:]')
  11. fi
  12. fi
  13. fi
  14. 12 if [ -z "${RAW_VERSION}" ]; then
  15. 3 if [ -f VERSION ]; then
  16. 3 RAW_VERSION=$(cat VERSION | tr -d '[:space:]')
  17. 2 elif [ -f package.json ]; then
  18. RAW_VERSION=$(jq -r '.version' package.json)
  19. 2 elif [ -f pom.xml ]; then
  20. RAW_VERSION=$(grep -oP '<version>\K[^<]+' pom.xml | head -1)
  21. 2 elif [ -f Chart.yaml ]; then
  22. 4 RAW_VERSION=$(tr -d "$(printf '\xef\xbb\xbf')" < Chart.yaml | sed -n 's/^version:[[:space:]]*\([^[:space:]]*\).*/\1/p')
  23. else
  24. 1 echo "ERROR: No version source found (VERSION_FILE, VERSION, package.json, pom.xml, Chart.yaml)" >&2
  25. 1 exit 1
  26. fi
  27. fi
  28. 33 BASE_VERSION=$(echo "$RAW_VERSION" | cut -d'.' -f1-2)
  29. 11 echo "gitea-ci-library - Tunnistettu Major.Minor versio: $BASE_VERSION"
  30. 22 TAGS_JSON=$(curl -s -f -H "Authorization: token ${GITEA_TOKEN}" \
  31. 22 "${SERVER_URL}/api/v1/repos/${REPO}/tags")
  32. 33 TAG=$(echo "$TAGS_JSON" | jq -r --arg prefix "${GIT_TAG_PREFIX-}" --arg sha "${SHA}" '
  33. 33 if type == "array" then
  34. 33 .[] | select(.commit.sha == $sha and (.name | startswith($prefix))) | .name
  35. 33 else empty end' | head -1)
  36. 11 mkdir -p /tmp/build-ctx
  37. 11
  38. 11 if [ -n "$TAG" ]; then
  39. 2 echo "ARTIFACT_EXISTS=true" > /tmp/build-ctx/build.env
  40. 2 echo "NEXT_VERSION=$TAG" >> /tmp/build-ctx/build.env
  41. 2 echo "gitea-ci-library - Artefakti löytyi jo tagilla: $TAG."
  42. else
  43. 9 echo "ARTIFACT_EXISTS=false" > /tmp/build-ctx/build.env
  44. 27 HIGHEST_PATCH=$(echo "$TAGS_JSON" | jq -r --arg prefix "${GIT_TAG_PREFIX-}" --arg bv "${GIT_TAG_PREFIX-}${BASE_VERSION}." '
  45. 27 if type == "array" then .[] | .name | select(startswith($bv)) | sub($bv; "") | tonumber else empty end' | sort -rn | head -1)
  46. 18
  47. 18 if [ -z "$HIGHEST_PATCH" ]; then NEXT_PATCH=0; else NEXT_PATCH=$((HIGHEST_PATCH + 1)); fi
  48. 9 FULL_VERSION="${BASE_VERSION}.${NEXT_PATCH}"
  49. 9 echo "NEXT_VERSION=$FULL_VERSION" >> /tmp/build-ctx/build.env
  50. 9 echo "gitea-ci-library - Uusi vapaa versio: $FULL_VERSION"
  51. fi

scripts/ci-report.sh

0.0% lines covered

62 relevant lines. 0 lines covered and 62 lines missed.
    
  1. #!/usr/bin/env sh
  2. set -eu
  3. DESCRIPTION="${1:-}"
  4. CONTEXT="${2:-}"
  5. SUITE="${3:-}"
  6. STATUS="${4:-success}"
  7. [ -n "$DESCRIPTION" ] || { echo "ERROR: description argument required" >&2; exit 1; }
  8. [ -n "$CONTEXT" ] || { echo "ERROR: context argument required" >&2; exit 1; }
  9. [ -n "$SUITE" ] || { echo "ERROR: suite argument required" >&2; exit 1; }
  10. REPORT_DIR="reports/${SUITE}"
  11. if [ ! -d "$REPORT_DIR" ]; then
  12. echo "ERROR: $REPORT_DIR not found" >&2
  13. sh .ci/scripts/report-status.sh failure "$DESCRIPTION" "$CONTEXT"
  14. exit 1
  15. fi
  16. FILE_COUNT=0
  17. SUBDIR_COUNT=0
  18. ENTRIES=""
  19. for f in "$REPORT_DIR"/*; do
  20. [ -f "$f" ] || continue
  21. base=$(basename "$f")
  22. [ "$base" = "index.html" ] && continue
  23. FILE_COUNT=$((FILE_COUNT + 1))
  24. ENTRIES="${ENTRIES}file:${base}
  25. "
  26. done
  27. for d in "$REPORT_DIR"/*/; do
  28. [ -d "$d" ] || continue
  29. base=$(basename "$d")
  30. [ -f "$d/index.html" ] || continue
  31. SUBDIR_COUNT=$((SUBDIR_COUNT + 1))
  32. ENTRIES="${ENTRIES}dir:${base}
  33. "
  34. done
  35. TOTAL=$((FILE_COUNT + SUBDIR_COUNT))
  36. if [ "$TOTAL" -eq 0 ]; then
  37. echo "ERROR: no reportable items in $REPORT_DIR" >&2
  38. sh .ci/scripts/report-status.sh failure "$DESCRIPTION" "$CONTEXT"
  39. exit 1
  40. fi
  41. SHA8=$(echo "${GITHUB_SHA:-xxxxxxxx}" | cut -c1-8)
  42. humanize() {
  43. name="$1"
  44. name=$(echo "$name" | sed -e 's/\.[^.]*$//' -e 's/[-_]/ /g')
  45. first=$(echo "$name" | cut -c1 | tr '[:lower:]' '[:upper:]')
  46. rest=$(echo "$name" | cut -c2-)
  47. echo "${first}${rest}"
  48. }
  49. generate_index() {
  50. {
  51. echo '<!DOCTYPE html><html lang="en"><head><meta charset="utf-8">'
  52. echo "<title>$DESCRIPTION</title>"
  53. echo '<style>body{font-family:sans-serif;margin:2em;max-width:960px}h1{color:#1e293b}ul{list-style:none;padding:0}li{margin:.5em 0;padding:.5em;background:#f8fafc;border-radius:6px}a{color:#2563eb;text-decoration:none}a:hover{text-decoration:underline}</style>'
  54. echo "</head><body><h1>$DESCRIPTION</h1><ul>"
  55. echo "$ENTRIES" | while IFS= read -r entry; do
  56. [ -z "$entry" ] && continue
  57. entry_type=$(echo "$entry" | cut -d: -f1)
  58. entry_name=$(echo "$entry" | cut -d: -f2-)
  59. if [ "$entry_type" = "file" ]; then
  60. echo "<li><a href=\"$entry_name\">$(humanize "$entry_name")</a></li>"
  61. else
  62. cap=$(echo "$entry_name" | sed 's/\(.\).*/\1/' | tr '[:lower:]' '[:upper:]')$(echo "$entry_name" | sed 's/.//')
  63. echo "<li><a href=\"$entry_name/index.html\">${cap}</a></li>"
  64. fi
  65. done
  66. echo '</ul></body></html>'
  67. } > "$REPORT_DIR/index.html"
  68. }
  69. STAGED="reports/${SHA8}/${SUITE}"
  70. mkdir -p "$STAGED"
  71. if [ "$TOTAL" -eq 1 ]; then
  72. cp -a "$REPORT_DIR/." "$STAGED/"
  73. sh .ci/scripts/publish-git-pages.sh "$SUITE"
  74. first_entry=$(echo "$ENTRIES" | head -1)
  75. first_type=$(echo "$first_entry" | cut -d: -f1)
  76. first_name=$(echo "$first_entry" | cut -d: -f2-)
  77. if [ "$first_type" = "file" ]; then
  78. SINGLE_ENTRY="$first_name"
  79. else
  80. SINGLE_ENTRY="${first_name}/index.html"
  81. fi
  82. URL="${GIT_PAGES_URL}/${GITHUB_REPOSITORY}/reports/${SHA8}/${SUITE}/${SINGLE_ENTRY}"
  83. sh .ci/scripts/report-status.sh "$STATUS" "$DESCRIPTION" "$CONTEXT" "" "$URL"
  84. else
  85. generate_index
  86. cp -a "$REPORT_DIR/." "$STAGED/"
  87. sh .ci/scripts/publish-git-pages.sh "$SUITE"
  88. sh .ci/scripts/report-status.sh "$STATUS" "$DESCRIPTION" "$CONTEXT" "$SUITE"
  89. fi
  90. rm -rf "$STAGED"

scripts/ci-validate.sh

95.24% lines covered

21 relevant lines. 20 lines covered and 1 lines missed.
    
  1. #!/usr/bin/env bash
  2. 6 set -euo pipefail
  3. 6 CONF_FILE="${CI_CONF_FILE:-.gitea/workflows/gitea-env.conf}"
  4. 7 ERRORS=0
  5. 9 [ -f "$CONF_FILE" ] || { echo "ERROR: $CONF_FILE not found — checkout missing?" >&2; exit 1; }
  6. 6 echo "Reading $CONF_FILE..."
  7. 36 while IFS='=' read -r key value || [ -n "$key" ]; do
  8. 27 key=$(echo "$key" | xargs)
  9. 27 value=$(echo "$value" | xargs)
  10. 10 [ -z "$key" ] && continue
  11. 9 [[ "$key" == "#"* ]] && continue
  12. 9 [ -z "$value" ] && echo "ERROR: $key is empty in $CONF_FILE" >&2 && ERRORS=1
  13. 19 if [ -n "$value" ] && [[ "$key" == *"URL"* ]] && [[ "$value" != http://* ]] && [[ "$value" != https://* ]]; then
  14. 1 echo "ERROR: $key should be a URL (http/https), got: $value" >&2
  15. 1 ERRORS=1
  16. fi
  17. done < "$CONF_FILE"
  18. 8 [ -z "${GITEA_TOKEN:-}" ] && echo "ERROR: GITEA_TOKEN secret is not set" >&2 && ERRORS=1
  19. 8 [ -z "${GIT_PAGES_PUBLISH_TOKEN:-}" ] && echo "ERROR: GIT_PAGES_PUBLISH_TOKEN secret is not set" >&2 && ERRORS=1
  20. 6 if [ "$ERRORS" -ne 0 ]; then
  21. 4 echo "FATAL: CI config validation failed" >&2
  22. 4 exit 1
  23. fi
  24. 2 echo "OK: all CI env vars validated"

scripts/dispatch-workflow.sh

83.33% lines covered

60 relevant lines. 50 lines covered and 10 lines missed.
    
  1. #!/usr/bin/env bash
  2. 13 set -euo pipefail
  3. 13 TARGET_REPO="${1:-}"
  4. 13 WORKFLOW_FILE="${2:-}"
  5. 13 REF="${3:-}"
  6. 13 INPUTS_JSON="${4:-}"
  7. 13 GITEA_API_URL="${5:-}"
  8. 13 GITEA_TOKEN="${6:-}"
  9. 13 TIMEOUT_MINUTES="${7:-360}"
  10. 13 POLL_INTERVAL="${DISPATCH_POLL_INTERVAL:-10}"
  11. 15 [ -z "$TARGET_REPO" ] && echo "ERROR: target_repo argument is required" >&2 && exit 1
  12. 14 [ -z "$WORKFLOW_FILE" ] && echo "ERROR: workflow_file argument is required" >&2 && exit 1
  13. 13 [ -z "$REF" ] && echo "ERROR: ref argument is required" >&2 && exit 1
  14. 12 [ -z "$INPUTS_JSON" ] && echo "ERROR: inputs_json argument is required" >&2 && exit 1
  15. 11 [ -z "$GITEA_API_URL" ] && echo "ERROR: gitea_api_url argument is required" >&2 && exit 1
  16. 10 [ -z "$GITEA_TOKEN" ] && echo "ERROR: gitea_token argument is required" >&2 && exit 1
  17. # Generate unique dispatch_id for display_title matching
  18. # Can be overridden via DISPATCH_ID env var (for tests)
  19. 7 DISPATCH_ID="${DISPATCH_ID:-$(xxd -l 4 -p /dev/urandom 2>/dev/null || openssl rand -hex 4 2>/dev/null || date +%s | md5sum | head -c 8)}"
  20. 21 INPUTS_JSON=$(echo "$INPUTS_JSON" | jq --arg id "$DISPATCH_ID" '. + {dispatch_id: $id}')
  21. 7 DISPATCH_URL="$GITEA_API_URL/api/v1/repos/$TARGET_REPO/actions/workflows/$WORKFLOW_FILE/dispatches"
  22. 14 DISPATCH_BODY=$(jq -nc --arg ref "$REF" --argjson inputs "$INPUTS_JSON" '{ref: $ref, inputs: $inputs}')
  23. DISPATCH_CODE=$(curl -s -o /dev/null -w "%{http_code}" \
  24. --connect-timeout 5 --max-time 10 \
  25. -X POST "$DISPATCH_URL" \
  26. -H "Authorization: token $GITEA_TOKEN" \
  27. -H "Content-Type: application/json" \
  28. 14 -d "$DISPATCH_BODY")
  29. 7 if [ "$DISPATCH_CODE" != "201" ]; then
  30. 1 echo "ERROR: Dispatch failed with HTTP $DISPATCH_CODE" >&2
  31. 1 exit 1
  32. fi
  33. # Poll: find dispatched run by display_title matching
  34. 6 RUN_ID=""
  35. 12 TIMEOUT_SECONDS=$(awk "BEGIN {printf \"%.3f\", $TIMEOUT_MINUTES * 60}")
  36. 12 START_TIME=$(date +%s)
  37. 15 while [ -z "$RUN_ID" ]; do
  38. 22 NOW=$(date +%s)
  39. 11 ELAPSED=$((NOW - START_TIME))
  40. 11 if awk -v e="$ELAPSED" -v t="$TIMEOUT_SECONDS" 'BEGIN { exit !(e >= t) }'; then
  41. 2 echo "ERROR: Timeout after ${TIMEOUT_MINUTES} minutes — run not found" >&2
  42. 2 exit 124
  43. fi
  44. RUNS_RESP=$(curl -s --connect-timeout 5 --max-time 10 \
  45. "$GITEA_API_URL/api/v1/repos/$TARGET_REPO/actions/runs?event=workflow_dispatch&limit=10" \
  46. 18 -H "Authorization: token $GITEA_TOKEN")
  47. 27 RUN_ID=$(echo "$RUNS_RESP" | jq -r --arg id "$DISPATCH_ID" \
  48. 27 '[.workflow_runs[] | select(.display_title | contains($id))] | .[0].id // empty')
  49. 14 [ -z "$RUN_ID" ] && sleep "$POLL_INTERVAL"
  50. done
  51. # Poll: wait for run to complete
  52. 8 while true; do
  53. 16 NOW=$(date +%s)
  54. 8 ELAPSED=$((NOW - START_TIME))
  55. 8 if awk -v e="$ELAPSED" -v t="$TIMEOUT_SECONDS" 'BEGIN { exit !(e >= t) }'; then
  56. echo "ERROR: Timeout after ${TIMEOUT_MINUTES} minutes" >&2
  57. exit 124
  58. fi
  59. 8 RUN_URL="$GITEA_API_URL/api/v1/repos/$TARGET_REPO/actions/runs/$RUN_ID"
  60. RUN_RESP=$(curl -s --connect-timeout 5 --max-time 10 \
  61. 16 -H "Authorization: token $GITEA_TOKEN" "$RUN_URL")
  62. 24 STATUS=$(echo "$RUN_RESP" | jq -r '.status // "running"')
  63. 8 if [ "$STATUS" = "completed" ]; then
  64. 12 CONCLUSION=$(echo "$RUN_RESP" | jq -r '.conclusion // "failure"')
  65. 4 if [ "$CONCLUSION" = "success" ]; then
  66. 2 exit 0
  67. fi
  68. 2 echo "ERROR: Workflow completed with conclusion: $CONCLUSION" >&2
  69. 2 exit 1
  70. fi
  71. 4 sleep "$POLL_INTERVAL"
  72. done

scripts/gitops-update.sh

44.78% lines covered

67 relevant lines. 30 lines covered and 37 lines missed.
    
  1. #!/usr/bin/env bash
  2. 14 set -euo pipefail
  3. 56 SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
  4. _gitops_fail() {
  5. 10 local MSG="${1:-GitOps update failed}"
  6. 10 echo "[ERROR] ${MSG}" >&2
  7. 19 if [ -n "${GITOPS_REPO:-}" ] && [ -n "${GITOPS_SHA:-}" ] && \
  8. [ -n "${SOURCE_REPO:-}" ] && [ -n "${SOURCE_COMMIT:-}" ] && \
  9. [ -n "${GITEA_API_URL:-}" ] && [ -n "${GITEA_TOKEN:-}" ]; then
  10. local env repo context
  11. env=$(dirname "${INPUT_FILE}")
  12. repo=$(basename "${SOURCE_REPO}")
  13. context="${repo}"
  14. [ -n "${GIT_TAG_PREFIX:-}" ] && context="${repo}/${GIT_TAG_PREFIX}"
  15. local SOURCE_URL="${GITEA_API_URL}/${SOURCE_REPO}/commit/${SOURCE_COMMIT}"
  16. ROOT_REPO="${GITOPS_REPO}" ROOT_COMMIT="${GITOPS_SHA}" \
  17. GITEA_API_URL="${GITEA_API_URL}" GITEA_TOKEN="${GITEA_TOKEN}" \
  18. bash "${SCRIPT_DIR}/report-status.sh" failure "Install to ${env} ${VERSION}" \
  19. "${context}" "" "${SOURCE_URL}" 2>/dev/null || true
  20. fi
  21. 10 exit 1
  22. }
  23. _gitops_validate() {
  24. 15 [ -n "${INPUT_FILE:-}" ] || _gitops_fail "INPUT_FILE is required"
  25. 14 [ -n "${YQ_TPL:-}" ] || _gitops_fail "YQ_TPL is required"
  26. 13 [ -n "${VERSION:-}" ] || _gitops_fail "VERSION is required"
  27. 12 [ -n "${SOURCE_REPO:-}" ] || _gitops_fail "SOURCE_REPO is required"
  28. 11 [ -n "${SOURCE_COMMIT:-}" ] || _gitops_fail "SOURCE_COMMIT is required"
  29. 10 [ -n "${GITOPS_REPO:-}" ] || _gitops_fail "GITOPS_REPO is required"
  30. 9 [ -n "${GITEA_TOKEN:-}" ] || _gitops_fail "GITEA_TOKEN is required"
  31. 8 [ -n "${GITEA_API_URL:-}" ] || _gitops_fail "GITEA_API_URL is required"
  32. }
  33. _gitops_success() {
  34. local env repo context
  35. env=$(dirname "${INPUT_FILE}")
  36. repo=$(basename "${SOURCE_REPO}")
  37. context="${repo}"
  38. [ -n "${GIT_TAG_PREFIX:-}" ] && context="${repo}/${GIT_TAG_PREFIX}"
  39. local SOURCE_URL="${GITEA_API_URL}/${SOURCE_REPO}/commit/${SOURCE_COMMIT}"
  40. ROOT_REPO="${GITOPS_REPO}" ROOT_COMMIT="${GITOPS_SHA}" \
  41. GITEA_API_URL="${GITEA_API_URL}" GITEA_TOKEN="${GITEA_TOKEN}" \
  42. bash "${SCRIPT_DIR}/report-status.sh" success \
  43. "Install to ${env} ${VERSION}" \
  44. "${context}" "" "${SOURCE_URL}"
  45. }
  46. _gitops_nochange() {
  47. local env repo context
  48. env=$(dirname "${INPUT_FILE}")
  49. repo=$(basename "${SOURCE_REPO}")
  50. context="${repo}"
  51. [ -n "${GIT_TAG_PREFIX:-}" ] && context="${repo}/${GIT_TAG_PREFIX}"
  52. local SOURCE_URL="${GITEA_API_URL}/${SOURCE_REPO}/commit/${SOURCE_COMMIT}"
  53. ROOT_REPO="${GITOPS_REPO}" ROOT_COMMIT="${GITOPS_SHA}" \
  54. GITEA_API_URL="${GITEA_API_URL}" GITEA_TOKEN="${GITEA_TOKEN}" \
  55. bash "${SCRIPT_DIR}/report-status.sh" success \
  56. "Install to ${env} ${VERSION} — no change" \
  57. "${context}" "" "${SOURCE_URL}"
  58. }
  59. _gitops_substitute() {
  60. 16 echo "$1" | sed "s/{{VERSION}}/$2/g"
  61. }
  62. _gitops_update() {
  63. 4 local CLONE_DIR="${GITOPS_TARGET_DIR:-$(mktemp -d)}"
  64. 2 if [ -n "${GITOPS_CLONE_URL:-}" ]; then
  65. git clone "${GITOPS_CLONE_URL}" "${CLONE_DIR}" || _gitops_fail "Failed to clone GitOps repo"
  66. else
  67. 2 git clone "${CLONE_URL}" "${CLONE_DIR}" || _gitops_fail "Failed to clone GitOps repo"
  68. fi
  69. 2 cd "${CLONE_DIR}" || _gitops_fail "Failed to enter clone directory"
  70. 2 yq eval -i "${YQ_EXPR}" "${INPUT_FILE}" || _gitops_fail "Failed to update ${INPUT_FILE}"
  71. 2 git add "${INPUT_FILE}" || _gitops_fail "Failed to stage ${INPUT_FILE}"
  72. 2 if git diff --cached --quiet; then
  73. echo "No changes — ${INPUT_FILE} already at ${VERSION}"
  74. GITOPS_SHA="$(git rev-parse HEAD)"
  75. _gitops_nochange
  76. exit 0
  77. fi
  78. 2 git -c user.name="gitea-ci-bot" \
  79. -c user.email="ci@keskikuja.site" \
  80. 2 commit -m "[skip ci] gitops: update version to ${VERSION}" || _gitops_fail "Failed to commit"
  81. GITOPS_SHA="$(git rev-parse HEAD)"
  82. git push || _gitops_fail "Failed to push"
  83. _gitops_success
  84. }
  85. 14 _gitops_validate
  86. 12 YQ_EXPR=$(_gitops_substitute "${YQ_TPL}" "${VERSION}")
  87. 24 GITEA_HOST=$(echo "${GITEA_API_URL}" | sed 's|https://||' | sed 's|http://||')
  88. 6 CLONE_URL="${GITOPS_CLONE_URL:-https://${GITEA_TOKEN}@${GITEA_HOST}/${GITOPS_REPO}.git}"
  89. 6 if [ "${BASH_SOURCE[0]}" = "${0}" ]; then
  90. 2 _gitops_update
  91. fi

scripts/poc-dispatch-match.sh

0.0% lines covered

107 relevant lines. 0 lines covered and 107 lines missed.
    
  1. #!/usr/bin/env bash
  2. set -euo pipefail
  3. #
  4. # POC: testaa display_title-matchingia dispatchatuille workflow runeille.
  5. #
  6. # Ajaa kaksi testiä:
  7. # A — dispatchaa gitea-ci-library:n poc-dispatch.yml (tämä repo, feature-haara)
  8. # B — dispatchaa gitea-ci-gitops-tests:n gitops-service.yaml
  9. #
  10. # Käyttö:
  11. # export GITEA_API_URL=https://gitea.app.keskikuja.site
  12. # export GITEA_TOKEN=...
  13. # bash scripts/poc-dispatch-match.sh
  14. #
  15. GITEA_API_URL="${GITEA_API_URL:?GITEA_API_URL is required}"
  16. GITEA_TOKEN="${GITEA_TOKEN:?GITEA_TOKEN is required}"
  17. BRANCH="${BRANCH:-feature/gitops}"
  18. TIMEOUT_SECONDS="${TIMEOUT_SECONDS:-60}"
  19. POLL_INTERVAL="${POLL_INTERVAL:-5}"
  20. GITOPS_REPO="${GITOPS_REPO:-niko/gitea-ci-gitops-tests}"
  21. GITOPS_WORKFLOW="${GITOPS_WORKFLOW:-gitops-service.yaml}"
  22. LIB_REPO="${LIB_REPO:-niko/gitea-ci-library}"
  23. LIB_WORKFLOW="${LIB_WORKFLOW:-poc-dispatch.yml}"
  24. PASS=0
  25. FAIL=0
  26. _ts() {
  27. date -u +%Y-%m-%dT%H:%M:%SZ
  28. }
  29. _report() {
  30. local label="$1" status="$2" detail="$3"
  31. if [ "$status" = "PASS" ]; then
  32. PASS=$((PASS + 1))
  33. echo " ✅ $label: $detail"
  34. else
  35. FAIL=$((FAIL + 1))
  36. echo " ❌ $label: $detail"
  37. fi
  38. }
  39. _dispatch_and_poll() {
  40. local label="$1" target_repo="$2" workflow_file="$3" ref="$4" dispatch_id="$5"
  41. local inputs_json="$6"
  42. echo ""
  43. echo "=== Test: $label ==="
  44. echo " target: $target_repo"
  45. echo " workflow: $workflow_file"
  46. echo " ref: $ref"
  47. echo " dispatch_id: $dispatch_id"
  48. # 1. Ennen dispatchia: ota snapshot viimeisimmästä run_number:sta
  49. local before_resp before_run before_count
  50. before_resp=$(curl -s --connect-timeout 5 --max-time 10 \
  51. "$GITEA_API_URL/api/v1/repos/$target_repo/actions/runs?event=workflow_dispatch&limit=1" \
  52. -H "Authorization: token $GITEA_TOKEN")
  53. before_run=$(echo "$before_resp" | jq -r '.workflow_runs[0].run_number // 0')
  54. before_count=$(echo "$before_resp" | jq -r '.total_count // 0')
  55. echo " before: $before_count runs, latest run_number=$before_run"
  56. # 2. Dispatch
  57. local dispatch_url="$GITEA_API_URL/api/v1/repos/$target_repo/actions/workflows/$workflow_file/dispatches"
  58. local dispatch_body
  59. dispatch_body=$(jq -nc --arg ref "$ref" --argjson inputs "$inputs_json" '{ref: $ref, inputs: $inputs}')
  60. local dispatch_code
  61. dispatch_code=$(curl -s -o /dev/null -w "%{http_code}" --connect-timeout 5 --max-time 10 \
  62. -X POST "$dispatch_url" \
  63. -H "Authorization: token $GITEA_TOKEN" \
  64. -H "Content-Type: application/json" \
  65. -d "$dispatch_body")
  66. if [ "$dispatch_code" != "201" ] && [ "$dispatch_code" != "204" ]; then
  67. _report "$label" "FAIL" "Dispatch failed with HTTP $dispatch_code"
  68. return
  69. fi
  70. echo " dispatch: HTTP $dispatch_code — started"
  71. # 3. Pollaa: etsi run jossa display_title sisältää dispatch_id:n
  72. local start_time elapsed found=""
  73. start_time=$(date +%s)
  74. while true; do
  75. elapsed=$(( $(date +%s) - start_time ))
  76. if [ "$elapsed" -ge "$TIMEOUT_SECONDS" ]; then
  77. break
  78. fi
  79. local runs_resp found_id found_display found_status found_run_num
  80. runs_resp=$(curl -s --connect-timeout 5 --max-time 10 \
  81. "$GITEA_API_URL/api/v1/repos/$target_repo/actions/runs?event=workflow_dispatch&limit=20" \
  82. -H "Authorization: token $GITEA_TOKEN")
  83. found_id=$(echo "$runs_resp" | jq -r --arg id "$dispatch_id" \
  84. '[.workflow_runs[] | select(.display_title | contains($id))] | .[0].id // empty')
  85. if [ -n "$found_id" ] && [ "$found_id" != "null" ]; then
  86. found_display=$(echo "$runs_resp" | jq -r --arg id "$dispatch_id" \
  87. '[.workflow_runs[] | select(.display_title | contains($id))] | .[0].display_title // "?"')
  88. found_status=$(echo "$runs_resp" | jq -r --arg id "$dispatch_id" \
  89. '[.workflow_runs[] | select(.display_title | contains($id))] | .[0].status // "?"')
  90. found_run_num=$(echo "$runs_resp" | jq -r --arg id "$dispatch_id" \
  91. '[.workflow_runs[] | select(.display_title | contains($id))] | .[0].run_number // "?"')
  92. echo " found: id=$found_id run_number=$found_run_num status=$found_status display_title=\"$found_display\" (after ${elapsed}s)"
  93. # Odota että run on completed
  94. local poll_url="$GITEA_API_URL/api/v1/repos/$target_repo/actions/runs/$found_id"
  95. while [ "$elapsed" -lt "$TIMEOUT_SECONDS" ]; do
  96. local run_resp run_status run_conclusion
  97. run_resp=$(curl -s --connect-timeout 5 --max-time 10 \
  98. "$poll_url" -H "Authorization: token $GITEA_TOKEN")
  99. run_status=$(echo "$run_resp" | jq -r '.status // "unknown"')
  100. if [ "$run_status" = "completed" ]; then
  101. run_conclusion=$(echo "$run_resp" | jq -r '.conclusion // "?"')
  102. elapsed=$(( $(date +%s) - start_time ))
  103. _report "$label" "PASS" "display_title matched, status=$run_status conclusion=$run_conclusion run_number=$found_run_num (${elapsed}s)"
  104. echo " run detail: id=$found_id display_title=\"$found_display\""
  105. echo " endpoint: $GITEA_API_URL/$target_repo/actions/runs/$found_id"
  106. return
  107. fi
  108. sleep "$POLL_INTERVAL"
  109. elapsed=$(( $(date +%s) - start_time ))
  110. done
  111. _report "$label" "FAIL" "Run found but didn't complete within ${TIMEOUT_SECONDS}s"
  112. return
  113. fi
  114. sleep "$POLL_INTERVAL"
  115. done
  116. _report "$label" "FAIL" "No run with display_title containing \"$dispatch_id\" found within ${TIMEOUT_SECONDS}s"
  117. }
  118. # Tallenna aloitusaika
  119. POC_START=$(_ts)
  120. echo "=============================================="
  121. echo "POC: dispatch-workflow display_title matching"
  122. echo "Started: $POC_START"
  123. echo "API URL: $GITEA_API_URL"
  124. echo "=============================================="
  125. # Testi A: dispatchaa tämän repon poc-dispatch.yml
  126. DISPATCH_ID_A=$(xxd -l 4 -p /dev/urandom 2>/dev/null || openssl rand -hex 4 2>/dev/null || date +%s | md5sum | head -c 8)
  127. INPUTS_A=$(jq -nc \
  128. --arg dispatch_id "$DISPATCH_ID_A" \
  129. --arg type "local" \
  130. '{dispatch_id: $dispatch_id, type: $type}')
  131. _dispatch_and_poll \
  132. "A: local poc-dispatch" \
  133. "$LIB_REPO" "$LIB_WORKFLOW" "$BRANCH" \
  134. "$DISPATCH_ID_A" "$INPUTS_A"
  135. # Testi B: dispatchaa gitea-ci-gitops-tests gitops-service.yaml
  136. DISPATCH_ID_B=$(xxd -l 4 -p /dev/urandom 2>/dev/null || openssl rand -hex 4 2>/dev/null || date +%s | md5sum | head -c 8)
  137. INPUTS_B=$(jq -nc \
  138. --arg dispatch_id "$DISPATCH_ID_B" \
  139. --arg file "dev/Chart.yaml" \
  140. --arg yq_tpl '.version = "{{VERSION}}"' \
  141. --arg version "0.1.1" \
  142. --arg source_repo "$LIB_REPO" \
  143. --arg source_commit "poc-test-$(date +%s)" \
  144. '{dispatch_id: $dispatch_id, file: $file, yq_tpl: $yq_tpl, version: $version, source_repo: $source_repo, source_commit: $source_commit}')
  145. _dispatch_and_poll \
  146. "B: gitops test" \
  147. "$GITOPS_REPO" "$GITOPS_WORKFLOW" "main" \
  148. "$DISPATCH_ID_B" "$INPUTS_B"
  149. # Loppuraportti
  150. echo ""
  151. echo "=============================================="
  152. echo "POC complete"
  153. echo " PASS: $PASS"
  154. echo " FAIL: $FAIL"
  155. echo "=============================================="
  156. if [ "$FAIL" -gt 0 ]; then
  157. exit 1
  158. fi

scripts/publish-git-pages.sh

78.05% lines covered

82 relevant lines. 64 lines covered and 18 lines missed.
    
  1. 3 #!/usr/bin/env sh
  2. 9 set -eu
  3. 9 SUITE_PATH="${1:-}"
  4. 11 [ -n "$SUITE_PATH" ] || { echo "ERROR: suite_path argument required" >&2; exit 1; }
  5. 10 [ -n "${GITEA_API_URL:-}" ] || { echo "ERROR: GITEA_API_URL is not set" >&2; exit 1; }
  6. 9 [ -n "${GIT_PAGES_URL:-}" ] || { echo "ERROR: GIT_PAGES_URL is not set" >&2; exit 1; }
  7. 8 [ -n "${GIT_PAGES_PUBLISH_TOKEN:-}" ] || { echo "ERROR: GIT_PAGES_PUBLISH_TOKEN is not set" >&2; exit 1; }
  8. 7 [ -n "${GITHUB_REPOSITORY:-}" ] || { echo "ERROR: GITHUB_REPOSITORY is not set" >&2; exit 1; }
  9. 4 [ -n "${GITHUB_SHA:-}" ] || { echo "ERROR: GITHUB_SHA is not set" >&2; exit 1; }
  10. 4 OWNER="${GITHUB_REPOSITORY%%/*}"
  11. 4 REPO="${GITHUB_REPOSITORY##*/}"
  12. 12 SHA8=$(echo "$GITHUB_SHA" | cut -c1-8)
  13. 4 PAGES_USER="${GIT_PAGES_PUBLISH_USER:-publish}"
  14. 4 REPORT_DIR="reports/${SHA8}/${SUITE_PATH%/}"
  15. 4 REPORT_BASE="${GIT_PAGES_URL}/${OWNER}/${REPO}/reports/${SHA8}"
  16. 6 [ -d "$REPORT_DIR" ] || { echo "ERROR: not a directory: $REPORT_DIR" >&2; exit 1; }
  17. 3 PUBLISH_SITE_URL="${GIT_PAGES_URL}/"
  18. 6 WORK=$(mktemp -d)
  19. 6 TAR=$(mktemp)
  20. 3 trap 'rm -rf "$WORK" "$TAR"' EXIT
  21. 3 RELPATH="${REPORT_DIR#reports/${SHA8}/}"
  22. 6 if [ "$RELPATH" != "$REPORT_DIR" ] && [ -n "$RELPATH" ]; then
  23. 3 TARGET="$WORK/${OWNER}/${REPO}/reports/${SHA8}/${RELPATH}"
  24. else
  25. TARGET="$WORK/${OWNER}/${REPO}/reports/${SHA8}"
  26. fi
  27. 3 mkdir -p "$TARGET"
  28. 3 cp -a "$REPORT_DIR/." "$TARGET/"
  29. 3 if [ ! -f "$TARGET/index.html" ]; then
  30. 1 ITEM_LIST=""
  31. 1 ITEM_COUNT=0
  32. 1 for f in "$TARGET"/*; do
  33. 1 [ -f "$f" ] || continue
  34. 2 base=$(basename "$f")
  35. 1 [ "$base" = "index.html" ] && continue
  36. 1 ITEM_LIST="${ITEM_LIST}file:${base}
  37. 1 "
  38. 1 ITEM_COUNT=$((ITEM_COUNT + 1))
  39. 1 done
  40. 1
  41. 1 for d in "$TARGET"/*/; do
  42. 2 [ -d "$d" ] || continue
  43. base=$(basename "$d")
  44. [ -f "$d/index.html" ] || continue
  45. 1 ITEM_LIST="${ITEM_LIST}dir:${base}
  46. 1 "
  47. 1 ITEM_COUNT=$((ITEM_COUNT + 1))
  48. 1 done
  49. 1
  50. 1 if [ "$ITEM_COUNT" -gt 1 ]; then
  51. {
  52. echo '<!DOCTYPE html><html lang="en"><head><meta charset="utf-8">'
  53. echo "<title>Test report ${SHA8}</title>"
  54. echo '<style>body{font-family:sans-serif;margin:2em;max-width:960px}'
  55. echo 'h1{color:#1e293b}ul{list-style:none;padding:0}'
  56. echo 'li{margin:.5em 0;padding:.5em;background:#f8fafc;border-radius:6px}'
  57. echo 'a{color:#2563eb;text-decoration:none}a:hover{text-decoration:underline}'
  58. echo '</style></head><body>'
  59. echo "<h1>Test report <code>${SHA8}</code></h1><ul>"
  60. echo "$ITEM_LIST" | while IFS= read -r item; do
  61. [ -z "$item" ] && continue
  62. item_type=$(echo "$item" | cut -d: -f1)
  63. item_name=$(echo "$item" | cut -d: -f2-)
  64. label=$(echo "$item_name" | sed -e 's/\.[^.]*$//' -e 's/[-_]/ /g')
  65. first=$(echo "$label" | cut -c1 | tr '[:lower:]' '[:upper:]')
  66. rest=$(echo "$label" | cut -c2-)
  67. if [ "$item_type" = "file" ]; then
  68. echo "<li><a href=\"$item_name\">${first}${rest}</a></li>"
  69. else
  70. echo "<li><a href=\"$item_name/index.html\">${first}${rest}</a></li>"
  71. fi
  72. done
  73. echo '</ul></body></html>'
  74. } > "$TARGET/index.html"
  75. fi
  76. fi
  77. 6 cat > "$TARGET/.meta" <<EOF
  78. 6 {"branch":"${GITHUB_REF_NAME:-}","sha":"${GITHUB_SHA}","published_at":"$(date -u +%Y-%m-%dT%H:%M:%SZ)"}
  79. 6 EOF
  80. 9 find "$WORK/$OWNER" \( -type f -o -type l \) -print | sed "s|^${WORK}/||" | tar -cf "$TAR" -C "$WORK" -T -
  81. publish() {
  82. 3 method="$1"
  83. 3 curl -sS -X "$method" "$PUBLISH_SITE_URL" \
  84. 3 -u "${PAGES_USER}:${GIT_PAGES_PUBLISH_TOKEN}" \
  85. 3 -H "Content-Type: application/x-tar" \
  86. 3 -H "Atomic: no" \
  87. 3 -H "Create-Parents: yes" \
  88. 3 --data-binary @"$TAR" \
  89. 3 -o /tmp/git-pages-publish-response.txt \
  90. 3 -w "%{http_code}"
  91. }
  92. 6 HTTP_CODE=$(publish PATCH)
  93. 3 case "$HTTP_CODE" in
  94. 200|201|204) ;;
  95. *)
  96. 1 echo "ERROR: git-pages publish HTTP ${HTTP_CODE}" >&2
  97. 1 cat /tmp/git-pages-publish-response.txt >&2
  98. 1 exit 1
  99. ;;
  100. esac
  101. 2 echo "$REPORT_BASE"

scripts/publish.sh

70.0% lines covered

10 relevant lines. 7 lines covered and 3 lines missed.
    
  1. #!/usr/bin/env bash
  2. 5 set -euo pipefail
  3. 5 SUITE_PATH="${1:-}"
  4. 7 [ -n "$SUITE_PATH" ] || { echo "ERROR: suite_path argument required" >&2; exit 1; }
  5. 6 [ -n "${GITEA_API_URL:-}" ] || { echo "ERROR: GITEA_API_URL is not set" >&2; exit 1; }
  6. 5 [ -n "${GITEA_TOKEN:-}" ] || { echo "ERROR: GITEA_TOKEN is not set" >&2; exit 1; }
  7. 4 [ -n "${GIT_PAGES_URL:-}" ] || { echo "ERROR: GIT_PAGES_URL is not set" >&2; exit 1; }
  8. 3 [ -n "${GIT_PAGES_PUBLISH_TOKEN:-}" ] || { echo "ERROR: GIT_PAGES_PUBLISH_TOKEN is not set" >&2; exit 1; }
  9. SCRIPT_DIR="$(dirname "$0")"
  10. REPORT_URL=$(bash "$SCRIPT_DIR/publish-git-pages.sh" "$SUITE_PATH")
  11. echo "Published: $REPORT_URL"
  12. bash "$SCRIPT_DIR/report-status.sh" success "Reports published" "ci-report"

scripts/report-status.sh

81.82% lines covered

33 relevant lines. 27 lines covered and 6 lines missed.
    
  1. #!/usr/bin/env sh
  2. 10 set -eu
  3. 10 STATE="${1:-}"
  4. 10 DESCRIPTION="${2:-}"
  5. 30 SHA8=$(echo "${GITHUB_SHA:-}" | cut -c1-8)
  6. 10 KEY="${3:-commit-${SHA8}}"
  7. 10 SUITE="${4:-}"
  8. 10 CUSTOM_URL="${5:-}"
  9. 12 [ -z "$STATE" ] && echo "ERROR: state argument is required" >&2 && exit 1
  10. 11 [ -z "$DESCRIPTION" ] && echo "ERROR: description argument is required" >&2 && exit 1
  11. 10 [ -z "${GITEA_API_URL:-}" ] && echo "ERROR: GITEA_API_URL is not set" >&2 && exit 1
  12. 9 [ -z "${GITEA_TOKEN:-}" ] && echo "ERROR: GITEA_TOKEN is not set" >&2 && exit 1
  13. 6 if [ -n "$CUSTOM_URL" ]; then
  14. URL="$CUSTOM_URL"
  15. 6 elif [ -n "$SUITE" ]; then
  16. 1 SUITE="${SUITE%/}/"
  17. 3 SHA8_CUT=$(echo "$GITHUB_SHA" | cut -c1-8)
  18. 1 URL="${GIT_PAGES_URL}/${GITHUB_REPOSITORY}/reports/${SHA8_CUT}/${SUITE}"
  19. else
  20. 5 URL="${GITEA_API_URL}/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID}"
  21. fi
  22. 6 REPO="${ROOT_REPO:-${GITHUB_REPOSITORY:-}}"
  23. 6 COMMIT="${ROOT_COMMIT:-${GITHUB_SHA:-}}"
  24. 6 [ -z "$REPO" ] && echo "ERROR: GITHUB_REPOSITORY is not set" >&2 && exit 1
  25. 6 [ -z "$COMMIT" ] && echo "ERROR: GITHUB_SHA is not set" >&2 && exit 1
  26. HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" \
  27. -X POST "$GITEA_API_URL/api/v1/repos/$REPO/statuses/$COMMIT" \
  28. -H "Authorization: token $GITEA_TOKEN" \
  29. -H "Content-Type: application/json" \
  30. 12 -d "{\"state\":\"$STATE\",\"target_url\":\"$URL\",\"description\":\"$DESCRIPTION\",\"context\":\"$KEY\"}" || true)
  31. 6 if [ "$HTTP_CODE" = "201" ]; then
  32. 5 exit 0
  33. fi
  34. 2 if [ -z "$HTTP_CODE" ] || [ "$HTTP_CODE" = "000" ]; then
  35. echo "gitea-ci-library - ERROR: Failed to connect to Gitea API at $GITEA_API_URL" >&2
  36. else
  37. 1 echo "gitea-ci-library - ERROR: gitea-ci-library, API returned HTTP $HTTP_CODE" >&2
  38. fi
  39. 1 exit 1