Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
95 changes: 84 additions & 11 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
name: CUPS Snap CI - Native Build Pipeline
name: CUPS Snap CI - Unified Build Pipeline

on:
push:
branches:
Expand All @@ -8,49 +9,51 @@ on:
- master
workflow_dispatch:

permissions:
contents: read
pull-requests: write # Added this so the bot can post the PR comment

jobs:
build-snap:
name: Build CUPS Snap (${{ matrix.arch }})
# Job 1: Native builds for amd64 and arm64
build-native:
name: Build Native (${{ matrix.arch }})
runs-on: ${{ matrix.runs-on }}
strategy:
fail-fast: false
matrix:
include:
# x86_64 native build on standard Ubuntu runner
- arch: x86_64
- arch: amd64
runs-on: ubuntu-latest

# arm64 native build on ARM64-capable runner
- arch: arm64
runs-on: ubuntu-24.04-arm
steps:
- name: Checkout cups-snap sources
uses: actions/checkout@v4

- name: Print Ubuntu version
run: |
set -e
cat /etc/os-release | grep PRETTY_NAME | awk -F '=' '{print $2}'

- name: Build CUPS snap with Snapcraft action
id: snapcraft
uses: snapcore/action-build@v1
with:
path: .

- name: Install built snap (smoke test setup)
run: |
set -e
SNAP_FILE="${{ steps.snapcraft.outputs.snap }}"
echo "Installing snap: ${SNAP_FILE}"
sudo snap install --dangerous "${SNAP_FILE}"

- name: Run smoke tests
run: |
set -e

# Verify snap is listed
echo "Checking snap list..."
snap list | grep "^cups " || (echo "CUPS snap not found in snap list"; exit 1)

# Test ghostscript binary with -h flag
echo "Testing ghostscript binary..."
snap run cups.gs -h || true

