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
173 changes: 38 additions & 135 deletions .github/workflows/auto-release.yml
Original file line number Diff line number Diff line change
@@ -1,14 +1,7 @@
name: Auto Release to Marketplace
name: Release To Marketplace

on:
push:
branches: [main]
workflow_dispatch:
inputs:
force_version:
description: "Force a specific version (e.g., 1.3.0) or leave blank for auto-detect"
required: false
type: string

jobs:
release:
Expand All @@ -17,7 +10,6 @@ jobs:
timeout-minutes: 30
permissions:
contents: write
packages: write

steps:
- name: Checkout repository
Expand All @@ -26,80 +18,33 @@ jobs:
fetch-depth: 0
token: ${{ secrets.GITHUB_TOKEN }}

- name: Require main branch
run: |
if [ "${GITHUB_REF}" != "refs/heads/main" ]; then
echo "Run this workflow from main only. Current ref: ${GITHUB_REF}"
exit 1
fi

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: "20"
cache: "npm"

- name: Get last tag
id: last_tag
- name: Read release version
id: release_version
run: |
LAST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "")
echo "tag=${LAST_TAG}" >> $GITHUB_OUTPUT
echo "Last tag: ${LAST_TAG:-none}"
VERSION=$(node -p "require('./package.json').version")
echo "version=${VERSION}" >> $GITHUB_OUTPUT
echo "Releasing version ${VERSION} from package.json"

- name: Calculate version bump
id: version
- name: Ensure release tag does not exist
env:
FORCE_VERSION: ${{ github.event.inputs.force_version }}
LAST_TAG: ${{ steps.last_tag.outputs.tag }}
run: |
if [ -n "$FORCE_VERSION" ]; then
echo "version=$FORCE_VERSION" >> $GITHUB_OUTPUT
echo "Using forced version: $FORCE_VERSION"
else
# Parse commits to determine version bump
CURRENT_VERSION=$(node -p "require('./package.json').version")
MAJOR=$(echo $CURRENT_VERSION | cut -d. -f1)
MINOR=$(echo $CURRENT_VERSION | cut -d. -f2)
PATCH=$(echo $CURRENT_VERSION | cut -d. -f3)

# Check commit messages for version bump indicators
if [ -z "$LAST_TAG" ]; then
# No tags yet, check all commits or just HEAD
COMMITS=$(git log HEAD~1..HEAD --pretty=format:%B 2>/dev/null || git log HEAD --pretty=format:%B)
HAS_COMMITS=true
else
# Check commits since last tag
COMMITS=$(git log $LAST_TAG..HEAD --pretty=format:%B)
# Check if there are commits since last tag
COMMIT_COUNT=$(git rev-list --count $LAST_TAG..HEAD)
if [ "$COMMIT_COUNT" -gt 0 ]; then
HAS_COMMITS=true
else
HAS_COMMITS=false
fi
fi

if echo "$COMMITS" | grep -q "BREAKING CHANGE\|^feat!:"; then
NEW_VERSION="$((MAJOR+1)).0.0"
elif echo "$COMMITS" | grep -qE "^feat"; then
NEW_VERSION="$MAJOR.$((MINOR+1)).0"
elif echo "$COMMITS" | grep -qE "^fix"; then
NEW_VERSION="$MAJOR.$MINOR.$((PATCH+1))"
elif [ "$HAS_COMMITS" = "true" ]; then
# Always bump patch version if there are commits (even if not semantic)
NEW_VERSION="$MAJOR.$MINOR.$((PATCH+1))"
else
NEW_VERSION=$CURRENT_VERSION
fi

echo "version=$NEW_VERSION" >> $GITHUB_OUTPUT
echo "Auto-detected version: $NEW_VERSION"
fi

- name: Check if version changed
id: version_check
RELEASE_TAG: v${{ steps.release_version.outputs.version }}
run: |
CURRENT=$(node -p "require('./package.json').version")
NEW_VERSION=${{ steps.version.outputs.version }}
if [ "$CURRENT" = "$NEW_VERSION" ]; then
echo "changed=false" >> $GITHUB_OUTPUT
echo "Version unchanged: $CURRENT"
else
echo "changed=true" >> $GITHUB_OUTPUT
echo "Version will change from $CURRENT to $NEW_VERSION"
if git rev-parse "$RELEASE_TAG" >/dev/null 2>&1; then
echo "Tag $RELEASE_TAG already exists. Bump package.json and changelog in git before publishing."
exit 1
fi

