Skip to content

Commit beddfa9

Browse files
committed
Merge branch 'develop' into 28277-spatial-action-on-no-focus
2 parents a5813dd + 03ec748 commit beddfa9

165 files changed

Lines changed: 4454 additions & 1222 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/scripts/notifySlackTeam.js

Lines changed: 30 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
const fs = require('fs');
22
const https = require('https');
3+
const { parseChangelogEntry } = require('./parseChangelogEntry.js');
34

45
const versionNumber = process.argv[2];
56
const jobStatus = process.argv[3];
@@ -10,32 +11,32 @@ const runId = process.argv[6];
1011
const failureSlackChannelId = 'CGRK9DV7H';
1112
const successSlackChannelId = 'C0LJ16JBS';
1213

13-
fs.readFile(changelogPath, 'utf8', (err, fileContent) => {
14-
if (err) {
15-
throw err;
16-
}
17-
18-
const changelogContent = parseChangelogEntry(fileContent);
19-
sendSlackMessage(versionNumber, changelogContent);
20-
});
21-
14+
if (jobStatus !== 'success') {
15+
sendSlackMessage(versionNumber, '');
16+
} else {
17+
fs.readFile(changelogPath, 'utf8', (err, fileContent) => {
18+
if (err) {
19+
throw err;
20+
}
2221

23-
function parseChangelogEntry(fileContent) {
24-
// The regex looks for the first paragraph starting with "###" until it finds
25-
// a paragraph starting with "##".
26-
// For some reason it also matches 2 chars at the end. With the .slice
27-
// those 2 chars get removed from the string.
28-
const regex = /###(.)*[\s\S]*?(?=\s##\s\[v*?)/;
22+
let changelogContent;
23+
try {
24+
changelogContent = parseChangelogEntry(fileContent);
25+
} catch (parseError) {
26+
console.error(`Failed to parse the latest changelog entry for v${versionNumber}.`, parseError);
27+
changelogContent =
28+
`Changelog details could not be extracted automatically for v${versionNumber}. ` +
29+
'Please check CHANGELOG.md in the release tag.';
30+
}
2931

30-
let changelogContent = fileContent.match(regex);
31-
changelogContent = changelogContent.slice(0, -1);
32-
return changelogContent.toString();
32+
sendSlackMessage(versionNumber, changelogContent);
33+
});
3334
}
3435

3536
function sendSlackMessage(releaseVersion, changelogContent) {
3637
const slackChannelId = jobStatus === 'success' ? successSlackChannelId : failureSlackChannelId;
3738
const generalPayload = {
38-
channel: slackChannelId
39+
channel: slackChannelId,
3940
};
4041

4142
let payload;
@@ -63,7 +64,7 @@ function sendSlackMessage(releaseVersion, changelogContent) {
6364
],
6465
},
6566
],
66-
}
67+
};
6768
} else {
6869
payload = {
6970
...generalPayload,
@@ -76,31 +77,31 @@ function sendSlackMessage(releaseVersion, changelogContent) {
7677
text: `Please check the <https://github.com/bitmovin/bitmovin-player-ui/actions/runs/${runId}|failed run>`,
7778
},
7879
],
79-
}
80+
};
8081
}
8182

8283
const sampleData = JSON.stringify(payload);
8384
const options = {
8485
method: 'POST',
8586
headers: {
8687
'Content-Type': 'application/json',
87-
'Accept': "application/json",
88-
}
88+
Accept: 'application/json',
89+
},
8990
};
9091

