diff --git a/.github/workflows/manual-release.yml b/.github/workflows/manual-release.yml new file mode 100644 index 000000000..176c2d037 --- /dev/null +++ b/.github/workflows/manual-release.yml @@ -0,0 +1,317 @@ +name: Manual Release + +on: + workflow_dispatch: + inputs: + release_type: + description: "Type of release" + required: true + default: "patch" + type: choice + options: + - patch + - minor + - major + description: + description: "Release description (optional)" + required: false + type: string + dry_run: + description: "Dry run (test without making changes)" + required: false + default: false + type: boolean + +concurrency: + group: ${{ github.workflow }}-main + cancel-in-progress: false + +jobs: + complete-release: + name: Complete Manual Release + runs-on: ubuntu-latest + permissions: + contents: write + actions: write + id-token: write + + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + fetch-depth: 0 + fetch-tags: true + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: 22.x + + - name: Install dependencies + run: npm ci + + - name: Configure Git + run: | + git config --local user.email "action@github.com" + git config --local user.name "GitHub Action" + + - name: Get current version + id: current_version + run: | + CURRENT_VERSION=$(node -p "require('./package.json').version") + echo "current=${CURRENT_VERSION}" >> $GITHUB_OUTPUT + echo "Current version: ${CURRENT_VERSION}" + + - name: Set version bump type + id: version_bump + run: | + BUMP_TYPE="${{ github.event.inputs.release_type }}" + echo "bump_type=${BUMP_TYPE}" >> $GITHUB_OUTPUT + echo "Selected release type: ${BUMP_TYPE}" + + - name: Bump version + id: bump_version + run: | + CURRENT_VERSION="${{ steps.current_version.outputs.current }}" + BUMP_TYPE="${{ steps.version_bump.outputs.bump_type }}" + + IFS='.' read -ra VERSION_PARTS <<< "$CURRENT_VERSION" + MAJOR=${VERSION_PARTS[0]} + MINOR=${VERSION_PARTS[1]} + PATCH=${VERSION_PARTS[2]} + + case $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}" + echo "new_version=${NEW_VERSION}" >> $GITHUB_OUTPUT + echo "tag=v${NEW_VERSION}" >> $GITHUB_OUTPUT + + node -e " + const fs = require('fs'); + const pkg = JSON.parse(fs.readFileSync('package.json', 'utf8')); + pkg.version = '${NEW_VERSION}'; + fs.writeFileSync('package.json', JSON.stringify(pkg, null, 2) + '\n'); + " + + - name: Collect commit messages for release + id: commit_messages + run: | + # Ensure we have all tags + git fetch --tags origin + + # Debug: Show available tags + echo "Available tags:" + git tag --sort=-version:refname | head -5 + + LAST_TAG=$(git tag --sort=-version:refname | head -1 2>/dev/null || echo "") + + # Debug: Show what we detected + echo "Detected last tag: '$LAST_TAG'" + + if [[ -n "$LAST_TAG" && "$LAST_TAG" != "" ]]; then + # Use normal tag-based logic + git log ${LAST_TAG}..HEAD --pretty=format:"- %s" --no-merges > /tmp/commits.txt + echo "Using tag-based range: ${LAST_TAG}..HEAD" + else + # No tags exist, get last 10 commits + git log -10 --pretty=format:"- %s" --no-merges > /tmp/commits.txt + echo "No tags found, using last 10 commits" + fi + + echo "Raw commits:" + cat /tmp/commits.txt + + # Use base64 encoding to safely pass commit messages through JSON + COMMITS_B64=$(base64 -w 0 /tmp/commits.txt) + + # Only use base64 encoded commits to avoid multiline output issues + echo "commits_b64=$COMMITS_B64" >> $GITHUB_OUTPUT + + - name: Amend commit with version + run: | + NEW_VERSION="${{ steps.bump_version.outputs.new_version }}" + CURRENT_MESSAGE=$(git log -1 --pretty=%B) + NEW_MESSAGE="${CURRENT_MESSAGE} [v${NEW_VERSION}]" + + git add package.json + git commit --amend -m "${NEW_MESSAGE}" + + if [ "${{ github.event.inputs.dry_run }}" = "true" ]; then + echo "🔍 DRY RUN: Would push amended commit to main" + else + git push --force-with-lease origin main + fi + + - name: Create tag + run: | + TAG="${{ steps.bump_version.outputs.tag }}" + NEW_VERSION="${{ steps.bump_version.outputs.new_version }}" + + # Create tag with commit messages (decode from base64) + COMMIT_MESSAGES=$(echo "${{ steps.commit_messages.outputs.commits_b64 }}" | base64 -d) + + TAG_MESSAGE=$(printf "Release %s\n\nChanges in this release:\n%s" "${TAG}" "${COMMIT_MESSAGES}") + + git tag -a "${TAG}" -m "${TAG_MESSAGE}" + + if [ "${{ github.event.inputs.dry_run }}" = "true" ]; then + echo "🔍 DRY RUN: Would push tag ${TAG}" + echo "Tag message would be:" + echo "${TAG_MESSAGE}" + else + git push origin "${TAG}" + fi + + - name: Verify version validation passed + env: + TYPEGRAPHQL_PRISMA_VERSION: ${{ steps.bump_version.outputs.tag }} + run: | + echo "Verifying release for version: $TYPEGRAPHQL_PRISMA_VERSION" + + if ! printf "%s\n" "$TYPEGRAPHQL_PRISMA_VERSION" | grep -q -P '^v(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)(-(alpha|beta|rc)\.(0|[1-9][0-9]*))?$'; then + printf '[ERROR]: Invalid version tag format (%s)\n' "$TYPEGRAPHQL_PRISMA_VERSION" + exit 1 + fi + + echo "✅ Version tag format is valid" + + - name: Determine if version is prerelease + id: prerelease + env: + TYPEGRAPHQL_PRISMA_VERSION: ${{ steps.bump_version.outputs.tag }} + run: | + _prerelease= + if printf "%s\n" "$TYPEGRAPHQL_PRISMA_VERSION" | grep -q -P '^v(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)$'; then + _prerelease=false + else + _prerelease=true + fi + + printf 'value=%s\n' "$_prerelease" >> "$GITHUB_OUTPUT" + + - name: Setup Node.js for publishing + uses: actions/setup-node@v4 + with: + node-version: 22.x + registry-url: "https://registry.npmjs.org" + + - name: Install latest npm + run: | + npm install -g npm@latest + + - name: Configure npm authentication + run: | + echo "//registry.npmjs.org/:_authToken=\${NPM_TOKEN}" > .npmrc + + - name: Prepare package + run: | + npm run prepublishOnly + env: + TYPEGRAPHQL_PRISMA_REF: ${{ steps.bump_version.outputs.tag }} + + - name: Format commit messages for release + id: changelog + run: | + COMMITS_B64="${{ steps.commit_messages.outputs.commits_b64 }}" + + if [ -z "$COMMITS_B64" ]; then + echo "No commits provided" + FORMATTED_COMMITS="No changes listed" + else + FORMATTED_COMMITS=$(echo "$COMMITS_B64" | base64 -d) + fi + + RELEASE_BODY=$(printf "## Changes in this release:\n\n%s\n\nReleased as %s" "$FORMATTED_COMMITS" "${{ steps.bump_version.outputs.tag }}") + + # Use base64 encoding to avoid EOF delimiter issues + CHANGELOG_B64=$(echo "$RELEASE_BODY" | base64 -w 0) + echo "changelog_b64=$CHANGELOG_B64" >> $GITHUB_OUTPUT + + - name: Create GitHub Release + if: github.event.inputs.dry_run != 'true' + env: + CHANGELOG_B64: ${{ steps.changelog.outputs.changelog_b64 }} + GH_TOKEN: ${{ github.token }} + run: | + RELEASE_BODY=$(echo "$CHANGELOG_B64" | base64 -d) + gh release create "${{ steps.bump_version.outputs.tag }}" \ + --title "${{ steps.bump_version.outputs.tag }}" \ + --notes "$RELEASE_BODY" \ + ${{ steps.prerelease.outputs.value == 'true' && '--prerelease' || '' }} + + - name: Show GitHub Release Info (Dry Run) + if: github.event.inputs.dry_run == 'true' + run: | + echo "🔍 DRY RUN: Would create GitHub release" + echo "Tag: ${{ steps.bump_version.outputs.tag }}" + echo "Prerelease: ${{ steps.prerelease.outputs.value == 'true' }}" + echo "Release body:" + echo "${{ steps.changelog.outputs.changelog_b64 }}" | base64 -d + + - name: Publish to npm + if: github.event.inputs.dry_run != 'true' + env: + NPM_TOKEN: ${{ secrets.NPM_AUTH_TOKEN }} + TYPEGRAPHQL_PRISMA_PRERELEASE: ${{ steps.prerelease.outputs.value }} + run: | + _tag= + if [ "$TYPEGRAPHQL_PRISMA_PRERELEASE" = "true" ]; then + _tag="next" + else + _tag="latest" + fi + + npm publish --ignore-scripts --access public --tag "$_tag" + + - name: Show npm Publish Info (Dry Run) + if: github.event.inputs.dry_run == 'true' + env: + TYPEGRAPHQL_PRISMA_PRERELEASE: ${{ steps.prerelease.outputs.value }} + run: | + _tag= + if [ "$TYPEGRAPHQL_PRISMA_PRERELEASE" = "true" ]; then + _tag="next" + else + _tag="latest" + fi + + echo "🔍 DRY RUN: Would publish to npm" + echo "Package: @scope3/typegraphql-prisma@${{ steps.bump_version.outputs.new_version }}" + echo "Tag: $_tag" + echo "Access: public" + + - name: Output summary + run: | + if [ "${{ github.event.inputs.dry_run }}" = "true" ]; then + echo "## 🔍 Manual Release Summary (DRY RUN)" >> $GITHUB_STEP_SUMMARY + echo "- **Mode**: DRY RUN - No changes made" >> $GITHUB_STEP_SUMMARY + else + echo "## 🚀 Manual Release Summary" >> $GITHUB_STEP_SUMMARY + fi + echo "- **Previous Version**: ${{ steps.current_version.outputs.current }}" >> $GITHUB_STEP_SUMMARY + echo "- **New Version**: ${{ steps.bump_version.outputs.new_version }}" >> $GITHUB_STEP_SUMMARY + echo "- **Bump Type**: ${{ steps.version_bump.outputs.bump_type }}" >> $GITHUB_STEP_SUMMARY + echo "- **Tag**: ${{ steps.bump_version.outputs.tag }}" >> $GITHUB_STEP_SUMMARY + echo "- **Description**: ${{ github.event.inputs.description || 'None provided' }}" >> $GITHUB_STEP_SUMMARY + if [ "${{ github.event.inputs.dry_run }}" = "true" ]; then + echo "- **Commit**: Would amend last commit with version info" >> $GITHUB_STEP_SUMMARY + echo "- **GitHub Release**: Would create with commit messages" >> $GITHUB_STEP_SUMMARY + echo "- **npm Package**: Would publish successfully" >> $GITHUB_STEP_SUMMARY + else + echo "- **Commit**: Amended last commit with version info" >> $GITHUB_STEP_SUMMARY + echo "- **GitHub Release**: Created with commit messages" >> $GITHUB_STEP_SUMMARY + echo "- **npm Package**: Published successfully" >> $GITHUB_STEP_SUMMARY + fi diff --git a/package.json b/package.json index cc4d1adb2..33c52970b 100644 --- a/package.json +++ b/package.json @@ -1,12 +1,13 @@ { - "name": "typegraphql-prisma", + "name": "@scope3/typegraphql-prisma", "version": "0.28.0", "scripts": { "prepare": "husky install", - "build": "tsc", + "prebuild": "rm -rf lib", + "build": "tsc -p tsconfig.build.json", + "postbuild": "chmod +x lib/generator.js", "prettier": "node ./node_modules/.bin/prettier", - "package:build": "./package.sh", - "package:publish": "cd package *&& npm publish", + "prepublishOnly": "npm run build", "check:type": "tsc --noEmit --skipLibCheck", "check:experiments:postgres": "cd ./experiments/postgres && tsc --noEmit --skipLibCheck", "check:experiments:mongodb": "cd ./experiments/mongodb && tsc --noEmit --skipLibCheck", @@ -20,6 +21,11 @@ "bin": { "typegraphql-prisma": "lib/generator.js" }, + "files": [ + "lib", + "README.md", + "LICENSE" + ], "peerDependencies": { "@prisma/client": "^5.18.0", "@types/graphql-fields": "^1.3.9", @@ -109,5 +115,5 @@ "prettier --ignore-path ./.cli.prettierignore --write" ] }, - "private": true + "private": false } diff --git a/package.sh b/package.sh deleted file mode 100755 index 87f458db0..000000000 --- a/package.sh +++ /dev/null @@ -1,35 +0,0 @@ -#!/bin/bash -START_TIME=$SECONDS - -echo "Building package for distribution..." -rm -rf lib -rm -rf package -mkdir package - -echo "Compiling TypeScript with production config..." -npx tsc -p tsconfig.build.json - -echo "Copying files..." -# Copy the compiled lib directory (already excludes dev files due to tsconfig.build.json) -cp -r lib package/lib - -# Copy essential root files only -cp package.json Readme.md LICENSE package/ - -echo "Setting executable permissions..." -chmod +x package/lib/generator.js - -echo "Adjusting package.json..." -sed -i '' 's/"private": true/"private": false/' ./package/package.json -npm pkg delete scripts.prepare --prefix ./package - -echo "Production build complete!" -echo "Excluded files via tsconfig.build.json:" -echo " - *benchmarked* files" -echo " - *backup* files" -echo " - benchmark.* files" -echo " - test-parallel.* files" -echo " - test-schemas/ directory" - -ELAPSED_TIME=$(($SECONDS - $START_TIME)) -echo "Done in $ELAPSED_TIME seconds!"