Shortens deploy label, adds manual test-deploy toggle, skips unaffected backend/frontend gates #4
@@ -3,8 +3,12 @@ name: Continuous Integration
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
deploy_test:
|
||||
description: 'Deploy to Test'
|
||||
type: boolean
|
||||
default: false
|
||||
deploy_production:
|
||||
description: 'Also deploy to production after a successful build/test (in addition to the automatic test deploy)'
|
||||
description: 'Deploy to Production'
|
||||
type: boolean
|
||||
default: false
|
||||
pull_request:
|
||||
@@ -62,8 +66,47 @@ jobs:
|
||||
echo "health_check_url_test=${{ env.HEALTH_CHECK_URL_TEST }}" >> "$GITHUB_OUTPUT"
|
||||
echo "health_check_url_production=${{ env.HEALTH_CHECK_URL_PRODUCTION }}" >> "$GITHUB_OUTPUT"
|
||||
|
||||
# Path-based skip: keeps the pipeline short when a change only touches one side of the repo.
|
||||
# fetch-depth: 0 gives paths-filter full local git history to diff against, rather than relying
|
||||
# on its GitHub-API fallback for missing history, which targets GitHub's REST API and cannot be
|
||||
# assumed to work against a Gitea remote. Changes under the workflow files themselves count as
|
||||
# both backend and frontend, so a workflow edit is never left partially untested. A manual
|
||||
# workflow_dispatch run has no `before` commit to diff against and is always an explicit request
|
||||
# to run everything, so it force-reports both sides as changed rather than trusting the filter.
|
||||
changes:
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
backend: ${{ github.event_name == 'workflow_dispatch' || steps.filter.outputs.backend == 'true' }}
|
||||
frontend: ${{ github.event_name == 'workflow_dispatch' || steps.filter.outputs.frontend == 'true' }}
|
||||
steps:
|
||||
# Skipped on workflow_dispatch: there's no `before` commit to diff against, and a manual run
|
||||
# always force-reports both sides changed anyway (see the outputs above), so the diff would be
|
||||
# wasted work.
|
||||
- uses: actions/checkout@v4
|
||||
if: github.event_name != 'workflow_dispatch'
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- uses: dorny/paths-filter@v3
|
||||
if: github.event_name != 'workflow_dispatch'
|
||||
id: filter
|
||||
with:
|
||||
filters: |
|
||||
workflow: &workflow
|
||||
- '.gitea/workflows/**'
|
||||
backend:
|
||||
- *workflow
|
||||
- 'src/**'
|
||||
- 'tests/**'
|
||||
- '*.sln'
|
||||
- '**/*.csproj'
|
||||
frontend:
|
||||
- *workflow
|
||||
- 'frontend/**'
|
||||
|
||||
# --- Gate 1: backend build ---
|
||||
backend-build:
|
||||
needs: changes
|
||||
if: needs.changes.outputs.backend == 'true'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
@@ -75,7 +118,8 @@ jobs:
|
||||
|
||||
# --- Gate 2: backend tests ---
|
||||
backend-test:
|
||||
needs: backend-build
|
||||
needs: [changes, backend-build]
|
||||
if: needs.changes.outputs.backend == 'true'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
@@ -90,6 +134,8 @@ jobs:
|
||||
# step greps its own output and fails deliberately (FR-22, D-12, OPEN-03 — closed by pinning
|
||||
# Microsoft.OpenApi and System.Security.Cryptography.Xml in the relevant .csproj files).
|
||||
vulnerability-scan:
|
||||
needs: changes
|
||||
if: needs.changes.outputs.backend == 'true'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
@@ -106,6 +152,8 @@ jobs:
|
||||
fi
|
||||
|
||||
frontend-prepare:
|
||||
needs: changes
|
||||
if: needs.changes.outputs.frontend == 'true'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
@@ -135,7 +183,8 @@ jobs:
|
||||
# that environment's Vite variables set and copies the result into wwwroot/admin before
|
||||
# `dotnet publish` runs — see that step's comment for why this isn't an MSBuild target instead.
|
||||
frontend-build:
|
||||
needs: frontend-prepare
|
||||
needs: [changes, frontend-prepare]
|
||||
if: needs.changes.outputs.frontend == 'true'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
@@ -163,7 +212,8 @@ jobs:
|
||||
|
||||
# --- Gate 5: frontend tests ---
|
||||
frontend-test:
|
||||
needs: frontend-prepare
|
||||
needs: [changes, frontend-prepare]
|
||||
if: needs.changes.outputs.frontend == 'true'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
@@ -191,7 +241,8 @@ jobs:
|
||||
|
||||
# --- Gate 6: frontend lint / format-check ---
|
||||
frontend-lint:
|
||||
needs: frontend-prepare
|
||||
needs: [changes, frontend-prepare]
|
||||
if: needs.changes.outputs.frontend == 'true'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
@@ -227,7 +278,15 @@ jobs:
|
||||
# gate cannot see the actual runtime CSP configuration; it only catches drift between the frontend
|
||||
# build and what this variable claims the CSP allows.
|
||||
publish-test:
|
||||
needs: [backend-build, backend-test, vulnerability-scan, frontend-build, frontend-test, frontend-lint]
|
||||
needs: [changes, backend-build, backend-test, vulnerability-scan, frontend-build, frontend-test, frontend-lint]
|
||||
# always() bypasses the automatic skip-cascade from a gate job that was itself skipped (because
|
||||
# its side of the repo didn't change) — !failure() && !cancelled() still blocks a run where a
|
||||
# gate that DID run actually failed. The remaining changes.outputs check makes sure there's
|
||||
# something to publish at all: a run that touched neither backend nor frontend has nothing new
|
||||
# to deploy.
|
||||
if: |
|
||||
always() && !failure() && !cancelled() &&
|
||||
(needs.changes.outputs.backend == 'true' || needs.changes.outputs.frontend == 'true')
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
@@ -289,8 +348,12 @@ jobs:
|
||||
# a distinct job rather than a parameterized reuse of publish-test, because VITE_APP_ENV is a
|
||||
# Vite build-time value: one dist/ bundle cannot be tagged as both 'test' and 'production' (FR-05).
|
||||
publish-production:
|
||||
needs: [backend-build, backend-test, vulnerability-scan, frontend-build, frontend-test, frontend-lint]
|
||||
if: github.event_name == 'workflow_dispatch' && github.event.inputs.deploy_production == 'true'
|
||||
needs: [changes, backend-build, backend-test, vulnerability-scan, frontend-build, frontend-test, frontend-lint]
|
||||
# See publish-test's comment on the always()/!failure()/!cancelled() combination above.
|
||||
if: |
|
||||
always() && !failure() && !cancelled() &&
|
||||
github.event_name == 'workflow_dispatch' && github.event.inputs.deploy_production == 'true' &&
|
||||
(needs.changes.outputs.backend == 'true' || needs.changes.outputs.frontend == 'true')
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
@@ -342,10 +405,13 @@ jobs:
|
||||
path: ${{ env.ARTIFACT_NAME_PRODUCTION }}
|
||||
retention-days: 1
|
||||
|
||||
# Automatic test deploy on push to master, or on any workflow_dispatch run (FR-03, D-01, D-09).
|
||||
# Automatic test deploy on every push to master (unchanged — a merge should reach test without
|
||||
# extra steps). A manual workflow_dispatch run only deploys to test when deploy_test is checked,
|
||||
# since a dispatch run is often just re-running CI/production, not a new test build (FR-03, D-01,
|
||||
# D-09).
|
||||
deploy-test:
|
||||
needs: [publish-test, config]
|
||||
if: github.event_name == 'workflow_dispatch' || (github.event_name == 'push' && github.ref == 'refs/heads/master')
|
||||
if: (github.event_name == 'workflow_dispatch' && github.event.inputs.deploy_test == 'true') || (github.event_name == 'push' && github.ref == 'refs/heads/master')
|
||||
uses: ./.gitea/workflows/deploy-scp.yaml
|
||||
secrets: inherit
|
||||
with:
|
||||
|
||||
Reference in New Issue
Block a user