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
This commit is contained in:
Alex Sparkes
2026-01-25 17:27:54 +00:00
committed by GitHub
parent 6d209e10fb
commit 896816c185
10 changed files with 1546 additions and 1 deletions

6
.github/CODEOWNERS vendored
View File

@@ -1,2 +1,8 @@
# Automatically assigned to any PRs # Automatically assigned to any PRs
* @davidcralph @alexsparkes * @davidcralph @alexsparkes
# Workflow files require maintainer approval
/.github/workflows/ @davidcralph @alexsparkes
# Release process documentation
/docs/RELEASE_PROCESS.md @davidcralph @alexsparkes

65
.github/PULL_REQUEST_TEMPLATE.md vendored Normal file
View File

@@ -0,0 +1,65 @@
## Description
<!-- Provide a brief description of your changes -->
## Type of Change
<!-- Mark the relevant option with an 'x' -->
- [ ] 🐛 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
<!-- Describe the tests you ran and how to reproduce them -->
- [ ] 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)
<!-- Only fill out if this is a release PR -->
- [ ] 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)
<!-- Add screenshots to help explain your changes -->
## Related Issues
<!-- Link any related issues here -->
Closes #
Relates to #
## Additional Notes
<!-- Any additional information for reviewers -->

165
.github/workflows/beta-release.yml vendored Normal file
View File

