Skip to content

Commit

Permalink
chore(ci): Build/publish Docker images used to create AppImages
Browse files Browse the repository at this point in the history
This follows what was done in commit 51ba67b, but for AppImages.
  • Loading branch information
guihkx committed Sep 12, 2024
1 parent 589eea2 commit da974a8
Show file tree
Hide file tree
Showing 6 changed files with 375 additions and 201 deletions.
184 changes: 60 additions & 124 deletions .github/workflows/linux.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ on:
workflow_dispatch:

env:
APP_ID: io.github.nuttyartist.notes
REGISTRY: ghcr.io

jobs:
Expand Down Expand Up @@ -195,156 +194,93 @@ jobs:
name: ${{ steps.rpm.outputs.name }}-qt${{ matrix.qt-version-major }}-${{ steps.vars.outputs.distro_name }}-${{ matrix.build-type }}
path: ${{ steps.rpm.outputs.path }}

# Build the AppImage using official Qt releases, downloaded by aqtinstall.
# This is also done for macOS and Windows, just to make sure we use the exact same Qt version across all three OSes.
#
# NOTE: This job uses a fixed Qt version (set in the 'qt-version' key below)!
# So, remember to keep it updated whenever a new Qt version is available on aqtinstall.
appimage-aqtinstall:
name: AppImage (${{ matrix.build-type }}, Qt ${{ matrix.qt-version }}, ${{ matrix.image }})
runs-on: ${{ matrix.os }}
container:
image: zjeffer/notes:${{ matrix.image }}
appimage:
name: AppImage (${{ matrix.build-type }}, Qt ${{ matrix.qt-version-major }}, ${{ matrix.image }})
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
include:
- os: ubuntu-22.04
- image: appimage-qt5
qt-version-major: 5
build-type: release
qt-version: 5.15.2
image: ubuntu-aqtinstall-5

- os: ubuntu-22.04

- image: appimage-qt6
qt-version-major: 6
build-type: release
qt-version: 6.4.3
image: ubuntu-aqtinstall-6
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
submodules: recursive

- name: Setup variables
shell: bash
id: vars
- name: Check if Dockerfile has been modified
id: docker_image
run: |
set -x
version=$(grep -oPm1 '\bAPP_VERSION +\K[^)]+' CMakeLists.txt)
if [ -z "${version}" ]
then
echo 'Failed to extract app version from CMakeLists.txt.'
exit 1
fi
if [ '${{ github.ref_type }}' != 'tag' ]
set -ex
git remote add upstream https://github.com/nuttyartist/notes.git
git fetch --unshallow upstream master
# NOTE: The following should give us the previous commit hash of the base branch, but that will
# only work reliably for 'push' and pull_request events. For workflow_dispatch events, we
# have to fallback to the default branch ('master'), until a better solution is found...
previous_ref=${{ github.event.pull_request.base.sha || github.event.before || 'upstream/master' }}
if ! git diff --compact-summary --exit-code "${previous_ref}" -- 'Dockerfiles/${{ matrix.image }}'
then
version="${version}+g${GITHUB_SHA::7}"
fi
artifact_name="Notes_${version}-Qt${{ matrix.qt-version }}-x86_64"
if [ '${{ matrix.build-type }}' == 'debug' ]
needs_rebuild=true
elif ! docker pull '${{ env.REGISTRY }}/nuttyartist/notes:${{ matrix.image }}'
then
file_name="${artifact_name}-debug.AppImage"
needs_rebuild=true
else
file_name="${artifact_name}.AppImage"
needs_rebuild=false
fi
echo "version=${version}" >> "${GITHUB_OUTPUT}"
echo "artifact_name=${artifact_name}" >> "${GITHUB_OUTPUT}"
echo "file_name=${file_name}" >> "${GITHUB_OUTPUT}"
# TODO: Figure out why this error only occurs on the Linux container when building with -DGIT_REVISION=ON
# The error: fatal: detected dubious ownership in repository
- name: Prevent git's dubious ownership message
if: github.ref_type != 'tag'
run: |
git config --global --add safe.directory "${PWD}"
- name: Build (${{ matrix.build-type }})
env:
VERBOSE: 1
run: |
cmake --warn-uninitialized --warn-unused-vars \
-B build \
-DCMAKE_BUILD_TYPE=${{ matrix.build-type }} \
-DGIT_REVISION=${{ github.ref_type != 'tag' && 'ON' || 'OFF' }} \
-DCMAKE_INSTALL_PREFIX=/usr \
-DPRO_VERSION=OFF
cmake --build build --parallel $(nproc)
- name: (FIXME) Run qmllint
if: startsWith(matrix.qt-version, '6.')
run: |
cmake --build build --target all_qmllint || true
echo "needs_rebuild=${needs_rebuild}" >> "${GITHUB_OUTPUT}"
- name: Install (${{ matrix.build-type }})
run: |
make -C build DESTDIR=Notes install
- name: Build and tag Docker image
if: steps.docker_image.outputs.needs_rebuild == 'true'
run: docker build -f 'Dockerfiles/${{ matrix.image }}' -t '${{ env.REGISTRY }}/nuttyartist/notes:${{ matrix.image }}' .

