Skip to content
Merged
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
55 changes: 55 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -546,3 +546,58 @@ jobs:
TAG="${{ needs.publish.outputs.release_tag }}"
chmod +x ./scripts/linux/aur_publish.sh
./scripts/linux/aur_publish.sh "$VER" "$TAG"

publish-linux-repo:
name: Publish APT + DNF repository
needs: [publish]
runs-on: ubuntu-latest
steps:
- name: Check repository secrets
id: repo
env:
GPG_KEY: ${{ secrets.PACKAGE_REPO_GPG_PRIVATE_KEY }}
TOKEN: ${{ secrets.PACKAGE_REPO_TOKEN }}
run: |
if [ -n "${GPG_KEY}" ] && [ -n "${TOKEN}" ]; then
echo "enabled=true" >> "$GITHUB_OUTPUT"
else
echo "enabled=false" >> "$GITHUB_OUTPUT"
echo "PACKAGE_REPO_GPG_PRIVATE_KEY / PACKAGE_REPO_TOKEN not set; skipping."
fi

- uses: actions/checkout@v4
if: steps.repo.outputs.enabled == 'true'

- uses: actions/download-artifact@v4
if: steps.repo.outputs.enabled == 'true'
with:
name: bundle-linux
path: artifacts/linux

- name: Install repository tooling
if: steps.repo.outputs.enabled == 'true'
run: |
sudo apt-get update
sudo apt-get install -y apt-utils createrepo-c rpm

- name: Import signing key
if: steps.repo.outputs.enabled == 'true'
id: gpg
env:
GPG_KEY: ${{ secrets.PACKAGE_REPO_GPG_PRIVATE_KEY }}
run: |
set -euo pipefail
echo "$GPG_KEY" | gpg --batch --import
fpr="$(gpg --batch --list-secret-keys --with-colons | awk -F: '/^fpr:/ {print $10; exit}')"
echo "fpr=$fpr" >> "$GITHUB_OUTPUT"

- name: Publish
if: steps.repo.outputs.enabled == 'true'
env:
PACKAGE_REPO_URL: https://x-access-token:${{ secrets.PACKAGE_REPO_TOKEN }}@github.com/QueryaHub/repo.git
GPG_KEY_ID: ${{ steps.gpg.outputs.fpr }}
run: |
set -euo pipefail
deb="$(find artifacts/linux -name '*.deb' | head -n1)"
rpm="$(find artifacts/linux -name '*.rpm' | head -n1)"
./scripts/linux/publish_package_repo.sh "$deb" "$rpm"
17 changes: 16 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,22 @@ Whether you are navigating multi-million row datasets, authoring complex analyti
## Installation

