Skip to content

Commit bda111b

Browse files
committed
QPI-UI: Upgrade the packaging to support 'rpm', 'apk', macOS and windows installers
1 parent 3014164 commit bda111b

12 files changed

Lines changed: 269 additions & 126 deletions

File tree

.github/workflows/ci.yml

Lines changed: 67 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@ concurrency:
1111
group: ci-${{ github.ref }}
1212
cancel-in-progress: true
1313

14+
env:
15+
RAW_VERSION: ${{ github.ref_name }}
16+
1417
jobs:
1518
# -------------------------------------------------------------------------
1619
# Core lint-and-test matrix (orchestrator + driver)
@@ -303,8 +306,55 @@ jobs:
303306
if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v') && vars.PUBLISH_GO_APP == 'true'
304307
permissions:
305308
contents: write
306-
env:
307-
RAW_VERSION: ${{ github.ref_name }}
309+
steps:
310+
- name: Checkout Code
311+
uses: actions/checkout@v4
312+
with:
313+
fetch-depth: 0
314+
315+
- name: Set up Go
316+
uses: actions/setup-go@v5
317+
with:
318+
go-version: '1.26.x'
319+
320+
- name: Set up Node.js
321+
uses: actions/setup-node@v4
322+
with:
323+
node-version: '20'
324+
325+
# Installs wixl (msitools) onto Ubuntu to compile the .msi package natively
326+
- name: Install MSI Packing Tooling
327+
run: sudo apt-get update && sudo apt-get install -y msitools
328+
329+
- name: Run GoReleaser
330+
uses: goreleaser/goreleaser-action@v6
331+
with:
332+
distribution: goreleaser
333+
version: latest
334+
args: release --clean --config qpi-ui/pkg/.goreleaser.yaml
335+
env:
336+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
337+
338+
# Compiles the real .msi Windows package from GoReleaser's output binary
339+
- name: Package Windows MSI Installer
340+
run: |
341+
VERSION="${RAW_VERSION#v}"
342+
sed -i "s/Version=\"[^\"]*\"/Version=\"${VERSION}\"/" qpi-ui/pkg/qpi.wxs
343+
wixl -v qpi-ui/pkg/qpi.wxs -o dist/qpi_windows_amd64.msi
344+
345+
# Appends the new MSI installer asset into the active GitHub release draft
346+
- name: Upload Windows MSI to Release
347+
uses: softprops/action-gh-release@v3
348+
with:
349+
files: dist/qpi_windows_amd64.msi
350+
351+
# Independent job to build the official Mac installer natively
352+
package-macos-pkg:
353+
needs: [publish-go-release]
354+
runs-on: macos-latest
355+
if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v') && vars.PUBLISH_GO_APP == 'true'
356+
permissions:
357+
contents: write
308358
steps:
309359
- name: Checkout Code
310360
uses: actions/checkout@v4
@@ -314,20 +364,25 @@ jobs:
314364
with:
315365
go-version: '1.26.x'
316366

317-
- name: Install zip utility
318-
run: sudo apt-get update && sudo apt-get install -y zip
367+
- name: Set up Node.js
368+
uses: actions/setup-node@v4
369+
with:
370+
node-version: '20'
319371