- name: Setup linuxdeploy
run: |
cd build
curl -fLO --retry 10 https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous/linuxdeploy-x86_64.AppImage
chmod +x linuxdeploy-x86_64.AppImage
- name: Setup GCC problem matcher
uses: ammaraskar/[email protected]

- name: Setup Qt plugin for linuxdeploy
run: |
cd build
curl -fLO --retry 10 https://github.com/linuxdeploy/linuxdeploy-plugin-qt/releases/download/continuous/linuxdeploy-plugin-qt-x86_64.AppImage
chmod +x linuxdeploy-plugin-qt-x86_64.AppImage
- name: Build, package and lint
id: build
run: docker run --rm -v "${GITHUB_OUTPUT}:/GITHUB_OUTPUT" -v "$(pwd):/src" -t '${{ env.REGISTRY }}/nuttyartist/notes:${{ matrix.image }}' -t ${{ matrix.build-type }} ${{ github.ref_type == 'tag' && '-n' || ' ' }}

- name: Deploy (${{ matrix.build-type }})
env:
APPIMAGE_EXTRACT_AND_RUN: 1
run: |
export QML_SOURCES_PATHS="${PWD}/src/qml"
cd build
./linuxdeploy-x86_64.AppImage --appdir Notes --plugin qt
- name: (FIXME) Run qmllint
if: endsWith(matrix.image, 'qt6')
run: docker run --rm -v "$(pwd):/src" --entrypoint '' -t '${{ env.REGISTRY }}/nuttyartist/notes:${{ matrix.image }}' cmake --build build --target all_qmllint || true

- name: Remove unnecessary Qt plugins and libraries
shell: bash
run: |
set -x
set -e
cd build/Notes
if [[ '${{ matrix.qt-version }}' == 5.* ]]
then
# The bearer plugin has caused problems for us in the past. Plus, it was removed altogether in Qt 6.
rm -rv usr/plugins/bearer
fi
# We only use the SQLite Qt driver, so it's fine to delete others.
rm -v usr/plugins/sqldrivers/libqsqlodbc.so
rm -v usr/plugins/sqldrivers/libqsqlpsql.so
if [[ '${{ matrix.qt-version }}' == 6.* ]]
then
# The Qt 6 build also has a MySQL Qt driver we don't use.
rm -v usr/plugins/sqldrivers/libqsqlmysql.so
rm -v usr/lib/libmysqlclient.so.*
fi
- name: Upload AppImage artifact
uses: actions/upload-artifact@v4
with:
if-no-files-found: error
name: ${{ steps.build.outputs.artifact_name }}-${{ runner.os }}-${{ matrix.build-type }}
path: ${{ steps.build.outputs.appimage_path }}

