# Getting started ## Pin to `@v1` Reference everything at the moving major tag. `release` (release-please) cuts a new version on merge to `main` and moves the `v1` tag to it automatically, so `@v1` always points at the latest backward-compatible release. ```yaml - uses: FSHTech/github-actions/setup-python@v1 # reusable workflow: # uses: FSHTech/github-actions/.github/workflows/pr-title.yml@v1 ``` Breaking changes ship as `v2` (a new major tag); pin to a full version (`@v1.3.0`) if you need to freeze. ## Composite actions vs reusable workflows - **Composite actions** are *step* bundles — they go inside an existing job's `steps:`, after `actions/checkout` (and the relevant language setup). Use them to assemble a job whose shape is specific to your repo (e.g. `lint`). - **Reusable workflows** are whole *jobs* — you call them with `uses:` at the job level and they bring their own runner, permissions and steps. Use them when the entire job is the same across repos (`pr-title`, `release`, `docs`). ## A typical Python repo ```yaml # .github/workflows/lint.yml — job graph stays local, built from actions name: lint on: push: { branches: [main] } pull_request: workflow_dispatch: permissions: contents: read jobs: lint: runs-on: ubuntu-latest steps: - uses: actions/checkout@v6 - uses: FSHTech/github-actions/setup-python@v1 - uses: FSHTech/github-actions/uv-sync@v1 with: { args: --group dev --group lint } - uses: FSHTech/github-actions/just-run@v1 with: { recipes: lint type-check } pre-commit: runs-on: ubuntu-latest steps: - uses: actions/checkout@v6 - uses: FSHTech/github-actions/setup-python@v1 - uses: FSHTech/github-actions/pre-commit@v1 tests: runs-on: ubuntu-latest steps: - uses: actions/checkout@v6 - uses: FSHTech/github-actions/setup-python@v1 - uses: FSHTech/github-actions/uv-sync@v1 with: { args: --group dev } - uses: FSHTech/github-actions/just-run@v1 with: { recipes: coverage-ci } ``` The recipes (`lint`, `type-check`, `coverage-ci`, …) live in your repo's `justfile`. A node repo is the same shape — `setup-node` then `just-run` — so it needs a `justfile` exposing the equivalent recipes (e.g. `lint`, `type-check`, `build`, `test`) that wrap the underlying `yarn workspace …` calls. ```yaml # .github/workflows/pr-title.yml — thin caller for the reusable workflow name: pr-title on: pull_request: types: [opened, edited, synchronize, reopened] jobs: validate: uses: FSHTech/github-actions/.github/workflows/pr-title.yml@v1 with: scopes: | my-repo deps ci release ``` ```yaml # .github/workflows/release.yml — thin caller for the reusable workflow name: release on: push: { branches: [main] } jobs: release: uses: FSHTech/github-actions/.github/workflows/release-python.yml@v1 secrets: inherit # monorepo: with: { all-packages: true, check-url: true } ``` ## Preview environments Demo apps get an ephemeral environment per pull request — a full app (be/fe/opa/render + Postgres) on a per-PR EC2, seeded from the base branch's trunk database, reachable at `https://..preview.efesaitch.com` behind Cloudflare Access (Google login). The PR gets a comment with the link; closing it tears the environment down. Push to `main`/`staging` refreshes that base branch's always-on trunk, which PR previews seed from. ```yaml # .github/workflows/preview.yml — thin caller for the reusable workflow name: preview on: pull_request: types: [opened, synchronize, reopened, closed] push: branches: [main, staging] workflow_dispatch: jobs: preview: # fork PRs can't read secrets, so skip them if: >- github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository uses: FSHTech/github-actions/.github/workflows/deploy-preview.yml@v1 with: app: my-app worker_entrypoint: my_app.queue.main:main db_name_prefix: my_app ecr_registry: ${{ vars.PREVIEW_ECR_REGISTRY }} launch_template_id: ${{ vars.PREVIEW_LAUNCH_TEMPLATE_ID }} subnet_id: ${{ vars.PREVIEW_SUBNET_ID }} cf_account_id: ${{ vars.PREVIEW_CF_ACCOUNT_ID }} secrets: AWS_ACCESS_KEY_ID: ${{ secrets.PREVIEW_AWS_ACCESS_KEY_ID }} AWS_SECRET_ACCESS_KEY: ${{ secrets.PREVIEW_AWS_SECRET_ACCESS_KEY }} CF_API_TOKEN: ${{ secrets.PREVIEW_CF_API_TOKEN }} ``` **Onboarding a new demo app:** add one line to `infra/demo-repos.hcl` and `just apply domain` (creates the app's Cloudflare Access app at `*..preview.efesaitch.com`), then copy the caller above into the repo. The `PREVIEW_*` repo vars/secrets are provisioned by infra's `development` account. The full design + AWS/Cloudflare substrate is in `infra/docs/internal-paas.md`. See **[Reference](reference/index)** for the exact inputs of each action and workflow, and **[Conventions](conventions)** for what your repo must provide (uv layout, deploy keys, CodeArtifact / Cloudflare variables, …).