{"id":34897094,"url":"https://github.com/nikolareljin/ci-helpers","last_synced_at":"2026-06-15T23:00:45.467Z","repository":{"id":330176765,"uuid":"1121858016","full_name":"nikolareljin/ci-helpers","owner":"nikolareljin","description":"Shared GitHub Actions workflows and Bash utilities for CI/CD across multiple repos - tests, builds, deploys, and PR gates with reusable presets.","archived":false,"fork":false,"pushed_at":"2026-06-12T23:10:07.000Z","size":816,"stargazers_count":2,"open_issues_count":18,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-12T23:22:56.633Z","etag":null,"topics":["automation","bash","ci-cd","composite-actions","devops","docker","dotnet","github-actions","golang","java","nodejs","php","pr-checks","python","react","release-management","reusable-workflows","semver"],"latest_commit_sha":null,"homepage":"","language":"Shell","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/nikolareljin.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"docs/SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":"AGENTS.md","dco":null,"cla":null}},"created_at":"2025-12-23T17:08:46.000Z","updated_at":"2026-06-12T23:09:35.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/nikolareljin/ci-helpers","commit_stats":null,"previous_names":["nikolareljin/ci-helpers"],"tags_count":39,"template":false,"template_full_name":null,"purl":"pkg:github/nikolareljin/ci-helpers","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nikolareljin%2Fci-helpers","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nikolareljin%2Fci-helpers/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nikolareljin%2Fci-helpers/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nikolareljin%2Fci-helpers/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/nikolareljin","download_url":"https://codeload.github.com/nikolareljin/ci-helpers/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nikolareljin%2Fci-helpers/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34383468,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-15T02:00:07.085Z","response_time":63,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["automation","bash","ci-cd","composite-actions","devops","docker","dotnet","github-actions","golang","java","nodejs","php","pr-checks","python","react","release-management","reusable-workflows","semver"],"created_at":"2025-12-26T07:37:01.917Z","updated_at":"2026-06-15T23:00:45.461Z","avatar_url":"https://github.com/nikolareljin.png","language":"Shell","funding_links":[],"categories":[],"sub_categories":[],"readme":"# ci-helpers\n\n[![Latest Release](https://img.shields.io/github/v/release/nikolareljin/ci-helpers?style=flat-square\u0026logo=github\u0026color=2ea44f\u0026label=release)](https://github.com/nikolareljin/ci-helpers/releases/latest)\n[![License](https://img.shields.io/github/license/nikolareljin/ci-helpers?style=flat-square)](LICENSE)\n[![Production gate](https://github.com/nikolareljin/ci-helpers/actions/workflows/production-branch.yml/badge.svg)](https://github.com/nikolareljin/ci-helpers/actions/workflows/production-branch.yml)\n[![Security scan](https://github.com/nikolareljin/ci-helpers/actions/workflows/security-weekly.yml/badge.svg)](https://github.com/nikolareljin/ci-helpers/actions/workflows/security-weekly.yml)\n[![Used by 12+ repos](https://img.shields.io/badge/used%20by-12%2B%20repos-blue?style=flat-square\u0026logo=github)](https://github.com/search?q=nikolareljin%2Fci-helpers+language%3Ayaml\u0026type=code)\n\nShared GitHub Actions workflows and Bash helpers for CI across multiple repos.\n\nCurrent production tag: **0.14.2**.\n\nIncludes:\n- Reusable workflows for CI, PR gating, and deploys.\n- Reusable workflows for release builds (generic, Rust, and Tauri desktop).\n- Reusable scan workflows for Gitleaks, Trivy, Docker (Trivy/Snyk), and language scans.\n- Composite actions for semver comparison, release tag checks, and release notes.\n- Composite actions for Trivy, Gitleaks, JSON data-safety, and WordPress plugin-check scans.\n- Composite actions for macOS codesigning (`macos-sign`) and Windows signing (`windows-sign` — free ED25519, paid PFX, or Azure Trusted Signing).\n- Tauri CI/CD: `tauri-scan.yml` (fast gate), `tauri.yml` (CI), `tauri-release.yml` (3-OS matrix with signing, notarization, and GitHub release).\n- `winget-submit.yml` for automated Windows Package Manager manifest submission.\n- `docker-multiarch.yml` for multi-architecture Docker builds (QEMU + buildx, optional Trivy scan).\n- `manifest-version.yml` for manifest-based auto-versioning and release dispatch (supports `package.json`, `Cargo.toml`, `pubspec.yaml`, `pyproject.toml`, `VERSION`, and custom commands).\n- `release-rc-pr.yml` as a reusable `workflow_call` workflow — add 10 lines to any repo to get automatic release PRs on `release/*` branch pushes.\n- Vendored [`script-helpers`](https://github.com/nikolareljin/script-helpers) to reuse common Bash logging/utilities.\n- Preset workflows for common stacks (Java, Kotlin, Rust, C#, Node, Python, PHP, Go, React, Docker, Playwright, Cypress).\n- pnpm presets: `pnpm.yml` (monorepo CI with optional JUnit test result upload), `pnpm-playwright.yml` (Playwright E2E), `pnpm-cypress.yml` (Cypress component/E2E).\n- Optional E2E runs (Playwright/Cypress) via `e2e_command`.\n\n## Docs\n\nSee detailed usage, inputs, and examples in:\n- [Docs index](docs/README.md)\n- [Reusable workflows](docs/workflows.md)\n- [Presets](docs/presets.md)\n- [Composite actions](docs/actions.md)\n- [Examples](docs/examples.md)\n- [Usage guide](docs/usage.md)\n- [App Store (Fastlane)](docs/APPLE_FASTLANE_PUBLISH.md)\n- [Google Play (Fastlane)](docs/GOOGLE_PLAY_PUBLISH.md)\n\n## Quick Start\n\n1) Create `.github/workflows/ci.yml` in your repo:\n\n```yaml\nname: CI\non:\n  push:\n    branches: [ main, master ]\n  pull_request:\n\njobs:\n  ci:\n    uses: nikolareljin/ci-helpers/.github/workflows/node.yml@production\n    with:\n      node_version: \"22\"\n```\n\n2) Commit and push. GitHub will run the workflow on PRs and main/master.\n\n3) Need E2E? Add an `e2e_command` (runs after Docker if set). See [presets](docs/presets.md) and [examples](docs/examples.md) for more patterns:\n\n```yaml\njobs:\n  ci:\n    uses: nikolareljin/ci-helpers/.github/workflows/playwright.yml@production\n    with:\n      node_version: \"22\"\n      e2e_command: \"yarn dlx start-server-and-test 'yarn dev' http://localhost:3000 'npx playwright test'\"\n```\n\n## Layout\n\n- `.github/workflows/ci.yml`: reusable CI workflow (lint/test/build/docker/extra)\n- `.github/workflows/pr-gate.yml`: reusable PR gate workflow with optional release tag checks\n- `.github/workflows/deploy.yml`: reusable deploy workflow\n- `.github/workflows/php-scan.yml`: reusable PHP scan workflow (unit, framework lint, WP-CLI scan)\n- `.github/workflows/python-scan.yml`: reusable Python scan workflow (lint + unit + Django)\n- `.github/workflows/go-scan.yml`: reusable Go scan workflow (lint + tests + gosec)\n- `.github/workflows/rust-scan.yml`: reusable Rust scan workflow (lint + tests + audit)\n- `.github/workflows/java-scan.yml`: reusable Java scan workflow (lint + tests + dependency check)\n- `.github/workflows/csharp-scan.yml`: reusable C# scan workflow (lint + tests + vulnerable packages)\n- `.github/workflows/node-scan.yml`: reusable Node.js scan workflow (lint/test/audit)\n- `.github/workflows/react-scan.yml`: reusable React scan workflow (lint/test/build/audit)\n- `.github/workflows/vue-scan.yml`: reusable Vue scan workflow (lint/test/build/audit)\n- `.github/workflows/docker-scan.yml`: reusable Docker scan workflow (Trivy + Snyk)\n- `.github/workflows/trivy-scan.yml`: reusable Trivy scan workflow\n- `.github/workflows/gitleaks-scan.yml`: reusable Gitleaks scan workflow\n- `.github/workflows/wp-plugin-check.yml`: reusable WordPress plugin-check workflow\n- `.github/workflows/auto-tag-release.yml`: reusable auto-tag workflow for release branches\n- `.github/workflows/release-tag-gate.yml`: reusable PR gate for release tag availability\n- `.github/workflows/release-tag-check.yml`: repo guard that checks tag availability on new release branches\n- `.github/workflows/release-build.yml`: reusable release build workflow for any language\n- `.github/workflows/flutter-release.yml`: reusable Flutter build + store deploy workflow (Android/iOS)\n- `.github/workflows/release-rc-pr.yml`: repo-local workflow to open PRs on `release/*-rc*` branch creation\n- `.github/workflows/rust-release.yml`: reusable Rust multi-target release workflow\n- `.github/workflows/go-release.yml`: reusable Go multi-target release workflow\n- `.github/workflows/fpc-release.yml`: reusable Free Pascal (FPC) multi-platform release workflow (Linux/macOS/Windows)\n- `.github/workflows/go-deploy.yml`: reusable Go binary build + SSH/rsync deploy workflow\n- `.github/workflows/ppa-deb.yml`: reusable Debian source build + Launchpad PPA publish workflow\n- `.github/workflows/deb-build.yml`: reusable Debian package build workflow (artifacts only)\n- `.github/workflows/rpm-build.yml`: reusable RPM build workflow (artifacts only)\n- `.github/workflows/homebrew-package.yml`: reusable Homebrew tarball/formula build + optional publish workflow\n- `.github/actions/semver-compare`: composite action for semver comparison\n- `.github/actions/check-release-tag`: composite action for release tag guard\n- `.github/actions/release-notes`: composite action for release note generation\n- `.github/workflows/production-branch.yml`: repo-local workflow that updates the `production` tag to a released tag (it does not move a branch)\n- `.github/actions/trivy-scan`: composite action for Trivy scanning\n- `.github/actions/gitleaks-scan`: composite action for Gitleaks scanning\n- `.github/actions/wp-plugin-check`: composite action for WordPress plugin-check\n- `scripts/`: bash utilities used by actions\n- `vendor/script-helpers/scripts/ppa_upload.sh`: helper to build and upload a Debian source package to Launchpad\n- `vendor/script-helpers`: vendored helper scripts from [`script-helpers`](https://github.com/nikolareljin/script-helpers) (sync via `scripts/sync_script_helpers.sh`)\n- `.github/workflows/{node,react,python,go,java,java-gradle,kotlin,rust,csharp,php,docker,playwright,cypress}.yml`: reusable stack presets\n\n## Reusable workflow examples\n\nPR gate example:\n\n```yaml\nname: PR\non:\n  pull_request:\n\njobs:\n  gate:\n    uses: nikolareljin/ci-helpers/.github/workflows/pr-gate.yml@production\n    with:\n      node_version: \"22\"\n      lint_command: \"npm ci \u0026\u0026 npm run lint\"\n      test_command: \"npm test\"\n      build_command: \"npm run build\"\n      e2e_command: \"npm run e2e\"\n      check_release_tag: true\n      release_branch: ${{ github.head_ref }}\n```\n\nCI example (push/main or master):\n\n```yaml\nname: CI\non:\n  push:\n    branches: [ main, master ]\n\njobs:\n  ci:\n    uses: nikolareljin/ci-helpers/.github/workflows/ci.yml@production\n    with:\n      python_version: \"3.13\"\n      test_command: \"pip install -r requirements.txt \u0026\u0026 pytest\"\n      e2e_command: \"python -m pytest tests/e2e\"\n```\n\n## Preset usage by language/framework\n\nNode.js:\n\n```yaml\njobs:\n  node:\n    uses: nikolareljin/ci-helpers/.github/workflows/node.yml@production\n    with:\n      node_version: \"22\"\n```\n\nReact:\n\n```yaml\njobs:\n  react:\n    uses: nikolareljin/ci-helpers/.github/workflows/react.yml@production\n    with:\n      node_version: \"22\"\n      test_command: \"npm test -- --watchAll=false\"\n      e2e_command: \"npm run e2e\"\n```\n\nPlaywright:\n\n```yaml\njobs:\n  playwright:\n    uses: nikolareljin/ci-helpers/.github/workflows/playwright.yml@production\n    with:\n      node_version: \"22\"\n```\n\nCypress:\n\n```yaml\njobs:\n  cypress:\n    uses: nikolareljin/ci-helpers/.github/workflows/cypress.yml@production\n    with:\n      node_version: \"22\"\n```\n\nPython:\n\n```yaml\njobs:\n  python:\n    uses: nikolareljin/ci-helpers/.github/workflows/python.yml@production\n    with:\n      python_version: \"3.13\"\n      lint_command: \"if [ -f requirements.txt ]; then python -m pip install -r requirements.txt; elif [ -f pyproject.toml ]; then python -m pip install pyinstaller \u0026\u0026 python -m pip install .; fi \u0026\u0026 python -m pip install ruff \u0026\u0026 ruff check .\"\n      test_command: \"python -m pip install pytest \u0026\u0026 python -m pytest\"\n```\n\nPHP:\n\n```yaml\njobs:\n  php:\n    uses: nikolareljin/ci-helpers/.github/workflows/php.yml@production\n    with:\n      php_version: \"8.4\"\n      lint_command: \"composer install --no-interaction --prefer-dist \u0026\u0026 vendor/bin/phpcs --standard=PSR12 --extensions=php\"\n      test_command: \"vendor/bin/phpunit\"\n```\n\nGo:\n\n```yaml\njobs:\n  go:\n    uses: nikolareljin/ci-helpers/.github/workflows/go.yml@production\n    with:\n      go_version: \"1.24\"\n      test_command: \"go test ./...\"\n      build_command: \"go build ./...\"\n```\n\nJava (Maven defaults):\n\n```yaml\njobs:\n  java:\n    uses: nikolareljin/ci-helpers/.github/workflows/java.yml@production\n    with:\n      java_version: \"17\"\n      test_command: \"mvn -B test\"\n      build_command: \"mvn -B package\"\n```\n\nJava (Gradle defaults):\n\n```yaml\njobs:\n  java_gradle:\n    uses: nikolareljin/ci-helpers/.github/workflows/java-gradle.yml@production\n    with:\n      java_version: \"17\"\n      test_command: \"./gradlew test\"\n      build_command: \"./gradlew build\"\n```\n\nKotlin (Gradle/Android defaults):\n\n```yaml\njobs:\n  kotlin:\n    uses: nikolareljin/ci-helpers/.github/workflows/kotlin.yml@production\n    with:\n      java_version: \"17\"\n      lint_command: \"./gradlew lint\"\n      test_command: \"./gradlew test\"\n      build_command: \"./gradlew assembleDebug\"\n```\n\nRust:\n\n```yaml\njobs:\n  rust:\n    uses: nikolareljin/ci-helpers/.github/workflows/rust.yml@production\n    with:\n      rust_toolchain: \"stable\"\n      test_command: \"cargo test --verbose\"\n      build_command: \"cargo build --verbose\"\n```\n\nC# (.NET):\n\n```yaml\njobs:\n  csharp:\n    uses: nikolareljin/ci-helpers/.github/workflows/csharp.yml@production\n    with:\n      dotnet_version: \"8.0.x\"\n      test_command: \"dotnet test\"\n      build_command: \"dotnet build -c Release\"\n```\n\nDocker:\n\n```yaml\njobs:\n  docker:\n    uses: nikolareljin/ci-helpers/.github/workflows/docker.yml@production\n    with:\n      docker_command: \"docker build .\"\n```\n\nNotes for presets:\n- Defaults assume common commands per stack; override `lint_command`, `test_command`, `build_command`, or `docker_command` as needed.\n- Use `e2e_command` for Playwright or Cypress (default presets use Yarn + `start-server-and-test`).\n- `e2e_command` runs after `docker_command` if both are set.\n\nDeploy example:\n\n```yaml\nname: Deploy\non:\n  workflow_dispatch:\n\njobs:\n  deploy:\n    uses: nikolareljin/ci-helpers/.github/workflows/deploy.yml@production\n    with:\n      deploy_command: \"./scripts/deploy.sh\"\n```\n\n## Composite action examples\n\nSemver compare:\n\n```yaml\n- name: Compare versions\n  id: semver\n  uses: nikolareljin/ci-helpers/.github/actions/semver-compare@production\n  with:\n    version_a: \"1.2.3\"\n    version_b: \"1.3.0\"\n\n- name: Use result\n  run: echo \"Result: ${{ steps.semver.outputs.result }}\"  # lt, eq, or gt\n```\n\nRelease tag guard (`release/[v]X.Y.Z`, `release/[v]X.Y.Z-rcN`, or `release/[v]X.Y.Z-rc.N`):\n\n```yaml\n- name: Guard release tag\n  uses: nikolareljin/ci-helpers/.github/actions/check-release-tag@production\n  with:\n    release_branch: ${{ github.head_ref }}\n```\n\n## Notes\n\n- The PR gate only blocks if your branch protection requires its status checks.\n- `check-release-tag` expects branch naming `release/[v]X.Y.Z`, `release/[v]X.Y.Z-rcN`, or `release/[v]X.Y.Z-rc.N`.\n- `scripts/check_release_version.sh` enforces that `VERSION` matches `release/[v]X.Y.Z[-rcN]` or `release/[v]X.Y.Z[-rc.N]`. A tracked pre-commit hook is available at `.githooks/pre-commit`; enable it locally with `git config core.hooksPath .githooks`.\n\n## Release tagging in external repos\n\nRecommended setup:\n- Add a PR gate that blocks merges if the release tag already exists.\n- Require that gate in your branch protection rules.\n- Add an auto-tag workflow on your default branch; it fails if the tag already exists.\n\nPR gate workflow:\n\n```yaml\nname: Release Tag Gate\non:\n  pull_request:\n\njobs:\n  gate:\n    uses: nikolareljin/ci-helpers/.github/workflows/release-tag-gate.yml@production\n```\n\nAuto-tag workflow (tag only):\n\n```yaml\nname: Auto Tag Release\non:\n  push:\n    branches: [ main, master ]\n\npermissions:\n  contents: write\n  pull-requests: read\n\njobs:\n  tag:\n    uses: nikolareljin/ci-helpers/.github/workflows/auto-tag-release.yml@production\n    with:\n      update_production_tag: false\n```\n\nAuto-tag + auto-create GitHub Release (recommended):\n\n1. Add a local wrapper at `.github/workflows/create-github-release.yml`:\n\n```yaml\nname: create-github-release\non:\n  workflow_dispatch:\n    inputs:\n      release_tag:\n        description: \"Version tag to release (e.g. 1.2.3)\"\n        type: string\n        required: true\npermissions:\n  contents: write\njobs:\n  release:\n    uses: nikolareljin/ci-helpers/.github/workflows/create-github-release.yml@production\n    with:\n      release_tag: ${{ inputs.release_tag }}\n```\n\n2. Pass `release_workflow` in the auto-tag caller:\n\n```yaml\nname: Auto Tag Release\non:\n  push:\n    branches: [ main, master ]\n\npermissions:\n  contents: write\n  pull-requests: read\n  actions: write\n\njobs:\n  tag:\n    uses: nikolareljin/ci-helpers/.github/workflows/auto-tag-release.yml@production\n    with:\n      release_workflow: create-github-release.yml\n      # update_production_tag: false  # set this if your repo does not use a floating production tag\n```\n\nAfter each `release/X.Y.Z` (or `release/vX.Y.Z`, `release/X.Y.Z-rc1`) merge the tag is created and a GitHub Release is published automatically. Release notes come from a matching `## DATE — VERSION` section in `CHANGELOG.md`, falling back to GitHub auto-generated notes.\n\n- Update vendored `script-helpers` with:\n  - `./scripts/sync_script_helpers.sh`\n  - Optional overrides: `SCRIPT_HELPERS_REPO_URL=...` and `SCRIPT_HELPERS_REF=...`\n  - Source repo: `https://github.com/nikolareljin/script-helpers`\n\n## Using from other repositories\n\n1) Create a workflow in your repo (for example `.github/workflows/ci.yml`) and call a reusable workflow:\n\n```yaml\nname: CI\non:\n  push:\n    branches: [ main, master ]\n\njobs:\n  ci:\n    uses: nikolareljin/ci-helpers/.github/workflows/node.yml@production\n```\n\n2) Pin to a tag or commit SHA:\n\n```yaml\nuses: nikolareljin/ci-helpers/.github/workflows/python.yml@production\n```\n\n3) Add/override commands and versions as needed:\n\n```yaml\njobs:\n  ci:\n    uses: nikolareljin/ci-helpers/.github/workflows/ci.yml@production\n    with:\n      node_version: \"22\"\n      lint_command: \"npm ci \u0026\u0026 npm run lint\"\n      test_command: \"npm test\"\n      build_command: \"npm run build\"\n```\n\n4) For PR blocking, add branch protection rules in your repo:\n- Settings → Branches → Branch protection rules\n- Require status checks to pass before merging\n- Select the workflow job name you use (for example `gate` or `ci`)\n\n## Clone locally (optional)\n\n```bash\ngit clone git@github.com:nikolareljin/ci-helpers.git\ncd ci-helpers\n```\n\nHTTPS alternative:\n\n```bash\ngit clone https://github.com/nikolareljin/ci-helpers.git\ncd ci-helpers\n```\n\nUse this when you want to update workflows, actions, or sync vendored helpers.\n\n\n---\n\n## Clone traffic\n\n![Clone traffic](https://raw.githubusercontent.com/nikolareljin/stats/main/charts/ci-helpers.svg)\n\n_Updated daily. Total and unique cloners over the last 14 days._\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnikolareljin%2Fci-helpers","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnikolareljin%2Fci-helpers","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnikolareljin%2Fci-helpers/lists"}