From 896816c185c9010f974175a8a52825190b70784a Mon Sep 17 00:00:00 2001 From: Alex Sparkes Date: Sun, 25 Jan 2026 17:27:54 +0000 Subject: [PATCH] feat: add professional three-branch release workflow automation (#1129) - Add version-bump workflow for semantic versioning across all files - Add beta-release workflow for automated pre-release testing - Add production-release workflow with manual approval gates - Add hotfix-release workflow for emergency patches - Create comprehensive CONTRIBUTING.md with workflow guide - Create detailed RELEASE_PROCESS.md for maintainers - Add PR template with release checklists - Update CODEOWNERS to protect workflow files - Update README with contribution links - Remove /docs from .gitignore to allow documentation This implements a dev beta main branching strategy with: - Automated version management across 6 files - Changelog generation from conventional commits - GitHub Releases with build artifacts - Environment-based approvals for production - Back-merge support for hotfixes --- .github/CODEOWNERS | 6 + .github/PULL_REQUEST_TEMPLATE.md | 65 ++++ .github/workflows/beta-release.yml | 165 ++++++++ .github/workflows/hotfix-release.yml | 194 ++++++++++ .github/workflows/production-release.yml | 187 +++++++++ .github/workflows/version-bump.yml | 140 +++++++ .gitignore | 1 - CONTRIBUTING.md | 310 +++++++++++++++ README.md | 10 + docs/RELEASE_PROCESS.md | 469 +++++++++++++++++++++++ 10 files changed, 1546 insertions(+), 1 deletion(-) create mode 100644 .github/PULL_REQUEST_TEMPLATE.md create mode 100644 .github/workflows/beta-release.yml create mode 100644 .github/workflows/hotfix-release.yml create mode 100644 .github/workflows/production-release.yml create mode 100644 .github/workflows/version-bump.yml create mode 100644 CONTRIBUTING.md create mode 100644 docs/RELEASE_PROCESS.md diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 4e872f20..671244b0 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1,2 +1,8 @@ # Automatically assigned to any PRs * @davidcralph @alexsparkes + +# Workflow files require maintainer approval +/.github/workflows/ @davidcralph @alexsparkes + +# Release process documentation +/docs/RELEASE_PROCESS.md @davidcralph @alexsparkes diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 00000000..bae76c5d --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,65 @@ +## Description + + + + +## Type of Change + + +- [ ] ๐Ÿ› Bug fix (non-breaking change which fixes an issue) +- [ ] โœจ New feature (non-breaking change which adds functionality) +- [ ] ๐Ÿ’ฅ Breaking change (fix or feature that would cause existing functionality to not work as expected) +- [ ] ๐Ÿ“ Documentation update +- [ ] ๐ŸŽจ UI/UX improvement +- [ ] โšก Performance improvement +- [ ] ๐Ÿ”ง Maintenance/refactoring + +## Testing + + +- [ ] Tested on Chrome/Edge +- [ ] Tested on Firefox +- [ ] Tested on Safari (if applicable) +- [ ] Checked console for errors +- [ ] Tested in different screen sizes + +## Checklist + +### General +- [ ] My code follows the project's code style +- [ ] I have performed a self-review of my own code +- [ ] I have commented my code, particularly in hard-to-understand areas +- [ ] My changes generate no new warnings or errors +- [ ] I have tested my changes locally + +### For Feature/Bug Fix PRs +- [ ] I have added/updated tests that prove my fix is effective or that my feature works +- [ ] New and existing unit tests pass locally with my changes +- [ ] I have updated the documentation accordingly + +### For Release PRs (beta โ†’ main) + +- [ ] Version has been bumped in all necessary files +- [ ] Changelog has been updated +- [ ] Beta testing period completed (minimum X days) +- [ ] All critical bugs from beta have been resolved +- [ ] Extension has been tested by at least X beta testers +- [ ] No open P0/P1 issues blocking release +- [ ] Release notes prepared +- [ ] Store submission credentials verified + +## Screenshots (if applicable) + + + + +## Related Issues + + +Closes # +Relates to # + +## Additional Notes + + + diff --git a/.github/workflows/beta-release.yml b/.github/workflows/beta-release.yml new file mode 100644 index 00000000..3846ccda --- /dev/null +++ b/.github/workflows/beta-release.yml @@ -0,0 +1,165 @@ +name: Beta Release + +on: + push: + branches: + - beta + tags: + - 'v*-beta.*' + +permissions: + contents: write + +jobs: + build-and-release: + runs-on: ubuntu-latest + environment: beta + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Setup Bun + uses: oven-sh/setup-bun@v2 + with: + bun-version: '1.3.1' + + - name: Install dependencies + run: bun install + + - name: Build extension + run: bun run build + env: + NODE_ENV: production + + - name: Get version from package.json + id: version + run: | + VERSION=$(node -p "require('./package.json').version") + echo "version=$VERSION" >> $GITHUB_OUTPUT + echo "Building version: $VERSION" + + - name: Generate changelog + id: changelog + run: | + # Get the latest beta or production tag + PREVIOUS_TAG=$(git describe --tags --abbrev=0 HEAD^ 2>/dev/null || echo "") + + if [ -z "$PREVIOUS_TAG" ]; then + echo "No previous tag found, using all commits" + COMMITS=$(git log --pretty=format:"- %s (%h)" HEAD) + else + echo "Generating changelog from $PREVIOUS_TAG to HEAD" + COMMITS=$(git log --pretty=format:"- %s (%h)" ${PREVIOUS_TAG}..HEAD) + fi + + # Create changelog with categorization + FEATURES=$(echo "$COMMITS" | grep -i "^- feat" || echo "") + FIXES=$(echo "$COMMITS" | grep -i "^- fix" || echo "") + CHORES=$(echo "$COMMITS" | grep -i "^- chore\|^- docs\|^- style\|^- refactor" || echo "") + OTHER=$(echo "$COMMITS" | grep -v -i "^- feat\|^- fix\|^- chore\|^- docs\|^- style\|^- refactor" || echo "") + + { + echo "changelog<> $GITHUB_OUTPUT + + - name: Check if release exists + id: check_release + run: | + if gh release view "v${{ steps.version.outputs.version }}" >/dev/null 2>&1; then + echo "exists=true" >> $GITHUB_OUTPUT + else + echo "exists=false" >> $GITHUB_OUTPUT + fi + env: + GH_TOKEN: ${{ github.token }} + + - name: Create or Update GitHub Pre-Release + run: | + RELEASE_NOTES=$(cat <> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "**Version**: v${{ steps.version.outputs.version }}" >> $GITHUB_STEP_SUMMARY + echo "**Release URL**: https://github.com/${{ github.repository }}/releases/tag/v${{ steps.version.outputs.version }}" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "### ๐Ÿ“ฆ Build Artifacts" >> $GITHUB_STEP_SUMMARY + echo "- Chrome/Edge: \`chrome-${{ steps.version.outputs.version }}.zip\`" >> $GITHUB_STEP_SUMMARY + echo "- Firefox: \`firefox-${{ steps.version.outputs.version }}.zip\`" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "### ๐Ÿงช Testing" >> $GITHUB_STEP_SUMMARY + echo "Share the release link with beta testers for feedback." >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "### โš ๏ธ Next Steps" >> $GITHUB_STEP_SUMMARY + echo "1. Test the beta release thoroughly" >> $GITHUB_STEP_SUMMARY + echo "2. Gather feedback from testers" >> $GITHUB_STEP_SUMMARY + echo "3. Fix any critical issues" >> $GITHUB_STEP_SUMMARY + echo "4. When ready, create PR from \`beta\` โ†’ \`main\` for production release" >> $GITHUB_STEP_SUMMARY diff --git a/.github/workflows/hotfix-release.yml b/.github/workflows/hotfix-release.yml new file mode 100644 index 00000000..b2c98cbd --- /dev/null +++ b/.github/workflows/hotfix-release.yml @@ -0,0 +1,194 @@ +name: Hotfix Release + +on: + workflow_dispatch: + inputs: + description: + description: 'Brief description of the hotfix' + required: true + branch_name: + description: 'Hotfix branch name (e.g., hotfix/critical-security-fix)' + required: true + +permissions: + contents: write + pull-requests: write + +jobs: + hotfix-release: + runs-on: ubuntu-latest + environment: production # Requires maintainer approval + steps: + - name: Validate branch name + run: | + if [[ ! "${{ github.event.inputs.branch_name }}" =~ ^hotfix/ ]]; then + echo "โŒ Branch name must start with 'hotfix/'" >> $GITHUB_STEP_SUMMARY + exit 1 + fi + + - name: Checkout hotfix branch + uses: actions/checkout@v4 + with: + ref: ${{ github.event.inputs.branch_name }} + fetch-depth: 0 + + - name: Setup Bun + uses: oven-sh/setup-bun@v2 + with: + bun-version: '1.3.1' + + - name: Configure Git + run: | + git config user.name "github-actions[bot]" + git config user.email "github-actions[bot]@users.noreply.github.com" + + - name: Calculate hotfix version (auto-patch bump) + id: version + run: | + CURRENT_VERSION=$(node -p "require('./package.json').version") + echo "Current version: $CURRENT_VERSION" + + # Remove any pre-release suffix + BASE_VERSION=$(echo $CURRENT_VERSION | sed 's/-.*$//') + IFS='.' read -r -a VERSION_PARTS <<< "$BASE_VERSION" + + MAJOR="${VERSION_PARTS[0]}" + MINOR="${VERSION_PARTS[1]}" + PATCH="${VERSION_PARTS[2]}" + + # Hotfixes always bump patch version + PATCH=$((PATCH + 1)) + NEW_VERSION="${MAJOR}.${MINOR}.${PATCH}" + + echo "new_version=$NEW_VERSION" >> $GITHUB_OUTPUT + echo "Hotfix version will be: $NEW_VERSION" + + - name: Update version in all files + run: | + # Update package.json + bun x json -I -f package.json -e "this.version='${{ steps.version.outputs.new_version }}'" + + # Update manifests + bun x json -I -f manifest/chrome.json -e "this.version='${{ steps.version.outputs.new_version }}'" + bun x json -I -f manifest/firefox.json -e "this.version='${{ steps.version.outputs.new_version }}'" + bun x json -I -f safari/Mue\ Extension/Resources/manifest.json -e "this.version='${{ steps.version.outputs.new_version }}'" + + # Update Safari Xcode project + sed -i "s/MARKETING_VERSION = [^;]*/MARKETING_VERSION = ${{ steps.version.outputs.new_version }}/g" safari/Mue.xcodeproj/project.pbxproj + + # Update constants.js + sed -i "s/export const VERSION = '[^']*'/export const VERSION = '${{ steps.version.outputs.new_version }}'/" src/config/constants.js + + - name: Install dependencies + run: bun install + + - name: Build extension + run: bun run build + env: + NODE_ENV: production + + - name: Commit version bump + run: | + git add package.json manifest/chrome.json manifest/firefox.json safari/Mue\ Extension/Resources/manifest.json safari/Mue.xcodeproj/project.pbxproj src/config/constants.js + git commit -m "chore: hotfix version bump to ${{ steps.version.outputs.new_version }}" + + - name: Merge hotfix to main + run: | + git fetch origin main + git checkout main + git merge --no-ff ${{ github.event.inputs.branch_name }} -m "fix: merge hotfix ${{ github.event.inputs.branch_name }} (#${{ steps.version.outputs.new_version }})" + git tag -a "v${{ steps.version.outputs.new_version }}" -m "Hotfix v${{ steps.version.outputs.new_version }}: ${{ github.event.inputs.description }}" + git push origin main + git push origin "v${{ steps.version.outputs.new_version }}" + + - name: Generate changelog + id: changelog + run: | + # Get commits from hotfix branch + git checkout ${{ github.event.inputs.branch_name }} + COMMITS=$(git log --pretty=format:"- %s (%h)" origin/main..${{ github.event.inputs.branch_name }}) + + { + echo "changelog<> $GITHUB_OUTPUT + + - name: Create GitHub Release + run: | + git checkout main + + RELEASE_NOTES=$(cat <> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "**Version**: v${{ steps.version.outputs.new_version }}" >> $GITHUB_STEP_SUMMARY + echo "**Description**: ${{ github.event.inputs.description }}" >> $GITHUB_STEP_SUMMARY + echo "**Release URL**: https://github.com/${{ github.repository }}/releases/tag/v${{ steps.version.outputs.new_version }}" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "### โœ… Completed Actions" >> $GITHUB_STEP_SUMMARY + echo "- [x] Merged hotfix to \`main\`" >> $GITHUB_STEP_SUMMARY + echo "- [x] Created tag v${{ steps.version.outputs.new_version }}" >> $GITHUB_STEP_SUMMARY + echo "- [x] Created GitHub Release" >> $GITHUB_STEP_SUMMARY + echo "- [x] Back-merged to \`beta\` branch" >> $GITHUB_STEP_SUMMARY + echo "- [x] Back-merged to \`dev\` branch" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "### ๐Ÿšจ URGENT: Manual Steps Required" >> $GITHUB_STEP_SUMMARY + echo "1. **Submit to stores IMMEDIATELY**:" >> $GITHUB_STEP_SUMMARY + echo " - Go to [Submit workflow](https://github.com/${{ github.repository }}/actions/workflows/submit.yml)" >> $GITHUB_STEP_SUMMARY + echo " - Run with tag: \`${{ steps.version.outputs.new_version }}\`" >> $GITHUB_STEP_SUMMARY + echo "2. Update [muetab.com/blog/changelog](https://muetab.com/blog/changelog)" >> $GITHUB_STEP_SUMMARY + echo "3. Notify users via Discord/social media" >> $GITHUB_STEP_SUMMARY + echo "4. Delete hotfix branch: \`${{ github.event.inputs.branch_name }}\`" >> $GITHUB_STEP_SUMMARY diff --git a/.github/workflows/production-release.yml b/.github/workflows/production-release.yml new file mode 100644 index 00000000..af7462bf --- /dev/null +++ b/.github/workflows/production-release.yml @@ -0,0 +1,187 @@ +name: Production Release + +on: + pull_request: + branches: + - main + types: + - closed + +permissions: + contents: write + +jobs: + # Only run if PR was merged (not just closed) + check-merge: + if: github.event.pull_request.merged == true && github.event.pull_request.head.ref == 'beta' + runs-on: ubuntu-latest + outputs: + should_release: ${{ steps.check.outputs.should_release }} + steps: + - name: Check if this is a beta to main merge + id: check + run: | + echo "should_release=true" >> $GITHUB_OUTPUT + echo "โœ… This is a beta โ†’ main merge, proceeding with production release" >> $GITHUB_STEP_SUMMARY + + build-and-release: + needs: check-merge + if: needs.check-merge.outputs.should_release == 'true' + runs-on: ubuntu-latest + environment: production # Requires manual approval from maintainers + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: main + fetch-depth: 0 + + - name: Setup Bun + uses: oven-sh/setup-bun@v2 + with: + bun-version: '1.3.1' + + - name: Install dependencies + run: bun install + + - name: Build extension + run: bun run build + env: + NODE_ENV: production + + - name: Get version from package.json + id: version + run: | + VERSION=$(node -p "require('./package.json').version") + # Remove any pre-release suffix for production + STABLE_VERSION=$(echo $VERSION | sed 's/-.*$//') + echo "version=$STABLE_VERSION" >> $GITHUB_OUTPUT + echo "full_version=$VERSION" >> $GITHUB_OUTPUT + echo "Building production version: $STABLE_VERSION" + + - name: Generate production changelog + id: changelog + run: | + # Get the latest production (non-beta) tag + PREVIOUS_TAG=$(git tag -l 'v*' --sort=-v:refname | grep -v 'beta\|alpha\|rc' | head -n 1 || echo "") + + if [ -z "$PREVIOUS_TAG" ]; then + echo "No previous production tag found, using all commits" + COMMITS=$(git log --pretty=format:"- %s (%h)" main) + else + echo "Generating changelog from $PREVIOUS_TAG to main" + COMMITS=$(git log --pretty=format:"- %s (%h)" ${PREVIOUS_TAG}..main) + fi + + # Categorize commits + FEATURES=$(echo "$COMMITS" | grep -i "^- feat" || echo "") + FIXES=$(echo "$COMMITS" | grep -i "^- fix" || echo "") + PERFORMANCE=$(echo "$COMMITS" | grep -i "^- perf" || echo "") + BREAKING=$(echo "$COMMITS" | grep -i "BREAKING CHANGE" || echo "") + + { + echo "changelog<> $GITHUB_OUTPUT + + - name: Check if tag exists + id: check_tag + run: | + if git rev-parse "v${{ steps.version.outputs.version }}" >/dev/null 2>&1; then + echo "exists=true" >> $GITHUB_OUTPUT + else + echo "exists=false" >> $GITHUB_OUTPUT + fi + + - name: Create production tag + if: steps.check_tag.outputs.exists == 'false' + run: | + git config user.name "github-actions[bot]" + git config user.email "github-actions[bot]@users.noreply.github.com" + git tag -a "v${{ steps.version.outputs.version }}" -m "Release v${{ steps.version.outputs.version }}" + git push origin "v${{ steps.version.outputs.version }}" + + - name: Create GitHub Release + run: | + RELEASE_NOTES=$(cat <> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "**Version**: v${{ steps.version.outputs.version }}" >> $GITHUB_STEP_SUMMARY + echo "**Release URL**: https://github.com/${{ github.repository }}/releases/tag/v${{ steps.version.outputs.version }}" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "### ๐Ÿ“ฆ Build Artifacts" >> $GITHUB_STEP_SUMMARY + echo "- Chrome/Edge: \`chrome-${{ steps.version.outputs.version }}.zip\`" >> $GITHUB_STEP_SUMMARY + echo "- Firefox: \`firefox-${{ steps.version.outputs.version }}.zip\`" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "### โš ๏ธ Manual Steps Required" >> $GITHUB_STEP_SUMMARY + echo "1. Go to [GitHub Actions](https://github.com/${{ github.repository }}/actions/workflows/submit.yml)" >> $GITHUB_STEP_SUMMARY + echo "2. Click 'Run workflow'" >> $GITHUB_STEP_SUMMARY + echo "3. Enter tag: \`${{ steps.version.outputs.version }}\`" >> $GITHUB_STEP_SUMMARY + echo "4. Click 'Run workflow' to submit to Chrome/Firefox/Edge stores" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "### ๐Ÿ“ข Post-Release Checklist" >> $GITHUB_STEP_SUMMARY + echo "- [ ] Submit to browser stores (see manual steps above)" >> $GITHUB_STEP_SUMMARY + echo "- [ ] Update [muetab.com/blog/changelog](https://muetab.com/blog/changelog)" >> $GITHUB_STEP_SUMMARY + echo "- [ ] Announce release on Discord/social media" >> $GITHUB_STEP_SUMMARY + echo "- [ ] Monitor issue tracker for bug reports" >> $GITHUB_STEP_SUMMARY + echo "- [ ] Merge \`main\` back to \`beta\` and \`dev\` to sync version" >> $GITHUB_STEP_SUMMARY diff --git a/.github/workflows/version-bump.yml b/.github/workflows/version-bump.yml new file mode 100644 index 00000000..11cf6e06 --- /dev/null +++ b/.github/workflows/version-bump.yml @@ -0,0 +1,140 @@ +name: Version Bump + +on: + workflow_dispatch: + inputs: + bump_type: + description: 'Version bump type' + required: true + type: choice + options: + - patch # 7.5.0 -> 7.5.1 (bug fixes) + - minor # 7.5.0 -> 7.6.0 (new features) + - major # 7.5.0 -> 8.0.0 (breaking changes) + pre_release: + description: 'Pre-release label (leave empty for stable release)' + required: false + type: choice + options: + - '' + - beta + - rc + - alpha + +permissions: + contents: write + +jobs: + bump-version: + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + fetch-depth: 0 + token: ${{ secrets.GITHUB_TOKEN }} + + - name: Setup Bun + uses: oven-sh/setup-bun@v2 + with: + bun-version: '1.3.1' + + - name: Configure Git + run: | + git config user.name "github-actions[bot]" + git config user.email "github-actions[bot]@users.noreply.github.com" + + - name: Calculate new version + id: version + run: | + CURRENT_VERSION=$(node -p "require('./package.json').version") + echo "Current version: $CURRENT_VERSION" + + # Remove any pre-release suffix for base version + BASE_VERSION=$(echo $CURRENT_VERSION | sed 's/-.*$//') + IFS='.' read -r -a VERSION_PARTS <<< "$BASE_VERSION" + + MAJOR="${VERSION_PARTS[0]}" + MINOR="${VERSION_PARTS[1]}" + PATCH="${VERSION_PARTS[2]}" + + # Bump version based on type + case "${{ github.event.inputs.bump_type }}" in + major) + MAJOR=$((MAJOR + 1)) + MINOR=0 + PATCH=0 + ;; + minor) + MINOR=$((MINOR + 1)) + PATCH=0 + ;; + patch) + PATCH=$((PATCH + 1)) + ;; + esac + + NEW_VERSION="${MAJOR}.${MINOR}.${PATCH}" + + # Add pre-release label if specified + if [ -n "${{ github.event.inputs.pre_release }}" ]; then + # Get beta number by counting existing beta tags for this version + BETA_COUNT=$(git tag -l "v${NEW_VERSION}-${{ github.event.inputs.pre_release }}.*" | wc -l) + BETA_NUM=$((BETA_COUNT + 1)) + NEW_VERSION="${NEW_VERSION}-${{ github.event.inputs.pre_release }}.${BETA_NUM}" + fi + + echo "new_version=$NEW_VERSION" >> $GITHUB_OUTPUT + echo "New version will be: $NEW_VERSION" + + - name: Update package.json + run: | + bun x json -I -f package.json -e "this.version='${{ steps.version.outputs.new_version }}'" + + - name: Update Chrome manifest + run: | + VERSION_WITHOUT_PRERELEASE=$(echo "${{ steps.version.outputs.new_version }}" | sed 's/-.*$//') + bun x json -I -f manifest/chrome.json -e "this.version='${VERSION_WITHOUT_PRERELEASE}'" + + - name: Update Firefox manifest + run: | + VERSION_WITHOUT_PRERELEASE=$(echo "${{ steps.version.outputs.new_version }}" | sed 's/-.*$//') + bun x json -I -f manifest/firefox.json -e "this.version='${VERSION_WITHOUT_PRERELEASE}'" + + - name: Update Safari manifest + run: | + VERSION_WITHOUT_PRERELEASE=$(echo "${{ steps.version.outputs.new_version }}" | sed 's/-.*$//') + bun x json -I -f safari/Mue\ Extension/Resources/manifest.json -e "this.version='${VERSION_WITHOUT_PRERELEASE}'" + + - name: Update Safari Xcode project + run: | + VERSION_WITHOUT_PRERELEASE=$(echo "${{ steps.version.outputs.new_version }}" | sed 's/-.*$//') + sed -i "s/MARKETING_VERSION = [^;]*/MARKETING_VERSION = ${VERSION_WITHOUT_PRERELEASE}/g" safari/Mue.xcodeproj/project.pbxproj + + - name: Update constants.js + run: | + sed -i "s/export const VERSION = '[^']*'/export const VERSION = '${{ steps.version.outputs.new_version }}'/" src/config/constants.js + + - name: Commit version bump + run: | + git add package.json manifest/chrome.json manifest/firefox.json safari/Mue\ Extension/Resources/manifest.json safari/Mue.xcodeproj/project.pbxproj src/config/constants.js + git commit -m "chore: bump version to ${{ steps.version.outputs.new_version }}" + git tag -a "v${{ steps.version.outputs.new_version }}" -m "Release v${{ steps.version.outputs.new_version }}" + + - name: Push changes + run: | + git push origin ${{ github.ref_name }} + git push origin "v${{ steps.version.outputs.new_version }}" + + - name: Summary + run: | + echo "โœ… Version bumped to ${{ steps.version.outputs.new_version }}" >> $GITHUB_STEP_SUMMARY + echo "๐Ÿ“ฆ Tag created: v${{ steps.version.outputs.new_version }}" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "### Files updated:" >> $GITHUB_STEP_SUMMARY + echo "- package.json" >> $GITHUB_STEP_SUMMARY + echo "- manifest/chrome.json" >> $GITHUB_STEP_SUMMARY + echo "- manifest/firefox.json" >> $GITHUB_STEP_SUMMARY + echo "- safari/Mue Extension/Resources/manifest.json" >> $GITHUB_STEP_SUMMARY + echo "- safari/Mue.xcodeproj/project.pbxproj" >> $GITHUB_STEP_SUMMARY + echo "- src/config/constants.js" >> $GITHUB_STEP_SUMMARY diff --git a/.gitignore b/.gitignore index 98d1e06f..3fd28081 100644 --- a/.gitignore +++ b/.gitignore @@ -5,7 +5,6 @@ node_modules/ build/ .idea/ dist/ -/docs # Safari Extension Build Files safari/Mue Extension/Resources/*.html diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 00000000..b279f432 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,310 @@ +# Contributing to Mue + +Thanks for your interest in contributing to Mue! We welcome contributions from the community. + +## ๐Ÿ“‹ Table of Contents + +- [Code of Conduct](#code-of-conduct) +- [Getting Started](#getting-started) +- [Development Workflow](#development-workflow) +- [Branch Strategy](#branch-strategy) +- [Making Changes](#making-changes) +- [Commit Messages](#commit-messages) +- [Pull Request Process](#pull-request-process) +- [Release Process](#release-process) + +## Code of Conduct + +Please be respectful and constructive in your interactions with the community. + +## Getting Started + +### Prerequisites + +- [Bun](https://bun.sh/) >= 1.3.0 +- Node.js >= 20.0.0 (for some tooling) +- Git + +### Setup + +1. Fork the repository +2. Clone your fork: + ```bash + git clone https://github.com/YOUR_USERNAME/mue.git + cd mue + ``` + +3. Install dependencies: + ```bash + bun install + ``` + +4. Start development server: + ```bash + bun run dev + ``` + +## Development Workflow + +### Scripts + +- `bun run dev` - Start development server with hot reload +- `bun run dev:host` - Start development server accessible on network +- `bun run build` - Build production extension for all browsers +- `bun run lint` - Run ESLint and Stylelint +- `bun run lint:fix` - Auto-fix linting issues +- `bun run pretty` - Format code with Prettier + +### Testing Your Changes + +1. Load the extension in your browser: + - **Chrome/Edge**: Go to `chrome://extensions`, enable Developer mode, click "Load unpacked", select `dist` folder + - **Firefox**: Go to `about:debugging#/runtime/this-firefox`, click "Load Temporary Add-on", select any file in `dist` folder + +2. Test your changes thoroughly across different browsers + +## Branch Strategy + +Mue uses a three-branch workflow: + +``` +dev (active development) + โ†“ +beta (release candidates) + โ†“ +main (production/stable) +``` + +### Branches + +- **`dev`** - Active development branch + - All feature and bug fix PRs merge here first + - Maintainers can push directly for small fixes + - Contributors must create PRs + - CI must pass before merge + +- **`beta`** - Release candidate testing + - PRs from `dev` โ†’ `beta` for release candidates + - Triggers beta release workflow + - Requires 2 maintainer approvals + - Used for testing with beta testers before production + +- **`main`** - Production/stable releases + - PRs from `beta` โ†’ `main` only + - Triggers production release workflow + - Requires 2 maintainer approvals + manual environment approval + - Represents current live extension version + +### Special Branches + +- **`hotfix/*`** - Emergency production fixes + - Branch from `main` for critical bugs + - Triggers hotfix workflow (auto-merges to all branches) + - Maintainers only + +## Making Changes + +### For Contributors + +1. Create a feature branch from `dev`: + ```bash + git checkout dev + git pull origin dev + git checkout -b feature/your-feature-name + ``` + +2. Make your changes following our code style + +3. Test your changes locally + +4. Commit your changes (see [Commit Messages](#commit-messages)) + +5. Push to your fork: + ```bash + git push origin feature/your-feature-name + ``` + +6. Create a Pull Request targeting the `dev` branch + +### For Maintainers + +Maintainers can push directly to `dev` for small fixes, or follow the contributor process for larger changes. + +## Commit Messages + +We use [Conventional Commits](https://www.conventionalcommits.org/) for automated changelog generation. + +### Format + +``` +(): + +[optional body] + +[optional footer] +``` + +### Types + +- `feat:` - New feature +- `fix:` - Bug fix +- `perf:` - Performance improvement +- `docs:` - Documentation changes +- `style:` - Code style changes (formatting, etc.) +- `refactor:` - Code refactoring +- `test:` - Adding or updating tests +- `chore:` - Maintenance tasks, dependency updates + +### Examples + +```bash +feat(weather): add hourly forecast widget +fix(greeting): resolve time zone display issue +perf(background): optimize image loading +docs(readme): update installation instructions +chore: bump version to 7.6.0 +``` + +### Breaking Changes + +For breaking changes, add `BREAKING CHANGE:` in the commit body: + +```bash +feat(api): change settings storage format + +BREAKING CHANGE: Settings format has changed. Users will need to reconfigure their settings. +``` + +## Pull Request Process + +1. **Fill out the PR template** completely + +2. **Ensure all checks pass**: + - โœ… Build succeeds + - โœ… Linting passes + - โœ… No merge conflicts + +3. **Get reviews**: + - Contributors: 1 maintainer approval required + - Beta โ†’ Main: 2 maintainer approvals required + +4. **Address review feedback** + +5. **Squash commits** if requested (maintainers can squash on merge) + +6. **Wait for merge** - maintainers will merge when ready + +### PR Guidelines + +- Keep PRs focused on a single feature/fix +- Include screenshots/videos for UI changes +- Update documentation if needed +- Link related issues +- Test on multiple browsers + +## Release Process + +### Version Numbering + +We follow [Semantic Versioning](https://semver.org/): + +- **Major** (8.0.0): Breaking changes, major feature overhauls +- **Minor** (7.6.0): New features, backward-compatible +- **Patch** (7.5.1): Bug fixes, small improvements + +### Release Workflow (Maintainers Only) + +#### 1. Development Phase + +Contributors and maintainers work on `dev` branch. + +#### 2. Create Beta Release + +When ready for testing: + +1. Run version bump workflow: + ``` + Actions โ†’ Version Bump โ†’ Run workflow + - Branch: dev + - Bump type: minor/major/patch + - Pre-release: beta + ``` + +2. Create PR from `dev` โ†’ `beta` + +3. Merge PR (triggers beta release workflow) + +4. Share beta release with testers + +5. Gather feedback and fix issues on `dev` + +6. Repeat until stable + +#### 3. Promote to Production + +When beta is stable: + +1. Create PR from `beta` โ†’ `main` with checklist: + - [ ] Beta tested for X days + - [ ] All critical bugs resolved + - [ ] Y+ testers approved + - [ ] Release notes prepared + +2. Get 2 maintainer approvals + +3. Merge PR (triggers production release workflow) + +4. Workflow pauses for manual approval (10 min wait) + +5. Approve in GitHub Actions โ†’ Environments โ†’ production + +6. Release is created on GitHub + +7. Manually trigger store submission: + ``` + Actions โ†’ Submit โ†’ Run workflow + - Enter version tag (e.g., 7.6.0) + ``` + +#### 4. Emergency Hotfix + +For critical production bugs: + +1. Create hotfix branch from `main`: + ```bash + git checkout main + git pull origin main + git checkout -b hotfix/critical-bug-fix + ``` + +2. Fix the issue and commit + +3. Push branch: + ```bash + git push origin hotfix/critical-bug-fix + ``` + +4. Run hotfix workflow: + ``` + Actions โ†’ Hotfix Release โ†’ Run workflow + - Description: Brief description + - Branch name: hotfix/critical-bug-fix + ``` + +5. Workflow will: + - Auto-bump patch version + - Merge to `main` + - Create release + - Back-merge to `beta` and `dev` + +6. Immediately submit to stores + +## Questions? + +- ๐Ÿ’ฌ Join our [Discord](https://discord.gg/zv8C9F8) (if available) +- ๐Ÿ“ง Email: [contact info] +- ๐Ÿ› Report bugs: [GitHub Issues](https://github.com/mue/mue/issues) + +## License + +By contributing, you agree that your contributions will be licensed under the BSD-3-Clause License. diff --git a/README.md b/README.md index 841ba1f6..50dd8d85 100644 --- a/README.md +++ b/README.md @@ -49,6 +49,16 @@ Install dependencies with `bun install`, and then you can run any of the followi - `bun run translations` - migrate old translation format to new - `bun run translations:percentages` - update translation completion percentages from Weblate +### Contributing + +We welcome contributions! Please read [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines on: +- Development workflow +- Branch strategy (dev โ†’ beta โ†’ main) +- Commit message format +- Pull request process + +For maintainers, see [docs/RELEASE_PROCESS.md](docs/RELEASE_PROCESS.md) for release procedures. + ## ๐Ÿณ Docker development Hot reload is available while coding. diff --git a/docs/RELEASE_PROCESS.md b/docs/RELEASE_PROCESS.md new file mode 100644 index 00000000..7db12ba0 --- /dev/null +++ b/docs/RELEASE_PROCESS.md @@ -0,0 +1,469 @@ +# Mue Release Process + +This document outlines the complete release process for Mue maintainers. + +## ๐Ÿ“‹ Table of Contents + +- [Overview](#overview) +- [Version Numbering](#version-numbering) +- [Pre-Release Checklist](#pre-release-checklist) +- [Beta Release Process](#beta-release-process) +- [Production Release Process](#production-release-process) +- [Hotfix Release Process](#hotfix-release-process) +- [Post-Release Tasks](#post-release-tasks) +- [Store Submission](#store-submission) +- [Troubleshooting](#troubleshooting) + +## Overview + +Mue uses a three-branch release workflow: + +``` +dev โ†’ beta โ†’ main +``` + +- **`dev`**: Active development and feature integration +- **`beta`**: Release candidates for community testing +- **`main`**: Production-ready stable releases + +## Version Numbering + +We follow [Semantic Versioning](https://semver.org/): `MAJOR.MINOR.PATCH` + +### When to Bump + +| Type | When | Example | +|------|------|---------| +| **Major** (x.0.0) | Breaking changes, API changes, major UI overhaul | 7.5.0 โ†’ 8.0.0 | +| **Minor** (0.x.0) | New features, backward-compatible changes | 7.5.0 โ†’ 7.6.0 | +| **Patch** (0.0.x) | Bug fixes, small improvements | 7.5.0 โ†’ 7.5.1 | + +### Beta Versions + +Beta versions follow the format: `MAJOR.MINOR.PATCH-beta.X` + +Example: `7.6.0-beta.1`, `7.6.0-beta.2` + +## Pre-Release Checklist + +Before starting any release: + +- [ ] All intended features/fixes are merged to `dev` +- [ ] No critical bugs in issue tracker +- [ ] `dev` branch builds successfully +- [ ] All CI checks passing +- [ ] Translation updates synced from Weblate (if applicable) +- [ ] Breaking changes documented + +## Beta Release Process + +### Step 1: Version Bump + +1. Go to **Actions** โ†’ **Version Bump** โ†’ **Run workflow** + +2. Configure: + - **Branch**: `dev` + - **Bump type**: Choose `patch`, `minor`, or `major` + - **Pre-release**: Select `beta` + +3. Click **Run workflow** + +4. Workflow will: + - Calculate new version (e.g., `7.6.0-beta.1`) + - Update all 6 version files + - Create git tag + - Push to `dev` + +### Step 2: Create Beta PR + +1. Go to **Pull Requests** โ†’ **New pull request** + +2. Configure: + - Base: `beta` + - Compare: `dev` + +3. Fill in PR template: + - Add changelog preview + - List major changes + - Add testing notes + +4. Get 2 maintainer approvals + +### Step 3: Merge and Release + +1. **Merge PR** to `beta` branch + +2. **Beta Release Workflow** auto-triggers: + - Builds extension for all browsers + - Creates GitHub pre-release + - Uploads Chrome/Firefox ZIPs + - Generates changelog + +3. **Verify release**: + - Check [Releases page](https://github.com/mue/mue/releases) + - Download and test ZIPs + - Verify version numbers + +### Step 4: Beta Testing + +1. **Share with testers**: + - Post release link in Discord/testing channel + - Include installation instructions + - Provide feedback form/issue template + +2. **Monitor feedback**: + - Track issues tagged with beta version + - Prioritize critical bugs + - Document all feedback + +3. **Fix issues**: + - Fix bugs on `dev` branch + - Create new beta (repeat from Step 1) + - Increment beta number (7.6.0-beta.2, etc.) + +4. **Minimum beta period**: 3-7 days (depending on changes) + +5. **Stability criteria**: + - No P0/P1 bugs reported + - Positive feedback from 5+ testers + - All critical features tested + +## Production Release Process + +### Step 1: Pre-Production Checks + +- [ ] Beta has been stable for minimum period +- [ ] All critical beta bugs resolved +- [ ] Release notes prepared +- [ ] Store credentials verified +- [ ] Team notified of pending release + +### Step 2: Version Bump to Stable + +1. Go to **Actions** โ†’ **Version Bump** โ†’ **Run workflow** + +2. Configure: + - **Branch**: `beta` + - **Bump type**: Usually same as beta (minor/major/patch) + - **Pre-release**: Leave empty (stable release) + +3. This updates `7.6.0-beta.X` โ†’ `7.6.0` + +### Step 3: Create Production PR + +1. Go to **Pull Requests** โ†’ **New pull request** + +2. Configure: + - Base: `main` + - Compare: `beta` + +3. Fill in **release PR checklist**: + - [ ] Beta tested for X days + - [ ] All critical bugs resolved + - [ ] 5+ beta testers approved + - [ ] Release notes prepared + - [ ] Store submission ready + - [ ] Changelog updated on website + +4. Get 2 maintainer approvals + +### Step 4: Merge and Release + +1. **Merge PR** to `main` + +2. **Production Release Workflow** starts: + - Builds extension + - Creates production tag + - Generates full changelog + - Creates GitHub release + - **Pauses for manual approval** + +3. **Review in GitHub**: + - Go to **Actions** โ†’ **Production Release** โ†’ running workflow + - Review release notes + - Check build artifacts + - **Approve deployment** in Environments โ†’ production + +4. **Wait 10 minutes** (cooldown period) + +5. **Release completes**: + - GitHub release published + - ZIPs uploaded + - Tag created + +### Step 5: Store Submission + +**Manual submission required** (for now): + +1. Go to **Actions** โ†’ **Submit** โ†’ **Run workflow** + +2. Enter version tag: `7.6.0` (no 'v' prefix) + +3. Click **Run workflow** + +4. Monitor submission workflow: + - Chrome Web Store submission + - Firefox Add-ons submission + - Edge Add-ons submission + +5. **Verify store listings**: + - Chrome: https://chromewebstore.google.com/detail/mue/bngmbednanpcfochchhgbkookpiaiaid + - Edge: https://microsoftedge.microsoft.com/addons/detail/mue/aepnglgjfokepefimhbnibfjekidhmja + - Firefox: https://addons.mozilla.org/en-GB/firefox/addon/mue/ + +6. **Store review times**: + - Chrome: 1-3 days + - Edge: 1-2 days + - Firefox: hours to days + +### Step 6: Sync Branches + +After production release, sync version to other branches: + +```bash +# Update dev and beta with main +git checkout dev +git pull origin dev +git merge main +git push origin dev + +git checkout beta +git pull origin beta +git merge main +git push origin beta +``` + +## Hotfix Release Process + +### When to Use Hotfix + +**Only for critical production bugs:** +- Security vulnerabilities +- Data loss bugs +- Extension completely broken +- Critical functionality broken for all users + +### Process + +1. **Create hotfix branch** from `main`: + ```bash + git checkout main + git pull origin main + git checkout -b hotfix/brief-description + ``` + +2. **Fix the bug**: + - Make minimal changes (hotfix only) + - Test thoroughly + - Commit with conventional format + +3. **Push branch**: + ```bash + git push origin hotfix/brief-description + ``` + +4. **Run hotfix workflow**: + - Go to **Actions** โ†’ **Hotfix Release** โ†’ **Run workflow** + - **Description**: Brief bug description + - **Branch name**: `hotfix/brief-description` + - Click **Run workflow** + +5. **Approve deployment**: + - Workflow pauses for approval + - Review changes carefully + - Approve in **Environments** โ†’ **production** + +6. **Workflow automatically**: + - Bumps patch version (7.6.0 โ†’ 7.6.1) + - Merges to `main` + - Creates release tag + - Builds and releases + - Back-merges to `beta` and `dev` + +7. **Submit to stores immediately**: + - Go to **Actions** โ†’ **Submit** โ†’ **Run workflow** + - Enter new version (e.g., `7.6.1`) + +8. **Notify users**: + - Post urgent update notice + - Update website changelog + - Notify via social media if critical + +9. **Clean up**: + ```bash + git push origin --delete hotfix/brief-description + ``` + +## Post-Release Tasks + +After any production release: + +### Immediate (within 24 hours) + +- [ ] Verify store submissions completed +- [ ] Update https://muetab.com/blog/changelog +- [ ] Announce on Discord/social media +- [ ] Monitor issue tracker for new reports +- [ ] Verify demo site (demo.muetab.com) is updated + +### Within 1 Week + +- [ ] Review analytics for adoption rate +- [ ] Address any quick-fix bugs as patch release +- [ ] Update roadmap/milestones +- [ ] Thank beta testers and contributors + +### Ongoing + +- [ ] Monitor store reviews/ratings +- [ ] Respond to user feedback +- [ ] Plan next release cycle + +## Store Submission + +### Required Credentials + +Stored in GitHub Secrets as `SUBMIT_KEYS`: + +```json +{ + "chrome": { + "extId": "bngmbednanpcfochchhgbkookpiaiaid", + "clientId": "...", + "clientSecret": "...", + "refreshToken": "..." + }, + "firefox": { + "extId": "{ac143a20-4b61-4c81-abdd-4bff77032972}", + "jwtIssuer": "...", + "jwtSecret": "..." + }, + "edge": { + "productId": "...", + "clientId": "...", + "clientSecret": "...", + "accessTokenUrl": "..." + } +} +``` + +### Beta Distribution + +**Chrome/Edge Beta**: +- Use unlisted listing (share link with testers) +- Or use trusted testers group (max 1000) + +**Firefox Beta**: +- Upload as unlisted to AMO +- Share download link from GitHub Releases + +**Safari Beta**: +- Currently manual sideload from GitHub Releases + +## Troubleshooting + +### Build Fails + +**Issue**: Build fails in workflow + +**Solutions**: +1. Check CI logs for specific error +2. Run `bun run build` locally to reproduce +3. Ensure all dependencies installed +4. Check for linting errors: `bun run lint` + +### Version Mismatch + +**Issue**: Version numbers don't match across files + +**Solutions**: +1. Re-run Version Bump workflow +2. Manually verify all 6 files: + - package.json + - manifest/chrome.json + - manifest/firefox.json + - safari/Mue Extension/Resources/manifest.json + - safari/Mue.xcodeproj/project.pbxproj + - src/config/constants.js + +### Tag Already Exists + +**Issue**: Git tag already exists for version + +**Solutions**: +1. Delete existing tag: + ```bash + git tag -d v7.6.0 + git push origin :refs/tags/v7.6.0 + ``` +2. Re-run workflow + +### Store Submission Fails + +**Issue**: PlasmoHQ BPP submission fails + +**Solutions**: +1. Check workflow logs for specific error +2. Verify credentials in `SUBMIT_KEYS` secret +3. Check store developer console for issues +4. Try manual submission as fallback + +### Merge Conflicts + +**Issue**: Conflicts when merging beta โ†’ main + +**Solutions**: +1. Update beta with main first: + ```bash + git checkout beta + git merge main + git push origin beta + ``` +2. Create new PR from beta โ†’ main + +## Emergency Rollback + +If a production release has critical bugs: + +### Option 1: Hotfix (Preferred) + +Follow [Hotfix Process](#hotfix-release-process) to quickly patch and release. + +### Option 2: Store Rollback + +Each store allows rolling back to previous version: + +**Chrome Web Store**: +1. Go to Developer Dashboard +2. Select Mue extension +3. Package โ†’ Select previous version +4. Publish + +**Firefox Add-ons**: +1. Go to Developer Hub +2. Select Mue add-on +3. Manage Status & Versions +4. Enable previous version + +**Edge Add-ons**: +1. Go to Partner Center +2. Select Mue extension +3. Packages โ†’ Restore previous + +### Option 3: Revert and Re-release + +```bash +git checkout main +git revert +git push origin main +``` + +Then follow production release process. + +## Questions? + +Contact maintainers: +- @davidcralph +- @alexsparkes + +Or open a discussion: https://github.com/mue/mue/discussions