diff --git a/.github/workflows/_main.yml b/.github/workflows/_main.yml index c021efbc3..1802419a3 100644 --- a/.github/workflows/_main.yml +++ b/.github/workflows/_main.yml @@ -18,31 +18,29 @@ on: jobs: - build-docs: - uses: ./.github/workflows/docs.yml + build: + name: Build + uses: ./.github/workflows/build.yml with: BRANCH_REF: ${{ github.ref }} - linters: - uses: ./.github/workflows/linters.yml + static-analysis: + name: Lint + uses: ./.github/workflows/static-analysis.yml with: BRANCH_REF: ${{ github.ref }} - tests-standard: - uses: ./.github/workflows/tests-standard.yml + tests: + name: Tests + uses: ./.github/workflows/tests-unit.yml with: BRANCH_REF: ${{ github.ref }} - - tests-premium: - uses: ./.github/workflows/tests-premium.yml - with: - BRANCH_REF: ${{ github.ref }} - environment: Main Tests secrets: inherit - tests-ultimate: - uses: ./.github/workflows/tests-ultimate.yml + tests-acceptance: + name: Acceptance Tests + uses: ./.github/workflows/tests-acceptance.yml with: BRANCH_REF: ${{ github.ref }} environment: Main Tests - secrets: inherit \ No newline at end of file + secrets: inherit diff --git a/.github/workflows/_releases.yml b/.github/workflows/_releases.yml index fff405b8b..c2cc08b5f 100644 --- a/.github/workflows/_releases.yml +++ b/.github/workflows/_releases.yml @@ -4,8 +4,16 @@ on: push: tags: - 'v*' - # Allow manual triggering of the workflow + # Allow manual triggering of the workflow. + # A maintainer can use the `force` input to bypass main workflow verification + # when a release must proceed due to unexpected issues with main workflow that prevent normal execution. workflow_dispatch: + inputs: + force: + description: 'Skip main workflow verification and force release' + required: false + default: false + type: boolean permissions: contents: write @@ -13,50 +21,63 @@ permissions: jobs: - linters: - uses: ./.github/workflows/linters.yml - with: - BRANCH_REF: ${{ github.ref }} - - tests-standard: - uses: ./.github/workflows/tests-standard.yml - with: - BRANCH_REF: ${{ github.ref }} + verify-main-workflow: + name: Verify main workflow + runs-on: ubuntu-latest + steps: + - name: Check main branch workflow completion + uses: actions/github-script@v7 + env: + FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true + with: + script: | + const force = context.payload.inputs?.force === true || context.payload.inputs?.force === 'true'; + if (force) { + console.log('Force release enabled; skipping main workflow verification.'); + return; + } - tests-premium: - uses: ./.github/workflows/tests-premium.yml - with: - BRANCH_REF: ${{ github.ref }} - environment: Main Tests - secrets: inherit + const runs = await github.rest.actions.listWorkflowRunsForRepo({ + owner: context.repo.owner, + repo: context.repo.repo, + event: 'push', + branch: 'main', + per_page: 50, + }); + const mainRun = runs.data.workflow_runs.find( + run => run.head_sha === context.sha && run.name === 'Main branch' + ); + if (!mainRun) { + throw new Error('No completed main workflow was found for this commit.'); + } + if (mainRun.status !== 'completed' || mainRun.conclusion !== 'success') { + throw new Error(`Main workflow did not pass. status=${mainRun.status} conclusion=${mainRun.conclusion}`); + } - tests-ultimate: - uses: ./.github/workflows/tests-ultimate.yml + build-release-artifacts: + name: Build release artifacts + needs: + - verify-main-workflow + uses: ./.github/workflows/build.yml with: BRANCH_REF: ${{ github.ref }} - environment: Main Tests - secrets: inherit publish-docs: + name: Docs needs: - - linters - - tests-standard - - tests-premium - - tests-ultimate + - build-release-artifacts runs-on: ubuntu-latest steps: - - uses: actions/checkout@v6 + - name: Checkout repository + uses: actions/checkout@v6 with: ref: ${{ github.ref }} fetch-depth: 2 - - name: Configure uv environment - uses: ./.github/actions/setup-uv-local - - name: Setup Python ${{ env.UV_PYTHON }} and install dependencies - run: | - uv sync --frozen --no-dev --group docs - - name: Build docs - run: | - uv run --no-sync docs build + - name: Download built documentation + uses: actions/download-artifact@v4 + with: + name: docs-site + path: site - name: Deploy 🚀 uses: JamesIves/github-pages-deploy-action@v4.8.0 with: @@ -64,11 +85,9 @@ jobs: folder: site publish-to-github: + name: Publish Release needs: - - linters - - tests-standard - - tests-premium - - tests-ultimate + - build-release-artifacts runs-on: ubuntu-latest steps: - name: Create release in GitHub @@ -80,11 +99,9 @@ jobs: token: ${{ secrets.GITHUB_TOKEN }} publish-to-pypi: + name: Publish PyPI needs: - - linters - - tests-standard - - tests-premium - - tests-ultimate + - build-release-artifacts runs-on: ubuntu-latest environment: name: pypi @@ -92,15 +109,20 @@ jobs: permissions: id-token: write # IMPORTANT: this permission is mandatory for trusted publishing steps: - - uses: actions/checkout@v6 + - name: Checkout repository + uses: actions/checkout@v6 with: ref: ${{ github.ref }} fetch-depth: 2 - name: Configure uv environment uses: ./.github/actions/setup-uv-local + with: + python-version: "3.14" - name: Setup Python ${{ env.UV_PYTHON }} and install dependencies run: | uv sync --frozen --no-dev --group release + # TODO: In a separate PR, consume the build artifact (package-dist) uploaded + # in build-release-artifacts instead of rebuilding and verifying the package here. - name: Build and verify the package run: | uv run --no-sync package build @@ -110,15 +132,16 @@ jobs: uv run --no-sync package publish publish-to-ghcr: + name: Publish GHCR needs: - - linters - - tests-standard - - tests-premium - - tests-ultimate + - build-release-artifacts - publish-to-pypi runs-on: ubuntu-latest steps: - - uses: actions/checkout@v6 + # TODO: In a separate PR, optimize docker image build to consume the built package artifact + # (package-dist) instead of copying and rebuilding from source if applicable. + - name: Checkout repository + uses: actions/checkout@v6 - name: Get the version from the tag run: echo "VERSION=${GITHUB_REF/refs\/tags\/v/}" >> $GITHUB_ENV - name: Docker metadata diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 000000000..d216aafd8 --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,84 @@ +name: Build and package artifacts + +on: + workflow_call: + inputs: + BRANCH_REF: + type: string + required: true + +permissions: + contents: read + +jobs: + package: + name: Package + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v6 + with: + ref: ${{ inputs.BRANCH_REF }} + fetch-depth: 2 + - name: Configure uv environment + uses: ./.github/actions/setup-uv-local + with: + python-version: "3.14" + - name: Install dependencies + run: uv sync --frozen --no-dev --group release + - name: Build and verify the package + run: | + uv run --no-sync package build + uv run --no-sync package verify + - name: Upload package distribution + uses: actions/upload-artifact@v4 + with: + name: package-dist + path: dist/* + + docs: + name: Docs + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v6 + with: + ref: ${{ inputs.BRANCH_REF }} + fetch-depth: 2 + - name: Configure uv environment + uses: ./.github/actions/setup-uv-local + with: + python-version: "3.14" + - name: Install dependencies + run: uv sync --frozen --no-dev --group docs + - name: Build documentation + run: uv run --no-sync docs build + - name: Upload docs site + uses: actions/upload-artifact@v4 + with: + name: docs-site + path: site + + smoke-tests: + name: "Smoke test - (${{ matrix.os == 'ubuntu-latest' && 'Linux' || matrix.os == 'macos-latest' && 'macOS' || 'Windows' }}, Python ${{ matrix.python-version }})" + strategy: + fail-fast: false + matrix: + os: [ubuntu-latest, macos-latest, windows-latest] + python-version: ["3.14", "3.12"] + needs: package + runs-on: ${{ matrix.os }} + steps: + - name: Checkout repository + uses: actions/checkout@v6 + with: + ref: ${{ inputs.BRANCH_REF }} + fetch-depth: 2 + - name: Configure uv environment + uses: ./.github/actions/setup-uv-local + with: + python-version: ${{ matrix.python-version }} + - name: Install dependencies + run: uv sync --frozen --no-dev --group test + - name: Run smoke tests + run: uv run --no-sync gitlabform -V diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml deleted file mode 100644 index 916fc1dda..000000000 --- a/.github/workflows/docs.yml +++ /dev/null @@ -1,28 +0,0 @@ -name: Docs - -on: - workflow_call: - inputs: - BRANCH_REF: - type: string - required: true - -permissions: - contents: read - -jobs: - build-docs: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v6 - with: - ref: ${{ inputs.BRANCH_REF }} - fetch-depth: 2 - - name: Configure uv environment - uses: ./.github/actions/setup-uv-local - - name: Setup Python ${{ env.UV_PYTHON }} and install dependencies - run: | - uv sync --frozen --no-dev --group docs - - name: Build documentation - run: | - uv run --no-sync docs build diff --git a/.github/workflows/linters.yml b/.github/workflows/linters.yml deleted file mode 100644 index 3e0689b13..000000000 --- a/.github/workflows/linters.yml +++ /dev/null @@ -1,67 +0,0 @@ -name: Linters - -on: - workflow_call: - inputs: - BRANCH_REF: - type: string - required: true - -permissions: - contents: read - -jobs: - black-formatting: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v6 - with: - ref: ${{ inputs.BRANCH_REF }} - fetch-depth: 2 - - name: Configure uv environment - uses: ./.github/actions/setup-uv-local - - name: Setup Python ${{ env.UV_PYTHON }} and install dependencies - run: | - uv sync --frozen --no-dev --group lint - - name: Run black formatting check - run: | - uv run --no-sync qa lint black --check . - - types: - runs-on: ubuntu-latest - strategy: - max-parallel: 1 - matrix: - python-version: [3.14] - fail-fast: false - steps: - - uses: actions/checkout@v6 - with: - ref: ${{ inputs.BRANCH_REF }} - fetch-depth: 2 - - name: Configure uv environment - uses: ./.github/actions/setup-uv-local - with: - python-version: ${{ matrix.python-version }} - - name: Setup Python ${{ matrix.python-version }} and install dependencies - run: | - uv sync --frozen --no-dev --group lint - - name: Run mypy - run: | - uv run --no-sync qa lint mypy . - - bandit: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v6 - with: - ref: ${{ inputs.BRANCH_REF }} - fetch-depth: 2 - - name: Configure uv environment - uses: ./.github/actions/setup-uv-local - - name: Setup Python ${{ env.UV_PYTHON }} and install dependencies - run: | - uv sync --frozen --no-dev --group lint - - name: Run bandit - run: | - uv run --no-sync qa lint bandit . diff --git a/.github/workflows/prs.yml b/.github/workflows/pr-ci-workflow.yml similarity index 78% rename from .github/workflows/prs.yml rename to .github/workflows/pr-ci-workflow.yml index 6c4d006f1..95593d1ca 100644 --- a/.github/workflows/prs.yml +++ b/.github/workflows/pr-ci-workflow.yml @@ -1,4 +1,11 @@ -name: Linter and tests (PRs) +name: "CI - Build · Lint · Tests" + +# Reusable workflow containing the actual CI jobs for pull request validation. +# This file is called by prs-entrypoint.yml and is intentionally separated so that +# event/routing logic stays in the entrypoint while the CI job set remains reusable. + +# This reusable workflow does not receive secrets automatically from the PR event. +# The caller workflow (prs-entrypoint.yml) must explicitly pass secrets when calling it. on: workflow_call: @@ -9,54 +16,31 @@ on: jobs: - approve: - runs-on: ubuntu-latest - steps: - - name: Approve - run: echo For security reasons, all pull requests need to be approved first before running the Premium Acceptance Tests. - - build-docs: - uses: ./.github/workflows/docs.yml - permissions: - contents: read - pull-requests: write - with: - branch_ref: ${{ inputs.BRANCH_REF }} - - linters: - uses: ./.github/workflows/linters.yml - permissions: - contents: read - pull-requests: write + build: + name: Build + uses: ./.github/workflows/build.yml with: - branch_ref: ${{ inputs.BRANCH_REF }} + BRANCH_REF: ${{ inputs.BRANCH_REF }} - tests-standard: - uses: ./.github/workflows/tests-standard.yml - permissions: - contents: read - pull-requests: write + static-analysis: + name: Lint + uses: ./.github/workflows/static-analysis.yml with: - branch_ref: ${{ inputs.BRANCH_REF }} + BRANCH_REF: ${{ inputs.BRANCH_REF }} - tests-premium: - uses: ./.github/workflows/tests-premium.yml - permissions: - contents: read - pull-requests: write + tests: + name: Tests + uses: ./.github/workflows/tests-unit.yml with: - branch_ref: ${{ inputs.BRANCH_REF }} - environment: Integrate Pull Request # Our dummy environment + BRANCH_REF: ${{ inputs.BRANCH_REF }} secrets: inherit - tests-ultimate: - uses: ./.github/workflows/tests-ultimate.yml - permissions: - contents: read - pull-requests: write + tests-acceptance: + name: Acceptance Tests + uses: ./.github/workflows/tests-acceptance.yml with: - branch_ref: ${{ inputs.BRANCH_REF }} - environment: Integrate Pull Request # Our dummy environment + BRANCH_REF: ${{ inputs.BRANCH_REF }} + environment: Integrate Pull Request secrets: inherit analyze: diff --git a/.github/workflows/pr_on_fork.yml b/.github/workflows/pr_on_fork.yml deleted file mode 100644 index fe255d2bf..000000000 --- a/.github/workflows/pr_on_fork.yml +++ /dev/null @@ -1,29 +0,0 @@ -name: Linter and tests (PRs raised from Forks) - -permissions: - actions: read - contents: read - pull-requests: write -concurrency: - group: ${{github.workflow}}-${{ github.event.pull_request.number }} - cancel-in-progress: true - -on: - pull_request_target: - branches: - - main - -jobs: - pr_jobs: - # github.event.pull_request object defined here: https://docs.github.com/en/rest/pulls/pulls?apiVersion=2026-03-10#get-a-pull-request - if: ${{ github.event.pull_request.head.repo.full_name != 'gitlabform/gitlabform' }} - uses: ./.github/workflows/prs.yml - permissions: - actions: read - contents: read - packages: read - pull-requests: write - security-events: write - with: - branch_ref: ${{ github.event.pull_request.head.sha }} - secrets: inherit \ No newline at end of file diff --git a/.github/workflows/pr_on_main_repo.yml b/.github/workflows/pr_on_main_repo.yml deleted file mode 100644 index 3bbb29887..000000000 --- a/.github/workflows/pr_on_main_repo.yml +++ /dev/null @@ -1,29 +0,0 @@ -name: Linter and tests (PRs raised on main repo) - -permissions: - actions: read - contents: read - pull-requests: write -concurrency: - group: ${{github.workflow}}-${{ github.event.pull_request.number }} - cancel-in-progress: true - -on: - pull_request: - branches: - - main - -jobs: - pr_jobs: - # github.event.pull_request object defined here: https://docs.github.com/en/rest/pulls/pulls?apiVersion=2026-03-10#get-a-pull-request - if: ${{ github.event.pull_request.head.repo.full_name == 'gitlabform/gitlabform' }} - uses: ./.github/workflows/prs.yml - permissions: - actions: read - contents: read - packages: read - pull-requests: write - security-events: write - with: - branch_ref: ${{ github.event.pull_request.head.sha }} - secrets: inherit \ No newline at end of file diff --git a/.github/workflows/prs-entrypoint-forks.yml b/.github/workflows/prs-entrypoint-forks.yml new file mode 100644 index 000000000..d665bb656 --- /dev/null +++ b/.github/workflows/prs-entrypoint-forks.yml @@ -0,0 +1,34 @@ +name: "CI - Fork PRs" + +# This workflow handles pull requests from forked repositories. +# It uses pull_request_target so the reusable CI workflow can receive explicit secrets. + +permissions: + actions: read + contents: read + pull-requests: write + security-events: write +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number }} + cancel-in-progress: true + +on: + pull_request_target: + branches: + - main + +jobs: + pr_jobs: + name: "Pipeline" + # github.event.pull_request object defined here: https://docs.github.com/en/rest/pulls/pulls?apiVersion=2026-03-10#get-a-pull-request + if: ${{ github.event.pull_request.head.repo.full_name != github.repository }} + uses: ./.github/workflows/pr-ci-workflow.yml + permissions: + actions: read + contents: read + packages: read + pull-requests: write + security-events: write + with: + BRANCH_REF: ${{ github.event.pull_request.head.sha }} + secrets: inherit diff --git a/.github/workflows/prs-entrypoint-main.yml b/.github/workflows/prs-entrypoint-main.yml new file mode 100644 index 000000000..2a2917c8e --- /dev/null +++ b/.github/workflows/prs-entrypoint-main.yml @@ -0,0 +1,34 @@ +name: "CI - PRs" + +# This workflow is the entrypoint for pull requests opened from host repository. +# Fork PRs are handled by prs-entrypoint-forks.yml using pull_request_target. +# It forwards the branch SHA and explicit secrets to the reusable workflow. + +permissions: + actions: read + contents: read + pull-requests: write +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number }} + cancel-in-progress: true + +on: + pull_request: + branches: + - main + +jobs: + pr_jobs: + name: "Pipeline" + # github.event.pull_request object defined here: https://docs.github.com/en/rest/pulls/pulls?apiVersion=2026-03-10#get-a-pull-request + if: ${{ github.event.pull_request.head.repo.full_name == github.repository }} + uses: ./.github/workflows/pr-ci-workflow.yml + permissions: + actions: read + contents: read + packages: read + pull-requests: write + security-events: write + with: + BRANCH_REF: ${{ github.event.pull_request.head.sha }} + secrets: inherit diff --git a/.github/workflows/static-analysis.yml b/.github/workflows/static-analysis.yml new file mode 100644 index 000000000..6c346402d --- /dev/null +++ b/.github/workflows/static-analysis.yml @@ -0,0 +1,56 @@ +name: Static Analysis + +on: + workflow_call: + inputs: + BRANCH_REF: + type: string + required: true + +permissions: + contents: read + +# This workflow currently covers lockfile verification plus lint-style checks. +# Bandit is treated here as a lightweight quality/security guardrail, not a full +# security scanning pipeline. Future security-only workflows can be introduced +# once heavier security tooling is needed. +jobs: + lockfile-verify: + name: Lockfile + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v6 + with: + ref: ${{ inputs.BRANCH_REF }} + - name: Configure uv environment + uses: ./.github/actions/setup-uv-local + - name: Verify that uv.lock is in sync + run: uv lock --check + + linting: + name: "${{ matrix.check == 'black' && 'Black' || matrix.check == 'mypy' && 'Mypy' || 'Bandit' }}" + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + check: [black, mypy, bandit] + steps: + - name: Checkout repository + uses: actions/checkout@v6 + with: + ref: ${{ inputs.BRANCH_REF }} + fetch-depth: 2 + - name: Configure uv environment + uses: ./.github/actions/setup-uv-local + - name: Install dependencies + run: uv sync --frozen --no-dev --group lint + - name: Run ${{ matrix.check }} + run: | + if [ "${{ matrix.check }}" == "black" ]; then + uv run --no-sync qa lint black --check . + elif [ "${{ matrix.check }}" == "mypy" ]; then + uv run --no-sync qa lint mypy . + elif [ "${{ matrix.check }}" == "bandit" ]; then + uv run --no-sync qa lint bandit . + fi diff --git a/.github/workflows/tests-acceptance.yml b/.github/workflows/tests-acceptance.yml new file mode 100644 index 000000000..924fa4ad1 --- /dev/null +++ b/.github/workflows/tests-acceptance.yml @@ -0,0 +1,91 @@ +name: Acceptance Tests + +on: + workflow_call: + inputs: + BRANCH_REF: + type: string + required: true + environment: + description: "Environment to run licensed acceptance tests in: 'Integrate Pull Request' for PRs (requires approval) or 'Main Tests' for main/release runs." + type: string + required: true + secrets: + GITLAB_EE_LICENSE: + required: false + GITLAB_EE_ULTIMATE_LICENSE: + required: false + CODECOV_TOKEN: + required: true + +permissions: + contents: read + actions: read # Required by codecov/codecov-action + +jobs: + acceptance-standard: + name: "GitLab ${{ matrix.flavor == 'ce' && 'CE' || 'EE' }}" + runs-on: ubuntu-latest + strategy: + matrix: + flavor: [ce, ee] + fail-fast: false + steps: + - name: Checkout repository + uses: actions/checkout@v6 + with: + ref: ${{ inputs.BRANCH_REF }} + fetch-depth: 2 + - name: Configure uv environment + uses: ./.github/actions/setup-uv-local + - name: Install dependencies + run: uv sync --frozen --no-dev --group test + - name: Start GitLab (${{ matrix.flavor }}) in docker + run: uv run --no-sync gitlab-local up --gitlab-flavor ${{ matrix.flavor }} + - name: Run Standard acceptance tests for ${{ matrix.flavor }} flavor + run: uv run --no-sync qa test tests/acceptance/standard --cov=. --cov-report=xml --durations=0 --reruns 3 --reruns-delay 10 --log-cli-level=WARNING + - name: Upload coverage + uses: Wandalen/wretry.action@v3 + with: + action: codecov/codecov-action@v3 + with: | + name: codecov-acceptance-test-standard-${{ matrix.flavor }} + flags: integration + token: ${{ secrets.CODECOV_TOKEN }} + attempt_limit: 5 + attempt_delay: 10000 + + acceptance-licensed: + name: "GitLab ${{ matrix.tier == 'premium' && 'Premium' || 'Ultimate' }}" + environment: ${{ inputs.environment }} + runs-on: ubuntu-latest + strategy: + matrix: + tier: [premium, ultimate] + fail-fast: false + steps: + - name: Checkout repository + uses: actions/checkout@v6 + with: + ref: ${{ inputs.BRANCH_REF }} + fetch-depth: 2 + - name: Configure uv environment + uses: ./.github/actions/setup-uv-local + - name: Install dependencies + run: uv sync --frozen --no-dev --group test + - name: Start GitLab (${{ matrix.tier }}) in docker + env: + GITLAB_EE_LICENSE: "${{ matrix.tier == 'premium' && secrets.GITLAB_EE_LICENSE || secrets.GITLAB_EE_ULTIMATE_LICENSE }}" + run: uv run --no-sync gitlab-local up + - name: Run acceptance Tests for ${{ matrix.tier }} features + run: uv run --no-sync qa test tests/acceptance/${{ matrix.tier }} --cov=. --cov-report=xml --durations=0 --reruns 3 --reruns-delay 10 --log-cli-level=WARNING + - name: Upload coverage + uses: Wandalen/wretry.action@v3 + with: + action: codecov/codecov-action@v3 + with: | + name: codecov-acceptance-test-${{ matrix.tier }} + flags: integration + token: ${{ secrets.CODECOV_TOKEN }} + attempt_limit: 5 + attempt_delay: 10000 diff --git a/.github/workflows/tests-premium.yml b/.github/workflows/tests-premium.yml deleted file mode 100644 index 66f60eb62..000000000 --- a/.github/workflows/tests-premium.yml +++ /dev/null @@ -1,56 +0,0 @@ -name: Tests premium - -on: - workflow_call: - inputs: - BRANCH_REF: - type: string - required: true - environment: - description: "Environment to run tests in: 'Integrate Pull Request' for PRs (requires approval) or 'Main' for Main." - type: string - required: true - -permissions: - contents: read - -jobs: - acceptance-tests-premium: - environment: - name: ${{ inputs.environment }} - runs-on: ubuntu-latest - strategy: - max-parallel: 5 - matrix: - python-version: [3.14] - fail-fast : false - steps: - - uses: actions/checkout@v6 - with: - ref: ${{ inputs.BRANCH_REF }} - - name: Configure uv environment - uses: ./.github/actions/setup-uv-local - with: - python-version: ${{ matrix.python-version }} - - name: Setup Python ${{ matrix.python-version }} and install dependencies - run: | - uv sync --frozen --no-dev --group test - - name: Start GitLab in Docker - env: - GITLAB_EE_LICENSE: ${{ secrets.GITLAB_EE_LICENSE }} - run: | - uv run --no-sync gitlab-local up - - name: Run acceptance tests for premium features - run: | - uv run --no-sync qa test tests/acceptance/premium --cov=. --cov-report=xml --durations=0 --reruns 3 --reruns-delay 10 --log-cli-level=WARNING - - name: Upload coverage to Codecov - uses: Wandalen/wretry.action@v3 - with: - action: codecov/codecov-action@v3 - with: | - name: codecov-acceptance-test-premium - flags: integration - fail_ci_if_error: true - token: 3e6d6cb5-fcdb-41ea-b134-f6c5856363e9 - attempt_limit: 5 - attempt_delay: 10000 diff --git a/.github/workflows/tests-standard.yml b/.github/workflows/tests-standard.yml deleted file mode 100644 index 554e3dd43..000000000 --- a/.github/workflows/tests-standard.yml +++ /dev/null @@ -1,176 +0,0 @@ -name: Tests standard - -on: - workflow_call: - inputs: - BRANCH_REF: - type: string - required: true - -permissions: - contents: read - -jobs: - lockfile-verify: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v6 - with: - ref: ${{ inputs.BRANCH_REF }} - - name: Configure uv environment - uses: ./.github/actions/setup-uv-local - - name: Verify that uv.lock is in sync with pyproject.toml - run: | - uv lock --check - - acceptance-tests: - runs-on: ubuntu-latest - strategy: - max-parallel: 5 - matrix: - python-version: [3.14] - fail-fast : false - steps: - - uses: actions/checkout@v6 - with: - ref: ${{ inputs.BRANCH_REF }} - fetch-depth: 2 - - name: Configure uv environment - uses: ./.github/actions/setup-uv-local - with: - python-version: ${{ matrix.python-version }} - - name: Setup Python ${{ matrix.python-version }} and install dependencies - run: | - uv sync --frozen --no-dev --group test - - name: Start GitLab in Docker - run: | - uv run --no-sync gitlab-local up - - name: Run standard acceptance tests against Enterprise Edition - run: uv run --no-sync qa test tests/acceptance/standard --cov=. --cov-report=xml --durations=0 --reruns 3 --reruns-delay 10 --log-cli-level=WARNING - - name: Upload coverage to Codecov - uses: Wandalen/wretry.action@v3 - with: - action: codecov/codecov-action@v3 - with: | - name: codecov-acceptance-test-standard - flags: integration - fail_ci_if_error: true - token: 3e6d6cb5-fcdb-41ea-b134-f6c5856363e9 - attempt_limit: 5 - attempt_delay: 10000 - - acceptance-tests-CE: - runs-on: ubuntu-latest - strategy: - max-parallel: 5 - matrix: - python-version: [ 3.14 ] - fail-fast: false - steps: - - uses: actions/checkout@v6 - with: - ref: ${{ inputs.BRANCH_REF }} - fetch-depth: 2 - - name: Configure uv environment - uses: ./.github/actions/setup-uv-local - with: - python-version: ${{ matrix.python-version }} - - name: Setup Python ${{ matrix.python-version }} and install dependencies - run: | - uv sync --frozen --no-dev --group test - - name: Start GitLab in Docker - run: | - uv run --no-sync gitlab-local up --gitlab-flavor ce - - name: Run standard acceptance tests against Community Edition - run: uv run --no-sync qa test tests/acceptance/standard --cov=. --cov-report=xml --durations=0 --reruns 3 --reruns-delay 10 --log-cli-level=WARNING - - name: Upload coverage to Codecov - uses: Wandalen/wretry.action@v3 - with: - action: codecov/codecov-action@v3 - with: | - name: codecov-acceptance-test-standard-ce - flags: integration - fail_ci_if_error: true - token: 3e6d6cb5-fcdb-41ea-b134-f6c5856363e9 - attempt_limit: 5 - attempt_delay: 10000 - - unit-tests: - runs-on: ubuntu-latest - strategy: - max-parallel: 1 - matrix: - python-version: [3.14, 3.12] - fail-fast : false - steps: - - uses: actions/checkout@v6 - with: - ref: ${{ inputs.BRANCH_REF }} - fetch-depth: 2 - - name: Configure uv environment - uses: ./.github/actions/setup-uv-local - with: - python-version: ${{ matrix.python-version }} - - name: Setup Python ${{ matrix.python-version }} and install dependencies - run: | - uv sync --frozen --no-dev --group test - - name: Run unit tests - run: | - uv run --no-sync qa test tests/unit --cov=. --cov-report=xml --log-cli-level=WARNING - - name: Upload coverage to Codecov - uses: Wandalen/wretry.action@v3 - with: - action: codecov/codecov-action@v3 - with: | - flags: unittests - fail_ci_if_error: true - token: 3e6d6cb5-fcdb-41ea-b134-f6c5856363e9 - attempt_limit: 5 - attempt_delay: 10000 - - security-tests: - runs-on: ubuntu-latest - strategy: - max-parallel: 5 - matrix: - python-version: [ 3.14, 3.12 ] - fail-fast: false - steps: - - uses: actions/checkout@v6 - with: - ref: ${{ inputs.BRANCH_REF }} - fetch-depth: 2 - - name: Configure uv environment - uses: ./.github/actions/setup-uv-local - with: - python-version: ${{ matrix.python-version }} - - name: Setup Python ${{ matrix.python-version }} and install dependencies - run: | - uv sync --frozen --no-dev --group test - - name: Run security tests - run: | - uv run --no-sync qa lint bandit gitlabform - - smoke-tests: - strategy: - max-parallel: 2 - matrix: - os: [ubuntu-latest, windows-latest, macos-latest] - python-version: [ 3.14, 3.12 ] - fail-fast: true - runs-on: ${{ matrix.os }} - steps: - - uses: actions/checkout@v6 - with: - ref: ${{ inputs.BRANCH_REF }} - fetch-depth: 2 - - name: Configure uv environment - uses: ./.github/actions/setup-uv-local - with: - python-version: ${{ matrix.python-version }} - - name: Setup Python ${{ matrix.python-version }} and install dependencies - run: | - uv sync --frozen --no-dev --group test - - name: Run smoke tests - run: | - uv run --no-sync gitlabform -V diff --git a/.github/workflows/tests-ultimate.yml b/.github/workflows/tests-ultimate.yml deleted file mode 100644 index 35552fac1..000000000 --- a/.github/workflows/tests-ultimate.yml +++ /dev/null @@ -1,59 +0,0 @@ -name: Tests Ultimate - -on: - workflow_call: - inputs: - BRANCH_REF: - type: string - required: true - environment: - description: "Environment to run tests in: 'Integrate Pull Request' for PRs (requires approval) or 'Main' for Main." - type: string - required: true - -permissions: - contents: read - -jobs: - acceptance-tests-ultimate: - environment: - name: ${{ inputs.environment }} - runs-on: ubuntu-latest - strategy: - max-parallel: 5 - matrix: - python-version: [3.14] - fail-fast : false - steps: - - uses: actions/checkout@v6 - with: - ref: ${{ inputs.BRANCH_REF }} - - name: Configure uv environment - uses: ./.github/actions/setup-uv-local - with: - python-version: ${{ matrix.python-version }} - - name: Setup Python ${{ matrix.python-version }} and install dependencies - # uv will automatically create and use a virtual environment for the specified Python version - # Only install dependencies needed for running tests, to save time and resources. - run: | - uv sync --frozen --no-dev --group test - - name: Start GitLab in Docker - env: - # requested via: https://handbook.gitlab.com/handbook/marketing/developer-relations/contributor-success/community-contributors-workflows/#contributing-to-the-gitlab-enterprise-edition-ee - # https://gitlab.com/gitlab-org/developer-relations/contributor-success/team-task/-/issues - GITLAB_EE_LICENSE: ${{ secrets.GITLAB_EE_ULTIMATE_LICENSE }} - run: | - uv run --no-sync gitlab-local up - - name: Run acceptance tests for ultimate features - run: | - uv run --no-sync qa test tests/acceptance/ultimate --cov=. --cov-report=xml --durations=0 --reruns 3 --reruns-delay 10 --log-cli-level=WARNING - - name: Upload coverage to Codecov - uses: Wandalen/wretry.action@v3 - with: - action: codecov/codecov-action@v3 - with: | - name: codecov-acceptance-test-ultimate - flags: integration - token: 3e6d6cb5-fcdb-41ea-b134-f6c5856363e9 - attempt_limit: 5 - attempt_delay: 10000 \ No newline at end of file diff --git a/.github/workflows/tests-unit.yml b/.github/workflows/tests-unit.yml new file mode 100644 index 000000000..9009f1f9c --- /dev/null +++ b/.github/workflows/tests-unit.yml @@ -0,0 +1,49 @@ +name: Unit Tests +# Reusable workflow for unit tests only. + +on: + workflow_call: + inputs: + BRANCH_REF: + type: string + required: true + secrets: + CODECOV_TOKEN: + required: true + +permissions: + contents: read + +jobs: + unit: + name: "Unit (${{ matrix.python-version }})" + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + python-version: ["3.14", "3.12"] + steps: + - name: Checkout repository + uses: actions/checkout@v6 + with: + ref: ${{ inputs.BRANCH_REF }} + fetch-depth: 2 + - name: Configure uv environment + uses: ./.github/actions/setup-uv-local + with: + python-version: ${{ matrix.python-version }} + - name: Install dependencies + run: uv sync --frozen --no-dev --group test + - name: Run unit tests + run: uv run --no-sync qa test tests/unit --cov=. --cov-report=xml --log-cli-level=WARNING + - name: Upload coverage to Codecov + uses: Wandalen/wretry.action@v3 + with: + action: codecov/codecov-action@v3 + with: | + name: unit-tests-${{ matrix.python-version }} + flags: unittests + fail_ci_if_error: true + token: ${{ secrets.CODECOV_TOKEN }} + attempt_limit: 5 + attempt_delay: 10000 diff --git a/README.md b/README.md index 8df6818f1..83c1f5e56 100644 --- a/README.md +++ b/README.md @@ -15,4 +15,4 @@ ...and more using hierarchical configuration written in YAML. -Please see the project site for more information. +Please see [the project site](https://gitlabform.github.io/gitlabform/) for more information. diff --git a/docs/contrib/releases.md b/docs/contrib/releases.md index c5afda5b2..72f951299 100644 --- a/docs/contrib/releases.md +++ b/docs/contrib/releases.md @@ -20,4 +20,6 @@ We try to follow the [PEP 440](https://peps.python.org/pep-0440/) versioning sch - Upload new version of gitlabform to [pypi package registry under gitlabform](https://pypi.org/project/gitlabform/). - A corresponding [GitHub release](https://github.com/gitlabform/gitlabform/releases) will be created that references the new tag. + The release workflow also verifies that the commit on `main` passed the normal main-branch checks before publishing. If a release must proceed despite issues, a maintainer can manually trigger the `Releases` workflow and enable `force: true` to bypass that verification. + 3. Edit the release in GitHub and copy the changelog entry into its description.