### Linux
Download the latest `.deb`, `.AppImage`, or `.tar.gz` from [Releases](https://github.com/QueryaHub/Querya-Desktop/releases):
**Debian / Ubuntu (APT repository, updates with `apt upgrade`):**

```bash
curl -fsSL https://repo.querya.app/gpg.key | sudo gpg --dearmor -o /etc/apt/keyrings/querya.gpg
echo "deb [signed-by=/etc/apt/keyrings/querya.gpg] https://repo.querya.app/apt stable main" | sudo tee /etc/apt/sources.list.d/querya.list
sudo apt update && sudo apt install querya-desktop
```

**Fedora / RHEL (DNF repository):**

```bash
sudo dnf config-manager --add-repo https://repo.querya.app/rpm/querya.repo
sudo dnf install querya-desktop
```

Or download the latest `.deb`, `.AppImage`, or `.tar.gz` from [Releases](https://github.com/QueryaHub/Querya-Desktop/releases):

```bash
# Debian / Ubuntu (.deb)
Expand Down
25 changes: 25 additions & 0 deletions docs/packaging.md
Original file line number Diff line number Diff line change
Expand Up @@ -88,3 +88,28 @@ flatpak override --user com.queryahub.querya_desktop --filesystem=/var/run/postg
```

Flathub submission can reuse [`packaging/linux/flatpak/com.queryahub.querya_desktop.yml`](../packaging/linux/flatpak/com.queryahub.querya_desktop.yml).

## APT and DNF repository (`repo.querya.app`)

The Release workflow job `publish-linux-repo` runs
[`scripts/linux/publish_package_repo.sh`](../scripts/linux/publish_package_repo.sh)
after the GitHub Release is created. It adds the new `.deb` / `.rpm` to the
`gh-pages` branch of `QueryaHub/repo`, regenerates the APT indexes
(`apt-ftparchive`, signed `InRelease` / `Release.gpg`) and the DNF metadata
(`createrepo_c`, signed packages and `repomd.xml.asc`). Older versions stay in
the pool, so users can pin them.

The job is skipped while its secrets are not set, like the AUR job.

One-time setup:

1. Create a signing key without a passphrase: `gpg --quick-generate-key "Querya Packages <[email protected]>" rsa4096 sign never`.
2. Add repository secrets in `QueryaHub/Querya-Desktop`:
`PACKAGE_REPO_GPG_PRIVATE_KEY` (`gpg --armor --export-secret-keys <fpr>`) and
`PACKAGE_REPO_TOKEN` (a token with write access to `QueryaHub/repo`).
3. In `QueryaHub/repo`, serve the `gh-pages` branch with GitHub Pages and set the
custom domain `repo.querya.app` (DNS `CNAME` to `queryahub.github.io`).
4. Run a release (or re-run `publish-linux-repo`) and check
`https://repo.querya.app/gpg.key` and `https://repo.querya.app/apt/dists/stable/InRelease`.

Rotating the key means re-running the job and asking users to refresh `gpg.key`.
100 changes: 100 additions & 0 deletions scripts/linux/publish_package_repo.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
#!/usr/bin/env bash
# Publish the release .deb / .rpm to the signed APT + DNF repository.
#
# Usage:
# ./scripts/linux/publish_package_repo.sh <path/to/*.deb> <path/to/*.rpm>
#
# Environment:
# PACKAGE_REPO_URL git URL of the repository served as repo.querya.app
# (token embedded for HTTPS), e.g. QueryaHub/repo
# PACKAGE_REPO_BRANCH branch that is served (default: gh-pages)
# GPG_KEY_ID fingerprint of the signing key (already imported)
#
# Layout written to the branch:
# gpg.key public key (ASCII armor)
# apt/pool/main/*.deb every published .deb
# apt/dists/stable/... Packages, Release, InRelease, Release.gpg
# rpm/*.rpm, rpm/repodata/ every published .rpm, signed repomd.xml
# rpm/querya.repo file for `dnf config-manager --add-repo`
#
# Requires: git, gpg, apt-utils (apt-ftparchive), createrepo-c, rpm.
set -euo pipefail

DEB="${1:?path to .deb}"
RPM="${2:?path to .rpm}"
: "${PACKAGE_REPO_URL:?}"
: "${GPG_KEY_ID:?}"
BRANCH="${PACKAGE_REPO_BRANCH:-gh-pages}"
BASE_URL="${PACKAGE_REPO_BASE_URL:-https://repo.querya.app}"

WORK="$(mktemp -d "${TMPDIR:-/tmp}/querya-pkgrepo.XXXXXX")"
trap 'rm -rf "$WORK"' EXIT
SITE="$WORK/site"

if git ls-remote --exit-code --heads "$PACKAGE_REPO_URL" "$BRANCH" >/dev/null 2>&1; then
git clone --quiet --depth 1 --branch "$BRANCH" "$PACKAGE_REPO_URL" "$SITE"
else
git init --quiet "$SITE"
git -C "$SITE" checkout --quiet -b "$BRANCH"
git -C "$SITE" remote add origin "$PACKAGE_REPO_URL"
fi

gpg --batch --armor --export "$GPG_KEY_ID" > "$SITE/gpg.key"

# ---- APT -------------------------------------------------------------------
APT="$SITE/apt"
mkdir -p "$APT/pool/main" "$APT/dists/stable/main/binary-amd64"
cp -f "$DEB" "$APT/pool/main/"
(
cd "$APT"
apt-ftparchive packages pool > dists/stable/main/binary-amd64/Packages
gzip -9kf dists/stable/main/binary-amd64/Packages
apt-ftparchive \
-o APT::FTPArchive::Release::Origin=Querya \
-o APT::FTPArchive::Release::Label=Querya \
-o APT::FTPArchive::Release::Suite=stable \
-o APT::FTPArchive::Release::Codename=stable \
-o APT::FTPArchive::Release::Architectures=amd64 \
-o APT::FTPArchive::Release::Components=main \
release dists/stable > dists/stable/Release
gpg --batch --yes --default-key "$GPG_KEY_ID" \
--clearsign -o dists/stable/InRelease dists/stable/Release
gpg --batch --yes --default-key "$GPG_KEY_ID" \
--armor --detach-sign -o dists/stable/Release.gpg dists/stable/Release
)

# ---- DNF -------------------------------------------------------------------
RPMDIR="$SITE/rpm"
mkdir -p "$RPMDIR"
cp -f "$RPM" "$RPMDIR/"
rpmsign_conf="$WORK/rpmmacros"
printf '%%_gpg_name %s\n%%__gpg %s\n' "$GPG_KEY_ID" "$(command -v gpg)" > "$rpmsign_conf"
HOME_RPM="$WORK/home"
mkdir -p "$HOME_RPM"
cp "$rpmsign_conf" "$HOME_RPM/.rpmmacros"
HOME="$HOME_RPM" GNUPGHOME="${GNUPGHOME:-$HOME/.gnupg}" rpmsign --addsign "$RPMDIR"/*.rpm
createrepo_c --update "$RPMDIR"
gpg --batch --yes --default-key "$GPG_KEY_ID" \
--armor --detach-sign -o "$RPMDIR/repodata/repomd.xml.asc" "$RPMDIR/repodata/repomd.xml"
cat > "$RPMDIR/querya.repo" <<REPO
[querya]
name=Querya Desktop
baseurl=$BASE_URL/rpm
enabled=1
gpgcheck=1
repo_gpgcheck=1
gpgkey=$BASE_URL/gpg.key
REPO

# ---- push ------------------------------------------------------------------
cd "$SITE"
touch .nojekyll
git add -A
if git diff --cached --quiet; then
echo "package repository already up to date"
exit 0
fi
git -c user.name="querya-release-bot" -c user.email="[email protected]" \
commit --quiet -m "repo: publish $(basename "$DEB")"
git push --quiet origin "HEAD:$BRANCH"
echo "published $(basename "$DEB") and $(basename "$RPM") to $BASE_URL"
Loading