diff --git a/.github/homebridge-alpha-bot.json b/.github/homebridge-alpha-bot.json new file mode 100644 index 0000000..6413142 --- /dev/null +++ b/.github/homebridge-alpha-bot.json @@ -0,0 +1,43 @@ +{ + "auto_merge": true, + "git_user": { + "name": "Homebridge Alpha Bot", + "email": "actions@github.com" + }, + "directories": [ + { + "directory": "alpha/32bit", + "packages": [ + { + "name": "homebridge-config-ui-x", + "tag": "alpha" + }, + { + "name": "homebridge", + "pattern": "^2.0.0-alpha" + }, + { + "name": "node", + "tag": "^22.x.x" + } + ] + }, + { + "directory": "alpha/64bit", + "packages": [ + { + "name": "homebridge-config-ui-x", + "tag": "alpha" + }, + { + "name": "homebridge", + "pattern": "^2.0.0-alpha" + }, + { + "name": "node", + "tag": "^24.x.x" + } + ] + } + ] +} \ No newline at end of file diff --git a/.github/workflows/alpha-stage-1_update_alpha_dependencies.yml b/.github/workflows/alpha-stage-1_update_alpha_dependencies.yml new file mode 100644 index 0000000..c9d172b --- /dev/null +++ b/.github/workflows/alpha-stage-1_update_alpha_dependencies.yml @@ -0,0 +1,27 @@ +name: Alpha Stage 1 - Update Alpha Dependencies, Create PR, Merge PR and Trigger Alpha Stage 2 +on: + schedule: + - cron: '0 9 * * *' # 5 AM Eastern (11 AM UTC), Docker updates at 6 AM Eastern (12 PM UTC) + workflow_dispatch: +jobs: + homebridge-alpha-bot: + name: Run Homebridge Alpha Bot + uses: homebridge/.github/.github/workflows/homebridge-beta-bot.yml@latest + with: + config_file: '.github/homebridge-alpha-bot.json' + secrets: inherit + + trigger-alpha-stage-2: + name: Trigger Build and Release Alpha Package + needs: homebridge-alpha-bot + if: needs.homebridge-alpha-bot.outputs.changes_detected == 'true' && needs.homebridge-alpha-bot.outputs.auto_merge == 'true' + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + - name: Trigger Alpha Stage 2 Workflow + run: | + echo "::notice::Triggering Alpha Stage 2 - Build and Release Alpha Package" + gh workflow run alpha-stage-2_build_alpha_release_and_store.yml --ref latest || { echo "::error::Failed to trigger Alpha Stage 2 workflow"; exit 1; } + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} \ No newline at end of file diff --git a/.github/workflows/alpha-stage-2_build_alpha_release_and_store.yml b/.github/workflows/alpha-stage-2_build_alpha_release_and_store.yml new file mode 100644 index 0000000..72a24bb --- /dev/null +++ b/.github/workflows/alpha-stage-2_build_alpha_release_and_store.yml @@ -0,0 +1,278 @@ +name: Alpha Stage 2 - Build and Release Alpha Package + +permissions: + contents: write + actions: write + id-token: write + +on: + pull_request: + types: [closed] + workflow_dispatch: + +jobs: + check-changes: + if: github.event.pull_request.merged == true || github.event_name == 'workflow_dispatch' + runs-on: ubuntu-latest + outputs: + alpha_only: ${{ steps.verify_changes.outputs.alpha_only }} + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Log event context for debugging + if: github.event_name == 'pull_request' + run: | + echo "Event: ${{ github.event_name }}" + echo "Merged: ${{ github.event.pull_request.merged }}" + + - name: Verify alpha-only changes + id: verify_changes + run: | + if [ "${{ github.event_name }}" == "workflow_dispatch" ]; then + echo "Workflow dispatch detected, setting alpha_only=true" + echo "alpha_only=true" >> $GITHUB_OUTPUT + else + alpha_only=true + changed_files=$(git diff --name-only HEAD^ HEAD) + for file in $changed_files; do + if [[ ! $file == alpha/* ]]; then + echo "Non-alpha changes detected in $file. Setting alpha_only=false" + alpha_only=false + fi + done + echo "alpha_only=$alpha_only" >> $GITHUB_OUTPUT + fi + + generate_alpha_version: + needs: check-changes + if: ${{ needs.check-changes.outputs.alpha_only == 'true' }} + name: Generate Alpha Package Version + runs-on: ubuntu-latest + outputs: + version: ${{ steps.alpha_version.outputs.version }} + npm_version: ${{ steps.alpha_version.outputs.npm_version }} + steps: + - uses: actions/checkout@v4 + + - name: Get base version + uses: reecetech/version-increment@2023.10.1 + id: release_version + with: + scheme: semver + increment: patch + + - name: Generate alpha package version + id: alpha_version + run: | + BASE_VERSION=${{ steps.release_version.outputs.version }} + BASE_VERSION_CLEAN=$(echo "$BASE_VERSION" | sed -E 's/-[a-z0-9.]+//') + DATE=$(date +%Y%m%d) + VERSION="${BASE_VERSION_CLEAN}~alpha.${DATE}" + NPM_VERSION="${BASE_VERSION_CLEAN}-alpha.${DATE}" + echo "version=$VERSION" >> $GITHUB_OUTPUT + echo "npm_version=$NPM_VERSION" >> $GITHUB_OUTPUT + echo "::notice::📦 Alpha version: $VERSION" + + build_alpha_and_store: + name: Build Alpha Packages for (${{ matrix.name }}) + needs: [generate_alpha_version] + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + name: [debian-x86_64, debian-arm64v8, debian-arm32v6] + include: + - name: debian-x86_64 + os: ubuntu-latest + BASE_IMAGE: library/debian:bullseye + QEMU_ARCH: x86_64 + + - name: debian-arm64v8 + os: ubuntu-24.04-arm + BASE_IMAGE: arm64v8/debian:bullseye + QEMU_ARCH: aarch64 + + - name: debian-arm32v6 + os: ubuntu-24.04-arm + BASE_IMAGE: balenalib/raspberrypi3-debian:bullseye + QEMU_ARCH: arm + + steps: + - uses: actions/checkout@v4 + + - name: Setup build environment X64 + if: runner.os == 'Linux' && runner.arch == 'X64' + run: | + sudo apt-get update + sudo apt-get --yes --no-install-recommends install binfmt-support qemu-user-static + docker run --rm --privileged multiarch/qemu-user-static:register --reset + continue-on-error: false + + - name: Setup build environment ARM64 + if: runner.os == 'Linux' && runner.arch == 'ARM64' + run: | + sudo apt-get update + sudo apt-get --yes --no-install-recommends install binfmt-support + continue-on-error: false + + - name: Build Docker image + run: | + docker build -f build/Dockerfile \ + --build-arg BASE_IMAGE=${{ matrix.BASE_IMAGE }} \ + --build-arg QEMU_ARCH=${{ matrix.QEMU_ARCH }} \ + -t alpha-package-build \ + --platform=linux/${{ matrix.QEMU_ARCH }} \ + --cache-from=alpha-package-build:latest \ + --build-arg BUILDKIT_INLINE_CACHE=1 . + continue-on-error: false + + - name: Build package + run: | + docker run --rm -v $(pwd):/repo \ + -e PKG_RELEASE_TYPE="alpha" \ + -e PKG_RELEASE_VERSION="${{ needs.generate_alpha_version.outputs.version }}" \ + alpha-package-build + continue-on-error: false + + - name: Rename package to include v + run: | + DEB_FILE=$(ls homebridge*.deb 2>/dev/null || echo "") + if [ -z "$DEB_FILE" ]; then + echo "No .deb file found. Exiting." + exit 1 + fi + UPDATED=$(echo "$DEB_FILE" | sed -e 's/homebridge_/homebridge_v/g') + mv "$DEB_FILE" "$UPDATED" + + - name: Rename manifest to include v + run: | + MANIFEST_FILE=$(ls homebridge*.manifest 2>/dev/null || echo "") + if [ -z "$MANIFEST_FILE" ]; then + echo "No .manifest file found. Exiting." + exit 1 + fi + UPDATED=$(echo "$MANIFEST_FILE" | sed -e 's/homebridge_/homebridge_v/g') + mv "$MANIFEST_FILE" "$UPDATED" + + - uses: actions/upload-artifact@v4 + with: + name: artifacts-${{ matrix.name }} + retention-days: 7 + path: | + homebridge_v*.deb + homebridge_v*.manifest + + publish_apt_alpha: + name: APT Alpha Repo Publish ${{ needs.generate_alpha_version.outputs.version }} + runs-on: ubuntu-latest + needs: [generate_alpha_version, build_alpha_and_store] + steps: + - uses: actions/checkout@v4 + + - name: Download all artifacts + uses: actions/download-artifact@v4 + with: + pattern: artifacts-* + merge-multiple: true + path: repo/ + + - name: Display structure of downloaded files + run: ls -R + + - name: Import GPG Key + uses: crazy-max/ghaction-import-gpg@v6 + with: + gpg_private_key: ${{ secrets.GPG_PRIVATE_KEY }} + passphrase: ${{ secrets.GPG_PASSPHRASE }} + + - name: Install deb-s3 + run: | + curl -sLO https://github.com/deb-s3/deb-s3/releases/download/0.11.8/deb-s3-0.11.8.gem + sudo gem install deb-s3-0.11.8.gem + + - name: Upload to Alpha APT Repo + run: | + sudo chown -R $USER: repo/ + deb-s3 upload \ + --codename=alpha \ + --suite=alpha \ + --preserve-versions \ + --s3-region=us-west-2 \ + --bucket repo.homebridge.io \ + --access-key-id=${{ secrets.AWS_ACCESS_KEY_ID }} \ + --secret-access-key=${{ secrets.AWS_SECRET_ACCESS_KEY }} \ + --sign=${{ secrets.GPG_KEY_ID }} \ + repo/homebridge_v*.deb + + publish_github_alpha_release: + name: Publish GitHub Alpha Release v${{ needs.generate_alpha_version.outputs.npm_version }} + needs: [check-changes, publish_apt_alpha, generate_alpha_version] + runs-on: ubuntu-latest + steps: + - name: Download all artifacts + uses: actions/download-artifact@v4 + with: + pattern: artifacts-* + merge-multiple: true + path: artifacts/ + + - name: Read amd64 manifest content + id: read_manifest + run: | + echo "MANIFEST_FILE=$(ls artifacts/*.manifest | head -n 1)" >> $GITHUB_OUTPUT + + - name: Create GitHub Release + uses: softprops/action-gh-release@v2 + with: + tag_name: v${{ needs.generate_alpha_version.outputs.npm_version }} + name: Alpha Release v${{ needs.generate_alpha_version.outputs.npm_version }} + prerelease: true + files: | + artifacts/homebridge_v*.deb + artifacts/homebridge_v*.manifest + body_path: ${{ steps.read_manifest.outputs.MANIFEST_FILE }} + body: | + Homebridge Apt Package Manifest + + Release Version: v${{ needs.generate_alpha_version.outputs.npm_version }} + Release Type: alpha + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + purge_cloudflare_cache: + name: Purge Cloudflare Cache + needs: [publish_apt_alpha] + uses: ./.github/workflows/stage-3_5_purge_cloudflare_cache.yml + secrets: + CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }} + CLOUDFLARE_ZONE_ID: ${{ secrets.CLOUDFLARE_ZONE_ID }} + + publish_to_npm: + needs: [generate_alpha_version, build_alpha_and_store] + name: NPM Publish ${{ needs.generate_alpha_version.outputs.npm_version }} + runs-on: ubuntu-latest + steps: + - name: Checkout Repo + uses: actions/checkout@v4 + + - name: Set up Node.js + uses: actions/setup-node@v4 + with: + node-version: latest + registry-url: 'https://registry.npmjs.org' + + - name: Set package.json version + run: | + ALPHA_VERSION="${{ needs.generate_alpha_version.outputs.npm_version }}" + echo "Setting version to $ALPHA_VERSION" + jq ".version = \"$ALPHA_VERSION\"" package.json > tmp.$$.json && mv tmp.$$.json package.json + cat package.json + + - name: Publish to npm with alpha tag + run: npm publish --access public --tag alpha + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} + + - name: Output Success Notice + run: echo "::notice::Published @homebridge/homebridge-apt-pkg as version ${{ needs.generate_alpha_version.outputs.npm_version }} with alpha tag" \ No newline at end of file diff --git a/README.md b/README.md index 650e385..a6fb049 100644 --- a/README.md +++ b/README.md @@ -244,6 +244,35 @@ sudo apt-get update sudo apt-get install homebridge ``` +## Alpha Builds + +Alpha builds of the homebridge package are supplied with the latest alpha versions of Homebridge and Homebridge UI for testing new features before they reach beta. + +⚠️ **Warning**: Alpha builds are experimental and may contain bugs or unstable features. Use only for testing purposes. + +### Installing Alpha Version via APT + +Add package source: + +```bash +# make sure the tools needed to add the repo exist +sudo apt-get update +sudo apt-get install -y curl gpg + +# add the homebridge gpg key +curl -sSfL https://repo.homebridge.io/KEY.gpg | sudo gpg --dearmor | sudo tee /usr/share/keyrings/homebridge.gpg > /dev/null + +# add the homebridge repo +echo "deb [signed-by=/usr/share/keyrings/homebridge.gpg] https://repo.homebridge.io alpha main" | sudo tee /etc/apt/sources.list.d/homebridge.list > /dev/null +``` + +Update and install: + +```bash +sudo apt-get update +sudo apt-get install homebridge +``` + ## Packaging Notes Package scripts workflow (preinst, postinst, postrm etc.): diff --git a/alpha/32bit/package.json b/alpha/32bit/package.json new file mode 100644 index 0000000..ce59904 --- /dev/null +++ b/alpha/32bit/package.json @@ -0,0 +1,28 @@ +{ + "name": "@homebridge/homebridge-apt-pkg-alpha", + "version": "0.0.0", + "description": "Stub package for tracking ALPHA Homebridge APT release versions via npm", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1", + "prepublishOnly": "cp ../README.npm.md README.md" + }, + "files": [ + "README.md" + ], + "repository": { + "type": "git", + "url": "git+https://github.com/homebridge/homebridge-apt-pkg.git" + }, + "author": "Homebridge", + "license": "ISC", + "bugs": { + "url": "https://github.com/homebridge/homebridge-apt-pkg/issues" + }, + "homepage": "https://github.com/homebridge/homebridge-apt-pkg#readme", + "private": false, + "dependencies": { + "homebridge": "^2.0.0-alpha.39", + "homebridge-config-ui-x": "^5.5.1-alpha.0", + "node": "^22.19.0" + } +} \ No newline at end of file diff --git a/alpha/64bit/package.json b/alpha/64bit/package.json new file mode 100644 index 0000000..090c1a0 --- /dev/null +++ b/alpha/64bit/package.json @@ -0,0 +1,28 @@ +{ + "name": "@homebridge/homebridge-apt-pkg-alpha", + "version": "0.0.0", + "description": "Stub package for tracking ALPHA Homebridge APT release versions via npm", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1", + "prepublishOnly": "cp ../README.npm.md README.md" + }, + "files": [ + "README.md" + ], + "repository": { + "type": "git", + "url": "git+https://github.com/homebridge/homebridge-apt-pkg.git" + }, + "author": "Homebridge", + "license": "ISC", + "bugs": { + "url": "https://github.com/homebridge/homebridge-apt-pkg/issues" + }, + "homepage": "https://github.com/homebridge/homebridge-apt-pkg#readme", + "private": false, + "dependencies": { + "homebridge": "^2.0.0-alpha.39", + "homebridge-config-ui-x": "^5.5.1-alpha.0", + "node": "^24.7.0" + } +} \ No newline at end of file diff --git a/build.sh b/build.sh index 05a6d2c..58aad4c 100755 --- a/build.sh +++ b/build.sh @@ -5,7 +5,7 @@ set -x #trap 'rm -rf staging *.tar.gz *.manifest /tmp/*' EXIT -# Determine if beta or stable config should be used +# Determine if alpha, beta or stable config should be used if [[ "$PKG_RELEASE_TYPE" == "beta" ]]; then BUILD_ARCH=${QEMU_ARCH:-aarch64} case "$BUILD_ARCH" in @@ -17,6 +17,17 @@ if [[ "$PKG_RELEASE_TYPE" == "beta" ]]; then ;; *) echo "unsupported architecture"; exit 1 ;; esac +elif [[ "$PKG_RELEASE_TYPE" == "alpha" ]]; then + BUILD_ARCH=${QEMU_ARCH:-aarch64} + case "$BUILD_ARCH" in + x86_64|aarch64) + PACKAGE_JSON_PATH="alpha/64bit/package.json" + ;; + arm|i386) + PACKAGE_JSON_PATH="alpha/32bit/package.json" + ;; + *) echo "unsupported architecture"; exit 1 ;; + esac else PACKAGE_JSON_PATH="package.json" fi