diff --git a/.github/scripts/defineVersion.js b/.github/scripts/defineVersion.js new file mode 100644 index 000000000..62bb8ef20 --- /dev/null +++ b/.github/scripts/defineVersion.js @@ -0,0 +1,29 @@ +const semver = require('semver'); + +function getPlayerUiVersion(versionInput) { + const playerUiVersion = semver.valid(versionInput); + if (!playerUiVersion) { + console.error(`${versionInput} is not a valid semver`); + process.exit(1); + } + + return { + major: semver.major(playerUiVersion), + minor: semver.minor(playerUiVersion), + patch: semver.patch(playerUiVersion), + prereleaseLabels: semver.prerelease(playerUiVersion), + full: playerUiVersion, + }; +} + +function defineReleaseVersion({ core }, targetReleaseLevel, givenVersion) { + core.info(`Defining new release version for level ${targetReleaseLevel} and version ${givenVersion}`); + + const newVersion = semver.inc(givenVersion, targetReleaseLevel); + + const parsedPlayerVersion = getPlayerUiVersion(newVersion); + core.info(`Using release version ${parsedPlayerVersion.full}`); + return parsedPlayerVersion; +} + +module.exports.defineReleaseVersion = defineReleaseVersion; diff --git a/.github/scripts/updateChangelog.js b/.github/scripts/updateChangelog.js new file mode 100644 index 000000000..8a34b0e5e --- /dev/null +++ b/.github/scripts/updateChangelog.js @@ -0,0 +1,17 @@ +/** + * Updates the changelog by replacing the changelog header with the correct version + * + * @param {string} changelogString the content of the changelog file + * @param {string} version the player version to be released + * @param {string} releaseDate the release date to be written to the changelog + */ +function updateChangeLog(changelogString, version, releaseDate) { + const optionalBetaOrRc = '(-rc.d+)?(-(b|beta).d+)?'; + const changelogVersionRegExp = new RegExp( + `\\[(development|develop|unreleased|${version})${optionalBetaOrRc}.*`, + 'gi', + ); + return changelogString.replace(changelogVersionRegExp, `[${version}] - ${releaseDate}`); + } + + module.exports.updateChangeLog = updateChangeLog; diff --git a/.github/workflows/tag-release-version.yml b/.github/workflows/tag-release-version.yml new file mode 100644 index 000000000..0c46294a3 --- /dev/null +++ b/.github/workflows/tag-release-version.yml @@ -0,0 +1,64 @@ +name: Trigger release on merge +run-name: Starting release for ${{ github.actor }} PR merge +on: + pull_request: + types: + - closed + branches: + - develop + +jobs: + trigger-ui-release: + if: github.event.pull_request.merged == true + runs-on: ubuntu-latest + steps: + - name: Install dependencies + run: npm ci + + - name: Read package.json version + uses: actions/github-script@v6 + id: define-package-json-version + with: + script: | + const { version } = require('./package.json') + core.info(`performing a minor release for existing version ${version}`) + core.setOutput('packageJsonVersion', version) + + - name: Define release version + uses: actions/github-script@v6 + id: define-release-version + with: + script: | + const { defineReleaseVersion } = require('./.github/scripts/defineVersion.js') + return defineReleaseVersion({core}, 'minor', undefined, "${{ steps.define-package-json-version.outputs.packageJsonVersion }}" ) + + - name: Bump package.json version + run: | + git config --global user.name 'Automated Release' + git config --global user.email 'release-automation@bitmovin.com' + npm version "${{ fromJson(steps.define-release-version.outputs.result).full }}" + + - name: Update Changelog + uses: actions/github-script@v6 + with: + script: | + const fs = require('fs'); + const { updateChangeLog } = require('./.github/scripts/updateChangelog.js') + + const stableVersion = '${{ fromJson(steps.define-release-version.outputs.result).full }}'.split('-')[0] + const releaseDate = new Date().toISOString().split('T')[0] + + const data = fs.readFileSync('./CHANGELOG.md',{encoding:'utf8', flag:'r'}); + + core.info(`Updating ${stableVersion} with date ${releaseDate} in Changelog`); + + const changelogFileContents = updateChangeLog(data, stableVersion, releaseDate); + + fs.writeFileSync('./CHANGELOG.md', changelogFileContents, 'utf-8'); + + - name: Push changes + run: | + git add . + git commit -m "Add release date to changelog" + git push origin develop + git push origin --tags diff --git a/CHANGELOG.md b/CHANGELOG.md index 8debf7fe6..96398d496 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,9 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ## [develop] +### Added +- Automate release on every PR merge to develop + ## [3.52.2] - 2023-11-23 ### Fixed diff --git a/package-lock.json b/package-lock.json index 5857c7c5c..5e1fcebdd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6,7 +6,7 @@ "packages": { "": { "name": "bitmovin-player-ui", - "version": "3.51.0", + "version": "3.52.2", "license": "MIT", "devDependencies": { "@inrupt/jest-jsdom-polyfills": "^1.6.0", @@ -35,6 +35,7 @@ "merge2": "^1.4.1", "postcss-svg": "^3.0.0", "sass": "^1.59.3", + "semver": "^7.5.4", "stream-combiner2": "^1.1.1", "ts-jest": "^29.0.5", "tsify": "^5.0.4", @@ -12258,21 +12259,6 @@ "node": ">=7.0.0" } }, - "node_modules/jest-snapshot/node_modules/semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/jest-util": { "version": "29.5.0", "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.5.0.tgz", @@ -13750,6 +13736,15 @@ "validate-npm-package-license": "^3.0.1" } }, + "node_modules/normalize-package-data/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, "node_modules/normalize-path": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", @@ -16470,12 +16465,18 @@ "dev": true }, "node_modules/semver": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.3.0.tgz", - "integrity": "sha1-myzl094C0XxgEq0yaqa00M9U+U8=", + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, "bin": { - "semver": "bin/semver" + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" } }, "node_modules/semver-greatest-satisfied-range": { @@ -18205,21 +18206,6 @@ "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==", "dev": true }, - "node_modules/ts-jest/node_modules/semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/tsconfig": { "version": "5.0.3", "resolved": "https://registry.npmjs.org/tsconfig/-/tsconfig-5.0.3.tgz", @@ -18348,6 +18334,15 @@ "node": ">=4" } }, + "node_modules/tslint/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, "node_modules/tslint/node_modules/supports-color": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", @@ -29351,15 +29346,6 @@ "requires": { "color-name": "~1.1.4" } - }, - "semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", - "dev": true, - "requires": { - "lru-cache": "^6.0.0" - } } } }, @@ -30525,6 +30511,14 @@ "resolve": "^1.10.0", "semver": "2 || 3 || 4 || 5", "validate-npm-package-license": "^3.0.1" + }, + "dependencies": { + "semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true + } } }, "normalize-path": { @@ -32577,10 +32571,13 @@ } }, "semver": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.3.0.tgz", - "integrity": "sha1-myzl094C0XxgEq0yaqa00M9U+U8=", - "dev": true + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } }, "semver-greatest-satisfied-range": { "version": "1.1.0", @@ -33920,15 +33917,6 @@ "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==", "dev": true - }, - "semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", - "dev": true, - "requires": { - "lru-cache": "^6.0.0" - } } } }, @@ -34033,6 +34021,12 @@ "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", "dev": true }, + "semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true + }, "supports-color": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", diff --git a/package.json b/package.json index b45312582..d952922ee 100644 --- a/package.json +++ b/package.json @@ -49,6 +49,7 @@ "merge2": "^1.4.1", "postcss-svg": "^3.0.0", "sass": "^1.59.3", + "semver": "^7.5.4", "stream-combiner2": "^1.1.1", "ts-jest": "^29.0.5", "tsify": "^5.0.4", @@ -59,4 +60,4 @@ "watchify": "^4.0.0", "yargs": "^17.7.1" } -} \ No newline at end of file +} diff --git a/spec/release/defineVersion.spec.ts b/spec/release/defineVersion.spec.ts new file mode 100644 index 000000000..2ca1fc6aa --- /dev/null +++ b/spec/release/defineVersion.spec.ts @@ -0,0 +1,26 @@ +const { defineReleaseVersion } = require('../../.github/scripts/defineVersion'); + +describe('defineReleaseVersion', () => { + test.each` + existingVersion | desiredReleaseLevel | expectedVersion + ${'1.0.0'} | ${'major'} | ${'2.0.0'} + ${'1.0.0'} | ${'minor'} | ${'1.1.0'} + ${'1.1.0'} | ${'minor'} | ${'1.2.0'} + ${'1.0.0'} | ${'patch'} | ${'1.0.1'} + ${'1.1.0'} | ${'patch'} | ${'1.1.1'} + ${'1.0.4'} | ${'patch'} | ${'1.0.5'} + ${'1.0.0'} | ${'minor'} | ${'1.1.0'} + ${'1.0.0'} | ${'minor'} | ${'1.1.0'} + ${'1.0.0'} | ${'major'} | ${'2.0.0'} + ${'1.5.0'} | ${'major'} | ${'2.0.0'} + ${'2.0.0'} | ${'major'} | ${'3.0.0'} + `( + 'should return version $expectedVersion with version $existingVersion and $desiredReleaseLevel release level', + ({ existingVersion, desiredReleaseLevel, expectedVersion }) => { + const core = { info() {} }; + const result = defineReleaseVersion({ core }, desiredReleaseLevel, existingVersion); + + expect(result.full).toEqual(expectedVersion); + }, + ); +});