diff --git a/.github/workflows/npm-publish.yaml b/.github/workflows/npm-publish.yaml index 3c256bb8..d776c081 100644 --- a/.github/workflows/npm-publish.yaml +++ b/.github/workflows/npm-publish.yaml @@ -3,11 +3,6 @@ name: Release Packages # Manual trigger only - run from GitHub Actions UI when ready to publish on: workflow_dispatch: - inputs: - skip_jira: - description: 'Skip Jira release creation' - type: boolean - default: false # Prevents multiple release workflows from running simultaneously concurrency: ${{ github.workflow }}-${{ github.ref }} @@ -57,8 +52,4 @@ jobs: publish: bash ./scripts/publish.sh env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - NPM_TOKEN: ${{ secrets.NPM_TOKEN }} - SKIP_JIRA: ${{ github.event.inputs.skip_jira }} - JIRA_URL: ${{ secrets.JIRA_URL }} - JIRA_BOT_USERNAME: ${{ secrets.JIRA_BOT_USERNAME }} - JIRA_BOT_PASSWORD: ${{ secrets.JIRA_BOT_PASSWORD }} \ No newline at end of file + NPM_TOKEN: ${{ secrets.NPM_TOKEN }} \ No newline at end of file diff --git a/DEVELOPMENT.md b/DEVELOPMENT.md index b98c24b4..c9095359 100644 --- a/DEVELOPMENT.md +++ b/DEVELOPMENT.md @@ -57,6 +57,10 @@ Follow the prompts to: Commit the generated `.changeset/*.md` file with your changes. +When the version bump PR is created, each changelog entry is automatically prefixed +with a link to its Jira ticket (via [`.issuetracker`](./.issuetracker)), read from the +branch name in the merge commit that added the changeset file. + ### Release process Releases are managed through GitHub Actions workflows. Changesets accumulate until you're ready to release. @@ -76,7 +80,6 @@ Releases are managed through GitHub Actions workflows. Changesets accumulate unt - Go to GitHub Actions → "Release Packages" - Run workflow - Packages publish with `@beta` tag - - Jira release created with `released: false` 4. **Test and iterate** - QA tests using `npm install @optimizely/cms-sdk@beta` @@ -98,7 +101,6 @@ Releases are managed through GitHub Actions workflows. Changesets accumulate unt - Run workflow - Packages publish with `@latest` tag - Beta versions automatically deprecated - - Jira release updated to `released: true` #### Direct stable release (skip beta) diff --git a/scripts/publish.sh b/scripts/publish.sh index 7668740c..ce78a48e 100755 --- a/scripts/publish.sh +++ b/scripts/publish.sh @@ -28,133 +28,3 @@ if [ ! -f .changeset/pre.json ]; then npm deprecate "${PKG_NAME}@${MAJOR_MINOR}.*-beta*" "Beta versions deprecated. Use stable ${PKG_VERSION}" 2>/dev/null || echo " No beta versions found or already deprecated" done fi - -# Create or update Jira release (non-blocking - npm publish always succeeds) -set +e # Disable exit on error for Jira section -if [ "$SKIP_JIRA" = "true" ]; then - echo "⏭️ Skipping Jira (skip_jira=true)" -elif [ -n "$JIRA_BOT_PASSWORD" ]; then - # Check if this is a pre-release - IS_PRERELEASE=false - if [ -f .changeset/pre.json ]; then - IS_PRERELEASE=true - echo "📋 Creating Jira releases (unreleased)..." - else - echo "📋 Updating Jira releases (released)..." - fi - - for pkg in packages/*/package.json; do - PKG_NAME=$(node -p "require('./$pkg').name") - PKG_VERSION=$(node -p "require('./$pkg').version") - - # Strip beta suffix for Jira release name (2.2.0-beta.0 → 2.2.0) - JIRA_VERSION=$(echo "$PKG_VERSION" | sed 's/-beta\.[0-9]*$//') - - # Find previous tag for this package - PREV_TAG=$(git tag --sort=-creatordate | grep "^${PKG_NAME}@" | head -1) - - if [ -z "$PREV_TAG" ]; then - echo "No previous tag for $PKG_NAME, skipping Jira release" - continue - fi - - # Extract Jira IDs from merge commits since previous tag - JIRA_IDS=$(git log --merges --oneline "$PREV_TAG"..HEAD --format="%s" \ - | grep -oE 'CMS-[0-9]+' | sort -u) - - if [ -z "$JIRA_IDS" ]; then - echo "No Jira tickets found for $PKG_NAME@$JIRA_VERSION" - continue - fi - - echo "Found tickets for $PKG_NAME@$JIRA_VERSION: $(echo $JIRA_IDS | tr '\n' ' ')" - - # Check if release already exists in Jira - SEARCH_RESPONSE=$(curl -s "$JIRA_URL/rest/api/3/project/CMS/versions" \ - -H "Content-Type: application/json" \ - -u "$JIRA_BOT_USERNAME:$JIRA_BOT_PASSWORD") - - EXISTING_VERSION_ID=$(echo "$SEARCH_RESPONSE" | node -p " - const versions = JSON.parse(require('fs').readFileSync(0)); - const existing = versions.find(v => v.name === '${PKG_NAME}@${JIRA_VERSION}'); - existing ? existing.id : '' - ") - - if [ -n "$EXISTING_VERSION_ID" ]; then - # Update existing release - if [ "$IS_PRERELEASE" = false ]; then - echo "Updating existing Jira release to released=true..." - RESPONSE=$(curl -s -w "\n%{http_code}" -X PUT "$JIRA_URL/rest/api/3/version/$EXISTING_VERSION_ID" \ - -H "Content-Type: application/json" \ - -u "$JIRA_BOT_USERNAME:$JIRA_BOT_PASSWORD" \ - -d "{ - \"released\": true, - \"releaseDate\": \"$(date +%Y-%m-%d)\" - }") - - HTTP_CODE=$(echo "$RESPONSE" | tail -1) - if [ "$HTTP_CODE" = "200" ]; then - echo "Updated Jira release version ID: $EXISTING_VERSION_ID" - else - echo "::warning::Failed to update Jira release (HTTP $HTTP_CODE)" - fi - else - echo "Jira release already exists (ID: $EXISTING_VERSION_ID), skipping" - fi - continue - fi - - # Create new release version in Jira - if [ "$IS_PRERELEASE" = true ]; then - RELEASE_PAYLOAD="{ - \"name\": \"${PKG_NAME}@${JIRA_VERSION}\", - \"project\": \"CMS\", - \"released\": false - }" - else - RELEASE_PAYLOAD="{ - \"name\": \"${PKG_NAME}@${JIRA_VERSION}\", - \"project\": \"CMS\", - \"released\": true, - \"releaseDate\": \"$(date +%Y-%m-%d)\" - }" - fi - - RESPONSE=$(curl -s -w "\n%{http_code}" -X POST "$JIRA_URL/rest/api/3/version" \ - -H "Content-Type: application/json" \ - -u "$JIRA_BOT_USERNAME:$JIRA_BOT_PASSWORD" \ - -d "$RELEASE_PAYLOAD") - - HTTP_CODE=$(echo "$RESPONSE" | tail -1) - BODY=$(echo "$RESPONSE" | sed '$d') - - if [ "$HTTP_CODE" != "201" ]; then - echo "::warning::Failed to create Jira release (HTTP $HTTP_CODE): $BODY" - continue - fi - - VERSION_ID=$(echo "$BODY" | node -p "JSON.parse(require('fs').readFileSync(0)).id") - echo "Created Jira release version ID: $VERSION_ID" - - # Link each Jira issue to this release - for ISSUE in $JIRA_IDS; do - LINK_RESPONSE=$(curl -s -w "\n%{http_code}" -X PUT "$JIRA_URL/rest/api/3/issue/$ISSUE" \ - -H "Content-Type: application/json" \ - -u "$JIRA_BOT_USERNAME:$JIRA_BOT_PASSWORD" \ - -d "{ - \"update\": { - \"fixVersions\": [{\"add\": {\"id\": \"$VERSION_ID\"}}] - } - }") - - LINK_HTTP_CODE=$(echo "$LINK_RESPONSE" | tail -1) - - if [ "$LINK_HTTP_CODE" = "204" ]; then - echo " ✓ Linked $ISSUE" - else - echo " ✗ Failed to link $ISSUE (HTTP $LINK_HTTP_CODE)" - fi - done - done -fi -set -e # Re-enable exit on error diff --git a/scripts/version-selective.sh b/scripts/version-selective.sh index f6118b9a..6319a173 100755 --- a/scripts/version-selective.sh +++ b/scripts/version-selective.sh @@ -8,7 +8,34 @@ set -e # are moved aside and restored so they stay pending on main. TARGET="$1" +# Prepend each changeset's release note with a link to its Jira ticket, so +# every changelog entry traces back to the ticket that introduced it. The +# ticket ID is pulled from the branch name recorded in the merge commit that +# added the changeset file (e.g. "Merge pull request #1 from org/CMS-123-foo"). +link_jira_tickets() { + local regex url + regex=$(sed -n 's/.*regex = "\(.*\)".*/\1/p' .issuetracker | sed 's/\\\\/\\/g; s/\\d/[0-9]/g') + url=$(sed -n 's/.*url = "\(.*\)".*/\1/p' .issuetracker) + + for f in .changeset/*.md; do + [ "$(basename "$f")" = "README.md" ] && continue + local commit ticket id link + commit=$(git log --diff-filter=A --max-count=1 --pretty=format:%H -- "$f") + [ -z "$commit" ] && continue + ticket=$(git log -1 --format=%B "$commit" | grep -oE "$regex" | head -1) + [ -z "$ticket" ] && continue + id=${ticket#CMS-} + link="[$ticket](${url/\$1/$id})" + awk -v link="$link" ' + $0 == "---" { fm++; print; next } + fm >= 2 && !inserted && NF > 0 { print link ": " $0; inserted=1; next } + { print } + ' "$f" > "$f.tmp" && mv "$f.tmp" "$f" + done +} + if [ -z "$TARGET" ] || [ "$TARGET" = "all" ]; then + link_jira_tickets pnpm changeset version exit 0 fi @@ -21,6 +48,7 @@ for f in .changeset/*.md; do grep -q "'$TARGET'" "$f" || mv "$f" "$HOLD/" done +link_jira_tickets pnpm changeset version # restore held changesets so they remain pending (unchanged in the PR diff)