ci(workflows): update permissions and trigger #203
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Linting and Testing | |
| on: | |
| push: | |
| branches-ignore: | |
| - master | |
| - release/** | |
| paths-ignore: | |
| - '**.md' | |
| - 'docs/**' | |
| tags-ignore: | |
| - v** | |
| workflow_call: | |
| permissions: | |
| contents: read | |
| packages: read | |
| concurrency: | |
| group: ci-${{ github.workflow }}-${{ github.ref }} | |
| cancel-in-progress: true | |
| jobs: | |
| ruff: | |
| name: Linting and Formatting | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v5 | |
| - name: Set up Python | |
| uses: actions/setup-python@v5 | |
| with: | |
| python-version: '3.12' | |
| - name: Install Poetry | |
| uses: snok/install-poetry@v1 | |
| with: | |
| version: 'latest' | |
| virtualenvs-create: true | |
| virtualenvs-in-project: true | |
| - name: Load cached venv | |
| id: cached-poetry-dependencies | |
| uses: actions/cache@v4 | |
| with: | |
| path: .venv | |
| key: venv-ruff-${{ runner.os }}-${{ hashFiles('**/poetry.lock') }} | |
| - name: Install dependencies | |
| if: steps.cached-poetry-dependencies.outputs.cache-hit != 'true' | |
| run: poetry install --only dev | |
| - name: Ruff version | |
| run: poetry run ruff --version | |
| - name: Check formatting | |
| run: poetry run ruff format --check . | |
| - name: Lint (GitHub Annotations) | |
| run: poetry run ruff check --output-format=github . | |
| run-unit-tests: | |
| name: Run unit tests | |
| needs: ruff | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| os: [ubuntu-latest, macos-latest, windows-latest] | |
| python-version: ["3.9", "3.10", "3.11", "3.12", "3.13", "3.14"] | |
| defaults: | |
| run: | |
| shell: bash | |
| runs-on: ${{ matrix.os }} | |
| timeout-minutes: 30 | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v5 | |
| - name: Set up Python | |
| uses: actions/setup-python@v5 | |
| with: | |
| python-version: ${{ matrix.python-version }} | |
| - name: Install Poetry | |
| uses: snok/install-poetry@v1 | |
| with: | |
| version: 'latest' | |
| virtualenvs-create: true | |
| virtualenvs-in-project: true | |
| - name: Load cached venv | |
| id: cached-poetry-dependencies | |
| uses: actions/cache@v4 | |
| with: | |
| path: .venv | |
| key: venv-tests-${{ runner.os }}-${{ hashFiles('**/poetry.lock') }} | |
| - name: Install dependencies | |
| run: poetry install --no-interaction | |
| - name: Run unit tests with coverage | |
| run: | | |
| poetry run pytest \ | |
| --cov=c2pie \ | |
| -m "not e2e" \ | |
| --maxfail=1 \ | |
| -v | |
| - name: Upload coverage artifact | |
| if: (matrix.python-version == '3.12') && (matrix.os == 'ubuntu-latest') | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| include-hidden-files: true | |
| name: coverage-unit | |
| path: .coverage | |
| run-e2e-tests: | |
| name: Run e2e tests | |
| needs: ruff | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| os: [ubuntu-latest, macos-latest, windows-latest] | |
| python-version: ["3.9", "3.10", "3.11", "3.12", "3.13", "3.14"] | |
| defaults: | |
| run: | |
| shell: bash | |
| runs-on: ${{ matrix.os }} | |
| timeout-minutes: 30 | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v5 | |
| - name: Set up Python | |
| uses: actions/setup-python@v5 | |
| with: | |
| python-version: ${{ matrix.python-version }} | |
| - name: Install Poetry | |
| uses: snok/install-poetry@v1 | |
| with: | |
| version: 'latest' | |
| virtualenvs-create: true | |
| virtualenvs-in-project: true | |
| - name: Load cached venv | |
| id: cached-poetry-dependencies | |
| uses: actions/cache@v4 | |
| with: | |
| path: .venv | |
| key: venv-tests-${{ runner.os }}-${{ hashFiles('**/poetry.lock') }} | |
| - name: Install dependencies | |
| run: poetry install --no-interaction | |
| - name: Install Rust toolchain and c2patool | |
| uses: baptiste0928/cargo-install@v3 | |
| with: | |
| crate: c2patool | |
| - name: Verify if c2patool is installed | |
| run: | | |
| c2patool -V | |
| - name: Run e2e tests with coverage | |
| run: | | |
| poetry run pytest tests/c2pa/e2e_test.py \ | |
| --cov=c2pie \ | |
| -v | |
| env: | |
| C2PIE_KEY_FILEPATH: ${{ vars.C2PIE_KEY_FILEPATH }} | |
| C2PIE_CERT_FILEPATH: ${{ vars.C2PIE_CERT_FILEPATH }} | |
| - name: Upload coverage artifact | |
| if: (matrix.python-version == '3.12') && (matrix.os == 'ubuntu-latest') | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| include-hidden-files: true | |
| name: coverage-e2e | |
| path: .coverage | |
| combine-coverage: | |
| name: Combine and upload coverage | |
| needs: [run-unit-tests, run-e2e-tests] | |
| if: always() | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v5 | |
| - name: Set up Python | |
| uses: actions/setup-python@v5 | |
| with: | |
| python-version: "3.12" | |
| - name: Install coverage | |
| run: python -m pip install coverage[toml] | |
| - name: Download unit coverage | |
| uses: actions/download-artifact@v5 | |
| with: | |
| name: coverage-unit | |
| path: coverage-unit | |
| continue-on-error: true | |
| - name: Download e2e coverage | |
| uses: actions/download-artifact@v5 | |
| with: | |
| name: coverage-e2e | |
| path: coverage-e2e | |
| continue-on-error: true | |
| - name: Check if artifacts exist | |
| id: check | |
| run: | | |
| if [ -f ./coverage-e2e/.coverage ] && [ -f ./coverage-unit/.coverage ]; then | |
| echo "ready=true" >> $GITHUB_OUTPUT | |
| else | |
| echo "ready=false" >> $GITHUB_OUTPUT | |
| fi | |
| - name: Fail if coverage missing | |
| if: steps.check.outputs.ready != 'true' | |
| run: | | |
| echo "Coverage artifacts not found — skipping coverage report" | |
| exit 1 | |
| - name: Combine coverage reports | |
| run: | | |
| coverage combine ./coverage-e2e/.coverage ./coverage-unit/.coverage | |
| coverage xml -o coverage-combined.xml | |
| coverage report --format=markdown >> $GITHUB_STEP_SUMMARY | |
| coverage json -o coverage-combined.json | |
| - name: Upload combined coverage artifact | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: coverage-combined | |
| path: coverage-combined.json | |
| update-coverage: | |
| name: Update Coverage | |
| runs-on: ubuntu-latest | |
| needs: [combine-coverage] | |
| permissions: | |
| contents: write | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v5 | |
| - name: Download jq | |
| run: | | |
| sudo apt install jq | |
| - name: Download combined coverage | |
| uses: actions/download-artifact@v5 | |
| with: | |
| name: coverage-combined | |
| path: coverage-combined | |
| # Find existing score and color by line matching in README and get calculated coverage from json file | |
| - name: Find existing and calculated test coverage scores and existing color | |
| run: | | |
| echo "EXISTING_COVERAGE=$(grep -oP '(?<=coverage-)\d+' README.md | head -n1)" >> "$GITHUB_ENV" | |
| echo "EXISTING_BADGE_COLOR=$(grep -oP '(?<=%25-)[^?]+' README.md | head -n1)" >> "$GITHUB_ENV" | |
| echo "CALCULATED_COVERAGE=$(jq -r .totals.percent_covered_display coverage-combined/coverage-combined.json)" >> "$GITHUB_ENV" | |
| - name: Check found coverage scores and color | |
| run: | | |
| echo $EXISTING_COVERAGE | |
| echo $CALCULATED_COVERAGE | |
| echo $EXISTING_BADGE_COLOR | |
| # 0-60: red; 60-70: orange; 70-80: yellow; 80-90: yellowish green; 90-100: green | |
| # set new color and then add its variable to workflow's environment | |
| - name: Define new badge color | |
| if: ${{ env.EXISTING_COVERAGE != env.CALCULATED_COVERAGE }} | |
| run: | | |
| python3 - <<'PY' | |
| import os | |
| new_coverage = int(os.getenv("CALCULATED_COVERAGE")) | |
| if new_coverage < 60: | |
| new_badge_color = "crimson" | |
| elif 60 <= new_coverage < 70: | |
| new_badge_color = "orange" | |
| elif 70 <= new_coverage < 80: | |
| new_badge_color = "yellow" | |
| elif 80 <= new_coverage < 90: | |
| new_badge_color = "olivedrab" | |
| elif new_coverage >= 90: | |
| new_badge_color = "forestgreen" | |
| env_file = os.getenv('GITHUB_ENV') | |
| with open(env_file, "a") as f: | |
| f.write(f"NEW_BADGE_COLOR={new_badge_color}") | |
| PY | |
| # Find existing badge url in README assuming that it looks like we expect (must be perfect match) | |
| # Replace it with calculated url, where score and color are new | |
| - name: Replace badge URL in README | |
| if: ${{ env.EXISTING_COVERAGE != env.CALCULATED_COVERAGE }} | |
| run: | | |
| export EXISTING_COVERAGE_BADGE_URL="https://img.shields.io/badge/coverage-$EXISTING_COVERAGE%25-$EXISTING_BADGE_COLOR?logo=codecov&logoColor=ff9d1c" | |
| export CALCULATED_COVERAGE_BADGE_URL="https://img.shields.io/badge/coverage-$CALCULATED_COVERAGE%25-$NEW_BADGE_COLOR?logo=codecov&logoColor=ff9d1c" | |
| echo $EXISTING_COVERAGE_BADGE_URL | |
| echo $CALCULATED_COVERAGE_BADGE_URL | |
| python3 - <<'PY' | |
| import io, sys, os | |
| old_badge_url = os.getenv("EXISTING_COVERAGE_BADGE_URL") | |
| new_badge_url = os.getenv("CALCULATED_COVERAGE_BADGE_URL") | |
| path = "README.md" | |
| if not old_badge_url or not new_badge_url: | |
| sys.exit("Either existing or calculated badge URL doesn't exist") | |
| with io.open(path, "r", encoding="utf-8") as f: | |
| content = f.read() | |
| if old_badge_url in content: | |
| content = content.replace(old_badge_url, new_badge_url) | |
| with io.open(path, "w", encoding="utf-8") as f: | |
| f.write(content) | |
| print("Replaced coverage badge URL in README.md") | |
| else: | |
| print("Old URL not found in README.md, no replacement made") | |
| PY | |
| - name: Commit README changes | |
| if: ${{ env.EXISTING_COVERAGE != env.CALCULATED_COVERAGE }} | |
| run: | | |
| git config --global user.name github-actions[bot] | |
| git config --global user.email 41898282+github-actions[bot]@users.noreply.github.com | |
| git add README.md | |
| git commit -m "docs(readme): bring test coverage score up to date" | |
| git push origin ${{ github.ref }} |