320-
- name: Generate Changelog
372+
- name: Build Dashboard & Mac Binary
321373
run: |
322-
VERSION=${RAW_VERSION#v}
323-
awk -v ver="$VERSION" '/^## \[/ { if ($0 ~ "^## \\[" ver "\\]") { flag=1; next } else { flag=0 } } flag' CHANGELOG.md > ${{ github.workspace }}-CHANGELOG.txt
374+
cd qpi-ui/internal/dashboard && npm ci && npm run build && cd ../..
375+
cd qpi-ui && GOOS=darwin GOARCH=amd64 go build -o ../qpi .
324376
325-
- name: Build Packages
377+
# Uses Apple's built-in tool suite to build the native component installer
378+
- name: Build Native macOS .pkg
326379
run: |
327-
make package VERSION=${RAW_VERSION#v}
380+
mkdir -p pkg_root/usr/local/bin
381+
cp qpi pkg_root/usr/local/bin/
382+
VERSION="${RAW_VERSION#v}"
383+
pkgbuild --identifier "com.sopherapps.qpi" --version "${VERSION}" --install-location "/" --root pkg_root qpi_macos_amd64.pkg
328384
329-
- name: Upload Binaries to Release
385+
- name: Upload macOS PKG to Release
330386
uses: softprops/action-gh-release@v3
331387
with:
332-
files: bin/dist/*
333-
body_path: ${{ github.workspace }}-CHANGELOG.txt
388+
files: qpi_macos_amd64.pkg

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@ and this project follows versions of format `{year}.{month}.{patch_number}`.
77

88
## [Unreleased]
99

10+
### Changed
11+
12+
- `qpi-ui`: Upgraded the packaging to support 'rpm', 'apk', macOS and windows installers.
13+
1014
## [0.0.14] - 2026-06-23
1115

1216
### Fixed

Makefile

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -176,11 +176,6 @@ format-py-client:
176176
# ---------------------------------------------------------------------------
177177
# Package / Publish targets
178178
# ---------------------------------------------------------------------------
179-
180-
package: build-dashboard
181-
@echo "Packaging Go application..."
182-
./scripts/package.sh $(VERSION)
183-
184179
package-js:
185180
@echo "Packaging JS client..."
186181
(cd qpi-client/js && npm ci && npm run build)

qpi-ui/pkg/.goreleaser.yaml

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
version: 2
2+
3+
project_name: qpi
4+
5+
before:
6+
hooks:
7+
- dir: qpi-ui/internal/dashboard
8+
cmd: npm ci
9+
env:
10+
- CYPRESS_INSTALL_BINARY=0
11+
- dir: qpi-ui/internal/dashboard
12+
cmd: npm run build
13+
- go mod tidy
14+
15+
builds:
16+
- id: qpi
17+
dir: qpi-ui
18+
main: .
19+
binary: qpi
20+
env:
21+
- CGO_ENABLED=0
22+
goos:
23+
- darwin
24+
- windows
25+
- linux
26+
goarch:
27+
- amd64
28+
- arm64
29+
ldflags:
30+
- -X 'main.Version={{.Tag}}'
31+
32+
archives:
33+
- id: qpi-archive
34+
name_template: "qpi-{{ .Version }}-{{ .Os }}-{{ .Arch }}"
35+
format_overrides:
36+
- goos: windows
37+
format: binary
38+
- goos: darwin
39+
format: binary
40+
files:
41+
- src: README.md
42+
- src: qpi-ui/LICENSE
43+
- src: qpi-ui/qpi.config.example.yml
44+
dst: qpi.config.example.yml
45+
46+
nfpms:
47+
- id: qpi-linux-packages
48+
package_name: qpi
49+
file_name_template: "qpi_{{ .Version }}_{{ .Arch }}"
50+
maintainer: "SopherApps <team.sopherapps@gmail.com>"
51+
description: |
52+
Quantum Processing Interface (QPI) Orchestrator
53+
QPI is a distributed quantum control stack architecture designed
54+
to control multiple Quantum Processing Units (QPUs).
55+
homepage: https://github.com/SopherApps/qpi
56+
section: utils
57+
priority: optional
58+
59+
# 1. Target all major Linux packaging flavors here:
60+
formats:
61+
- deb # Ubuntu, Debian, Pop!_OS, Mint
62+
- rpm # Fedora, RHEL, CentOS, Rocky Linux, openSUSE
63+
- apk # Alpine Linux (Note: Alpine uses OpenRC, not systemd, by default)
64+
65+
dependencies:
66+
- systemd: [deb, rpm]
67+
68+
contents:
69+
- dst: /usr/local/bin/qpi
70+
# For systemd systems (Debian/RPM)
71+
- src: qpi-ui/pkg/qpi.service
72+
dst: /lib/systemd/system/qpi.service
73+
74+
# For OpenRC systems (Alpine APK)
75+
- src: qpi-ui/pkg/qpi.initd
76+
dst: /etc/init.d/qpi
77+
file_info:
78+
mode: 0755 # Crucial: Init scripts must be executable
79+
80+
# Map the example config file to the live config destination
81+
- src: qpi-ui/qpi.config.example.yml
82+
dst: /etc/qpi.config.yml
83+
type: config # Protects the file from being overwritten blindly during package updates
84+
85+
# Life-cycle execution hooks for starting and updating the service
86+
scripts:
87+
postinstall: qpi-ui/pkg/postinstall.sh
88+
prerm: qpi-ui/pkg/prerm.sh
89+
postremove: qpi-ui/pkg/postremove.sh

qpi-ui/pkg/postinstall.sh

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
#!/bin/sh
2+
set -e
3+
4+
# --- Systemd Handling (Debian/RPM) ---
5+
if [ -d /run/systemd/system ]; then
6+
systemctl daemon-reload
7+
systemctl enable qpi.service
8+
systemctl start qpi.service
9+
10+
# --- OpenRC Handling (Alpine) ---
11+
elif command -v rc-update >/dev/null 2>&1; then
12+
# Add to the default runlevel so it boots automatically
13+
rc-update add qpi default
14+
# Start the service immediately
15+
rc-service qpi start
16+
fi

qpi-ui/pkg/postremove.sh

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
#!/bin/sh
2+
set -e
3+
4+
if [ -d /run/systemd/system ]; then
5+
systemctl daemon-reload
6+
fi

qpi-ui/pkg/prerm.sh

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
#!/bin/sh
2+
set -e
3+
4+
# --- Systemd Handling (Debian/RPM) ---
5+
if [ -d /run/systemd/system ]; then
6+
systemctl stop qpi.service || true
7+
8+
# --- OpenRC Handling (Alpine) ---
9+
elif command -v rc-service >/dev/null 2>&1; then
10+
rc-service qpi stop || true
11+
fi

qpi-ui/pkg/qpi.initd

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
#!/sbin/openrc-run
2+
3+
description="QPI Server Service"
4+
# OpenRC tracks the process ID automatically using this supervisor
5+
supervisor="supervise-daemon"
6+
command="/usr/local/bin/qpi"
7+
# Passes the runtime hostname variable directly into your Go command flags
8+
command_args="serve ${RC_HOSTNAME} --dir /var/qpi --config-file /etc/qpi.config.yml --server-port 443 --domain ${RC_HOSTNAME}"
9+
10+
depend() {
11+
need net
12+
after firewall
13+
}

qpi-ui/pkg/qpi.service

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
[Unit]
2+
Description=QPI Server Service
3+
After=network.target
4+
5+
[Service]
6+
Type=simple
7+
# %H will be replaced by the machine's actual hostname at runtime
8+
ExecStart=/usr/local/bin/qpi serve %H --dir /var/qpi \
9+
--config-file /etc/qpi.config.yml \
10+
--server-port 443 \
11+
--domain %H
12+
Restart=on-failure
13+
User=root
14+
15+
# Journalctl logging configuration
16+
StandardOutput=journal
17+
StandardError=journal
18+
SyslogIdentifier=qpi
19+
20+
[Install]
21+
WantedBy=multi-user.target

qpi-ui/pkg/qpi.wxs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
3+
<Product Name="QPI Orchestrator" Id="*" UpgradeCode="32AAA554-16F5-420B-B646-6A57FF07D1B0" Language="1033" Codepage="1252" Version="0.0.14" Manufacturer="SopherApps">
4+
<Package InstallScope="perMachine" Id="*" Keywords="Installer" Description="QPI Orchestrator Installer" Compressed="yes" />
5+
<Media Id="1" Cabinet="qpi.cab" EmbedCab="yes" />
6+
7+
<Directory Id="TARGETDIR" Name="SourceDir">
8+
<Directory Id="ProgramFiles64Folder" Name="PFiles">
9+
<Directory Id="APPLICATIONFOLDER" Name="QPI">
10+
<Component Id="MainExecutable" Guid="*">
11+
<File Id="QpiEXE" Name="qpi.exe" Source="dist/qpi_windows_amd64_v1/qpi.exe" KeyPath="yes" />
12+
</Component>
13+
</Directory>
14+
</Directory>
15+
</Directory>
16+
17+
<Feature Id="Complete" Level="1">
18+
<ComponentRef Id="MainExecutable" />
19+
</Feature>
20+
</Product>
21+
</Wix>

0 commit comments

Comments
 (0)