Release #13
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Release & Publish | |
| on: | |
| # Only run on main branch after CI passes | |
| workflow_run: | |
| workflows: ["CI"] | |
| types: [completed] | |
| branches: [main] | |
| # Manual trigger for emergency releases | |
| workflow_dispatch: | |
| inputs: | |
| release_type: | |
| description: 'Release type' | |
| required: true | |
| default: 'patch' | |
| type: choice | |
| options: | |
| - patch | |
| - minor | |
| - major | |
| - prerelease | |
| permissions: | |
| contents: write | |
| packages: write | |
| id-token: write | |
| actions: read | |
| jobs: | |
| check-ci: | |
| name: Check CI Status | |
| runs-on: ubuntu-latest | |
| if: | | |
| github.event_name == 'workflow_dispatch' || | |
| github.event.workflow_run.conclusion == 'success' | |
| outputs: | |
| should_release: ${{ steps.check.outputs.should_release }} | |
| steps: | |
| - name: Check CI passed | |
| id: check | |
| run: | | |
| if [ "${{ github.event_name }}" == "workflow_dispatch" ]; then | |
| echo "Manual release triggered" | |
| echo "should_release=true" >> $GITHUB_OUTPUT | |
| elif [ "${{ github.event.workflow_run.conclusion }}" == "success" ]; then | |
| echo "CI passed, checking for release commits" | |
| echo "should_release=true" >> $GITHUB_OUTPUT | |
| else | |
| echo "CI failed, skipping release" | |
| echo "should_release=false" >> $GITHUB_OUTPUT | |
| exit 1 | |
| fi | |
| release: | |
| name: Release & Publish | |
| needs: check-ci | |
| if: needs.check-ci.outputs.should_release == 'true' | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| token: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: '20.x' | |
| registry-url: 'https://registry.npmjs.org' | |
| - name: Cache node_modules | |
| uses: actions/cache@v4 | |
| id: npm-cache | |
| with: | |
| path: node_modules | |
| key: ${{ runner.os }}-node-20.x-${{ hashFiles('**/package-lock.json') }} | |
| restore-keys: | | |
| ${{ runner.os }}-node-20.x- | |
| - name: Install dependencies | |
| if: steps.npm-cache.outputs.cache-hit != 'true' | |
| run: npm ci | |
| - name: Configure Git | |
| run: | | |
| git config user.name "github-actions[bot]" | |
| git config user.email "github-actions[bot]@users.noreply.github.com" | |
| - name: Determine version bump | |
| id: version | |
| run: | | |
| if [ "${{ github.event_name }}" == "workflow_dispatch" ]; then | |
| echo "bump_type=${{ github.event.inputs.release_type }}" >> $GITHUB_OUTPUT | |
| else | |
| # Check commit messages for conventional commits | |
| COMMITS=$(git log $(git describe --tags --abbrev=0 2>/dev/null || echo '')..HEAD --pretty=format:"%s" 2>/dev/null || git log --pretty=format:"%s") | |
| # Check if this is the first release (no tags exist) | |
| if ! git describe --tags --abbrev=0 2>/dev/null; then | |
| echo "First release detected" | |
| echo "bump_type=patch" >> $GITHUB_OUTPUT | |
| elif echo "$COMMITS" | grep -qE "^(feat|fix)!:|BREAKING CHANGE:"; then | |
| echo "bump_type=major" >> $GITHUB_OUTPUT | |
| elif echo "$COMMITS" | grep -qE "^feat(\(.+\))?:"; then | |
| echo "bump_type=minor" >> $GITHUB_OUTPUT | |
| elif echo "$COMMITS" | grep -qE "^fix(\(.+\))?:"; then | |
| echo "bump_type=patch" >> $GITHUB_OUTPUT | |
| else | |
| # For workflow_run events, default to patch if no conventional commits | |
| if [ "${{ github.event_name }}" == "workflow_run" ]; then | |
| echo "No conventional commits found, defaulting to patch" | |
| echo "bump_type=patch" >> $GITHUB_OUTPUT | |
| else | |
| echo "No version bump needed" | |
| echo "skip=true" >> $GITHUB_OUTPUT | |
| exit 0 | |
| fi | |
| fi | |
| fi | |
| - name: Check if should publish | |
| id: check | |
| if: steps.version.outputs.skip != 'true' | |
| run: | | |
| # Check if package exists on NPM | |
| if npm view @nexcraft/forge version 2>/dev/null; then | |
| echo "Package exists on NPM" | |
| CURRENT_VERSION=$(npm view @nexcraft/forge version) | |
| echo "current_npm_version=$CURRENT_VERSION" >> $GITHUB_OUTPUT | |
| else | |
| echo "Package does not exist on NPM yet" | |
| echo "first_publish=true" >> $GITHUB_OUTPUT | |
| fi | |
| - name: Build library | |
| if: steps.version.outputs.skip != 'true' | |
| run: npm run build | |
| - name: Bump version | |
| id: bump | |
| if: steps.version.outputs.skip != 'true' | |
| run: | | |
| CURRENT_VERSION=$(node -p "require('./package.json').version") | |
| # For first publish, use current version if it's already set | |
| if [ "${{ steps.check.outputs.first_publish }}" == "true" ]; then | |
| if [ "$CURRENT_VERSION" == "0.0.0" ]; then | |
| npm version 0.0.1 --no-git-tag-version --allow-same-version | |
| else | |
| echo "Using existing version $CURRENT_VERSION for first publish" | |
| fi | |
| else | |
| npm version ${{ steps.version.outputs.bump_type }} --no-git-tag-version | |
| fi | |
| VERSION=$(node -p "require('./package.json').version") | |
| echo "new_version=$VERSION" >> $GITHUB_OUTPUT | |
| - name: Generate changelog entry | |
| if: steps.version.outputs.skip != 'true' | |
| run: | | |
| VERSION="${{ steps.bump.outputs.new_version }}" | |
| DATE=$(date +%Y-%m-%d) | |
| # Create changelog entry | |
| cat > CHANGELOG_ENTRY.md << EOF | |
| ## v$VERSION - $DATE | |
| ### Changes | |
| EOF | |
| # Add commit messages | |
| git log $(git describe --tags --abbrev=0 2>/dev/null || echo '')..HEAD --pretty=format:"- %s" >> CHANGELOG_ENTRY.md || echo "- Initial release" >> CHANGELOG_ENTRY.md | |
| # Prepend to CHANGELOG.md (after the header) | |
| if [ -f CHANGELOG.md ]; then | |
| head -n 2 CHANGELOG.md > CHANGELOG_NEW.md | |
| cat CHANGELOG_ENTRY.md >> CHANGELOG_NEW.md | |
| echo "" >> CHANGELOG_NEW.md | |
| tail -n +3 CHANGELOG.md >> CHANGELOG_NEW.md | |
| mv CHANGELOG_NEW.md CHANGELOG.md | |
| else | |
| echo "# Changelog" > CHANGELOG.md | |
| echo "" >> CHANGELOG.md | |
| cat CHANGELOG_ENTRY.md >> CHANGELOG.md | |
| fi | |
| rm CHANGELOG_ENTRY.md | |
| - name: Commit version bump | |
| if: steps.version.outputs.skip != 'true' | |
| run: | | |
| git add package.json package-lock.json CHANGELOG.md | |
| git commit -m "chore(release): v${{ steps.bump.outputs.new_version }} [skip ci]" || echo "No changes to commit" | |
| - name: Create git tag | |
| if: steps.version.outputs.skip != 'true' | |
| run: | | |
| if ! git rev-parse v${{ steps.bump.outputs.new_version }} >/dev/null 2>&1; then | |
| git tag -a v${{ steps.bump.outputs.new_version }} -m "Release v${{ steps.bump.outputs.new_version }}" | |
| else | |
| echo "Tag v${{ steps.bump.outputs.new_version }} already exists, skipping tag creation" | |
| fi | |
| - name: Push changes | |
| if: steps.version.outputs.skip != 'true' | |
| run: | | |
| git push origin main --follow-tags | |
| - name: Publish to NPM | |
| if: steps.version.outputs.skip != 'true' | |
| run: | | |
| # Dry run first to check | |
| npm publish --dry-run | |
| # Actual publish | |
| npm publish --access public | |
| env: | |
| NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} | |
| - name: Create GitHub Release | |
| if: steps.version.outputs.skip != 'true' | |
| uses: softprops/action-gh-release@v2 | |
| with: | |
| tag_name: v${{ steps.bump.outputs.new_version }} | |
| name: Release v${{ steps.bump.outputs.new_version }} | |
| body_path: CHANGELOG.md | |
| draft: false | |
| prerelease: ${{ steps.version.outputs.bump_type == 'prerelease' }} | |
| files: | | |
| dist/nexcraft-forge.es.js | |
| dist/nexcraft-forge.umd.js | |
| dist/index.d.ts | |
| publish-docs: | |
| name: Publish Documentation | |
| needs: release | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| with: | |
| ref: main # Get the latest including version bump | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: '20.x' | |
| - name: Cache node_modules | |
| uses: actions/cache@v4 | |
| id: npm-cache | |
| with: | |
| path: node_modules | |
| key: ${{ runner.os }}-node-20.x-${{ hashFiles('**/package-lock.json') }} | |
| restore-keys: | | |
| ${{ runner.os }}-node-20.x- | |
| - name: Install dependencies | |
| if: steps.npm-cache.outputs.cache-hit != 'true' | |
| run: npm ci | |
| - name: Build Storybook | |
| run: npm run build-storybook | |
| - name: Deploy to GitHub Pages | |
| uses: peaceiris/actions-gh-pages@v4 | |
| with: | |
| github_token: ${{ secrets.GITHUB_TOKEN }} | |
| publish_dir: ./storybook-static | |
| cname: forge.ignis.dev # Optional: custom domain |