Add Android and Linux desktop SDK variants with matrix pipelines

Adds Dockerfile.android (Flutter + Android SDK/JDK 17) and
Dockerfile.linux (Flutter + clang/cmake/GTK3 for desktop builds).
Publish and Scout pipelines now use matrix strategy to build all
three variants in parallel. Registry secrets updated to
REGISTRY_USERNAME/REGISTRY_PASSWORD. Update-check adds explicit
stable channel filter.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Mathias Beaulieu-Duncan 2026-02-02 00:57:40 -05:00
parent 8d48dcc5fd
commit 34c649cbda
5 changed files with 179 additions and 42 deletions

View File

@ -7,12 +7,21 @@ on:
permissions: permissions:
contents: read contents: read
env:
IMAGE_NAME: gpb-flutter-sdk-web
jobs: jobs:
build-and-push: build-and-push:
runs-on: ubuntu-latest runs-on: ubuntu-latest
strategy:
matrix:
include:
- dockerfile: Dockerfile
image_name: gpb-flutter-sdk-web
description: Minimal Flutter SDK for Web/WASM CI builds
- dockerfile: Dockerfile.android
image_name: gpb-flutter-sdk-android
description: Flutter SDK for Android CI builds
- dockerfile: Dockerfile.linux
image_name: gpb-flutter-sdk-linux
description: Flutter SDK for Linux desktop CI builds
steps: steps:
- name: Checkout code - name: Checkout code
uses: actions/checkout@v3 uses: actions/checkout@v3
@ -32,19 +41,20 @@ jobs:
- name: Login to Docker Registry - name: Login to Docker Registry
uses: docker/login-action@v3 uses: docker/login-action@v3
with: with:
username: ${{ secrets.DOCKERHUB_SVRNTY_USERNAME }} username: ${{ secrets.REGISTRY_USERNAME }}
password: ${{ secrets.DOCKERHUB_SVRNTY_ACCESS_TOKEN }} password: ${{ secrets.REGISTRY_PASSWORD }}
- name: Build image for Scout analysis - name: Build image for Scout analysis
uses: docker/build-push-action@v5 uses: docker/build-push-action@v5
with: with:
context: . context: .
file: ${{ matrix.dockerfile }}
platforms: linux/amd64 platforms: linux/amd64
push: false push: false
load: true load: true
build-args: | build-args: |
FLUTTER_VERSION=${{ github.event.release.tag_name }} FLUTTER_VERSION=${{ github.event.release.tag_name }}
tags: ${{ vars.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.event.release.tag_name }} tags: ${{ vars.REGISTRY }}/${{ matrix.image_name }}:${{ github.event.release.tag_name }}
- name: Install Docker Scout - name: Install Docker Scout
run: | run: |
@ -53,12 +63,13 @@ jobs:
- name: Docker Scout CVE Scan - name: Docker Scout CVE Scan
run: | run: |
docker scout cves ${{ vars.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.event.release.tag_name }} --only-severity critical,high docker scout cves ${{ vars.REGISTRY }}/${{ matrix.image_name }}:${{ github.event.release.tag_name }} --only-severity critical,high
- name: Build and push with attestations - name: Build and push with attestations
uses: docker/build-push-action@v5 uses: docker/build-push-action@v5
with: with:
context: . context: .
file: ${{ matrix.dockerfile }}
platforms: linux/amd64 platforms: linux/amd64
push: true push: true
sbom: true sbom: true
@ -66,10 +77,10 @@ jobs:
build-args: | build-args: |
FLUTTER_VERSION=${{ github.event.release.tag_name }} FLUTTER_VERSION=${{ github.event.release.tag_name }}
tags: | tags: |
${{ vars.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.event.release.tag_name }} ${{ vars.REGISTRY }}/${{ matrix.image_name }}:${{ github.event.release.tag_name }}
${{ vars.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.tag_type.outputs.tag }} ${{ vars.REGISTRY }}/${{ matrix.image_name }}:${{ steps.tag_type.outputs.tag }}
labels: | labels: |
org.opencontainers.image.title=${{ env.IMAGE_NAME }} org.opencontainers.image.title=${{ matrix.image_name }}
org.opencontainers.image.description=Minimal Flutter SDK for Web/WASM CI builds org.opencontainers.image.description=${{ matrix.description }}
org.opencontainers.image.version=${{ github.event.release.tag_name }} org.opencontainers.image.version=${{ github.event.release.tag_name }}
org.opencontainers.image.revision=${{ github.sha }} org.opencontainers.image.revision=${{ github.sha }}

View File

