Skip to content
Draft
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
179 changes: 179 additions & 0 deletions .github/workflows/deb-package.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
name: Build .deb Packages

on:
push:
tags:
- "v*"
pull_request:
branches:
- main
paths:
- ".github/workflows/deb-package.yml"
- "CMakeLists.txt"
- "cmake/**"
workflow_dispatch:
inputs:
tag:
description: "Release tag (e.g. v1.2.3) — leave blank to build a test package"
required: false

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

jobs:
build-deb:
name: Build .deb (${{ matrix.distro.label }})
runs-on: ubuntu-latest
container:
image: ${{ matrix.distro.image }}
permissions:
contents: write

strategy:
fail-fast: false
matrix:
distro:
- label: ubuntu-22.04
image: ubuntu:22.04
codename: jammy
qt_svg_pkg: libqt6svg6-dev
- label: ubuntu-24.04
image: ubuntu:24.04
codename: noble
qt_svg_pkg: qt6-svg-dev
- label: debian-12
image: debian:bookworm
codename: bookworm
qt_svg_pkg: qt6-svg-dev

steps:
- name: Resolve tag
id: meta
shell: bash
env:
GITHUB_EVENT_NAME: ${{ github.event_name }}
INPUT_TAG: ${{ inputs.tag }}
GITHUB_REF_NAME: ${{ github.ref_name }}
run: |
set -euo pipefail
TAG=""
IS_RELEASE="false"

if [[ "$GITHUB_EVENT_NAME" == "workflow_dispatch" && -n "${INPUT_TAG:-}" ]]; then
TAG="$INPUT_TAG"
elif [[ "$GITHUB_EVENT_NAME" == "push" && "$GITHUB_REF_NAME" =~ ^v[0-9]+(\.[0-9]+)*$ ]]; then
TAG="$GITHUB_REF_NAME"
fi

if [[ -n "$TAG" ]]; then
if ! [[ "$TAG" =~ ^v[0-9]+(\.[0-9]+)*$ ]]; then
echo "Tag '$TAG' does not match expected format (e.g. v1.2.3)." >&2
exit 1
fi
VERSION="${TAG#v}"
IS_RELEASE="true"
else
VERSION="0.0.0~test"
fi

echo "tag=$TAG" >> "$GITHUB_OUTPUT"
echo "version=$VERSION" >> "$GITHUB_OUTPUT"
echo "version_tag=v${VERSION}" >> "$GITHUB_OUTPUT"
echo "is_release=$IS_RELEASE" >> "$GITHUB_OUTPUT"
echo "package=vicinae_${VERSION}_${{ matrix.distro.codename }}_amd64.deb" >> "$GITHUB_OUTPUT"

- name: Install git
env:
DEBIAN_FRONTEND: noninteractive
run: |
apt-get update -y
apt-get install -y --no-install-recommends git ca-certificates

- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
ref: ${{ steps.meta.outputs.tag || github.sha }}

- name: Install build dependencies
env:
DEBIAN_FRONTEND: noninteractive
run: |
apt-get install -y --no-install-recommends \
build-essential cmake ninja-build pkg-config curl \
libssl-dev libxml2-dev libminizip-dev libwayland-dev \
qt6-base-dev qt6-base-private-dev qt6-declarative-dev \
${{ matrix.distro.qt_svg_pkg }} qt6-wayland-dev \
libqalculate-dev \
dpkg-dev

- name: Install Node.js
env:
DEBIAN_FRONTEND: noninteractive
run: |
curl -fsSL https://deb.nodesource.com/setup_20.x | bash -
apt-get install -y nodejs

- name: Configure CMake
run: |
cmake -S . -B build -G Ninja \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_POLICY_VERSION_MINIMUM=3.5 \
-DVICINAE_PROVENANCE=deb_package \
-DVICINAE_GIT_TAG=${{ steps.meta.outputs.version_tag }} \
-DUSE_SYSTEM_PROTOBUF=OFF \
-DUSE_SYSTEM_ABSEIL=OFF \
-DUSE_SYSTEM_CMARK_GFM=OFF \
-DUSE_SYSTEM_LAYER_SHELL=OFF \
-DUSE_SYSTEM_KF6=OFF \
-DUSE_SYSTEM_QT_KEYCHAIN=OFF \
-DCMAKE_INSTALL_PREFIX=/usr

- name: Build
run: cmake --build build --parallel $(nproc)

- name: Package with CPack
run: |
cd build
cpack -G DEB -D CPACK_PACKAGE_FILE_NAME="${{ steps.meta.outputs.package }}"

- name: Verify .deb package
shell: bash
run: |
set -euo pipefail
DEB="build/${{ steps.meta.outputs.package }}"