- name: Install dependencies
Expand All @@ -121,70 +66,32 @@ jobs:
- name: Check compliance
run: node scripts/check-extension-compliance.js

- name: Update package.json
if: steps.version_check.outputs.changed == 'true'
run: |
npm version ${{ steps.version.outputs.version }} --no-git-tag-version

- name: Update CHANGELOG.md
if: steps.version_check.outputs.changed == 'true'
run: |
DATE=$(date +"%Y-%m-%d")
NEW_VERSION=${{ steps.version.outputs.version }}

# Get commit summary since last tag
if [ -n "${{ steps.last_tag.outputs.tag }}" ]; then
SUMMARY=$(git log ${{ steps.last_tag.outputs.tag }}..HEAD --oneline | sed 's/^/- /')
else
SUMMARY=$(git log HEAD --oneline | head -20 | sed 's/^/- /')
fi

CHANGELOG_ENTRY="## [$NEW_VERSION] - $DATE

### Changes
$SUMMARY

"

# Prepend to CHANGELOG.md
(echo "$CHANGELOG_ENTRY" && cat CHANGELOG.md) > CHANGELOG.md.tmp && mv CHANGELOG.md.tmp CHANGELOG.md

- name: Commit version changes
if: steps.version_check.outputs.changed == 'true'
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git add package.json CHANGELOG.md
git commit -m "chore: release v${{ steps.version.outputs.version }}"

- name: Create and push tag
if: steps.version_check.outputs.changed == 'true'
env:
HUSKY: 0
run: |
git tag -a v${{ steps.version.outputs.version }} -m "Release v${{ steps.version.outputs.version }}"
git push origin main
git push origin v${{ steps.version.outputs.version }}

- name: Package extension
- name: Build production bundle
run: npm run package

- name: Create .vsix file
run: npx -y @vscode/vsce package

- name: Publish to VS Code Marketplace
if: steps.version_check.outputs.changed == 'true'
env:
VSCE_PAT: ${{ secrets.VSCODE_MARKETPLACE_TOKEN }}
run: npm run deploy
run: npm run publish:marketplace

- name: Create .vsix file for GitHub Release
if: steps.version_check.outputs.changed == 'true'
run: npx -y @vscode/vsce package
- name: Create and push release tag
env:
HUSKY: 0
RELEASE_TAG: v${{ steps.release_version.outputs.version }}
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git tag -a "$RELEASE_TAG" -m "Release $RELEASE_TAG"
git push origin "$RELEASE_TAG"

- name: Create GitHub Release
uses: softprops/action-gh-release@v1
if: steps.version_check.outputs.changed == 'true'
with:
tag_name: v${{ steps.version.outputs.version }}
name: Release v${{ steps.version.outputs.version }}
tag_name: v${{ steps.release_version.outputs.version }}
name: Release v${{ steps.release_version.outputs.version }}
draft: false
prerelease: false
files: annotative-*.vsix
Expand All @@ -195,18 +102,14 @@ jobs:
uses: actions/upload-artifact@v4
if: always()
with:
name: extension-package-${{ steps.version.outputs.version }}
name: extension-package-${{ steps.release_version.outputs.version }}
path: annotative-*.vsix
retention-days: 30

- name: Report Status
if: always()
run: |
echo "### Release Status" >> $GITHUB_STEP_SUMMARY
if [ "${{ steps.version_check.outputs.changed }}" = "true" ]; then
echo "✅ Released v${{ steps.version.outputs.version }}" >> $GITHUB_STEP_SUMMARY
echo "- Package: annotative-${{ steps.version.outputs.version }}.vsix" >> $GITHUB_STEP_SUMMARY
echo "- Marketplace: https://marketplace.visualstudio.com/items?itemName=bryan-shea.annotative" >> $GITHUB_STEP_SUMMARY
else
echo "ℹ️ No version change detected - skipped release" >> $GITHUB_STEP_SUMMARY
fi
echo "Released v${{ steps.release_version.outputs.version }} from an already-versioned main commit." >> $GITHUB_STEP_SUMMARY
echo "- Package: annotative-${{ steps.release_version.outputs.version }}.vsix" >> $GITHUB_STEP_SUMMARY
echo "- Marketplace: https://marketplace.visualstudio.com/items?itemName=bryan-shea.annotative" >> $GITHUB_STEP_SUMMARY
7 changes: 6 additions & 1 deletion .husky/commit-msg
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"
. "$(dirname "$0")/_/annotative-hook-config.sh"

