name: Release on: push: tags: - 'v*' permissions: contents: write jobs: build: strategy: fail-fast: false matrix: include: - platform: macos-latest target: aarch64-apple-darwin - platform: macos-15-intel target: x86_64-apple-darwin - platform: ubuntu-22.04 target: x86_64-unknown-linux-gnu - platform: ubuntu-22.04-arm target: aarch64-unknown-linux-gnu - platform: windows-latest target: x86_64-pc-windows-msvc runs-on: ${{ matrix.platform }} steps: - uses: actions/checkout@v4 - name: Setup Node.js uses: actions/setup-node@v4 with: node-version: 20 - name: Setup pnpm uses: pnpm/action-setup@v4 with: version: 9 - name: Install frontend dependencies run: pnpm install - name: Setup Rust uses: dtolnay/rust-toolchain@stable with: targets: ${{ matrix.target }} - name: Compute Rust dependency hash id: deps-hash shell: bash run: | { find . -name Cargo.toml -not -path './target/*' -print0 \ | sort -z \ | xargs -0 sed -E '/^version = /d' grep -v '^version = ' Cargo.lock } | sha256sum | cut -d' ' -f1 | { read -r hash echo "hash=${hash:0:20}" >> "$GITHUB_OUTPUT" } - name: Rust cache uses: swatinem/rust-cache@v2 with: workspaces: './ -> target' shared-key: release-${{ matrix.target }}-${{ steps.deps-hash.outputs.hash }} add-rust-environment-hash-key: false cache-on-failure: true - name: Install Apple certificate (macOS) if: startsWith(matrix.platform, 'macos') env: APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }} APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }} run: | CERTIFICATE_PATH=$RUNNER_TEMP/certificate.p12 KEYCHAIN_PATH=$RUNNER_TEMP/app-signing.keychain-db echo -n "$APPLE_CERTIFICATE" | base64 --decode -o $CERTIFICATE_PATH security create-keychain -p "" $KEYCHAIN_PATH security set-keychain-settings -lut 21600 $KEYCHAIN_PATH security unlock-keychain -p "" $KEYCHAIN_PATH security import $CERTIFICATE_PATH -P "$APPLE_CERTIFICATE_PASSWORD" -A -t cert -f pkcs12 -k $KEYCHAIN_PATH security set-key-partition-list -S apple-tool:,apple: -k "" $KEYCHAIN_PATH security list-keychains -d user -s $KEYCHAIN_PATH login.keychain-db - name: Install system dependencies (Linux) if: startsWith(matrix.platform, 'ubuntu') run: | sudo apt-get update sudo apt-get install -y libwebkit2gtk-4.1-dev libgtk-3-dev libappindicator3-dev librsvg2-dev patchelf libssl-dev - name: Setup Tauri signing key shell: bash run: | echo "${{ secrets.TAURI_SIGNING_PRIVATE_KEY_BASE64 }}" | base64 --decode > "$RUNNER_TEMP/updater.key" KEY_B64=$(base64 < "$RUNNER_TEMP/updater.key" | tr -d '\r\n') echo "TAURI_SIGNING_PRIVATE_KEY=$KEY_B64" >> "$GITHUB_ENV" if [ -n "${{ secrets.TAURI_SIGNING_PRIVATE_KEY_PASSWORD }}" ]; then echo "TAURI_SIGNING_PRIVATE_KEY_PASSWORD=${{ secrets.TAURI_SIGNING_PRIVATE_KEY_PASSWORD }}" >> "$GITHUB_ENV" fi - name: Generate release notes id: release-notes shell: bash env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | BODY="$(gh api "repos/${GITHUB_REPOSITORY}/releases/generate-notes" \ -f tag_name="${GITHUB_REF_NAME}" \ --jq '.body')" if [ -z "$BODY" ]; then BODY="DBX ${GITHUB_REF_NAME}" fi DELIM="RELEASE_NOTES_$(date +%s%N)" { echo "body<<$DELIM" printf '%s\n' "$BODY" echo "$DELIM" } >> "$GITHUB_OUTPUT" - name: Build Tauri app uses: tauri-apps/tauri-action@v0 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} APPLE_SIGNING_IDENTITY: ${{ startsWith(matrix.platform, 'macos') && secrets.APPLE_SIGNING_IDENTITY || '' }} APPLE_ID: ${{ startsWith(matrix.platform, 'macos') && secrets.APPLE_ID || '' }} APPLE_PASSWORD: ${{ startsWith(matrix.platform, 'macos') && secrets.APPLE_PASSWORD || '' }} APPLE_TEAM_ID: ${{ startsWith(matrix.platform, 'macos') && secrets.APPLE_TEAM_ID || '' }} with: tagName: ${{ github.ref_name }} releaseName: 'DBX ${{ github.ref_name }}' releaseBody: ${{ steps.release-notes.outputs.body }} releaseDraft: true prerelease: false args: --target ${{ matrix.target }} - name: Upload Windows portable ZIP if: matrix.platform == 'windows-latest' shell: pwsh env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | $version = "${env:GITHUB_REF_NAME}".TrimStart("v") $portableRoot = "portable" $portableDir = Join-Path $portableRoot "DBX_${version}_x64" $zipName = "DBX_${version}_x64-portable.zip" $exePath = "target/${{ matrix.target }}/release/dbx.exe" if (!(Test-Path $exePath)) { Write-Error "Missing Windows executable: $exePath" exit 1 } New-Item -ItemType Directory -Force -Path $portableDir | Out-Null Copy-Item $exePath (Join-Path $portableDir "DBX.exe") -Force Copy-Item "LICENSE" (Join-Path $portableDir "LICENSE") -Force Copy-Item "README.md" (Join-Path $portableDir "README.md") -Force Compress-Archive -Path (Join-Path $portableDir "*") -DestinationPath $zipName -Force gh release upload "${env:GITHUB_REF_NAME}" $zipName --repo "${env:GITHUB_REPOSITORY}" --clobber jdbc-plugin: needs: build runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Setup Java uses: actions/setup-java@v4 with: distribution: temurin java-version: '17' cache: maven - name: Read JDBC plugin version id: jdbc-plugin shell: bash run: | VERSION="$(grep -m1 '' plugins/jdbc/pom.xml | sed -E 's/.*([^<]+)<.*/\1/')" echo "version=${VERSION}" >> "$GITHUB_OUTPUT" - name: Package JDBC plugin run: ./plugins/jdbc/package.sh - name: Upload JDBC plugin asset env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | gh release upload "${GITHUB_REF_NAME}" \ "plugins/jdbc/dist/dbx-jdbc-plugin-${{ steps.jdbc-plugin.outputs.version }}.zip" \ --repo "${GITHUB_REPOSITORY}" \ --clobber publish: needs: [build, docker-manifest, jdbc-plugin] runs-on: ubuntu-latest steps: - name: Publish draft release env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: gh release edit ${{ github.ref_name }} --repo ${{ github.repository }} --draft=false --prerelease docker: runs-on: ubuntu-latest strategy: fail-fast: false matrix: platform: [linux/amd64, linux/arm64] steps: - 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 Docker Hub uses: docker/login-action@v3 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Build and push by digest id: build uses: docker/build-push-action@v6 with: context: . platforms: ${{ matrix.platform }} outputs: type=image,name=${{ secrets.DOCKERHUB_USERNAME }}/dbx,push-by-digest=true,name-canonical=true,push=true cache-from: type=gha,scope=${{ matrix.platform }} cache-to: type=gha,scope=${{ matrix.platform }},mode=max - name: Export digest run: | mkdir -p /tmp/digests digest="${{ steps.build.outputs.digest }}" touch "/tmp/digests/${digest#sha256:}" - name: Upload digest uses: actions/upload-artifact@v4 with: name: digests-${{ matrix.platform == 'linux/amd64' && 'amd64' || 'arm64' }} path: /tmp/digests/* if-no-files-found: error retention-days: 1 docker-manifest: needs: docker runs-on: ubuntu-latest steps: - name: Download digests uses: actions/download-artifact@v4 with: path: /tmp/digests pattern: digests-* merge-multiple: true - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 - name: Login to Docker Hub uses: docker/login-action@v3 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Extract version from tag id: version run: echo "version=${GITHUB_REF_NAME#v}" >> "$GITHUB_OUTPUT" - name: Create manifest list and push working-directory: /tmp/digests run: | docker buildx imagetools create \ -t ${{ secrets.DOCKERHUB_USERNAME }}/dbx:${{ steps.version.outputs.version }} \ -t ${{ secrets.DOCKERHUB_USERNAME }}/dbx:latest \ $(printf '${{ secrets.DOCKERHUB_USERNAME }}/dbx@sha256:%s ' *)