diff --git a/.github/workflows/publish-deb.yml b/.github/workflows/publish-deb.yml index 55ce3dc..fab38e1 100644 --- a/.github/workflows/publish-deb.yml +++ b/.github/workflows/publish-deb.yml @@ -1,42 +1,100 @@ name: Build and Upload Debian Package on: + workflow_dispatch: + inputs: + release_type: + description: "Release type" + required: true + type: choice + options: + - stable + - beta + default: stable push: branches: - master - release: - types: [released] jobs: + calculate-version: + name: Calculate Version + runs-on: ubuntu-latest + outputs: + version: ${{ steps.calver.outputs.version }} + is_beta: ${{ steps.calver.outputs.is_beta }} + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Calculate CalVer version + id: calver + env: + RELEASE_TYPE: ${{ github.event.inputs.release_type || 'beta' }} + run: | + YEAR=$(date -u +"%Y") + MONTH=$(date -u +"%-m") + IS_BETA=$([[ "$RELEASE_TYPE" == "beta" ]] && echo "true" || echo "false") + + PREFIX="v${YEAR}.${MONTH}" + + if [ "$IS_BETA" == "true" ]; then + LATEST_BETA=$(git tag -l "${PREFIX}.*-beta.*" | sed -E "s/.*-beta\.([0-9]+)/\1/" | sort -n | tail -1) + if [ -z "$LATEST_BETA" ]; then + BETA_NUM=1 + else + BETA_NUM=$((LATEST_BETA + 1)) + fi + LATEST_STABLE=$(git tag -l "${PREFIX}.*" | grep -v beta | sed "s/${PREFIX}\.//" | sort -n | tail -1) + PATCH=${LATEST_STABLE:-0} + NEXT_PATCH=$((PATCH + 1)) + VERSION="${YEAR}.${MONTH}.${NEXT_PATCH}-beta.${BETA_NUM}" + else + LATEST_PATCH=$(git tag -l "${PREFIX}.*" | grep -v beta | sed "s/${PREFIX}\.//" | sort -n | tail -1) + if [ -z "$LATEST_PATCH" ]; then + PATCH=0 + else + PATCH=$((LATEST_PATCH + 1)) + fi + VERSION="${YEAR}.${MONTH}.${PATCH}" + fi + + echo "version=${VERSION}" >> $GITHUB_OUTPUT + echo "is_beta=${IS_BETA}" >> $GITHUB_OUTPUT + echo "โœ… Version: ${VERSION} (Beta: ${IS_BETA})" + deb: + name: Build Debian Package + needs: calculate-version runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 + with: + submodules: recursive + - run: sudo apt update && sudo apt install -y qemu-user-static binfmt-support + - uses: docker/build-push-action@v3 with: context: . outputs: build platforms: linux/arm64 - - uses: paulhatch/semantic-version@v5.4.0 - id: semantic - with: - tag_prefix: "" - version_format: ${{ github.event_name == 'release' && '${major}.${minor}.${patch}' || '${major}.${minor}.${patch}-prerelease${increment}' }} + - uses: jiro4989/build-deb-action@v4 id: deb with: - package: irl-belacoder + package: ceracoder package_root: ./build - maintainer: IRL Software + maintainer: CERALIVE desc: "Live video encoder with dynamic bitrate control and SRT support" - version: ${{ steps.semantic.outputs.version }} - #depends: "openssl, libssl-dev" - homepage: "https://irl.software" + version: ${{ needs.calculate-version.outputs.version }} + homepage: "https://github.com/CERALIVE/ceracoder" arch: "arm64" - section: "unknown" + section: "video" compress_type: zstd + - uses: actions/upload-artifact@v4 with: - name: belacoder-arm64.deb + name: ceracoder-arm64.deb path: ${{ steps.deb.outputs.file_name }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 4ee05d7..e6b0c96 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,9 +1,24 @@ name: Build and Release Ceracoder on: - release: - types: [published] workflow_dispatch: + inputs: + release_type: + description: "Release type" + required: true + type: choice + options: + - stable + - beta + default: stable + release_notes: + description: "Release notes (what changed in this release)" + required: false + type: string + force_version: + description: "Override auto-detected version (optional, e.g., 2026.1.0)" + required: false + type: string permissions: contents: write @@ -15,6 +30,7 @@ jobs: outputs: version: ${{ steps.calver.outputs.version }} version_tag: ${{ steps.calver.outputs.version_tag }} + is_beta: ${{ steps.calver.outputs.is_beta }} steps: - name: Checkout code @@ -22,32 +38,76 @@ jobs: with: fetch-depth: 0 - - name: Calculate calendar version (YYYY.M.patch format like CeraUI) + - name: Calculate CalVer version with beta support id: calver + env: + RELEASE_TYPE: ${{ github.event.inputs.release_type }} + FORCE_VERSION: ${{ github.event.inputs.force_version }} run: | # Get current year and month (no leading zeros for month) YEAR=$(date -u +"%Y") MONTH=$(date -u +"%-m") # %-m removes leading zero + IS_BETA=$([[ "$RELEASE_TYPE" == "beta" ]] && echo "true" || echo "false") - # Find the latest tag for this year.month - LATEST_TAG=$(git tag -l "v${YEAR}.${MONTH}.*" | sort -V | tail -n 1) - - if [ -z "$LATEST_TAG" ]; then - # No tags for this year.month yet, start at .0 - PATCH=0 + # Check if force_version is provided + if [ -n "$FORCE_VERSION" ]; then + VERSION="$FORCE_VERSION" + echo "๐Ÿ“Œ Using forced version: $VERSION" else - # Extract patch number and increment - PATCH=$(echo "$LATEST_TAG" | sed -E "s/v${YEAR}\.${MONTH}\.([0-9]+).*/\1/") - PATCH=$((PATCH + 1)) + # Find existing tags for this year.month + PREFIX="v${YEAR}.${MONTH}" + + if [ "$IS_BETA" == "true" ]; then + # For beta: find highest beta number for this month + LATEST_BETA=$(git tag -l "${PREFIX}.*-beta.*" | sed -E "s/.*-beta\.([0-9]+)/\1/" | sort -n | tail -1) + + if [ -z "$LATEST_BETA" ]; then + BETA_NUM=1 + echo "๐Ÿงช First beta of ${YEAR}.${MONTH}" + else + BETA_NUM=$((LATEST_BETA + 1)) + echo "๐Ÿ”„ Incrementing beta: ${LATEST_BETA} โ†’ ${BETA_NUM}" + fi + + # Get the base patch (latest stable or 0) + LATEST_STABLE=$(git tag -l "${PREFIX}.*" | grep -v beta | sed "s/${PREFIX}\.//" | sort -n | tail -1) + PATCH=${LATEST_STABLE:-0} + NEXT_PATCH=$((PATCH + 1)) + + VERSION="${YEAR}.${MONTH}.${NEXT_PATCH}-beta.${BETA_NUM}" + else + # For stable: find highest patch number (excluding betas) + LATEST_PATCH=$(git tag -l "${PREFIX}.*" | grep -v beta | sed "s/${PREFIX}\.//" | sort -n | tail -1) + + if [ -z "$LATEST_PATCH" ]; then + PATCH=0 + echo "๐Ÿ“… First release of ${YEAR}.${MONTH}" + else + PATCH=$((LATEST_PATCH + 1)) + echo "๐Ÿ”„ Incrementing patch: ${LATEST_PATCH} โ†’ ${PATCH}" + fi + + VERSION="${YEAR}.${MONTH}.${PATCH}" + fi fi - VERSION="${YEAR}.${MONTH}.${PATCH}" + VERSION_TAG="v${VERSION}" echo "version=${VERSION}" >> $GITHUB_OUTPUT - echo "version_tag=v${VERSION}" >> $GITHUB_OUTPUT + echo "version_tag=${VERSION_TAG}" >> $GITHUB_OUTPUT + echo "is_beta=${IS_BETA}" >> $GITHUB_OUTPUT - echo "๐Ÿ“… Calculated CalVer version: ${VERSION} (YYYY.M.patch format)" - echo "๐Ÿท๏ธ Version tag: v${VERSION}" + echo "โœ… Next version: ${VERSION}" + echo "๐Ÿท๏ธ Tag: ${VERSION_TAG}" + echo "๐Ÿงช Beta: ${IS_BETA}" + + - name: Version Summary + run: | + echo "## ๐Ÿท๏ธ Version Calculated" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "**Version:** \`${{ steps.calver.outputs.version }}\`" >> $GITHUB_STEP_SUMMARY + echo "**Tag:** \`${{ steps.calver.outputs.version_tag }}\`" >> $GITHUB_STEP_SUMMARY + echo "**Type:** ${{ steps.calver.outputs.is_beta == 'true' && '๐Ÿงช Beta' || 'โœ… Stable' }}" >> $GITHUB_STEP_SUMMARY build-release: name: Build ${{ matrix.arch }} @@ -107,11 +167,12 @@ jobs: name: Create Release needs: [version, build-release] runs-on: ubuntu-latest - if: github.event_name == 'workflow_dispatch' steps: - name: Checkout code uses: actions/checkout@v4 + with: + fetch-depth: 0 - name: Download all artifacts uses: actions/download-artifact@v4 @@ -124,66 +185,99 @@ jobs: find release-artifacts -type f \( -name '*.tar.gz' -o -name '*.sha256' \) -exec cp {} release-files/ \; ls -lh release-files/ + - name: Generate release body + env: + VERSION: ${{ needs.version.outputs.version }} + VERSION_TAG: ${{ needs.version.outputs.version_tag }} + IS_BETA: ${{ needs.version.outputs.is_beta }} + RELEASE_NOTES: ${{ github.event.inputs.release_notes }} + run: | + # Get the previous tag for changelog + PREV_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "") + + # Generate changelog + if [ -n "$PREV_TAG" ]; then + CHANGELOG_HEADER="Changes since ${PREV_TAG}:" + CHANGELOG=$(git log ${PREV_TAG}..HEAD --pretty=format:"- %s" --no-merges | head -20) + else + CHANGELOG_HEADER="Recent commits:" + CHANGELOG=$(git log --pretty=format:"- %s" --no-merges -20) + fi + + DATE=$(date -u +"%Y-%m-%d") + + # Build release body + { + echo "# Ceracoder ${VERSION_TAG}" + echo "" + if [ "$IS_BETA" == "true" ]; then + echo "> โš ๏ธ **This is a beta release.** It may contain bugs or incomplete features. Use in production at your own risk." + echo "" + fi + echo "**Release Date:** ${DATE}" + echo "" + echo "## ๐Ÿ“ฆ Downloads" + echo "" + echo "| Architecture | File |" + echo "|--------------|------|" + echo "| x86_64 (amd64) | \`ceracoder-linux-x86_64-v${VERSION}.tar.gz\` |" + echo "| ARM64 | \`ceracoder-linux-arm64-v${VERSION}.tar.gz\` |" + echo "" + echo "SHA256 checksums are provided for verification." + echo "" + echo "## ๐Ÿ“ Installation" + echo "" + echo "\`\`\`bash" + echo "# Download and extract" + echo "tar -xzf ceracoder-linux-*.tar.gz" + echo "sudo mv ceracoder /usr/local/bin/" + echo "" + echo "# Verify installation" + echo "ceracoder -v" + echo "\`\`\`" + echo "" + echo "## ๐Ÿ“‹ Release Notes" + echo "" + echo "${RELEASE_NOTES:-No release notes provided.}" + echo "" + echo "## ๐Ÿ”„ What's Changed" + echo "" + echo "${CHANGELOG_HEADER}" + echo "" + echo "${CHANGELOG}" + echo "" + echo "---" + echo "" + echo "**Ceracoder** is a fork of [irlserver/belacoder](https://github.com/irlserver/belacoder), itself a fork of [BELABOX/belacoder](https://github.com/BELABOX/belacoder)." + echo "" + echo "๐Ÿค– Built with GitHub Actions using CalVer (YYYY.M.patch) versioning" + } > release-body.md + + echo "๐Ÿ“„ Generated release body:" + cat release-body.md + - name: Create Release uses: softprops/action-gh-release@v1 with: - tag_name: v${{ needs.version.outputs.version }} - name: Ceracoder v${{ needs.version.outputs.version }} + tag_name: ${{ needs.version.outputs.version_tag }} + name: Ceracoder ${{ needs.version.outputs.version_tag }}${{ needs.version.outputs.is_beta == 'true' && ' (Beta)' || '' }} + body_path: release-body.md files: release-files/* - body: | - ## Ceracoder v${{ needs.version.outputs.version }} - - ### Downloads - - - **Linux x86_64**: `ceracoder-linux-x86_64-v${{ needs.version.outputs.version }}.tar.gz` - - **Linux ARM64**: `ceracoder-linux-arm64-v${{ needs.version.outputs.version }}.tar.gz` - - SHA256 checksums are provided for verification. - - ### Installation - - ```bash - # Download and extract - tar -xzf ceracoder-linux-*.tar.gz - sudo mv ceracoder /usr/local/bin/ - - # Verify installation - ceracoder -v - ``` - - ### What's Changed - - See commit history for details. - - --- - - **Ceracoder** is a fork of [irlserver/belacoder](https://github.com/irlserver/belacoder), itself a fork of [BELABOX/belacoder](https://github.com/BELABOX/belacoder). draft: false - prerelease: false + prerelease: ${{ needs.version.outputs.is_beta == 'true' }} env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - upload-to-existing-release: - name: Upload to Existing Release - needs: [version, build-release] - runs-on: ubuntu-latest - if: github.event_name == 'release' - - steps: - - name: Download all artifacts - uses: actions/download-artifact@v4 - with: - path: release-artifacts - - name: Prepare release assets + - name: Release Summary run: | - mkdir -p release-files - find release-artifacts -type f \( -name '*.tar.gz' -o -name '*.sha256' \) -exec cp {} release-files/ \; - ls -lh release-files/ - - - name: Upload to Release - uses: softprops/action-gh-release@v1 - with: - files: release-files/* - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + echo "## ๐ŸŽ‰ Release Created!" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "**Version:** \`${{ needs.version.outputs.version }}\`" >> $GITHUB_STEP_SUMMARY + echo "**Tag:** \`${{ needs.version.outputs.version_tag }}\`" >> $GITHUB_STEP_SUMMARY + echo "**Type:** ${{ needs.version.outputs.is_beta == 'true' && '๐Ÿงช Beta (Pre-release)' || 'โœ… Stable' }}" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "### Assets Uploaded:" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + ls -1 release-files/ | while read f; do echo "- \`$f\`" >> $GITHUB_STEP_SUMMARY; done + echo "" >> $GITHUB_STEP_SUMMARY + echo "๐Ÿ”— [View Release](https://github.com/${{ github.repository }}/releases/tag/${{ needs.version.outputs.version_tag }})" >> $GITHUB_STEP_SUMMARY diff --git a/README.md b/README.md index 82cafd8..61d239a 100644 --- a/README.md +++ b/README.md @@ -317,6 +317,7 @@ Documentation * [Architecture](docs/architecture.md) โ€“ System overview and dataflow * [Dependencies](docs/dependencies.md) โ€“ Full dependency list with versions * [Bitrate Control](docs/bitrate-control.md) โ€“ Adaptive bitrate algorithm details +* [Versioning](docs/versioning.md) โ€“ CalVer versioning scheme with beta release support License diff --git a/docs/versioning.md b/docs/versioning.md new file mode 100644 index 0000000..4d0692f --- /dev/null +++ b/docs/versioning.md @@ -0,0 +1,271 @@ +# Ceracoder Versioning + +This document describes the versioning scheme used for Ceracoder releases. + +## Overview + +Ceracoder uses **Calendar Versioning (CalVer)** with automatic version detection, matching the versioning scheme used in [CeraUI](https://github.com/CERALIVE/CeraUI). + +## Version Format + +| Release Type | Format | Example | +|--------------|--------|---------| +| **Stable** | `YYYY.M.patch` | `v2026.1.0`, `v2026.1.1`, `v2026.2.0` | +| **Beta** | `YYYY.M.patch-beta.N` | `v2026.1.1-beta.1`, `v2026.1.2-beta.2` | + +Where: +- `YYYY` = 4-digit year (e.g., 2026) +- `M` = Month without leading zero (e.g., 1 for January, 12 for December) +- `patch` = Incrementing patch number starting from 0 each month +- `N` = Beta number, incremented for each beta release + +## Version Calculation + +Versions are automatically calculated based on existing git tags. The system looks at the current year and month, then determines the next appropriate version number. + +### Stable Release Examples + +``` +January 2026: + First stable release: v2026.1.0 + Second stable release: v2026.1.1 + Third stable release: v2026.1.2 + +February 2026 (new month, patch resets): + First stable release: v2026.2.0 + Second stable release: v2026.2.1 +``` + +### Beta Release Examples + +Beta releases use the **next** patch number with a beta suffix: + +``` +January 2026: + Current stable: v2026.1.1 + First beta (next patch): v2026.1.2-beta.1 + Second beta: v2026.1.2-beta.2 + Third beta: v2026.1.2-beta.3 + + When v2026.1.2 is released as stable: + Next beta: v2026.1.3-beta.1 +``` + +### Key Rules + +1. **Stable releases** increment the patch number for the current year.month +2. **Beta releases** use the next patch number with a `-beta.N` suffix +3. Multiple betas can exist for the same patch version (beta.1, beta.2, etc.) +4. When a new month starts, the patch number resets to 0 +5. Beta numbers are tracked independently per patch version + +## Creating Releases + +### Using GitHub Actions (Recommended) + +Releases are created through GitHub Actions workflow dispatch: + +1. Navigate to **Actions** โ†’ **Build and Release Ceracoder** +2. Click **Run workflow** +3. Select parameters: + - **Release type**: `stable` or `beta` + - **Release notes**: Optional description of changes + - **Force version**: Optional manual version override (e.g., `2026.1.5`) +4. Click **Run workflow** + +The workflow will: +- Automatically calculate the next version based on existing tags +- Build binaries for x86_64 and ARM64 +- Create a GitHub release with all assets +- Tag the release with the calculated version +- Mark beta releases as "pre-release" + +### Manual Versioning + +If you need to override the automatic version detection, use the `force_version` input: + +``` +force_version: 2026.1.5 +``` + +This is useful for: +- Hotfix releases out of sequence +- Correcting version numbering issues +- Creating specific version numbers for compatibility + +## Version Information in Binary + +The version is compiled into the binary via the `VERSION` macro defined in the Makefile: + +```makefile +VERSION=$(shell git rev-parse --short HEAD) +CFLAGS=... -DVERSION=\"$(VERSION)\" ... +``` + +To display the version: + +```bash +ceracoder -v +``` + +## Release Workflow Details + +### Workflow Inputs + +| Input | Required | Description | Options | +|-------|----------|-------------|---------| +| `release_type` | Yes | Type of release | `stable`, `beta` | +| `release_notes` | No | Description of changes | Free text | +| `force_version` | No | Override auto version | e.g., `2026.1.0` | + +### Workflow Jobs + +1. **calculate-version** + - Fetches all git tags with `fetch-depth: 0` + - Determines next version based on `release_type` + - Outputs: `version`, `version_tag`, `is_beta` + +2. **build-release** (matrix: x86_64, arm64) + - Builds ceracoder binary for each architecture + - Creates compressed `.tar.gz` archives + - Generates SHA256 checksums + - Uploads artifacts + +3. **create-release** + - Downloads all build artifacts + - Generates changelog from commit history + - Creates GitHub release with: + - Version tag (e.g., `v2026.1.0`) + - Release name with beta indicator if applicable + - Formatted release notes + - All binary archives and checksums + - Pre-release flag for beta releases + +## Debian Package Versioning + +Debian packages use the same CalVer versioning scheme. The `publish-deb.yml` workflow: + +- Automatically calculates the CalVer version +- Builds ARM64 Debian packages +- Packages are named: `ceracoder_YYYY.M.patch_arm64.deb` or `ceracoder_YYYY.M.patch-beta.N_arm64.deb` + +To trigger a Debian package build: + +```bash +# Via GitHub Actions +Actions โ†’ Build and Upload Debian Package โ†’ Run workflow + +# Or automatically on push to master (builds beta by default) +git push origin master +``` + +## Migration from Previous Versioning + +Ceracoder previously used git commit hashes as versions. The new CalVer system: + +- Provides human-readable version numbers +- Enables proper version ordering and comparison +- Aligns with CeraUI's versioning scheme +- Supports both stable and beta release channels +- Integrates with Debian package management + +Existing installations using commit-based versions will continue to work. New releases will use the CalVer format. + +## Best Practices + +### When to Use Beta Releases + +Use beta releases for: +- Testing new features before stable release +- Gathering user feedback +- Pre-release validation +- Release candidates + +### When to Use Stable Releases + +Use stable releases for: +- Production deployments +- Official announcements +- Long-term support versions +- Recommended installations + +### Release Frequency + +- **Stable**: Release when features are complete and tested +- **Beta**: Release as often as needed for testing +- **Monthly**: Patch number resets each month, creating natural release cycles + +## Troubleshooting + +### Version Calculation Errors + +If the version calculation fails: + +1. Ensure you have git tags fetched: `git fetch --tags` +2. Check existing tags: `git tag -l` +3. Use `force_version` input to override if needed + +### Wrong Version Detected + +If the wrong version is detected: + +1. Verify your git tags follow the format `vYYYY.M.patch` or `vYYYY.M.patch-beta.N` +2. Check that old tags don't interfere (e.g., `v1.0.0` from old versioning) +3. Use `force_version` to specify the correct version + +### Beta Version Conflicts + +If beta versioning is incorrect: + +1. List beta tags: `git tag -l "v*-beta.*"` +2. Ensure beta tags follow the exact format `vYYYY.M.patch-beta.N` +3. Remove conflicting tags if necessary + +## Related Documentation + +- [CeraUI Versioning](https://github.com/CERALIVE/CeraUI/blob/master/docs/BUILD_PIPELINE.md) - Reference implementation +- [GitHub Actions Workflows](../.github/workflows/) - Workflow definitions +- [Makefile](../Makefile) - Build configuration with VERSION macro + +## Examples + +### Creating a Stable Release + +```bash +# 1. Go to GitHub Actions โ†’ Build and Release Ceracoder +# 2. Select: +# - release_type: stable +# - release_notes: "Added SRT statistics logging" +# 3. Run workflow +# +# Result: v2026.1.0 (or next available version) +``` + +### Creating a Beta Release + +```bash +# 1. Go to GitHub Actions โ†’ Build and Release Ceracoder +# 2. Select: +# - release_type: beta +# - release_notes: "Testing new bitrate algorithm" +# 3. Run workflow +# +# Result: v2026.1.1-beta.1 (or next available beta) +``` + +### Force a Specific Version + +```bash +# 1. Go to GitHub Actions โ†’ Build and Release Ceracoder +# 2. Select: +# - release_type: stable +# - release_notes: "Hotfix for critical bug" +# - force_version: 2026.1.5 +# 3. Run workflow +# +# Result: v2026.1.5 (regardless of existing versions) +``` + +--- + +For questions or issues with versioning, please open an issue on [GitHub](https://github.com/CERALIVE/ceracoder/issues).