name: Release on: push: tags: - 'v*.*.*' workflow_dispatch: inputs: version: description: 'Release version (e.g., v1.2.3)' required: true permissions: contents: write jobs: build: name: Build Release Binaries runs-on: ubuntu-latest strategy: matrix: include: # Linux - goos: linux goarch: amd64 - goos: linux goarch: arm64 - goos: linux goarch: arm goarm: 7 # Windows - goos: windows goarch: amd64 - goos: windows goarch: arm64 # macOS - goos: darwin goarch: amd64 - goos: darwin goarch: arm64 steps: - name: Checkout code uses: actions/checkout@v4 with: fetch-depth: 0 - name: Set up Go uses: actions/setup-go@v5 with: go-version: '1.23' - name: Get version id: version run: | if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then VERSION="${{ github.event.inputs.version }}" else VERSION=${GITHUB_REF#refs/tags/} fi echo "VERSION=${VERSION}" >> $GITHUB_OUTPUT echo "SHORT_SHA=$(git rev-parse --short HEAD)" >> $GITHUB_OUTPUT echo "Version: ${VERSION}" - name: Build binaries env: GOOS: ${{ matrix.goos }} GOARCH: ${{ matrix.goarch }} GOARM: ${{ matrix.goarm }} CGO_ENABLED: 0 run: | VERSION=${{ steps.version.outputs.VERSION }} SHORT_SHA=${{ steps.version.outputs.SHORT_SHA }} LDFLAGS="-s -w -X main.Version=${VERSION} -X main.Commit=${SHORT_SHA}" # Set file extension for Windows EXT="" if [ "${{ matrix.goos }}" = "windows" ]; then EXT=".exe" fi # Build all CLI tools mkdir -p dist echo "🔨 Building onvif-cli..." go build -ldflags="${LDFLAGS}" -o "dist/onvif-cli-${{ matrix.goos }}-${{ matrix.goarch }}${EXT}" ./cmd/onvif-cli echo "🔨 Building onvif-quick..." go build -ldflags="${LDFLAGS}" -o "dist/onvif-quick-${{ matrix.goos }}-${{ matrix.goarch }}${EXT}" ./cmd/onvif-quick echo "🔨 Building onvif-server..." go build -ldflags="${LDFLAGS}" -o "dist/onvif-server-${{ matrix.goos }}-${{ matrix.goarch }}${EXT}" ./cmd/onvif-server echo "🔨 Building onvif-diagnostics..." go build -ldflags="${LDFLAGS}" -o "dist/onvif-diagnostics-${{ matrix.goos }}-${{ matrix.goarch }}${EXT}" ./cmd/onvif-diagnostics - name: Create archive run: | VERSION=${{ steps.version.outputs.VERSION }} PLATFORM="${{ matrix.goos }}-${{ matrix.goarch }}" ARCHIVE_NAME="onvif-go-${VERSION}-${PLATFORM}" mkdir -p releases staging # Copy binaries with clean names (without platform suffix) if [ "${{ matrix.goos }}" = "windows" ]; then cp dist/onvif-cli-${{ matrix.goos }}-${{ matrix.goarch }}.exe staging/onvif-cli.exe cp dist/onvif-quick-${{ matrix.goos }}-${{ matrix.goarch }}.exe staging/onvif-quick.exe cp dist/onvif-server-${{ matrix.goos }}-${{ matrix.goarch }}.exe staging/onvif-server.exe cp dist/onvif-diagnostics-${{ matrix.goos }}-${{ matrix.goarch }}.exe staging/onvif-diagnostics.exe else cp dist/onvif-cli-${{ matrix.goos }}-${{ matrix.goarch }} staging/onvif-cli cp dist/onvif-quick-${{ matrix.goos }}-${{ matrix.goarch }} staging/onvif-quick cp dist/onvif-server-${{ matrix.goos }}-${{ matrix.goarch }} staging/onvif-server cp dist/onvif-diagnostics-${{ matrix.goos }}-${{ matrix.goarch }} staging/onvif-diagnostics fi # Copy documentation cp README.md LICENSE staging/ 2>/dev/null || true # Create archive from staging directory if [ "${{ matrix.goos }}" = "windows" ]; then cd staging zip -r "../releases/${ARCHIVE_NAME}.zip" . cd .. else cd staging tar czf "../releases/${ARCHIVE_NAME}.tar.gz" . cd .. fi echo "✅ Created ${ARCHIVE_NAME}.tar.gz" - name: Generate checksums run: | cd releases if command -v sha256sum >/dev/null 2>&1; then sha256sum * > checksums-${{ matrix.goos }}-${{ matrix.goarch }}.txt else shasum -a 256 * > checksums-${{ matrix.goos }}-${{ matrix.goarch }}.txt fi - name: Upload artifacts uses: actions/upload-artifact@v4 with: name: release-${{ matrix.goos }}-${{ matrix.goarch }} path: releases/* retention-days: 7 release: name: Create GitHub Release needs: build runs-on: ubuntu-latest steps: - name: Checkout code uses: actions/checkout@v4 with: fetch-depth: 0 - name: Download all artifacts uses: actions/download-artifact@v4 with: path: all-releases pattern: release-* merge-multiple: true - name: Generate combined checksums run: | cd all-releases # Combine all checksum files cat checksums-*.txt > checksums.txt 2>/dev/null || true # Remove individual checksum files rm -f checksums-*.txt - name: Get version and changelog id: version run: | if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then VERSION="${{ github.event.inputs.version }}" else VERSION=${GITHUB_REF#refs/tags/} fi echo "VERSION=${VERSION}" >> $GITHUB_OUTPUT # Generate changelog from commits since last tag PREV_TAG=$(git describe --tags --abbrev=0 HEAD^ 2>/dev/null || echo "") if [ -n "$PREV_TAG" ]; then echo "CHANGELOG<> $GITHUB_OUTPUT git log --pretty=format:"- %s (%h)" ${PREV_TAG}..HEAD >> $GITHUB_OUTPUT echo "" >> $GITHUB_OUTPUT echo "EOF" >> $GITHUB_OUTPUT else echo "CHANGELOG=Initial release" >> $GITHUB_OUTPUT fi - name: Create Release uses: softprops/action-gh-release@v2 with: files: all-releases/* draft: false prerelease: ${{ contains(github.ref, '-rc') || contains(github.ref, '-beta') || contains(github.ref, '-alpha') }} generate_release_notes: true make_latest: true body: | ## Release ${{ steps.version.outputs.VERSION }} ### 📦 Installation Download the appropriate binary for your platform below. #### Linux/macOS ```bash # Download and extract wget https://github.com/${{ github.repository }}/releases/download/${{ steps.version.outputs.VERSION }}/onvif-go-${{ steps.version.outputs.VERSION }}-linux-amd64.tar.gz tar xzf onvif-go-${{ steps.version.outputs.VERSION }}-linux-amd64.tar.gz # Make executable and move to PATH chmod +x onvif-cli sudo mv onvif-cli /usr/local/bin/onvif-cli ``` #### Windows Download the `.zip` file for your architecture and extract it. #### Go Library ```bash go get github.com/${{ github.repository }}@${{ steps.version.outputs.VERSION }} ``` ### 🔐 Checksums SHA256 checksums are available in `checksums.txt` ### 📝 Changes ${{ steps.version.outputs.CHANGELOG }} env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} docker: name: Build and Push Docker Image needs: build runs-on: ubuntu-latest if: (github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v')) || github.event_name == 'workflow_dispatch' steps: - name: Checkout code uses: actions/checkout@v4 - name: Set up QEMU uses: docker/setup-qemu-action@v3 - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 - name: Login to GitHub Container Registry uses: docker/login-action@v3 with: registry: ghcr.io username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - name: Get version id: version run: | if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then VERSION="${{ github.event.inputs.version }}" # Remove 'v' prefix if present VERSION=${VERSION#v} else VERSION=${GITHUB_REF#refs/tags/v} fi echo "VERSION=${VERSION}" >> $GITHUB_OUTPUT - name: Build and push uses: docker/build-push-action@v5 with: context: . platforms: linux/amd64,linux/arm64,linux/arm/v7 push: true tags: | ghcr.io/${{ github.repository }}:latest ghcr.io/${{ github.repository }}:${{ steps.version.outputs.VERSION }} cache-from: type=gha cache-to: type=gha,mode=max