@ -8,63 +8,62 @@ permissions:
contents: read contents: read
pull-requests: write pull-requests: write
env:
IMAGE_NAME: gpb-flutter-sdk-web
jobs: jobs:
check-image: scout:
runs-on: ubuntu-latest runs-on: ubuntu-latest
outputs: strategy:
image_exists: ${{ steps.check.outputs.exists }} matrix:
include:
- dockerfile: Dockerfile
image_name: gpb-flutter-sdk-web
- dockerfile: Dockerfile.android
image_name: gpb-flutter-sdk-android
- dockerfile: Dockerfile.linux
image_name: gpb-flutter-sdk-linux
steps: steps:
- name: Log in to DockerHub - name: Log in to DockerHub
uses: docker/login-action@v3 uses: docker/login-action@v3
with: with:
username: ${{ secrets.DOCKERHUB_SVRNTY_USERNAME }} username: ${{ secrets.REGISTRY_USERNAME }}
password: ${{ secrets.DOCKERHUB_SVRNTY_ACCESS_TOKEN }} password: ${{ secrets.REGISTRY_PASSWORD }}
- name: Check if latest image exists - name: Check if latest image exists
id: check id: should_run
run: | run: |
if docker manifest inspect ${{ vars.REGISTRY }}/${{ env.IMAGE_NAME }}:latest > /dev/null 2>&1; then if docker manifest inspect ${{ vars.REGISTRY }}/${{ matrix.image_name }}:latest > /dev/null 2>&1; then
echo "exists=true" >> $GITHUB_OUTPUT echo "run=true" >> $GITHUB_OUTPUT
echo "Latest image found, Scout compare will run" echo "Latest ${{ matrix.image_name }} found, Scout compare will run"
else else
echo "exists=false" >> $GITHUB_OUTPUT echo "run=false" >> $GITHUB_OUTPUT
echo "No latest image found, skipping Scout compare (nothing to compare against)" echo "No latest ${{ matrix.image_name }} found, skipping (nothing to compare against)"
fi fi
scout-amd64:
runs-on: ubuntu-latest
needs: check-image
if: needs.check-image.outputs.image_exists == 'true'
steps:
- name: Checkout code - name: Checkout code
if: steps.should_run.outputs.run == 'true'
uses: actions/checkout@v3 uses: actions/checkout@v3
- name: Set up Docker Buildx - name: Set up Docker Buildx
if: steps.should_run.outputs.run == 'true'
uses: docker/setup-buildx-action@v3 uses: docker/setup-buildx-action@v3
- name: Log in to DockerHub - name: Build image
uses: docker/login-action@v3 if: steps.should_run.outputs.run == 'true'
with:
username: ${{ secrets.DOCKERHUB_SVRNTY_USERNAME }}
password: ${{ secrets.DOCKERHUB_SVRNTY_ACCESS_TOKEN }}
- name: Build amd64 image
uses: docker/build-push-action@v5 uses: docker/build-push-action@v5
with: with:
context: . context: .
file: ${{ matrix.dockerfile }}
platforms: linux/amd64 platforms: linux/amd64
push: false push: false
load: true load: true
tags: ${{ vars.REGISTRY }}/${{ env.IMAGE_NAME }}:pr-${{ github.event.pull_request.number }}-amd64 tags: ${{ vars.REGISTRY }}/${{ matrix.image_name }}:pr-${{ github.event.pull_request.number }}
- name: Install Docker Scout - name: Install Docker Scout
if: steps.should_run.outputs.run == 'true'
run: | run: |
curl -fsSL https://raw.githubusercontent.com/docker/scout-cli/main/install.sh -o install-scout.sh curl -fsSL https://raw.githubusercontent.com/docker/scout-cli/main/install.sh -o install-scout.sh
sh install-scout.sh sh install-scout.sh
- name: Docker Scout Compare (amd64) - name: Docker Scout Compare
if: steps.should_run.outputs.run == 'true'
run: | run: |
docker scout compare ${{ vars.REGISTRY }}/${{ env.IMAGE_NAME }}:pr-${{ github.event.pull_request.number }}-amd64 --to ${{ vars.REGISTRY }}/${{ env.IMAGE_NAME }}:latest --ignore-unchanged --only-severity critical,high docker scout compare ${{ vars.REGISTRY }}/${{ matrix.image_name }}:pr-${{ github.event.pull_request.number }} --to ${{ vars.REGISTRY }}/${{ matrix.image_name }}:latest --ignore-unchanged --only-severity critical,high

View File

@ -12,8 +12,8 @@ jobs:
- name: Get latest Flutter stable version - name: Get latest Flutter stable version
id: flutter id: flutter
run: | run: |
LATEST=$(curl -fsSL https://storage.googleapis.com/flutter_infra_release/releases/releases_linux.json \ RESPONSE=$(curl -fsSL https://storage.googleapis.com/flutter_infra_release/releases/releases_linux.json)
| jq -r '.current_release.stable as $hash | .releases[] | select(.hash == $hash) | .version') LATEST=$(echo "$RESPONSE" | jq -r '.current_release.stable as $hash | .releases[] | select(.hash == $hash and .channel == "stable") | .version')
echo "version=${LATEST}" >> $GITHUB_OUTPUT echo "version=${LATEST}" >> $GITHUB_OUTPUT
echo "Latest Flutter stable: ${LATEST}" echo "Latest Flutter stable: ${LATEST}"