echo "=== Checking package file ==="
test -s "$DEB" || { echo "ERROR: .deb file not found or empty: $DEB" >&2; exit 1; }
ls -lh "$DEB"

echo "=== Package metadata ==="
dpkg-deb --info "$DEB"

echo "=== Package contents ==="
dpkg-deb --contents "$DEB"

echo "=== Installing package ==="
apt-get install -y --no-install-recommends "./$DEB"

echo "=== Verifying installed files ==="
test -x /usr/bin/vicinae \
|| { echo "ERROR: /usr/bin/vicinae not found after install" >&2; exit 1; }
echo "OK: /usr/bin/vicinae is present"
test -x /usr/libexec/vicinae/vicinae-server \
|| { echo "ERROR: /usr/libexec/vicinae/vicinae-server not found after install" >&2; exit 1; }
echo "OK: /usr/libexec/vicinae/vicinae-server is present"

- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: ${{ steps.meta.outputs.package }}
path: build/${{ steps.meta.outputs.package }}

- name: Upload to GitHub Release
if: steps.meta.outputs.is_release == 'true'
uses: softprops/action-gh-release@v2
with:
tag_name: ${{ steps.meta.outputs.tag }}
files: build/${{ steps.meta.outputs.package }}
16 changes: 16 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -271,3 +271,19 @@ if (UNIX AND NOT APPLE)
make_directory(${SYSTEMD_USER_DIR})
install(FILES ./extra/vicinae.service DESTINATION ${SYSTEMD_USER_DIR})
endif()

# CPack .deb package configuration
string(REGEX REPLACE "^v" "" CPACK_PACKAGE_VERSION "${VICINAE_GIT_TAG}")
if(CPACK_PACKAGE_VERSION STREQUAL "")
set(CPACK_PACKAGE_VERSION "${PROJECT_VERSION}")
endif()
set(CPACK_PACKAGE_NAME "vicinae")
set(CPACK_PACKAGE_VENDOR "vicinaehq")
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "A focused launcher for your desktop")
set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/LICENSE")
set(CPACK_DEBIAN_PACKAGE_MAINTAINER "vicinaehq <contact@vicinaehq.com>")
set(CPACK_DEBIAN_PACKAGE_SECTION "utils")
set(CPACK_DEBIAN_PACKAGE_PRIORITY "optional")
set(CPACK_DEBIAN_PACKAGE_HOMEPAGE "https://github.com/vicinaehq/vicinae")
set(CPACK_DEBIAN_PACKAGE_SHLIBDEPS ON)
include(CPack)
35 changes: 35 additions & 0 deletions cmake/KF6.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,41 @@ include(FetchContent)
function(import_kf6)
set(BUILD_SHARED_LIBS OFF)
set(FETCHCONTENT_QUIET OFF)

# ECM (extra-cmake-modules) 6.x is required by the KF6 syntax-highlighting
# CMakeLists.txt but is not yet packaged as 6.x on Ubuntu 22/24 or Debian 12.
# Fetch the source; then replace the generated ECMConfig.cmake (which
# hard-codes install-tree paths that do not exist) with one that points
# directly to the ECM source-tree module directories.
FetchContent_Declare(
ECM
GIT_REPOSITORY https://invent.kde.org/frameworks/extra-cmake-modules
GIT_TAG v6.20.0
GIT_SHALLOW TRUE
EXCLUDE_FROM_ALL
)
FetchContent_MakeAvailable(ECM)

# Overwrite the broken build-tree ECMConfig.cmake with one that resolves
# module paths from the source directory (no installation required).
set(_ecm_modules "${ecm_SOURCE_DIR}/modules")
set(_ecm_find "${ecm_SOURCE_DIR}/find-modules")
set(_ecm_kde "${ecm_SOURCE_DIR}/kde-modules")
file(WRITE "${ecm_BINARY_DIR}/ECMConfig.cmake"
"set(ECM_VERSION \"6.20.0\")\n"
"set(ECM_VERSION_MAJOR 6)\n"
"set(ECM_VERSION_MINOR 20)\n"
"set(ECM_VERSION_PATCH 0)\n"
"set(ECM_MODULE_DIR \"${_ecm_modules}\")\n"
"set(ECM_FIND_MODULE_DIR \"${_ecm_find}\")\n"
"set(ECM_KDE_MODULE_DIR \"${_ecm_kde}\")\n"
"list(APPEND CMAKE_MODULE_PATH"
" \"${_ecm_modules}\""
" \"${_ecm_find}\""
" \"${_ecm_kde}\")\n"
)
set(ECM_DIR "${ecm_BINARY_DIR}" CACHE PATH "Path to ECMConfig.cmake" FORCE)

FetchContent_Declare(
KF6
GIT_REPOSITORY https://github.com/KDE/syntax-highlighting
Expand Down