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
11 changes: 1 addition & 10 deletions .github/workflows/npm-publish.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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 }}
Expand Down Expand Up @@ -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 }}
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
6 changes: 4 additions & 2 deletions DEVELOPMENT.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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`
Expand All @@ -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)

Expand Down
130 changes: 0 additions & 130 deletions scripts/publish.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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
28 changes: 28 additions & 0 deletions scripts/version-selective.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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)
Expand Down
Loading