72
Dockerfile.android Normal file
View File

@ -0,0 +1,72 @@
FROM debian:bookworm-slim
ARG FLUTTER_VERSION=3.38.9
ARG ANDROID_SDK_TOOLS_VERSION=11076708
ARG ANDROID_COMPILE_SDK=35
ARG ANDROID_BUILD_TOOLS=35.0.1
LABEL org.opencontainers.image.title="gpb-flutter-sdk-android"
LABEL org.opencontainers.image.description="Flutter SDK for Android CI builds"
LABEL org.opencontainers.image.version="${FLUTTER_VERSION}"
# Install dependencies for Flutter + Android SDK
RUN apt-get update && apt-get install -y --no-install-recommends \
curl \
git \
unzip \
xz-utils \
ca-certificates \
openjdk-17-jdk-headless \
&& rm -rf /var/lib/apt/lists/*
# Android SDK
ENV ANDROID_HOME=/opt/android-sdk
ENV PATH="${ANDROID_HOME}/cmdline-tools/latest/bin:${ANDROID_HOME}/platform-tools:${PATH}"
RUN mkdir -p "${ANDROID_HOME}/cmdline-tools" && \
curl -fsSL "https://dl.google.com/android/repository/commandlinetools-linux-${ANDROID_SDK_TOOLS_VERSION}_latest.zip" \
-o /tmp/cmdline-tools.zip && \
unzip -q /tmp/cmdline-tools.zip -d /tmp/cmdline-tools && \
mv /tmp/cmdline-tools/cmdline-tools "${ANDROID_HOME}/cmdline-tools/latest" && \
rm -rf /tmp/cmdline-tools.zip /tmp/cmdline-tools
# Accept licenses and install SDK components
RUN yes | sdkmanager --licenses > /dev/null 2>&1 && \
sdkmanager --install \
"platform-tools" \
"platforms;android-${ANDROID_COMPILE_SDK}" \
"build-tools;${ANDROID_BUILD_TOOLS}"
# Flutter SDK
ENV FLUTTER_HOME=/opt/flutter
ENV PATH="${FLUTTER_HOME}/bin:${FLUTTER_HOME}/bin/cache/dart-sdk/bin:${PATH}"
RUN curl -fsSL "https://storage.googleapis.com/flutter_infra_release/releases/stable/linux/flutter_linux_${FLUTTER_VERSION}-stable.tar.xz" \
-o /tmp/flutter.tar.xz && \
tar xf /tmp/flutter.tar.xz -C /opt && \
rm /tmp/flutter.tar.xz
RUN git config --global --add safe.directory "${FLUTTER_HOME}"
# Configure for Android-only
RUN flutter config --enable-android \
--no-enable-web \
--no-enable-ios \
--no-enable-linux-desktop \
--no-enable-macos-desktop \
--no-enable-windows-desktop \
--android-sdk "${ANDROID_HOME}"
# Precache only Android artifacts
RUN flutter precache --android \
--no-web \
--no-ios \
--no-linux \
--no-macos \
--no-windows \
--no-fuchsia \
--no-universal
RUN flutter doctor -v
WORKDIR /app

55
Dockerfile.linux Normal file
View File

@ -0,0 +1,55 @@
FROM debian:bookworm-slim
ARG FLUTTER_VERSION=3.38.9
LABEL org.opencontainers.image.title="gpb-flutter-sdk-linux"
LABEL org.opencontainers.image.description="Flutter SDK for Linux desktop CI builds"
LABEL org.opencontainers.image.version="${FLUTTER_VERSION}"
# Install dependencies for Flutter + Linux desktop builds
RUN apt-get update && apt-get install -y --no-install-recommends \
curl \
git \
unzip \
xz-utils \
ca-certificates \
clang \
cmake \
ninja-build \
pkg-config \
libgtk-3-dev \
liblzma-dev \
libstdc++-12-dev \
&& rm -rf /var/lib/apt/lists/*
ENV FLUTTER_HOME=/opt/flutter
ENV PATH="${FLUTTER_HOME}/bin:${FLUTTER_HOME}/bin/cache/dart-sdk/bin:${PATH}"
RUN curl -fsSL "https://storage.googleapis.com/flutter_infra_release/releases/stable/linux/flutter_linux_${FLUTTER_VERSION}-stable.tar.xz" \
-o /tmp/flutter.tar.xz && \
tar xf /tmp/flutter.tar.xz -C /opt && \
rm /tmp/flutter.tar.xz
RUN git config --global --add safe.directory "${FLUTTER_HOME}"
# Configure for Linux desktop only
RUN flutter config --enable-linux-desktop \
--no-enable-web \
--no-enable-android \
--no-enable-ios \
--no-enable-macos-desktop \
--no-enable-windows-desktop
# Precache only Linux artifacts
RUN flutter precache --linux \
--no-web \
--no-android \
--no-ios \
--no-macos \
--no-windows \
--no-fuchsia \
--no-universal
RUN flutter doctor -v
WORKDIR /app