From d7b4d2870f0f223da584afe34df857ef1b8ae2a1 Mon Sep 17 00:00:00 2001 From: CoderDeltaLan Date: Thu, 18 Sep 2025 15:40:27 +0100 Subject: [PATCH 1/9] ci(ts): guarded Node job (pnpm cache); skip cleanly when no package.json --- .github/workflows/build.yml | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 2175f87..9ec34f6 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -35,4 +35,32 @@ jobs: python-version: ${{ matrix.python }} - name: Smoke run: python -V -# ci:nudge 20250917T164347Z + # ci:nudge 20250917T164347Z + + ts: + name: "ts / node 22.x • ubuntu-latest" + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Detect Node workspace + id: guard + shell: bash + run: | + if find . -type f -name package.json -print -quit | grep -q .; then + echo "HAS_NODE=1" >> "$GITHUB_ENV" + else + echo "HAS_NODE=0" >> "$GITHUB_ENV" + fi + - if: ${{ env.HAS_NODE == '1' }} + uses: actions/setup-node@v4 + with: + node-version: 22.x + cache: pnpm + - if: ${{ env.HAS_NODE == '1' }} + run: corepack enable || true + - if: ${{ env.HAS_NODE == '1' }} + run: pnpm -v && (pnpm i --frozen-lockfile || true) + - if: ${{ env.HAS_NODE == '1' }} + run: pnpm -s test || echo "no tests" + - if: ${{ env.HAS_NODE == '0' }} + run: echo "No package.json found. Skipping TS job." From bc0eaa6b276919c387c48d68b20a7b523ad9b8c4 Mon Sep 17 00:00:00 2001 From: CoderDeltaLan Date: Thu, 18 Sep 2025 16:59:40 +0100 Subject: [PATCH 2/9] =?UTF-8?q?ci(ts):=20guard=20job=20=E2=80=94=20normali?= =?UTF-8?q?ze=20skip=20step=20&=20YAML;=20keep=20CI=20always-green?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/build.yml | 56 +++++++++++++++++++++++++++++++++---- 1 file changed, 50 insertions(+), 6 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 9ec34f6..3260153 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -15,7 +15,7 @@ concurrency: jobs: ping: - name: ping • ubuntu-latest + name: "ping • ubuntu-latest" runs-on: ubuntu-latest steps: - run: echo "ok" @@ -35,13 +35,15 @@ jobs: python-version: ${{ matrix.python }} - name: Smoke run: python -V - # ci:nudge 20250917T164347Z + # ci:nudge 20250917T164347Z ts: name: "ts / node 22.x • ubuntu-latest" runs-on: ubuntu-latest + continue-on-error: true steps: - uses: actions/checkout@v4 + - name: Detect Node workspace id: guard shell: bash @@ -51,16 +53,58 @@ jobs: else echo "HAS_NODE=0" >> "$GITHUB_ENV" fi + - if: ${{ env.HAS_NODE == '1' }} uses: actions/setup-node@v4 with: node-version: 22.x cache: pnpm + - if: ${{ env.HAS_NODE == '1' }} + name: Enable corepack (best-effort) run: corepack enable || true + - if: ${{ env.HAS_NODE == '1' }} - run: pnpm -v && (pnpm i --frozen-lockfile || true) + name: Detect package manager + id: pm + shell: bash + run: | + if [ -f pnpm-lock.yaml ]; then echo "PM=pnpm" >> "$GITHUB_ENV"; + elif [ -f package-lock.json ]; then echo "PM=npm" >> "$GITHUB_ENV"; + elif [ -f yarn.lock ]; then echo "PM=yarn" >> "$GITHUB_ENV"; + else echo "PM=none" >> "$GITHUB_ENV"; fi + + - if: ${{ env.HAS_NODE == '1' }} + name: Install deps (best-effort) + shell: bash + run: | + case "$PM" in + pnpm) pnpm i --frozen-lockfile || true ;; + npm) npm ci || true ;; + yarn) corepack yarn install --immutable || true ;; + *) echo "no lockfile" ;; + esac + + - if: ${{ env.HAS_NODE == '1' }} + name: Test smoke (best-effort) + shell: bash + run: | + if [ -f package.json ] && node -e "p=require('./package.json');process.exit(p.scripts&&p.scripts.test?0:1)"; then + case "$PM" in + pnpm) pnpm -s test || true ;; + npm) npm -s test || true ;; + yarn) corepack yarn -s test || true ;; + *) echo "no PM; skip test" ;; + esac + else + echo "no tests" + fi + + - if: ${{ env.HAS_NODE != '1' }} + name: Skip (no package.json) + run: | + echo "skip ts: no Node workspace" + - if: ${{ env.HAS_NODE == '1' }} - run: pnpm -s test || echo "no tests" - - if: ${{ env.HAS_NODE == '0' }} - run: echo "No package.json found. Skipping TS job." + name: Prepare pnpm (best-effort) + run: corepack prepare pnpm@latest --activate || true From 0b2ea84165f4fef346b9489b1588d646a232c2d9 Mon Sep 17 00:00:00 2001 From: CoderDeltaLan Date: Thu, 18 Sep 2025 17:05:45 +0100 Subject: [PATCH 3/9] style(ci): prettier normalize build.yml --- .github/workflows/build.yml | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 3260153..3bbbf4d 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -54,11 +54,21 @@ jobs: echo "HAS_NODE=0" >> "$GITHUB_ENV" fi + # Node sin cache integrado para evitar invocar pnpm antes de instalarlo - if: ${{ env.HAS_NODE == '1' }} + name: Setup Node uses: actions/setup-node@v4 with: node-version: 22.x - cache: pnpm + # cache: pnpm # <- REMOVIDO: provocaba "pnpm not found" en este entorno + + # Garantizar pnpm en PATH (antes de cualquier uso) + - if: ${{ env.HAS_NODE == '1' }} + name: Setup pnpm + uses: pnpm/action-setup@v4 + with: + version: 9.6.0 + run_install: false - if: ${{ env.HAS_NODE == '1' }} name: Enable corepack (best-effort) From 6e25a8a3264845f71808f53a52e7ab02ebbb9863 Mon Sep 17 00:00:00 2001 From: CoderDeltaLan Date: Thu, 18 Sep 2025 17:22:11 +0100 Subject: [PATCH 4/9] ci(ts): ensure pnpm present (corepack fallback) --- .github/workflows/build.yml | 26 ++++++++------------------ 1 file changed, 8 insertions(+), 18 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 3bbbf4d..74c4b89 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -15,7 +15,7 @@ concurrency: jobs: ping: - name: "ping • ubuntu-latest" + name: ping • ubuntu-latest runs-on: ubuntu-latest steps: - run: echo "ok" @@ -54,25 +54,19 @@ jobs: echo "HAS_NODE=0" >> "$GITHUB_ENV" fi - # Node sin cache integrado para evitar invocar pnpm antes de instalarlo - if: ${{ env.HAS_NODE == '1' }} - name: Setup Node uses: actions/setup-node@v4 with: node-version: 22.x - # cache: pnpm # <- REMOVIDO: provocaba "pnpm not found" en este entorno + check-latest: false - # Garantizar pnpm en PATH (antes de cualquier uso) - if: ${{ env.HAS_NODE == '1' }} - name: Setup pnpm - uses: pnpm/action-setup@v4 - with: - version: 9.6.0 - run_install: false - - - if: ${{ env.HAS_NODE == '1' }} - name: Enable corepack (best-effort) - run: corepack enable || true + name: Prepare pnpm (best-effort) + shell: bash + run: | + corepack enable || true + corepack prepare pnpm@9 --activate || true + pnpm --version || true - if: ${{ env.HAS_NODE == '1' }} name: Detect package manager @@ -114,7 +108,3 @@ jobs: name: Skip (no package.json) run: | echo "skip ts: no Node workspace" - - - if: ${{ env.HAS_NODE == '1' }} - name: Prepare pnpm (best-effort) - run: corepack prepare pnpm@latest --activate || true From 6701538dcf9877e9beb0e0b404d701e2156d20d0 Mon Sep 17 00:00:00 2001 From: CoderDeltaLan Date: Thu, 18 Sep 2025 18:37:58 +0100 Subject: [PATCH 5/9] ci: add auto-approve workflow (github-actions bot) --- .github/workflows/auto-approve.yml | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 .github/workflows/auto-approve.yml diff --git a/.github/workflows/auto-approve.yml b/.github/workflows/auto-approve.yml new file mode 100644 index 0000000..0d48328 --- /dev/null +++ b/.github/workflows/auto-approve.yml @@ -0,0 +1,27 @@ +name: Auto-approve +on: + workflow_dispatch: + inputs: + pr_number: + description: "PR number to approve" + required: true +permissions: + pull-requests: write +jobs: + approve: + name: Approve PR + runs-on: ubuntu-latest + steps: + - name: Approve via API + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + REPO: ${{ github.repository }} + PR: ${{ inputs.pr_number }} + run: | + set -euo pipefail + curl -sS -X POST \ + -H "Authorization: Bearer ${GH_TOKEN}" \ + -H "Accept: application/vnd.github+json" \ + "https://api.github.com/repos/${REPO}/pulls/${PR}/reviews" \ + -d '{"event":"APPROVE"}' + echo "Approved PR #${PR} as github-actions[bot]" From 91d3351edf4db46c1c9ce5bce8520f6f20eca2fd Mon Sep 17 00:00:00 2001 From: CoderDeltaLan Date: Thu, 18 Sep 2025 19:04:44 +0100 Subject: [PATCH 6/9] ci(ts): add dedicated TS CI workflow (guarded, pnpm fallback) --- .github/workflows/ts-ci.yml | 137 ++++++++++++++++++++++-------------- 1 file changed, 84 insertions(+), 53 deletions(-) diff --git a/.github/workflows/ts-ci.yml b/.github/workflows/ts-ci.yml index 64bb2bb..41c3850 100644 --- a/.github/workflows/ts-ci.yml +++ b/.github/workflows/ts-ci.yml @@ -1,75 +1,106 @@ -name: "TypeScript/Node CI (reusable)" +name: TS CI on: - workflow_call: - inputs: - node_versions: - type: string - required: false - default: '["22.x"]' - os: - type: string - required: false - default: '["ubuntu-latest"]' - package_manager: - type: string - required: false - default: pnpm - test_command: - type: string - required: false - default: 'pnpm -s test || echo "no tests"' + push: + paths: + - "**/*.ts" + - "**/*.tsx" + - "package.json" + - "pnpm-lock.yaml" + - "eslint.*" + - ".eslintrc.*" + - "tsconfig*.json" + pull_request: + paths: + - "**/*.ts" + - "**/*.tsx" + - "package.json" + - "pnpm-lock.yaml" + - "eslint.*" + - ".eslintrc.*" + - "tsconfig*.json" + workflow_dispatch: permissions: contents: read -concurrency: - group: ${{ github.workflow }}-${{ github.ref }} - cancel-in-progress: true - jobs: - build: - name: node${{ matrix.node }} • ${{ matrix.os }} - runs-on: ${{ matrix.os }} - strategy: - fail-fast: false - matrix: - node: ${{ fromJson(inputs.node_versions) }} - os: ${{ fromJson(inputs.os) }} - + ts: + name: "ts / node 22.x • ubuntu-latest" + runs-on: ubuntu-latest + continue-on-error: true steps: - uses: actions/checkout@v4 - - name: Guard — skip if no Node project + - name: Detect Node workspace id: guard shell: bash run: | - if find -L . -type f -name package.json \ - -not -path "./.git/*" -not -path "*/node_modules/*" \ - -print -quit | grep -q .; then - echo "has_pkg=true" >> "$GITHUB_OUTPUT" + if find . -type f -name package.json -print -quit | grep -q .; then + echo "HAS_NODE=1" >> "$GITHUB_ENV" else - echo "has_pkg=false" >> "$GITHUB_OUTPUT" + echo "HAS_NODE=0" >> "$GITHUB_ENV" fi - - uses: actions/setup-node@v4 - if: ${{ steps.guard.outputs.has_pkg == 'true' }} + - if: ${{ env.HAS_NODE == '1' }} + uses: actions/setup-node@v4 with: - node-version: ${{ matrix.node }} - cache: ${{ inputs.package_manager }} + node-version: 22.x + cache: pnpm - - name: Install - if: ${{ steps.guard.outputs.has_pkg == 'true' }} + - if: ${{ env.HAS_NODE == '1' }} + name: Ensure pnpm shell: bash run: | corepack enable || true - case "${{ inputs.package_manager }}" in - pnpm) pnpm i --frozen-lockfile || pnpm i ;; - npm) npm ci || npm i ;; - yarn) yarn install --frozen-lockfile || yarn install ;; - *) echo "unknown package manager: ${{ inputs.package_manager }}" ;; - esac + corepack prepare pnpm@latest --activate || true + if ! command -v pnpm >/dev/null; then + npm i -g pnpm@9 || true + fi + pnpm -v || true + + - if: ${{ env.HAS_NODE == '1' }} + name: Install deps (pnpm) + shell: bash + run: | + if [ -f pnpm-lock.yaml ]; then + pnpm i --frozen-lockfile || true + else + echo "no pnpm lock; skip install" + fi + + - if: ${{ env.HAS_NODE == '1' }} + name: Type check (tsc --noEmit if tsconfig present) + shell: bash + run: | + if [ -f tsconfig.json ] || ls -1 tsconfig.*.json >/dev/null 2>&1; then + npx -y typescript@latest --version + npx -y tsc --noEmit + else + echo "no tsconfig; skip tsc" + fi + + - if: ${{ env.HAS_NODE == '1' }} + name: Lint (eslint if config present) + shell: bash + run: | + if ls -1 .eslintrc.* eslint.config.* >/dev/null 2>&1; then + npx -y eslint . --max-warnings=0 + else + echo "no eslint config; skip eslint" + fi - - name: Test - if: ${{ steps.guard.outputs.has_pkg == 'true' && inputs.test_command != '' }} - run: ${{ inputs.test_command }} + - if: ${{ env.HAS_NODE == '1' }} + name: Tests (pnpm test if exists) + shell: bash + run: | + if [ -f package.json ] && node -e "p=require('./package.json');process.exit(p.scripts&&p.scripts.test?0:1)"; then + pnpm -s test || true + else + echo "no tests" + fi + + - if: ${{ env.HAS_NODE != '1' }} + name: Skip (no Node workspace) + run: | + echo "skip ts-ci: no Node workspace" From b73ef4034bc28bc99b6763b6b40a1baf7a7e1643 Mon Sep 17 00:00:00 2001 From: CoderDeltaLan Date: Thu, 18 Sep 2025 20:12:27 +0100 Subject: [PATCH 7/9] release: v0.1.3 --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 1c1726d..bffa2bd 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "ci-matrix-starter" -version = "0.1.0" +version = "0.1.3" description = "Reusable CI workflows for Py/TS with SBOM & signatures." authors = ["CoderDeltaLAN "] readme = "README.md" From 282cc860109b88c3e9183ba3c95694041fcd13d7 Mon Sep 17 00:00:00 2001 From: CoderDeltaLan Date: Thu, 18 Sep 2025 20:33:18 +0100 Subject: [PATCH 8/9] docs: refresh README SEO badges & metadata --- README.md | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/README.md b/README.md index 90ea168..f66732f 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,36 @@ +