if ! annotative_should_enforce_hooks; then
echo "Skipping commit message validation on branch $(annotative_current_branch)"
exit 0
fi

node scripts/validate-commit-msg.js $1
16 changes: 9 additions & 7 deletions .husky/pre-commit
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"
. "$(dirname "$0")/_/annotative-hook-config.sh"

# Pre-commit hook: lint and format validation
echo "Running pre-commit checks..."
if ! annotative_should_enforce_hooks; then
echo "Skipping pre-commit checks on branch $(annotative_current_branch)"
exit 0
fi

# Run ESLint
echo "Running pre-commit checks on protected branch..."
echo "Linting code..."
npm run lint --if-present
if [ $? -ne 0 ]; then

if ! npm run lint --if-present; then
echo "Linting failed. Fix errors and try again."
exit 1
fi

echo "Pre-commit checks passed\n"
echo "Pre-commit checks passed"
21 changes: 13 additions & 8 deletions .husky/pre-push
Original file line number Diff line number Diff line change
@@ -1,27 +1,32 @@
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"
. "$(dirname "$0")/_/annotative-hook-config.sh"

if ! annotative_should_enforce_hooks; then
echo "Skipping pre-push checks on branch $(annotative_current_branch)"
exit 0
fi

# Pre-push hook: validation before pushing to remote
echo "🔍 Running pre-push checks..."
echo "Running pre-push checks on protected branch..."

# Compile TypeScript
echo "🔨 Compiling TypeScript..."
echo "Compiling TypeScript..."
npm run compile
if [ $? -ne 0 ]; then
echo "Compilation failed. Fix errors and try again."
echo "Compilation failed. Fix errors and try again."
exit 1
fi

# Run tests (skip on Windows - tests run in CI)
if [ "$OSTYPE" != "msys" ] && [ "$OSTYPE" != "win32" ]; then
echo "🧪 Running tests..."
echo "Running tests..."
npm test
if [ $? -ne 0 ]; then
echo "Tests failed. Fix tests and try again."
echo "Tests failed. Fix tests and try again."
exit 1
fi
else
echo "⏭️ Skipping tests on Windows (run locally with: npm test)"
echo "Skipping tests on Windows (run locally with: npm test)"
fi

echo "Pre-push checks passed"
echo "Pre-push checks passed"
2 changes: 2 additions & 0 deletions .vscodeignore
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ vsc-extension-quickstart.md
**/.vscode-test.*
logs/**
*.log
*.vsix
.changeset-temp.md

# CI/CD
.github/**
Expand Down
39 changes: 31 additions & 8 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,16 +1,39 @@
## [3.0.0] - 2026-02-01

### Changes
- 90e81af Merge pull request #9 from bryan-shea/feat/updates-optimizations
- 3655a85 feat: introduce user-defined tags and project-based storage system
- 659a063 docs: complete documentation overhaul with professional standards
- 15a5845 refactor!: simplify UX with user-defined tags and project storage

<!-- markdownlint-disable MD024 MD036 -->

# Changelog

All notable changes to Annotative are documented in this file.

## [3.0.0] - 2026-03-24

### Upgrade Notes

- `v3.0.0` continues the project-based `.annotative/` storage model introduced in `v2`
- Existing `v2.x` workspaces do not require a manual storage migration
- Legacy pre-`v2` global-state annotations are still not imported automatically

### Added

- Annotation anchoring and reattachment support to keep saved annotations aligned after nearby source edits
- Dedicated export service and workspace selection helpers for multi-root behavior
- Regression coverage for storage, CRUD, export, manager, anchoring, and sidebar behavior
- A repository test runner that works reliably on Windows paths containing spaces

### Changed

- Storage handling now uses schema-versioned payloads and normalization on load
- Export flows are routed through clearer service boundaries for Markdown, AI export, and Copilot-oriented output
- Sidebar webview state handling is more consistent for filtering, grouping, and refresh
- Release automation now publishes an already-versioned `main` commit through a manual GitHub Actions workflow
- Documentation has been rewritten to match the current product, upgrade path, and release flow

### Fixed

- Non-atomic storage writes and weak recovery behavior for corrupt storage files
- Annotation persistence edge cases caused by path and workspace resolution issues
- Packaging and release hygiene around temporary files and manual release preparation
- Windows test execution issues in repository paths that include spaces

## [2.0.0] - 2026-02-01

### Breaking Changes
Expand Down
Loading
Loading