- name: Validate AppStream metadata
if: matrix.image != 'ubuntu:20.04'
run: |
cd build/Notes
appstreamcli validate --verbose 'usr/share/metainfo/${{ env.APP_ID }}.metainfo.xml'
- name: Login to GitHub Container Registry
if: ${{ steps.docker_image.outputs.needs_rebuild == 'true' && github.repository == 'nuttyartist/notes' && github.event_name != 'pull_request' && github.ref_name == 'master' }}
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Validate desktop file
run: |
cd build/Notes
desktop-file-validate 'usr/share/applications/${{ env.APP_ID }}.desktop'
- name: Extract metadata (tags, labels) for Docker
if: ${{ steps.docker_image.outputs.needs_rebuild == 'true' && github.repository == 'nuttyartist/notes' && github.event_name != 'pull_request' && github.ref_name == 'master' }}
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/nuttyartist/notes:${{ matrix.image }}

- name: Build AppImage (${{ matrix.build-type }})
- name: Build and push Docker image
if: ${{ steps.docker_image.outputs.needs_rebuild == 'true' && github.repository == 'nuttyartist/notes' && github.event_name != 'pull_request' && github.ref_name == 'master' }}
uses: docker/build-push-action@v6
env:
APPIMAGE_EXTRACT_AND_RUN: 1
run: |
cd build
export VERSION='${{ steps.vars.outputs.version }}'
./linuxdeploy-x86_64.AppImage --appdir Notes --output appimage
mv -v Notes*.AppImage '${{ steps.vars.outputs.file_name }}'
- name: Upload AppImage artifact (${{ matrix.build-type }})
uses: actions/upload-artifact@v4
DOCKER_BUILD_SUMMARY: false
with:
if-no-files-found: error
name: ${{ steps.vars.outputs.artifact_name }}-${{ runner.os }}-${{ matrix.build-type }}
path: build/${{ steps.vars.outputs.file_name }}
file: Dockerfiles/${{ matrix.image }}
push: true
tags: ${{ env.REGISTRY }}/nuttyartist/notes:${{ matrix.image }}

snap:
name: snap
Expand Down
83 changes: 83 additions & 0 deletions Dockerfiles/appimage-qt5
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
# vim: set syntax=dockerfile:
FROM ubuntu:20.04

LABEL org.opencontainers.image.description="Base image used to build Notes with Qt 5 and AppImage-package it"

ENV QT_VERSION=5.15.2
ENV QT_ARCHITECTURE=gcc_64

# Prevent tzdata from asking for input.
ARG DEBIAN_FRONTEND=noninteractive

# Install all required dependencies:
#
# - appstream: Used to validate the AppStream metadata file.
# - cmake: Used to help build the application.
# - desktop-file-utils: Used to validate the desktop file.
# - file: Required by linuxdeploy.
# - git: Used to clone this repository.
# - g++: Used to compile the application.
# - libdbus-1-3: libQt5DBus links against this library.
# - libegl1: Used as dependency of the resulting AppImage.
# - libfontconfig1: Used as dependency of the resulting AppImage.
# - libglib2.0-0: The iuc binary included with Qt 5 links against this library.
# - libgl-dev: OpenGL headers needed at build time by Qt 6.
# - libxcb-icccm4: Used as dependency of the resulting AppImage.
# - libxcb-image0: Used as dependency of the resulting AppImage.
# - libxcb-keysyms1: Used as dependency of the resulting AppImage.
# - libxcb-randr0: Used as dependency of the resulting AppImage.
# - libxcb-render-util0: Used as dependency of the resulting AppImage.
# - libxcb-shape0: Used as dependency of the resulting AppImage.
# - libxcb-xinerama0: Used as dependency of the resulting AppImage.
# - libxcb-xkb1: Used as dependency of the resulting AppImage.
# - libxkbcommon-x11-0: Used as dependency of the resulting AppImage.
# - make: Used to help build the application.
# - python3/python3-pip: Used to install and run aqtinstall.
RUN apt-get update && \
apt-get install -y --no-install-recommends appstream cmake desktop-file-utils file git g++ libdbus-1-3 \
libegl1 libfontconfig1 libglib2.0-0 libgl-dev libxcb-icccm4 libxcb-image0 libxcb-keysyms1 libxcb-randr0 \
libxcb-render-util0 libxcb-shape0 libxcb-xinerama0 libxcb-xkb1 libxkbcommon-x11-0 make python3 python3-pip && \
apt-get clean && \
rm -rf /var/lib/apt/lists