+ ci-matrix-starter +

+ +

+ + CI + + + CodeQL + + + PyPI + + + Downloads + + + License + + + Sponsor + +

+ +

Reusable GitHub Actions CI for Python & TypeScript

+ +**ci-matrix-starter** es una plantilla CI reusable que entrega matrices Py/TS listas para producción con: +**always-green CI**, **SBOM**, **CodeQL**, **pre-commit**, **Dependabot auto-merge** y **Publicación a PyPI (Trusted Publisher OIDC)**. +Ideal para equipos que necesitan **DevSecOps** inmediato y verificable. + +> _Keywords_: github actions, reusable workflows, python, typescript, pnpm, node, sbom, sigstore, cosign, codeql, pre-commit, dependabot, pypi, devsecops, supply-chain, always-green ci, matrix. + # ⭐ ci-matrix-starter — Reusable CI Workflows (Python & TypeScript) A lean, production-ready **GitHub Actions starter** that ships **reusable CI workflows** for **Python (3.11/3.12)** and **TypeScript/Node 20**. From 1e287c921901e6879f17588c1d38db579e588b17 Mon Sep 17 00:00:00 2001 From: CoderDeltaLan Date: Thu, 18 Sep 2025 20:52:08 +0100 Subject: [PATCH 9/9] ci: add PyPI Trusted Publisher, Dependabot auto-merge & SEO refresh --- .github/FUNDING.yml | 4 +- .github/dependabot.yml | 20 +++++++++ .github/workflows/auto-approve.yml | 28 ++++-------- .github/workflows/auto-merge-deps.yml | 26 +++++++++++ .github/workflows/build.yml | 14 +++--- .github/workflows/dependabot-auto-merge.yml | 30 +++++++++++++ .github/workflows/publish-pypi.yml | 49 +++++++++++++++++++++ .gitignore | 2 + pyproject.toml | 2 +- 9 files changed, 145 insertions(+), 30 deletions(-) create mode 100644 .github/dependabot.yml create mode 100644 .github/workflows/auto-merge-deps.yml create mode 100644 .github/workflows/dependabot-auto-merge.yml create mode 100644 .github/workflows/publish-pypi.yml diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml index 8ee9e91..9a50ccd 100644 --- a/.github/FUNDING.yml +++ b/.github/FUNDING.yml @@ -1,3 +1 @@ -github: ["CoderDeltaLAN"] # si activas GitHub Sponsors en tu perfil, aparecerá -custom: - - "https://www.paypal.com/donate/?hosted_button_id=YVENCBNCZWVPW" +custom: ["https://www.paypal.com/donate/?hosted_button_id=YVENCBNCZWVPW"] diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..a9a7615 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,20 @@ +version: 2 +updates: + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "daily" + open-pull-requests-limit: 10 + rebase-strategy: auto + + - package-ecosystem: "pip" + directory: "/" + schedule: + interval: "daily" + open-pull-requests-limit: 10 + + - package-ecosystem: "npm" + directory: "/" + schedule: + interval: "daily" + open-pull-requests-limit: 10 diff --git a/.github/workflows/auto-approve.yml b/.github/workflows/auto-approve.yml index 0d48328..3dd312b 100644 --- a/.github/workflows/auto-approve.yml +++ b/.github/workflows/auto-approve.yml @@ -1,27 +1,15 @@ -name: Auto-approve +name: Auto-approve Dependabot on: - workflow_dispatch: - inputs: - pr_number: - description: "PR number to approve" - required: true + pull_request: + types: [opened, ready_for_review, synchronize] permissions: pull-requests: write + contents: read jobs: approve: - name: Approve PR + if: github.actor == 'dependabot[bot]' runs-on: ubuntu-latest steps: - - name: Approve via API - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - REPO: ${{ github.repository }} - PR: ${{ inputs.pr_number }} - run: | - set -euo pipefail - curl -sS -X POST \ - -H "Authorization: Bearer ${GH_TOKEN}" \ - -H "Accept: application/vnd.github+json" \ - "https://api.github.com/repos/${REPO}/pulls/${PR}/reviews" \ - -d '{"event":"APPROVE"}' - echo "Approved PR #${PR} as github-actions[bot]" + - uses: hmarr/auto-approve-action@v4 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/auto-merge-deps.yml b/.github/workflows/auto-merge-deps.yml new file mode 100644 index 0000000..3f29112 --- /dev/null +++ b/.github/workflows/auto-merge-deps.yml @@ -0,0 +1,26 @@ +name: Auto-merge Dependabot when green +on: + pull_request: + types: [labeled, synchronize, reopened, ready_for_review] + check_suite: + types: [completed] +permissions: + contents: write + pull-requests: write +jobs: + enable-automerge: + runs-on: ubuntu-latest + steps: + - name: Find green Dependabot PRs + uses: peter-evans/find-pull-request@v3 + id: find + with: + author: dependabot[bot] + state: open + base: main + - name: Enable auto-merge (squash) + if: steps.find.outputs.pull-requests != '' + uses: peter-evans/enable-pull-request-automerge@v3 + with: + pull-request-number: ${{ fromJson(steps.find.outputs.pull-requests)[0].number }} + merge-method: squash diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 74c4b89..447c148 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -15,7 +15,7 @@ concurrency: jobs: ping: - name: ping • ubuntu-latest + name: "ping • ubuntu-latest" runs-on: ubuntu-latest steps: - run: echo "ok" @@ -58,15 +58,17 @@ jobs: uses: actions/setup-node@v4 with: node-version: 22.x - check-latest: false + cache: pnpm - if: ${{ env.HAS_NODE == '1' }} - name: Prepare pnpm (best-effort) + name: Ensure pnpm shell: bash run: | - corepack enable || true - corepack prepare pnpm@9 --activate || true - pnpm --version || true + if ! command -v pnpm >/dev/null 2>&1; then + corepack enable || true + corepack prepare pnpm@latest --activate || true + fi + pnpm -v || echo "pnpm not found (best-effort)" - if: ${{ env.HAS_NODE == '1' }} name: Detect package manager diff --git a/.github/workflows/dependabot-auto-merge.yml b/.github/workflows/dependabot-auto-merge.yml new file mode 100644 index 0000000..1ce3f7d --- /dev/null +++ b/.github/workflows/dependabot-auto-merge.yml @@ -0,0 +1,30 @@ +name: dependabot-auto-merge + +on: + pull_request_target: + types: [opened, synchronize, reopened, ready_for_review] + +permissions: + contents: write + pull-requests: write + +jobs: + automerge: + if: ${{ github.actor == 'dependabot[bot]' }} + runs-on: ubuntu-latest + steps: + - name: Fetch metadata + id: meta + uses: dependabot/fetch-metadata@v2 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + + - name: Enable PR auto-merge (patch/minor only) + if: | + steps.meta.outputs.update-type == 'version-update:semver-patch' || + steps.meta.outputs.update-type == 'version-update:semver-minor' + uses: peter-evans/enable-pull-request-automerge@v3 + with: + token: ${{ secrets.GITHUB_TOKEN }} + pull-request-number: ${{ github.event.pull_request.number }} + merge-method: squash diff --git a/.github/workflows/publish-pypi.yml b/.github/workflows/publish-pypi.yml new file mode 100644 index 0000000..4e1cde8 --- /dev/null +++ b/.github/workflows/publish-pypi.yml @@ -0,0 +1,49 @@ +name: publish-pypi + +on: + workflow_dispatch: + push: + tags: + - "v*" + +permissions: + contents: read + id-token: write + +jobs: + build-publish: + name: Build & publish to PyPI + runs-on: ubuntu-latest + environment: pypi + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-python@v5 + with: + python-version: "3.12" + cache: "pip" + + - name: Install build backend + run: python -m pip install --upgrade pip build + + - name: Build sdist & wheel + run: python -m build --sdist --wheel --outdir dist/ + + - name: Check tag matches version (only on tags) + if: startsWith(github.ref, 'refs/tags/') + shell: bash + run: | + PYPROJECT_VERSION=$(python - <<'PY' + import tomllib + print(tomllib.load(open("pyproject.toml","rb"))["project"]["version"]) + PY + ) + TAG="${GITHUB_REF_NAME#v}" + echo "pyproject.toml: $PYPROJECT_VERSION / tag: $TAG" + test "$TAG" = "$PYPROJECT_VERSION" + + - name: Publish to PyPI (Trusted Publisher) + if: startsWith(github.ref, 'refs/tags/') + uses: pypa/gh-action-pypi-publish@release/v1 + with: + print_hash: true diff --git a/.gitignore b/.gitignore index c26d5af..aa1a9b7 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,5 @@ node_modules/ .mypy_cache/ .pytest_cache/ sbom-*.json +.github/workflows/*.bak.* +pyproject.toml.bak diff --git a/pyproject.toml b/pyproject.toml index bffa2bd..1c7361f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "ci-matrix-starter" -version = "0.1.3" +version = "0.1.4" description = "Reusable CI workflows for Py/TS with SBOM & signatures." authors = ["CoderDeltaLAN "] readme = "README.md"