@@ -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<<EOF"
if [ -n "$FEATURES" ]; then
echo "### ✨ Features"
echo "$FEATURES"
echo ""
fi
if [ -n "$FIXES" ]; then
echo "### 🐛 Bug Fixes"
echo "$FIXES"
echo ""
fi
if [ -n "$CHORES" ]; then
echo "### 🔧 Maintenance"
echo "$CHORES"
echo ""
fi
if [ -n "$OTHER" ]; then
echo "### 📝 Other Changes"
echo "$OTHER"
fi
echo "EOF"
} >> $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 <<EOF
## 🧪 Mue Beta v${{ steps.version.outputs.version }}
**⚠️ This is a beta release for testing purposes only.**
### Testing Instructions
1. Download the appropriate ZIP file below
2. For Chrome: Load as unpacked extension or install from [unlisted link](https://chromewebstore.google.com/detail/mue/bngmbednanpcfochchhgbkookpiaiaid) (dev team only)
3. For Firefox: Install via about:debugging → Load Temporary Add-on
4. Report issues at https://github.com/mue/mue/issues
${{ steps.changelog.outputs.changelog }}
### Installation Files
- **Chrome/Edge**: \`chrome-${{ steps.version.outputs.version }}.zip\`
- **Firefox**: \`firefox-${{ steps.version.outputs.version }}.zip\`
---
**🔗 Demo**: [demo.muetab.com](https://demo.muetab.com)
**📱 Beta Branch Demo**: [mue-git-beta-mue.vercel.app](https://mue-git-beta-mue.vercel.app)
EOF
)
if [ "${{ steps.check_release.outputs.exists }}" = "true" ]; then
echo "Updating existing release..."
gh release edit "v${{ steps.version.outputs.version }}" \
--notes "$RELEASE_NOTES" \
--prerelease
# Upload new files (will replace if they exist)
gh release upload "v${{ steps.version.outputs.version }}" \
"build/chrome-${{ steps.version.outputs.version }}.zip" \
"build/firefox-${{ steps.version.outputs.version }}.zip" \
--clobber
else
echo "Creating new release..."
gh release create "v${{ steps.version.outputs.version }}" \
"build/chrome-${{ steps.version.outputs.version }}.zip" \
"build/firefox-${{ steps.version.outputs.version }}.zip" \
--title "Beta v${{ steps.version.outputs.version }}" \
--notes "$RELEASE_NOTES" \
--prerelease
fi
env:
GH_TOKEN: ${{ github.token }}
- name: Output release info
run: |
echo "## 🎉 Beta Release Created!" >> $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

194
.github/workflows/hotfix-release.yml vendored Normal file
View File

@@ -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<<EOF"
echo "### 🚨 Hotfix"
echo "${{ github.event.inputs.description }}"
echo ""
echo "### Changes"
echo "$COMMITS"
echo "EOF"
} >> $GITHUB_OUTPUT
- name: Create GitHub Release
run: |
git checkout main
RELEASE_NOTES=$(cat <<EOF
## 🚨 Mue Hotfix v${{ steps.version.outputs.new_version }}
**This is an emergency hotfix release.**
${{ steps.changelog.outputs.changelog }}
### 📦 Installation
**Browser Extensions (will be updated shortly):**
- **Chrome**: [Chrome Web Store](https://chromewebstore.google.com/detail/mue/bngmbednanpcfochchhgbkookpiaiaid)
- **Edge**: [Edge Add-ons](https://microsoftedge.microsoft.com/addons/detail/mue/aepnglgjfokepefimhbnibfjekidhmja)
- **Firefox**: [Firefox Add-ons](https://addons.mozilla.org/en-GB/firefox/addon/mue/)
**Immediate Manual Installation:**
- Download the ZIP file below for immediate deployment
- Chrome/Edge: Load unpacked extension
- Firefox: Install from about:debugging
---
**⚠️ This hotfix should be submitted to stores immediately.**
EOF
)
gh release create "v${{ steps.version.outputs.new_version }}" \
"build/chrome-${{ steps.version.outputs.new_version }}.zip" \
"build/firefox-${{ steps.version.outputs.new_version }}.zip" \
--title "🚨 Hotfix v${{ steps.version.outputs.new_version }}" \
--notes "$RELEASE_NOTES" \
--latest
env:
GH_TOKEN: ${{ github.token }}
- name: Back-merge to beta
run: |
git fetch origin beta
git checkout beta
git merge --no-ff main -m "chore: back-merge hotfix v${{ steps.version.outputs.new_version }} from main"
git push origin beta
- name: Back-merge to dev
run: |
git fetch origin dev
git checkout dev
git merge --no-ff main -m "chore: back-merge hotfix v${{ steps.version.outputs.new_version }} from main"
git push origin dev
- name: Output success summary
run: |
echo "## 🚨 Hotfix Released!" >> $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

187
.github/workflows/production-release.yml vendored Normal file
View File

@@ -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<<EOF"
if [ -n "$BREAKING" ]; then
echo "### ⚠️ Breaking Changes"
echo "$BREAKING"
echo ""
fi
if [ -n "$FEATURES" ]; then
echo "### ✨ New Features"
echo "$FEATURES"
echo ""
fi
if [ -n "$FIXES" ]; then
echo "### 🐛 Bug Fixes"
echo "$FIXES"
echo ""
fi
if [ -n "$PERFORMANCE" ]; then
echo "### ⚡ Performance Improvements"
echo "$PERFORMANCE"
fi
echo "EOF"
} >> $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 <<EOF
## 🎉 Mue v${{ steps.version.outputs.version }}
${{ steps.changelog.outputs.changelog }}
### 📦 Installation
**Browser Extensions:**
- **Chrome**: [Chrome Web Store](https://chromewebstore.google.com/detail/mue/bngmbednanpcfochchhgbkookpiaiaid)
- **Edge**: [Edge Add-ons](https://microsoftedge.microsoft.com/addons/detail/mue/aepnglgjfokepefimhbnibfjekidhmja)
- **Firefox**: [Firefox Add-ons](https://addons.mozilla.org/en-GB/firefox/addon/mue/)
**Manual Installation:**
- Download the appropriate ZIP file below
- Chrome/Edge: Load unpacked extension from extracted folder
- Firefox: Install from about:debugging → Load Temporary Add-on
### 🔗 Links
- **Demo**: [demo.muetab.com](https://demo.muetab.com)
- **Changelog**: [muetab.com/blog/changelog](https://muetab.com/blog/changelog)
- **Documentation**: [github.com/mue/mue](https://github.com/mue/mue)
---
### 📝 Build Information
- **Version**: ${{ steps.version.outputs.version }}
- **Build Date**: $(date -u +"%Y-%m-%d %H:%M:%S UTC")
- **Commit**: ${{ github.sha }}
EOF
)
gh release create "v${{ steps.version.outputs.version }}" \
"build/chrome-${{ steps.version.outputs.version }}.zip" \
"build/firefox-${{ steps.version.outputs.version }}.zip" \
--title "Mue v${{ steps.version.outputs.version }}" \
--notes "$RELEASE_NOTES" \
--latest
env:
GH_TOKEN: ${{ github.token }}
- name: Output success summary
run: |
echo "## 🚀 Production Release Published!" >> $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

140
.github/workflows/version-bump.yml vendored Normal file
View File

@@ -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

1
.gitignore vendored
View File

@@ -5,7 +5,6 @@ node_modules/
build/ build/
.idea/ .idea/
dist/ dist/
/docs
# Safari Extension Build Files # Safari Extension Build Files
safari/Mue Extension/Resources/*.html safari/Mue Extension/Resources/*.html

310
CONTRIBUTING.md Normal file
View File

@@ -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
```
<type>(<scope>): <description>
[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.

View File

@@ -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` - migrate old translation format to new
- `bun run translations:percentages` - update translation completion percentages from Weblate - `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 ## 🐳 Docker development
Hot reload is available while coding. Hot reload is available while coding.

469
docs/RELEASE_PROCESS.md Normal file
View File

@@ -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 <commit-hash>
git push origin main
```
Then follow production release process.
## Questions?
Contact maintainers:
- @davidcralph
- @alexsparkes
Or open a discussion: https://github.com/mue/mue/discussions