Upload to Launchpad PPA #5
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # .github/workflows/launchpad_ppa.yml | |
| name: Upload to Launchpad PPA | |
| on: | |
| workflow_dispatch: | |
| inputs: | |
| release_tag: | |
| description: 'Release tag to upload to PPA (e.g. v0.5.0). Empty = latest release' | |
| required: false | |
| distributions: | |
| description: 'Target distributions (comma-separated: jammy,noble,oracular)' | |
| required: false | |
| default: 'jammy,noble' | |
| permissions: | |
| contents: read | |
| jobs: | |
| upload-ppa: | |
| name: Upload to PPA (${{ matrix.distro }}) | |
| runs-on: ubuntu-latest | |
| environment: packaging | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| distro: [jammy, noble, oracular] | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| - name: Check distribution | |
| id: check_distro | |
| run: | | |
| DISTRIBUTIONS="${{ github.event.inputs.distributions }}" | |
| if [[ ",$DISTRIBUTIONS," == *",${{ matrix.distro }},"* ]]; then | |
| echo "should_run=true" >> "$GITHUB_OUTPUT" | |
| else | |
| echo "should_run=false" >> "$GITHUB_OUTPUT" | |
| echo "Skipping ${{ matrix.distro }} - not in requested distributions" | |
| fi | |
| - name: Get release tag | |
| if: steps.check_distro.outputs.should_run == 'true' | |
| id: get_tag | |
| run: | | |
| if [ -n "${{ github.event.inputs.release_tag }}" ]; then | |
| echo "tag=${{ github.event.inputs.release_tag }}" >> "$GITHUB_OUTPUT" | |
| else | |
| TAG=$(gh release list --limit 1 --json tagName -q '.[0].tagName') | |
| echo "tag=${TAG}" >> "$GITHUB_OUTPUT" | |
| fi | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| - name: Update debian/changelog from release | |
| if: steps.check_distro.outputs.should_run == 'true' | |
| run: | | |
| sudo apt-get update && sudo apt-get install -y curl | |
| bash ./debian/update-changelog.sh \ | |
| -d ${{ matrix.distro }} \ | |
| -p lablup/backend-ai \ | |
| --auto-increment \ | |
| ${{ steps.get_tag.outputs.tag }} | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| - name: Install build dependencies | |
| if: steps.check_distro.outputs.should_run == 'true' | |
| run: | | |
| sudo apt update | |
| sudo apt install -y \ | |
| devscripts \ | |
| debhelper \ | |
| dh-make \ | |
| fakeroot \ | |
| dput \ | |
| gpg \ | |
| dpkg-dev \ | |
| build-essential | |
| # ─────────────────────────────────────────────────────────────── | |
| # NEW Step 5.5: Install Rust toolchain 1.75 (to produce lockfile v3) | |
| # ─────────────────────────────────────────────────────────────── | |
| - name: Install Rust 1.75 (for lockfile v3 & vendor) | |
| if: steps.check_distro.outputs.should_run == 'true' | |
| uses: dtolnay/rust-toolchain@1.75.0 | |
| # ─────────────────────────────────────────────────────────────── | |
| # NEW Step 5.6: Generate Cargo.lock (v3) with Cargo 1.75 | |
| # ─────────────────────────────────────────────────────────────── | |
| - name: Generate lockfile v3 (Cargo 1.75) | |
| if: steps.check_distro.outputs.should_run == 'true' | |
| run: | | |
| # Ensure we create a lockfile compatible with jammy's cargo (v3) | |
| rm -f Cargo.lock | |
| cargo generate-lockfile | |
| # Safety check: lockfile must be version = 3 (1.75 writes v3) | |
| awk '/^version = /{print; found=1} END{ if(!found) exit 1 }' Cargo.lock | |
| if ! grep -q '^version = 3' Cargo.lock; then | |
| echo "ERROR: Cargo.lock is not v3 (jammy-compatible)." | |
| exit 1 | |
| fi | |
| # ─────────────────────────────────────────────────────────────── | |
| # NEW Step 5.7: Vendor dependencies & write .cargo/config.toml | |
| # ─────────────────────────────────────────────────────────────── | |
| - name: Vendor Rust dependencies (offline build on Launchpad) | |
| if: steps.check_distro.outputs.should_run == 'true' | |
| run: | | |
| mkdir -p .cargo | |
| # Create vendor directory and config | |
| cargo vendor vendor > .cargo/config.toml | |
| # Ensure config has replace-with vendored-sources | |
| grep -q 'replace-with = "vendored-sources"' .cargo/config.toml | |
| grep -q '\[source.vendored-sources\]' .cargo/config.toml | |
| grep -q '^directory = "vendor"$' .cargo/config.toml | |
| # Quick sanity: no network is needed for build now | |
| echo "Vendoring done. Files:" | |
| ls -lah vendor | head -n 50 | |
| - name: Prepare package version | |
| if: steps.check_distro.outputs.should_run == 'true' | |
| run: | | |
| VERSION="${{ steps.get_tag.outputs.tag }}" | |
| VERSION="${VERSION#v}" | |
| echo "PACKAGE_VERSION=${VERSION}" >> "$GITHUB_ENV" | |
| CHANGELOG_VERSION=$(head -n 1 debian/changelog | awk '{print $2}' | tr -d '()') | |
| echo "FULL_PACKAGE_VERSION=${CHANGELOG_VERSION}" >> "$GITHUB_ENV" | |
| echo "Package version: ${CHANGELOG_VERSION}" | |
| head -n 1 debian/changelog | grep -q "${VERSION}-" || { | |
| echo "Error: Changelog doesn't contain expected version ${VERSION}" | |
| exit 1 | |
| } | |
| - name: Import GPG key | |
| if: steps.check_distro.outputs.should_run == 'true' | |
| run: | | |
| echo "${{ secrets.GPG_PRIVATE_KEY }}" | gpg --batch --import | |
| gpg --list-secret-keys --keyid-format LONG | |
| FINGERPRINT=$(gpg --list-secret-keys --with-colons | grep '^fpr:' | head -1 | cut -d: -f10) | |
| echo "GPG_FINGERPRINT=$FINGERPRINT" >> "$GITHUB_ENV" | |
| echo "${FINGERPRINT}:6:" | gpg --import-ownertrust | |
| - name: Configure GPG | |
| if: steps.check_distro.outputs.should_run == 'true' | |
| run: | | |
| export GNUPGHOME=/home/runner/.gnupg | |
| mkdir -p $GNUPGHOME | |
| chmod 700 $GNUPGHOME | |
| cat > $GNUPGHOME/gpg-agent.conf << 'EOF' | |
| allow-loopback-pinentry | |
| default-cache-ttl 300 | |
| max-cache-ttl 3600 | |
| EOF | |
| cat > $GNUPGHOME/gpg.conf << 'EOF' | |
| use-agent | |
| pinentry-mode loopback | |
| batch | |
| no-tty | |
| EOF | |
| if [ -n "${{ secrets.GPG_PASSPHRASE }}" ]; then | |
| echo "${{ secrets.GPG_PASSPHRASE }}" > $GNUPGHOME/passphrase | |
| chmod 600 $GNUPGHOME/passphrase | |
| fi | |
| gpgconf --kill gpg-agent || true | |
| - name: Build source package | |
| if: steps.check_distro.outputs.should_run == 'true' | |
| run: | | |
| # Clean any build artifacts | |
| rm -f bssh | |
| rm -rf target/ | |
| # Ensure Architecture field is 'any' | |
| sed -i 's/Architecture: .*/Architecture: any/' debian/control | |
| chmod +x debian/rules | |
| export GNUPGHOME=/home/runner/.gnupg | |
| # IMPORTANT: vendor/ and .cargo/config.toml are already present in the tree | |
| # dpkg-buildpackage -S -sa will include them into the source tarball | |
| if [ -n "${{ secrets.GPG_PASSPHRASE }}" ]; then | |
| echo "Building and signing source package with passphrase..." | |
| cat > /tmp/gpg-sign.sh << 'EOSCRIPT' | |
| #!/bin/bash | |
| echo "$GPG_PASSPHRASE" | gpg --batch --yes --passphrase-fd 0 --pinentry-mode loopback "$@" | |
| EOSCRIPT | |
| chmod +x /tmp/gpg-sign.sh | |
| export GPG_PASSPHRASE="${{ secrets.GPG_PASSPHRASE }}" | |
| dpkg-buildpackage -S -sa -k"$GPG_FINGERPRINT" -d --sign-command="/tmp/gpg-sign.sh" | |
| else | |
| echo "Building and signing source package without passphrase..." | |
| dpkg-buildpackage -S -sa -k"$GPG_FINGERPRINT" -d | |
| fi | |
| echo "Source package built and signed successfully" | |
| - name: Upload to Ubuntu PPA | |
| if: steps.check_distro.outputs.should_run == 'true' | |
| run: | | |
| cat > ~/.dput.cf << 'EOF' | |
| [backend-ai-ppa] | |
| fqdn = ppa.launchpad.net | |
| method = ftp | |
| incoming = ~lablup/ubuntu/backend-ai/ | |
| login = anonymous | |
| allow_unsigned_uploads = 0 | |
| EOF | |
| CHANGES_FILE=$(ls ../*_source.changes 2>/dev/null | head -1) | |
| if [ -z "$CHANGES_FILE" ]; then | |
| echo "Error: No source .changes file found" | |
| exit 1 | |
| fi | |
| echo "Uploading $CHANGES_FILE to PPA lablup/backend-ai" | |
| dput backend-ai-ppa "$CHANGES_FILE" | |
| echo "✅ Successfully uploaded to PPA" | |
| echo "📦 Version: $FULL_PACKAGE_VERSION" | |
| echo "📦 Package will be available at: https://launchpad.net/~lablup/+archive/ubuntu/backend-ai" |