Skip to content
Open
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
120 changes: 63 additions & 57 deletions .github/workflows/prepare-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ on:
description: 'Version number (e.g., 3.6.0 or 1.0.0-beta1)'
required: true
type: string
ticket:
description: 'Jira ticket number (e.g., 1234 for SDK-1234)'
required: true
type: string

permissions:
contents: write
Expand All @@ -16,71 +20,61 @@ jobs:
prepare-release:
runs-on: ubuntu-latest
steps:
- uses: actions/create-github-app-token@v1
id: app-token
with:
app-id: ${{ vars.ITERABLE_SDK_RELEASE_APP_ID }}
private-key: ${{ secrets.ITERABLE_SDK_RELEASE_APP_PRIVATE_KEY }}

- uses: actions/checkout@v4
with:
token: ${{ secrets.GITHUB_TOKEN }}
ref: master
token: ${{ steps.app-token.outputs.token }}

- name: Validate version format
run: |
if ! [[ "${{ github.event.inputs.version }}" =~ ^[0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9]+)?$ ]]; then
echo "::error::Invalid version format. Use semantic versioning (e.g., 3.6.0 or 3.6.0-beta1)"
exit 1
fi

- name: Update Changelog
id: update_changelog
run: |
version="${{ github.event.inputs.version }}"
changelog_file="CHANGELOG.md"

# Function to extract content between two patterns, including the first pattern
extract_between() {
awk "/^## \[$1\]/{p=1;print;next} /^## \[/{p=0} p" "$3"
}

# Get the unreleased content
unreleased_content=$(extract_between "Unreleased" "[0-9]" "$changelog_file")


unreleased_content=$(awk '/^## \[Unreleased\]/{p=1;next} /^## \[/{p=0} p' "$changelog_file")

if [ -z "$unreleased_content" ]; then
echo "No unreleased changes found in $changelog_file"
exit 1
fi

# Get the current version
current_version=$(grep -oP "^## \[\K[0-9]+\.[0-9]+\.[0-9]+(?:-[a-zA-Z0-9]+)?(?=\])" "$changelog_file" | head -n1)
new_version="${{ github.event.inputs.version }}"

# Validate version format (now includes beta versions)
if ! [[ $new_version =~ ^[0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9]+)?$ ]]; then
echo "Invalid version format. Please use semantic versioning (e.g., 3.6.0 or 1.0.0-beta1)"
echo "::error::No unreleased changes found in $changelog_file. Add release notes to the [Unreleased] section before running this workflow."
exit 1
fi
echo "new_version=${new_version}" >> $GITHUB_OUTPUT

# Create temporary file

notes_file="$RUNNER_TEMP/release-notes.md"
printf '%s' "$unreleased_content" > "$notes_file"

temp_file=$(mktemp)

# Preserve header and write new content
{
# Preserve the header (first 4 lines)
head -n 4 "$changelog_file"
echo "## [Unreleased]"
echo ""
echo "## [$new_version]"
# Remove the "## [Unreleased]" line from unreleased_content if it exists
echo "## [$version]"
echo "$unreleased_content" | sed '1{/^## \[Unreleased\]/d}'
echo ""
# Get the rest of the file starting from the first version entry
sed -n '/^## \[[0-9]/,$p' "$changelog_file"
} > "$temp_file"

# Replace original file
mv "$temp_file" "$changelog_file"

- name: Update Version Files
run: |
# Create temp file for build.gradle updates
version="${{ github.event.inputs.version }}"

sed -i "s/libraryVersion = '.*'/libraryVersion = '$version'/" iterableapi/build.gradle
sed -i "s/versionName=\".*\"/versionName=\"$version\"/" iterableapi/build.gradle

temp_gradle=$(mktemp)

# Update iterableapi/build.gradle - libraryVersion and versionName
sed -i "s/libraryVersion = '.*'/libraryVersion = '${{ github.event.inputs.version }}'/" iterableapi/build.gradle
sed -i "s/versionName=\".*\"/versionName=\"${{ github.event.inputs.version }}\"/" iterableapi/build.gradle

