name: CI/CD

on:
  merge_group:
  pull_request:
    branches:
      - dev
      - main
      - v1
  push:
    branches:
      - dev
      - main
      - v1
    tags:
      - 'v*'
  workflow_dispatch:
  workflow_run:
    workflows: ['Update pre-commit hooks']
    branches:
      - update-pre-commit-hooks
    types:
      - completed

env:
  FORCE_COLOR: 1

concurrency:
  cancel-in-progress: ${{ !contains(fromJSON('["dev", "main", "v1"]'), github.ref_name) }}
  group: ${{ github.repository }}-${{ github.workflow }}-${{ github.head_ref || github.ref_name }}

jobs:
  pre-commit:
    name: Run pre-commit
    runs-on: ubuntu-24.04
    steps:
      - name: Check out repository
        uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3

      - name: Set up Python
        uses: actions/setup-python@83679a892e2d95755f2dac6acb0bfd1e9ac5d548
        with:
          check-latest: true
          python-version: '3.14'

      - name: Run pre-commit
        uses: pre-commit/action@2c7b3805fd2a0fd8c1884dcaebf91fc102a13ecd

  code-ql:
    name: CodeQL
    needs:
      - pre-commit
    permissions:
      security-events: write
    runs-on: ubuntu-24.04
    steps:
      - name: Check out repository
        uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3

      - name: Initialize CodeQL
        uses: github/codeql-action/init@fdbfb4d2750291e159f0156def62b853c2798ca2
        with:
          languages: python

      - name: Perform CodeQL Analysis
        uses: github/codeql-action/analyze@fdbfb4d2750291e159f0156def62b853c2798ca2
        with:
          category: '/language:python'

  test:
    name: Test Python ${{ matrix.python-version }} on ${{ matrix.os }}
    runs-on: ${{ matrix.os }}
    needs:
      - pre-commit
    strategy:
      matrix:
        os:
          - macos-latest
          - ubuntu-latest
          - windows-latest
        python-version:
          - '3.10'
          - '3.11'
          - '3.12'
          - '3.13'
          - '3.14'
    steps:
      - name: Check out repository
        uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3

      - name: Set up Python ${{ matrix.python-version }}
        uses: actions/setup-python@83679a892e2d95755f2dac6acb0bfd1e9ac5d548
        with:
          allow-prereleases: true
          cache: pip
          cache-dependency-path: |
            requirements/runtime.txt
            requirements/tests.txt
          check-latest: true
          python-version: ${{ matrix.python-version }}

      - name: Install dependencies
        run: |
          python -m pip install --upgrade pip
          python -m pip install --requirement requirements/tests.txt
          python -m pip install .

      - name: Run tests
        run: |
          make test

      - name: Upload coverage to Codecov
        uses: codecov/codecov-action@5a1091511ad55cbe89839c7260b706298ca349f7
        with:
          token: ${{ secrets.CODECOV_TOKEN }}

  build:
    name: Build distribution
    needs: test
    runs-on: ubuntu-24.04
    steps:
      - name: Check out repository
        uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3

      - name: Set up Python
        uses: actions/setup-python@83679a892e2d95755f2dac6acb0bfd1e9ac5d548
        with:
          cache: pip
          cache-dependency-path: |
            requirements/build.txt
          check-latest: true
          python-version: '3.14'

      - name: Install dependencies
        run: |
          python -m pip install --upgrade pip
          python -m pip install -r requirements/build.txt
          python -m pip install .

      - name: Build distribution
        run: |
          make package

      - name: Upload package artifacts
        uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4
        with:
          name: dist
          path: dist

      - name: Set version
        if: startsWith(github.event.ref, 'refs/tags/v')
        run: echo "VERSION=$(echo ${{ github.ref_name }} | sed 's/^v//')" >> $GITHUB_ENV

      - name: Generate SBOM
        if: startsWith(github.event.ref, 'refs/tags/v')
        run: |
          make sbom > holidays-${{ env.VERSION }}-sbom.json

      - name: Upload SBOM
        if: startsWith(github.event.ref, 'refs/tags/v')
        uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4
        with:
          name: sbom
          path: holidays-${{ env.VERSION }}-sbom.json

  test-build:
    name: Test build on ${{ matrix.os }}
    runs-on: ${{ matrix.os }}
    needs: build
    strategy:
      matrix:
        os:
          - macos-latest
          - ubuntu-latest
          - windows-latest
    steps:
      - name: Check out repository
        uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3

      - name: Set up Python
        uses: actions/setup-python@83679a892e2d95755f2dac6acb0bfd1e9ac5d548
        with:
          cache: pip
          cache-dependency-path: |
            requirements/runtime.txt
            requirements/tests.txt
          check-latest: true
          python-version: '3.14'

      - name: Get package artifacts
        uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53
        with:
          name: dist
          path: dist

      - name: Run tests
        shell: bash
        run: |
          rm -rf holidays
          python -m pip install --requirement requirements/tests.txt
          python -m pip install `ls dist/*.whl`
          pytest --dist loadscope --numprocesses auto tests/countries tests/financial
          python -m pip uninstall -y holidays python-dateutil six
          python -m pip install `ls dist/*.tar.gz`
          pytest --dist loadscope --numprocesses auto tests/countries tests/financial

  test-docs:
    name: Test docs build
    runs-on: ubuntu-24.04
    needs: test
    steps:
      - name: Check out repository
        uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3

      - name: Set Up Python
        uses: actions/setup-python@83679a892e2d95755f2dac6acb0bfd1e9ac5d548
        with:
          cache: pip
          cache-dependency-path: requirements/docs.txt
          python-version: '3.14'

      - name: Install dependencies
        run: |
          python -m pip install --requirement requirements/docs.txt
          python -m pip install .

      - name: Build docs
        run: |
          make doc

  publish-main:
    name: Publish generated artifacts
    if: |
      github.repository == 'vacanza/holidays' &&
      github.event_name == 'push' &&
      startsWith(github.event.ref, 'refs/tags/v')
    environment: main
    needs:
      - test-build
      - test-docs
    permissions:
      contents: write
      id-token: write
    runs-on: ubuntu-24.04
    steps:
      - name: Download package artifacts
        uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53
        with:
          name: dist
          path: dist

      - name: Publish package distributions to PyPI
        uses: pypa/gh-action-pypi-publish@ed0c53931b1dc9bd32cbe73a98c7f6766f8a527e

  sign-artifacts:
    name: Create SHA1 checksums and Sigstore signatures
    runs-on: ubuntu-24.04
    needs:
      - publish-main
    permissions:
      id-token: write
    steps:
      - name: Download package artifacts
        uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53
        with:
          name: dist
          path: dist

      - name: Compute SHA1 checksums
        run: |
          cd dist
          for file in *; do
            sha1sum "$file" > "$file.sha1"
          done

      - name: Sign the files using Sigstore
        uses: sigstore/gh-action-sigstore-python@f832326173235dcb00dd5d92cd3f353de3188e6c
        with:
          inputs: |
            ./dist/*.tar.gz
            ./dist/*.whl

      - name: Upload package dist and signatures
        uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4
        with:
          name: signed-artifacts
          path: dist

  update-github-release:
    name: Update GitHub release with SBOM and signed artifacts
    runs-on: ubuntu-24.04
    needs:
      - sign-artifacts
    permissions:
      contents: write
    steps:
      - name: Download SBOM
        uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53
        with:
          name: sbom

      - name: Download package dist and signatures
        uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53
        with:
          name: signed-artifacts
          path: dist

      - name: Update Github release
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        run: |
          gh release upload --repo vacanza/holidays ${{ github.ref_name }} dist/*
          gh release upload --repo vacanza/holidays ${{ github.ref_name }} holidays-*-sbom.json
