diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml new file mode 100644 index 00000000..f56b671a --- /dev/null +++ b/.github/workflows/release.yaml @@ -0,0 +1,195 @@ +name: Release Package + +on: + workflow_dispatch: + inputs: + dry_run: + description: 'Dry run (skip actual publish)' + required: true + type: boolean + default: true + npm_tag: + description: 'NPM tag (e.g., latest, beta, next)' + required: true + type: string + default: 'latest' + version: + description: 'Version override (optional, e.g., 1.0.0)' + required: false + type: string + +jobs: + release: + runs-on: ubuntu-latest + timeout-minutes: 15 + permissions: + contents: write + id-token: write + + steps: + - name: Checkout + uses: actions/checkout@v5 + with: + fetch-depth: 0 + token: ${{ secrets.GITHUB_TOKEN }} + + - name: Setup Bun + uses: oven-sh/setup-bun@v2 + with: + bun-version-file: .bun-version + + - name: Configure git + run: | + git config user.name "github-actions[bot]" + git config user.email "github-actions[bot]@users.noreply.github.com" + + - name: Install dependencies + run: bun install + + - name: Build library + run: bun run build + + - name: Check types + run: bun run check:typescript + + - name: Check linting and formatting + run: bun run lint + + - name: Check circular dependencies + run: bun run circular:check + + - name: Run tests + run: bun run test + + - name: Update version (if specified) + if: ${{ inputs.version != '' }} + working-directory: packages/uniwind + run: | + echo "Updating version to ${{ inputs.version }}" + bun version --no-git-tag-version ${{ inputs.version }} + + - name: Get package version + id: package_version + working-directory: packages/uniwind + run: | + VERSION=$(cat package.json | grep '"version"' | head -1 | awk -F: '{ print $2 }' | sed 's/[",]//g' | xargs) + echo "version=$VERSION" >> $GITHUB_OUTPUT + echo "Package version: $VERSION" + + - name: Check if version already published + id: check_published + working-directory: packages/uniwind + run: | + PACKAGE_NAME=$(cat package.json | grep '"name"' | head -1 | awk -F: '{ print $2 }' | sed 's/[",]//g' | xargs) + VERSION="${{ steps.package_version.outputs.version }}" + + if npm view "$PACKAGE_NAME@$VERSION" version 2>/dev/null; then + echo "published=true" >> $GITHUB_OUTPUT + echo "âš ī¸ Version $VERSION is already published to NPM" + else + echo "published=false" >> $GITHUB_OUTPUT + echo "✅ Version $VERSION is not yet published" + fi + + - name: Generate release notes + id: release_notes + run: | + VERSION="${{ steps.package_version.outputs.version }}" + PREV_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "") + + if [ -z "$PREV_TAG" ]; then + echo "No previous tag found, using all commits" + COMMITS=$(git log --pretty=format:"- %s (%h)" --no-merges) + else + echo "Generating changelog from $PREV_TAG to HEAD" + COMMITS=$(git log $PREV_TAG..HEAD --pretty=format:"- %s (%h)" --no-merges) + fi + + NOTES="## What's Changed + +$COMMITS + +**Full Changelog**: https://github.com/${{ github.repository }}/compare/${PREV_TAG}...v${VERSION}" + + # Save to file for multiline handling + echo "$NOTES" > release_notes.txt + echo "notes_file=release_notes.txt" >> $GITHUB_OUTPUT + + - name: Commit version bump (if version was updated) + if: ${{ inputs.version != '' && !inputs.dry_run }} + run: | + git add packages/uniwind/package.json + git commit -m "chore: bump version to ${{ steps.package_version.outputs.version }}" || echo "No changes to commit" + git push origin main + + - name: Create Git tag + if: ${{ !inputs.dry_run }} + run: | + VERSION="${{ steps.package_version.outputs.version }}" + git tag -a "v$VERSION" -m "Release v$VERSION" + git push origin "v$VERSION" + + - name: Publish to NPM (Dry Run) + if: ${{ inputs.dry_run }} + working-directory: packages/uniwind + run: | + echo "🔍 DRY RUN MODE - Would publish with:" + echo " Version: ${{ steps.package_version.outputs.version }}" + echo " Tag: ${{ inputs.npm_tag }}" + echo " Already published: ${{ steps.check_published.outputs.published }}" + npm pack --dry-run + + - name: Setup NPM authentication + if: ${{ !inputs.dry_run && steps.check_published.outputs.published == 'false' }} + run: | + echo "//registry.npmjs.org/:_authToken=${{ secrets.NPM_TOKEN }}" > ~/.npmrc + + - name: Publish to NPM + if: ${{ !inputs.dry_run && steps.check_published.outputs.published == 'false' }} + working-directory: packages/uniwind + run: | + npm publish --tag ${{ inputs.npm_tag }} --provenance --access public + + - name: Create GitHub Release (Dry Run) + if: ${{ inputs.dry_run }} + run: | + echo "🔍 DRY RUN MODE - Would create GitHub release:" + echo " Tag: v${{ steps.package_version.outputs.version }}" + echo " Title: Release v${{ steps.package_version.outputs.version }}" + echo "" + echo "Release notes:" + cat ${{ steps.release_notes.outputs.notes_file }} + + - name: Create GitHub Release + if: ${{ !inputs.dry_run }} + env: + GH_TOKEN: ${{ github.token }} + run: | + VERSION="${{ steps.package_version.outputs.version }}" + gh release create "v$VERSION" \ + --title "Release v$VERSION" \ + --notes-file ${{ steps.release_notes.outputs.notes_file }} \ + --verify-tag + + - name: Summary + run: | + echo "## Release Summary" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "- **Version:** ${{ steps.package_version.outputs.version }}" >> $GITHUB_STEP_SUMMARY + echo "- **NPM Tag:** ${{ inputs.npm_tag }}" >> $GITHUB_STEP_SUMMARY + echo "- **Dry Run:** ${{ inputs.dry_run }}" >> $GITHUB_STEP_SUMMARY + echo "- **Already Published:** ${{ steps.check_published.outputs.published }}" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + + if [ "${{ inputs.dry_run }}" == "true" ]; then + echo "### â„šī¸ This was a dry run - no changes were published" >> $GITHUB_STEP_SUMMARY + else + if [ "${{ steps.check_published.outputs.published }}" == "true" ]; then + echo "### âš ī¸ Version already published - skipped NPM publish" >> $GITHUB_STEP_SUMMARY + else + echo "### ✅ Package published successfully!" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "- NPM: https://www.npmjs.com/package/uniwind/v/${{ steps.package_version.outputs.version }}" >> $GITHUB_STEP_SUMMARY + echo "- GitHub: https://github.com/${{ github.repository }}/releases/tag/v${{ steps.package_version.outputs.version }}" >> $GITHUB_STEP_SUMMARY + fi + fi