# Update buildConfigField version in defaultConfig section
awk -v version="${{ github.event.inputs.version }}" '
awk -v version="$version" '
/defaultConfig {/,/}/ {
if ($0 ~ /buildConfigField.*ITERABLE_SDK_VERSION/) {
print " buildConfigField \"String\", \"ITERABLE_SDK_VERSION\", \"\\\"" version "\\\"\""
Expand All @@ -89,34 +83,46 @@ jobs:
}
{ print }' iterableapi/build.gradle > "$temp_gradle" && cat "$temp_gradle" > iterableapi/build.gradle
rm "$temp_gradle"

# Update iterableapi-ui/build.gradle
sed -i "s/libraryVersion = '.*'/libraryVersion = '${{ github.event.inputs.version }}'/" iterableapi-ui/build.gradle

# Update sample app versions
sed -i "s/implementation 'com.iterable:iterableapi:[^']*'/implementation 'com.iterable:iterableapi:${{ github.event.inputs.version }}'/" sample-apps/inbox-customization/app/build.gradle
sed -i "s/implementation 'com.iterable:iterableapi-ui:[^']*'/implementation 'com.iterable:iterableapi-ui:${{ github.event.inputs.version }}'/" sample-apps/inbox-customization/app/build.gradle

sed -i "s/libraryVersion = '.*'/libraryVersion = '$version'/" iterableapi-ui/build.gradle

sed -i "s/implementation 'com.iterable:iterableapi:[^']*'/implementation 'com.iterable:iterableapi:$version'/" sample-apps/inbox-customization/app/build.gradle
sed -i "s/implementation 'com.iterable:iterableapi-ui:[^']*'/implementation 'com.iterable:iterableapi-ui:$version'/" sample-apps/inbox-customization/app/build.gradle

- name: Create Pull Request
uses: peter-evans/create-pull-request@4e1beaa7521e8b457b572c090b25bd3db56bf1c5 # v5
with:
token: ${{ secrets.GITHUB_TOKEN }}
title: "Prepare for Release ${{ steps.update_changelog.outputs.new_version }}"
token: ${{ steps.app-token.outputs.token }}
title: "SDK-${{ github.event.inputs.ticket }}: Prepare for Release ${{ github.event.inputs.version }}"
body: |
# Prepare for Release ${{ steps.update_changelog.outputs.new_version }}
# Prepare for Release ${{ github.event.inputs.version }}

## SDK Release Checklist
- [ ] CHANGELOG.md updated
- [ ] Version numbers updated in build.gradle files:
- [ ] iterableapi/build.gradle (libraryVersion, versionName, and ITERABLE_SDK_VERSION)
- [ ] iterableapi/build.gradle (libraryVersion, versionName, ITERABLE_SDK_VERSION)
- [ ] iterableapi-ui/build.gradle (libraryVersion)
- [ ] sample-apps/inbox-customization/app/build.gradle (both dependencies)
- [ ] README.md reviewed (if needed)
- [ ] Sample apps verified
- [ ] All tests passing
- [ ] Documentation updated (if needed)

branch: "prepare-for-release-${{ steps.update_changelog.outputs.new_version }}"
commit-message: "Prepare for release ${{ steps.update_changelog.outputs.new_version }}"
branch: "release/SDK-${{ github.event.inputs.ticket }}-${{ github.event.inputs.version }}"
commit-message: "[SDK-${{ github.event.inputs.ticket }}]: Prepare for release ${{ github.event.inputs.version }}"
labels: release
delete-branch: true
delete-branch: true

- name: Create Draft GitHub Release
env:
GH_TOKEN: ${{ steps.app-token.outputs.token }}
run: |
version="${{ github.event.inputs.version }}"

if gh release view "$version" &>/dev/null; then
echo "Draft release $version already exists, skipping."
else
gh release create "$version" \
--draft \
--title "$version" \
--notes-file "$RUNNER_TEMP/release-notes.md"
fi
86 changes: 86 additions & 0 deletions .github/workflows/publish-release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
name: Publish Release

on:
workflow_dispatch:
inputs:
version:
description: 'Version to publish (e.g., 3.6.0)'
required: true
type: string

env:
VERSION: ${{ github.event.inputs.version }}

permissions:
contents: write

jobs:
publish-release:
runs-on: ubuntu-latest
steps:
- uses: actions/create-github-app-token@v1
id: app-token
with:
app-id: ${{ vars.ITERABLE_SDK_RELEASE_APP_ID }}
private-key: ${{ secrets.ITERABLE_SDK_RELEASE_APP_PRIVATE_KEY }}

- uses: actions/checkout@v4
with:
ref: master
token: ${{ steps.app-token.outputs.token }}

- name: Verify release is ready
run: |
if ! grep -qE "^## \[$VERSION\]" CHANGELOG.md; then
echo "::error::CHANGELOG.md has no entry for [$VERSION]. Merge the prepare-release PR to master before running this workflow."
exit 1
fi

- name: Set up JDK
uses: actions/setup-java@v4
with:
java-version: "17"
distribution: "temurin"
cache: gradle

- name: Import GPG Key
run: |
echo "${{ secrets.GPG_PRIVATE_KEY }}" | base64 -d | gpg --batch --import
gpg --batch --pinentry-mode loopback --passphrase "${{ secrets.GPG_PASSPHRASE }}" --export-secret-keys > ~/.gnupg/secring.gpg
GPG_KEY_ID="${{ secrets.GPG_KEY_ID }}"
echo "SHORT_GPG_KEY_ID=${GPG_KEY_ID: -8}" >> $GITHUB_ENV

- name: Publish to Sonatype Central
run: ./gradlew clean :iterableapi:assemble :iterableapi-ui:assemble publishAllPublicationsToCentralPortal
env:
ORG_GRADLE_PROJECT_SIGNING_KEY_ID: ${{ env.SHORT_GPG_KEY_ID }}
ORG_GRADLE_PROJECT_SIGNING_PASSWORD: ${{ secrets.GPG_PASSPHRASE }}
ORG_GRADLE_PROJECT_SIGNING_SECRET_KEY_RING_FILE: /home/runner/.gnupg/secring.gpg
ORG_GRADLE_PROJECT_SONATYPE_USERNAME: ${{ secrets.SONATYPE_USERNAME }}
ORG_GRADLE_PROJECT_SONATYPE_PASSWORD: ${{ secrets.SONATYPE_PASSWORD }}

- name: Publish draft GitHub release and tag master
env:
GH_TOKEN: ${{ steps.app-token.outputs.token }}
run: |
gh release edit "$VERSION" \
--draft=false \
--target "$(git rev-parse HEAD)" \
--latest

- name: Slack notification
run: |
release_url="https://github.com/${{ github.repository }}/releases/tag/$VERSION"
payload=$(jq -n \
--arg text ":android: *Android SDK ${VERSION}* has been released. <${release_url}|View release notes>." \
'{"text": $text}')
curl -sS -X POST -H 'Content-type: application/json' --data "$payload" "${{ secrets.SLACK_WEBHOOK }}"

- name: Slack failure notification
if: failure()
run: |
run_url="${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}/attempts/${{ github.run_attempt }}"
payload=$(jq -n \
--arg text ":alert: Android SDK release ${VERSION} failed (attempt ${{ github.run_attempt }}). Run: ${run_url}" \
'{"text": $text}')
curl -sS -X POST -H 'Content-type: application/json' --data "$payload" "${{ secrets.SLACK_WEBHOOK }}"
41 changes: 0 additions & 41 deletions .github/workflows/publish.yml

This file was deleted.

Loading