|
| 1 | +# Contributing |
| 2 | + |
| 3 | +## Development setup |
| 4 | + |
| 5 | +1. Fork and clone |
| 6 | +2. Install the git hooks (one-time setup): |
| 7 | + |
| 8 | + ```bash |
| 9 | + pip install pre-commit |
| 10 | + pre-commit install # runs on git commit |
| 11 | + pre-commit install --hook-type pre-push # runs on git push |
| 12 | + ``` |
| 13 | + |
| 14 | + If you open the repo in the devcontainer, this runs automatically. |
| 15 | + |
| 16 | +3. Changes live in `src/claude-code/install.sh` and `test/claude-code/` |
| 17 | +4. Open a pull request against `develop` |
| 18 | + |
| 19 | +## Branching model |
| 20 | + |
| 21 | +| Branch pattern | Purpose | PR target | |
| 22 | +| -------------- | ------------------------- | --------- | |
| 23 | +| `feat/*` | New features | `develop` | |
| 24 | +| `fix/*` | Bug fixes | `develop` | |
| 25 | +| `hotfix/*` | Critical production fixes | `main` | |
| 26 | + |
| 27 | +- All feature and fix PRs target `develop`. Use squash merges to keep history clean. |
| 28 | +- `hotfix/*` branches are the only branches (besides `develop`) allowed to open PRs |
| 29 | + directly to `main`. This is enforced by CI (`source-branch-check.yml`). |
| 30 | +- Direct commits to `main` and `develop` are blocked by pre-commit hooks and branch |
| 31 | + protection rules. |
| 32 | + |
| 33 | +## Pre-commit hooks |
| 34 | + |
| 35 | +The following checks run automatically on every `git commit` and `git push`: |
| 36 | + |
| 37 | +| Hook | What it checks | |
| 38 | +| --------------------- | --------------------------------------------- | |
| 39 | +| `shellcheck` | Shell script correctness (warnings and above) | |
| 40 | +| `shfmt` | Shell script formatting (`-i 4 -ci`) | |
| 41 | +| `prettier` | JSON, YAML, and Markdown formatting | |
| 42 | +| `markdownlint` | Markdown style rules | |
| 43 | +| `check-json` | JSON syntax validity | |
| 44 | +| `check-yaml` | YAML syntax validity | |
| 45 | +| `trailing-whitespace` | No trailing whitespace | |
| 46 | +| `detect-private-key` | No accidentally committed secrets | |
| 47 | +| `no-commit-to-branch` | Blocks direct commits to `main` and `develop` | |
| 48 | + |
| 49 | +**Running manually:** |
| 50 | + |
| 51 | +```bash |
| 52 | +pre-commit run --all-files # check everything |
| 53 | +pre-commit run prettier # check one hook |
| 54 | +pre-commit run --files src/claude-code/install.sh # check one file |
| 55 | +``` |
| 56 | + |
| 57 | +**If a hook fails:** fix the flagged issue and `git add` the changes before retrying. |
| 58 | +Prettier and shfmt auto-fix in place — just stage the result. ShellCheck and markdownlint |
| 59 | +report what to fix but won't rewrite your code. |
| 60 | + |
| 61 | +## Maintainers |
| 62 | + |
| 63 | +### Advancing main |
| 64 | + |
| 65 | +When `develop` is ready for release, use the **Advance main** workflow: |
| 66 | + |
| 67 | +1. Go to **Actions** → **Advance main** → **Run workflow** |
| 68 | +2. The workflow fast-forwards `main` to the current tip of `develop` via the GitHub API |
| 69 | + (no merge commit is created) |
| 70 | +3. It verifies that `main` and `develop` point to the same SHA before completing |
| 71 | + |
| 72 | +### Releasing a version |
| 73 | + |
| 74 | +1. Update the `version` field in `src/claude-code/devcontainer-feature.json` as part of |
| 75 | + the work merged to `develop` — this must be done **before** tagging, as the release |
| 76 | + workflow validates that the tag version matches the JSON |
| 77 | +2. Advance `main` using the workflow above |
| 78 | +3. Tag the release from the updated `main`: |
| 79 | + |
| 80 | + ```bash |
| 81 | + git checkout main |
| 82 | + git pull origin main |
| 83 | + git tag v<VERSION> |
| 84 | + git push origin v<VERSION> |
| 85 | + ``` |
| 86 | + |
| 87 | +4. The `v*` tag push triggers the **Release** workflow, which: |
| 88 | + - Runs ShellCheck validation |
| 89 | + - Smoke-tests against 3 representative base images |
| 90 | + - Verifies the tag version matches `devcontainer-feature.json` |
| 91 | + - Publishes the feature to `ghcr.io/pkramek/claude-devcontainer/claude-code` |
| 92 | + - Verifies the published feature is accessible |
| 93 | + |
| 94 | +Tags are protected — no deletion or force-push. |
| 95 | + |
| 96 | +### Hotfix workflow |
| 97 | + |
| 98 | +For critical fixes that cannot wait for the normal `develop` cycle: |
| 99 | + |
| 100 | +1. Create a `hotfix/*` branch from `main` |
| 101 | +2. Make the fix and open a PR targeting `main` — the source-branch-check CI allows |
| 102 | + `hotfix/*` to bypass the `develop`-only gate |
| 103 | +3. After the hotfix merges to `main`, tag and release as described above |
| 104 | +4. Open a second PR from `hotfix/*` (or from `main`) to `develop` to keep the branches |
| 105 | + in sync |
| 106 | + |
| 107 | +### First release: GHCR visibility |
| 108 | + |
| 109 | +After the first tag push, the GHCR package is created as **private**. To make it public: |
| 110 | + |
| 111 | +1. Go to the repository's **Packages** tab |
| 112 | +2. Click the `claude-code` package → **Package settings** |
| 113 | +3. Under **Danger Zone**, change visibility to **Public** |
0 commit comments