Automated build, test, and release pipeline using GitHub Actions.
Push/PR to main or develop:
┌──────────┬───────────┬────────────┬───────────┬───────────┬───────────┬────────┐
│ Lint │ Typecheck │ Unit Tests │ E2E CLI │ E2E TUI │ E2E Web │ Docker │
└──────────┴───────────┴────────────┴───────────┴───────────┴───────────┴────────┘
┌───────────────┬──────────────────────┬──────────┬─────────┬──────────┐
│ Trivy (deps) │ Trivy (container) │ Gitleaks │ Semgrep │ Hadolint │
└───────────────┴──────────────────────┴──────────┴─────────┴──────────┘
(all run in parallel)
On PR only:
┌──────────────────────────────────────────────────────────────────────┐
│ Claude Review │ Documentation & Architecture compliance check │
└──────────────────────────────────────────────────────────────────────┘
On push to main only (after ALL jobs pass, including security):
┌───────────┐
│ Release │ → npm publish + Docker push + GitHub release
└───────────┘
| Job | Description | Duration |
|---|---|---|
| Lint & Format | ESLint + Prettier + TypeSpec compile (pnpm tsp:compile) |
~30s |
| Type Check | TypeScript strict mode validation (requires TypeSpec types) | ~20s |
| Unit Tests | Vitest unit + integration tests | ~20s |
| E2E (CLI) | CLI command execution tests | ~30s |
| E2E (TUI) | Terminal UI interaction tests | ~20s |
| E2E (Web) | Playwright browser tests | ~25s |
| Docker | Build and push SHA-tagged image (non-main only) | ~50s |
| Trivy (deps) | Dependency vulnerability scan (HIGH/CRITICAL) | ~30s |
| Trivy (container) | Docker image vulnerability scan | ~60s |
| Gitleaks | Secret detection in git history | ~15s |
| Semgrep | SAST for TypeScript/JavaScript patterns | ~30s |
| Hadolint | Dockerfile best practices linting | ~5s |
Security scanners run in parallel and block releases on main:
| Scanner | Tool | Severity Filter |
|---|---|---|
| Trivy (deps) | Filesystem scan for dependency CVEs | HIGH, CRITICAL |
| Trivy (container) | Docker image scan for OS/package vulnerabilities | HIGH, CRITICAL |
| Gitleaks | Secret detection (API keys, passwords, tokens) | All findings |
| Semgrep | SAST rules (p/typescript, p/javascript, p/security-audit) |
All findings |
| Hadolint | Dockerfile linting | Warning+ |
Results are uploaded to GitHub Security tab (SARIF format) and displayed in job summaries.
Note: Gitleaks uses the CLI directly (not gitleaks-action) because the GitHub Action requires a paid license for organizations.
Automated code review using Claude Code, focusing on:
| Check Area | What It Validates |
|---|---|
| Documentation Consistency | Changes reflected in docs/, CLAUDE.md, AGENTS.md |
| Architecture Compliance | Clean Architecture layers, dependency rule, patterns |
| TDD & Testing | Test coverage for new functionality |
| Spec-Driven Workflow | Feature PRs have specs/ directory with required files |
Review Output:
Required Secret: CLAUDE_CODE_OAUTH_TOKEN (org-level)
Runs after all parallel jobs pass, including security scanners. Uses semantic-release to:
@shepai/cli packagelatest, v<version>, sha-<commit>chore(release): <version> [skip ci]Images are published to GitHub Container Registry (ghcr.io):
ghcr.io/shep-ai/cli
| Branch | Trigger | Tags |
|---|---|---|
| PR / develop | Docker job | sha-<full-commit-sha> |
| main | semantic-release | latest, v1.2.3, sha-<commit> |
# Latest stable
docker pull ghcr.io/shep-ai/cli:latest
docker run ghcr.io/shep-ai/cli --version
# Specific version
docker pull ghcr.io/shep-ai/cli:v1.0.0
# Specific commit (for testing)
docker pull ghcr.io/shep-ai/cli:sha-abc123...
node:22-alpine (~180MB)shep (UID 1001)node dist/presentation/cli/index.jsReleases are fully automated based on Conventional Commits:
| Commit Type | Version Bump | Example |
|---|---|---|
feat: |
Minor (0.X.0) | feat(cli): add analyze command |
fix: |
Patch (0.0.X) | fix(agents): resolve memory leak |
perf: |
Patch | perf(db): optimize query performance |
refactor: |
Patch | refactor(core): simplify state management |
BREAKING CHANGE |
Major (X.0.0) | Footer in commit message |
Commits that don’t trigger releases:
docs:, style:, test:, build:, ci:, chore:If needed, you can trigger a release manually:
# Ensure you're on main with latest changes
git checkout main && git pull
# Run semantic-release in dry-run mode first
npx semantic-release --dry-run
# If satisfied, run actual release (requires NPM_TOKEN)
NPM_TOKEN=xxx GITHUB_TOKEN=xxx npx semantic-release
| File | Purpose |
|---|---|
.github/workflows/ci.yml |
Main CI/CD workflow (build, test, security, release) |
.github/workflows/pr-check.yml |
PR-specific checks (commitlint, PR title) |
.github/workflows/claude-review.yml |
Claude Code automated review |
release.config.mjs |
semantic-release plugins and settings |
Dockerfile |
Multi-stage build for production image |
.dockerignore |
Files excluded from Docker build context |
commitlint.config.mjs |
Commit message validation rules |
type=gha) for layer cachingdocker build)[skip ci] in release commits| Secret | Purpose | Where to Set |
|---|---|---|
GITHUB_TOKEN |
Automatic, provided by GitHub Actions | Built-in |
NPM_TOKEN |
Publishing to npm registry | Repository secrets |
CLAUDE_CODE_OAUTH_TOKEN |
Claude Code automated PR review | Organization secrets |
Recommended settings for main:
Lint & Format, Type Check, Unit Tests, all E2E jobs, all Security jobsmain branch[skip ci].dockerignore isn’t excluding required filespnpm-lock.yaml is committedpackage.json enginesNPM_TOKEN secret is set and validpackage.json wasn’t manually bumpeddocker build -t shep-cli .
docker run shep-cli --version
npx semantic-release --dry-run
echo "feat(cli): add new command" | npx commitlint
Update when:
Related files: