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
115 changes: 115 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
name: Release

on:
push:
tags:
- 'v[0-9]+.[0-9]+.[0-9]+'

permissions:
contents: write

jobs:
lint:
name: Lint & Format Check
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '22'
cache: 'npm'
- run: npm ci
- run: npm run lint
- run: npm run format:check

test:
name: Unit & Integration Tests
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '22'
cache: 'npm'
- run: npm ci
- run: npm run test:unit
- run: npm run test:integration

build:
name: Build & Bundle Size Check
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '22'
cache: 'npm'
- run: npm ci
- run: npm run build
- name: Check bundle size
run: npm run size-check
- name: Upload build artifacts
uses: actions/upload-artifact@v4
with:
name: dist
path: dist/

release:
name: Create GitHub Release
runs-on: ubuntu-latest
needs: [lint, test, build]
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Download build artifacts
uses: actions/download-artifact@v4
with:
name: dist
path: dist/

- name: Extract version from tag
id: version
run: |
VERSION=${GITHUB_REF_NAME#v}
echo "version=$VERSION" >> $GITHUB_OUTPUT
echo "Releasing version: $VERSION"

- name: Check if package.json version needs update
id: check-version
run: |
CURRENT_VERSION=$(node -p "require('./package.json').version")
TAG_VERSION=${{ steps.version.outputs.version }}
if [ "$CURRENT_VERSION" = "$TAG_VERSION" ]; then
echo "needs_update=false" >> $GITHUB_OUTPUT
echo "Package.json already at version $TAG_VERSION"
else
echo "needs_update=true" >> $GITHUB_OUTPUT
echo "Package.json version $CURRENT_VERSION differs from tag $TAG_VERSION"
fi

- name: Update package.json version
if: steps.check-version.outputs.needs_update == 'true'
run: |
npm version ${{ steps.version.outputs.version }} --no-git-tag-version
echo "Updated package.json to version ${{ steps.version.outputs.version }}"

- name: Commit and push version update
if: steps.check-version.outputs.needs_update == 'true'
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git add package.json package-lock.json
git commit -m "chore(release): ${{ github.ref_name }}"
git push origin HEAD:main

- name: Create GitHub Release
uses: softprops/action-gh-release@v2
with:
generate_release_notes: true
files: |
dist/sonar-quiz.iife.js
dist/sonar-quiz.iife.js.map
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
2 changes: 2 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -557,6 +557,8 @@ function getStorageKey(release: ReleaseId, serviceId: ServiceId): string {
- IndexedDB (primary) - obfuscation at adapter layer; sessionStorage unchanged (009-encrypt-stored-data)
- CSS3 + TypeScript 5.x (for JS integration) + Existing DITA template CSS (`f13ldman.css`), Lit 3.x components (010-css-answer-hiding)
- N/A (CSS-only feature) (010-css-answer-hiding)
- YAML (GitHub Actions workflows), Bash (scripts) + GitHub Actions (actions/checkout, actions/setup-node, softprops/action-gh-release) (011-release-automation)
- N/A (CI/CD infrastructure only) (011-release-automation)

## Recent Changes
- 001-security-refactor: Added TypeScript 5.x / JavaScript ES2020+ + Lit 3.0 (Web Components), Vite 5.x (build), Vitest (testing)
12 changes: 12 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -123,10 +123,22 @@ npm run build:dita

This copies `dist/sonar-quiz.iife.js` to `dita/template/resources/` for inclusion in WebHelp output. See [dita/README.md](./dita/README.md) for DITA authoring guidelines and template customization.

## Releases

Releases are created by pushing a version tag to the main branch:

```bash
git tag v0.2.0
git push origin v0.2.0
```

See [docs/RELEASE.md](./docs/RELEASE.md) for complete release instructions.

## Project Documentation

| Document | Description |
|----------|-------------|
| [docs/RELEASE.md](./docs/RELEASE.md) | Release process and versioning guide |
| [System_Requirements.md](./System_Requirements.md) | Functional requirements, user roles, data model, and authoring rules |
| [Technical_Design.md](./Technical_Design.md) | Architecture, technology decisions, packaging, integration, and acceptance criteria |
| [ARCHITECTURE_FLOWS.md](./ARCHITECTURE_FLOWS.md) | Event flows, login processes, DOM patterns, and service interactions |
Expand Down
133 changes: 133 additions & 0 deletions docs/RELEASE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
# Release Process

This document describes how to create releases for the BrowserTest (Sonar Quiz System) project.

## Overview

Releases are automated via GitHub Actions. When you push a version tag to the main branch, a workflow automatically:

1. Runs all CI checks (lint, tests, build)
2. Builds the production bundle
3. Creates a GitHub Release with release notes
4. Attaches the bundle artifacts

## Versioning

This project uses [Semantic Versioning](https://semver.org/):

- **MAJOR** (`X.0.0`): Breaking changes
- **MINOR** (`0.X.0`): New features (backward-compatible)
- **PATCH** (`0.0.X`): Bug fixes (backward-compatible)

## How to Create a Release

### Prerequisites

- You must have push access to the repository
- The main branch must be in a passing CI state

### Steps

1. **Ensure you're on the latest main branch:**

```bash
git checkout main
git pull origin main
```

2. **Create and push a version tag:**

```bash
git tag v0.2.0
git push origin v0.2.0
```

3. **Monitor the release workflow:**
- Go to the [Actions tab](../../actions)
- Watch the "Release" workflow complete (~3-5 minutes)

4. **Verify the release:**
- Go to the [Releases page](../../releases)
- Confirm the new release exists with:
- Correct version number
- Auto-generated release notes
- Attached `sonar-quiz.iife.js` bundle
- Attached `sonar-quiz.iife.js.map` source map

### Using GitHub CLI

```bash
# Create tag and release in one command
gh release create v0.2.0 --generate-notes
```

## Version Tag Format

Tags **must** follow semantic versioning format: `vX.Y.Z`

| Valid Tags | Invalid Tags |
|------------|--------------|
| `v0.1.0` | `0.1.0` (missing 'v' prefix) |
| `v1.0.0` | `v1.0` (missing patch number) |
| `v10.20.30` | `release-1.0.0` (wrong prefix) |
| `v2.0.0-beta.1` | N/A (pre-release not currently supported) |

## What's Included in a Release

Each release includes:

- **sonar-quiz.iife.js** - The production bundle (IIFE format)
- **sonar-quiz.iife.js.map** - Source map for debugging
- **Source code** - Automatically generated zip and tar.gz archives

## Troubleshooting

### Tag pushed but no release created

1. **Check tag format** - Must match `vX.Y.Z` pattern exactly
2. **Verify tag was pushed:**
```bash
git ls-remote --tags origin | grep v0.2.0
```
3. **Check Actions tab** - Look for workflow failures
4. **Review CI status** - Release won't be created if lint/tests/build fail

### CI checks failing after tag push

The release workflow runs the full CI suite. If it fails:

1. Fix the issues on main branch
2. Delete the failed tag:
```bash
git push --delete origin v0.2.0
git tag -d v0.2.0
```
3. Create the tag again after fixes are merged

### Re-releasing the same version

If you need to re-release (e.g., release was incomplete):

```bash
# Delete the existing release
gh release delete v0.2.0 --yes

# Delete the remote tag
git push --delete origin v0.2.0

# Delete local tag
git tag -d v0.2.0

# Create new tag and push
git tag v0.2.0
git push origin v0.2.0
```

### Package.json version mismatch

The release workflow automatically updates `package.json` to match the tag version. If there's a mismatch, the tag version is the source of truth.

## Related Documentation

- [CLAUDE.md](../CLAUDE.md) - Development guidelines and project architecture
- [README.md](../README.md) - Project overview and quick start
36 changes: 36 additions & 0 deletions specs/011-release-automation/checklists/requirements.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# Specification Quality Checklist: Release Automation

**Purpose**: Validate specification completeness and quality before proceeding to planning
**Created**: 2025-11-28
**Feature**: [spec.md](../spec.md)

## Content Quality

- [x] No implementation details (languages, frameworks, APIs)
- [x] Focused on user value and business needs
- [x] Written for non-technical stakeholders
- [x] All mandatory sections completed

## Requirement Completeness

- [x] No [NEEDS CLARIFICATION] markers remain
- [x] Requirements are testable and unambiguous
- [x] Success criteria are measurable
- [x] Success criteria are technology-agnostic (no implementation details)
- [x] All acceptance scenarios are defined
- [x] Edge cases are identified
- [x] Scope is clearly bounded
- [x] Dependencies and assumptions identified

## Feature Readiness

- [x] All functional requirements have clear acceptance criteria
- [x] User scenarios cover primary flows
- [x] Feature meets measurable outcomes defined in Success Criteria
- [x] No implementation details leak into specification

## Notes

- All items pass validation
- Spec is ready for `/speckit.clarify` or `/speckit.plan`
- Conventional commits assumption documented - may need user confirmation during planning
67 changes: 67 additions & 0 deletions specs/011-release-automation/plan.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
# Implementation Plan: Release Automation

**Branch**: `011-release-automation` | **Date**: 2025-11-28 | **Spec**: [spec.md](./spec.md)
**Input**: Feature specification from `/specs/011-release-automation/spec.md`

## Summary

Establish CI/CD automation for semantic versioning releases via GitHub Actions. Releases are triggered by pushing a `vX.Y.Z` tag to the main branch. The workflow validates CI checks, builds the bundle, updates package.json to match the tag version, and creates a GitHub Release with artifacts attached.

## Technical Context

**Language/Version**: YAML (GitHub Actions workflows), Bash (scripts)
**Primary Dependencies**: GitHub Actions (actions/checkout, actions/setup-node, softprops/action-gh-release)
**Storage**: N/A (CI/CD infrastructure only)
**Testing**: Tag push to trigger workflow, verify release creation
**Target Platform**: GitHub Actions runners (ubuntu-latest)
**Project Type**: Single project with existing CI workflows
**Performance Goals**: Release workflow completes in <5 minutes
**Constraints**: Must run all CI checks before release; tag is source of truth for version

## Constitution Check

*GATE: Must pass before Phase 0 research. Re-check after Phase 1 design.*

- [x] **Offline-First**: N/A - CI/CD infrastructure, not runtime code. Does not affect offline operation.
- [x] **Progressive Enhancement**: N/A - No changes to runtime behavior or DITA enhancement.
- [x] **Test-Driven Development**: Workflow validated via tag push testing before merge.
- [x] **Phase-Gated Delivery**: Clear exit criteria: workflow runs, release created with artifacts.
- [x] **Performance Constraints**: N/A - Does not affect bundle size or runtime performance.
- [x] **Data Isolation**: N/A - No user data involved.
- [x] **Zero Configuration**: N/A - Deployment infrastructure, not runtime script.

**All gates pass** - This feature is purely CI/CD infrastructure with no impact on the constitution's runtime constraints.

## Project Structure

### Documentation (this feature)

```text
specs/011-release-automation/
├── plan.md # This file
├── research.md # Phase 0 output
├── data-model.md # N/A - no data entities
├── quickstart.md # Release instructions
├── contracts/ # N/A - no API contracts
└── tasks.md # Phase 2 output
```

### Source Code (repository root)

```text
.github/workflows/
├── ci.yml # Existing CI workflow (lint, test, build)
├── pages.yml # Existing GitHub Pages deployment
├── pr-preview.yml # Existing PR preview deployment
├── pr-preview-comment.yml
└── release.yml # NEW: Release automation workflow (tag-triggered)

docs/
└── RELEASE.md # NEW: Release process documentation
```

**Structure Decision**: Single new workflow file plus documentation. Follows existing GitHub Actions patterns established in ci.yml.

## Complexity Tracking

No constitution violations. Feature is infrastructure-only.
Loading
Loading