Expand All @@ -65,4 +68,74 @@ jobs:
with:
name: cups-snap-${{ matrix.arch }}
path: ./*.snap
if-no-files-found: error
if-no-files-found: error

# Job 2: Remote build via Launchpad for armhf
# Job 2: Remote build via Launchpad for armhf
build-remote:
name: Build Remote (armhf)
runs-on: ubuntu-latest
steps:
- name: Checkout cups-snap sources
uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Check Launchpad Credentials & Scenarios
id: check-secrets
env:
LP_CREDENTIALS: ${{ secrets.LP_CREDENTIALS }}
run: |
if [ -z "$LP_CREDENTIALS" ]; then
if [ "${{ github.event_name }}" == "pull_request" ]; then
echo "available=false" >> $GITHUB_OUTPUT
echo "::notice title=Launchpad CI Bypassed::GitHub Actions cannot securely access repository secrets in PRs from external forks. Bypassing the armhf remote build so it does not falsely block your merge. The compilation will be verified automatically in the push workflow immediately after merging into master."
else
echo "available=false" >> $GITHUB_OUTPUT
echo "::error::No secrets found. LP_CREDENTIALS is missing from the repository."
exit 1
fi
else
echo "available=true" >> $GITHUB_OUTPUT
fi

- name: Install Snapcraft
if: steps.check-secrets.outputs.available == 'true'
run: |
sudo snap install snapcraft --channel latest/stable --classic

- name: Setup Launchpad credentials
if: steps.check-secrets.outputs.available == 'true'
env:
LP_CREDENTIALS: ${{ secrets.LP_CREDENTIALS }}
run: |
set -e
mkdir -p ~/.local/share/snapcraft/provider/launchpad ~/.local/share/snapcraft
echo "$LP_CREDENTIALS" > ~/.local/share/snapcraft/provider/launchpad/credentials
echo "$LP_CREDENTIALS" > ~/.local/share/snapcraft/launchpad-credentials

- name: Remote build CUPS snap on Launchpad
if: steps.check-secrets.outputs.available == 'true'
run: |
set +e # Disable auto-exit to capture output
OUTPUT=$(snapcraft remote-build --launchpad-accept-public-upload --build-for=armhf 2>&1)
EXIT_CODE=$?
set -e # Re-enable auto-exit

if [ $EXIT_CODE -ne 0 ]; then
echo "$OUTPUT" # Print the full log for debugging
if echo "$OUTPUT" | grep -iqE "macaroon|unauthorized|authentication|login|credentials"; then
echo "::error::Secrets are invalid or expired. Launchpad authentication failed."
else
echo "::error::Launchpad build failed due to a code compilation error or infrastructure issue."
fi
exit $EXIT_CODE
fi

- name: Upload CUPS snap artifact
if: steps.check-secrets.outputs.available == 'true'
uses: actions/upload-artifact@v4
with:
name: cups-snap-armhf
path: ./*.snap
if-no-files-found: error
73 changes: 73 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,79 @@ This repository uses a custom GitHub Actions workflow for CodeQL static analysis

*Note: If the Default setup is active, GitHub may reject the results uploaded by the manual workflow, causing the CI job to fail.*

## Launchpad Credentials for armhf Remote Build

The `armhf` build in CI uses **Snapcraft remote-build with Launchpad**.
Since GitHub runners do not have a Launchpad identity, authentication credentials must be generated locally and stored as a **GitHub repository secret**.

Follow the steps below to generate and configure the credentials.

### 1. Generate Launchpad Credentials
The credentials are generated via an interactive **Snapcraft OAuth login**.
First navigate to the project directory:
```
cd path/to/cups-snap
```
Run the following command:
```bash
snapcraft remote-build
```
Snapcraft will display a Launchpad authorization URL.
- Copy the URL shown in the terminal.
- Open it in your browser.
- Click Authorize.
- Return to the terminal.
- Once the upload starts, stop the process using:
```
Ctrl + C
```
Stopping the process here is expected. The credentials will already have been generated.

### 2. Extract the Credentials
Snapcraft stores the generated credentials locally.
Run:
```
cat ~/.local/share/snapcraft/provider/launchpad/credentials
```
If the file is not present, check:
```
cat ~/.local/share/snapcraft/launchpad-credentials
```
You will see output similar to:
```
[1]
consumer_key = System-wide: Ubuntu (...)
consumer_secret =
access_token = <alphanumeric-string>
access_secret = <alphanumeric-string>
```
Copy the entire block, including [1].

### 3. Store the Credentials in GitHub Secrets
The credentials must be added as a repository secret.
Navigate to:
```
Repository → Settings → Secrets and variables → Actions
```
Create a new secret:
```
LP_CREDENTIALS
```
Value:
Paste the complete credential block copied in the previous step.

Example:
```
[1]
consumer_key = System-wide: Ubuntu (...)
consumer_secret =
access_token = XXXXX
access_secret = XXXXX
```
These credentials will then be used automatically by the CI workflow when performing the armhf remote build.

*Note: Launchpad OAuth credentials generated by Snapcraft expire after approximately one year.If the CI workflow begins failing with authentication or authorization errors, new credentials must be generated by repeating the steps above and updating the LP_CREDENTIALS repository secret.*

## Discussion and Links

Call for testing:
Expand Down
13 changes: 11 additions & 2 deletions snapcraft.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name: cups
base: core22 # The base Snap is the execution environment for this Snap
version: '2.4.16-1'
version: '2.4.16-2'
grade: stable
summary: CUPS-based printing stack Snap
description: Complete printing environment in a Snap
Expand All @@ -12,11 +12,16 @@ adopt-info: cups
assumes: [snapd2.55]

# Only build on the architectures supported
# Explicit architecture mapping to support both native runners and Launchpad remote-build
architectures:
- build-on: amd64
build-for: amd64
- build-on: arm64
build-for: arm64
- build-on: armhf
build-for: armhf
- build-on: riscv64
build-for: riscv64

# System user for filters and backends to drop privileges, "lp" is not
# available in a Snap
Expand Down Expand Up @@ -339,6 +344,9 @@ parts:
- --with-cups-serverroot=/var/snap/cups/common/etc/cups
- --with-cups-datadir=/snap/cups/current/share/cups
build-environment:
# Universal fixes: Forces C99 standard, compatible across all architectures.
- CFLAGS: "-std=gnu99 -Wno-error=declaration-after-statement"
- CXXFLAGS: "-std=gnu++99"
# To find the libraries built in this Snap
- LD_LIBRARY_PATH: "${LD_LIBRARY_PATH:+$LD_LIBRARY_PATH:}$CRAFT_STAGE/usr/lib:$CRAFT_STAGE/usr/lib/${CRAFT_ARCH_TRIPLET_BUILD_FOR}:$CRAFT_STAGE/lib"
stage-packages:
Expand Down Expand Up @@ -594,7 +602,8 @@ parts:
source: scripts/
override-build: |
set -eux
gcc -o port-occupied port-occupied.c
# Uses CRAFT_ARCH_TRIPLET_BUILD_FOR to gracefully support all architectures natively and via remote
"${CRAFT_ARCH_TRIPLET_BUILD_FOR}-gcc" -o port-occupied port-occupied.c
craftctl default
organize:
run-cupsd: scripts/run-cupsd
Expand Down
Loading