name: ci "on": push: branches: - main pull_request: null workflow_dispatch: null permissions: contents: read actions: read concurrency: group: ci-${{ github.ref }} cancel-in-progress: ${{ github.ref != 'refs/heads/main' }} jobs: checks: runs-on: homelab timeout-minutes: 30 steps: - name: Checkout repository uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 - name: Prepare pinned tools shell: bash run: | set -euo pipefail tools_dir="$(bash .gitea/workflows/install-ci-tools.sh)" echo "$tools_dir" >> "$GITHUB_PATH" - name: Validate Compose files shell: bash run: | set -euo pipefail source .gitea/workflows/compose-lint.sh mapfile -t safe_flags < <(compose_safe_flags) echo "docker compose config ${safe_flags[*]-}" mapfile -t files < <(compose_files) if [ "${#files[@]}" -eq 0 ]; then echo "No Compose files found." exit 0 fi failed=0 for f in "${files[@]}"; do if ! out="$(validate_compose_file "$f" ${safe_flags[@]+"${safe_flags[@]}"} 2>&1)"; then failed=1 echo "::error file=${f}::$(printf '%s' "$out" | head -1)" fi done if [ "$failed" -ne 0 ]; then echo "Compose validation failed." exit 1 fi echo "checked ${#files[@]} Compose file(s)" - name: Lint Gitea Actions workflows with actionlint shell: bash run: | set -euo pipefail actionlint -config-file .gitea/actionlint.yaml -color .gitea/workflows/*.yaml - name: Lint shell scripts with ShellCheck shell: bash run: | set -euo pipefail mapfile -t scripts < <( git ls-files '*.sh' ':(glob)**/*.bash' ) if [ "${#scripts[@]}" -eq 0 ]; then echo "No shell scripts found." exit 0 fi shellcheck --external-sources --source-path=SCRIPTDIR --severity=style "${scripts[@]}" bash .gitea/tests/deploy-validation.sh - name: Check formatting with Prettier shell: bash run: | set -euo pipefail mapfile -t prettier_files < <( git ls-files \ | grep -E '\.(md|json|ya?ml|html|css)$' \ | grep -Ev '^(\.docs/|\.zed/|errorpages/html/|homepages/(forust_files|xdfnx_files)/)' ) if [ "${#prettier_files[@]}" -eq 0 ]; then echo "No Prettier-managed files found." exit 0 fi prettier --check --ignore-unknown "${prettier_files[@]}" - name: Lint and format-check Python with Ruff shell: bash run: | set -euo pipefail ruff check . .gitea/workflows ruff format --check . .gitea/workflows python3 -m unittest discover -s tests -v - name: Lint YAML syntax shell: bash run: | set -euo pipefail mapfile -t yaml_files < <( git ls-files '*.yaml' '*.yml' \ ':!node_modules/**' \ ':!**/.venv/**' ) if [ "${#yaml_files[@]}" -eq 0 ]; then echo "No YAML files found." exit 0 fi yamllint -c .yamllint "${yaml_files[@]}" - name: Lint Dockerfiles shell: bash run: | set -euo pipefail mapfile -t dockerfiles < <( git ls-files ':(glob)**/Dockerfile' ':(glob)**/Dockerfile.*' ) if [ "${#dockerfiles[@]}" -eq 0 ]; then echo "No Dockerfiles found." exit 0 fi hadolint -c .hadolint.yaml "${dockerfiles[@]}" - name: Validate Kubernetes manifests against JSON schemas shell: bash run: | set -euo pipefail mapfile -t manifests < <( git ls-files ':(glob)**/k8s/**/*.yaml' ':(glob)**/k8s/**/*.yml' \ | grep -Ev '(^|/)(kustomization\.ya?ml|.*\.example\.ya?ml|.*values\.ya?ml|patch-.*\.ya?ml)$' ) if [ "${#manifests[@]}" -eq 0 ]; then echo "No Kubernetes manifests found." exit 0 fi kubeconform \ -strict \ -ignore-missing-schemas \ -summary \ "${manifests[@]}" build: needs: - checks if: github.event_name != 'pull_request' && github.ref == 'refs/heads/main' runs-on: homelab timeout-minutes: 60 steps: - name: Checkout repository uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 with: fetch-depth: 0 - name: Build changed images and write release env: GITEA_TOKEN: ${{ github.token }} REGISTRY_USERNAME: ${{ secrets.REGISTRY_USERNAME }} REGISTRY_PASSWORD: ${{ secrets.REGISTRY_PASSWORD }} run: python3 .gitea/workflows/release.py build - name: Store commit release uses: actions/upload-artifact@c6a366c94c3e0affe28c06c8df20a878f24da3cf with: name: release-${{ github.sha }} path: release.json if-no-files-found: error retention-days: 30