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
5,908 changes: 0 additions & 5,908 deletions .github/release/package-lock.json

This file was deleted.

9 changes: 0 additions & 9 deletions .github/release/package.json

This file was deleted.

34 changes: 0 additions & 34 deletions .github/release/releaserc.json

This file was deleted.

219 changes: 207 additions & 12 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -1,12 +1,34 @@
name: Manual Release
name: Create Release

on:
workflow_dispatch:
inputs:
previous_release:
description: 'Existing tag to release from'
required: true
type: string
bump:
description: 'Version bump -- required when Previous Release is a stable tag; leave "none" when Previous Release is an RC (to continue its RC series or promote it to stable)'
required: true
type: choice
options:
- none
- patch
- minor
- major
create_rc:
description: 'Create RC tag (Note: unchecked = stable release / promote an existing RC to stable)'
required: false
type: boolean
default: false

jobs:
release:
if: github.ref_name == 'main' || endsWith(github.ref_name, '-rc') || endsWith(github.ref_name, '.x-maintenance')
if: github.ref_type == 'branch' && (github.ref_name == 'main' || endsWith(github.ref_name, '.rc') || endsWith(github.ref_name, '.x-maintenance'))
runs-on: ubuntu-latest
concurrency:
group: release
cancel-in-progress: false
permissions:
contents: write
issues: write
Expand All @@ -17,17 +39,190 @@ jobs:
uses: actions/checkout@v4
with:
fetch-depth: 0
token: ${{ secrets.SEMANTIC_RELEASE_TOKEN }}
ssh-key: ${{ secrets.RDKCM_DEPLOY_KEY }}

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 'lts/*'
- name: Validate release branch
shell: bash
run: |
branch="${GITHUB_REF_NAME}"
case "$branch" in
main|*.rc|*.*.x-maintenance)
echo "Release allowed from branch: $branch"
;;
*)
echo "Release blocked: branch '$branch' is not allowed. Use 'main', a '*.rc' branch, or a '*.*.x-maintenance' branch."
exit 1
;;
esac

- name: Compute next version
id: version
env:
PREV: ${{ inputs.previous_release }}
BUMP: ${{ inputs.bump }}
CREATE_RC: ${{ inputs.create_rc }}
shell: bash
run: |
git fetch --tags --force origin

if ! git tag --list "$PREV" | grep -qxF "$PREV"; then
echo "ERROR: '${PREV}' is not an existing tag on this repo. Check Previous Release for typos."
exit 1
fi

# Bump a vX.Y.Z string by the requested level
bump_stable() {
local ver="${1#v}" major minor patch
IFS='.' read -r major minor patch <<< "$ver"
case "$2" in
major) echo "v$((major+1)).0.0" ;;
minor) echo "v${major}.$((minor+1)).0" ;;
patch) echo "v${major}.${minor}.$((patch+1))" ;;
esac
}

is_rc=false
is_promotion=false
next=""

if [[ "$PREV" =~ ^v[0-9]+\.[0-9]+\.[0-9]+\.rc[0-9]+$ ]]; then
# Previous release is itself an RC -- no bump makes sense here;
# either continue its RC series or promote it straight to stable.
if [ "$BUMP" != "none" ]; then
echo "ERROR: A version bump isn't supported when Previous Release is an RC tag (${PREV}). Select its underlying stable tag instead."
exit 1
fi
base_stable="${PREV%%.rc*}"
if [ "$CREATE_RC" = "true" ]; then
rc_num="${PREV##*.rc}"
next="${base_stable}.rc$((rc_num + 1))"
is_rc=true
else
next="$base_stable"
is_promotion=true
fi

