|
| 1 | +# SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. |
| 2 | +# SPDX-License-Identifier: Apache-2.0 |
| 3 | + |
| 4 | +name: Build Snap |
| 5 | + |
| 6 | +on: |
| 7 | + workflow_call: |
| 8 | + inputs: |
| 9 | + checkout-ref: |
| 10 | + required: true |
| 11 | + type: string |
| 12 | + artifact-layout: |
| 13 | + description: "Layout of the prebuilt binary artifacts (tarball or raw)" |
| 14 | + required: false |
| 15 | + type: string |
| 16 | + default: tarball |
| 17 | + arch: |
| 18 | + description: "Snap package architecture" |
| 19 | + required: true |
| 20 | + type: string |
| 21 | + runner: |
| 22 | + description: "GitHub Actions runner label" |
| 23 | + required: true |
| 24 | + type: string |
| 25 | + cli-artifact-name: |
| 26 | + required: false |
| 27 | + type: string |
| 28 | + default: "" |
| 29 | + cli-artifact-prefix: |
| 30 | + required: false |
| 31 | + type: string |
| 32 | + default: "" |
| 33 | + gateway-artifact-name: |
| 34 | + required: false |
| 35 | + type: string |
| 36 | + default: "" |
| 37 | + gateway-artifact-prefix: |
| 38 | + required: false |
| 39 | + type: string |
| 40 | + default: "" |
| 41 | + supervisor-artifact-name: |
| 42 | + required: false |
| 43 | + type: string |
| 44 | + default: "" |
| 45 | + supervisor-artifact-prefix: |
| 46 | + required: false |
| 47 | + type: string |
| 48 | + default: "" |
| 49 | + upload-channel: |
| 50 | + required: false |
| 51 | + type: string |
| 52 | + default: "" |
| 53 | + description: "Snap Store channel to upload to" |
| 54 | + github-environment: |
| 55 | + required: false |
| 56 | + type: string |
| 57 | + default: "" |
| 58 | + description: "GitHub deployment environment for approval gates" |
| 59 | + publish: |
| 60 | + required: false |
| 61 | + type: boolean |
| 62 | + default: false |
| 63 | + description: "Whether to upload the built Snap to the Snap Store" |
| 64 | + |
| 65 | + secrets: |
| 66 | + publish-credentials: |
| 67 | + required: false |
| 68 | + description: "Snap Store credentials (SNAPCRAFT_STORE_CREDENTIALS)" |
| 69 | + |
| 70 | +permissions: |
| 71 | + contents: read |
| 72 | + |
| 73 | +defaults: |
| 74 | + run: |
| 75 | + shell: bash |
| 76 | + |
| 77 | +jobs: |
| 78 | + build-snap: |
| 79 | + name: Build Snap (Linux ${{ inputs.arch }}) |
| 80 | + runs-on: ${{ inputs.runner }} |
| 81 | + timeout-minutes: 60 |
| 82 | + environment: ${{ inputs.publish && inputs.github-environment || '' }} |
| 83 | + steps: |
| 84 | + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 |
| 85 | + with: |
| 86 | + ref: ${{ inputs.checkout-ref }} |
| 87 | + fetch-depth: 0 |
| 88 | + |
| 89 | + - name: Install snapd |
| 90 | + run: | |
| 91 | + set -euo pipefail |
| 92 | + if ! command -v snapd >/dev/null 2>&1; then |
| 93 | + sudo apt-get update |
| 94 | + sudo apt-get install -y snapd |
| 95 | + fi |
| 96 | + sudo systemctl enable --now snapd.socket |
| 97 | + sudo systemctl start snapd |
| 98 | + sudo snap wait system seed.loaded |
| 99 | +
|
| 100 | + - name: Install LXD |
| 101 | + run: | |
| 102 | + set -euo pipefail |
| 103 | + sudo snap install lxd |
| 104 | + sudo usermod -aG lxd "$USER" |
| 105 | + sudo lxd waitready |
| 106 | + sudo lxd init --auto |
| 107 | + sudo iptables -P FORWARD ACCEPT |
| 108 | + sudo chgrp lxd /var/snap/lxd/common/lxd/unix.socket |
| 109 | + sudo chmod 660 /var/snap/lxd/common/lxd/unix.socket |
| 110 | +
|
| 111 | + - name: Install snapcraft |
| 112 | + run: sudo snap install snapcraft --classic |
| 113 | + |
| 114 | + - name: Download prebuilt CLI binary |
| 115 | + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 |
| 116 | + with: |
| 117 | + name: ${{ inputs.cli-artifact-name || (inputs.artifact-layout == 'raw' && format('{0}-linux-{1}', inputs.cli-artifact-prefix, inputs.arch)) || format('cli-linux-{0}', inputs.arch) }} |
| 118 | + path: prebuilt/cli |
| 119 | + |
| 120 | + - name: Download prebuilt gateway binary |
| 121 | + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 |
| 122 | + with: |
| 123 | + name: ${{ inputs.gateway-artifact-name || (inputs.artifact-layout == 'raw' && format('{0}-linux-{1}', inputs.gateway-artifact-prefix, inputs.arch)) || format('gateway-binary-linux-{0}', inputs.arch) }} |
| 124 | + path: prebuilt/gateway |
| 125 | + |
| 126 | + - name: Download prebuilt sandbox binary |
| 127 | + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 |
| 128 | + with: |
| 129 | + name: ${{ inputs.supervisor-artifact-name || (inputs.artifact-layout == 'raw' && format('{0}-linux-{1}', inputs.supervisor-artifact-prefix, inputs.arch)) || format('supervisor-binary-linux-{0}', inputs.arch) }} |
| 130 | + path: prebuilt/sandbox |
| 131 | + |
| 132 | + - name: Prepare snap build directory |
| 133 | + run: | |
| 134 | + set -euo pipefail |
| 135 | + case "${{ inputs.artifact-layout }}" in |
| 136 | + tarball) |
| 137 | + for directory in cli gateway sandbox; do |
| 138 | + for tarball in "prebuilt/$directory"/*.tar.gz; do |
| 139 | + test -f "$tarball" || continue |
| 140 | + tar -xzf "$tarball" -C "prebuilt/$directory" |
| 141 | + done |
| 142 | + done |
| 143 | + ;; |
| 144 | + raw) ;; |
| 145 | + *) |
| 146 | + echo "unsupported artifact layout: ${{ inputs.artifact-layout }}" >&2 |
| 147 | + exit 1 |
| 148 | + ;; |
| 149 | + esac |
| 150 | +
|
| 151 | + find_binary() { |
| 152 | + find "$1" -type f -name "$2" -print -quit |
| 153 | + } |
| 154 | + cli="$(find_binary prebuilt/cli openshell)" |
| 155 | + gateway="$(find_binary prebuilt/gateway openshell-gateway)" |
| 156 | + sandbox="$(find_binary prebuilt/sandbox openshell-sandbox)" |
| 157 | + test -n "$cli" && test -n "$gateway" && test -n "$sandbox" |
| 158 | +
|
| 159 | + mkdir -p snap/prebuilt/meta/gui |
| 160 | + install -m 0755 "$cli" snap/prebuilt/openshell |
| 161 | + install -m 0755 "$gateway" snap/prebuilt/openshell-gateway |
| 162 | + install -m 0755 "$sandbox" snap/prebuilt/openshell-sandbox |
| 163 | + install -m 0755 tasks/scripts/snap-gateway-wrapper.sh snap/prebuilt/openshell-gateway-wrapper |
| 164 | + cp LICENSE README.md snap/prebuilt/ |
| 165 | + cp snap/local/term.desktop snap/prebuilt/meta/gui/term.desktop |
| 166 | + cp snap/local/icon.png snap/prebuilt/meta/gui/icon.png |
| 167 | + python3 tasks/scripts/release.py get-version --snap > snap/prebuilt/version |
| 168 | +
|
| 169 | + - name: Build snap |
| 170 | + run: | |
| 171 | + set -euo pipefail |
| 172 | + runtime_dir="/run/user/$(id -u)" |
| 173 | + sudo install -d -m 0700 -o "$(id -u)" -g "$(id -g)" "$runtime_dir" |
| 174 | + export XDG_RUNTIME_DIR="$runtime_dir" |
| 175 | + sg lxd -c "XDG_RUNTIME_DIR=${runtime_dir} snapcraft pack -v" |
| 176 | +
|
| 177 | + - name: Upload snapcraft logs on failure |
| 178 | + if: failure() |
| 179 | + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 |
| 180 | + with: |
| 181 | + name: snapcraft-logs-${{ inputs.arch }} |
| 182 | + path: "~/.local/state/snapcraft/log/snapcraft-*.log" |
| 183 | + retention-days: 7 |
| 184 | + |
| 185 | + - name: Capture Snap filename |
| 186 | + id: capture |
| 187 | + run: | |
| 188 | + set -euo pipefail |
| 189 | + snap_file=$(find . -maxdepth 1 -type f -name '*.snap' -printf '%f\n' | head -1) |
| 190 | + if [ -z "$snap_file" ]; then |
| 191 | + echo "::error::No .snap file found after snapcraft pack" |
| 192 | + exit 1 |
| 193 | + fi |
| 194 | + echo "snap-file=$snap_file" >> "$GITHUB_OUTPUT" |
| 195 | + echo "Built Snap: $snap_file" |
| 196 | +
|
| 197 | + - name: Upload snap artifact (${{ inputs.arch }}) |
| 198 | + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 |
| 199 | + with: |
| 200 | + name: snap-linux-${{ inputs.arch }} |
| 201 | + path: | |
| 202 | + ${{ steps.capture.outputs.snap-file }} |
| 203 | + *.comp |
| 204 | + retention-days: 5 |
| 205 | + |
| 206 | + - name: Upload Snap to Snap Store |
| 207 | + if: inputs.publish |
| 208 | + env: |
| 209 | + SNAPCRAFT_STORE_CREDENTIALS: ${{ secrets.publish-credentials }} |
| 210 | + INPUTS_UPLOAD_CHANNEL: ${{ inputs.upload-channel }} |
| 211 | + run: | |
| 212 | + set -euo pipefail |
| 213 | + snap_file="${{ steps.capture.outputs.snap-file }}" |
| 214 | + snap_name="${snap_file%.snap}" |
| 215 | + snap_name="${snap_name%%_*}" |
| 216 | +
|
| 217 | + component_args=() |
| 218 | + shopt -s nullglob |
| 219 | + for component in "${snap_name}"+*.comp; do |
| 220 | + echo "Adding component: $component" |
| 221 | + component_args+=(--component "$component") |
| 222 | + done |
| 223 | +
|
| 224 | + echo "Uploading $snap_file to ${INPUTS_UPLOAD_CHANNEL}" |
| 225 | + snapcraft upload --release "${INPUTS_UPLOAD_CHANNEL}" "$snap_file" "${component_args[@]}" |
0 commit comments