# Install Qt using aqtinstall.
RUN python3 -m pip install aqtinstall && \
rm -rf ~/.cache

# Download the specified Qt version using aqtinstall.
RUN python3 -m aqt install-qt --outputdir /Qt linux desktop "$QT_VERSION" "$QT_ARCHITECTURE" && \
rm -f aqtinstall.log

# Qt 5 ships with a variety of SQL drivers, but we only need the SQLite one, so here we symlink all
# the other drivers to it, in order to avoid having to install their dependencies for no reason.
# This is a workaround for: https://github.com/linuxdeploy/linuxdeploy-plugin-qt/issues/153
RUN for driver in libqsqlodbc libqsqlpsql; do \
ln -fsv libqsqlite.so "/Qt/$QT_VERSION/$QT_ARCHITECTURE/plugins/sqldrivers/$driver.so"; \
done

# Download linuxdeploy and its Qt plugin:
ADD --chmod=755 https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous/linuxdeploy-x86_64.AppImage /usr/bin/linuxdeploy
ADD --chmod=755 https://github.com/linuxdeploy/linuxdeploy-plugin-qt/releases/download/continuous/linuxdeploy-plugin-qt-x86_64.AppImage /usr/bin/linuxdeploy-plugin-qt

# Note's app ID on Linux.
ENV APP_ID="io.github.nuttyartist.notes"
# Other environment variables expected by CMake and linuxdeploy.
ENV APPIMAGE_EXTRACT_AND_RUN=1
ENV DISABLE_COPYRIGHT_FILES_DEPLOYMENT=1
ENV LD_LIBRARY_PATH="/Qt/$QT_VERSION/$QT_ARCHITECTURE/lib"
ENV PATH="/Qt/$QT_VERSION/$QT_ARCHITECTURE/bin:$PATH"
ENV PKG_CONFIG_PATH="/Qt/$QT_VERSION/$QT_ARCHITECTURE/lib/pkgconfig"
ENV QML2_IMPORT_PATH="/Qt/$QT_VERSION/$QT_ARCHITECTURE/qml"
ENV QML_SOURCES_PATHS="/src/src/qml"
ENV Qt5_DIR="/Qt/$QT_VERSION/$QT_ARCHITECTURE"
ENV QT_PLUGIN_PATH="/Qt/$QT_VERSION/$QT_ARCHITECTURE/plugins"

# Prevent a fatal error from git: "detected dubious ownership in repository at '/src'".
RUN git config --global --add safe.directory /src

# Don't forget to mount the current git tree to /src, i.e.:
# docker run -v $(pwd):/src -it --rm ...
WORKDIR /src

ADD --chmod=755 ./Dockerfiles/appimage_entrypoint.sh /usr/bin/entrypoint.sh
ENTRYPOINT ["entrypoint.sh"]
87 changes: 87 additions & 0 deletions Dockerfiles/appimage-qt6
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
# vim: set syntax=dockerfile:
FROM ubuntu:22.04

LABEL org.opencontainers.image.description="Base image used to build Notes with Qt 6 and AppImage-package it"

ENV QT_VERSION=6.4.3
ENV QT_ARCHITECTURE=gcc_64

# Prevent tzdata from asking for input.
ARG DEBIAN_FRONTEND=noninteractive