elif [[ "$PREV" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
# Previous release is a stable tag -- a bump is required to know
# what comes next.
if [ "$BUMP" = "none" ]; then
echo "ERROR: Select a version bump to release from stable tag ${PREV}."
exit 1
fi
next_stable="$(bump_stable "$PREV" "$BUMP")"
if [ "$CREATE_RC" = "true" ]; then
next="${next_stable}.rc1"
is_rc=true
else
next="$next_stable"
fi

else
echo "ERROR: '${PREV}' doesn't look like a release tag (expected vX.Y.Z or vX.Y.Z.rcN)."
exit 1
fi

- name: Install release deps
run: npm ci --prefix .github/release
echo "baseline=$PREV" | tee -a "$GITHUB_OUTPUT"
echo "next=$next" | tee -a "$GITHUB_OUTPUT"
echo "is_rc=$is_rc" | tee -a "$GITHUB_OUTPUT"
echo "is_promotion=$is_promotion" | tee -a "$GITHUB_OUTPUT"

- name: Validate release has changes
env:
BASELINE: ${{ steps.version.outputs.baseline }}
IS_PROMOTION: ${{ steps.version.outputs.is_promotion }}
shell: bash
run: |
if [ "$IS_PROMOTION" = "true" ]; then
if ! git merge-base --is-ancestor "${BASELINE}" HEAD; then
echo "ERROR: ${BASELINE} is not an ancestor of HEAD; select a descendant commit from this branch before promoting to stable."
exit 1
fi
echo "Promoting ${BASELINE} to stable release; current HEAD is a descendant."
exit 0
fi
if ! git merge-base --is-ancestor "${BASELINE}" HEAD; then
echo "ERROR: ${BASELINE} is not an ancestor of HEAD; select a Previous Release tag from this branch."
exit 1
fi
count="$(git rev-list --count "${BASELINE}..HEAD")"
if [ "$count" -eq 0 ]; then
echo "ERROR: No new commits since ${BASELINE}; refusing to create a duplicate release."
exit 1
fi

- name: Validate CHANGELOG
env:
NEXT: ${{ steps.version.outputs.next }}
shell: bash
run: |
if grep -q '^## \[Unreleased\]' CHANGELOG.md; then
echo "ERROR: CHANGELOG.md has an [Unreleased] section. Update it before releasing."
exit 1
fi
version="${NEXT#v}"
version="${version%%.rc*}"
top="$(awk '/^## \[[^]]+\]/ { sub(/^## \[/, ""); sub(/\].*$/, ""); print; exit }' CHANGELOG.md)"
if [ -z "$top" ] || [ "$top" != "$version" ]; then
echo "ERROR: Top CHANGELOG.md entry (${top:-<none>}) does not match version ${version}. Move the ${version} entry to the top."
exit 1
fi

- name: Create tag
env:
TAG: ${{ steps.version.outputs.next }}
GH_TOKEN: ${{ secrets.SEMANTIC_RELEASE_TOKEN }}
shell: bash
run: |
if git ls-remote --exit-code --tags origin "refs/tags/${TAG}" >/dev/null 2>&1; then
git fetch --force origin "refs/tags/${TAG}:refs/tags/${TAG}"
if [ "$(git rev-parse "refs/tags/${TAG}^{commit}")" != "$(git rev-parse HEAD)" ]; then
echo "ERROR: Tag ${TAG} already exists on origin but does not point to the current HEAD; refusing to overwrite its release assets."
exit 1
fi
echo "Tag ${TAG} already exists at the current HEAD; resuming the release."
exit 0
fi
# Identity is just for the annotated tag's metadata -- SEMANTIC_RELEASE_TOKEN is
# fine for this lookup, it doesn't touch ref creation.
author_login="$(gh api user --jq '.login')"
author_name="$(gh api user --jq '.name // .login')"
git config user.name "$author_name"
git config user.email "${author_login}@users.noreply.github.com"
git tag -a "${TAG}" -m "Release ${TAG}"
git push origin "${TAG}"

- name: Build release archive
id: asset
env:
VERSION: ${{ steps.version.outputs.next }}
shell: bash
run: |
bare="${VERSION#v}"
./.github/scripts/mk-release-package.sh \
--version "${bare}" \
--package firebolt-cpp-client
awk '/^## / { if (s) exit; s=1 } s{ print }' CHANGELOG.md > release_notes.md
echo "archive=build/firebolt-cpp-client-${bare}.tar.gz" >> "$GITHUB_OUTPUT"

- name: Run semantic-release
run: npm --prefix .github/release exec -- semantic-release --extends ./.github/release/releaserc.json
- name: Create GitHub release
env:
GITHUB_TOKEN: ${{ secrets.SEMANTIC_RELEASE_TOKEN }}
GH_TOKEN: ${{ secrets.SEMANTIC_RELEASE_TOKEN }}
TAG: ${{ steps.version.outputs.next }}
IS_RC: ${{ steps.version.outputs.is_rc }}
ARCHIVE: ${{ steps.asset.outputs.archive }}
shell: bash
run: |
release_flags=()
[ "$IS_RC" = "true" ] && release_flags+=(--prerelease)
if gh release view "$TAG" >/dev/null 2>&1; then
gh release upload "$TAG" "$ARCHIVE" --clobber
else
# The tag already exists (pushed in "Create tag"), so this only
# creates the release object against it.
gh release create "$TAG" \
--title "$TAG" \
--notes-file release_notes.md \
"${release_flags[@]}" \
"$ARCHIVE"
fi
26 changes: 25 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,33 @@
## [0.7.0](https://github.com/rdkcentral/firebolt-cpp-client/compare/v0.6.4...v0.7.0)

### Added
- New APIs
- `Localization.timeZone` getter and `onTimeZoneChanged` event
- `Device.dolbyAtmosExperienceAvailable` getter and `onDolbyAtmosExperienceAvailableChanged` event
- `Device.osName`, `Device.osVersion`, and `Device.firmware`
- `SpeechSynthesis` (`speak`, `cancel`, `pause`, `resume`, `voices`, `subscribeOnVoicesChanged`, `onUtteranceEvent`)
- `VideoOutput` implementation

### Changed
- **Breaking**: `Stats.memoryUsage` now returns the value in bytes
- **Breaking**: `Discovery.watchedV2` return type changed to `Result<void>`

## [0.6.4](https://github.com/rdkcentral/firebolt-cpp-client/compare/v0.6.3...v0.6.4)

### Changed
- **Breaking**: `Actions.intent()` return type changed from `Result<std::string>` to `Result<Intent>`
- **Breaking**: `subscribeOnIntent` / `subscribeOnIntentChanged` callback parameter changed from `const std::string&` to `const Intent&`

### Added
- `Actions.start(const IntentData& intent, std::optional<std::string> handlerAppId)` — new API per Firebolt 9 spec
- New public types: `Firebolt::Actions::Intent`, `IntentData`, `IntentContext`

## [0.6.3](https://github.com/rdkcentral/firebolt-cpp-client/compare/0.6.2...v0.6.3)

### Fixed
- `Actions.intent` and `Actions.onIntent` now correctly handle a JSON object payload (`{"intent":"...","intentId":N}`) sent by the Firebolt backend. Previously the client failed to parse the response because it expected a plain string.

## [0.6.2](https://github.com/rdkcentral/firebolt-cpp-client/compare/v0.6.1...v0.6.2)
## [0.6.2](https://github.com/rdkcentral/firebolt-cpp-client/compare/v0.6.1...0.6.2)

### Fixed
- `Discovery.watched` now returns `Result<bool>` again (reverts the `Result<void>` change introduced in v0.6.0).
Expand Down
Loading
Loading