Skip to content

Commit a9e9e17

Browse files
committed
ci: add create-release-pr workflow action (#1084)
1 parent d26d108 commit a9e9e17

File tree

4 files changed

+306
-70
lines changed

4 files changed

+306
-70
lines changed

.github/release-drafter.yml

Lines changed: 0 additions & 27 deletions
This file was deleted.
Lines changed: 305 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,305 @@
1+
name: Create Release PR
2+
3+
on:
4+
# For making a release pr from android / ios sdk actions
5+
workflow_call:
6+
inputs:
7+
cordova_version:
8+
description: 'New Cordova Version (e.g., 5.2.15 or 5.2.15-beta.1)'
9+
required: true
10+
type: string
11+
android_version:
12+
description: 'New Android SDK Version (e.g., 2.3.0). Leave blank to skip.'
13+
required: false
14+
type: string
15+
ios_version:
16+
description: 'New iOS SDK Version (e.g., 1.5.0). Leave blank to skip.'
17+
required: false
18+
type: string
19+
20+
# For making a release pr from cordova github actions
21+
workflow_dispatch:
22+
inputs:
23+
cordova_version:
24+
description: 'New Cordova Version (e.g., 5.2.15 or 5.2.15-beta.1)'
25+
required: true
26+
type: string
27+
android_version:
28+
description: 'New Android SDK Version (e.g., 2.3.0). Leave blank to skip.'
29+
required: false
30+
type: string
31+
ios_version:
32+
description: 'New iOS SDK Version (e.g., 1.5.0). Leave blank to skip.'
33+
required: false
34+
type: string
35+
36+
jobs:
37+
update-version:
38+
runs-on: ubuntu-latest
39+
40+
env:
41+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
42+
43+
steps:
44+
- name: Checkout
45+
uses: actions/checkout@v5
46+
with:
47+
fetch-depth: 0
48+
fetch-tags: true
49+
50+
- name: Setup Bun
51+
uses: oven-sh/setup-bun@v2
52+
with:
53+
bun-version: latest
54+
55+
- name: Install
56+
run: bun install --frozen-lockfile
57+
58+
- name: Get last release commit
59+
id: last_commit
60+
run: |
61+
CURRENT_VERSION=$(bun -e "console.log(require('./package.json').version)")
62+
LAST_RELEASE_DATE=$(git show -s --format=%cI "$CURRENT_VERSION")
63+
echo "date=$LAST_RELEASE_DATE" >> $GITHUB_OUTPUT
64+
65+
- name: Release branch name
66+
id: release_branch
67+
run: |
68+
BRANCH_VERSION=$(echo "${{ inputs.cordova_version }}" | sed 's/\(-[a-z]*\)\.[0-9]*$/\1/')
69+
echo "releaseBranch=rel/$BRANCH_VERSION" >> $GITHUB_OUTPUT
70+
71+
- name: Get merged PRs
72+
id: get_prs
73+
uses: actions/github-script@v8
74+
with:
75+
script: |
76+
const lastReleaseDate = '${{ steps.last_commit.outputs.date }}';
77+
const releaseBranch = '${{ steps.release_branch.outputs.releaseBranch }}';
78+
79+
// Get merged PRs
80+
const { data: prs } = await github.rest.pulls.list({
81+
owner: context.repo.owner,
82+
repo: context.repo.repo,
83+
state: 'closed',
84+
base: 'main',
85+
per_page: 100
86+
});
87+
const { data: relPrs } = await github.rest.pulls.list({
88+
owner: context.repo.owner,
89+
repo: context.repo.repo,
90+
state: 'closed',
91+
base: releaseBranch,
92+
per_page: 100
93+
});
94+
95+
// Filter and process PRs
96+
const mergedPrs = [...prs, ...relPrs]
97+
.filter(pr => pr.merged_at && new Date(pr.merged_at) > new Date(lastReleaseDate))
98+
.map(pr => ({
99+
number: pr.number,
100+
title: pr.title,
101+
}));
102+
core.setOutput('prs', JSON.stringify(mergedPrs));
103+
104+
- name: Create release branch
105+
run: |
106+
releaseBranch="${{ steps.release_branch.outputs.releaseBranch }}"
107+
git checkout -b "$releaseBranch"
108+
git push -u origin "$releaseBranch"
109+
110+
- name: Get current native SDK versions
111+
id: current_versions
112+
run: |
113+
# Extract current Android SDK version
114+
ANDROID_VERSION=$(grep -oP 'com\.onesignal:OneSignal:\K[0-9.]+' plugin.xml | head -1)
115+
116+
# Extract current iOS SDK version
117+
IOS_VERSION=$(grep -oP 'OneSignalXCFramework.*spec="\K[0-9.]+' plugin.xml | head -1)
118+
119+
echo "prev_android=$ANDROID_VERSION" >> $GITHUB_OUTPUT
120+
echo "prev_ios=$IOS_VERSION" >> $GITHUB_OUTPUT
121+
122+
# Cordova specific steps
123+
- name: Update Android SDK version
124+
if: inputs.android_version != ''
125+
run: |
126+
VERSION="${{ inputs.android_version }}"
127+
128+
# Validate version exists on GitHub
129+
RELEASE=$(curl -s -H "Authorization: token ${{ github.token }}" \
130+
"https://api.github.com/repos/OneSignal/OneSignal-Android-SDK/releases/tags/${VERSION}")
131+
132+
if echo "$RELEASE" | grep -q "\"id\""; then
133+
# Update plugin.xml with new version
134+
sed -i "s|<framework src=\"com\.onesignal:OneSignal:[^\"]*\" />|<framework src=\"com.onesignal:OneSignal:${VERSION}\" />|" plugin.xml
135+
echo "✓ Updated plugin.xml with Android SDK ${VERSION}"
136+
else
137+
echo "✗ Android SDK version ${VERSION} not found"
138+
exit 1
139+
fi
140+
141+
- name: Update iOS SDK version
142+
if: inputs.ios_version != ''
143+
run: |
144+
VERSION="${{ inputs.ios_version }}"
145+
146+
# Validate version exists on GitHub
147+
RELEASE=$(curl -s -H "Authorization: token ${{ github.token }}" \
148+
"https://api.github.com/repos/OneSignal/OneSignal-iOS-SDK/releases/tags/${VERSION}")
149+
150+
if echo "$RELEASE" | grep -q "\"id\""; then
151+
# Update plugin.xml with new version
152+
sed -i "s|<pod name=\"OneSignalXCFramework\" spec=\"[^\"]*\" />|<pod name=\"OneSignalXCFramework\" spec=\"${VERSION}\" />|" plugin.xml
153+
echo "✓ Updated plugin.xml with iOS SDK ${VERSION}"
154+
155+
# Need to clear the Podfile.lock to force a re-install of the framework
156+
rm -f example/IonicCapOneSignal/ios/App/Podfile.lock
157+
else
158+
echo "✗ iOS SDK version ${VERSION} not found"
159+
exit 1
160+
fi
161+
162+
- name: Capacitor update
163+
run: |
164+
bunx cap sync || exit 1
165+
git add .
166+
167+
- name: Update sdk version
168+
run: |
169+
NEW_VERSION="${{ inputs.cordova_version }}"
170+
git config user.name "github-actions[bot]"
171+
git config user.email "github-actions[bot]@users.noreply.github.com"
172+
173+
# Convert version format for OneSignal wrapper (e.g., 5.2.15 -> 050215)
174+
# For pre-releases, extract base version first (e.g., 5.2.15-alpha.1 -> 5.2.15)
175+
BASE_VERSION=$(echo "$NEW_VERSION" | sed 's/-[a-z].*//')
176+
WRAPPER_VERSION=$(echo "$BASE_VERSION" | awk -F'.' '{printf "%02d%02d%02d", $1, $2, $3}')
177+
178+
# Update package.json version
179+
npm pkg set version="$NEW_VERSION"
180+
181+
# Update plugin.xml cordova plugin version (target <plugin> element specifically)
182+
sed -i 's|<plugin \(xmlns="[^"]*" xmlns:android="[^"]*" id="[^"]*"\) version="[^"]*"|<plugin \1 version="'"$NEW_VERSION"'"|' plugin.xml
183+
184+
# Update OneSignalPush.java wrapper version
185+
sed -i "s/OneSignalWrapper\.setSdkVersion(\"[^\"]*\")/OneSignalWrapper.setSdkVersion(\"$WRAPPER_VERSION\")/g" src/android/com/onesignal/cordova/OneSignalPush.java
186+
187+
# Update OneSignalPush.m wrapper version
188+
sed -i "s/OneSignalWrapper\.sdkVersion = @\"[^\"]*\"/OneSignalWrapper.sdkVersion = @\"$WRAPPER_VERSION\"/g" src/ios/OneSignalPush.m
189+
190+
git add package.json plugin.xml src/android/com/onesignal/cordova/OneSignalPush.java src/ios/OneSignalPush.m
191+
192+
git commit -m "Release $NEW_VERSION"
193+
git push
194+
195+
- name: Document native sdk changes
196+
id: native_deps
197+
run: |
198+
# Get the current plugin.xml
199+
CURRENT_PLUGIN=$(cat plugin.xml)
200+
201+
# Extract current Android SDK version
202+
ANDROID_VERSION=$(echo "$CURRENT_PLUGIN" | grep -oP 'com\.onesignal:OneSignal:\K[0-9.]+' | head -1)
203+
PREVIOUS_ANDROID="${{ steps.current_versions.outputs.prev_android }}"
204+
205+
# Extract current iOS SDK version
206+
IOS_VERSION=$(echo "$CURRENT_PLUGIN" | grep -oP 'OneSignalXCFramework.*spec="\K[0-9.]+' | head -1)
207+
PREVIOUS_IOS="${{ steps.current_versions.outputs.prev_ios }}"
208+
209+
# Build output for native dependency changes
210+
NATIVE_UPDATES=""
211+
if [[ "$ANDROID_VERSION" != "$PREVIOUS_ANDROID" && ! -z "$PREVIOUS_ANDROID" ]]; then
212+
printf -v NATIVE_UPDATES '%sANDROID_UPDATE=true\nANDROID_FROM=%s\nANDROID_TO=%s\n' "$NATIVE_UPDATES" "$PREVIOUS_ANDROID" "$ANDROID_VERSION"
213+
fi
214+
215+
if [[ "$IOS_VERSION" != "$PREVIOUS_IOS" && ! -z "$PREVIOUS_IOS" ]]; then
216+
printf -v NATIVE_UPDATES '%sIOS_UPDATE=true\nIOS_FROM=%s\nIOS_TO=%s\n' "$NATIVE_UPDATES" "$PREVIOUS_IOS" "$IOS_VERSION"
217+
fi
218+
219+
# Output the variables
220+
echo "$NATIVE_UPDATES" >> $GITHUB_OUTPUT
221+
222+
- name: Get release type
223+
id: release_type
224+
run: |
225+
NEW_VERSION="${{ inputs.cordova_version }}"
226+
if [[ "$NEW_VERSION" =~ -alpha ]]; then
227+
echo "release-type=Alpha" >> $GITHUB_OUTPUT
228+
elif [[ "$NEW_VERSION" =~ -beta ]]; then
229+
echo "release-type=Beta" >> $GITHUB_OUTPUT
230+
else
231+
echo "release-type=Current" >> $GITHUB_OUTPUT
232+
fi
233+
234+
- name: Generate release notes
235+
id: release_notes
236+
uses: actions/github-script@v8
237+
with:
238+
script: |
239+
// Trim whitespace from PR titles
240+
const prs = JSON.parse('${{ steps.get_prs.outputs.prs }}').map(pr => ({
241+
...pr,
242+
title: pr.title.trim()
243+
}));
244+
245+
// Categorize PRs
246+
const features = prs.filter(pr => /^feat/i.test(pr.title));
247+
const fixes = prs.filter(pr => /^fix/i.test(pr.title));
248+
const improvements = prs.filter(pr => /^(perf|refactor|chore)/i.test(pr.title));
249+
250+
// Helper function to build section
251+
const buildSection = (title, prs) => {
252+
if (prs.length === 0) return '';
253+
let section = `### ${title}\n\n`;
254+
prs.forEach(pr => {
255+
section += `- ${pr.title} (#${pr.number})\n`;
256+
});
257+
return section + '\n';
258+
};
259+
260+
let releaseNotes = `Channels: ${{ steps.release_type.outputs.release-type }}\n\n`;
261+
releaseNotes += buildSection('🚀 New Features', features);
262+
releaseNotes += buildSection('🐛 Bug Fixes', fixes);
263+
releaseNotes += buildSection('✨ Improvements', improvements);
264+
265+
// Check for native dependency changes
266+
const hasAndroidUpdate = '${{ steps.native_deps.outputs.ANDROID_UPDATE }}' === 'true';
267+
const hasIosUpdate = '${{ steps.native_deps.outputs.IOS_UPDATE }}' === 'true';
268+
269+
if (hasAndroidUpdate || hasIosUpdate) {
270+
releaseNotes += '\n### 🛠️ Native Dependency Updates\n\n';
271+
if (hasAndroidUpdate) {
272+
releaseNotes += `- Update Android SDK from ${{ steps.native_deps.outputs.ANDROID_FROM }} to ${{ steps.native_deps.outputs.ANDROID_TO }}\n`;
273+
releaseNotes += `- See [release notes](https://github.com/OneSignal/OneSignal-Android-SDK/releases) for full details\n`;
274+
}
275+
if (hasIosUpdate) {
276+
releaseNotes += `- Update iOS SDK from ${{ steps.native_deps.outputs.IOS_FROM }} to ${{ steps.native_deps.outputs.IOS_TO }}\n`;
277+
releaseNotes += `- See [release notes](https://github.com/OneSignal/OneSignal-iOS-SDK/releases) for full details\n`;
278+
}
279+
releaseNotes += '\n';
280+
}
281+
282+
core.setOutput('notes', releaseNotes);
283+
284+
- name: Create release PR
285+
run: |
286+
NEW_VERSION="${{ inputs.cordova_version }}"
287+
RELEASE_TYPE="${{ steps.release_type.outputs.release-type }}"
288+
289+
# Determine base branch based on release type
290+
if [[ "$RELEASE_TYPE" == "Current" ]]; then
291+
BASE_BRANCH="main"
292+
else
293+
BASE_BRANCH="${{ steps.release_branch.outputs.releaseBranch }}"
294+
fi
295+
296+
# Write release notes to file to avoid shell interpretation
297+
cat > release_notes.md << 'EOF'
298+
${{ steps.release_notes.outputs.notes }}
299+
EOF
300+
301+
gh pr create \
302+
--title "Release $NEW_VERSION" \
303+
--body-file release_notes.md \
304+
--base "$BASE_BRANCH" \
305+
--reviewer fadi-george,sherwinski,jkasten2

.github/workflows/lint-pr-title.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ concurrency:
1010
cancel-in-progress: true
1111

1212
jobs:
13-
lint:
13+
lint-pr-title:
1414
runs-on: ubuntu-latest
1515
steps:
1616
- uses: amannn/action-semantic-pull-request@v6

.github/workflows/release-drafter.yml

Lines changed: 0 additions & 42 deletions
This file was deleted.

0 commit comments

Comments
 (0)