# Install all required dependencies:
#
# - appstream: Used to validate the AppStream metadata file.
# - cmake: Used to help build the application.
# - desktop-file-utils: Used to validate the desktop file.
# - file: Required by linuxdeploy.
# - git: Used to clone this repository.
# - g++: Used to compile the application.
# - libdbus-1-3: libQt6DBus links against this library.
# - libegl1: libQt6Gui links against this library.
# - libfontconfig1: Used as dependency of the resulting AppImage.
# - libgl-dev: OpenGL headers needed at build time by Qt 6.
# - libxcb-cursor0: Used as dependency of the resulting AppImage.
# - libxcb-icccm4: Used as dependency of the resulting AppImage.
# - libxcb-keysyms1: Used as dependency of the resulting AppImage.
# - libxcb-shape0: Used as dependency of the resulting AppImage.
# - libxkbcommon-dev: XKB headers needed at build time by Qt 6.
# - libxkbcommon-x11-0: Used as dependency of the resulting AppImage.
# - make: Used to help build the application.
# - python3/python3-pip: Used to install and run aqtinstall.
RUN apt-get update && \
apt-get install -y --no-install-recommends appstream cmake desktop-file-utils file git g++ libdbus-1-3 \
libegl1 libfontconfig1 libgl-dev libxcb-cursor0 libxcb-icccm4 libxcb-keysyms1 libxcb-shape0 \
libxkbcommon-dev libxkbcommon-x11-0 make python3 python3-pip && \
# TODO: Remove the next 4 lines when targeting Qt 6.5+, which doesn't require libssl 1.1.
echo 'deb http://security.ubuntu.com/ubuntu focal-security main' > /etc/apt/sources.list.d/focal-security.list && \
apt-get update && \
apt-get install libssl1.1 && \
rm /etc/apt/sources.list.d/focal-security.list && \
apt-get clean && \
rm -rf /var/lib/apt/lists

# Prevent warnings from uic while compiling the app.
ENV LANG=C.UTF-8

# Install Qt using aqtinstall.
RUN python3 -m pip install aqtinstall && \
rm -rf ~/.cache

# Download the specified Qt version using aqtinstall.
RUN python3 -m aqt install-qt --outputdir /Qt linux desktop "$QT_VERSION" "$QT_ARCHITECTURE" && \
rm -f aqtinstall.log

# Qt 6 ships with a variety of SQL drivers, but we only need the SQLite one, so here we symlink all
# the other drivers to it, in order to avoid having to install their dependencies for no reason.
# This is a workaround for: https://github.com/linuxdeploy/linuxdeploy-plugin-qt/issues/153
RUN for driver in libqsqlmimer libqsqlmysql libqsqlodbc libqsqlpsql; do \
ln -fsv libqsqlite.so "/Qt/$QT_VERSION/$QT_ARCHITECTURE/plugins/sqldrivers/$driver.so"; \
done

# Download linuxdeploy and its Qt plugin.
ADD --chmod=755 https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous/linuxdeploy-x86_64.AppImage /usr/bin/linuxdeploy
ADD --chmod=755 https://github.com/linuxdeploy/linuxdeploy-plugin-qt/releases/download/continuous/linuxdeploy-plugin-qt-x86_64.AppImage /usr/bin/linuxdeploy-plugin-qt

# Note's app ID on Linux.
ENV APP_ID="io.github.nuttyartist.notes"
# Other environment variables expected by CMake and linuxdeploy.
ENV APPIMAGE_EXTRACT_AND_RUN=1
ENV DISABLE_COPYRIGHT_FILES_DEPLOYMENT=1
ENV LD_LIBRARY_PATH="/Qt/$QT_VERSION/$QT_ARCHITECTURE/lib"
ENV PATH="/Qt/$QT_VERSION/$QT_ARCHITECTURE/bin:$PATH"
ENV PKG_CONFIG_PATH="/Qt/$QT_VERSION/$QT_ARCHITECTURE/lib/pkgconfig"
ENV QML2_IMPORT_PATH="/Qt/$QT_VERSION/$QT_ARCHITECTURE/qml"
ENV QML_SOURCES_PATHS="/src/src/qml"
ENV Qt6_DIR="/Qt/$QT_VERSION/$QT_ARCHITECTURE"
ENV QT_PLUGIN_PATH="/Qt/$QT_VERSION/$QT_ARCHITECTURE/plugins"

# Prevent a fatal error from git: "detected dubious ownership in repository at '/src'".
RUN git config --global --add safe.directory /src

# Don't forget to mount the current git tree to /src, i.e.:
# docker run -v $(pwd):/src -it --rm ...
WORKDIR /src

ADD --chmod=755 ./Dockerfiles/appimage_entrypoint.sh /usr/bin/entrypoint.sh
ENTRYPOINT ["entrypoint.sh"]
Loading

0 comments on commit da974a8

Please sign in to comment.