91-
var req = https.request(slackWebhookUrl, options, (res) => {
92+
var req = https.request(slackWebhookUrl, options, res => {
9293
console.log('statusCode:', res.statusCode);
9394
console.log('headers:', res.headers);
94-
95-
res.on('data', (d) => {
95+
96+
res.on('data', d => {
9697
process.stdout.write(d);
9798
});
9899
});
99-
100-
req.on('error', (e) => {
100+
101+
req.on('error', e => {
101102
console.error(e);
102103
});
103-
104+
104105
req.write(sampleData);
105106
req.end();
106107
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
/**
2+
* Extracts the first (latest) changelog entry from a changelog string.
3+
*
4+
* @param {string} changelogContent - The full changelog file content
5+
* @returns {string} The changelog entry content (without the ## heading)
6+
* @throws {Error} If no changelog entry is found
7+
*/
8+
function parseChangelogEntry(changelogContent) {
9+
const match = changelogContent.match(/## \[[\s\S]*?(?=\n## |$)/);
10+
11+
if (!match) {
12+
throw new Error('No changelog entry found');
13+
}
14+
15+
return match[0].replace(/^## .*\n/, '').trim();
16+
}
17+
18+
module.exports.parseChangelogEntry = parseChangelogEntry;

.github/workflows/ci.yml

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,34 @@ on:
44
push:
55
branches:
66
- '**'
7-
7+
pull_request:
88
workflow_call:
99

1010
concurrency:
11-
group: ${{ github.event_name == 'workflow_call' && format('release-ci-{0}', github.run_id) || format('ci-{0}', github.ref) }}
11+
group: ${{ github.event_name == 'workflow_call' && format('ci-{0}', github.run_id) || format('ci-{0}', github.ref) }}
1212
cancel-in-progress: true
1313

1414
jobs:
15+
gate:
16+
name: Gate
17+
runs-on: ubuntu-latest
18+
outputs:
19+
should_run: ${{ steps.eval.outputs.should_run }}
20+
steps:
21+
- id: eval
22+
run: |
23+
if [[ "${{ github.event_name }}" == "push" ]] || [[ "${{ github.event_name }}" == "workflow_call" ]]; then
24+
echo "should_run=true" >> "$GITHUB_OUTPUT"
25+
elif [[ "${{ github.event_name }}" == "pull_request" && "${{ github.event.pull_request.head.repo.full_name }}" != "${{ github.repository }}" ]]; then
26+
echo "should_run=true" >> "$GITHUB_OUTPUT"
27+
else
28+
echo "should_run=false" >> "$GITHUB_OUTPUT"
29+
fi
30+
1531
test:
1632
name: Test
33+
needs: gate
34+
if: needs.gate.outputs.should_run == 'true'
1735
runs-on: ubuntu-latest
1836

1937
steps:
@@ -28,6 +46,8 @@ jobs:
2846

2947
build:
3048
name: Build
49+
needs: gate
50+
if: needs.gate.outputs.should_run == 'true'
3151
runs-on: ubuntu-latest
3252

3353
steps:
@@ -42,6 +62,8 @@ jobs:
4262

4363
lint:
4464
name: Lint
65+
needs: gate
66+
if: needs.gate.outputs.should_run == 'true'
4567
runs-on: ubuntu-latest
4668

4769
steps:

.github/workflows/release.yml

Lines changed: 44 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,9 @@ on:
5555
RELEASE_DEPLOY_KEY:
5656
description: 'SSH deploy key with write access to the repository'
5757
required: true
58+
GCS_BUCKET:
59+
description: 'Google Cloud Storage bucket name for uploading docs'
60+
required: true
5861

5962
concurrency:
6063
group: release-${{ inputs.version_number }}-${{ inputs.release_type }}
@@ -143,7 +146,7 @@ jobs:
143146
run: |
144147
git config --global user.name 'Automated Release'
145148
git config --global user.email 'release-automation@bitmovin.com'
146-
git add package.json CHANGELOG.md
149+
git add package.json package-lock.json CHANGELOG.md
147150
git commit -m "[skip ci] Bump version to ${{ steps.version_number.outputs.version_number }}"
148151
git tag "${{ steps.version_number.outputs.tag_name }}"
149152
git push origin ${{ inputs.branch_name || github.ref_name }}
@@ -172,6 +175,42 @@ jobs:
172175
env:
173176
NPM_AUTH_TOKEN: ${{ secrets.NPM_AUTH_TOKEN }}
174177

178+
github_release:
179+
name: Create GitHub Release
180+
needs: [version_bump, release]
181+
if: inputs.release_type == 'final' && inputs.dry_run != true
182+
runs-on: ubuntu-latest
183+
steps:
184+
- name: Checkout
185+
uses: actions/checkout@v4
186+
with:
187+
ref: ${{ needs.version_bump.outputs.tag_name }}
188+
189+
- name: Extract changelog entry
190+
uses: actions/github-script@v6
191+
id: changelog
192+
with:
193+
script: |
194+
const fs = require('fs');
195+
const { parseChangelogEntry } = require('./.github/scripts/parseChangelogEntry.js');
196+
const version = '${{ needs.version_bump.outputs.version_number }}';
197+
const changelog = fs.readFileSync('CHANGELOG.md', 'utf8');
198+
let body;
199+
200+
try {
201+
body = parseChangelogEntry(changelog);
202+
} catch (error) {
203+
core.warning(`Failed to extract release notes for v${version}: ${error.message}`);
204+
body = `Release notes are not available for v${version}. Please check CHANGELOG.md in this tag.`;
205+
}
206+
207+
fs.writeFileSync('release_notes.md', body);
208+
209+
- name: Create GitHub Release
210+
run: gh release create "${{ needs.version_bump.outputs.tag_name }}" --title "v${{ needs.version_bump.outputs.version_number }}" --notes-file release_notes.md
211+
env:
212+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
213+
175214
upload_docs:
176215
name: Build and upload Documentation
177216
needs: [test, version_bump, release]
@@ -211,9 +250,9 @@ jobs:
211250

212251
notify_success:
213252
name: Notify Success
214-
needs: [test, version_bump, release, upload_docs]
253+
needs: [test, version_bump, release, upload_docs, github_release]
215254
runs-on: ubuntu-latest
216-
if: inputs.dry_run != true
255+
if: ${{ always() && inputs.dry_run != true && needs.test.result == 'success' && needs.version_bump.result == 'success' && needs.release.result == 'success' && needs.upload_docs.result == 'success' && (inputs.release_type != 'final' || needs.github_release.result == 'success') }}
217256
steps:
218257
- name: Checkout
219258
uses: actions/checkout@v4
@@ -226,8 +265,8 @@ jobs:
226265
handle_failure:
227266
name: Handle Failure
228267
runs-on: ubuntu-latest
229-
needs: [test, version_bump, release, upload_docs, notify_success]
230-
if: ${{ always() && inputs.dry_run != true && (needs.test.result == 'failure' || needs.version_bump.result == 'failure' || needs.release.result == 'failure' || needs.upload_docs.result == 'failure' || needs.notify_success.result == 'failure') }}
268+
needs: [test, version_bump, release, upload_docs, github_release, notify_success]
269+
if: ${{ always() && inputs.dry_run != true && (needs.test.result == 'failure' || needs.version_bump.result == 'failure' || needs.release.result == 'failure' || needs.upload_docs.result == 'failure' || needs.github_release.result == 'failure' || needs.notify_success.result == 'failure') }}
231270
steps:
232271
- name: Checkout
233272
uses: actions/checkout@v4
Lines changed: 37 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,46 +1,47 @@
1-
name: Trigger release on merge
2-
run-name: Starting release for ${{ github.actor }} PR merge
1+
name: Weekly Release Train
2+
run-name: Weekly release train ${{ github.event_name == 'workflow_dispatch' && ' (manual)' || '' }}
3+
34
on:
4-
pull_request_target:
5-
types:
6-
- closed
7-
branches:
8-
- develop
9-
- support/*
5+
schedule:
6+
- cron: '0 12 * * 4' # Every Thursday at 12:00 UTC
7+
workflow_dispatch:
108

119
concurrency:
12-
group: continuous-deployment-${{ github.event.pull_request.base.ref }}
10+
group: weekly-release-train
1311
cancel-in-progress: true
1412

1513
jobs:
16-
verify-changelog:
17-
name: Verify that CHANGELOG.md has been updated
18-
if: github.event.pull_request.merged == true
19-
outputs:
20-
HAS_CHANGELOG: ${{ steps.ensure-changelog.outputs.HAS_CHANGELOG }}
14+
check-unreleased:
15+
name: Check for unreleased changes
2116
runs-on: ubuntu-latest
17+
outputs:
18+
has_unreleased: ${{ steps.check.outputs.has_unreleased }}
2219
steps:
23-
- name: Checkout
24-
uses: actions/checkout@v4
20+
- name: Checkout
21+
uses: actions/checkout@v4
22+
23+
- name: Setup dependencies
24+
uses: ./.github/actions/setup-dependencies
25+
26+
- name: Check for unreleased changelog entries
27+
uses: actions/github-script@v6
28+
id: check
29+
with:
30+
script: |
31+
const { detectReleaseLevel } = require('./.github/scripts/detectReleaseLevel.js');
2532
26-
- name: Ensure Changelog
27-
id: ensure-changelog
28-
shell: bash
29-
run: |
30-
changes=$(gh pr view ${{github.event.pull_request.number}} --json files -q '.files[].path')
31-
if echo $changes | grep -q CHANGELOG.md; then
32-
echo "CHANGELOG.md has been updated"
33-
echo "HAS_CHANGELOG=true" >> $GITHUB_OUTPUT
34-
else
35-
echo "CHANGELOG.md has not been updated, skipping release"
36-
fi
37-
env:
38-
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
33+
try {
34+
detectReleaseLevel(core);
35+
core.setOutput('has_unreleased', 'true');
36+
} catch (error) {
37+
core.info(`No unreleased changes found, skipping release: ${error.message}`);
38+
core.setOutput('has_unreleased', 'false');
39+
}
3940
4041
prepare-version:
4142
name: Detect and build the version number for the release
42-
needs: verify-changelog
43-
if: ${{ needs.verify-changelog.outputs.HAS_CHANGELOG }}
43+
needs: check-unreleased
44+
if: needs.check-unreleased.outputs.has_unreleased == 'true'
4445
outputs:
4546
version_number: ${{ steps.define-release-version.outputs.version_number }}
4647
runs-on: ubuntu-latest
@@ -65,7 +66,7 @@ jobs:
6566
with:
6667
script: |
6768
const { detectReleaseLevel } = require('./.github/scripts/detectReleaseLevel.js');
68-
69+
6970
try {
7071
const releaseLevel = detectReleaseLevel(core);
7172
core.setOutput('release_level', releaseLevel);
@@ -82,7 +83,7 @@ jobs:
8283
const { defineReleaseVersion } = require('./.github/scripts/defineVersion.js');
8384
const releaseLevel = '${{ steps.detect-release-level.outputs.release_level }}';
8485
const currentVersion = '${{ steps.define-package-json-version.outputs.packageJsonVersion }}';
85-
86+
8687
const result = defineReleaseVersion({core}, releaseLevel, currentVersion);
8788
core.setOutput('version_number', result.full);
8889
@@ -93,8 +94,10 @@ jobs:
9394
with:
9495
version_number: ${{ needs.prepare-version.outputs.version_number }}
9596
release_type: final
96-
branch_name: ${{ github.event.pull_request.base.ref }}
97+
branch_name: develop
9798
secrets:
9899
NPM_AUTH_TOKEN: ${{ secrets.NPM_AUTH_TOKEN }}
99100
GCS_CREDENTIALS: ${{ secrets.GCS_CREDENTIALS }}
100101
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
102+
RELEASE_DEPLOY_KEY: ${{ secrets.RELEASE_DEPLOY_KEY }}
103+
GCS_BUCKET: ${{ secrets.GCS_BUCKET }}

0 commit comments

Comments
 (0)