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
71 changes: 0 additions & 71 deletions .github/workflows/build.yml

This file was deleted.

117 changes: 117 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
name: ci

# PRs: a `changes` job decides if non-docs files changed; the test matrix
# (ubuntu + windows) runs only if so; an always-running `ci-ok` gate job is the
# single required status check (green when tests pass OR were skipped for a
# docs-only PR, red when any test leg fails).
# Push to main (non-docs, via paths-ignore): after tests pass, `release` runs
# semantic-release -> publish to GitHub Packages @latest, tag, pre-release
# GitHub Release.
on:
push:
branches: [main]
paths-ignore:
- '**/*.md'
- 'docs/**'
pull_request:
branches: [main]
# No paths-ignore here on purpose: the required checks (ci-ok, commitlint)
# must ALWAYS post, or a docs-only PR would hang "waiting for status".

permissions:
contents: read

concurrency:
group: ci-${{ github.ref }}
cancel-in-progress: false

jobs:
changes:
runs-on: ubuntu-latest
outputs:
code: ${{ steps.f.outputs.code }}
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- id: f
shell: bash
run: |
if [ "${{ github.event_name }}" = "pull_request" ]; then
base="${{ github.event.pull_request.base.sha }}"
head="${{ github.event.pull_request.head.sha }}"
else
base="${{ github.event.before }}"
head="${{ github.sha }}"
fi
# If base is missing/zero (first push, force-push), run tests to be safe.
if ! git rev-parse --verify --quiet "${base}^{commit}" >/dev/null; then
echo "code=true" >> "$GITHUB_OUTPUT"; echo "base unknown -> code=true"; exit 0
fi
changed=$(git diff --name-only "$base" "$head")
echo "changed files:"; echo "$changed"
# code=true if ANY changed file is NOT a markdown/docs file.
if echo "$changed" | grep -qvE '(\.md$|^docs/)'; then
echo "code=true" >> "$GITHUB_OUTPUT"
else
echo "code=false" >> "$GITHUB_OUTPUT"
fi

test:
needs: changes
if: needs.changes.outputs.code == 'true'
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, windows-latest]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 22
- run: npm ci
- run: npm run build
- run: npm test

# The single REQUIRED status check. Always runs; green when tests passed or
# were skipped (docs-only), red when any matrix leg failed/was cancelled.
ci-ok:
needs: [test]
if: always()
runs-on: ubuntu-latest
steps:
- name: Gate on test result
run: |
result="${{ needs.test.result }}"
echo "test job result: $result"
if [ "$result" = "failure" ] || [ "$result" = "cancelled" ]; then
exit 1
fi
echo "ok"

release:
needs: [changes, test]
if: github.event_name == 'push' && github.ref == 'refs/heads/main' && needs.changes.outputs.code == 'true'
runs-on: ubuntu-latest
permissions:
contents: write # push tags, create GitHub Releases
packages: write # publish to GitHub Packages
issues: write # semantic-release/github (kept for verifyConditions)
pull-requests: write
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
fetch-tags: true
- uses: actions/setup-node@v4
with:
node-version: 22
- run: npm ci
- run: npm run build
- name: Release
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
NPM_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: npx semantic-release
28 changes: 28 additions & 0 deletions .github/workflows/commitlint.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
name: commitlint

# Lint every commit in a PR's range against Conventional Commits, so
# semantic-release computes the right version bump after a merge-commit merge.
on:
pull_request:
branches: [main]

permissions:
contents: read

jobs:
commitlint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: actions/setup-node@v4
with:
node-version: 22
- run: npm ci
- name: Lint PR commits
run: >
npx commitlint
--from ${{ github.event.pull_request.base.sha }}
--to ${{ github.event.pull_request.head.sha }}
--verbose
48 changes: 0 additions & 48 deletions .github/workflows/release.yml

This file was deleted.

1 change: 1 addition & 0 deletions .husky/commit-msg
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
npx --no-install commitlint --edit "$1"
23 changes: 23 additions & 0 deletions .releaserc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{
"branches": ["main"],
"tagFormat": "v${version}",
"plugins": [
"@semantic-release/commit-analyzer",
"@semantic-release/release-notes-generator",
"@semantic-release/npm",
[
"@semantic-release/github",
{
"successComment": false,
"failComment": false,
"releasedLabels": false
}
],
[
"@semantic-release/exec",
{
"successCmd": "gh release edit v${nextRelease.version} --prerelease"
}
]
]
}
36 changes: 31 additions & 5 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,34 @@ Any field left off is inherited from the default (prod). Profiles live in

## Releases

- Every push to `main` publishes a build to the `@next` dist-tag:
`npm install -g @reply-team/reply-cli@next`.
- A release promotes a tested `@next` version to `@latest` with
`npm dist-tag add` — the exact published bytes, no rebuild — and tags the
source commit.
Releases are automated with [semantic-release](https://semantic-release.gitbook.io/).

### Internal builds (automatic)

Every merge to `main` runs CI. If the merged commits include a `feat:` or `fix:`
(per Conventional Commits), semantic-release:

- computes the next semver version,
- publishes it to GitHub Packages under `@latest`
(`npm install -g @reply-team/reply-cli`),
- pushes a `vX.Y.Z` git tag, and
- creates a **pre-release** GitHub Release whose notes are the changelog.

Commits that only touch docs/CI/chores (`docs:`, `ci:`, `chore:`, `test:`) do not
produce a release. A PR touching only `README.md` / `docs/**` skips the build (the
test matrix doesn't run) and never publishes; such a merge to `main` doesn't start
the workflow at all.

`package.json`'s `version` is intentionally `0.0.0-development` — the real version
of record is the git tag / GitHub Release / published package. Do not hand-edit it.

Commit messages are enforced by commitlint (a local `commit-msg` hook and a PR
check), because the version bump is derived from them.

### Public npm release (deferred — not yet enabled)

Promoting a tested internal build to the public npm registry will be a **manual,
tag-selected** workflow: pick a `vX.Y.Z` tag, rebuild from that commit, publish the
unscoped `reply-cli` to public npm, and flip that tag's GitHub Release from
pre-release to a full release. This is gated on npm-name ownership consolidation and
is tracked in Jira. **It is not implemented yet — there is no public-release workflow.**
3 changes: 3 additions & 0 deletions commitlint.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module.exports = {
extends: ['@commitlint/config-conventional'],
};
Loading
Loading