|
1 | | -name: Build and Push Docker Image |
| 1 | +name: Build .deb Package for Raspberry Pi |
2 | 2 |
|
3 | 3 | on: |
4 | 4 | push: |
5 | | - branches: |
6 | | - - master |
| 5 | + branches: [master] |
7 | 6 |
|
8 | | -concurrency: |
9 | | - group: build-client |
10 | | - cancel-in-progress: false |
| 7 | +permissions: |
| 8 | + contents: write |
| 9 | + |
| 10 | +env: |
| 11 | + PKG_NAME: intercom-client |
| 12 | + PKG_ARCH: arm64 |
| 13 | + PKG_DEPENDS: "libgstreamer1.0-0, gstreamer1.0-plugins-base, gstreamer1.0-plugins-good, libv4l-0" |
11 | 14 |
|
12 | 15 | jobs: |
13 | | - build-and-push: |
| 16 | + bump: |
| 17 | + name: Bump version |
14 | 18 | runs-on: ubuntu-22.04-arm |
15 | | - |
| 19 | + outputs: |
| 20 | + new_version: ${{ steps.semver.outputs.new_version }} |
16 | 21 | steps: |
17 | | - - name: Checkout repository |
18 | | - uses: actions/checkout@v4 |
19 | | - |
20 | | - - name: Log in to private Docker registry |
21 | | - run: echo "${{ secrets.DOCKER_PASSWORD }}" | docker login docker.kmanning.ie:5000 -u "${{ secrets.DOCKER_USERNAME }}" --password-stdin |
| 22 | + - uses: actions/checkout@v5 |
| 23 | + with: |
| 24 | + fetch-depth: 0 |
| 25 | + token: ${{ secrets.GITHUB_TOKEN }} |
22 | 26 |
|
23 | | - - name: Build and push |
| 27 | + - name: Determine next version from conventional commits |
| 28 | + id: semver |
24 | 29 | run: | |
25 | | - IMAGE=docker.kmanning.ie:5000/intercom-client |
| 30 | + set -euo pipefail |
26 | 31 |
|
27 | | - # Collect tags |
28 | | - TAGS="-t $IMAGE:latest -t $IMAGE:${{ github.sha }}" |
29 | | -
|
30 | | - # Add semver tag from pyproject.toml |
31 | | - VERSION=$(python3 -c " |
| 32 | + CURRENT_VERSION=$(python3 -c " |
32 | 33 | import re |
33 | 34 | with open('pyproject.toml') as f: |
34 | 35 | m = re.search(r'^version\s*=\s*\"([^\"]+)\"', f.read(), re.MULTILINE) |
35 | 36 | print(m.group(1)) |
36 | 37 | ") |
37 | | - TAGS="$TAGS -t $IMAGE:v$VERSION" |
| 38 | + echo "Current version: ${CURRENT_VERSION}" |
| 39 | +
|
| 40 | + IFS='.' read -r MAJOR MINOR PATCH <<< "${CURRENT_VERSION}" |
| 41 | +
|
| 42 | + LAST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "") |
| 43 | +
|
| 44 | + if [ -z "${LAST_TAG}" ]; then |
| 45 | + echo "No existing tags — analyzing all commits" |
| 46 | + COMMITS=$(git log --format='%s') |
| 47 | + else |
| 48 | + echo "Last tag: ${LAST_TAG}" |
| 49 | + COMMITS=$(git log "${LAST_TAG}"..HEAD --format='%s') |
| 50 | + fi |
| 51 | +
|
| 52 | + BUMP="patch" |
| 53 | + while IFS= read -r subject; do |
| 54 | + # Major: breaking change via ! suffix |
| 55 | + if echo "$subject" | grep -qE '^[a-zA-Z]+(\([^)]+\))?!:'; then |
| 56 | + BUMP="major" |
| 57 | + break |
| 58 | + fi |
| 59 | + # Major: BREAKING CHANGE in commit body |
| 60 | + HASH=$(git log --format='%H %s' | grep -F "${subject}" | head -1 | awk '{print $1}') |
| 61 | + if [ -n "${HASH}" ] && git log -1 --format='%B' "${HASH}" | grep -q 'BREAKING CHANGE'; then |
| 62 | + BUMP="major" |
| 63 | + break |
| 64 | + fi |
| 65 | + # Minor: feat commits |
| 66 | + if [ "${BUMP}" != "major" ] && echo "$subject" | grep -qE '^feat(\([^)]+\))?:'; then |
| 67 | + BUMP="minor" |
| 68 | + fi |
| 69 | + done <<< "${COMMITS}" |
| 70 | +
|
| 71 | + echo "Bump type: ${BUMP}" |
| 72 | +
|
| 73 | + case "${BUMP}" in |
| 74 | + major) MAJOR=$((MAJOR + 1)); MINOR=0; PATCH=0 ;; |
| 75 | + minor) MINOR=$((MINOR + 1)); PATCH=0 ;; |
| 76 | + patch) PATCH=$((PATCH + 1)) ;; |
| 77 | + esac |
| 78 | +
|
| 79 | + NEW_VERSION="${MAJOR}.${MINOR}.${PATCH}" |
| 80 | + echo "New version: ${NEW_VERSION}" |
| 81 | + echo "new_version=${NEW_VERSION}" >> "$GITHUB_OUTPUT" |
| 82 | +
|
| 83 | + - name: Update pyproject.toml version |
| 84 | + run: | |
| 85 | + NEW_VERSION="${{ steps.semver.outputs.new_version }}" |
| 86 | + sed -i 's/^version = ".*"/version = "'"${NEW_VERSION}"'"/' pyproject.toml |
| 87 | + echo "Updated pyproject.toml to ${NEW_VERSION}" |
| 88 | + grep "^version" pyproject.toml |
| 89 | +
|
| 90 | + - name: Configure git |
| 91 | + run: | |
| 92 | + git config user.name "github-actions[bot]" |
| 93 | + git config user.email "github-actions[bot]@users.noreply.github.com" |
| 94 | +
|
| 95 | + - name: Commit version bump and push tag |
| 96 | + run: | |
| 97 | + NEW_VERSION="${{ steps.semver.outputs.new_version }}" |
| 98 | + git add pyproject.toml |
| 99 | + git commit -m "chore: bump version to ${NEW_VERSION}" |
| 100 | + git tag "v${NEW_VERSION}" |
| 101 | + git push origin HEAD |
| 102 | + git push origin "v${NEW_VERSION}" |
| 103 | +
|
| 104 | + - name: Create GitHub Release |
| 105 | + uses: softprops/action-gh-release@v2 |
| 106 | + with: |
| 107 | + tag_name: v${{ steps.semver.outputs.new_version }} |
| 108 | + generate_release_notes: true |
| 109 | + env: |
| 110 | + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} |
| 111 | + |
| 112 | + test: |
| 113 | + name: Run tests |
| 114 | + needs: bump |
| 115 | + runs-on: ubuntu-22.04-arm |
| 116 | + steps: |
| 117 | + - uses: actions/checkout@v5 |
| 118 | + with: |
| 119 | + ref: v${{ needs.bump.outputs.new_version }} |
| 120 | + |
| 121 | + - name: Install uv |
| 122 | + uses: astral-sh/setup-uv@v7 |
| 123 | + with: |
| 124 | + enable-cache: true |
| 125 | + cache-dependency-glob: uv.lock |
| 126 | + |
| 127 | + - name: Install dependencies |
| 128 | + run: uv sync |
| 129 | + |
| 130 | + - name: Run tests |
| 131 | + run: uv run pytest |
| 132 | + |
| 133 | + build: |
| 134 | + name: Build .deb |
| 135 | + needs: [test, bump] |
| 136 | + runs-on: ubuntu-22.04-arm |
| 137 | + steps: |
| 138 | + - uses: actions/checkout@v5 |
| 139 | + with: |
| 140 | + ref: v${{ needs.bump.outputs.new_version }} |
| 141 | + |
| 142 | + - name: Install uv |
| 143 | + uses: astral-sh/setup-uv@v7 |
| 144 | + with: |
| 145 | + enable-cache: true |
| 146 | + cache-dependency-glob: uv.lock |
| 147 | + |
| 148 | + - name: Install project dependencies |
| 149 | + run: uv sync |
| 150 | + |
| 151 | + - name: Install Nuitka |
| 152 | + run: uv pip install nuitka |
| 153 | + |
| 154 | + - name: Cache Nuitka build output |
| 155 | + uses: actions/cache@v4 |
| 156 | + with: |
| 157 | + path: | |
| 158 | + dist/ |
| 159 | + build/ |
| 160 | + main.build/ |
| 161 | + main.dist/ |
| 162 | + main.onefile-build/ |
| 163 | + key: nuitka-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('uv.lock', 'main.py', 'intercomclient/**/*.py') }} |
| 164 | + |
| 165 | + - name: Build native binary with Nuitka |
| 166 | + run: > |
| 167 | + uv run python -m nuitka |
| 168 | + --standalone |
| 169 | + --onefile |
| 170 | + --output-filename=intercom-client |
| 171 | + --output-dir=dist |
| 172 | + --include-package=intercomclient |
| 173 | + --include-package=aiortc |
| 174 | + --include-package=av |
| 175 | + --include-package=cv2 |
| 176 | + --include-package=numpy |
| 177 | + --include-package=websockets |
| 178 | + --include-package=requests |
| 179 | + --include-package=jsonschema |
| 180 | + --include-package=boto3 |
| 181 | + --include-package=botocore |
| 182 | + --include-package=cryptography |
| 183 | + --include-package=cffi |
| 184 | + --include-package=jmespath |
| 185 | + --include-package=transparenc_sdk |
| 186 | + --include-package-data=opencv_python.libs |
| 187 | + --include-package-data=cv2 |
| 188 | + main.py |
| 189 | +
|
| 190 | + - name: Build .deb package |
| 191 | + run: | |
| 192 | + set -euo pipefail |
| 193 | +
|
| 194 | + PKG_VERSION="${{ needs.bump.outputs.new_version }}" |
| 195 | + PKG_DIR="dist/${PKG_NAME}_${PKG_VERSION}_${PKG_ARCH}" |
| 196 | + DEB_FILE="${PKG_DIR}.deb" |
| 197 | +
|
| 198 | + mkdir -p "${PKG_DIR}/usr/local/bin" |
| 199 | + mkdir -p "${PKG_DIR}/lib/systemd/system" |
| 200 | + mkdir -p "${PKG_DIR}/etc/intercom-client" |
| 201 | + mkdir -p "${PKG_DIR}/DEBIAN" |
| 202 | +
|
| 203 | + cp dist/intercom-client "${PKG_DIR}/usr/local/bin/" |
| 204 | + chmod 755 "${PKG_DIR}/usr/local/bin/intercom-client" |
| 205 | +
|
| 206 | + cat > "${PKG_DIR}/DEBIAN/control" <<EOF |
| 207 | + Package: ${PKG_NAME} |
| 208 | + Version: ${PKG_VERSION} |
| 209 | + Section: net |
| 210 | + Priority: optional |
| 211 | + Architecture: ${PKG_ARCH} |
| 212 | + Depends: ${PKG_DEPENDS} |
| 213 | + Maintainer: Intercom Team |
| 214 | + Description: Intercom Pi client for WebRTC live streaming |
| 215 | + Raspberry Pi client that connects to the intercom signaling server |
| 216 | + and streams live video via WebRTC. |
| 217 | + EOF |
| 218 | +
|
| 219 | + cat > "${PKG_DIR}/etc/intercom-client/env" <<EOF |
| 220 | + # Intercom Client Configuration |
| 221 | + # Set your environment variables here — these are sourced by the systemd service. |
| 222 | + # |
| 223 | + # OAUTH_CLIENT_ID=your_client_id |
| 224 | + # OAUTH_CLIENT_SECRET=your_client_secret |
| 225 | + # VIDEO_SOURCE=0 |
| 226 | + # TOKEN_FILE_PATH=/home/pi/.config/intercom-client/tokens.json |
| 227 | + # WEBSOCKET_API_BASE_URL=wss://your-server.com/ws/live_stream |
| 228 | + # HTTP_API_BASE_URL=https://your-server.com |
| 229 | + EOF |
| 230 | +
|
| 231 | + cat > "${PKG_DIR}/lib/systemd/system/intercom-client.service" <<EOF |
| 232 | + [Unit] |
| 233 | + Description=Intercom Pi Client |
| 234 | + After=network-online.target |
| 235 | + Wants=network-online.target |
| 236 | +
|
| 237 | + [Service] |
| 238 | + Type=simple |
| 239 | + User=pi |
| 240 | + Group=pi |
| 241 | + EnvironmentFile=-/etc/intercom-client/env |
| 242 | + ExecStart=/usr/local/bin/intercom-client |
| 243 | + Restart=on-failure |
| 244 | + RestartSec=10 |
| 245 | +
|
| 246 | + [Install] |
| 247 | + WantedBy=multi-user.target |
| 248 | + EOF |
38 | 249 |
|
39 | | - docker build \ |
40 | | - -f Dockerfile \ |
41 | | - $TAGS \ |
42 | | - . |
| 250 | + dpkg-deb --build "${PKG_DIR}" |
43 | 251 |
|
44 | | - docker push "$IMAGE:latest" |
45 | | - docker push "$IMAGE:${{ github.sha }}" |
46 | | - docker push "$IMAGE:v$VERSION" |
| 252 | + echo "--- Built package ---" |
| 253 | + ls -lh "${DEB_FILE}" |
| 254 | + echo "" |
| 255 | + echo "--- Package contents ---" |
| 256 | + dpkg-deb --contents "${DEB_FILE}" |
| 257 | + echo "" |
| 258 | + echo "--- Package info ---" |
| 259 | + dpkg-deb --info "${DEB_FILE}" |
47 | 260 |
|
48 | | - echo "Pushed: $IMAGE:latest, $IMAGE:${{ github.sha }}, $IMAGE:v$VERSION" |
| 261 | + - name: Upload .deb artifact |
| 262 | + uses: actions/upload-artifact@v4 |
| 263 | + with: |
| 264 | + name: intercom-client-deb |
| 265 | + path: dist/intercom-client_*.deb |
| 266 | + retention-days: 30 |
0 commit comments