Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .cursorrules
1 change: 1 addition & 0 deletions .github/copilot-instructions.md
82 changes: 82 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
# CLAUDE.md — AI Assistant Context

This file provides context for AI coding assistants (Claude, Cursor, GitHub Copilot).
For full documentation, see the [`documentation/`](./documentation/) directory.

## What This Repository Is

A mono-repo of reusable [composite GitHub Actions](https://docs.github.com/en/actions/creating-actions/creating-a-composite-action)
used across GenUI's CI/CD pipelines. All actions are composite actions (YAML + shell scripts) —
not Docker or JavaScript actions.

Consumers reference actions via:

```yaml
uses: generalui/github-workflow-accelerators/.github/actions/{action-name}@{version-tag}
```

## Repository Structure

```text
.github/
actions/
{action-name}/
action.yml # Composite action definition
project.json # Version — MUST be bumped on every change to this action
README.md # Action documentation
scripts/ # Shell scripts invoked by action.yml
workflows/
code-quality.yml # PR gate: markdownlint + per-action bats tests
create-release.yml # Auto-releases on merge to main
tests/
unit/
{action-name}/ # bats tests for that action's shell scripts
helpers/
mock_helpers.bash # Shared mock utilities
documentation/ # Contributor and DevOps guides
```

## Critical: Versioning Contract

**Every change to an action requires a `project.json` version bump. No exceptions.**

- Patch (1.0.0 → 1.0.1): bug fixes, dependency updates, documentation, refactors
- Minor (1.0.0 → 1.1.0): new optional inputs, backwards-compatible features
- Major (1.0.0 → 2.0.0): breaking changes to inputs or outputs

Skipping the version bump causes `create-release.yml` to fail on merge to `main` with a
"tag already exists" error.

See [UPDATING_AN_ACTION.md](./documentation/UPDATING_AN_ACTION.md).

## CI vs Release Triggers

**`code-quality.yml`** (PR gate) — runs on PRs to `main`:

- Markdownlint: fires when any `**/*.md` file changes
- bats tests: fires per-action when files in `.github/actions/{name}/` or `tests/unit/{name}/` change
- To add a new testable action, add its name to the `actions_with_tests` array in `code-quality.yml`

**`create-release.yml`** (release) — runs on push to `main`:

- Reads `project.json` from each changed action directory
- Ignores: `documentation/`, `tests/`, `*.md`, `.github/workflows/`, config files
- Creates tag `{version}-{action-name}` and GitHub Release per changed action

See [DEVOPS.md](./documentation/DEVOPS.md), [CODE_QUALITY.md](./documentation/CODE_QUALITY.md),
and [CREATE_RELEASE.md](./documentation/CREATE_RELEASE.md).

## Adding or Modifying Actions

- **Adding**: [ADDING_AN_ACTION.md](./documentation/ADDING_AN_ACTION.md)
- **Modifying**: [UPDATING_AN_ACTION.md](./documentation/UPDATING_AN_ACTION.md)
- **Testing**: [WRITING_TESTS.md](./documentation/WRITING_TESTS.md)
- **Contributing**: [CONTRIBUTING.md](./documentation/CONTRIBUTING.md)

## Key Conventions

- `main` is protected — all changes via PR; direct commits are blocked
- Shell scripts: `#!/usr/bin/env bash`, inputs passed via env vars not positional args
- Tests: bats, `REPO_ROOT="$(cd "$BATS_TEST_DIRNAME/../../.." && pwd)"` (3 levels deep)
- Internal action references are pinned to a specific release tag
- New actions start at version `1.0.0`
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ This repo hold various accelerators for Github workflows (Actions) as well as re

## Contributing

See [documentation/CONTRIBUTING.md](./documentation/CONTRIBUTING.md) for the full contributor guide, including
how to add or update actions, write tests, and understand the CI/CD workflows.

### Linting and Formatting

See [documentation/LINTING.md](./documentation/LINTING.md) for more information.
Expand Down
87 changes: 87 additions & 0 deletions documentation/ADDING_AN_ACTION.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
# Adding an Action

This guide covers how to add a new reusable composite action to this repository.

## Directory Structure

Each action lives in its own directory under `.github/actions/`:

```text
.github/actions/{action-name}/
├── action.yml # Composite action definition (required)
├── project.json # Version metadata (required)
├── README.md # Action documentation (required)
└── scripts/ # Shell scripts invoked by action.yml (if needed)
└── {script}.sh
```

## Step-by-Step

### 1. Create the action directory

Use kebab-case for the directory name. It becomes part of the version tag and the consumer's `uses:` reference.

```sh
mkdir -p .github/actions/my-new-action/scripts
```

### 2. Create `action.yml`

Refer to the [GitHub documentation on creating actions](https://docs.github.com/en/actions/sharing-automations/creating-actions)
for the full `action.yml` syntax. Any action type is supported.

Two conventions specific to this repo:

- Reference internal actions (e.g. `configure-aws`) by pinning to a release tag:
`uses: generalui/github-workflow-accelerators/.github/actions/configure-aws@{tag}`
- When invoking shell scripts, pass inputs via environment variables rather than
positional arguments — it keeps the script interface explicit and testable

### 3. Create `project.json`

Start at version `1.0.0`. This file is read by the release workflow to create a version tag on merge to `main`.

```json
{
"name": "my-new-action",
"version": "1.0.0"
}
```

The `name` field must match the directory name exactly.

### 4. Create `README.md`

Document the action's inputs, outputs, and a usage example. See any existing action README for the expected format.

### 5. Write shell scripts (if applicable)

Place scripts in the `scripts/` directory. Follow the patterns established in existing scripts:

- Use `#!/usr/bin/env bash`
- Guard required environment variables at the top before doing any work
- Source `scripts/general/options_helpers.sh` if the script accepts CLI flags
- Exit with code `1` on validation failure (makes testing straightforward)

### 6. Write tests (if the action contains testable shell scripts)

See [WRITING_TESTS.md](./WRITING_TESTS.md) for the full guide.

Then register the action in the `actions_with_tests` array in `.github/workflows/code-quality.yml`:

```yaml
actions_with_tests=(
"my-new-action"
...
)
```

### 7. Open a pull request

The `code-quality.yml` PR gate will run markdownlint and, if registered, the bats test suite for your new action.

On merge to `main`, `create-release.yml` will automatically create a git tag `1.0.0-my-new-action` and a GitHub Release.

## Versioning

New actions always start at `1.0.0`. See [UPDATING_AN_ACTION.md](./UPDATING_AN_ACTION.md) for version bump rules when making subsequent changes.
44 changes: 44 additions & 0 deletions documentation/CODE_QUALITY.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# Code Quality Workflow

The `code-quality.yml` workflow is the PR gate for this repository. It runs automatically on every pull request targeting `main`.

## What It Does

The workflow runs a single `quality` job with conditional steps:

1. **Detect changes** — uses `tj-actions/changed-files` to determine which files changed
2. **Lint Markdown** — runs `markdownlint-cli2` if any `.md` files or the workflow file itself changed
3. **Install bats** — installs the test runner if any action or test files changed
4. **Per-action tests** — runs `bats tests/unit/{action-name}/` for each action whose files changed

Only the steps relevant to the PR's changes are executed, keeping runner time minimal.

## Triggering Conditions

| Step | Triggers when... |
| ------ | ----------------- |
| Lint Markdown | Any `**/*.md` file or `code-quality.yml` itself changed |
| bats tests | Files changed in `.github/actions/{action-name}/` or `tests/unit/{action-name}/` |

## Per-Action Test Detection

The workflow maintains an explicit list of actions that have bats test suites:

```yaml
actions_with_tests=(
"promote-ecr-image"
"test-python"
"update-aws-ecs"
"update-aws-lambda"
)
```

When adding a new action with testable shell scripts, add its name to this array. See [ADDING_AN_ACTION.md](./ADDING_AN_ACTION.md).

## Single-Job Design

All steps run sequentially in one job rather than as parallel matrix jobs. For fast-running bats suites, the overhead of spinning up multiple runners exceeds any parallelism benefit.

## Required Status Check

The `Quality` check produced by this workflow is a required status check on `main`. A PR cannot be merged until it passes.
43 changes: 43 additions & 0 deletions documentation/CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# Contributing

Thank you for contributing to GitHub Workflow Accelerators. This document is the starting point for contributors — human or AI.

## Prerequisites

- [bats-core](https://github.com/bats-core/bats-core) — for running shell script tests locally
- [markdownlint-cli2](https://github.com/DavidAnson/markdownlint-cli2) — for linting markdown
- [shellcheck](https://www.shellcheck.net/) — recommended for shell script authoring

See [LINTING.md](./LINTING.md) and [TESTING.md](./TESTING.md) for setup details.

## Guides

| Task | Document |
| ------ | ---------- |
| Add a new action | [ADDING_AN_ACTION.md](./ADDING_AN_ACTION.md) |
| Modify an existing action | [UPDATING_AN_ACTION.md](./UPDATING_AN_ACTION.md) |
| Write tests for shell scripts | [WRITING_TESTS.md](./WRITING_TESTS.md) |
| Understand CI/CD workflows | [DEVOPS.md](./DEVOPS.md) |

## Branch and PR Conventions

- `main` is a protected branch — all changes must go through a pull request
- Branch naming: `feat/`, `fix/`, `chore/` prefixes (e.g. `feat/add-notify-slack`)
- Each PR should change only the action(s) it intends to change
- PRs that change an action's files **must** include a `project.json` version bump — see [UPDATING_AN_ACTION.md](./UPDATING_AN_ACTION.md)

## Commit Messages

Use conventional commit prefixes:

- `feat:` — new action or new feature in an existing action
- `fix:` — bug fix
- `chore:` — dependency updates, version bumps, tooling changes
- `docs:` — documentation only changes
- `refactor:` — code changes that don't affect behaviour
- `test:` — adding or updating tests

## Code Review

- The `code-quality.yml` PR gate must pass before merging
- Markdownlint and bats tests run automatically for changed files — see [DEVOPS.md](./DEVOPS.md)
55 changes: 55 additions & 0 deletions documentation/CREATE_RELEASE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# Create Release Workflow

The `create-release.yml` workflow automatically creates versioned git tags and GitHub Releases when changes are merged to `main`.

## How It Works

1. **Detect changed files** — uses `tj-actions/changed-files` to identify which files changed in the push
2. **Extract action paths** — parses changed file paths to identify which action directories were modified
3. **Validate versions** — reads `project.json` from each changed action and verifies the version tag does not already exist
4. **Tag and release** — for each changed action, creates a git tag and GitHub Release with an auto-generated changelog

## Version Tag Format

Tags follow the format `{version}-{action-name}`:

```text
1.0.1-update-aws-ecs
1.2.0-lint-test-yarn
```

The changelog is generated from commit messages between the previous tag and the new one.

## What Triggers a Release

A push to `main` triggers a release for any action whose files changed **and** whose `project.json` version is higher than the most recent tag for that action.

If the version has not been bumped, the workflow fails with:

```text
The tag {version}-{action-name} already exists,
ensure you have incremented the version in project.json.
```

Always bump `project.json` before merging. See [UPDATING_AN_ACTION.md](./UPDATING_AN_ACTION.md).

## What Does NOT Trigger a Release

The following paths are excluded from change detection:

| Path | Reason |
| ------ | -------- |
| `.github/workflows/create-release.yml` | Self-referential |
| `.github/workflows/code-quality.yml` | Workflow-only change |
| `.github/**/*.md` | Workflow documentation |
| `documentation/**` | Documentation only |
| `tests/**` | Test files only |
| `*.md` | Root markdown files |
| `.vscode/**` | Editor config |
| `.gitignore`, `.markdownlint*`, `*.code-workspace` | Config files |

If you need to add a new top-level directory that should not trigger releases, add it to the `files_ignore` list in `create-release.yml`.

## Matrix Releases

If multiple actions change in a single merge, the workflow releases each one independently in parallel via a matrix strategy. Each action gets its own tag, changelog, and GitHub Release.
34 changes: 34 additions & 0 deletions documentation/DEVOPS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# DevOps

This document covers the CI/CD infrastructure for this repository.

## CI/CD Workflows

All workflows are defined in `.github/workflows/`.

| Workflow | Trigger | Purpose |
| ---------- | --------- | --------- |
| [`code-quality.yml`](./../.github/workflows/code-quality.yml) | PR to `main` | Linting and unit tests |
| [`create-release.yml`](./../.github/workflows/create-release.yml) | Push to `main` | Version tagging and GitHub Releases |

### Code Quality

See [CODE_QUALITY.md](./CODE_QUALITY.md) for details on the PR gate workflow.

### Create Release

See [CREATE_RELEASE.md](./CREATE_RELEASE.md) for details on the release workflow.

## Branch Protection

The `main` branch is protected:

- All changes must be submitted via pull request
- The `Quality` check (from `code-quality.yml`) must pass before merging
- Direct commits to `main` are blocked

## Dependency Management

Actions in this repo reference specific versions of external GitHub Actions (e.g. `actions/checkout`).
When new versions are released — particularly those resolving runtime deprecation warnings — the `action.yml`
files and corresponding `project.json` versions should be updated. See [UPDATING_AN_ACTION.md](./UPDATING_AN_ACTION.md).
7 changes: 6 additions & 1 deletion documentation/TESTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ tests/
## What Is Tested

| Action | Script | Tests | What's covered |
|--------|--------|-------|----------------|
| -------- | -------- | ------- | ---------------- |
| `promote-ecr-image` | `options_helpers.sh` | 15 | `has_argument()` and `extract_argument()` parsing logic |
| `promote-ecr-image` | `aws_unset.sh` | 7 | All 4 AWS credential env vars are cleared; no-op when already unset |
| `promote-ecr-image` | `promote_image.sh` | 13 | Every required env var validation (exits 1 for each missing var); `--help` |
Expand Down Expand Up @@ -93,6 +93,11 @@ and runs tests only for those actions — each in its own isolated job.

## Writing New Tests

For a full guide on writing new tests — including the mock pattern, exit code testing, and how to register
a new action with CI — see [WRITING_TESTS.md](./WRITING_TESTS.md).

Quick reference:

1. Create `tests/unit/<action-name>/test_<script_name>.bats`.
2. Set `REPO_ROOT` relative to `BATS_TEST_DIRNAME` — tests are three levels deep,
so use: `REPO_ROOT="$(cd "$BATS_TEST_DIRNAME/../../.." && pwd)"`
Expand Down
Loading
Loading