Feature/docker kuntoon (#11)
Co-authored-by: moilanik <niko.moilanen@tietoevry.com> Reviewed-on: #11
This commit is contained in:
@@ -1,30 +0,0 @@
|
||||
#!/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"
|
||||
@@ -1,124 +0,0 @@
|
||||
name: Build & Publish Artifact
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
env_json:
|
||||
required: true
|
||||
type: string
|
||||
bats-image:
|
||||
required: true
|
||||
type: string
|
||||
cucumber-node-image:
|
||||
required: true
|
||||
type: string
|
||||
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:
|
||||
check:
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
artifact_exists: ${{ steps.check.outputs.artifact_exists }}
|
||||
version: ${{ steps.check.outputs.version }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Check existing artifact
|
||||
id: check
|
||||
run: |
|
||||
VERSION=$(jq -r '.version' package.json)
|
||||
echo "version=$VERSION" >> "$GITHUB_OUTPUT"
|
||||
|
||||
TAG=$(curl -s "$GITEA_API_URL/api/v1/repos/$GITHUB_REPOSITORY/tags" | \
|
||||
jq -r '.[] | select(.commit.sha == "'"$GITHUB_SHA"'") | .name' | head -1)
|
||||
if [ -n "$TAG" ]; then
|
||||
echo "artifact_exists=true" >> "$GITHUB_OUTPUT"
|
||||
echo "Commit already tagged as $TAG, skipping build"
|
||||
else
|
||||
echo "artifact_exists=false" >> "$GITHUB_OUTPUT"
|
||||
fi
|
||||
|
||||
quality-gate:
|
||||
needs: [check]
|
||||
if: needs.check.outputs.artifact_exists == 'false'
|
||||
uses: niko/gitea-ci-library/.gitea/workflows/quality-gate.yml@main
|
||||
secrets: inherit
|
||||
with:
|
||||
env_json: ${{ inputs.env_json }}
|
||||
bats-image: ${{ inputs.bats-image }}
|
||||
cucumber-node-image: ${{ inputs.cucumber-node-image }}
|
||||
|
||||
build:
|
||||
needs: [check, quality-gate]
|
||||
if: needs.check.outputs.artifact_exists == 'false'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Build container
|
||||
run: |
|
||||
docker build -t "minimal:${{ needs.check.outputs.version }}" .
|
||||
mkdir -p /tmp/image
|
||||
docker save "minimal:${{ needs.check.outputs.version }}" -o /tmp/image/artifact.tar
|
||||
|
||||
- name: Save Docker image for next job
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: docker-image
|
||||
path: /tmp/image/artifact.tar
|
||||
|
||||
push:
|
||||
needs: [check, build]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Load saved Docker image
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: docker-image
|
||||
path: /tmp/image
|
||||
|
||||
- name: Push to Gitea Packages
|
||||
run: |
|
||||
VERSION="${{ needs.check.outputs.version }}"
|
||||
docker load -i /tmp/image/artifact.tar
|
||||
REGISTRY=$(echo "$GITEA_API_URL" | sed 's|https://||')
|
||||
IMAGE="$REGISTRY/niko/gitea-ci-library/minimal:$VERSION"
|
||||
docker tag "minimal:$VERSION" "$IMAGE"
|
||||
docker login "$REGISTRY" -u niko -p "$GITEA_TOKEN"
|
||||
docker push "$IMAGE"
|
||||
docker logout "$REGISTRY"
|
||||
|
||||
tag-commit:
|
||||
needs: [check, push]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Create git tag
|
||||
run: |
|
||||
VERSION="${{ needs.check.outputs.version }}"
|
||||
HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" -X POST \
|
||||
"$GITEA_API_URL/api/v1/repos/$GITHUB_REPOSITORY/tags" \
|
||||
-H "Authorization: token $GITEA_TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "{
|
||||
\"tag_name\": \"$VERSION\",
|
||||
\"message\": \"Build #$GITHUB_RUN_NUMBER\",
|
||||
\"target\": \"$GITHUB_SHA\"
|
||||
}")
|
||||
|
||||
if [ "$HTTP_CODE" = "201" ]; then
|
||||
echo "Tag $VERSION created"
|
||||
elif [ "$HTTP_CODE" = "409" ]; then
|
||||
echo "Tag $VERSION already exists (parallel build won), skipping"
|
||||
else
|
||||
echo "Failed to create tag: HTTP $HTTP_CODE"
|
||||
exit 1
|
||||
fi
|
||||
@@ -0,0 +1,64 @@
|
||||
name: Check Existing Artifact
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
env_json:
|
||||
required: true
|
||||
type: string
|
||||
secrets:
|
||||
GITEA_TOKEN:
|
||||
required: true
|
||||
outputs:
|
||||
artifact_exists:
|
||||
value: ${{ jobs.check.outputs.artifact_exists }}
|
||||
version:
|
||||
value: ${{ jobs.check.outputs.version }}
|
||||
|
||||
env:
|
||||
GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }}
|
||||
|
||||
jobs:
|
||||
check:
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
artifact_exists: ${{ steps.set-outputs.outputs.artifact_exists }}
|
||||
version: ${{ steps.set-outputs.outputs.version }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Check existing artifact and calculate version
|
||||
run: |
|
||||
RAW_VERSION=$(jq -r '.version' package.json)
|
||||
BASE_VERSION=$(echo "$RAW_VERSION" | cut -d'.' -f1-2)
|
||||
echo "gitea-ci-library - Tunnistettu Major.Minor versio: $BASE_VERSION"
|
||||
|
||||
TAGS_JSON=$(curl -s -f -H "Authorization: token $GITEA_TOKEN" \
|
||||
"${{ gitea.server_url }}/api/v1/repos/${{ gitea.repository }}/tags")
|
||||
|
||||
TAG=$(echo "$TAGS_JSON" | jq -r 'if type == "array" then .[] | select(.commit.sha == "${{ github.sha }}") | .name else empty end' | head -1)
|
||||
|
||||
mkdir -p /tmp/build-ctx
|
||||
|
||||
if [ -n "$TAG" ]; then
|
||||
echo "ARTIFACT_EXISTS=true" > /tmp/build-ctx/build.env
|
||||
echo "NEXT_VERSION=$TAG" >> /tmp/build-ctx/build.env
|
||||
echo "gitea-ci-library - Artefakti löytyi jo tagilla: $TAG."
|
||||
else
|
||||
echo "ARTIFACT_EXISTS=false" > /tmp/build-ctx/build.env
|
||||
|
||||
HIGHEST_PATCH=$(echo "$TAGS_JSON" | jq -r --arg bv "$BASE_VERSION." '
|
||||
if type == "array" then .[] | .name | select(startswith($bv)) | sub($bv; "") | tonumber else empty end' | sort -rn | head -1)
|
||||
|
||||
if [ -z "$HIGHEST_PATCH" ]; then NEXT_PATCH=0; else NEXT_PATCH=$((HIGHEST_PATCH + 1)); fi
|
||||
FULL_VERSION="${BASE_VERSION}.${NEXT_PATCH}"
|
||||
|
||||
echo "NEXT_VERSION=$FULL_VERSION" >> /tmp/build-ctx/build.env
|
||||
echo "gitea-ci-library - Uusi vapaa versio: $FULL_VERSION"
|
||||
fi
|
||||
|
||||
- name: Set job outputs
|
||||
id: set-outputs
|
||||
run: |
|
||||
source /tmp/build-ctx/build.env
|
||||
echo "artifact_exists=$ARTIFACT_EXISTS" >> "$GITHUB_OUTPUT"
|
||||
echo "version=$NEXT_VERSION" >> "$GITHUB_OUTPUT"
|
||||
@@ -1,34 +0,0 @@
|
||||
name: CI
|
||||
on:
|
||||
push:
|
||||
branches: ["**"]
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
load-config:
|
||||
name: Load gitea-env.conf to pipeline env
|
||||
uses: niko/gitea-ci-library/.gitea/workflows/config-provider.yml@main
|
||||
with:
|
||||
config_path: .gitea/workflows/gitea-env.conf
|
||||
|
||||
feature:
|
||||
name: Quality Gate
|
||||
if: github.ref != 'refs/heads/main'
|
||||
needs: [load-config]
|
||||
uses: niko/gitea-ci-library/.gitea/workflows/quality-gate.yml@main
|
||||
secrets: inherit
|
||||
with:
|
||||
env_json: ${{ needs.load-config.outputs.env_json }}
|
||||
bats-image: bats/bats:latest
|
||||
cucumber-node-image: node:22
|
||||
|
||||
main:
|
||||
name: Build & Push Artifact
|
||||
if: github.ref == 'refs/heads/main'
|
||||
needs: [load-config]
|
||||
uses: niko/gitea-ci-library/.gitea/workflows/build_publish-artifact.yml@main
|
||||
secrets: inherit
|
||||
with:
|
||||
env_json: ${{ needs.load-config.outputs.env_json }}
|
||||
bats-image: bats/bats:latest
|
||||
cucumber-node-image: node:22
|
||||
@@ -1,21 +1,41 @@
|
||||
name: Config Provider Library
|
||||
name: Config Provider
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
config_path:
|
||||
required: true
|
||||
type: string
|
||||
secrets:
|
||||
GITEA_TOKEN:
|
||||
required: true
|
||||
GIT_PAGES_PUBLISH_TOKEN:
|
||||
required: true
|
||||
outputs:
|
||||
env_json:
|
||||
value: ${{ jobs.parse-config.outputs.json_data }}
|
||||
config_path:
|
||||
value: ${{ jobs.parse-config.outputs.config_path }}
|
||||
|
||||
env:
|
||||
CI_CONF_FILE: ${{ inputs.config_path }}
|
||||
GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }}
|
||||
GIT_PAGES_PUBLISH_TOKEN: ${{ secrets.GIT_PAGES_PUBLISH_TOKEN }}
|
||||
|
||||
jobs:
|
||||
parse-config:
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
json_data: ${{ steps.convert.outputs.JSON_OUT }}
|
||||
config_path: ${{ steps.set-path.outputs.CONFIG_PATH }}
|
||||
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
|
||||
|
||||
- id: convert
|
||||
run: |
|
||||
@@ -29,3 +49,6 @@ jobs:
|
||||
|
||||
CLEAN_JSON=$(echo "$JSON_STRING" | jq -c .)
|
||||
echo "JSON_OUT=$CLEAN_JSON" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- id: set-path
|
||||
run: echo "CONFIG_PATH=${{ inputs.config_path }}" >> "$GITHUB_OUTPUT"
|
||||
|
||||
@@ -0,0 +1,101 @@
|
||||
name: Docker Build & Push
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
env_json:
|
||||
required: true
|
||||
type: string
|
||||
version:
|
||||
required: true
|
||||
type: string
|
||||
secrets:
|
||||
GITEA_TOKEN:
|
||||
required: true
|
||||
DOCKER_USERNAME:
|
||||
required: false
|
||||
DOCKER_PASSWORD:
|
||||
required: true
|
||||
|
||||
env:
|
||||
GITEA_API_URL: ${{ fromJson(inputs.env_json).GITEA_API_URL }}
|
||||
GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }}
|
||||
DOCKER_REGISTRY: ${{ fromJson(inputs.env_json).DOCKER_REGISTRY || '' }}
|
||||
DOCKER_IMAGE_NAME: ${{ fromJson(inputs.env_json).DOCKER_IMAGE_NAME || '' }}
|
||||
DOCKER_UI_URL: ${{ fromJson(inputs.env_json).DOCKER_UI_URL || '' }}
|
||||
VERSION: ${{ inputs.version }}
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
build-push:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
repository: niko/gitea-ci-library
|
||||
path: .ci
|
||||
|
||||
- name: Build and push container
|
||||
env:
|
||||
DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME || github.actor }}
|
||||
DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }}
|
||||
run: |
|
||||
NOW=$(date -u +%Y-%m-%dT%H:%M:%SZ)
|
||||
docker build \
|
||||
--label "git.commit=${{ github.sha }}" \
|
||||
--label "git.commitBy=${{ github.actor }}" \
|
||||
--label "build.date=${NOW}" \
|
||||
-t "${DOCKER_IMAGE_NAME}:${VERSION}" .
|
||||
|
||||
REGISTRY="${DOCKER_REGISTRY:?DOCKER_REGISTRY not set in env.conf}"
|
||||
IMAGE="${DOCKER_IMAGE_NAME:?DOCKER_IMAGE_NAME not set in env.conf}"
|
||||
REGISTRY_HOST="${REGISTRY%%/*}"
|
||||
|
||||
FULL_IMAGE="${REGISTRY}/${IMAGE}:${VERSION}"
|
||||
echo "Pushing ${FULL_IMAGE} ..."
|
||||
|
||||
docker tag "${DOCKER_IMAGE_NAME}:${VERSION}" "$FULL_IMAGE"
|
||||
echo "$DOCKER_PASSWORD" | docker login "$REGISTRY_HOST" -u "$DOCKER_USERNAME" --password-stdin
|
||||
docker push "$FULL_IMAGE"
|
||||
docker logout "$REGISTRY_HOST"
|
||||
|
||||
- name: Report status SUCCESS
|
||||
if: success()
|
||||
run: |
|
||||
CONTAINER_URL=""
|
||||
if [ -n "${DOCKER_UI_URL:-}" ] && [ -n "${VERSION:-}" ]; then
|
||||
CONTAINER_URL="${DOCKER_UI_URL}/${VERSION}"
|
||||
fi
|
||||
bash .ci/scripts/report-status.sh success "Docker build & push ${VERSION} OK" ci-docker-build-push "" "$CONTAINER_URL"
|
||||
|
||||
- name: Report status FAILURE
|
||||
if: failure()
|
||||
run: bash .ci/scripts/report-status.sh failure "Docker build & push ${VERSION} FAILED" ci-docker-build-push
|
||||
|
||||
tag-commit:
|
||||
runs-on: ubuntu-latest
|
||||
needs: [build-push]
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Create git tag
|
||||
env:
|
||||
GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }}
|
||||
SERVER_URL: ${{ gitea.server_url }}
|
||||
RUN_NUMBER: ${{ github.run_number }}
|
||||
SHA: ${{ github.sha }}
|
||||
run: |
|
||||
HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" -X POST \
|
||||
"$SERVER_URL/api/v1/repos/${{ github.repository }}/tags" \
|
||||
-H "Authorization: token $GITEA_TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "{\"tag_name\": \"${VERSION}\", \"message\": \"Build #$RUN_NUMBER\", \"target\": \"$SHA\"}")
|
||||
|
||||
if [ "$HTTP_CODE" = "201" ] || [ "$HTTP_CODE" = "409" ]; then
|
||||
exit 0
|
||||
else
|
||||
exit 1
|
||||
fi
|
||||
@@ -0,0 +1,64 @@
|
||||
name: Bats Tests
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
env_json:
|
||||
required: true
|
||||
type: string
|
||||
bats-image:
|
||||
required: true
|
||||
type: string
|
||||
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:
|
||||
bats:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
repository: niko/gitea-ci-library
|
||||
path: .ci
|
||||
|
||||
- name: Run bats tests
|
||||
id: bats-tests
|
||||
shell: bash
|
||||
run: |
|
||||
docker volume create bats-workspace
|
||||
tar c . | docker run --rm -i -v bats-workspace:/data alpine tar x -C /data
|
||||
mkdir -p "reports/${GITHUB_SHA:0:8}/bats"
|
||||
set +e
|
||||
docker run --rm \
|
||||
-v bats-workspace:/data \
|
||||
--entrypoint bash ${{ inputs.bats-image }} \
|
||||
-c 'apk add -q lsof python3 jq curl ruby && cd /data && gem install bashcov -v 3.3.0 2>&1 | tail -1 && bashcov -- bats tests/' \
|
||||
> "reports/${GITHUB_SHA:0:8}/bats/results.txt" 2>&1
|
||||
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
|
||||
bash .ci/.gitea/scripts/bats-report.sh "reports/${GITHUB_SHA:0:8}/bats"
|
||||
echo "BATS_EXIT=${BATS_EXIT}" >> "${GITHUB_ENV}"
|
||||
exit ${BATS_EXIT}
|
||||
|
||||
- name: Publish bats reports
|
||||
if: always()
|
||||
run: bash .ci/scripts/publish-git-pages.sh bats
|
||||
|
||||
- name: Report status
|
||||
if: always()
|
||||
run: |
|
||||
if [ "${BATS_EXIT}" = "0" ]; then
|
||||
bash .ci/scripts/report-status.sh success "Link to Bats reports" unit-tests bats
|
||||
else
|
||||
bash .ci/scripts/report-status.sh failure "Link to Bats reports" unit-tests bats
|
||||
fi
|
||||
@@ -0,0 +1,70 @@
|
||||
name: Cucumber Tests
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
env_json:
|
||||
required: true
|
||||
type: string
|
||||
cucumber-node-image:
|
||||
required: true
|
||||
type: string
|
||||
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:
|
||||
cucumber:
|
||||
runs-on: ubuntu-latest
|
||||
container:
|
||||
image: ${{ inputs.cucumber-node-image }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
repository: niko/gitea-ci-library
|
||||
path: .ci
|
||||
|
||||
- name: Run cucumber tests
|
||||
id: cucumber-tests
|
||||
shell: bash
|
||||
run: |
|
||||
apt-get update -qq && apt-get install -y -qq --no-install-recommends lsof jq
|
||||
npm install @cucumber/cucumber > /dev/null 2>&1
|
||||
mkdir -p "reports/${GITHUB_SHA:0:8}/cucumber"
|
||||
set +e
|
||||
npx cucumber-js \
|
||||
--format json:"reports/${GITHUB_SHA:0:8}/cucumber/report.json" \
|
||||
--format html:"reports/${GITHUB_SHA:0:8}/cucumber/index.html" 2>&1
|
||||
CUCUMBER_EXIT=$?
|
||||
echo "CUCUMBER_EXIT=${CUCUMBER_EXIT}" >> "${GITHUB_ENV}"
|
||||
exit ${CUCUMBER_EXIT}
|
||||
|
||||
- name: Publish cucumber reports
|
||||
if: always()
|
||||
run: bash .ci/scripts/publish-git-pages.sh cucumber
|
||||
|
||||
- name: Report status
|
||||
if: always()
|
||||
shell: bash
|
||||
run: |
|
||||
if [ "${CUCUMBER_EXIT}" = "0" ]; then
|
||||
if [ -f "reports/${GITHUB_SHA:0:8}/cucumber/index.html" ]; then
|
||||
bash .ci/scripts/report-status.sh success "Link to Cucumber reports" acc-tests cucumber
|
||||
else
|
||||
bash .ci/scripts/report-status.sh success "Link to Cucumber reports" acc-tests
|
||||
fi
|
||||
else
|
||||
if [ -f "reports/${GITHUB_SHA:0:8}/cucumber/index.html" ]; then
|
||||
bash .ci/scripts/report-status.sh failure "Link to Cucumber reports" acc-tests cucumber
|
||||
else
|
||||
bash .ci/scripts/report-status.sh failure "Link to Cucumber reports" acc-tests
|
||||
fi
|
||||
fi
|
||||
@@ -0,0 +1,41 @@
|
||||
name: CI Feature
|
||||
on:
|
||||
push:
|
||||
branches-ignore:
|
||||
- main
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
load-config:
|
||||
name: Load example-gitea-env.conf to pipeline env
|
||||
uses: niko/gitea-ci-library/.gitea/workflows/config-provider.yml@main
|
||||
secrets: inherit
|
||||
with:
|
||||
config_path: .gitea/workflows/example-gitea-env.conf
|
||||
|
||||
bats:
|
||||
name: Bats tests
|
||||
needs: [load-config]
|
||||
uses: niko/gitea-ci-library/.gitea/workflows/example-bats-tests.yml@main
|
||||
secrets: inherit
|
||||
with:
|
||||
env_json: ${{ needs.load-config.outputs.env_json }}
|
||||
bats-image: bats/bats:latest
|
||||
|
||||
cucumber:
|
||||
name: Cucumber tests
|
||||
needs: [load-config]
|
||||
uses: niko/gitea-ci-library/.gitea/workflows/example-cucumber-tests.yml@main
|
||||
secrets: inherit
|
||||
with:
|
||||
env_json: ${{ needs.load-config.outputs.env_json }}
|
||||
cucumber-node-image: node:22
|
||||
|
||||
report-summary:
|
||||
name: Report Summary
|
||||
needs: [load-config, bats, cucumber]
|
||||
if: always()
|
||||
uses: niko/gitea-ci-library/.gitea/workflows/example-report-summary.yml@main
|
||||
with:
|
||||
env_json: ${{ needs.load-config.outputs.env_json }}
|
||||
suites: bats cucumber
|
||||
@@ -0,0 +1,5 @@
|
||||
GITEA_API_URL=https://gitea.app.keskikuja.site
|
||||
GIT_PAGES_URL=https://ci-reports.helm-dev.keskikuja.site
|
||||
DOCKER_REGISTRY=gitea.app.keskikuja.site/niko
|
||||
DOCKER_IMAGE_NAME=gitea-ci-library-test-image
|
||||
DOCKER_UI_URL=https://gitea.app.keskikuja.site/niko/-/packages/container/gitea-ci-library-test-image
|
||||
@@ -0,0 +1,61 @@
|
||||
name: CI Main
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
load-config:
|
||||
name: Load example-gitea-env.conf to pipeline env
|
||||
uses: niko/gitea-ci-library/.gitea/workflows/config-provider.yml@main
|
||||
secrets: inherit
|
||||
with:
|
||||
config_path: .gitea/workflows/example-gitea-env.conf
|
||||
|
||||
check-version:
|
||||
name: Check existing artifact
|
||||
needs: [load-config]
|
||||
uses: niko/gitea-ci-library/.gitea/workflows/check-version.yml@main
|
||||
secrets: inherit
|
||||
with:
|
||||
env_json: ${{ needs.load-config.outputs.env_json }}
|
||||
|
||||
bats:
|
||||
name: Bats tests
|
||||
needs: [load-config, check-version]
|
||||
if: needs.check-version.outputs.artifact_exists != 'true'
|
||||
uses: niko/gitea-ci-library/.gitea/workflows/example-bats-tests.yml@main
|
||||
secrets: inherit
|
||||
with:
|
||||
env_json: ${{ needs.load-config.outputs.env_json }}
|
||||
bats-image: bats/bats:latest
|
||||
|
||||
cucumber:
|
||||
name: Cucumber tests
|
||||
needs: [load-config, check-version]
|
||||
if: needs.check-version.outputs.artifact_exists != 'true'
|
||||
uses: niko/gitea-ci-library/.gitea/workflows/example-cucumber-tests.yml@main
|
||||
secrets: inherit
|
||||
with:
|
||||
env_json: ${{ needs.load-config.outputs.env_json }}
|
||||
cucumber-node-image: node:22
|
||||
|
||||
build-push:
|
||||
name: Build & Push Docker
|
||||
needs: [load-config, check-version, bats, cucumber]
|
||||
if: needs.check-version.outputs.artifact_exists != 'true'
|
||||
uses: niko/gitea-ci-library/.gitea/workflows/docker-build-push.yml@main
|
||||
secrets: inherit
|
||||
with:
|
||||
env_json: ${{ needs.load-config.outputs.env_json }}
|
||||
version: ${{ needs.check-version.outputs.version }}
|
||||
|
||||
report-summary:
|
||||
name: Report Summary
|
||||
needs: [load-config, bats, cucumber]
|
||||
if: always()
|
||||
uses: niko/gitea-ci-library/.gitea/workflows/example-report-summary.yml@main
|
||||
with:
|
||||
env_json: ${{ needs.load-config.outputs.env_json }}
|
||||
suites: bats cucumber
|
||||
@@ -0,0 +1,34 @@
|
||||
name: Report Summary
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
env_json:
|
||||
required: true
|
||||
type: string
|
||||
suites:
|
||||
required: true
|
||||
type: string
|
||||
description: Space-separated suite names published to git-pages
|
||||
|
||||
env:
|
||||
GIT_PAGES_URL: ${{ fromJson(inputs.env_json).GIT_PAGES_URL }}
|
||||
|
||||
jobs:
|
||||
summary:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Generate report links
|
||||
shell: bash
|
||||
run: |
|
||||
SHA8="${GITHUB_SHA:0:8}"
|
||||
BASE="${GIT_PAGES_URL}/${GITHUB_REPOSITORY}/reports/${SHA8}"
|
||||
|
||||
{
|
||||
echo "## Test Reports"
|
||||
echo ""
|
||||
echo "| Suite | Report |"
|
||||
echo "|-------|--------|"
|
||||
for suite in ${{ inputs.suites }}; do
|
||||
echo "| ${suite} | [View report](${BASE}/${suite}/) |"
|
||||
done
|
||||
} >> "${GITHUB_STEP_SUMMARY}"
|
||||
@@ -1,2 +0,0 @@
|
||||
GITEA_API_URL=https://gitea.app.keskikuja.site
|
||||
GIT_PAGES_URL=https://ci-reports.helm-dev.keskikuja.site
|
||||
@@ -1,133 +0,0 @@
|
||||
name: Quality Gate
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
env_json:
|
||||
required: true
|
||||
type: string
|
||||
bats-image:
|
||||
required: true
|
||||
type: string
|
||||
cucumber-node-image:
|
||||
required: true
|
||||
type: string
|
||||
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:
|
||||
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:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
repository: niko/gitea-ci-library
|
||||
path: .ci
|
||||
|
||||
- name: Run bats tests
|
||||
id: bats-tests
|
||||
shell: bash
|
||||
run: |
|
||||
docker volume create bats-workspace
|
||||
tar c . | docker run --rm -i -v bats-workspace:/data alpine tar x -C /data
|
||||
mkdir -p "reports/${GITHUB_SHA:0:8}/bats"
|
||||
set +e
|
||||
docker run --rm \
|
||||
-v bats-workspace:/data \
|
||||
--entrypoint bash ${{ inputs.bats-image }} \
|
||||
-c 'apk add -q lsof python3 jq curl ruby && cd /data && gem install bashcov -v 3.3.0 2>&1 | tail -1 && bashcov -- bats tests/' \
|
||||
> "reports/${GITHUB_SHA:0:8}/bats/results.txt" 2>&1
|
||||
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
|
||||
bash .ci/.gitea/scripts/bats-report.sh "reports/${GITHUB_SHA:0:8}/bats"
|
||||
echo "BATS_EXIT=${BATS_EXIT}" >> "${GITHUB_ENV}"
|
||||
exit ${BATS_EXIT}
|
||||
|
||||
- name: Publish bats reports
|
||||
if: always()
|
||||
run: bash .ci/scripts/publish-git-pages.sh bats
|
||||
|
||||
- name: Set bats commit status
|
||||
if: always()
|
||||
run: |
|
||||
if [ "${BATS_EXIT}" = "0" ]; then
|
||||
bash .ci/scripts/report-status.sh success "Bats tests" ci-bats bats
|
||||
else
|
||||
bash .ci/scripts/report-status.sh failure "Bats tests FAILED" ci-bats bats
|
||||
fi
|
||||
|
||||
cucumber:
|
||||
runs-on: ubuntu-latest
|
||||
container:
|
||||
image: ${{ inputs.cucumber-node-image }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
repository: niko/gitea-ci-library
|
||||
path: .ci
|
||||
|
||||
- name: Run cucumber tests
|
||||
id: cucumber-tests
|
||||
shell: bash
|
||||
run: |
|
||||
apt-get update -qq && apt-get install -y -qq --no-install-recommends lsof jq
|
||||
npm install @cucumber/cucumber > /dev/null 2>&1
|
||||
mkdir -p "reports/${GITHUB_SHA:0:8}/cucumber"
|
||||
set +e
|
||||
npx cucumber-js \
|
||||
--format json:"reports/${GITHUB_SHA:0:8}/cucumber/report.json" \
|
||||
--format html:"reports/${GITHUB_SHA:0:8}/cucumber/index.html" 2>&1
|
||||
CUCUMBER_EXIT=$?
|
||||
|
||||
STATE="success"
|
||||
[ "${CUCUMBER_EXIT}" != "0" ] && STATE="failure"
|
||||
if [ -f "reports/${GITHUB_SHA:0:8}/cucumber/index.html" ]; then
|
||||
bash .ci/scripts/report-status.sh "${STATE}" "Cucumber tests" ci-cucumber cucumber
|
||||
else
|
||||
bash .ci/scripts/report-status.sh "${STATE}" "Cucumber tests" ci-cucumber
|
||||
fi
|
||||
|
||||
exit ${CUCUMBER_EXIT}
|
||||
|
||||
- name: Publish cucumber reports
|
||||
if: always()
|
||||
run: bash .ci/scripts/publish-git-pages.sh cucumber
|
||||
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
needs: [bats, cucumber]
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
repository: niko/gitea-ci-library
|
||||
path: .ci
|
||||
|
||||
- name: Generate report index
|
||||
run: bash .ci/.gitea/scripts/generate-report-index.sh
|
||||
|
||||
- name: Set build commit status
|
||||
run: bash .ci/scripts/report-status.sh success "Build complete" ci-build
|
||||
@@ -102,34 +102,56 @@ Act runner suorittaa Gitea Actions workflowt. **IaC-lähde:** alla oleva Helm-sn
|
||||
klusterin totuus — muutokset vain snippetiin, sitten `helm upgrade --install` (ei käsin muokattuja
|
||||
arvoja klusterissa).
|
||||
|
||||
> HUOM! Gitea ei ole vielä kunnolla stabiilissa tilassa, ja chart default dind sekä runner versiot ovat tätä tehdessä olleet bugiset. Niistä on olemassa uudemmat versiot, mutta eivät ole chartissa. Tätyy seurata ja päivittää tarpeen tulle.
|
||||
|
||||
Asennus Kubernetes-klusteriin Helm chartilla:
|
||||
|
||||
### 1. Rekisteröintitoken
|
||||
### 1. Rekisteröi token
|
||||
|
||||
Hae token Giteasta:
|
||||
- **Organization-taso:** Org → Settings → Actions → Runners → Create new runner
|
||||
- **Globaali (site admin):** Site Admin → Actions → Runners → Create new runner
|
||||
|
||||
### 2. Asenna runner
|
||||
### 2. variables
|
||||
|
||||
```bash
|
||||
GITEA_URL="https://<gitea-server-url>"
|
||||
GITEA_ACTIONS_TOKEN="<registration-token>"
|
||||
GITEA_ACTIONS_NAMESPACE="gitea-actions"
|
||||
```
|
||||
|
||||
helm repo add gitea https://dl.gitea.com/charts
|
||||
helm repo update
|
||||
### 3. Tee secret vain init install yhteydessä
|
||||
|
||||
```bash
|
||||
kubectl create secret generic act-runner-token \
|
||||
--from-literal=token="$GITEA_ACTIONS_TOKEN" \
|
||||
--namespace "$GITEA_ACTIONS_NAMESPACE" \
|
||||
--dry-run=client -o yaml | kubectl apply -f -
|
||||
|
||||
```
|
||||
|
||||
### 4. Helm install / upgrade
|
||||
|
||||
Menee samalla komennolla.
|
||||
|
||||
> Muista asettaa variables ennen ajoa.
|
||||
|
||||
Päivittää olemassa olevan installaation, käyttää olemassa olevaa secret
|
||||
ja sitä kautta Gitea ei tarvitse päivityksessä mitään temppuja.
|
||||
|
||||
Päivityksen jälkeen muista tappaa pod (käynnistyy automaattisesti uudelleen), että lataa varmasti kaikki uudesta. Sillä ConfigMap tms eivät lataudu
|
||||
mikäli pod jatkaa ajamista.
|
||||
|
||||
```bash
|
||||
helm repo add gitea https://dl.gitea.com/charts
|
||||
helm repo update
|
||||
|
||||
helm upgrade --install act-runner gitea/actions \
|
||||
--set enabled=true \
|
||||
--set giteaRootURL="$GITEA_URL" \
|
||||
--set existingSecret=act-runner-token \
|
||||
--set existingSecretKey=token \
|
||||
--set statefulset.runner.tag=1.0.8 \
|
||||
--set statefulset.dind.tag=29.5.2-dind \
|
||||
--set-string 'statefulset.runner.config=log:
|
||||
level: info
|
||||
|
||||
@@ -6,8 +6,8 @@ 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/workflows/` | Sekoitettu | Providerin reusable workflowt + consumerin example-pipeline |
|
||||
| `.gitea/workflows/example-gitea-env.conf` | Consumer | KEY=VALUE config |
|
||||
| `.gitea/scripts/` | Consumer | Consumer-skriptit |
|
||||
| `scripts/` | Provider | Providerin sisäiset työkalut |
|
||||
|
||||
@@ -30,12 +30,12 @@ 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.
|
||||
`check-version.yml`, `docker-build-push.yml`) ovat samassa `.gitea/workflows/`-kansiossa
|
||||
consumerin esimerkkipipeline-tiedostojen (`example-*`) kanssa.
|
||||
|
||||
Erottelu on nimessä ja dokumentaatiossa, ei kansiorakenteessa:
|
||||
- `config-provider.yml`, `build-feature.yml` — providerin tarjoamia
|
||||
- `ci.yml` — consumerin omistamia
|
||||
- `config-provider.yml`, `check-version.yml`, `docker-build-push.yml` — providerin tarjoamia
|
||||
- `example-feature.yml`, `example-main.yml`, `example-*.yml` — consumer-esimerkkejä
|
||||
|
||||
## Providerin `scripts/` (juuressa)
|
||||
|
||||
@@ -52,7 +52,7 @@ 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 `.gitea/workflows/example-gitea-env.conf`
|
||||
|
||||
Consumerin konfiguraatiotiedosto. Providerin `config-provider.yml`
|
||||
lukee tämän ja muuntaa JSONiksi, mutta consumer omistaa sisällön.
|
||||
@@ -61,8 +61,7 @@ lukee tämän ja muuntaa JSONiksi, mutta consumer omistaa sisällön.
|
||||
|
||||
- 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öä
|
||||
- Consumer voi muuttaa `example-*.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)
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
# 7. Statusraportoinnin pattern
|
||||
|
||||
## Päätös
|
||||
|
||||
Gitea Actionsin natiivi job-status on ensisijainen. Commit-status API:a
|
||||
(`report-status.sh`) käytetään **vain** kun työvaihe tuottaa ulkoisen linkin
|
||||
(testiraportti, Docker registry), jota natiivistaatus ei tue.
|
||||
|
||||
### Tool-jobit (validate, check-version, tag-commit)
|
||||
|
||||
Ei API-kutsuja. Luotetaan Gitean omaan job-statukseen.
|
||||
|
||||
```yaml
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Do work
|
||||
run: do-something
|
||||
```
|
||||
|
||||
### Test-jobit (bats, cucumber)
|
||||
|
||||
API:a käytetään raporttilinkin upottamiseksi commit-näkymään.
|
||||
|
||||
```
|
||||
testit → publish (always) → status (always, exit-koodin mukaan)
|
||||
```
|
||||
|
||||
```yaml
|
||||
- name: Run tests
|
||||
shell: bash
|
||||
run: |
|
||||
run-tests
|
||||
EXIT=$?
|
||||
echo "EXIT=${EXIT}" >> "${GITHUB_ENV}"
|
||||
exit ${EXIT}
|
||||
|
||||
- name: Publish reports
|
||||
if: always()
|
||||
run: bash .ci/scripts/publish-git-pages.sh bats
|
||||
|
||||
- name: Report status
|
||||
if: always()
|
||||
shell: bash
|
||||
run: |
|
||||
if [ "${EXIT}" = "0" ]; then
|
||||
bash .ci/scripts/report-status.sh success "Link to Bats reports" unit-tests bats
|
||||
else
|
||||
bash .ci/scripts/report-status.sh failure "Link to Bats reports" unit-tests bats
|
||||
fi
|
||||
```
|
||||
|
||||
### Build & push -jobit (docker-build-push)
|
||||
|
||||
API:a käytetään Docker registry -linkin upottamiseksi.
|
||||
|
||||
```
|
||||
build → push → SUCCESS (registry-linkillä) / FAILURE
|
||||
```
|
||||
|
||||
## Periaatteet
|
||||
|
||||
1. Gitea Actionsin natiivi job-status on ensisijainen — myös PENDING/Running-tila
|
||||
tulee natiivisti. API:a käytetään vain custom-linkin tarpeeseen (ADR 0004).
|
||||
2. `run`-komennon on nostettava virhe ylös — oli kyse tool-callista tai
|
||||
testivirheestä (ADR 0008).
|
||||
3. Test-jobit käyttävät `if: always()` publish- ja status-stepeissä — raportti
|
||||
julkaistaan ja status asetetaan aina, riippumatta testin lopputuloksesta.
|
||||
4. Testiraportit julkaistaan myös virhetilanteessa, mikäli ne ovat syntyneet.
|
||||
5. Commit-statuksen duplikaatio natiivijob-statuksen kanssa hyväksytään
|
||||
testijobeille — se on ainoa mekanismi upottaa raporttilinkki commit-näkymään.
|
||||
6. Tool-jobit eivät käytä API:a lainkaan — ne luottavat Gitean natiiviin
|
||||
job-statukseen.
|
||||
|
||||
## Tausta
|
||||
|
||||
Aiemmin commit-status API:a käytettiin jokaisessa työvaiheessa, myös niissä
|
||||
joilla ei ollut raporttia linkitettäväksi (validate, check-version, tag-commit).
|
||||
Tämä tuotti duplikaatiota: Gitea näytti sekä natiivin `CI Main / Validate CI config
|
||||
Successful` että API-statuksen `ci-validate CI config valid`. Kehittäjälle
|
||||
molemmat kertoivat saman asian.
|
||||
|
||||
Käytännön pakko kuitenkin pakottaa API:n käyttöön testijobeissa: ilman
|
||||
raporttilinkkiä kukaan ei löydä testituloksia. Gitean natiivi job-status
|
||||
linkittää aina jobin lokiin — ei ulkoiseen raporttiin. Tämä on paras
|
||||
saatavilla oleva kompromissi.
|
||||
@@ -0,0 +1,73 @@
|
||||
# 8. Exit code — ainoa onnistumisen mittari
|
||||
|
||||
## Päätös
|
||||
|
||||
Jokaisen `run`-stepin on nostettava virheellinen exit-koodi ylös sellaisenaan.
|
||||
Exit-koodia ei saa "syödä" missään tilanteessa. Onnistumisen ja epäonnistumisen
|
||||
päättely tapahtuu **ainoastaan** exit-koodin perusteella — ei tiedostojen
|
||||
olemassaolon, stdout-tulosteen tai minkään muun heuristiikan perusteella.
|
||||
|
||||
## Periaatteet
|
||||
|
||||
1. Exit-koodi on ainoa totuus. `0` = onnistui, kaikki muut = epäonnistui.
|
||||
2. Exit-koodia ei saa syödä. Pipe (`|`) viimeisenä komentona `tee`:hen syö
|
||||
exit-koodin — `docker run … | tee file` palauttaa aina 0.
|
||||
3. Data transfer -pipet ovat sallittuja (`tar c . | docker run … tar x`),
|
||||
koska niiden exit-koodilla ei ole semanttista merkitystä.
|
||||
4. Testien tai työkalujen ajaminen ei saa päättyä pipeen.
|
||||
5. `set -o pipefail` ei ole riittävä suojaus — PIPESTATUS resetoituu herkästi.
|
||||
|
||||
## Sallitut patternit
|
||||
|
||||
```yaml
|
||||
# Oikein: suora ajo, exit koodi $?:iin
|
||||
- name: Do work
|
||||
run: |
|
||||
some-command
|
||||
EXIT=$?
|
||||
echo "EXIT=${EXIT}" >> "${GITHUB_ENV}"
|
||||
exit ${EXIT}
|
||||
|
||||
# Oikein: stdout talteen ilman pipeä
|
||||
- name: Do work
|
||||
run: |
|
||||
some-command > results.txt 2>&1
|
||||
EXIT=$?
|
||||
echo "EXIT=${EXIT}" >> "${GITHUB_ENV}"
|
||||
exit ${EXIT}
|
||||
|
||||
# Oikein: docker run ilman pipeä
|
||||
- name: Run in container
|
||||
run: |
|
||||
docker run --rm image command > output.txt 2>&1
|
||||
EXIT=$?
|
||||
exit ${EXIT}
|
||||
```
|
||||
|
||||
## Kielletyt patternit
|
||||
|
||||
```yaml
|
||||
# Väärin: pipe syö exit-koodin
|
||||
- run: docker run … | tee results.txt
|
||||
|
||||
# Väärin: pipe syö exit-koodin
|
||||
- run: tar … | docker … | tee file
|
||||
|
||||
# Väärin: onnistumisen päättely tiedoston olemassaolosta
|
||||
- run: |
|
||||
some-command || true
|
||||
[ -f success.txt ] && exit 0 || exit 1
|
||||
```
|
||||
|
||||
## Tausta
|
||||
|
||||
Gitea Actionsissa `run`-stepin tila määräytyy viimeisen komennon exit-koodista.
|
||||
Pipe (`|`) asettaa `$?`:ksi viimeisen komennon tuloksen — jos viimeinen komento
|
||||
on `tee`, tulos on aina 0 riippumatta siitä mitä aiemmat komennot palauttivat.
|
||||
|
||||
Tämä on aiheuttanut tuotannossa tilanteita, joissa testit feilasivat mutta jobi
|
||||
näytti vihreää, koska `tee` söi exit-koodin. Virhe havaittiin vasta kun raportteja
|
||||
alettiin lukea manuaalisesti — commit-status valehteli.
|
||||
|
||||
Ratkaisu on yksiselitteinen: exit-koodi talteen `$?`-muuttujaan ennen kuin mikään
|
||||
muu komento ehtii muuttaa sitä, ja stepin viimeinen komento on aina `exit ${EXIT}`.
|
||||
+40
-62
@@ -1,6 +1,6 @@
|
||||
# AI Context: Gitea Actions CI -kirjasto
|
||||
|
||||
**Updated**: 2026-06-12 (POC-vaihe, suunniteltu uudelleenkirjoitus)
|
||||
**Updated**: 2026-06-15 (siivottu, provider/consumer-erottelu valmis)
|
||||
|
||||
## Project Overview
|
||||
Gitea Actions reusable workflow -kirjasto mikropalveluiden build-, testaus-,
|
||||
@@ -8,90 +8,68 @@ raportointi-, deployment- ja test flow -prosessien orkestrointiin. Korvaa
|
||||
`ci-jenkins-library`:n Gitea-natiivilla toteutuksella. Mikropalvelut
|
||||
käyttävät kirjastoa `uses:`-direktiivillä.
|
||||
|
||||
POC on valmis: raporttien julkaisu git-pagesiin ja commit-status linkillä
|
||||
toimii.
|
||||
|
||||
## Monorepo: kaksi erillistä kokonaisuutta
|
||||
|
||||
Tämä repo on käytännössä monorepo, jossa on kaksi itsenäistä osaa:
|
||||
|
||||
### 1. Juuri (`gitea-ci-library`)
|
||||
Provider-kirjasto: reusable workflowt, scriptit, ADRt, dokumentaatio.
|
||||
Consumer kutsuu `build-feature.yml`-workflowa `uses:`-direktiivillä.
|
||||
Consumer kutsuu provider-workflowta `uses:`-direktiivillä.
|
||||
|
||||
### 2. `git-pages/` — oma kokonaisuus
|
||||
Helm-chartti Codeberg git-pagesille. Täysin itsenäinen — oma dokumentaatio,
|
||||
omat tekniset valinnat, oma design-rationale. Kohdeltava kuten se olisi jo
|
||||
oma reponsa: kaikki git-pages-spesifi tieto kuuluu `git-pages/docs/`- alle,
|
||||
ei juuren `docs/`-kansioon.
|
||||
|
||||
### Rajapinta juuren ja git-pagesin välillä
|
||||
|
||||
Ohut ja yksiselitteinen:
|
||||
|
||||
```
|
||||
scripts/publish-git-pages.sh <report-dir>
|
||||
→ PATCH tar osoitteeseen GIT_PAGES_URL
|
||||
→ palauttaa BASE URL:n
|
||||
|
||||
git-pages tarjoaa:
|
||||
- HTTP endpoint (GET/PATCH/PUT)
|
||||
- retention (automaattinen)
|
||||
- TLS, BasicAuth (Traefik)
|
||||
```
|
||||
|
||||
Juuri ei tiedä git-pagesin sisäisestä toiminnasta (storage v2, .index,
|
||||
blob-arkkitehtuuri). Git-pages ei tiedä workflowista, scripteistä tai
|
||||
provider-logiikasta.
|
||||
|
||||
## Architecture (POC-tila)
|
||||
- **Provider & Consumer -malli**: `build-feature.yml` on lukittu rajapinta.
|
||||
ADR 0005.
|
||||
- **Raporttien hostaus**: git-pages Helm-chartilla (`git-pages/`), `GIT_PAGES_URL` määrittää perusosoitteen.
|
||||
- **Retention**: sidecar samassa podissa, HTTP API localhost:3000,
|
||||
Gitea API branch-check.
|
||||
- **Commit-status**: Gitea Actions näyttää automaattisesti. API vain
|
||||
custom-linkkiin. ADR 0004.
|
||||
- **Julkaisu**: `publish-git-pages.sh` → PATCH tar git-pagesiin.
|
||||
omat tekniset valinnat, oma design-rationale. Kaikki git-pages-spesifi tieto
|
||||
kuuluu `git-pages/docs/`-alle, ei juuren `docs/`-kansioon.
|
||||
|
||||
## Repository Structure
|
||||
|
||||
| Path | Purpose |
|
||||
|---|---|
|
||||
| `.gitea/workflows/` | Reusable workflowt (`build-feature.yml`, `config-provider.yml`) |
|
||||
| `scripts/` | `publish-git-pages.sh`, `report-status.sh`, `dispatch-workflow.sh` |
|
||||
| **`git-pages/`** | **Oma kokonaisuus: Helm-chartti + docs + retention** |
|
||||
| `docs/` | Root-tason arkkitehtuuri, ADRt (0001–0005) |
|
||||
| `.gitea/workflows/config-provider.yml` | Provider: lataa + validoi config-tiedoston, tuottaa `env_json` |
|
||||
| `.gitea/workflows/check-version.yml` | Provider: tarkistaa onko commitille jo artifact, laskee version |
|
||||
| `.gitea/workflows/docker-build-push.yml` | Provider: buildaa + puskea Docker-imagen, tagittaa commitin |
|
||||
| `.gitea/workflows/example-*` | **Consumer-esimerkki**: tämän repon oma CI (dogfood) |
|
||||
| `scripts/` | Provider-skriptit: `report-status.sh`, `publish-git-pages.sh`, `ci-validate.sh` |
|
||||
| `.gitea/scripts/` | **Consumer-skriptit**: `bats-coverage.sh`, `bats-report.sh` |
|
||||
| `docs/` | Arkkitehtuuri, ADRt (0004–0008) |
|
||||
| `docs/adr/` | Architecture Decision Records |
|
||||
| `git-pages/` | Raporttien hostaus (Helm-chartti) |
|
||||
| `tests/` | Bats-testit skripteille |
|
||||
| `.gitea/workflows/ci.yml` | Dogfood — kutsuu `build-feature.yml`:a |
|
||||
|
||||
**Tarkemmat git-pages-asiat:** `git-pages/docs/` (implementation-notes,
|
||||
architecture, design-rationale, secrets, tech-stack).
|
||||
### Provider workflowt (3 kpl)
|
||||
|
||||
| Workflow | Input | Output | Kuvaus |
|
||||
|---|---|---|---|
|
||||
| `config-provider.yml` | `config_path` | `env_json`, `config_path` | Validoi ja jäsentää `.conf` → JSON. Sama kutsu hoitaa validoinnin. |
|
||||
| `check-version.yml` | `env_json` | `artifact_exists`, `version` | Tarkistaa git-tagit ja `package.json`:n, laskee seuraavan version. Vain main-haarassa. |
|
||||
| `docker-build-push.yml` | `env_json`, `version` | — | Buildaa Docker-imagen, puskea rekisteriin, tagittaa commitin. |
|
||||
|
||||
### Example-tiedostot (consumer-referenssi)
|
||||
|
||||
| Tiedosto | Laukaisin | Flow |
|
||||
|---|---|---|
|
||||
| `example-feature.yml` | push [ei main] | load-config → bats + cucumber → report-summary |
|
||||
| `example-main.yml` | push [main] | load-config → check-version → bats + cucumber → report-summary → docker-build-push |
|
||||
| `example-bats-tests.yml` | workflow_call | Unit-testit Batsilla, raportit git-pagesiin, status linkillä |
|
||||
| `example-cucumber-tests.yml` | workflow_call | Hyväksymätestit Cucumberilla, raportit git-pagesiin, status linkillä |
|
||||
| `example-report-summary.yml` | workflow_call | `GITHUB_STEP_SUMMARY`-taulukko raporttilinkeillä (Gitea 1.27+) |
|
||||
| `example-gitea-env.conf` | — | KEY=VALUE config tälle repolle |
|
||||
|
||||
## Key Technical Decisions
|
||||
- **Provider & Consumer**: `build-feature.yml` lukittu rajapinta, muu koodi
|
||||
vapaasti muutettavissa
|
||||
- **Vain Gitea, vain reusable workflowt**: ei custom actioneita, ei
|
||||
multi-platform
|
||||
- **Raportit git-pagesissa**: HTML selailtavissa, retention automaattinen
|
||||
- **Git-pages omana kokonaisuutena**: voi erottaa omaksi repokseen
|
||||
tulevaisuudessa
|
||||
|
||||
## Tech Stack (POC)
|
||||
- **Runtime:** Bash, curl, jq, python3 (retention whiteout)
|
||||
- **Alusta:** Gitea Actions, Gitea act runner
|
||||
- **Hostaus:** git-pages 0.9.1 (Codeberg), Traefik, cert-manager
|
||||
- **Integraatiot:** Gitea REST API, Gitea Packages
|
||||
- **Provider & Consumer -malli**: `example-*`-tiedostot ovat consumer-esimerkkejä, provider-workflowt reusableja. ADR 0005.
|
||||
- **Vain Gitea, vain reusable workflowt**: ei custom actioneita, ei multi-platform
|
||||
- **Commit-status API vain raporttilinkeille**: Tool-jobit luottavat natiiviin. Test-jobit käyttävät API:a koska se on ainoa tapa upottaa raporttilinkki. ADR 0004, 0007.
|
||||
- **Exit-koodi on ainoa onnistumisen mittari**: Ei pipeä, ei tiedostoheuristiikkaa. ADR 0008.
|
||||
- **Raportit git-pagesissa**: HTML selailtavissa, retention automaattinen
|
||||
- **GITHUB_STEP_SUMMARY**: Summary-näkymä raporttilinkeille Gitea 1.27:ssä (forward-compat)
|
||||
|
||||
## Common Commands
|
||||
- Helm-asennus: `helm upgrade --install git-pages ./git-pages -n <ns> -f <values>`
|
||||
- Julkaisu: `bash scripts/publish-git-pages.sh <report-dir>`
|
||||
- Status: `bash scripts/report-status.sh <state> <desc> <url> <context>`
|
||||
- Status: `bash scripts/report-status.sh <state> <desc> <context> [suite] [url]`
|
||||
|
||||
## What NOT to Do
|
||||
- Älä lisää tukea muille Git-alustoille
|
||||
- Älä lisää Docker custom actioneita ilman pakottavaa syytä
|
||||
- Älä kirjoita git-pages-spesifiä tietoa juuren `docs/`-kansioon —
|
||||
kuuluu `git-pages/docs/`-alle
|
||||
- Älä POSTaa commit-status APIin jokaiselle vaiheelle — natiivi riittää
|
||||
- Älä kirjoita git-pages-spesifiä tietoa juuren `docs/`-kansioon
|
||||
- Älä käytä commit-status API:a jollei ole raporttia linkitettäväksi (ADR 0007)
|
||||
- Älä käytä pipeä `run`-komennon viimeisenä — se syö exit-koodin (ADR 0008)
|
||||
|
||||
+37
-17
@@ -1,7 +1,6 @@
|
||||
# Architecture — Gitea Actions CI -kirjasto
|
||||
|
||||
> ⚠️ POC-vaihe. Tämä dokumentti kuvaa suunniteltua arkkitehtuuria.
|
||||
> Normatiivinen lähde: ADR 0004, ADR 0005, `docs/design-rationale.md`.
|
||||
> Normatiivinen lähde: ADR 0004, 0005, 0006, 0007, 0008.
|
||||
|
||||
---
|
||||
|
||||
@@ -18,31 +17,52 @@ Kirjasto on Gitea-spesifi. Raportit hallinnoidaan git-pages Helm-chartilla
|
||||
|
||||
| Rooli | Kuvaus |
|
||||
|-------|--------|
|
||||
| **Provider** | `gitea-ci-library` — tarjoaa `build-feature.yml` (lukittu rajapinta) sekä scriptit |
|
||||
| **Consumer** | Mikropalveluprojekti — kutsuu `uses:`-direktiivillä, omistaa pipeline-logiikan |
|
||||
| **Provider** | `gitea-ci-library` — tarjoaa reusable workflowt (`config-provider.yml`, `check-version.yml`, `docker-build-push.yml`) ja scriptit |
|
||||
| **Consumer** | Mikropalveluprojekti — kutsuu `uses:`-direktiivillä, omistaa pipeline-logiikan. Tämän repon oma toteutus: `example-*`-tiedostot |
|
||||
|
||||
Tarkemmin: ADR 0005.
|
||||
|
||||
## Komponentit (POC)
|
||||
## Komponentit
|
||||
|
||||
| Komponentti | Tila |
|
||||
|-------------|------|
|
||||
| `build-feature.yml` | Toimii. Ainoa reusable workflow. |
|
||||
| `publish-git-pages.sh` | Toimii. PATCH tar git-pagesiin. |
|
||||
| `report-status.sh` | Toimii. POSTaa commit-status (vain custom-linkkiin). |
|
||||
| `dispatch-workflow.sh` | Toimii. Dispatchee workflown ja pollaa valmistumista. |
|
||||
| `git-pages/` | Helm-chartti raporttien hostaukseen. Oma kokonaisuus, tarkemmin: `git-pages/docs/`. |
|
||||
| Komponentti | Tyyppi | Kuvaus |
|
||||
|---|---|---|
|
||||
| `config-provider.yml` | Provider | Lataa + validoi `.conf`-tiedoston, tuottaa `env_json` |
|
||||
| `check-version.yml` | Provider | Tarkistaa git-tagit, laskee version, palauttaa `artifact_exists` + `version` |
|
||||
| `docker-build-push.yml` | Provider | Buildaa Docker-imagen, puskea rekisteriin, tagittaa commitin |
|
||||
| `example-feature.yml` | Consumer | Feature-haaran CI: load-config → bats + cucumber → summary |
|
||||
| `example-main.yml` | Consumer | Main-haaran CI: load-config → check-version → bats + cucumber → summary → docker |
|
||||
| `example-bats-tests.yml` | Consumer | Unit-testit Batsilla |
|
||||
| `example-cucumber-tests.yml` | Consumer | Hyväksymätestit Cucumberilla |
|
||||
| `example-report-summary.yml` | Consumer | `GITHUB_STEP_SUMMARY`-taulukko (Gitea 1.27+) |
|
||||
| `publish-git-pages.sh` | Provider-skripti | PATCH tar git-pagesiin |
|
||||
| `report-status.sh` | Provider-skripti | POSTaa commit-status (vain custom-linkkiin) |
|
||||
| `ci-validate.sh` | Provider-skripti | Validoi `.conf`-tiedoston ja tarkistaa secretit |
|
||||
| `dispatch-workflow.sh` | Provider-skripti | Dispatchee workflown ja pollaa valmistumista |
|
||||
| `git-pages/` | Infra | Helm-chartti raporttien hostaukseen. Oma kokonaisuus |
|
||||
|
||||
## Statusraportointi
|
||||
|
||||
| Job-tyyppi | Mekanismi | Syy |
|
||||
|---|---|---|
|
||||
| Tool-jobit | Vain Gitea natiivi job-status | Ei raporttia linkitettäväksi |
|
||||
| Test-jobit | Commit-status API linkillä | Ainoa tapa upottaa raporttilinkki commit-näkymään |
|
||||
| Docker-build-push | Commit-status API linkillä | Linkki Docker registryyn |
|
||||
|
||||
Tarkemmin: ADR 0004, 0007.
|
||||
|
||||
## Ulkoiset palvelut
|
||||
|
||||
| Palvelu | Rooli |
|
||||
|---------|-------|
|
||||
| **Gitea REST API** | Commit-status, workflow-dispatch, run-pollaus |
|
||||
| **Gitea Packages** | Docker-imagen säilytys |
|
||||
| **git-pages** | Raporttien hostaus |
|
||||
|---|---|
|
||||
| Gitea REST API | Commit-status (vain custom-linkit), git-tagit |
|
||||
| Gitea Packages | Docker-imagen säilytys |
|
||||
| git-pages | Raporttien hostaus |
|
||||
|
||||
## Arkkitehtuuriset rajoitteet
|
||||
|
||||
- `build-feature.yml` on ainoa consumerin kutsuma rajapinta (ADR 0005)
|
||||
- Provider-workflowt ovat reusableja (`workflow_call`), consumer omistaa orkestroinnin
|
||||
- Gitea Actionsin natiivi commit-status on ensisijainen (ADR 0004)
|
||||
- API:a käytetään vain custom-linkkeihin (ADR 0007)
|
||||
- Exit-koodi on ainoa onnistumisen mittari — ei pipeä (ADR 0008)
|
||||
- Raportit ovat julkisia URL:lla (osoite tunnettava)
|
||||
- Consumer-skriptit `.gitea/scripts/`-alla, provider-skriptit `scripts/`-alla (ADR 0006)
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
**⚠️ STATUS: ALERT DRAFT** — Ei ole validoitu. Voi sisältää virheellisiä tai puutteellisia käytäntöjä.
|
||||
**⚠️ STATUS: OSITTAIN VANHENTUNUT** — Statusraportointi (7) ja exit-koodit (8)
|
||||
on formalisoitu ADR:iin 0007 ja 0008. Loput osiot validioitu POC-ajossa.
|
||||
|
||||
|
||||
# CI Pipeline Practices
|
||||
|
||||
+72
-336
@@ -1,390 +1,126 @@
|
||||
# Reusable workflowt
|
||||
|
||||
> ⚠️ **POC-vaihe.** Toteutettu: `quality-gate.yml`. Suunnitteilla:
|
||||
> `ci-master.yml`, `deploy.yml`, `test.yml`.
|
||||
> Provider-workflowt tarjoavat ydintoiminnallisuuden. Consumer kokoaa ne
|
||||
> haluamakseen pipelineksi. Esimerkkitoteutus: `example-*`-tiedostot.
|
||||
|
||||
---
|
||||
|
||||
## Yhteiset konventiot
|
||||
|
||||
Kaikki workflowt:
|
||||
- Käyttävät `concurrency:`-ryhmää estämään saman branchin rinnakkaiset ajot (vastaa Jenkins `disableConcurrentBuilds()`)
|
||||
- Lukevat konfiguraation `ci-flow-values.yaml`:sta
|
||||
- Raportoivat jokaisen vaiheen Gitea-commitin statukseen `report-status.sh`:lla
|
||||
- Käyttävät projektilta saatuja `with:`-parametreja konttien määrittelyyn (kirjasto ei pakota konttiversioita)
|
||||
- Käyttävät `concurrency:`-ryhmää estämään saman branchin rinnakkaiset ajot
|
||||
- Provider-workflowt lukevat konfiguraation inputtina (`env_json`)
|
||||
- Statusraportointi: tool-jobit natiivilla, test-jobit API:lla raporttilinkin takia (ADR 0007)
|
||||
- Exit-koodi aina ylös, ei pipeä (ADR 0008)
|
||||
|
||||
---
|
||||
|
||||
## `quality-gate.yml` — Merge-portti
|
||||
## Provider-workflowt
|
||||
|
||||
**Trigger:** `workflow_call` — consumer kutsuu `uses:`-direktiivillä
|
||||
### `config-provider.yml` — Konfiguraation lataus ja validointi
|
||||
|
||||
**Rooli:** Laatuportti, joka ajetaan branch protection -sääntönä ennen PR:n
|
||||
sulkemista mainiin. Pipeline on ajettava (`run > 1`) eikä yhtään jobia
|
||||
saa failata.
|
||||
**Trigger:** `workflow_call`
|
||||
|
||||
**Provider-Consumer-malli (ADR 0005):** Provider tarjoaa orkestroinnin
|
||||
(validointi, raporttien julkaisu, commit-status). Consumer omistaa
|
||||
pipeline-stepit — valitsee testityökalunsa, mahdolliset laatu- ja
|
||||
tietoturva-analyy sit sekä niiden järjestyksen. Alla oleva esimerkki
|
||||
kuvaa tyypillistä Java-mikropalvelua Mavenilla; consumer korvaa nämä
|
||||
omalla tekniikkapinollaan.
|
||||
**Inputs:**
|
||||
|
||||
### Inputs (providerin rajapinta)
|
||||
| Parametri | Pakollinen | Kuvaus |
|
||||
|-----------|------------|--------|
|
||||
| `config_path` | Kyllä | Polku `.conf`-tiedostoon |
|
||||
|
||||
| Parametri | Pakollinen | Tyyppi | Kuvaus |
|
||||
|-----------|------------|--------|--------|
|
||||
| `env_json` | Kyllä | string | JSON-muotoiset ympäristömuuttujat (`GITEA_API_URL`, `GIT_PAGES_URL`) |
|
||||
| `*` | — | — | Consumer lisää omat parametrinsa (`maven-image`, `docker-image`, jne.) |
|
||||
|
||||
### Secrets
|
||||
**Secrets:**
|
||||
|
||||
| Secret | Pakollinen | Kuvaus |
|
||||
|--------|------------|--------|
|
||||
| `GITEA_TOKEN` | Kyllä | Gitea API-kutsuihin (commit-status) |
|
||||
| `GIT_PAGES_PUBLISH_TOKEN` | Kyllä | Raporttien julkaisuun git-pagesiin |
|
||||
| `GITEA_TOKEN` | Kyllä | Validointia varten |
|
||||
| `GIT_PAGES_PUBLISH_TOKEN` | Kyllä | Validointia varten |
|
||||
|
||||
### Steppi-kaavio (Java-esimerkki)
|
||||
**Outputs:**
|
||||
|
||||
```mermaid
|
||||
%%{init: {'theme': 'base', 'flowchart': {'arrowheadScale': 2}}}%%
|
||||
flowchart TD
|
||||
VAL["validate
|
||||
provider: tarkista
|
||||
CI-konfiguraatio"] --> TEST["test
|
||||
consumer: mvn test
|
||||
→ testiraportit + coverage"]
|
||||
| Output | Kuvaus |
|
||||
|--------|--------|
|
||||
| `env_json` | JSON-muotoiset ympäristömuuttujat |
|
||||
| `config_path` | Sama polku takaisin (DRY downstream-käyttöön) |
|
||||
|
||||
VAL --> AI_SCAN["ai-scan \[optional\]
|
||||
consumer: tietoturva-
|
||||
tai laatu-skannaus"]
|
||||
|
||||
TEST --> SONAR["sonarqube \[optional\]
|
||||
consumer: mvn sonar:sonar
|
||||
→ laatupoikkeamat"]
|
||||
TEST --> PUB["publish-reports
|
||||
provider: vie raportit
|
||||
git-pagesiin"]
|
||||
|
||||
SONAR --> PUB
|
||||
AI_SCAN --> PUB
|
||||
|
||||
PUB --> STATUS["commit-status
|
||||
provider: aseta status
|
||||
linkillä raporttiin"]
|
||||
|
||||
FAIL("fail") -. "if: always()" .-> PUB
|
||||
|
||||
style VAL fill:#2563eb,color:#ffffff
|
||||
style TEST fill:#059669,color:#ffffff
|
||||
style SONAR fill:#7c3aed,color:#ffffff
|
||||
style AI_SCAN fill:#7c3aed,color:#ffffff
|
||||
style PUB fill:#0891b2,color:#ffffff
|
||||
style STATUS fill:#f59e0b,color:#111827
|
||||
style FAIL fill:#dc2626,color:#ffffff
|
||||
linkStyle default stroke:#9ca3af,stroke-width:3px
|
||||
**Steppi-kaavio:**
|
||||
```
|
||||
checkout → validate CI config → parse conf to JSON
|
||||
```
|
||||
|
||||
Consumerin omat stepit (test, sonarqube, ai-scan) ovat esimerkki.
|
||||
Vastaava rakenne toimii millä tahansa kielellä tai työkalulla.
|
||||
### `check-version.yml` — Version ja artifactin tarkistus
|
||||
|
||||
### Optionaaliset laatu- ja tietoturvaskannaukset
|
||||
**Trigger:** `workflow_call` — käytetään vain main-haarassa
|
||||
|
||||
Consumer voi lisätä pipelineen omia skannaussteppejä testien rinnalle.
|
||||
Nämä ajetaan rinnakkain `validate`-vaiheen jälkeen ja syöttävät
|
||||
raporttinsa providerin `publish-reports`-palveluun. Jokainen skannaus
|
||||
on oma Gitea Actions -jobinsa.
|
||||
**Inputs:** `env_json`
|
||||
|
||||
```mermaid
|
||||
%%{init: {'theme': 'base', 'flowchart': {'arrowheadScale': 2}}}%%
|
||||
flowchart LR
|
||||
VAL["validate"] --> SAST["sast
|
||||
semgrep / codeql"]
|
||||
VAL --> SCA["sca
|
||||
snyk / owasp dc"]
|
||||
VAL --> SECRETS["secret-scan
|
||||
gitleaks"]
|
||||
VAL --> LICENSE["license
|
||||
fossa / scancode"]
|
||||
VAL --> AI_REVIEW["ai-review
|
||||
code quality"]
|
||||
**Outputs:** `artifact_exists` (true/false), `version` (string)
|
||||
|
||||
SAST --> PUB
|
||||
SCA --> PUB
|
||||
SECRETS --> PUB
|
||||
LICENSE --> PUB
|
||||
AI_REVIEW --> PUB
|
||||
|
||||
PUB["publish-reports + commit-status"]
|
||||
|
||||
style VAL fill:#2563eb,color:#ffffff
|
||||
style SAST fill:#7c3aed,color:#ffffff
|
||||
style SCA fill:#7c3aed,color:#ffffff
|
||||
style SECRETS fill:#7c3aed,color:#ffffff
|
||||
style LICENSE fill:#7c3aed,color:#ffffff
|
||||
style AI_REVIEW fill:#7c3aed,color:#ffffff
|
||||
style PUB fill:#0891b2,color:#ffffff
|
||||
linkStyle default stroke:#9ca3af,stroke-width:3px
|
||||
**Steppi-kaavio:**
|
||||
```
|
||||
checkout → laske versio package.json + git-tageista → output
|
||||
```
|
||||
|
||||
| Kategoria | Esimerkki | Kuvaus |
|
||||
|-----------|-----------|--------|
|
||||
| **SAST** | Semgrep, CodeQL | Staattinen analyysi — bugit ja haavoittuvuudet koodista |
|
||||
| **SCA** | Snyk, OWASP Dependency-Check | Riippuvuuksien tunnetut haavoittuvuudet |
|
||||
| **Secret scan** | Gitleaks, TruffleHog | API-avaimet, tokenit ja salasanat repossa |
|
||||
| **Lisenssit** | FOSSA, ScanCode | Riippuvuuksien lisenssien yhteensopivuus |
|
||||
| **AI review** | — | Automaattinen koodikatselmointi |
|
||||
### `docker-build-push.yml` — Docker build & push
|
||||
|
||||
### Error handling
|
||||
**Trigger:** `workflow_call`
|
||||
|
||||
Providerin julkaisu- ja status-stepit käyttävät `if: always()`-ehtoa,
|
||||
jotta raportit ja commit-status päivittyvät myös failaavista ajoista.
|
||||
Consumerin omat stepit voivat vapaasti päättää `continue-on-error`- tai
|
||||
`if: failure()`-logiikastaan. Provider ei määrittele virheidenkäsittelyä
|
||||
consumerin pipelineen.
|
||||
**Inputs:** `env_json`, `version`
|
||||
|
||||
### Merge-portti
|
||||
**Secrets:** `GITEA_TOKEN`, `DOCKER_USERNAME`, `DOCKER_PASSWORD`
|
||||
|
||||
Branch protection -säännössä Giteassa vaaditaan ennen PR:n sulkemista:
|
||||
- **Pipeline on ajettu** (`run > 1`, ei "never run" -tila)
|
||||
- **Kaikki commit-statukset vihreitä** — validate, testit, laatuportit
|
||||
- Jos joku steppi failaa, status asettuu `failure`-tilaan ja PR:n
|
||||
sulkeminen estyy
|
||||
|
||||
### Optionaalinen PR-ympäristö (preview app)
|
||||
|
||||
Consumer voi halutessaan buildata kontin ja deployata sen väliaikaiseen
|
||||
PR-ympäristöön. Tämä on optionaalinen continuation-haara, joka
|
||||
aktivoituu ehdolla:
|
||||
|
||||
- PR:ssä on tietty label (esim. `preview`)
|
||||
- Commit message sisältää triggerisanan (esim. `[preview]`)
|
||||
|
||||
**Elinkaari:**
|
||||
|
||||
```mermaid
|
||||
%%{init: {'theme': 'base', 'flowchart': {'arrowheadScale': 2}}}%%
|
||||
flowchart LR
|
||||
QG["quality-gate
|
||||
testit + skannaukset
|
||||
ok"] --> BUILD["build-container
|
||||
tag: pr-42"]
|
||||
BUILD --> DEPLOY["deploy-pr-env
|
||||
väliaikainen ympäristö"]
|
||||
|
||||
DEPLOY --> STATUS["commit-status
|
||||
linkki PR-ympäristöön"]
|
||||
|
||||
PR_CLOSE["PR merged / closed"] --> CLEANUP["cleanup-pr-env
|
||||
tuhoa ympäristö"]
|
||||
|
||||
style QG fill:#059669,color:#ffffff
|
||||
style BUILD fill:#0891b2,color:#ffffff
|
||||
style DEPLOY fill:#7c3aed,color:#ffffff
|
||||
style STATUS fill:#f59e0b,color:#111827
|
||||
style PR_CLOSE fill:#dc2626,color:#ffffff
|
||||
style CLEANUP fill:#dc2626,color:#ffffff
|
||||
linkStyle default stroke:#9ca3af,stroke-width:3px
|
||||
**Steppi-kaavio:**
|
||||
```
|
||||
|
||||
1. Quality-gate läpäisty (testit + skannaukset ok)
|
||||
2. Buildaa kontti, tagi sisältää PR-numeron (`pr-42`)
|
||||
3. Deployaa PR-ympäristöön (preview/review app)
|
||||
4. Asettaa commit-statuksen linkillä ympäristöön
|
||||
5. **PR:n sulkeutuessa** (merge/close): cleanup-job tuhoaa ympäristön
|
||||
|
||||
Tämä on **consumerin vastuulla** — provider tarjoaa tarvittavat
|
||||
skriptit (`publish-git-pages.sh`, `report-status.sh`), mutta
|
||||
trigger-ehto, kontin buildaus ja ympäristön hallinta kuuluvat
|
||||
consumerin pipelineen.
|
||||
|
||||
---
|
||||
|
||||
## `ci-master.yml` — Main-branch build
|
||||
|
||||
**Trigger:** `workflow_call` — kutsutaan main-branchiin pushattaessa
|
||||
|
||||
**Rooli:** Buildaa artifaktin (kontti, JAR, npm-paketti tms.) ja julkaisee
|
||||
sen rekisteriin. Jos sama commit on jo buildattu (version tag on olemassa),
|
||||
build skipataan ja siirrytään suoraan test flow'hun.
|
||||
|
||||
**Provider-Consumer-malli (ADR 0005):** Provider orkestroi idempotent
|
||||
build-logiikan (`isArtifactBuilt`-tarkistus), mutta consumer omistaa
|
||||
build-stepit — valitsee työkalut ja artifaktityypin.
|
||||
|
||||
### isArtifactBuilt-check
|
||||
|
||||
Ennen buildia tarkistetaan, onko tälle commitille jo olemassa versiotagi:
|
||||
|
||||
```bash
|
||||
TAG=$(git tag --points-at HEAD | grep -E '^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$' | head -1)
|
||||
if [ -n "$TAG" ]; then
|
||||
echo "artifact_already_built=true" >> $GITHUB_ENV
|
||||
echo "artifact_version=$TAG" >> $GITHUB_ENV
|
||||
fi
|
||||
```
|
||||
|
||||
Jos tagi löytyy, build- ja push-stepit skipataan. Committia vastaan on
|
||||
jo olemassa artifakti rekisterissä — uudelleenbuildaus aiheuttaisi
|
||||
versiokonflikteja ja tuhlaisi CI-aikaa.
|
||||
|
||||
### Steppi-kaavio
|
||||
|
||||
```mermaid
|
||||
%%{init: {'theme': 'base', 'flowchart': {'arrowheadScale': 2}}}%%
|
||||
flowchart TD
|
||||
CHECK{"isArtifactBuilt?
|
||||
git tag --points-at HEAD"}
|
||||
|
||||
CHECK -- "ei" --> QG["quality-gate
|
||||
testit + skannaukset"]
|
||||
QG --> BUILD["build-artifact
|
||||
consumer: docker build /
|
||||
mvn package / npm build"]
|
||||
BUILD --> PUSH["push registry
|
||||
gitea packages /
|
||||
docker registry"]
|
||||
PUSH --> TAG["tag-commit
|
||||
tagittaa commitin
|
||||
versiolla (esim. 1.2.3.${RUN})"]
|
||||
|
||||
CHECK -- "kyllä" --> K8S["continueToTestFlow
|
||||
(future: K8s-testit
|
||||
test plan -mukaan)"]
|
||||
TAG --> K8S
|
||||
|
||||
FAIL("fail") -. "quality-gate
|
||||
ei läpäisty" .-> END
|
||||
|
||||
K8S --> END(["end
|
||||
commit-status"])
|
||||
|
||||
style CHECK fill:#f59e0b,color:#111827
|
||||
style QG fill:#059669,color:#ffffff
|
||||
style BUILD fill:#0891b2,color:#ffffff
|
||||
style PUSH fill:#dc2626,color:#ffffff
|
||||
style TAG fill:#f59e0b,color:#111827
|
||||
style K8S fill:#7c3aed,color:#ffffff
|
||||
style FAIL fill:#dc2626,color:#ffffff
|
||||
style END fill:#2563eb,color:#ffffff
|
||||
linkStyle default stroke:#9ca3af,stroke-width:3px
|
||||
```
|
||||
|
||||
### Elinkaari
|
||||
|
||||
1. **isArtifactBuilt?** — tarkista onko tagi olemassa
|
||||
2. **quality-gate** — jos ei tagia, aja `quality-gate.yml` (testit, skannaukset)
|
||||
3. **build-artifact** — jos quality-gate läpäisty, buildaa artifakti
|
||||
4. **push registry** — julkaise rekisteriin (Gitea Packages, Docker registry, jne.)
|
||||
5. **tag-commit** — tagittaa commitin versiolla (esim. `1.2.3.<run_number>`)
|
||||
6. **continueToTestFlow** — *(future)* aja K8s-testit test plan -mukaan
|
||||
7. **commit-status** — aseta lopullinen status
|
||||
|
||||
### Concurrency
|
||||
|
||||
```yaml
|
||||
concurrency:
|
||||
group: master-${{ github.repository }}
|
||||
cancel-in-progress: false
|
||||
```
|
||||
|
||||
Vain yksi master-build kerrallaan per repo. Ei cancel-in-progress —
|
||||
käynnissä olevan buildin annetaan valmistua.
|
||||
|
||||
---
|
||||
|
||||
## `deploy.yml` — GitOps-deployment
|
||||
|
||||
**Trigger:** `workflow_dispatch` (aina dispatchataan toisesta workflow'sta)
|
||||
|
||||
**Elinkaari:**
|
||||
|
||||
```
|
||||
start → read-yaml → update-value → commit → push → report-cross-repo → end
|
||||
```
|
||||
|
||||
### Inputs (dispatch-parametrit)
|
||||
|
||||
| Parametri | Kuvaus |
|
||||
|-----------|--------|
|
||||
| `environment` | Ympäristön nimi (korvaa `{.environment}`) |
|
||||
| `version` | Uusi konttiversio |
|
||||
| `root_commit` | Mikropalvelun commit josta deploy käynnistyi |
|
||||
| `root_repo` | Mikropalvelun repo |
|
||||
| `root_build_url` | URL mikropalvelun buildiin |
|
||||
|
||||
### Mitä deploy tekee
|
||||
|
||||
1. Lukee `{projectFolder}/{fileName}` YAML-tiedoston (korvaa `{.environment}` → `environment`)
|
||||
2. Päivittää `{property}`-avaimen arvoksi `{version}`
|
||||
3. `git add`, `git commit -m "deploy {version} to {environment}"`
|
||||
4. `git push origin HEAD:master`
|
||||
5. Raportoi statuksen:
|
||||
- Helm-repon committiin: **"from {root_commit}"**, URL → root-build
|
||||
- Mikropalvelun committiin (`root_commit`): **"deployed to {environment}"**, URL → Helm-commit
|
||||
6. Palauttaa Helm-commitin hashin (`outputs.commit`)
|
||||
|
||||
### Concurrency
|
||||
|
||||
```yaml
|
||||
concurrency:
|
||||
group: deploy-${{ github.repository }}-${{ inputs.environment }}
|
||||
cancel-in-progress: false
|
||||
build-push (build + push samassa jobissa, ei levyn kautta) → tag-commit
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## `test.yml` — Test flow -steppi
|
||||
## Consumer-esimerkki (`example-*`)
|
||||
|
||||
**Trigger:** `workflow_dispatch` (dispatchataan deploy-workflow'n jälkeen)
|
||||
### `example-feature.yml` — Feature-haaran CI
|
||||
|
||||
**Elinkaari:**
|
||||
**Trigger:** `push` [branches-ignore: main]
|
||||
|
||||
```
|
||||
start → version-check → run-tests → push-reports → report-cross-repo → end
|
||||
load-config → bats + cucumber → report-summary (always)
|
||||
```
|
||||
|
||||
### Inputs (dispatch-parametrit)
|
||||
### `example-main.yml` — Main-haaran CI
|
||||
|
||||
| Parametri | Kuvaus |
|
||||
|-----------|--------|
|
||||
| `environment` | Testiympäristö |
|
||||
| `version` | Testattava konttiversio |
|
||||
| `tags` | Cucumber-tagit |
|
||||
| `versionApiUrl` | URL version tarkistukseen |
|
||||
| `versionCheckScript` | Polku version check -skriptiin |
|
||||
| `root_commit` | Mikropalvelun commit |
|
||||
| `root_repo` | Mikropalvelun repo |
|
||||
| `deploy_commit` | Helm-repon commit (deployattu versio) |
|
||||
| `deploy_repo` | Helm-repo |
|
||||
**Trigger:** `push` [branches: main]
|
||||
|
||||
### Version check
|
||||
|
||||
Ennen testejä varmistetaan, että ympäristössä pyörii oikea versio:
|
||||
|
||||
```yaml
|
||||
- name: Check deployed version
|
||||
if: inputs.versionCheckScript || inputs.versionApiUrl
|
||||
run: |
|
||||
if [ -n "${{ inputs.versionCheckScript }}" ]; then
|
||||
bash "${{ inputs.versionCheckScript }}" "${{ inputs.versionApiUrl }}" "${{ inputs.version }}"
|
||||
fi
|
||||
```
|
||||
load-config → check-version →
|
||||
[artifact exists] → done
|
||||
[no artifact] → bats + cucumber → report-summary (always) → docker-build-push
|
||||
```
|
||||
|
||||
Version check -skripti pollaa Fibonacci-backoffilla — ks. [config-model.md](config-model.md).
|
||||
### `example-bats-tests.yml` — Bats unit-testit
|
||||
|
||||
### Cross-repo-raportointi
|
||||
**Trigger:** `workflow_call`
|
||||
|
||||
Testien jälkeen raportoidaan kolmeen committiin:
|
||||
Ajaa Bats-testit Docker-kontissa, generoi coveragen (`bashcov`), julkaisee
|
||||
raportit git-pagesiin, asettaa commit-statuksen linkillä raporttiin.
|
||||
|
||||
1. Testi-repon oma commit: testin status
|
||||
2. Mikropalvelun commit (`root_commit`): "testit OK/epäonnistui"
|
||||
3. Helm-repon commit (`deploy_commit`): "testattu v{version}"
|
||||
### `example-cucumber-tests.yml` — Cucumber hyväksymätestit
|
||||
|
||||
### Concurrency
|
||||
**Trigger:** `workflow_call`
|
||||
|
||||
```yaml
|
||||
concurrency:
|
||||
group: test-${{ inputs.environment }}
|
||||
cancel-in-progress: false
|
||||
```
|
||||
Ajaa Cucumber-testit Node-kontissa, julkaisee raportit git-pagesiin, asettaa
|
||||
commit-statuksen linkillä raporttiin.
|
||||
|
||||
### `example-report-summary.yml` — Raporttien koontinäkymä
|
||||
|
||||
**Trigger:** `workflow_call` — ajetaan `if: always()` testien jälkeen
|
||||
|
||||
**Inputs:** `env_json`, `suites` (space-separated lista suite-nimistä)
|
||||
|
||||
Generoi Markdown-taulukon `GITHUB_STEP_SUMMARY`:yn kaikista julkaistuista
|
||||
raporteista. Renderöityy HTML:ksi Gitea 1.27+ Summary-välilehdellä.
|
||||
Forward-compatibeli — ei haittaa vanhemmilla Gitea-versioilla.
|
||||
|
||||
---
|
||||
|
||||
## Suunnitteilla
|
||||
|
||||
- `deploy.yml` — GitOps-deployment (dispatch-workflow.sh-pohjainen)
|
||||
- `test.yml` — Klusteritason test flow
|
||||
|
||||
@@ -16,7 +16,7 @@ curl_with_host() {
|
||||
declare -A BRANCH_CACHE
|
||||
branch_exists() {
|
||||
local owner="$1" repo="$2" branch="$3" key="${owner}/${repo}/${branch}"
|
||||
local status
|
||||
local status attempt
|
||||
|
||||
[ -z "$GITEA_API_URL" ] && return 0
|
||||
[ -z "$GITEA_TOKEN" ] && return 0
|
||||
@@ -25,15 +25,32 @@ branch_exists() {
|
||||
return 0
|
||||
fi
|
||||
|
||||
status=$(curl -sS -o /dev/null -w "%{http_code}" \
|
||||
-H "Authorization: token ${GITEA_TOKEN}" \
|
||||
"${GITEA_API_URL}/api/v1/repos/${owner}/${repo}/branches/${branch}" 2>/dev/null || echo "000")
|
||||
# Retry up to 2 times on API errors (hardcoded)
|
||||
for attempt in 1 2 3; do
|
||||
status=$(curl -sS -o /dev/null -w "%{http_code}" \
|
||||
-H "Authorization: token ${GITEA_TOKEN}" \
|
||||
"${GITEA_API_URL}/api/v1/repos/${owner}/${repo}/branches/${branch}" 2>/dev/null || echo "000")
|
||||
|
||||
if [ "$status" = "200" ]; then
|
||||
BRANCH_CACHE[$key]=1
|
||||
return 0
|
||||
fi
|
||||
return 1
|
||||
if [ "$status" = "200" ]; then
|
||||
BRANCH_CACHE[$key]=1
|
||||
return 0
|
||||
fi
|
||||
|
||||
if [ "$status" = "404" ]; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
# API error - retry if not last attempt
|
||||
if [ "$attempt" -lt 3 ]; then
|
||||
sleep 10
|
||||
continue
|
||||
fi
|
||||
done
|
||||
|
||||
# All retries failed - keep report (fail-safe)
|
||||
echo " WARN: Gitea API error for ${owner}/${repo}/${branch} (status ${status}) after 3 attempts - KEEPING report"
|
||||
BRANCH_CACHE[$key]=1
|
||||
return 0
|
||||
}
|
||||
|
||||
default_max_age=$(jq -r '.branches.default.maxAgeDays // 90' "$CONFIG")
|
||||
|
||||
@@ -0,0 +1,112 @@
|
||||
# Docker Registry Setup
|
||||
|
||||
Pipeline rakentaa Docker-kontin ja pushee sen haluttuun registryyn.
|
||||
|
||||
---
|
||||
|
||||
## 1. Konfiguroi `gitea-env.conf`
|
||||
|
||||
```
|
||||
# DOCKER_REGISTRY on muotoa: registry.example.com/org
|
||||
#
|
||||
# host+org: registry.example.com/org
|
||||
#
|
||||
# Pipeline rakentaa kuvan: ${DOCKER_REGISTRY}/${DOCKER_IMAGE_NAME}:${VERSION}
|
||||
|
||||
DOCKER_REGISTRY=gitea.app.keskikuja.site/niko # PAKOLLINEN — tyhjä ei käy
|
||||
DOCKER_IMAGE_NAME=gitea-ci-library-test-image # PAKOLLINEN — pelkkä kuvan nimi
|
||||
DOCKER_UI_URL= # valinnainen — tarkista Giteasta kontin oma UI-osoite ja laita se tähän ilman versiota. Workflow liittää perään /VERSION
|
||||
```
|
||||
|
||||
| Kenttä | Pakollinen | Kuvaus |
|
||||
|---|---|---|
|
||||
| `DOCKER_REGISTRY` | **kyllä** | Registry + mahdollinen organisaatio. **Tyhjä pysäyttää workflow'n.** |
|
||||
| `DOCKER_IMAGE_NAME` | **kyllä** | Pelkkä kuvan nimi. |
|
||||
| `DOCKER_UI_URL` | ei | Base-URL kontin UI-sivulle (ilman versiota). Osoite riippuu onko kontti linkitetty repoon vai ei — tarkista Giteasta. Workflow liittää perään `/VERSION`. |
|
||||
|
||||
**Koko image-ref = `${DOCKER_REGISTRY}/${DOCKER_IMAGE_NAME}:${VERSION}`**
|
||||
Esim. `gitea.app.keskikuja.site/niko/gitea-ci-library-test-image:0.1.0`
|
||||
|
||||
---
|
||||
|
||||
## 2. Luo PAT (Personal Access Token) Giteassa
|
||||
|
||||
**Gitea → oma profiili (oikea yläkulma) → Settings → Applications → Manage Access Tokens → Generate New Token**
|
||||
|
||||
Valitse scope:
|
||||
|
||||
| Scope | Pääsy |
|
||||
|---|---|
|
||||
| `package` | **Read and Write** |
|
||||
|
||||
> Tämä token toimii salasanana `docker login` -komennossa. Muut scopet (kuten `repository`) eivät riitä — konttirekisteri vaatii nimenomaan `package`-scopen.
|
||||
|
||||
Tokenin arvo näytetään **vain kerran** luomisen yhteydessä. Kopioi se talteen.
|
||||
|
||||
---
|
||||
|
||||
## 3. Tallenna PAT repositoryn Secretsiin
|
||||
|
||||
Nämä ovat kaksi eri paikkaa:
|
||||
- **Access Tokenit** (User Settings) = missä luot tokenin
|
||||
- **Repository Secrets** (Repository Settings) = minne talletat sen workflow'n käyttöön
|
||||
|
||||
**Repository → Settings → Actions → Secrets → Add new secret**
|
||||
|
||||
| Secret | Arvo |
|
||||
|---|---|
|
||||
| `DOCKER_PASSWORD` | Edellisessä vaiheessa luotu PAT |
|
||||
|
||||
`DOCKER_USERNAME`-secretiä **ei tarvita**. Workflow käyttää automaattisesti `${{ github.actor }}` (workflowin käynnistäjä).
|
||||
|
||||
Jos registry vaatii eri käyttäjätunnuksen kuin `github.actor` (esim. Artifactory, Docker Hub), lisää myös:
|
||||
|
||||
| Secret | Arvo |
|
||||
|---|---|
|
||||
| `DOCKER_USERNAME` | Registryn käyttäjätunnus |
|
||||
|
||||
---
|
||||
|
||||
## 4. Tarkistuslista ennen ajoa
|
||||
|
||||
- [ ] `DOCKER_REGISTRY` asetettu `gitea-env.conf`issa
|
||||
- [ ] `DOCKER_IMAGE_NAME` asetettu `gitea-env.conf`issa
|
||||
- [ ] PAT luotu Giteassa scopella `package` Read and Write
|
||||
- [ ] `DOCKER_PASSWORD`-secret tallennettu repositoryn Secretsiin (se PAT)
|
||||
- [ ] (tarvittaessa) `DOCKER_USERNAME`-secret — oletus `github.actor`
|
||||
|
||||
---
|
||||
|
||||
## 5. Esimerkkejä eri polkurakenteista
|
||||
|
||||
### 5a. Pelkkä hosti — Artifactory
|
||||
|
||||
```
|
||||
DOCKER_REGISTRY=ngdo-docker.artifactorypro.shared.pub.tds.tieto.com
|
||||
DOCKER_IMAGE_NAME=microservice-temperature-store
|
||||
DOCKER_UI_URL=https://artifactorypro.shared.pub.tds.tieto.com/ui/repos/tree/General/ngdo-docker.artifactorypro.shared.pub.tds.tieto.com/microservice-temperature-store
|
||||
```
|
||||
|
||||
- Kontti: `ngdo-docker.../microservice-temperature-store:0.1.0`
|
||||
- Secret `DOCKER_USERNAME` = service account -tunnus
|
||||
- Secret `DOCKER_PASSWORD` = API-token
|
||||
|
||||
### 5b. Hosti + org — Gitea user-taso
|
||||
|
||||
```
|
||||
DOCKER_REGISTRY=gitea.app.keskikuja.site/niko
|
||||
DOCKER_IMAGE_NAME=gitea-ci-library-test-image
|
||||
DOCKER_UI_URL= # tarkista Giteasta kontin UI-osoite
|
||||
```
|
||||
|
||||
- Kontti: `gitea.app.keskikuja.site/niko/gitea-ci-library-test-image:0.1.0`
|
||||
- Paketti käyttäjän `niko` alla. Linkitys repoon tehdään Gitean UI:sta: paketin sivulta (Package → Settings) → linkitä repositoryyn.
|
||||
|
||||
```
|
||||
DOCKER_REGISTRY=docker.io/library
|
||||
DOCKER_IMAGE_NAME=oma-kuva
|
||||
DOCKER_UI_URL=https://hub.docker.com/r/library/oma-kuva
|
||||
```
|
||||
|
||||
- Secret `DOCKER_USERNAME` = Docker Hub -käyttäjä
|
||||
- Secret `DOCKER_PASSWORD` = Access Token (ei salasana)
|
||||
+25
-25
@@ -1,27 +1,27 @@
|
||||
{
|
||||
"name": "gitea-ci-library",
|
||||
"version": "0.1.0",
|
||||
"description": "",
|
||||
"main": "cucumber.js",
|
||||
"directories": {
|
||||
"doc": "docs",
|
||||
"test": "tests"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "npm run test:bats && npm run test:cucumber",
|
||||
"test:bats": "mkdir -p reports && docker run --rm -v \"$(pwd):/repo:ro\" -v \"$(pwd)/reports:/repo/reports\" -w /repo --entrypoint bash bats/bats:latest -c 'apk add -q python3 curl jq lsof ruby && gem install bashcov -q > /dev/null 2>&1; bats tests/'",
|
||||
"test:bats:coverage": "mkdir -p reports && docker run --rm -v \"$(pwd):/repo\" -v \"$(pwd)/reports:/repo/reports\" -w /repo --entrypoint bash bats/bats:latest -c 'apk add -q python3 curl jq lsof ruby && gem install bashcov -q > /dev/null 2>&1; bashcov -- bats tests/'",
|
||||
"test:cucumber": "docker run --rm -v \"$(pwd):/repo:ro\" -v \"$(pwd)/node_modules:/repo/node_modules\" -w /repo --entrypoint bash node:22 -c 'apt-get update -qq && apt-get install -y -qq jq lsof && npm ci && npx cucumber-js tests/features/ --tags @mock and ~@wip'"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "ssh://git@gitea.app.keskikuja.site:30009/niko/gitea-ci-library.git"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"type": "commonjs",
|
||||
"devDependencies": {
|
||||
"@cucumber/cucumber": "^13.0.0"
|
||||
}
|
||||
"name": "gitea-ci-library",
|
||||
"version": "0.2.0",
|
||||
"description": "",
|
||||
"main": "cucumber.js",
|
||||
"directories": {
|
||||
"doc": "docs",
|
||||
"test": "tests"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "npm run test:bats && npm run test:cucumber",
|
||||
"test:bats": "mkdir -p reports && docker run --rm -v \"$(pwd):/repo:ro\" -v \"$(pwd)/reports:/repo/reports\" -w /repo --entrypoint bash bats/bats:latest -c 'apk add -q python3 curl jq lsof ruby && gem install bashcov -q > /dev/null 2>&1; bats tests/'",
|
||||
"test:bats:coverage": "mkdir -p reports && docker run --rm -v \"$(pwd):/repo\" -v \"$(pwd)/reports:/repo/reports\" -w /repo --entrypoint bash bats/bats:latest -c 'apk add -q python3 curl jq lsof ruby && gem install bashcov -q > /dev/null 2>&1; bashcov -- bats tests/'",
|
||||
"test:cucumber": "docker run --rm -v \"$(pwd):/repo:ro\" -v \"$(pwd)/node_modules:/repo/node_modules\" -w /repo --entrypoint bash node:22 -c 'apt-get update -qq && apt-get install -y -qq jq lsof && npm ci && npx cucumber-js tests/features/ --tags @mock and ~@wip'"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "ssh://git@gitea.app.keskikuja.site:30009/niko/gitea-ci-library.git"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"type": "commonjs",
|
||||
"devDependencies": {
|
||||
"@cucumber/cucumber": "^13.0.0"
|
||||
}
|
||||
}
|
||||
@@ -1,17 +1,22 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
# https://docs.gitea.com/api/next/#tag/repository/operation/repoCreateStatus
|
||||
|
||||
STATE="${1:-}"
|
||||
DESCRIPTION="${2:-}"
|
||||
KEY="${3:-commit-${GITHUB_SHA:0:8}}"
|
||||
SUITE="${4:-}"
|
||||
CUSTOM_URL="${5:-}"
|
||||
|
||||
[ -z "$STATE" ] && echo "ERROR: state argument is required" >&2 && exit 1
|
||||
[ -z "$DESCRIPTION" ] && echo "ERROR: description 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 "$SUITE" ]; then
|
||||
if [ -n "$CUSTOM_URL" ]; then
|
||||
URL="$CUSTOM_URL"
|
||||
elif [ -n "$SUITE" ]; then
|
||||
SUITE="${SUITE%/}/"
|
||||
URL="${GIT_PAGES_URL}/${GITHUB_REPOSITORY}/reports/${GITHUB_SHA:0:8}/${SUITE}"
|
||||
else
|
||||
@@ -28,15 +33,15 @@ HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" \
|
||||
-X POST "$GITEA_API_URL/api/v1/repos/$REPO/statuses/$COMMIT" \
|
||||
-H "Authorization: token $GITEA_TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "{\"state\":\"$STATE\",\"target_url\":\"$URL\",\"description\":\"$DESCRIPTION\",\"context\":\"$KEY\"}")
|
||||
-d "{\"state\":\"$STATE\",\"target_url\":\"$URL\",\"description\":\"$DESCRIPTION\",\"context\":\"$KEY\"}" || true)
|
||||
|
||||
if [ "$HTTP_CODE" = "201" ]; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [ -z "$HTTP_CODE" ]; then
|
||||
echo "ERROR: Failed to connect to Gitea API at $GITEA_API_URL" >&2
|
||||
if [ -z "$HTTP_CODE" ] || [ "$HTTP_CODE" = "000" ]; then
|
||||
echo "gitea-ci-library - ERROR: Failed to connect to Gitea API at $GITEA_API_URL" >&2
|
||||
else
|
||||
echo "ERROR: API returned HTTP $HTTP_CODE" >&2
|
||||
echo "gitea-ci-library - ERROR: gitea-ci-library, API returned HTTP $HTTP_CODE" >&2
|
||||
fi
|
||||
exit 1
|
||||
|
||||
@@ -6,10 +6,15 @@ const PROJECT_ROOT = path.resolve(__dirname, '..', '..', '..');
|
||||
const MOCK_SCRIPT = path.join(PROJECT_ROOT, 'tests', 'helpers', 'mock-api.sh');
|
||||
|
||||
Before({ tags: '@mock' }, function () {
|
||||
execSync(`bash -c 'source "${MOCK_SCRIPT}" && mock_start'`, {
|
||||
const out = execSync(`bash -c 'source "${MOCK_SCRIPT}" && mock_start && sleep 0.3 && curl -s -o /dev/null -w "%{http_code}" --max-time 3 http://localhost:18080/api/v1/repos/health/check'`, {
|
||||
cwd: PROJECT_ROOT,
|
||||
stdio: 'ignore',
|
||||
encoding: 'utf-8',
|
||||
stdio: ['pipe', 'pipe', 'pipe'],
|
||||
});
|
||||
const trimmed = out.trim();
|
||||
if (!trimmed.startsWith('2') && !trimmed.startsWith('4')) {
|
||||
throw new Error(`Mock server failed to start (HTTP ${trimmed})`);
|
||||
}
|
||||
});
|
||||
|
||||
After({ tags: '@mock' }, function () {
|
||||
|
||||
Reference in New Issue
Block a user