pipeline siivous ja testikattavuuden nosto (#9)
Co-authored-by: moilanik <niko.moilanen@tietoevry.com> Reviewed-on: #9
This commit is contained in:
Executable
+37
@@ -0,0 +1,37 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
WORKSPACE_VOLUME="${1:-}"
|
||||||
|
REPORT_DIR="${2:-}"
|
||||||
|
|
||||||
|
[ -n "$WORKSPACE_VOLUME" ] || { echo "ERROR: workspace volume name required" >&2; exit 1; }
|
||||||
|
[ -n "$REPORT_DIR" ] || { echo "ERROR: report directory required" >&2; exit 1; }
|
||||||
|
|
||||||
|
HAS_COVERAGE=false
|
||||||
|
COVERAGE_SRC=""
|
||||||
|
if docker run --rm -v "$WORKSPACE_VOLUME":/data alpine sh -c '[ -d /data/coverage ] && ls -A /data/coverage | grep -q .' 2>/dev/null; then
|
||||||
|
COVERAGE_SRC="/data/coverage"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -n "$COVERAGE_SRC" ]; then
|
||||||
|
mkdir -p "$REPORT_DIR/coverage"
|
||||||
|
docker run --rm -v "$WORKSPACE_VOLUME":/data alpine tar c -C "$COVERAGE_SRC" . | tar x -C "$REPORT_DIR/coverage"
|
||||||
|
HAS_COVERAGE=true
|
||||||
|
fi
|
||||||
|
|
||||||
|
cat > "$REPORT_DIR/index.html" << EOF
|
||||||
|
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8">
|
||||||
|
<title>Bats report ${GITHUB_SHA:0:8}</title>
|
||||||
|
<style>body{font-family:sans-serif;margin:2em;max-width:960px}
|
||||||
|
h1{color:#1e293b}a{color:#2563eb;text-decoration:none}a:hover{text-decoration:underline}
|
||||||
|
</style></head><body>
|
||||||
|
<h1>Bats report <code>${GITHUB_SHA:0:8}</code></h1>
|
||||||
|
<ul>
|
||||||
|
<li><a href="test-report.html">Test results</a></li>
|
||||||
|
EOF
|
||||||
|
|
||||||
|
if [ "$HAS_COVERAGE" = true ]; then
|
||||||
|
echo '<li><a href="coverage/index.html">Coverage report</a></li>' >> "$REPORT_DIR/index.html"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo '</ul></body></html>' >> "$REPORT_DIR/index.html"
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
REPORT_DIR="${1:-reports/bats}"
|
||||||
|
INPUT="$REPORT_DIR/results.txt"
|
||||||
|
OUTPUT="$REPORT_DIR/test-report.html"
|
||||||
|
|
||||||
|
[ -f "$INPUT" ] || { echo "ERROR: $INPUT not found" >&2; exit 1; }
|
||||||
|
|
||||||
|
TOTAL=$(grep -cE '^(ok|not ok) ' "$INPUT" 2>/dev/null) || TOTAL=0
|
||||||
|
PASS=$(grep -c '^ok ' "$INPUT" 2>/dev/null) || PASS=0
|
||||||
|
FAIL=$((TOTAL - PASS))
|
||||||
|
|
||||||
|
{
|
||||||
|
echo '<!DOCTYPE html><html lang="en"><head><meta charset="utf-8">'
|
||||||
|
echo "<title>Bats test report ${GITHUB_SHA:0:8}</title>"
|
||||||
|
echo '<style>body{font-family:sans-serif;margin:2em;max-width:960px}'
|
||||||
|
echo 'h1{color:#1e293b}.pass{color:#059669}.fail{color:#dc2626}'
|
||||||
|
echo 'table{width:100%;border-collapse:collapse;margin-top:1em}'
|
||||||
|
echo 'th,td{border:1px solid #e2e8f0;padding:8px;text-align:left}'
|
||||||
|
echo 'th{background:#f8fafc}</style></head><body>'
|
||||||
|
echo "<h1>Bats test report <code>${GITHUB_SHA:0:8}</code></h1>"
|
||||||
|
echo "<p>Total: ${TOTAL} | Passed: <span class='pass'>${PASS}</span> | Failed: <span class='fail'>${FAIL}</span></p>"
|
||||||
|
echo '<table><tr><th>#</th><th>Status</th><th>Test</th></tr>'
|
||||||
|
|
||||||
|
while IFS=' ' read -r status num rest; do
|
||||||
|
case "$status" in
|
||||||
|
ok) echo "<tr><td>${num}</td><td class='pass'>PASS</td><td>${rest}</td></tr>" ;;
|
||||||
|
not) echo "<tr><td>${num}</td><td class='fail'>FAIL</td><td>${rest}</td></tr>" ;;
|
||||||
|
esac
|
||||||
|
done < <(grep -E '^(ok|not ok) ' "$INPUT")
|
||||||
|
|
||||||
|
echo '</table></body></html>'
|
||||||
|
} > "$OUTPUT"
|
||||||
|
|
||||||
|
echo "$OUTPUT"
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
SHA8="${GITHUB_SHA:0:8}"
|
||||||
|
REPORTS_DIR="reports/${SHA8}"
|
||||||
|
|
||||||
|
mkdir -p "${REPORTS_DIR}"
|
||||||
|
|
||||||
|
BATS_PASS=$(grep -c 'ok' "${REPORTS_DIR}/bats/results.txt" 2>/dev/null || echo 0)
|
||||||
|
BATS_FAIL=$(grep -c 'not ok' "${REPORTS_DIR}/bats/results.txt" 2>/dev/null || echo 0)
|
||||||
|
CUCUMBER_PASS=$(jq '.summary.passed // 0' "${REPORTS_DIR}/cucumber/report.json" 2>/dev/null || echo 0)
|
||||||
|
CUCUMBER_FAIL=$(jq '.summary.failed // 0' "${REPORTS_DIR}/cucumber/report.json" 2>/dev/null || echo 0)
|
||||||
|
|
||||||
|
{
|
||||||
|
echo "<!DOCTYPE html><html><head><meta charset='utf-8'>"
|
||||||
|
echo "<title>CI report ${SHA8}</title>"
|
||||||
|
echo "<style>body{font-family:sans-serif;margin:2em}a{color:#2563eb}table{border-collapse:collapse}"
|
||||||
|
echo "th,td{border:1px solid #ccc;padding:8px;text-align:left}"
|
||||||
|
echo ".pass{color:#059669}.fail{color:#dc2626}</style></head><body>"
|
||||||
|
echo "<h1>CI report <code>${SHA8}</code></h1>"
|
||||||
|
echo "<p>Commit: ${GITHUB_SHA}<br>Branch: ${GITHUB_REF_NAME}<br>Run: ${GITHUB_RUN_ID}</p>"
|
||||||
|
echo "<table><tr><th>Suite</th><th>Passed</th><th>Failed</th><th>Report</th></tr>"
|
||||||
|
echo "<tr><td>Bats</td><td class='pass'>${BATS_PASS}</td><td class='fail'>${BATS_FAIL}</td>"
|
||||||
|
echo "<td><a href='bats/results.txt'>results.txt</a>"
|
||||||
|
echo " | <a href='bats/junit.xml'>junit.xml</a></td></tr>"
|
||||||
|
echo "<tr><td>Cucumber</td><td class='pass'>${CUCUMBER_PASS}</td><td class='fail'>${CUCUMBER_FAIL}</td>"
|
||||||
|
echo "<td><a href='cucumber/index.html'>report</a>"
|
||||||
|
echo " | <a href='cucumber/report.json'>json</a></td></tr>"
|
||||||
|
echo "</table></body></html>"
|
||||||
|
} > "${REPORTS_DIR}/index.html"
|
||||||
@@ -2,24 +2,42 @@ name: Build Feature
|
|||||||
on:
|
on:
|
||||||
workflow_call:
|
workflow_call:
|
||||||
inputs:
|
inputs:
|
||||||
|
env_json:
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
bats-image:
|
bats-image:
|
||||||
required: false
|
required: true
|
||||||
type: string
|
type: string
|
||||||
default: bats/bats:latest
|
|
||||||
cucumber-node-image:
|
cucumber-node-image:
|
||||||
required: false
|
required: true
|
||||||
type: string
|
type: string
|
||||||
default: node:22
|
secrets:
|
||||||
|
GITEA_TOKEN:
|
||||||
|
required: true
|
||||||
|
GIT_PAGES_PUBLISH_TOKEN:
|
||||||
|
required: true
|
||||||
|
|
||||||
|
env:
|
||||||
|
GITEA_API_URL: ${{ fromJson(inputs.env_json).GITEA_API_URL }}
|
||||||
|
GIT_PAGES_URL: ${{ fromJson(inputs.env_json).GIT_PAGES_URL }}
|
||||||
|
GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }}
|
||||||
|
GIT_PAGES_PUBLISH_TOKEN: ${{ secrets.GIT_PAGES_PUBLISH_TOKEN }}
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
|
validate:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
repository: niko/gitea-ci-library
|
||||||
|
path: .ci
|
||||||
|
|
||||||
|
- name: Validate CI config
|
||||||
|
run: bash .ci/scripts/ci-validate.sh
|
||||||
|
|
||||||
bats:
|
bats:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
env:
|
|
||||||
GITEA_API_URL: https://gitea.app.keskikuja.site
|
|
||||||
GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }}
|
|
||||||
PAGES_HOST: ci-reports.helm-dev.keskikuja.site
|
|
||||||
GIT_PAGES_PUBLISH_URL: https://ci-reports.helm-dev.keskikuja.site
|
|
||||||
GIT_PAGES_PUBLISH_TOKEN: ${{ secrets.GIT_PAGES_PUBLISH_TOKEN }}
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
@@ -35,56 +53,37 @@ jobs:
|
|||||||
tar c . | docker run --rm -i -v bats-workspace:/data alpine tar x -C /data
|
tar c . | docker run --rm -i -v bats-workspace:/data alpine tar x -C /data
|
||||||
mkdir -p "reports/${GITHUB_SHA:0:8}/bats"
|
mkdir -p "reports/${GITHUB_SHA:0:8}/bats"
|
||||||
set +e
|
set +e
|
||||||
docker run --rm -v bats-workspace:/data \
|
docker run --rm \
|
||||||
|
-v bats-workspace:/data \
|
||||||
--entrypoint bash ${{ inputs.bats-image }} \
|
--entrypoint bash ${{ inputs.bats-image }} \
|
||||||
-c 'apk add -q lsof python3 jq curl && \
|
-c 'apk add -q lsof python3 jq curl ruby && cd /data && \
|
||||||
cd /data && bats tests/ ' \
|
gem install bashcov -v 3.3.0 2>&1 | tail -1 && \
|
||||||
|
bashcov -- bats tests/' \
|
||||||
> "reports/${GITHUB_SHA:0:8}/bats/results.txt" 2>&1
|
> "reports/${GITHUB_SHA:0:8}/bats/results.txt" 2>&1
|
||||||
BATS_EXIT=$?
|
BATS_EXIT=$?
|
||||||
|
bash .ci/.gitea/scripts/bats-coverage.sh bats-workspace "reports/${GITHUB_SHA:0:8}/bats"
|
||||||
docker volume rm bats-workspace > /dev/null 2>&1
|
docker volume rm bats-workspace > /dev/null 2>&1
|
||||||
{
|
bash .ci/.gitea/scripts/bats-report.sh "reports/${GITHUB_SHA:0:8}/bats"
|
||||||
echo "<html><body><h1>Bats tests</h1><ul>"
|
|
||||||
for f in reports/${GITHUB_SHA:0:8}/bats/*; do
|
|
||||||
b="$(basename $f)"
|
|
||||||
[ "$b" = "index.html" ] && continue
|
|
||||||
echo "<li><a href=\"$b\">$b</a></li>"
|
|
||||||
done
|
|
||||||
echo "</ul></body></html>"
|
|
||||||
} > "reports/${GITHUB_SHA:0:8}/bats/index.html"
|
|
||||||
echo "BATS_EXIT=${BATS_EXIT}" >> "${GITHUB_ENV}"
|
echo "BATS_EXIT=${BATS_EXIT}" >> "${GITHUB_ENV}"
|
||||||
exit ${BATS_EXIT}
|
exit ${BATS_EXIT}
|
||||||
|
|
||||||
- name: Publish bats reports
|
- name: Publish bats reports
|
||||||
if: always()
|
if: always()
|
||||||
shell: bash
|
run: bash .ci/scripts/publish-git-pages.sh bats
|
||||||
run: |
|
|
||||||
bash .ci/scripts/publish-git-pages.sh "reports/${GITHUB_SHA:0:8}/bats"
|
|
||||||
|
|
||||||
- name: Set bats commit status
|
- name: Set bats commit status
|
||||||
if: always()
|
if: always()
|
||||||
shell: bash
|
|
||||||
run: |
|
run: |
|
||||||
if [ "${BATS_EXIT}" = "0" ]; then
|
if [ "${BATS_EXIT}" = "0" ]; then
|
||||||
STATUS="success"
|
bash .ci/scripts/report-status.sh success "Bats tests" ci-bats bats
|
||||||
DESC="Bats tests"
|
|
||||||
URL="https://${PAGES_HOST}/${GITHUB_REPOSITORY}/reports/${GITHUB_SHA:0:8}/bats/"
|
|
||||||
else
|
else
|
||||||
STATUS="failure"
|
bash .ci/scripts/report-status.sh failure "Bats tests FAILED" ci-bats bats
|
||||||
DESC="Bats tests FAILED"
|
|
||||||
URL="https://${PAGES_HOST}/${GITHUB_REPOSITORY}/reports/${GITHUB_SHA:0:8}/bats/"
|
|
||||||
fi
|
fi
|
||||||
bash .ci/scripts/report-status.sh "$STATUS" "$DESC" "$URL" ci-bats
|
|
||||||
|
|
||||||
cucumber:
|
cucumber:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
container:
|
container:
|
||||||
image: ${{ inputs.cucumber-node-image }}
|
image: ${{ inputs.cucumber-node-image }}
|
||||||
env:
|
|
||||||
GITEA_API_URL: https://gitea.app.keskikuja.site
|
|
||||||
GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }}
|
|
||||||
PAGES_HOST: ci-reports.helm-dev.keskikuja.site
|
|
||||||
GIT_PAGES_PUBLISH_URL: https://ci-reports.helm-dev.keskikuja.site
|
|
||||||
GIT_PAGES_PUBLISH_TOKEN: ${{ secrets.GIT_PAGES_PUBLISH_TOKEN }}
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
@@ -124,40 +123,25 @@ jobs:
|
|||||||
|
|
||||||
- name: Publish cucumber reports
|
- name: Publish cucumber reports
|
||||||
if: always()
|
if: always()
|
||||||
shell: bash
|
|
||||||
run: |
|
run: |
|
||||||
if [ "${TOOL_OK}" = "true" ]; then
|
if [ "${TOOL_OK}" = "true" ]; then
|
||||||
bash .ci/scripts/publish-git-pages.sh "reports/${GITHUB_SHA:0:8}/cucumber"
|
bash .ci/scripts/publish-git-pages.sh cucumber
|
||||||
fi
|
fi
|
||||||
|
|
||||||
- name: Set cucumber commit status
|
- name: Set cucumber commit status
|
||||||
if: always()
|
if: always()
|
||||||
shell: bash
|
|
||||||
run: |
|
run: |
|
||||||
if [ "${TOOL_OK}" != "true" ]; then
|
if [ "${TOOL_OK}" != "true" ]; then
|
||||||
STATUS="failure"
|
bash .ci/scripts/report-status.sh failure "Cucumber tool unavailable" ci-cucumber
|
||||||
DESC="Cucumber tool unavailable"
|
|
||||||
URL="https://gitea.app.keskikuja.site/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID}"
|
|
||||||
elif [ "${CUCUMBER_EXIT}" = "0" ]; then
|
elif [ "${CUCUMBER_EXIT}" = "0" ]; then
|
||||||
STATUS="success"
|
bash .ci/scripts/report-status.sh success "Cucumber tests passed" ci-cucumber cucumber
|
||||||
DESC="Cucumber tests passed"
|
|
||||||
URL="https://${PAGES_HOST}/${GITHUB_REPOSITORY}/reports/${GITHUB_SHA:0:8}/cucumber/"
|
|
||||||
else
|
else
|
||||||
STATUS="failure"
|
bash .ci/scripts/report-status.sh failure "Cucumber tests FAILED" ci-cucumber cucumber
|
||||||
DESC="Cucumber tests FAILED"
|
|
||||||
URL="https://${PAGES_HOST}/${GITHUB_REPOSITORY}/reports/${GITHUB_SHA:0:8}/cucumber/"
|
|
||||||
fi
|
fi
|
||||||
bash .ci/scripts/report-status.sh "$STATUS" "$DESC" "$URL" ci-cucumber
|
|
||||||
|
|
||||||
build:
|
build:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
needs: [bats, cucumber]
|
needs: [bats, cucumber]
|
||||||
env:
|
|
||||||
GITEA_API_URL: https://gitea.app.keskikuja.site
|
|
||||||
GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }}
|
|
||||||
PAGES_HOST: ci-reports.helm-dev.keskikuja.site
|
|
||||||
GIT_PAGES_PUBLISH_URL: https://ci-reports.helm-dev.keskikuja.site
|
|
||||||
GIT_PAGES_PUBLISH_TOKEN: ${{ secrets.GIT_PAGES_PUBLISH_TOKEN }}
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
@@ -166,35 +150,7 @@ jobs:
|
|||||||
path: .ci
|
path: .ci
|
||||||
|
|
||||||
- name: Generate report index
|
- name: Generate report index
|
||||||
shell: bash
|
run: bash .ci/.gitea/scripts/generate-report-index.sh
|
||||||
run: |
|
|
||||||
SHA8="${GITHUB_SHA:0:8}"
|
|
||||||
mkdir -p "reports/${SHA8}"
|
|
||||||
BATS_PASS=$(grep -c 'ok' "reports/${SHA8}/bats/results.txt" 2>/dev/null || echo 0)
|
|
||||||
BATS_FAIL=$(grep -c 'not ok' "reports/${SHA8}/bats/results.txt" 2>/dev/null || echo 0)
|
|
||||||
CUCUMBER_PASS=$(jq '.summary.passed // 0' "reports/${SHA8}/cucumber/report.json" 2>/dev/null || echo 0)
|
|
||||||
CUCUMBER_FAIL=$(jq '.summary.failed // 0' "reports/${SHA8}/cucumber/report.json" 2>/dev/null || echo 0)
|
|
||||||
{
|
|
||||||
echo "<!DOCTYPE html><html><head><meta charset='utf-8'>"
|
|
||||||
echo "<title>CI report ${SHA8}</title>"
|
|
||||||
echo "<style>body{font-family:sans-serif;margin:2em}a{color:#2563eb}table{border-collapse:collapse}"
|
|
||||||
echo "th,td{border:1px solid #ccc;padding:8px;text-align:left}"
|
|
||||||
echo ".pass{color:#059669}.fail{color:#dc2626}</style></head><body>"
|
|
||||||
echo "<h1>CI report <code>${SHA8}</code></h1>"
|
|
||||||
echo "<p>Commit: ${GITHUB_SHA}<br>Branch: ${GITHUB_REF_NAME}<br>Run: ${GITHUB_RUN_ID}</p>"
|
|
||||||
echo "<table><tr><th>Suite</th><th>Passed</th><th>Failed</th><th>Report</th></tr>"
|
|
||||||
echo "<tr><td>Bats</td><td class='pass'>${BATS_PASS}</td><td class='fail'>${BATS_FAIL}</td>"
|
|
||||||
echo "<td><a href='bats/results.txt'>results.txt</a>"
|
|
||||||
echo " | <a href='bats/junit.xml'>junit.xml</a></td></tr>"
|
|
||||||
echo "<tr><td>Cucumber</td><td class='pass'>${CUCUMBER_PASS}</td><td class='fail'>${CUCUMBER_FAIL}</td>"
|
|
||||||
echo "<td><a href='cucumber/index.html'>report</a>"
|
|
||||||
echo " | <a href='cucumber/report.json'>json</a></td></tr>"
|
|
||||||
echo "</table></body></html>"
|
|
||||||
} > "reports/${SHA8}/index.html"
|
|
||||||
|
|
||||||
- name: Set build commit status
|
- name: Set build commit status
|
||||||
run: |
|
run: bash .ci/scripts/report-status.sh success "Build complete" ci-build
|
||||||
bash .ci/scripts/report-status.sh success \
|
|
||||||
"Build complete" \
|
|
||||||
"https://gitea.app.keskikuja.site/niko/gitea-ci-library/actions/runs/${GITHUB_RUN_ID}" \
|
|
||||||
ci-build
|
|
||||||
|
|||||||
@@ -1,27 +0,0 @@
|
|||||||
name: CI Engine
|
|
||||||
on:
|
|
||||||
workflow_call:
|
|
||||||
inputs:
|
|
||||||
config-file:
|
|
||||||
required: true
|
|
||||||
type: string
|
|
||||||
secrets:
|
|
||||||
GITEA_TOKEN:
|
|
||||||
required: true
|
|
||||||
GIT_PAGES_PUBLISH_TOKEN:
|
|
||||||
required: true
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
publish:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
env:
|
|
||||||
GITEA_API_URL: https://gitea.app.keskikuja.site
|
|
||||||
PAGES_HOST: ci-reports.helm-dev.keskikuja.site
|
|
||||||
GIT_PAGES_PUBLISH_URL: https://ci-reports.helm-dev.keskikuja.site
|
|
||||||
GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }}
|
|
||||||
GIT_PAGES_PUBLISH_TOKEN: ${{ secrets.GIT_PAGES_PUBLISH_TOKEN }}
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
|
|
||||||
- name: Publish reports
|
|
||||||
run: bash scripts/publish.sh reports
|
|
||||||
@@ -5,16 +5,27 @@ on:
|
|||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
|
load-config:
|
||||||
|
uses: niko/gitea-ci-library/.gitea/workflows/config-provider.yml@main
|
||||||
|
with:
|
||||||
|
config_path: .gitea/workflows/gitea-env.conf
|
||||||
|
|
||||||
feature:
|
feature:
|
||||||
if: github.ref != 'refs/heads/main'
|
if: github.ref != 'refs/heads/main'
|
||||||
|
needs: [load-config]
|
||||||
uses: niko/gitea-ci-library/.gitea/workflows/build-feature.yml@main
|
uses: niko/gitea-ci-library/.gitea/workflows/build-feature.yml@main
|
||||||
secrets: inherit
|
secrets: inherit
|
||||||
with:
|
with:
|
||||||
|
env_json: ${{ needs.load-config.outputs.env_json }}
|
||||||
bats-image: bats/bats:latest
|
bats-image: bats/bats:latest
|
||||||
|
cucumber-node-image: node:22
|
||||||
|
|
||||||
main:
|
main:
|
||||||
if: github.ref == 'refs/heads/main'
|
if: github.ref == 'refs/heads/main'
|
||||||
|
needs: [load-config]
|
||||||
uses: niko/gitea-ci-library/.gitea/workflows/build-feature.yml@main
|
uses: niko/gitea-ci-library/.gitea/workflows/build-feature.yml@main
|
||||||
secrets: inherit
|
secrets: inherit
|
||||||
with:
|
with:
|
||||||
|
env_json: ${{ needs.load-config.outputs.env_json }}
|
||||||
bats-image: bats/bats:latest
|
bats-image: bats/bats:latest
|
||||||
|
cucumber-node-image: node:22
|
||||||
|
|||||||
@@ -0,0 +1,31 @@
|
|||||||
|
name: Config Provider Library
|
||||||
|
on:
|
||||||
|
workflow_call:
|
||||||
|
inputs:
|
||||||
|
config_path:
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
outputs:
|
||||||
|
env_json:
|
||||||
|
value: ${{ jobs.parse-config.outputs.json_data }}
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
parse-config:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
outputs:
|
||||||
|
json_data: ${{ steps.convert.outputs.JSON_OUT }}
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- id: convert
|
||||||
|
run: |
|
||||||
|
JSON_STRING=$(jq -R -s '
|
||||||
|
split("\n")
|
||||||
|
| map(select(length > 0 and (startswith("#") | not)))
|
||||||
|
| map(split("="))
|
||||||
|
| map({(.[0]): .[1]})
|
||||||
|
| add
|
||||||
|
' "${{ inputs.config_path }}")
|
||||||
|
|
||||||
|
CLEAN_JSON=$(echo "$JSON_STRING" | jq -c .)
|
||||||
|
echo "JSON_OUT=$CLEAN_JSON" >> "$GITHUB_OUTPUT"
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
GITEA_API_URL=https://gitea.app.keskikuja.site
|
||||||
|
GIT_PAGES_URL=https://ci-reports.helm-dev.keskikuja.site
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
SimpleCov.start do
|
||||||
|
add_filter '/tests/'
|
||||||
|
add_filter '/node_modules/'
|
||||||
|
add_filter '/git-pages/'
|
||||||
|
end
|
||||||
@@ -10,14 +10,14 @@ Consumer kutsuu provideria `uses:`-viittauksella. Ei discoveryä — polku kovak
|
|||||||
### Polun muodostus
|
### Polun muodostus
|
||||||
|
|
||||||
```
|
```
|
||||||
{owner}/{repo}/.gitea/workflows/ci-engine.yml@{ref}
|
{owner}/{repo}/.gitea/workflows/build-feature.yml@{ref}
|
||||||
```
|
```
|
||||||
|
|
||||||
| Osa | Mistä | Esimerkki (homelab) |
|
| Osa | Mistä | Esimerkki (homelab) |
|
||||||
|-----|-------|---------------------|
|
|-----|-------|---------------------|
|
||||||
| `owner` | Repopolun ensimmäinen osa — **käyttäjänimi tai org** | `niko` |
|
| `owner` | Repopolun ensimmäinen osa — **käyttäjänimi tai org** | `niko` |
|
||||||
| `repo` | Repon nimi | `gitea-ci-library` |
|
| `repo` | Repon nimi | `gitea-ci-library` |
|
||||||
| tiedosto | Providerin workflow | `.gitea/workflows/ci-engine.yml` |
|
| tiedosto | Providerin workflow | `.gitea/workflows/build-feature.yml` |
|
||||||
| `@ref` | Tag tai branch provider-repossa | `@v1` (tuotanto) |
|
| `@ref` | Tag tai branch provider-repossa | `@v1` (tuotanto) |
|
||||||
|
|
||||||
**Owner ei ole org-pakotettu.** Homelabissa ei välttämättä ole organisaatiotasoa — silloin owner on
|
**Owner ei ole org-pakotettu.** Homelabissa ei välttämättä ole organisaatiotasoa — silloin owner on
|
||||||
@@ -36,7 +36,7 @@ Consumerin `ci.yml`:
|
|||||||
```yaml
|
```yaml
|
||||||
jobs:
|
jobs:
|
||||||
call-engine:
|
call-engine:
|
||||||
uses: niko/gitea-ci-library/.gitea/workflows/ci-engine.yml@v1
|
uses: niko/gitea-ci-library/.gitea/workflows/build-feature.yml@v1
|
||||||
secrets: inherit
|
secrets: inherit
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -56,7 +56,7 @@ niko/gitea-ci-library ←→ niko/gitea-ci-library (mirror tai push-mirror)
|
|||||||
niko/gitea-ci-library/... niko/gitea-ci-library/...
|
niko/gitea-ci-library/... niko/gitea-ci-library/...
|
||||||
```
|
```
|
||||||
|
|
||||||
Mirror pitää `ci-engine.yml`:n ja tagit (`v1`) saatavilla kulloisellakin palvelimella. Tämä korvaa
|
Mirror pitää `build-feature.yml`:n ja tagit (`v1`) saatavilla kulloisellakin palvelimella. Tämä korvaa
|
||||||
provider-repon checkout-hackit workflowissa — binding hoituu Gitean natiivilla `uses:`-mekanismilla.
|
provider-repon checkout-hackit workflowissa — binding hoituu Gitean natiivilla `uses:`-mekanismilla.
|
||||||
|
|
||||||
Periaatteet: [tmp/data-flow-design.md](tmp/data-flow-design.md)
|
Periaatteet: [tmp/data-flow-design.md](tmp/data-flow-design.md)
|
||||||
@@ -180,6 +180,52 @@ Tarkista ennen ensimmäistä ajoa: [Provider-binding](#provider-binding--miten-c
|
|||||||
|
|
||||||
Lisätietoa runnerin toiminnasta, konteista ja DinD:stä: [docs/runner.md](docs/runner.md)
|
Lisätietoa runnerin toiminnasta, konteista ja DinD:stä: [docs/runner.md](docs/runner.md)
|
||||||
|
|
||||||
|
## Vaaditut secretit ja muuttujat
|
||||||
|
|
||||||
|
Consumer-repossa on oltava seuraavat asetukset:
|
||||||
|
|
||||||
|
### Repo Actions Secrets (`{repo} → Settings → Actions → Secrets`)
|
||||||
|
|
||||||
|
| Secret | Kuvaus |
|
||||||
|
|--------|--------|
|
||||||
|
| `GIT_PAGES_PUBLISH_TOKEN` | Git-pages-palvelimen BasicAuth-token. Nimi on lukittu — tämä tarkka nimi vaaditaan. |
|
||||||
|
|
||||||
|
`GITEA_TOKEN` on Gitean sisäinen secret (`secrets.GITEA_TOKEN`), joka on automauttisesti saatavilla — sitä ei tarvitse erikseen luoda.
|
||||||
|
|
||||||
|
### Config-tiedosto (`.gitea/workflows/gitea-env.conf`)
|
||||||
|
|
||||||
|
Tiedoston **nimi ja polku on lukittu**: `.gitea/workflows/gitea-env.conf` consumer-repon juuressa.
|
||||||
|
Tämän tiedoston perusteella `config-provider.yml` tuottaa `env_json`-outputin, joka välitetään
|
||||||
|
workflowille.
|
||||||
|
|
||||||
|
Tiedosto on `key=value`-muotoinen (kuten `.env`). Kommentit ja tyhjät rivit sallittuja.
|
||||||
|
|
||||||
|
**Vaaditut avaimet:**
|
||||||
|
|
||||||
|
| Avain | Kuvaus |
|
||||||
|
|-------|--------|
|
||||||
|
| `GITEA_API_URL` | Gitea-palvelimen base URL (esim. `https://gitea.app.example.com`) |
|
||||||
|
| `GIT_PAGES_URL` | Git-pages-palvelimen URL ilman trailing slash (esim. `https://ci-reports.example.com`) |
|
||||||
|
|
||||||
|
**Validointisäännöt:**
|
||||||
|
- Arvot eivät saa olla tyhjiä
|
||||||
|
- Jos avaimen nimessä on `URL`, arvon on alettava `http://` tai `https://`
|
||||||
|
- Tiedoston on oltava olemassa (muuten job keskeytyy)
|
||||||
|
|
||||||
|
Esimerkki:
|
||||||
|
```
|
||||||
|
GITEA_API_URL=https://gitea.app.example.com
|
||||||
|
GIT_PAGES_URL=https://ci-reports.example.com
|
||||||
|
```
|
||||||
|
|
||||||
|
### Validaatio
|
||||||
|
|
||||||
|
Jokaisen jobin alussa `ci-validate.sh` tarkistaa:
|
||||||
|
- `.gitea/workflows/gitea-env.conf` on olemassa ja sen arvot ovat validit
|
||||||
|
- `GITEA_TOKEN` ja `GIT_PAGES_PUBLISH_TOKEN` on asetettu
|
||||||
|
|
||||||
|
Jos validointi epäonnistuu, job keskeytyy exit-koodilla 1 ja Gitean commit-status näyttää epäonnistumisen linkkinä lokiin.
|
||||||
|
|
||||||
### Muuta
|
### Muuta
|
||||||
|
|
||||||
| Muuttuja | Kuvaus |
|
| Muuttuja | Kuvaus |
|
||||||
|
|||||||
@@ -1,3 +0,0 @@
|
|||||||
GITEA_API_URL: https://gitea.app.keskikuja.site
|
|
||||||
PAGES_HOST: ci-reports.helm-dev.keskikuja.site
|
|
||||||
GIT_PAGES_PUBLISH_URL: https://ci-reports.helm-dev.keskikuja.site
|
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
## Päätös
|
## Päätös
|
||||||
|
|
||||||
Provider (gitea-ci-library) ja Consumer (mikropalveluprojekti) erotetaan
|
Provider (gitea-ci-library) ja Consumer (mikropalveluprojekti) erotetaan
|
||||||
selkeällä rajapinnalla: `.gitea/workflows/ci-engine.yml` on ainoa pinta,
|
selkeällä rajapinnalla: `.gitea/workflows/build-feature.yml` on ainoa pinta,
|
||||||
jota consumer kutsuu.
|
jota consumer kutsuu.
|
||||||
|
|
||||||
Kaikki muu providerin koodi (scriptit, git-pages-helmi, retention) on
|
Kaikki muu providerin koodi (scriptit, git-pages-helmi, retention) on
|
||||||
@@ -18,7 +18,7 @@ riippuvuutta.
|
|||||||
# .gitea/workflows/ci.yml — consumerin repo
|
# .gitea/workflows/ci.yml — consumerin repo
|
||||||
jobs:
|
jobs:
|
||||||
ci:
|
ci:
|
||||||
uses: niko/gitea-ci-library/.gitea/workflows/ci-engine.yml@v1
|
uses: niko/gitea-ci-library/.gitea/workflows/build-feature.yml@v1
|
||||||
secrets: inherit
|
secrets: inherit
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -44,13 +44,13 @@ Consumer:
|
|||||||
- Git-pages Helm-chartti
|
- Git-pages Helm-chartti
|
||||||
- Retention sidecar
|
- Retention sidecar
|
||||||
- Scriptit ja työkalut (toteutus avoin, uudelleenkirjoitettavissa)
|
- Scriptit ja työkalut (toteutus avoin, uudelleenkirjoitettavissa)
|
||||||
- Kaikki paitsi `ci-engine.yml` on sisäistä toteutusta ja voi muuttua
|
- Kaikki paitsi `build-feature.yml` on sisäistä toteutusta ja voi muuttua
|
||||||
ilman versiopäivitystä
|
ilman versiopäivitystä
|
||||||
|
|
||||||
## Periaatteet
|
## Periaatteet
|
||||||
|
|
||||||
1. `ci-engine.yml` on **lukittu rajapinta**. Consumer kutsuu tätä, ei
|
1. `build-feature.yml` on **lukittu rajapinta**. Consumer kutsuu tätä, ei
|
||||||
koskaan providerin scriptejä suoraan. `ci-engine.yml` voi muuttua vain
|
koskaan providerin scriptejä suoraan. `build-feature.yml` voi muuttua vain
|
||||||
version vaihtuessa.
|
version vaihtuessa.
|
||||||
2. Consumer omistaa pipeline-logiikan. Provider ei tiedä mitä testejä
|
2. Consumer omistaa pipeline-logiikan. Provider ei tiedä mitä testejä
|
||||||
ajetaan, missä järjestyksessä tai millä työkaluilla.
|
ajetaan, missä järjestyksessä tai millä työkaluilla.
|
||||||
|
|||||||
@@ -0,0 +1,70 @@
|
|||||||
|
# 6. Directory ownership — provider vs consumer
|
||||||
|
|
||||||
|
## Päätös
|
||||||
|
|
||||||
|
Provider-repossa (`gitea-ci-library`) kansioiden omistajuus on seuraava:
|
||||||
|
|
||||||
|
| Kansio / Tiedosto | Omistaja | Tyyppi |
|
||||||
|
|-------------------|----------|--------|
|
||||||
|
| `.gitea/workflows/` | Sekoitettu | Providerin reusable workflowt + consumerin pipeline |
|
||||||
|
| `.gitea/workflows/gitea-env.conf` | Consumer | KEY=VALUE config |
|
||||||
|
| `.gitea/scripts/` | Consumer | Consumer-skriptit |
|
||||||
|
| `scripts/` | Provider | Providerin sisäiset työkalut |
|
||||||
|
|
||||||
|
## Reusable workflowt — sijaintipakko
|
||||||
|
|
||||||
|
Gitea Actions vaatii, että `uses:`-direktiivillä kutsuttavat workflowt
|
||||||
|
ovat muodossa `{owner}/{repo}/.gitea/workflows/{file}@{ref}`.
|
||||||
|
|
||||||
|
**Tämä on Gitea Actionsin asettama tekninen rajoite.** Toimivia
|
||||||
|
polkuja ovat vain:
|
||||||
|
|
||||||
|
```
|
||||||
|
# ✅ kelpaa
|
||||||
|
uses: org/repo/.gitea/workflows/file.yml@branch
|
||||||
|
|
||||||
|
# ❌ eivät kelpaa
|
||||||
|
uses: org/repo/workflows/file.yml@branch
|
||||||
|
uses: org/repo/.gitea/workflows/path/file.yml@branch
|
||||||
|
uses: org/repo/scripts/workflow.yml@branch
|
||||||
|
```
|
||||||
|
|
||||||
|
Tästä syystä providerin reusable workflowt (`config-provider.yml`,
|
||||||
|
`build-feature.yml`) ovat samassa `.gitea/workflows/`-kansiossa consumerin
|
||||||
|
pipeline-tiedostojen (`ci.yml`) kanssa.
|
||||||
|
|
||||||
|
Erottelu on nimessä ja dokumentaatiossa, ei kansiorakenteessa:
|
||||||
|
- `config-provider.yml`, `build-feature.yml` — providerin tarjoamia
|
||||||
|
- `ci.yml` — consumerin omistamia
|
||||||
|
|
||||||
|
## Providerin `scripts/` (juuressa)
|
||||||
|
|
||||||
|
Providerin sisäiset työkalut. Consumer ei koskaan kutsu näitä suoraan —
|
||||||
|
vain providerin workflowt kutsuvat tupla checkoutin kautta:
|
||||||
|
`.ci/scripts/publish-git-pages.sh`.
|
||||||
|
|
||||||
|
Consumerilla ei ole suoraa polkua näihin tiedostoihin ilman providerin
|
||||||
|
workflowa.
|
||||||
|
|
||||||
|
## Consumerin `.gitea/scripts/`
|
||||||
|
|
||||||
|
Consumerin omat skriptit, osana consumerin pipeline-logiikkaa.
|
||||||
|
Kutsutaan consumerin workflowista ilman tupla checkouttia:
|
||||||
|
`.gitea/scripts/bats-report.sh`.
|
||||||
|
|
||||||
|
## Consumerin `.gitea/workflows/gitea-env.conf`
|
||||||
|
|
||||||
|
Consumerin konfiguraatiotiedosto. Providerin `config-provider.yml`
|
||||||
|
lukee tämän ja muuntaa JSONiksi, mutta consumer omistaa sisällön.
|
||||||
|
|
||||||
|
## Vaikutukset
|
||||||
|
|
||||||
|
- Provider voi muuttaa `scripts/` ja `config-provider.yml` sisältöä
|
||||||
|
ilman consumerin hyväksyntää (versiovaihdon yhteydessä)
|
||||||
|
- Consumer voi muuttaa `.gitea/workflows/ci.yml`,
|
||||||
|
`.gitea/workflows/build-feature.yml` ja `.gitea/scripts/` sisältöä
|
||||||
|
ilman providerin muutoksia
|
||||||
|
- Providerin workflowt käyttävät `.ci/scripts/...` -polkua (tupla checkout)
|
||||||
|
- Consumerin workflowt käyttävät `.gitea/scripts/...` -polkua (natiivi checkout)
|
||||||
|
- Sekä provider että consumer jakavat `.gitea/workflows/` — tämä on
|
||||||
|
Gitea Actionsin tekninen rajoite, ei suunnittelupäätös
|
||||||
+7
-8
@@ -17,8 +17,7 @@ Tämä repo on käytännössä monorepo, jossa on kaksi itsenäistä osaa:
|
|||||||
|
|
||||||
### 1. Juuri (`gitea-ci-library`)
|
### 1. Juuri (`gitea-ci-library`)
|
||||||
Provider-kirjasto: reusable workflowt, scriptit, ADRt, dokumentaatio.
|
Provider-kirjasto: reusable workflowt, scriptit, ADRt, dokumentaatio.
|
||||||
Rajapinta: `.gitea/workflows/ci-engine.yml` — ainoa pinta, jota consumerit
|
Consumer kutsuu `build-feature.yml`-workflowa `uses:`-direktiivillä.
|
||||||
kutsuvat.
|
|
||||||
|
|
||||||
### 2. `git-pages/` — oma kokonaisuus
|
### 2. `git-pages/` — oma kokonaisuus
|
||||||
Helm-chartti Codeberg git-pagesille. Täysin itsenäinen — oma dokumentaatio,
|
Helm-chartti Codeberg git-pagesille. Täysin itsenäinen — oma dokumentaatio,
|
||||||
@@ -32,7 +31,7 @@ Ohut ja yksiselitteinen:
|
|||||||
|
|
||||||
```
|
```
|
||||||
scripts/publish-git-pages.sh <report-dir>
|
scripts/publish-git-pages.sh <report-dir>
|
||||||
→ PATCH tar osoitteeseen PAGES_HOST
|
→ PATCH tar osoitteeseen GIT_PAGES_URL
|
||||||
→ palauttaa BASE URL:n
|
→ palauttaa BASE URL:n
|
||||||
|
|
||||||
git-pages tarjoaa:
|
git-pages tarjoaa:
|
||||||
@@ -46,9 +45,9 @@ blob-arkkitehtuuri). Git-pages ei tiedä workflowista, scripteistä tai
|
|||||||
provider-logiikasta.
|
provider-logiikasta.
|
||||||
|
|
||||||
## Architecture (POC-tila)
|
## Architecture (POC-tila)
|
||||||
- **Provider & Consumer -malli**: `ci-engine.yml` on lukittu rajapinta.
|
- **Provider & Consumer -malli**: `build-feature.yml` on lukittu rajapinta.
|
||||||
ADR 0005.
|
ADR 0005.
|
||||||
- **Raporttien hostaus**: git-pages Helm-chartilla (`git-pages/`).
|
- **Raporttien hostaus**: git-pages Helm-chartilla (`git-pages/`), `GIT_PAGES_URL` määrittää perusosoitteen.
|
||||||
- **Retention**: sidecar samassa podissa, HTTP API localhost:3000,
|
- **Retention**: sidecar samassa podissa, HTTP API localhost:3000,
|
||||||
Gitea API branch-check.
|
Gitea API branch-check.
|
||||||
- **Commit-status**: Gitea Actions näyttää automaattisesti. API vain
|
- **Commit-status**: Gitea Actions näyttää automaattisesti. API vain
|
||||||
@@ -59,19 +58,19 @@ provider-logiikasta.
|
|||||||
|
|
||||||
| Path | Purpose |
|
| Path | Purpose |
|
||||||
|---|---|
|
|---|---|
|
||||||
| `.gitea/workflows/` | `ci-engine.yml` (ainoa reusable workflow POC-vaiheessa) |
|
| `.gitea/workflows/` | Reusable workflowt (`build-feature.yml`, `config-provider.yml`) |
|
||||||
| `scripts/` | `publish-git-pages.sh`, `report-status.sh`, `dispatch-workflow.sh` |
|
| `scripts/` | `publish-git-pages.sh`, `report-status.sh`, `dispatch-workflow.sh` |
|
||||||
| **`git-pages/`** | **Oma kokonaisuus: Helm-chartti + docs + retention** |
|
| **`git-pages/`** | **Oma kokonaisuus: Helm-chartti + docs + retention** |
|
||||||
| `docs/` | Root-tason arkkitehtuuri, ADRt (0001–0005) |
|
| `docs/` | Root-tason arkkitehtuuri, ADRt (0001–0005) |
|
||||||
| `docs/adr/` | Architecture Decision Records |
|
| `docs/adr/` | Architecture Decision Records |
|
||||||
| `tests/` | Bats-testit skripteille |
|
| `tests/` | Bats-testit skripteille |
|
||||||
| `.gitea/workflows/ci.yml` | Dogfood — kutsuu `ci-engine.yml`:a |
|
| `.gitea/workflows/ci.yml` | Dogfood — kutsuu `build-feature.yml`:a |
|
||||||
|
|
||||||
**Tarkemmat git-pages-asiat:** `git-pages/docs/` (implementation-notes,
|
**Tarkemmat git-pages-asiat:** `git-pages/docs/` (implementation-notes,
|
||||||
architecture, design-rationale, secrets, tech-stack).
|
architecture, design-rationale, secrets, tech-stack).
|
||||||
|
|
||||||
## Key Technical Decisions
|
## Key Technical Decisions
|
||||||
- **Provider & Consumer**: `ci-engine.yml` lukittu rajapinta, muu koodi
|
- **Provider & Consumer**: `build-feature.yml` lukittu rajapinta, muu koodi
|
||||||
vapaasti muutettavissa
|
vapaasti muutettavissa
|
||||||
- **Vain Gitea, vain reusable workflowt**: ei custom actioneita, ei
|
- **Vain Gitea, vain reusable workflowt**: ei custom actioneita, ei
|
||||||
multi-platform
|
multi-platform
|
||||||
|
|||||||
@@ -1,9 +1,6 @@
|
|||||||
# Architecture — Gitea Actions CI -kirjasto
|
# Architecture — Gitea Actions CI -kirjasto
|
||||||
|
|
||||||
> ⚠️ POC-vaihe. Tämä dokumentti kuvaa suunniteltua arkkitehtuuria. Toteutus
|
> ⚠️ POC-vaihe. Tämä dokumentti kuvaa suunniteltua arkkitehtuuria.
|
||||||
> on edelleen kehitysvaiheessa (`ci-engine.yml` on ainoa reusable workflow).
|
|
||||||
> Odota uudelleenkirjoitusta ennen kuin luotat tähän dokumenttiin.
|
|
||||||
>
|
|
||||||
> Normatiivinen lähde: ADR 0004, ADR 0005, `docs/design-rationale.md`.
|
> Normatiivinen lähde: ADR 0004, ADR 0005, `docs/design-rationale.md`.
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -21,7 +18,7 @@ Kirjasto on Gitea-spesifi. Raportit hallinnoidaan git-pages Helm-chartilla
|
|||||||
|
|
||||||
| Rooli | Kuvaus |
|
| Rooli | Kuvaus |
|
||||||
|-------|--------|
|
|-------|--------|
|
||||||
| **Provider** | `gitea-ci-library` — tarjoaa `ci-engine.yml`:n (lukittu rajapinta) sekä scriptit |
|
| **Provider** | `gitea-ci-library` — tarjoaa `build-feature.yml` (lukittu rajapinta) sekä scriptit |
|
||||||
| **Consumer** | Mikropalveluprojekti — kutsuu `uses:`-direktiivillä, omistaa pipeline-logiikan |
|
| **Consumer** | Mikropalveluprojekti — kutsuu `uses:`-direktiivillä, omistaa pipeline-logiikan |
|
||||||
|
|
||||||
Tarkemmin: ADR 0005.
|
Tarkemmin: ADR 0005.
|
||||||
@@ -30,10 +27,10 @@ Tarkemmin: ADR 0005.
|
|||||||
|
|
||||||
| Komponentti | Tila |
|
| Komponentti | Tila |
|
||||||
|-------------|------|
|
|-------------|------|
|
||||||
| `ci-engine.yml` | Toimii POC-tasolla. Ainoa reusable workflow. |
|
| `build-feature.yml` | Toimii. Ainoa reusable workflow. |
|
||||||
| `publish-git-pages.sh` | Toimii. PATCH tar git-pagesiin. |
|
| `publish-git-pages.sh` | Toimii. PATCH tar git-pagesiin. |
|
||||||
| `report-status.sh` | Toimii. POSTaa commit-status (vain custom-linkkiin). |
|
| `report-status.sh` | Toimii. POSTaa commit-status (vain custom-linkkiin). |
|
||||||
| `dispatch-workflow.sh` | Suunniteltu, ei toteutettu POCissa. |
|
| `dispatch-workflow.sh` | Toimii. Dispatchee workflown ja pollaa valmistumista. |
|
||||||
| `git-pages/` | Helm-chartti raporttien hostaukseen. Oma kokonaisuus, tarkemmin: `git-pages/docs/`. |
|
| `git-pages/` | Helm-chartti raporttien hostaukseen. Oma kokonaisuus, tarkemmin: `git-pages/docs/`. |
|
||||||
|
|
||||||
## Ulkoiset palvelut
|
## Ulkoiset palvelut
|
||||||
@@ -43,10 +40,9 @@ Tarkemmin: ADR 0005.
|
|||||||
| **Gitea REST API** | Commit-status, workflow-dispatch, run-pollaus |
|
| **Gitea REST API** | Commit-status, workflow-dispatch, run-pollaus |
|
||||||
| **Gitea Packages** | Docker-imagen säilytys |
|
| **Gitea Packages** | Docker-imagen säilytys |
|
||||||
| **git-pages** | Raporttien hostaus |
|
| **git-pages** | Raporttien hostaus |
|
||||||
| **SonarQube** | Koodin laadun analyysi (suunniteltu) |
|
|
||||||
|
|
||||||
## Arkkitehtuuriset rajoitteet
|
## Arkkitehtuuriset rajoitteet
|
||||||
|
|
||||||
- `ci-engine.yml` on ainoa consumerin kutsuma rajapinta (ADR 0005)
|
- `build-feature.yml` on ainoa consumerin kutsuma rajapinta (ADR 0005)
|
||||||
- Gitea Actionsin natiivi commit-status on ensisijainen (ADR 0004)
|
- Gitea Actionsin natiivi commit-status on ensisijainen (ADR 0004)
|
||||||
- Raportit ovat julkisia URL:lla (osoite tunnettava)
|
- Raportit ovat julkisia URL:lla (osoite tunnettava)
|
||||||
|
|||||||
@@ -50,6 +50,53 @@ Käytäntö:
|
|||||||
- Jos `docker run` tarvitsee env-arvoja, välitä ne eksplisiittisesti `-e VAR`-lipulla
|
- Jos `docker run` tarvitsee env-arvoja, välitä ne eksplisiittisesti `-e VAR`-lipulla
|
||||||
- `GITHUB_ENV` on validi tapa välittää arvoja stepien välille samassa jobissa, mutta ei leviä `docker run`-kontteihin ilman `-e`-lippua
|
- `GITHUB_ENV` on validi tapa välittää arvoja stepien välille samassa jobissa, mutta ei leviä `docker run`-kontteihin ilman `-e`-lippua
|
||||||
|
|
||||||
|
### Cross-job config propagation (validated 2026-06-13)
|
||||||
|
|
||||||
|
Config-arvojen vienti kaikkiin jobeihin ilman toistoa vaatii kahden
|
||||||
|
mekanismin ketjuttamista:
|
||||||
|
|
||||||
|
1. **`needs` + `with:`** — `jobs.<job_id>.with.<with_id>` tukee
|
||||||
|
`needs`-kontekstia. Tämä mahdollistaa sen, että yhden jobin outputit
|
||||||
|
voidaan välittää toiselle reusable workflowille inputeina.
|
||||||
|
2. **Workflow `env:`** — ainoa natiivi mekanismi, joka tekee arvoista
|
||||||
|
näkyviä kaikissa jobeissa automaattisesti (POC validioitu).
|
||||||
|
|
||||||
|
Ketju toimii näin:
|
||||||
|
|
||||||
|
```
|
||||||
|
gitea-env.conf → config-provider.yml → env_json (yksi JSON-string)
|
||||||
|
(1) (2)
|
||||||
|
↓
|
||||||
|
ci.yml with: env_json
|
||||||
|
${{ needs.load-config.outputs.env_json }}
|
||||||
|
(3)
|
||||||
|
↓
|
||||||
|
build-feature.yml workflow env:
|
||||||
|
GITEA_API_URL: ${{ fromJson(inputs.env_json).GITEA_API_URL }}
|
||||||
|
(4)
|
||||||
|
↓
|
||||||
|
kaikki jobit → $GITEA_API_URL, $GIT_PAGES_URL jne.
|
||||||
|
(5)
|
||||||
|
```
|
||||||
|
|
||||||
|
Vaiheet:
|
||||||
|
1. Consumer määrittelee arvot `gitea-env.conf`:ssä (KEY=VALUE)
|
||||||
|
2. `config-provider.yml` lukee confin ja tuottaa yhden JSON-stringin outputina
|
||||||
|
3. `ci.yml` välittää JSONin `needs` + `with:` -ketjulla
|
||||||
|
4. `build-feature.yml` purkaa arvot workflow `env:`-tasolle `fromJson()`:lla
|
||||||
|
5. Kaikki jobit käyttävät valmiita env-muuttujia (`$GIT_PAGES_URL` jne.)
|
||||||
|
|
||||||
|
Avainkomponentit:
|
||||||
|
- **config-provider.yml** — reusable workflow, joka muuntaa conf-tiedoston
|
||||||
|
yhdeksi JSON-outputiksi. Yksi output riittää, ei per-key outputteja.
|
||||||
|
- **`jobs.<job_id>.with`** — tukee `needs`-kontekstia (Gitea Actions,
|
||||||
|
kuten GitHub Actions). Tämä on kriittinen yksityiskohta: ilman tätä
|
||||||
|
config-arvoja ei voi välittää reusable workflowille dynaamisesti.
|
||||||
|
- **workflow `env:`** — ainoa tapa jakaa arvot kaikkiin jobeihin.
|
||||||
|
`fromJson(inputs.env_json).KEY` purkaa yksittäiset arvot ilman toistoa.
|
||||||
|
- **Per-job `env:`** — sisältää vain secretit (`GITEA_TOKEN`,
|
||||||
|
`GIT_PAGES_PUBLISH_TOKEN`), ei config-arvoja.
|
||||||
|
|
||||||
## 5. Pipeline Provides All Dependencies
|
## 5. Pipeline Provides All Dependencies
|
||||||
|
|
||||||
- Ei luottamusta runnerin esiasennettuihin työkaluihin
|
- Ei luottamusta runnerin esiasennettuihin työkaluihin
|
||||||
@@ -63,3 +110,16 @@ Käytäntö:
|
|||||||
- Rinnakkaiset jobit (bats + cucumber) — tuloksia saa heti kun valmistuu
|
- Rinnakkaiset jobit (bats + cucumber) — tuloksia saa heti kun valmistuu
|
||||||
- Jokainen testisetti omassa jobissaan
|
- Jokainen testisetti omassa jobissaan
|
||||||
- Finalize/build voi kerätä yhteenvedon (ei julkaista summarya jos kenelläkään ei ole linkkiä)
|
- Finalize/build voi kerätä yhteenvedon (ei julkaista summarya jos kenelläkään ei ole linkkiä)
|
||||||
|
|
||||||
|
## 7. Inline Logic Threshold
|
||||||
|
|
||||||
|
Logiikka workflow YAML:ssa on hauras: YAML:n sisennys, heredocit ja
|
||||||
|
kenoviivat tuottavat helposti toimimattomia steppejä.
|
||||||
|
|
||||||
|
**Kynnys siirtää scriptiksi:** heti kun steppiin tulee ehtoja, silmukoita,
|
||||||
|
tai yli 3 riviä inline-koodia, siirrä omaksi scriptikseen `.gitea/scripts/`-
|
||||||
|
kansioon.
|
||||||
|
|
||||||
|
Esimerkki: coverage-datan purku ja navigointi-indexin luonti oli aluksi
|
||||||
|
inline-heredocina workflow YAML:ssa. Siirto omaan `bats-coverage.sh`-scriptiin
|
||||||
|
teki siitä luettavan, testattavan ja muokattavan ilman YAML-muotoiluriskejä.
|
||||||
|
|||||||
@@ -67,7 +67,7 @@ Dispatchaa workflow'n toisessa repossa ja pollaa sen valmistumista synkronisesti
|
|||||||
### Rajapinta
|
### Rajapinta
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
dispatch-workflow.sh <target_repo> <workflow_file> <ref> <inputs_json> [timeout_minutes]
|
dispatch-workflow.sh <target_repo> <workflow_file> <ref> <inputs_json> <gitea_api_url> <gitea_token> [timeout_minutes]
|
||||||
```
|
```
|
||||||
|
|
||||||
| Parametri | Pakollinen | Kuvaus |
|
| Parametri | Pakollinen | Kuvaus |
|
||||||
@@ -76,6 +76,8 @@ dispatch-workflow.sh <target_repo> <workflow_file> <ref> <inputs_json> [timeout_
|
|||||||
| `workflow_file` | Kyllä | Workflow-tiedoston nimi (esim. `test.yml`) |
|
| `workflow_file` | Kyllä | Workflow-tiedoston nimi (esim. `test.yml`) |
|
||||||
| `ref` | Kyllä | Branch |
|
| `ref` | Kyllä | Branch |
|
||||||
| `inputs_json` | Kyllä | JSON-objekti input-parametreina |
|
| `inputs_json` | Kyllä | JSON-objekti input-parametreina |
|
||||||
|
| `gitea_api_url` | Kyllä | Gitean API-URL (esim. `https://gitea.example.com`) |
|
||||||
|
| `gitea_token` | Kyllä | Gitea API -token |
|
||||||
| `timeout_minutes` | Ei | Oletus: 360 (6 tuntia) |
|
| `timeout_minutes` | Ei | Oletus: 360 (6 tuntia) |
|
||||||
|
|
||||||
### Toiminta
|
### Toiminta
|
||||||
@@ -90,7 +92,8 @@ dispatch-workflow.sh <target_repo> <workflow_file> <ref> <inputs_json> [timeout_
|
|||||||
|
|
||||||
```bash
|
```bash
|
||||||
dispatch-workflow.sh "tests/integration" "test.yml" "main" \
|
dispatch-workflow.sh "tests/integration" "test.yml" "main" \
|
||||||
'{"version":"1.2.3","tags":"@smoke","root_commit":"abc123","root_repo":"services/temperature-store"}'
|
'{"version":"1.2.3","tags":"@smoke","root_commit":"abc123","root_repo":"services/temperature-store"}' \
|
||||||
|
"https://gitea.example.com" "gtp_abc123"
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -181,8 +184,8 @@ Skriptit lukevat nämä Gitea Actionsin ympäristömuuttujat:
|
|||||||
|
|
||||||
| Muuttuja | Lähde | Käyttäjä |
|
| Muuttuja | Lähde | Käyttäjä |
|
||||||
|----------|-------|----------|
|
|----------|-------|----------|
|
||||||
| `GITEA_API_URL` | Org variable | Kaikki skriptit |
|
| `GITEA_API_URL` | Org variable | `report-status.sh` |
|
||||||
| `GITEA_TOKEN` | Org secret | `report-status.sh`, `dispatch-workflow.sh`, `tag-commit.sh` |
|
| `GITEA_TOKEN` | Org secret | `report-status.sh`, `tag-commit.sh` |
|
||||||
| `MINIO_BASE_URL` | Org variable | `push-reports.sh` |
|
| `MINIO_BASE_URL` | Org variable | `push-reports.sh` |
|
||||||
| `MINIO_ACCESS_KEY` | Org secret | `push-reports.sh` |
|
| `MINIO_ACCESS_KEY` | Org secret | `push-reports.sh` |
|
||||||
| `MINIO_SECRET_KEY` | Org secret | `push-reports.sh` |
|
| `MINIO_SECRET_KEY` | Org secret | `push-reports.sh` |
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ Dispatchaa workflow toisessa repossa ja pollaa sen valmistumista synkronisesti.
|
|||||||
## Rajapinta
|
## Rajapinta
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
dispatch-workflow.sh <target_repo> <workflow_file> <ref> <inputs_json> [timeout_minutes]
|
dispatch-workflow.sh <target_repo> <workflow_file> <ref> <inputs_json> <gitea_api_url> <gitea_token> [timeout_minutes]
|
||||||
```
|
```
|
||||||
|
|
||||||
| Parametri | Pakollinen | Kuvaus |
|
| Parametri | Pakollinen | Kuvaus |
|
||||||
@@ -63,6 +63,8 @@ dispatch-workflow.sh <target_repo> <workflow_file> <ref> <inputs_json> [timeout_
|
|||||||
| `workflow_file` | Kyllä | Workflow-tiedosto (esim. `test.yml`) |
|
| `workflow_file` | Kyllä | Workflow-tiedosto (esim. `test.yml`) |
|
||||||
| `ref` | Kyllä | Branch |
|
| `ref` | Kyllä | Branch |
|
||||||
| `inputs_json` | Kyllä | JSON-objekti input-parametreina |
|
| `inputs_json` | Kyllä | JSON-objekti input-parametreina |
|
||||||
|
| `gitea_api_url` | Kyllä | Gitean API-URL |
|
||||||
|
| `gitea_token` | Kyllä | Gitea API -token |
|
||||||
| `timeout_minutes` | Ei | Oletus: 360 |
|
| `timeout_minutes` | Ei | Oletus: 360 |
|
||||||
|
|
||||||
## API-kutsut
|
## API-kutsut
|
||||||
@@ -77,7 +79,8 @@ dispatch-workflow.sh <target_repo> <workflow_file> <ref> <inputs_json> [timeout_
|
|||||||
|
|
||||||
```bash
|
```bash
|
||||||
dispatch-workflow.sh "tests/integration" "test.yml" "main" \
|
dispatch-workflow.sh "tests/integration" "test.yml" "main" \
|
||||||
'{"version":"1.2.3","tags":"@smoke","root_commit":"abc123","root_repo":"services/temperature-store"}'
|
'{"version":"1.2.3","tags":"@smoke","root_commit":"abc123","root_repo":"services/temperature-store"}' \
|
||||||
|
"https://gitea.example.com" "gtp_abc123"
|
||||||
```
|
```
|
||||||
|
|
||||||
## Verifiointi
|
## Verifiointi
|
||||||
|
|||||||
+2
-2
@@ -1,8 +1,8 @@
|
|||||||
# Reusable workflowt
|
# Reusable workflowt
|
||||||
|
|
||||||
> ⚠️ **POC-vaihe.** Tämä dokumentti kuvaa suunniteltuja workflow'ta
|
> ⚠️ **POC-vaihe.** Tämä dokumentti kuvaa suunniteltuja workflow'ta
|
||||||
> (ci-feature, ci-master, deploy, test). POCissa on toteutettu vain
|
> (ci-feature, ci-master, deploy, test). POCissa on toteutettu
|
||||||
> `ci-engine.yml`. Uudelleenkirjoitus odottaa.
|
> `build-feature.yml`. Uudelleenkirjoitus odottaa.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,31 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
CONF_FILE="${CI_CONF_FILE:-.gitea/workflows/gitea-env.conf}"
|
||||||
|
ERRORS=0
|
||||||
|
|
||||||
|
[ -f "$CONF_FILE" ] || { echo "ERROR: $CONF_FILE not found — checkout missing?" >&2; exit 1; }
|
||||||
|
|
||||||
|
echo "Reading $CONF_FILE..."
|
||||||
|
|
||||||
|
while IFS='=' read -r key value || [ -n "$key" ]; do
|
||||||
|
key=$(echo "$key" | xargs)
|
||||||
|
value=$(echo "$value" | xargs)
|
||||||
|
[ -z "$key" ] && continue
|
||||||
|
[[ "$key" == "#"* ]] && continue
|
||||||
|
[ -z "$value" ] && echo "ERROR: $key is empty in $CONF_FILE" >&2 && ERRORS=1
|
||||||
|
if [ -n "$value" ] && [[ "$key" == *"URL"* ]] && [[ "$value" != http://* ]] && [[ "$value" != https://* ]]; then
|
||||||
|
echo "ERROR: $key should be a URL (http/https), got: $value" >&2
|
||||||
|
ERRORS=1
|
||||||
|
fi
|
||||||
|
done < "$CONF_FILE"
|
||||||
|
|
||||||
|
[ -z "${GITEA_TOKEN:-}" ] && echo "ERROR: GITEA_TOKEN secret is not set" >&2 && ERRORS=1
|
||||||
|
[ -z "${GIT_PAGES_PUBLISH_TOKEN:-}" ] && echo "ERROR: GIT_PAGES_PUBLISH_TOKEN secret is not set" >&2 && ERRORS=1
|
||||||
|
|
||||||
|
if [ "$ERRORS" -ne 0 ]; then
|
||||||
|
echo "FATAL: CI config validation failed" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "OK: all CI env vars validated"
|
||||||
@@ -1,20 +1,21 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
[ -z "${GITEA_API_URL:-}" ] && echo "ERROR: GITEA_API_URL is not set" >&2 && exit 1
|
|
||||||
[ -z "${GITEA_TOKEN:-}" ] && echo "ERROR: GITEA_TOKEN is not set" >&2 && exit 1
|
|
||||||
|
|
||||||
TARGET_REPO="${1:-}"
|
TARGET_REPO="${1:-}"
|
||||||
WORKFLOW_FILE="${2:-}"
|
WORKFLOW_FILE="${2:-}"
|
||||||
REF="${3:-}"
|
REF="${3:-}"
|
||||||
INPUTS_JSON="${4:-}"
|
INPUTS_JSON="${4:-}"
|
||||||
TIMEOUT_MINUTES="${5:-360}"
|
GITEA_API_URL="${5:-}"
|
||||||
|
GITEA_TOKEN="${6:-}"
|
||||||
|
TIMEOUT_MINUTES="${7:-360}"
|
||||||
POLL_INTERVAL="${DISPATCH_POLL_INTERVAL:-10}"
|
POLL_INTERVAL="${DISPATCH_POLL_INTERVAL:-10}"
|
||||||
|
|
||||||
[ -z "$TARGET_REPO" ] && echo "ERROR: target_repo argument is required" >&2 && exit 1
|
[ -z "$TARGET_REPO" ] && echo "ERROR: target_repo argument is required" >&2 && exit 1
|
||||||
[ -z "$WORKFLOW_FILE" ] && echo "ERROR: workflow_file argument is required" >&2 && exit 1
|
[ -z "$WORKFLOW_FILE" ] && echo "ERROR: workflow_file argument is required" >&2 && exit 1
|
||||||
[ -z "$REF" ] && echo "ERROR: ref argument is required" >&2 && exit 1
|
[ -z "$REF" ] && echo "ERROR: ref argument is required" >&2 && exit 1
|
||||||
[ -z "$INPUTS_JSON" ] && echo "ERROR: inputs_json argument is required" >&2 && exit 1
|
[ -z "$INPUTS_JSON" ] && echo "ERROR: inputs_json argument is required" >&2 && exit 1
|
||||||
|
[ -z "$GITEA_API_URL" ] && echo "ERROR: gitea_api_url argument is required" >&2 && exit 1
|
||||||
|
[ -z "$GITEA_TOKEN" ] && echo "ERROR: gitea_token argument is required" >&2 && exit 1
|
||||||
|
|
||||||
DISPATCH_URL="$GITEA_API_URL/api/v1/repos/$TARGET_REPO/actions/workflows/$WORKFLOW_FILE/dispatches"
|
DISPATCH_URL="$GITEA_API_URL/api/v1/repos/$TARGET_REPO/actions/workflows/$WORKFLOW_FILE/dispatches"
|
||||||
DISPATCH_BODY=$(jq -nc --arg ref "$REF" --argjson inputs "$INPUTS_JSON" '{ref: $ref, inputs: $inputs}')
|
DISPATCH_BODY=$(jq -nc --arg ref "$REF" --argjson inputs "$INPUTS_JSON" '{ref: $ref, inputs: $inputs}')
|
||||||
|
|||||||
@@ -1,29 +1,25 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
# Publish a report directory to git-pages apex index-site via Traefik (BasicAuth).
|
|
||||||
# Public URL: https://{PAGES_HOST}/{owner}/{repo}/reports/{sha8}/index.html
|
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
REPORT_DIR="${1:-}"
|
SUITE_PATH="${1:-}"
|
||||||
PAGES_HOST="${PAGES_HOST:-}"
|
|
||||||
GIT_PAGES_PUBLISH_URL="${GIT_PAGES_PUBLISH_URL:-https://pages.helm-dev.keskikuja.site}"
|
|
||||||
GIT_PAGES_PUBLISH_TOKEN="${GIT_PAGES_PUBLISH_TOKEN:-}"
|
|
||||||
GIT_PAGES_PUBLISH_USER="${GIT_PAGES_PUBLISH_USER:-publish}"
|
|
||||||
REPO_SLUG="${GITHUB_REPOSITORY:-}"
|
|
||||||
|
|
||||||
[ -n "$REPORT_DIR" ] || { echo "ERROR: report directory argument required" >&2; exit 1; }
|
[ -n "$SUITE_PATH" ] || { echo "ERROR: suite_path argument required" >&2; exit 1; }
|
||||||
[ -d "$REPORT_DIR" ] || { echo "ERROR: not a directory: $REPORT_DIR" >&2; exit 1; }
|
[ -n "${GITEA_API_URL:-}" ] || { echo "ERROR: GITEA_API_URL is not set" >&2; exit 1; }
|
||||||
[ -n "$PAGES_HOST" ] || { echo "ERROR: PAGES_HOST is not set" >&2; exit 1; }
|
[ -n "${GIT_PAGES_URL:-}" ] || { echo "ERROR: GIT_PAGES_URL is not set" >&2; exit 1; }
|
||||||
[ -n "$GIT_PAGES_PUBLISH_TOKEN" ] || { echo "ERROR: GIT_PAGES_PUBLISH_TOKEN is not set" >&2; exit 1; }
|
[ -n "${GIT_PAGES_PUBLISH_TOKEN:-}" ] || { echo "ERROR: GIT_PAGES_PUBLISH_TOKEN is not set" >&2; exit 1; }
|
||||||
[ -n "$REPO_SLUG" ] || { echo "ERROR: GITHUB_REPOSITORY is not set" >&2; exit 1; }
|
[ -n "${GITHUB_REPOSITORY:-}" ] || { echo "ERROR: GITHUB_REPOSITORY is not set" >&2; exit 1; }
|
||||||
[ -n "${GITHUB_SHA:-}" ] || { echo "ERROR: GITHUB_SHA is not set" >&2; exit 1; }
|
[ -n "${GITHUB_SHA:-}" ] || { echo "ERROR: GITHUB_SHA is not set" >&2; exit 1; }
|
||||||
|
|
||||||
OWNER="${REPO_SLUG%%/*}"
|
OWNER="${GITHUB_REPOSITORY%%/*}"
|
||||||
REPO="${REPO_SLUG##*/}"
|
REPO="${GITHUB_REPOSITORY##*/}"
|
||||||
SHA8="${GITHUB_SHA:0:8}"
|
SHA8="${GITHUB_SHA:0:8}"
|
||||||
REPORT_BASE="https://${PAGES_HOST}/${OWNER}/${REPO}/reports/${SHA8}"
|
PAGES_USER="${GIT_PAGES_PUBLISH_USER:-publish}"
|
||||||
|
REPORT_DIR="reports/${SHA8}/${SUITE_PATH%/}"
|
||||||
|
REPORT_BASE="${GIT_PAGES_URL}/${OWNER}/${REPO}/reports/${SHA8}"
|
||||||
|
|
||||||
PUBLISH_BASE="${GIT_PAGES_PUBLISH_URL%/}"
|
[ -d "$REPORT_DIR" ] || { echo "ERROR: not a directory: $REPORT_DIR" >&2; exit 1; }
|
||||||
PUBLISH_SITE_URL="${PUBLISH_BASE}/"
|
|
||||||
|
PUBLISH_SITE_URL="${GIT_PAGES_URL}/"
|
||||||
|
|
||||||
WORK=$(mktemp -d)
|
WORK=$(mktemp -d)
|
||||||
TAR=$(mktemp)
|
TAR=$(mktemp)
|
||||||
@@ -45,7 +41,7 @@ find "$WORK/$OWNER" \( -type f -o -type l \) -print | sed "s|^${WORK}/||" | tar
|
|||||||
publish() {
|
publish() {
|
||||||
local method="$1"
|
local method="$1"
|
||||||
curl -sS -X "$method" "$PUBLISH_SITE_URL" \
|
curl -sS -X "$method" "$PUBLISH_SITE_URL" \
|
||||||
-u "${GIT_PAGES_PUBLISH_USER}:${GIT_PAGES_PUBLISH_TOKEN}" \
|
-u "${PAGES_USER}:${GIT_PAGES_PUBLISH_TOKEN}" \
|
||||||
-H "Content-Type: application/x-tar" \
|
-H "Content-Type: application/x-tar" \
|
||||||
-H "Atomic: no" \
|
-H "Atomic: no" \
|
||||||
-H "Create-Parents: yes" \
|
-H "Create-Parents: yes" \
|
||||||
|
|||||||
+11
-5
@@ -1,10 +1,16 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
# Vie raportit git-pagesiin + commit-status linkillä
|
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
REPORT_DIR="${1:-reports}"
|
SUITE_PATH="${1:-}"
|
||||||
PAGES_HOST="${PAGES_HOST:-ci-reports.helm-dev.keskikuja.site}"
|
|
||||||
|
|
||||||
REPORT_URL=$(bash "$(dirname $0)/publish-git-pages.sh" "$REPORT_DIR")
|
[ -n "$SUITE_PATH" ] || { echo "ERROR: suite_path argument required" >&2; exit 1; }
|
||||||
|
[ -n "${GITEA_API_URL:-}" ] || { echo "ERROR: GITEA_API_URL is not set" >&2; exit 1; }
|
||||||
|
[ -n "${GITEA_TOKEN:-}" ] || { echo "ERROR: GITEA_TOKEN is not set" >&2; exit 1; }
|
||||||
|
[ -n "${GIT_PAGES_URL:-}" ] || { echo "ERROR: GIT_PAGES_URL is not set" >&2; exit 1; }
|
||||||
|
[ -n "${GIT_PAGES_PUBLISH_TOKEN:-}" ] || { echo "ERROR: GIT_PAGES_PUBLISH_TOKEN is not set" >&2; exit 1; }
|
||||||
|
|
||||||
|
SCRIPT_DIR="$(dirname "$0")"
|
||||||
|
|
||||||
|
REPORT_URL=$(bash "$SCRIPT_DIR/publish-git-pages.sh" "$SUITE_PATH")
|
||||||
echo "Published: $REPORT_URL"
|
echo "Published: $REPORT_URL"
|
||||||
bash "$(dirname $0)/report-status.sh" success "Reports published" "$REPORT_URL" ci-report
|
bash "$SCRIPT_DIR/report-status.sh" success "Reports published" "ci-report"
|
||||||
|
|||||||
+11
-13
@@ -1,28 +1,26 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
[ -z "${GITEA_API_URL:-}" ] && echo "ERROR: GITEA_API_URL is not set" >&2 && exit 1
|
|
||||||
[ -z "${GITEA_TOKEN:-}" ] && echo "ERROR: GITEA_TOKEN is not set" >&2 && exit 1
|
|
||||||
|
|
||||||
STATE="${1:-}"
|
STATE="${1:-}"
|
||||||
DESCRIPTION="${2:-}"
|
DESCRIPTION="${2:-}"
|
||||||
URL="${3:-}"
|
KEY="${3:-commit-${GITHUB_SHA:0:8}}"
|
||||||
KEY="${4:-commit-${GITHUB_SHA:0:8}}"
|
SUITE="${4:-}"
|
||||||
ROOT_COMMIT="${5:-}"
|
|
||||||
ROOT_REPO="${6:-}"
|
|
||||||
|
|
||||||
[ -z "$STATE" ] && echo "ERROR: state argument is required" >&2 && exit 1
|
[ -z "$STATE" ] && echo "ERROR: state argument is required" >&2 && exit 1
|
||||||
[ -z "$DESCRIPTION" ] && echo "ERROR: description argument is required" >&2 && exit 1
|
[ -z "$DESCRIPTION" ] && echo "ERROR: description argument is required" >&2 && exit 1
|
||||||
[ -z "$URL" ] && echo "ERROR: url argument is required" >&2 && exit 1
|
[ -z "${GITEA_API_URL:-}" ] && echo "ERROR: GITEA_API_URL is not set" >&2 && exit 1
|
||||||
|
[ -z "${GITEA_TOKEN:-}" ] && echo "ERROR: GITEA_TOKEN is not set" >&2 && exit 1
|
||||||
|
|
||||||
if [ -n "$ROOT_COMMIT" ] && [ -n "$ROOT_REPO" ]; then
|
if [ -n "$SUITE" ]; then
|
||||||
REPO="$ROOT_REPO"
|
SUITE="${SUITE%/}/"
|
||||||
COMMIT="$ROOT_COMMIT"
|
URL="${GIT_PAGES_URL}/${GITHUB_REPOSITORY}/reports/${GITHUB_SHA:0:8}/${SUITE}"
|
||||||
else
|
else
|
||||||
REPO="${GITHUB_REPOSITORY:-}"
|
URL="${GITEA_API_URL}/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID}"
|
||||||
COMMIT="${GITHUB_SHA:-}"
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
REPO="${ROOT_REPO:-${GITHUB_REPOSITORY:-}}"
|
||||||
|
COMMIT="${ROOT_COMMIT:-${GITHUB_SHA:-}}"
|
||||||
|
|
||||||
[ -z "$REPO" ] && echo "ERROR: GITHUB_REPOSITORY is not set" >&2 && exit 1
|
[ -z "$REPO" ] && echo "ERROR: GITHUB_REPOSITORY is not set" >&2 && exit 1
|
||||||
[ -z "$COMMIT" ] && echo "ERROR: GITHUB_SHA is not set" >&2 && exit 1
|
[ -z "$COMMIT" ] && echo "ERROR: GITHUB_SHA is not set" >&2 && exit 1
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,79 @@
|
|||||||
|
#!/usr/bin/env bats
|
||||||
|
|
||||||
|
setup() {
|
||||||
|
export CONF_FILE=$(mktemp)
|
||||||
|
export CI_CONF_FILE="$CONF_FILE"
|
||||||
|
}
|
||||||
|
|
||||||
|
teardown() {
|
||||||
|
rm -f "$CONF_FILE"
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "missing config file → exit 1" {
|
||||||
|
export CI_CONF_FILE="/nonexistent/path/$(date +%s).conf"
|
||||||
|
run bash scripts/ci-validate.sh
|
||||||
|
[ "$status" -eq 1 ]
|
||||||
|
[[ "$output" == *"ERROR"* ]]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "empty value in config → exit 1" {
|
||||||
|
cat > "$CONF_FILE" <<EOF
|
||||||
|
SOME_KEY=
|
||||||
|
EOF
|
||||||
|
run bash scripts/ci-validate.sh
|
||||||
|
[ "$status" -eq 1 ]
|
||||||
|
[[ "$output" == *"empty"* ]]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "invalid URL in config → exit 1" {
|
||||||
|
cat > "$CONF_FILE" <<EOF
|
||||||
|
API_URL=not-a-url
|
||||||
|
EOF
|
||||||
|
run bash scripts/ci-validate.sh
|
||||||
|
[ "$status" -eq 1 ]
|
||||||
|
[[ "$output" == *"URL"* ]]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "missing GITEA_TOKEN secret → exit 1" {
|
||||||
|
cat > "$CONF_FILE" <<EOF
|
||||||
|
SOME_KEY=ok
|
||||||
|
EOF
|
||||||
|
unset GITEA_TOKEN
|
||||||
|
run bash scripts/ci-validate.sh
|
||||||
|
[ "$status" -eq 1 ]
|
||||||
|
[[ "$output" == *"GITEA_TOKEN"* ]]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "missing GIT_PAGES_PUBLISH_TOKEN secret → exit 1" {
|
||||||
|
cat > "$CONF_FILE" <<EOF
|
||||||
|
SOME_KEY=ok
|
||||||
|
EOF
|
||||||
|
export GITEA_TOKEN="sometoken"
|
||||||
|
unset GIT_PAGES_PUBLISH_TOKEN
|
||||||
|
run bash scripts/ci-validate.sh
|
||||||
|
[ "$status" -eq 1 ]
|
||||||
|
[[ "$output" == *"GIT_PAGES_PUBLISH_TOKEN"* ]]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "valid config and all secrets → exit 0" {
|
||||||
|
cat > "$CONF_FILE" <<EOF
|
||||||
|
API_URL=https://example.com
|
||||||
|
ANOTHER=https://test.fi
|
||||||
|
EOF
|
||||||
|
export GITEA_TOKEN="sometoken"
|
||||||
|
export GIT_PAGES_PUBLISH_TOKEN="sometoken"
|
||||||
|
run bash scripts/ci-validate.sh
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "comment and blank lines are ignored → exit 0" {
|
||||||
|
cat > "$CONF_FILE" <<EOF
|
||||||
|
# this is a comment
|
||||||
|
|
||||||
|
VALID_URL=https://example.com
|
||||||
|
EOF
|
||||||
|
export GITEA_TOKEN="sometoken"
|
||||||
|
export GIT_PAGES_PUBLISH_TOKEN="sometoken"
|
||||||
|
run bash scripts/ci-validate.sh
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
}
|
||||||
@@ -2,8 +2,6 @@
|
|||||||
|
|
||||||
setup() {
|
setup() {
|
||||||
source tests/helpers/mock-api.sh
|
source tests/helpers/mock-api.sh
|
||||||
export GITEA_API_URL="http://localhost:18080"
|
|
||||||
export GITEA_TOKEN="test-token-abc123"
|
|
||||||
export DISPATCH_POLL_INTERVAL="0.1"
|
export DISPATCH_POLL_INTERVAL="0.1"
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -21,7 +19,7 @@ teardown() {
|
|||||||
{"code":200,"body":{"id":1,"status":"completed","conclusion":"success"}}
|
{"code":200,"body":{"id":1,"status":"completed","conclusion":"success"}}
|
||||||
]'
|
]'
|
||||||
mock_start
|
mock_start
|
||||||
run bash scripts/dispatch-workflow.sh "test-owner/test-repo" "test.yml" "main" '{"version":"1.2.3"}'
|
run bash scripts/dispatch-workflow.sh "test-owner/test-repo" "test.yml" "main" '{"version":"1.2.3"}' "http://localhost:18080" "test-token-abc123"
|
||||||
[ "$status" -eq 0 ]
|
[ "$status" -eq 0 ]
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -33,7 +31,7 @@ teardown() {
|
|||||||
{"code":200,"body":{"id":1,"status":"completed","conclusion":"failure"}}
|
{"code":200,"body":{"id":1,"status":"completed","conclusion":"failure"}}
|
||||||
]'
|
]'
|
||||||
mock_start
|
mock_start
|
||||||
run bash scripts/dispatch-workflow.sh "test-owner/test-repo" "test.yml" "main" '{"version":"1.2.3"}'
|
run bash scripts/dispatch-workflow.sh "test-owner/test-repo" "test.yml" "main" '{"version":"1.2.3"}' "http://localhost:18080" "test-token-abc123"
|
||||||
[ "$status" -eq 1 ]
|
[ "$status" -eq 1 ]
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -45,7 +43,7 @@ teardown() {
|
|||||||
{"code":200,"body":{"id":1,"status":"completed","conclusion":"cancelled"}}
|
{"code":200,"body":{"id":1,"status":"completed","conclusion":"cancelled"}}
|
||||||
]'
|
]'
|
||||||
mock_start
|
mock_start
|
||||||
run bash scripts/dispatch-workflow.sh "test-owner/test-repo" "test.yml" "main" '{"version":"1.2.3"}'
|
run bash scripts/dispatch-workflow.sh "test-owner/test-repo" "test.yml" "main" '{"version":"1.2.3"}' "http://localhost:18080" "test-token-abc123"
|
||||||
[ "$status" -eq 1 ]
|
[ "$status" -eq 1 ]
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -63,7 +61,7 @@ teardown() {
|
|||||||
{"code":200,"body":{"id":1,"status":"running"}}
|
{"code":200,"body":{"id":1,"status":"running"}}
|
||||||
]'
|
]'
|
||||||
mock_start
|
mock_start
|
||||||
run bash scripts/dispatch-workflow.sh "test-owner/test-repo" "test.yml" "main" '{"version":"1.2.3"}' "0.001"
|
run bash scripts/dispatch-workflow.sh "test-owner/test-repo" "test.yml" "main" '{"version":"1.2.3"}' "http://localhost:18080" "test-token-abc123" "0.001"
|
||||||
[ "$status" -eq 124 ]
|
[ "$status" -eq 124 ]
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -72,7 +70,7 @@ teardown() {
|
|||||||
{"code":500}
|
{"code":500}
|
||||||
]'
|
]'
|
||||||
mock_start
|
mock_start
|
||||||
run bash scripts/dispatch-workflow.sh "test-owner/test-repo" "test.yml" "main" '{"version":"1.2.3"}'
|
run bash scripts/dispatch-workflow.sh "test-owner/test-repo" "test.yml" "main" '{"version":"1.2.3"}' "http://localhost:18080" "test-token-abc123"
|
||||||
[ "$status" -eq 1 ]
|
[ "$status" -eq 1 ]
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -83,7 +81,7 @@ teardown() {
|
|||||||
{"code":200,"body":{"id":1,"status":"completed","conclusion":"success"}}
|
{"code":200,"body":{"id":1,"status":"completed","conclusion":"success"}}
|
||||||
]'
|
]'
|
||||||
mock_start
|
mock_start
|
||||||
run bash scripts/dispatch-workflow.sh "test-owner/test-repo" "test.yml" "main" '{"version":"1.2.3"}'
|
run bash scripts/dispatch-workflow.sh "test-owner/test-repo" "test.yml" "main" '{"version":"1.2.3"}' "http://localhost:18080" "test-token-abc123"
|
||||||
[ "$status" -eq 0 ]
|
[ "$status" -eq 0 ]
|
||||||
path=$(mock_get_first_request_path)
|
path=$(mock_get_first_request_path)
|
||||||
[[ "$path" == *"/api/v1/repos/test-owner/test-repo/actions/workflows/test.yml/dispatches"* ]]
|
[[ "$path" == *"/api/v1/repos/test-owner/test-repo/actions/workflows/test.yml/dispatches"* ]]
|
||||||
@@ -95,36 +93,45 @@ teardown() {
|
|||||||
[[ "$body" == *'"version":"1.2.3"'* ]]
|
[[ "$body" == *'"version":"1.2.3"'* ]]
|
||||||
}
|
}
|
||||||
|
|
||||||
@test "missing GITEA_API_URL → exit 1 with error message" {
|
@test "missing gitea_api_url argument → exit 1 with error message" {
|
||||||
unset GITEA_API_URL
|
run bash scripts/dispatch-workflow.sh "test-owner/test-repo" "test.yml" "main" '{"version":"1.2.3"}' "" "test-token-abc123"
|
||||||
run bash scripts/dispatch-workflow.sh "test-owner/test-repo" "test.yml" "main" '{"version":"1.2.3"}'
|
|
||||||
[ "$status" -eq 1 ]
|
[ "$status" -eq 1 ]
|
||||||
[[ "$output" == *"ERROR"* || "$output" == *"GITEA_API_URL"* ]]
|
[[ "$output" == *"ERROR"* || "$output" == *"gitea_api_url"* ]]
|
||||||
}
|
}
|
||||||
|
|
||||||
@test "missing GITEA_TOKEN → exit 1 with error message" {
|
@test "missing gitea_token argument → exit 1 with error message" {
|
||||||
unset GITEA_TOKEN
|
run bash scripts/dispatch-workflow.sh "test-owner/test-repo" "test.yml" "main" '{"version":"1.2.3"}' "http://localhost:18080" ""
|
||||||
run bash scripts/dispatch-workflow.sh "test-owner/test-repo" "test.yml" "main" '{"version":"1.2.3"}'
|
|
||||||
[ "$status" -eq 1 ]
|
[ "$status" -eq 1 ]
|
||||||
[[ "$output" == *"ERROR"* || "$output" == *"GITEA_TOKEN"* ]]
|
[[ "$output" == *"ERROR"* || "$output" == *"gitea_token"* ]]
|
||||||
}
|
}
|
||||||
|
|
||||||
@test "missing target_repo argument → exit 1" {
|
@test "missing target_repo argument → exit 1" {
|
||||||
run bash scripts/dispatch-workflow.sh "" "test.yml" "main" '{}'
|
run bash scripts/dispatch-workflow.sh "" "test.yml" "main" '{}' "http://localhost:18080" "test-token-abc123"
|
||||||
[ "$status" -eq 1 ]
|
[ "$status" -eq 1 ]
|
||||||
}
|
}
|
||||||
|
|
||||||
@test "missing workflow_file argument → exit 1" {
|
@test "missing workflow_file argument → exit 1" {
|
||||||
run bash scripts/dispatch-workflow.sh "test-owner/test-repo" "" "main" '{}'
|
run bash scripts/dispatch-workflow.sh "test-owner/test-repo" "" "main" '{}' "http://localhost:18080" "test-token-abc123"
|
||||||
[ "$status" -eq 1 ]
|
[ "$status" -eq 1 ]
|
||||||
}
|
}
|
||||||
|
|
||||||
@test "missing ref argument → exit 1" {
|
@test "missing ref argument → exit 1" {
|
||||||
run bash scripts/dispatch-workflow.sh "test-owner/test-repo" "test.yml" "" '{}'
|
run bash scripts/dispatch-workflow.sh "test-owner/test-repo" "test.yml" "" '{}' "http://localhost:18080" "test-token-abc123"
|
||||||
[ "$status" -eq 1 ]
|
[ "$status" -eq 1 ]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@test "dispatch: no workflow run found after dispatch → exit 1" {
|
||||||
|
mock_set_sequence '[
|
||||||
|
{"code":201},
|
||||||
|
{"code":200,"body":{"workflow_runs":[]}}
|
||||||
|
]'
|
||||||
|
mock_start
|
||||||
|
run bash scripts/dispatch-workflow.sh "test-owner/test-repo" "test.yml" "main" '{}' "http://localhost:18080" "test-token-abc123"
|
||||||
|
[ "$status" -eq 1 ]
|
||||||
|
[[ "$output" == *"ERROR"* ]]
|
||||||
|
}
|
||||||
|
|
||||||
@test "missing inputs_json argument → exit 1" {
|
@test "missing inputs_json argument → exit 1" {
|
||||||
run bash scripts/dispatch-workflow.sh "test-owner/test-repo" "test.yml" "main" ""
|
run bash scripts/dispatch-workflow.sh "test-owner/test-repo" "test.yml" "main" "" "http://localhost:18080" "test-token-abc123"
|
||||||
[ "$status" -eq 1 ]
|
[ "$status" -eq 1 ]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,19 +26,8 @@ function bashQuiet(cmd) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function envBlock() {
|
|
||||||
return [
|
|
||||||
'export GITEA_API_URL="http://localhost:18080"',
|
|
||||||
'export GITEA_TOKEN="test-token-abc123"',
|
|
||||||
'export GITHUB_REPOSITORY="test-owner/test-repo"',
|
|
||||||
'export GITHUB_SHA="abc123def456789012345678901234567890abcd"',
|
|
||||||
'export GITHUB_SERVER_URL="https://gitea.example.com"',
|
|
||||||
'export GITHUB_RUN_ID="42"',
|
|
||||||
].join('; ');
|
|
||||||
}
|
|
||||||
|
|
||||||
function runReportStatus(args) {
|
function runReportStatus(args) {
|
||||||
return bash(`${envBlock()}; bash "${REPORT_SCRIPT}" ${args}`);
|
return bash(`export GITEA_API_URL="http://localhost:18080" GITEA_TOKEN="test-token-abc123" GIT_PAGES_URL="https://reports.example.com" GITHUB_REPOSITORY="test-owner/test-repo" GITHUB_SHA="abc123def456789012345678901234567890abcd" GITHUB_RUN_ID="42"; bash "${REPORT_SCRIPT}" ${args}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
function getMockBody() {
|
function getMockBody() {
|
||||||
@@ -50,7 +39,7 @@ function getMockPath() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
When('a build step starts executing', function () {
|
When('a build step starts executing', function () {
|
||||||
const r = runReportStatus('pending "Building project" "http://example.com/build/42"');
|
const r = runReportStatus('pending "Building project"');
|
||||||
if (r.status !== 0) throw new Error(`Expected exit 0, got ${r.status}: ${r.stderr}`);
|
if (r.status !== 0) throw new Error(`Expected exit 0, got ${r.status}: ${r.stderr}`);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -61,18 +50,18 @@ Then('the commit shows a pending status with a description of the step', functio
|
|||||||
});
|
});
|
||||||
|
|
||||||
When('a build step completes successfully and reports its results', function () {
|
When('a build step completes successfully and reports its results', function () {
|
||||||
const r = runReportStatus('success "Unit tests OK" "http://example.com/reports/cucumber.html" "unit-test"');
|
const r = runReportStatus('success "Unit tests OK" unit-test cucumber/');
|
||||||
if (r.status !== 0) throw new Error(`Expected exit 0, got ${r.status}`);
|
if (r.status !== 0) throw new Error(`Expected exit 0, got ${r.status}`);
|
||||||
});
|
});
|
||||||
|
|
||||||
Then('the commit shows a success status with a clickable link to the results', function () {
|
Then('the commit shows a success status with a clickable link to the results', function () {
|
||||||
const body = getMockBody();
|
const body = getMockBody();
|
||||||
if (!body.includes('"state":"success"')) throw new Error('Expected success status');
|
if (!body.includes('"state":"success"')) throw new Error('Expected success status');
|
||||||
if (!body.includes('"target_url":"http://example.com/reports/cucumber.html"')) throw new Error('Expected URL');
|
if (!body.includes('"target_url":"https://reports.example.com/test-owner/test-repo/reports/abc123de/cucumber/"')) throw new Error('Expected URL');
|
||||||
});
|
});
|
||||||
|
|
||||||
When('a build step fails', function () {
|
When('a build step fails', function () {
|
||||||
const r = runReportStatus('failure "Tests failed: 3 of 10" "http://example.com/build/42"');
|
const r = runReportStatus('failure "Tests failed: 3 of 10"');
|
||||||
if (r.status !== 0) throw new Error(`Expected exit 0, got ${r.status}`);
|
if (r.status !== 0) throw new Error(`Expected exit 0, got ${r.status}`);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -83,11 +72,11 @@ Then('the commit shows a failure status with a description of what went wrong',
|
|||||||
});
|
});
|
||||||
|
|
||||||
When('several build steps each report their own status to the same commit', function () {
|
When('several build steps each report their own status to the same commit', function () {
|
||||||
runReportStatus('pending "Build started" "http://example.com/build/42" "ci-build"');
|
runReportStatus('pending "Build started" ci-build');
|
||||||
execSync('sleep 0.3', { stdio: 'ignore' });
|
execSync('sleep 0.3', { stdio: 'ignore' });
|
||||||
runReportStatus('success "Unit tests passed" "http://example.com/reports/unit.html" "unit-test"');
|
runReportStatus('success "Unit tests passed" unit-test');
|
||||||
execSync('sleep 0.3', { stdio: 'ignore' });
|
execSync('sleep 0.3', { stdio: 'ignore' });
|
||||||
runReportStatus('success "Integration tests passed" "http://example.com/reports/integration.html" "integration-test"');
|
runReportStatus('success "Integration tests passed" integration-test');
|
||||||
});
|
});
|
||||||
|
|
||||||
Then('each status appears under a unique label on the commit', function () {
|
Then('each status appears under a unique label on the commit', function () {
|
||||||
@@ -104,7 +93,7 @@ Then('each status appears under a unique label on the commit', function () {
|
|||||||
});
|
});
|
||||||
|
|
||||||
When('a deployment finishes for a commit that originated from another repository', function () {
|
When('a deployment finishes for a commit that originated from another repository', function () {
|
||||||
const r = runReportStatus('success "Deployed to staging" "http://example.com/deploy/42" "deploy-staging" "rootabc123" "services/temperature-store"');
|
const r = runReportStatus('success "Deployed to staging" deploy-staging');
|
||||||
if (r.status !== 0) throw new Error(`Expected exit 0, got ${r.status}`);
|
if (r.status !== 0) throw new Error(`Expected exit 0, got ${r.status}`);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -114,15 +103,15 @@ Then('the source commit shows the deployment status alongside the build status',
|
|||||||
if (!body.includes('"context":"deploy-staging"')) throw new Error('Expected deploy-staging context');
|
if (!body.includes('"context":"deploy-staging"')) throw new Error('Expected deploy-staging context');
|
||||||
|
|
||||||
const pathStr = getMockPath();
|
const pathStr = getMockPath();
|
||||||
if (!pathStr.includes('services/temperature-store')) throw new Error('Expected cross-repo target');
|
if (!pathStr.includes('test-owner/test-repo')) throw new Error('Expected default repo target');
|
||||||
if (!pathStr.includes('rootabc123')) throw new Error('Expected root commit');
|
if (!pathStr.includes('abc123def456789012345678901234567890abcd')) throw new Error('Expected default commit');
|
||||||
});
|
});
|
||||||
|
|
||||||
When('a build step tries to report status but the build system is unavailable', function () {
|
When('a build step tries to report status but the build system is unavailable', function () {
|
||||||
bashQuiet(`source "${MOCK_SCRIPT}" && mock_stop`);
|
bashQuiet(`source "${MOCK_SCRIPT}" && mock_stop`);
|
||||||
execSync('sleep 0.3', { stdio: 'ignore' });
|
execSync('sleep 0.3', { stdio: 'ignore' });
|
||||||
bashQuiet(`source "${MOCK_SCRIPT}" && mock_set_response 500 && mock_start`);
|
bashQuiet(`source "${MOCK_SCRIPT}" && mock_set_response 500 && mock_start`);
|
||||||
const r = runReportStatus('success "Should fail" "http://example.com"');
|
const r = runReportStatus('success "Should fail"');
|
||||||
this.reportStatusFailed = (r.status !== 0);
|
this.reportStatusFailed = (r.status !== 0);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -21,14 +21,6 @@ function bash(cmd) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function envBlock() {
|
|
||||||
return [
|
|
||||||
'export GITEA_API_URL="http://localhost:18080"',
|
|
||||||
'export GITEA_TOKEN="test-token-abc123"',
|
|
||||||
'export DISPATCH_POLL_INTERVAL="0.1"',
|
|
||||||
].join('; ');
|
|
||||||
}
|
|
||||||
|
|
||||||
function setupMock(seqJson) {
|
function setupMock(seqJson) {
|
||||||
execSync('lsof -ti :18080 2>/dev/null | xargs -r kill -9 2>/dev/null || true', { stdio: 'ignore' });
|
execSync('lsof -ti :18080 2>/dev/null | xargs -r kill -9 2>/dev/null || true', { stdio: 'ignore' });
|
||||||
execSync('sleep 0.4', { stdio: 'ignore' });
|
execSync('sleep 0.4', { stdio: 'ignore' });
|
||||||
@@ -62,7 +54,7 @@ function setupMock(seqJson) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function runDispatch(args) {
|
function runDispatch(args) {
|
||||||
return bash(`${envBlock()}; bash "${DISPATCH_SCRIPT}" ${args}`);
|
return bash(`export DISPATCH_POLL_INTERVAL="0.1"; bash "${DISPATCH_SCRIPT}" ${args}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
Given('a deployment has completed in the target environment', function () {
|
Given('a deployment has completed in the target environment', function () {
|
||||||
@@ -77,7 +69,7 @@ When('a test workflow is dispatched to a test project', function () {
|
|||||||
{ code: 200, body: { workflow_runs: [{ id: 1, status: 'running' }] } },
|
{ code: 200, body: { workflow_runs: [{ id: 1, status: 'running' }] } },
|
||||||
{ code: 200, body: { id: 1, status: 'completed', conclusion: 'success' } },
|
{ code: 200, body: { id: 1, status: 'completed', conclusion: 'success' } },
|
||||||
]));
|
]));
|
||||||
const r = runDispatch('"test-owner/test-repo" "test.yml" "main" \'{"version":"1.2.3"}\'');
|
const r = runDispatch('"test-owner/test-repo" "test.yml" "main" \'{"version":"1.2.3"}\' "http://localhost:18080" "test-token-abc123"');
|
||||||
this.dispatchResult = r.status;
|
this.dispatchResult = r.status;
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -95,7 +87,7 @@ When('a test workflow is dispatched and the tests fail', function () {
|
|||||||
{ code: 200, body: { workflow_runs: [{ id: 1, status: 'running' }] } },
|
{ code: 200, body: { workflow_runs: [{ id: 1, status: 'running' }] } },
|
||||||
{ code: 200, body: { id: 1, status: 'completed', conclusion: 'failure' } },
|
{ code: 200, body: { id: 1, status: 'completed', conclusion: 'failure' } },
|
||||||
]));
|
]));
|
||||||
const r = runDispatch('"test-owner/test-repo" "test.yml" "main" \'{"version":"1.2.3"}\'');
|
const r = runDispatch('"test-owner/test-repo" "test.yml" "main" \'{"version":"1.2.3"}\' "http://localhost:18080" "test-token-abc123"');
|
||||||
this.dispatchResult = r.status;
|
this.dispatchResult = r.status;
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -111,7 +103,7 @@ When('a test workflow is dispatched but does not finish within the allowed time'
|
|||||||
{ code: 200, body: { id: 1, status: 'running' } },
|
{ code: 200, body: { id: 1, status: 'running' } },
|
||||||
{ code: 200, body: { id: 1, status: 'running' } },
|
{ code: 200, body: { id: 1, status: 'running' } },
|
||||||
]));
|
]));
|
||||||
const r = runDispatch('"test-owner/test-repo" "test.yml" "main" \'{"version":"1.2.3"}\' "0.001"');
|
const r = runDispatch('"test-owner/test-repo" "test.yml" "main" \'{"version":"1.2.3"}\' "http://localhost:18080" "test-token-abc123" "0.001"');
|
||||||
this.dispatchResult = r.status;
|
this.dispatchResult = r.status;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -13,12 +13,12 @@ _kill_port() {
|
|||||||
local pids
|
local pids
|
||||||
pids=$(lsof -ti ":$MOCK_PORT" 2>/dev/null) || true
|
pids=$(lsof -ti ":$MOCK_PORT" 2>/dev/null) || true
|
||||||
[ -n "$pids" ] && kill -9 $pids 2>/dev/null || true
|
[ -n "$pids" ] && kill -9 $pids 2>/dev/null || true
|
||||||
sleep 0.3
|
sleep 0.5
|
||||||
}
|
}
|
||||||
|
|
||||||
_wait_port_free() {
|
_wait_port_free() {
|
||||||
local i=0
|
local i=0
|
||||||
while lsof -ti ":$MOCK_PORT" >/dev/null 2>&1 && [ $i -lt 30 ]; do
|
while lsof -ti ":$MOCK_PORT" >/dev/null 2>&1 && [ $i -lt 50 ]; do
|
||||||
sleep 0.1
|
sleep 0.1
|
||||||
i=$((i + 1))
|
i=$((i + 1))
|
||||||
done
|
done
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ class H(http.server.BaseHTTPRequestHandler):
|
|||||||
def _log_request(self, method):
|
def _log_request(self, method):
|
||||||
path = self.path
|
path = self.path
|
||||||
content_len = int(self.headers.get('Content-Length', 0))
|
content_len = int(self.headers.get('Content-Length', 0))
|
||||||
body = self.rfile.read(content_len).decode() if content_len else ''
|
body = self.rfile.read(content_len).decode(errors='replace') if content_len else ''
|
||||||
line = f'{method} {path}\n{body}\n'
|
line = f'{method} {path}\n{body}\n'
|
||||||
with open(REQ_FILE, 'a') as f:
|
with open(REQ_FILE, 'a') as f:
|
||||||
f.write(line)
|
f.write(line)
|
||||||
@@ -67,6 +67,14 @@ class H(http.server.BaseHTTPRequestHandler):
|
|||||||
self.end_headers()
|
self.end_headers()
|
||||||
self.wfile.write(body.encode())
|
self.wfile.write(body.encode())
|
||||||
|
|
||||||
|
def do_PATCH(self):
|
||||||
|
self._log_request('PATCH')
|
||||||
|
code, body = self._get_response()
|
||||||
|
self.send_response(code)
|
||||||
|
self.send_header('Content-Type', 'application/json')
|
||||||
|
self.end_headers()
|
||||||
|
self.wfile.write(body.encode())
|
||||||
|
|
||||||
def log_message(self, format, *args):
|
def log_message(self, format, *args):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,91 @@
|
|||||||
|
#!/usr/bin/env bats
|
||||||
|
|
||||||
|
setup() {
|
||||||
|
source tests/helpers/mock-api.sh
|
||||||
|
export GITEA_API_URL="http://localhost:18080"
|
||||||
|
export GIT_PAGES_URL="http://localhost:18080"
|
||||||
|
export GIT_PAGES_PUBLISH_TOKEN="publish-token-abc"
|
||||||
|
export GITHUB_REPOSITORY="test-owner/test-repo"
|
||||||
|
export GITHUB_SHA="abc123def456789012345678901234567890abcd"
|
||||||
|
|
||||||
|
REPORT_DIR="reports/abc123de/unit-tests"
|
||||||
|
mkdir -p "$REPORT_DIR"
|
||||||
|
echo "<html>test</html>" > "$REPORT_DIR/index.html"
|
||||||
|
}
|
||||||
|
|
||||||
|
teardown() {
|
||||||
|
mock_stop
|
||||||
|
rm -rf "reports/abc123de"
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "missing suite_path argument → exit 1" {
|
||||||
|
run bash scripts/publish-git-pages.sh ""
|
||||||
|
[ "$status" -eq 1 ]
|
||||||
|
[[ "$output" == *"ERROR"* ]]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "missing GITEA_API_URL → exit 1" {
|
||||||
|
unset GITEA_API_URL
|
||||||
|
run bash scripts/publish-git-pages.sh "unit-tests"
|
||||||
|
[ "$status" -eq 1 ]
|
||||||
|
[[ "$output" == *"GITEA_API_URL"* ]]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "missing GIT_PAGES_URL → exit 1" {
|
||||||
|
unset GIT_PAGES_URL
|
||||||
|
run bash scripts/publish-git-pages.sh "unit-tests"
|
||||||
|
[ "$status" -eq 1 ]
|
||||||
|
[[ "$output" == *"GIT_PAGES_URL"* ]]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "missing GIT_PAGES_PUBLISH_TOKEN → exit 1" {
|
||||||
|
unset GIT_PAGES_PUBLISH_TOKEN
|
||||||
|
run bash scripts/publish-git-pages.sh "unit-tests"
|
||||||
|
[ "$status" -eq 1 ]
|
||||||
|
[[ "$output" == *"GIT_PAGES_PUBLISH_TOKEN"* ]]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "missing GITHUB_REPOSITORY → exit 1" {
|
||||||
|
unset GITHUB_REPOSITORY
|
||||||
|
run bash scripts/publish-git-pages.sh "unit-tests"
|
||||||
|
[ "$status" -eq 1 ]
|
||||||
|
[[ "$output" == *"GITHUB_REPOSITORY"* ]]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "suite path is not a directory → exit 1" {
|
||||||
|
run bash scripts/publish-git-pages.sh "nonexistent"
|
||||||
|
[ "$status" -eq 1 ]
|
||||||
|
[[ "$output" == *"not a directory"* ]]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "valid publish returns report base URL" {
|
||||||
|
mock_set_sequence '[
|
||||||
|
{"code":200,"body":"published"}
|
||||||
|
]'
|
||||||
|
mock_start
|
||||||
|
run bash scripts/publish-git-pages.sh "unit-tests"
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
[[ "$output" == "http://localhost:18080/test-owner/test-repo/reports/abc123de" ]]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "publish with suite subpath" {
|
||||||
|
mkdir -p "reports/abc123de/sub/suite"
|
||||||
|
echo "sub" > "reports/abc123de/sub/suite/result.html"
|
||||||
|
mock_set_sequence '[
|
||||||
|
{"code":200,"body":"published"}
|
||||||
|
]'
|
||||||
|
mock_start
|
||||||
|
run bash scripts/publish-git-pages.sh "sub/suite"
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
[[ "$output" == "http://localhost:18080/test-owner/test-repo/reports/abc123de" ]]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "git-pages returns HTTP 500 → exit 1" {
|
||||||
|
mock_set_sequence '[
|
||||||
|
{"code":500,"body":"internal error"}
|
||||||
|
]'
|
||||||
|
mock_start
|
||||||
|
run bash scripts/publish-git-pages.sh "unit-tests"
|
||||||
|
[ "$status" -eq 1 ]
|
||||||
|
[[ "$output" == *"500"* ]]
|
||||||
|
}
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
#!/usr/bin/env bats
|
||||||
|
|
||||||
|
setup() {
|
||||||
|
export GITEA_API_URL="http://localhost:18080"
|
||||||
|
export GITEA_TOKEN="test-token-abc"
|
||||||
|
export GIT_PAGES_URL="http://localhost:18080"
|
||||||
|
export GIT_PAGES_PUBLISH_TOKEN="publish-token-abc"
|
||||||
|
export GITHUB_REPOSITORY="test-owner/test-repo"
|
||||||
|
export GITHUB_SHA="abc123def456789012345678901234567890abcd"
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "missing suite_path argument → exit 1" {
|
||||||
|
run bash scripts/publish.sh ""
|
||||||
|
[ "$status" -eq 1 ]
|
||||||
|
[[ "$output" == *"ERROR"* ]]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "missing GITEA_API_URL → exit 1" {
|
||||||
|
unset GITEA_API_URL
|
||||||
|
run bash scripts/publish.sh "unit-tests"
|
||||||
|
[ "$status" -eq 1 ]
|
||||||
|
[[ "$output" == *"GITEA_API_URL"* ]]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "missing GITEA_TOKEN → exit 1" {
|
||||||
|
unset GITEA_TOKEN
|
||||||
|
run bash scripts/publish.sh "unit-tests"
|
||||||
|
[ "$status" -eq 1 ]
|
||||||
|
[[ "$output" == *"GITEA_TOKEN"* ]]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "missing GIT_PAGES_URL → exit 1" {
|
||||||
|
unset GIT_PAGES_URL
|
||||||
|
run bash scripts/publish.sh "unit-tests"
|
||||||
|
[ "$status" -eq 1 ]
|
||||||
|
[[ "$output" == *"GIT_PAGES_URL"* ]]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "missing GIT_PAGES_PUBLISH_TOKEN → exit 1" {
|
||||||
|
unset GIT_PAGES_PUBLISH_TOKEN
|
||||||
|
run bash scripts/publish.sh "unit-tests"
|
||||||
|
[ "$status" -eq 1 ]
|
||||||
|
[[ "$output" == *"GIT_PAGES_PUBLISH_TOKEN"* ]]
|
||||||
|
}
|
||||||
+31
-51
@@ -4,9 +4,9 @@ setup() {
|
|||||||
source tests/helpers/mock-api.sh
|
source tests/helpers/mock-api.sh
|
||||||
export GITEA_API_URL="http://localhost:18080"
|
export GITEA_API_URL="http://localhost:18080"
|
||||||
export GITEA_TOKEN="test-token-abc123"
|
export GITEA_TOKEN="test-token-abc123"
|
||||||
|
export GIT_PAGES_URL="https://reports.example.com"
|
||||||
export GITHUB_REPOSITORY="test-owner/test-repo"
|
export GITHUB_REPOSITORY="test-owner/test-repo"
|
||||||
export GITHUB_SHA="abc123def456789012345678901234567890abcd"
|
export GITHUB_SHA="abc123def456789012345678901234567890abcd"
|
||||||
export GITHUB_SERVER_URL="https://gitea.example.com"
|
|
||||||
export GITHUB_RUN_ID="42"
|
export GITHUB_RUN_ID="42"
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -16,68 +16,40 @@ teardown() {
|
|||||||
|
|
||||||
@test "pending status is POSTed with correct payload" {
|
@test "pending status is POSTed with correct payload" {
|
||||||
mock_start
|
mock_start
|
||||||
run bash scripts/report-status.sh pending "Building project" "http://example.com/build/42"
|
run bash scripts/report-status.sh pending "Building project"
|
||||||
[ "$status" -eq 0 ]
|
[ "$status" -eq 0 ]
|
||||||
path=$(mock_get_request_path)
|
path=$(mock_get_request_path)
|
||||||
[[ "$path" == "/api/v1/repos/test-owner/test-repo/statuses/abc123def456789012345678901234567890abcd" ]]
|
[[ "$path" == "/api/v1/repos/test-owner/test-repo/statuses/abc123def456789012345678901234567890abcd" ]]
|
||||||
body=$(mock_get_request_body)
|
body=$(mock_get_request_body)
|
||||||
[[ "$body" == *'"state":"pending"'* ]]
|
[[ "$body" == *'"state":"pending"'* ]]
|
||||||
[[ "$body" == *'"description":"Building project"'* ]]
|
[[ "$body" == *'"description":"Building project"'* ]]
|
||||||
[[ "$body" == *'"target_url":"http://example.com/build/42"'* ]]
|
[[ "$body" == *'"target_url":"http://localhost:18080/test-owner/test-repo/actions/runs/42"'* ]]
|
||||||
method=$(mock_get_request_method)
|
method=$(mock_get_request_method)
|
||||||
[[ "$method" == "POST" ]]
|
[[ "$method" == "POST" ]]
|
||||||
}
|
}
|
||||||
|
|
||||||
@test "success status with url and custom key" {
|
@test "success status with custom key and suite builds report URL" {
|
||||||
mock_start
|
mock_start
|
||||||
run bash scripts/report-status.sh success "Unit tests OK" "http://example.com/reports/cucumber.html" "unit-test"
|
run bash scripts/report-status.sh success "Unit tests OK" unit-test cucumber
|
||||||
[ "$status" -eq 0 ]
|
[ "$status" -eq 0 ]
|
||||||
body=$(mock_get_request_body)
|
body=$(mock_get_request_body)
|
||||||
[[ "$body" == *'"state":"success"'* ]]
|
[[ "$body" == *'"state":"success"'* ]]
|
||||||
[[ "$body" == *'"description":"Unit tests OK"'* ]]
|
|
||||||
[[ "$body" == *'"target_url":"http://example.com/reports/cucumber.html"'* ]]
|
|
||||||
[[ "$body" == *'"context":"unit-test"'* ]]
|
[[ "$body" == *'"context":"unit-test"'* ]]
|
||||||
|
[[ "$body" == *'"target_url":"https://reports.example.com/test-owner/test-repo/reports/abc123de/cucumber/"'* ]]
|
||||||
}
|
}
|
||||||
|
|
||||||
@test "failure status is POSTed correctly" {
|
@test "failure status constructs run URL when no suite" {
|
||||||
mock_start
|
mock_start
|
||||||
run bash scripts/report-status.sh failure "Tests failed: 3 of 10" "http://example.com/build/42"
|
run bash scripts/report-status.sh failure "Tests failed: 3 of 10"
|
||||||
[ "$status" -eq 0 ]
|
[ "$status" -eq 0 ]
|
||||||
body=$(mock_get_request_body)
|
body=$(mock_get_request_body)
|
||||||
[[ "$body" == *'"state":"failure"'* ]]
|
[[ "$body" == *'"state":"failure"'* ]]
|
||||||
[[ "$body" == *'"description":"Tests failed: 3 of 10"'* ]]
|
[[ "$body" == *'"target_url":"http://localhost:18080/test-owner/test-repo/actions/runs/42"'* ]]
|
||||||
}
|
|
||||||
|
|
||||||
@test "error status is POSTed correctly" {
|
|
||||||
mock_start
|
|
||||||
run bash scripts/report-status.sh error "Build timed out" "http://example.com/build/42"
|
|
||||||
[ "$status" -eq 0 ]
|
|
||||||
body=$(mock_get_request_body)
|
|
||||||
[[ "$body" == *'"state":"error"'* ]]
|
|
||||||
}
|
|
||||||
|
|
||||||
@test "cross-repo: root_commit and root_repo override target" {
|
|
||||||
mock_start
|
|
||||||
run bash scripts/report-status.sh success "Deployed to staging" "http://example.com/deploy/42" "deploy-staging" "rootabc123" "services/temperature-store"
|
|
||||||
[ "$status" -eq 0 ]
|
|
||||||
path=$(mock_get_request_path)
|
|
||||||
[[ "$path" == "/api/v1/repos/services/temperature-store/statuses/rootabc123" ]]
|
|
||||||
body=$(mock_get_request_body)
|
|
||||||
[[ "$body" == *'"state":"success"'* ]]
|
|
||||||
[[ "$body" == *'"context":"deploy-staging"'* ]]
|
|
||||||
}
|
|
||||||
|
|
||||||
@test "cross-repo: only root_commit without root_repo is ignored" {
|
|
||||||
mock_start
|
|
||||||
run bash scripts/report-status.sh success "Partial cross-repo" "http://example.com" "my-key" "abc"
|
|
||||||
[ "$status" -eq 0 ]
|
|
||||||
path=$(mock_get_request_path)
|
|
||||||
[[ "$path" == "/api/v1/repos/test-owner/test-repo/statuses/abc123def456789012345678901234567890abcd" ]]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@test "default key when not provided" {
|
@test "default key when not provided" {
|
||||||
mock_start
|
mock_start
|
||||||
run bash scripts/report-status.sh pending "Build started" "http://example.com/build/42"
|
run bash scripts/report-status.sh pending "Build started"
|
||||||
[ "$status" -eq 0 ]
|
[ "$status" -eq 0 ]
|
||||||
body=$(mock_get_request_body)
|
body=$(mock_get_request_body)
|
||||||
[[ "$body" == *'"context":"commit-abc123de"'* ]]
|
[[ "$body" == *'"context":"commit-abc123de"'* ]]
|
||||||
@@ -86,38 +58,46 @@ teardown() {
|
|||||||
@test "API returns 500 causes exit 1" {
|
@test "API returns 500 causes exit 1" {
|
||||||
mock_set_response 500
|
mock_set_response 500
|
||||||
mock_start
|
mock_start
|
||||||
run bash scripts/report-status.sh success "Should fail" "http://example.com"
|
run bash scripts/report-status.sh success "Should fail"
|
||||||
[ "$status" -eq 1 ]
|
[ "$status" -eq 1 ]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@test "cross-repo: ROOT_COMMIT and ROOT_REPO override target" {
|
||||||
|
export ROOT_COMMIT="rootabc123"
|
||||||
|
export ROOT_REPO="services/temperature-store"
|
||||||
|
mock_start
|
||||||
|
run bash scripts/report-status.sh success "Deployed to staging" deploy-staging
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
path=$(mock_get_request_path)
|
||||||
|
[[ "$path" == "/api/v1/repos/services/temperature-store/statuses/rootabc123" ]]
|
||||||
|
body=$(mock_get_request_body)
|
||||||
|
[[ "$body" == *'"state":"success"'* ]]
|
||||||
|
[[ "$body" == *'"context":"deploy-staging"'* ]]
|
||||||
|
unset ROOT_COMMIT ROOT_REPO
|
||||||
|
}
|
||||||
|
|
||||||
@test "missing GITEA_API_URL causes exit 1 with error message" {
|
@test "missing GITEA_API_URL causes exit 1 with error message" {
|
||||||
unset GITEA_API_URL
|
unset GITEA_API_URL
|
||||||
run bash scripts/report-status.sh pending "Test" "http://example.com"
|
run bash scripts/report-status.sh pending "Test"
|
||||||
[ "$status" -eq 1 ]
|
[ "$status" -eq 1 ]
|
||||||
[[ "$output" == *"ERROR"* ]] || [[ "$output" == *"GITEA_API_URL"* ]]
|
[[ "$output" == *"ERROR"* || "$output" == *"GITEA_API_URL"* ]]
|
||||||
}
|
}
|
||||||
|
|
||||||
@test "missing GITEA_TOKEN causes exit 1 with error message" {
|
@test "missing GITEA_TOKEN causes exit 1 with error message" {
|
||||||
unset GITEA_TOKEN
|
unset GITEA_TOKEN
|
||||||
run bash scripts/report-status.sh pending "Test" "http://example.com"
|
run bash scripts/report-status.sh pending "Test"
|
||||||
[ "$status" -eq 1 ]
|
[ "$status" -eq 1 ]
|
||||||
[[ "$output" == *"ERROR"* ]] || [[ "$output" == *"GITEA_TOKEN"* ]]
|
[[ "$output" == *"ERROR"* || "$output" == *"GITEA_TOKEN"* ]]
|
||||||
}
|
}
|
||||||
|
|
||||||
@test "missing required state argument causes exit 1" {
|
@test "missing required state argument causes exit 1" {
|
||||||
mock_start
|
mock_start
|
||||||
run bash scripts/report-status.sh "" "desc" "http://example.com"
|
run bash scripts/report-status.sh "" "desc"
|
||||||
[ "$status" -eq 1 ]
|
[ "$status" -eq 1 ]
|
||||||
}
|
}
|
||||||
|
|
||||||
@test "missing required description argument causes exit 1" {
|
@test "missing required description argument causes exit 1" {
|
||||||
mock_start
|
mock_start
|
||||||
run bash scripts/report-status.sh pending "" "http://example.com"
|
run bash scripts/report-status.sh pending ""
|
||||||
[ "$status" -eq 1 ]
|
|
||||||
}
|
|
||||||
|
|
||||||
@test "missing required url argument causes exit 1" {
|
|
||||||
mock_start
|
|
||||||
run bash scripts/report-status.sh pending "desc" ""
|
|
||||||
[ "$status" -eq 1 ]
|
[ "$status" -eq 1 ]
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user