Files

139 lines
12 KiB
Markdown

---
title: "Contribute"
description: "Help make Federated CoreDesktop better: suggest software, send a pull request, and learn how changes reach existing machines through migrations."
sections:
- type: hero
compact: true
eyebrow: "MIT licensed · Pull requests welcome"
title: "Help make CoreDesktop better."
subhead: "Want to help? Awesome! We welcome any and all help. Suggest missing titles or services, or contribute a PR and we're off to a better CoreDesktop."
visual: false
ctas:
- label: "Open the repository"
url: "https://gitea.federated.computer/Federated_Computer/coredesktop"
style: primary
- label: "Report an issue"
url: "https://gitea.federated.computer/Federated_Computer/coredesktop/issues"
style: ghost
- type: steps
kicker: "Ways to help"
headline: "Pick one."
items:
- title: "Suggest software"
body: "Missing a title or service you use every day? [Open an issue](https://gitea.federated.computer/Federated_Computer/coredesktop/issues) and say why. Found a bug? Report it there too."
- title: "Send a pull request"
body: "Packages live in `packages.conf`, Flatpaks in `install-flatpaks.sh`, update steps in `updates.d/` and setup in `configure.d/`. Every push is checked with [shellcheck](https://www.shellcheck.net); run `make check` first, which runs shellcheck and the bats tests. The [developer tools](#coredesktop-dev) make this easier."
- title: "Build a sibling"
body: "Have something that's only for you or your team? Make it a [sibling project](/siblings/) instead."
- type: text
id: coredesktop-dev
kicker: "Developer tools"
headline: "Install coredesktop-dev."
body: |
[coredesktop-dev](https://gitea.federated.computer/Federated_Computer/Coredesktop-Dev) has the tools for working on CoreDesktop itself. Only contributors need them, so it's a [sibling project](/siblings/) rather than part of CoreDesktop. Install it with:
```
sibling add https://gitea.federated.computer/Federated_Computer/Coredesktop-Dev.git
```
It asks where your working copy of CoreDesktop is (default `~/Projects/coredesktop`) and offers to clone it there. It installs shellcheck, bats, tea (Gitea's CLI), QEMU and xorriso, and `update` keeps it current from then on. To change the working copy, run `sibling add` again.
**Why it exists: your machine has two copies of CoreDesktop.** The *deployed* copy in `~/.local/share/coredesktop` is what the machine runs and what `update` pulls (fast-forward only). The *working* copy, e.g. `~/Projects/coredesktop`, is where you make changes. Never edit the deployed copy: one changed tracked file stops `update` from pulling. coredesktop-dev lets you test the working copy without touching the deployed one.
- type: table
id: coredesktop-dev-commands
kicker: "coredesktop-dev"
headline: "The commands."
lede: "Each takes `--help`. In a Flatpak, such as an editor's built-in terminal, coredesktop-dev runs itself on the host with `flatpak-spawn --host`."
headers: ["Command", "What it does"]
rows:
- ["`coredesktop-dev doctor`", "Checks the tools, the working copy, and that the deployed copy can still update"]
- ["`coredesktop-dev check [--fast]`", "Runs `make lint` and `make test` in the working copy, plus shellcheck on scripts you haven't committed yet (`make lint` only sees tracked files). `--fast` runs shellcheck only"]
- ["`coredesktop-dev try [--keep] [cmd...]`", "Runs the working copy's code as if it were installed, in a throwaway home with its own D-Bus session and no display, e.g. `coredesktop-dev try configure --list`. sudo, yay, pacman and systemctl still change this machine"]
- ["`coredesktop-dev deployed [status|restore]`", "Shows the deployed copy's state, or undoes local changes to it (after asking)"]
- ["`coredesktop-dev hooks [status|install|remove]`", "A pre-push hook in the working copy that runs `check` first. `git push --no-verify` skips it"]
- ["`coredesktop-dev smoketest ...`", "Tests install and update on throwaway virtual machines ([below](#smoketests))"]
- type: table
id: testing
kicker: "Testing"
headline: "Four kinds of tests."
lede: "CI only runs shellcheck (`make lint` in `.gitea/workflows/shellcheck.yml`), so run the bats tests and smoketests yourself before sending a PR."
headers: ["Test", "What it checks", "How to run it", "Documented in"]
rows:
- ["Lint", "Every tracked bash script, with [shellcheck](https://www.shellcheck.net) at warning level. Settings in `.shellcheckrc`", "`make lint`, or `coredesktop-dev check --fast` to include untracked scripts", "[README.md](https://gitea.federated.computer/Federated_Computer/coredesktop/src/branch/main/README.md#contributing)"]
- ["Unit tests", "The logic of the scripts, with [bats](https://github.com/bats-core/bats-core) tests in `tests/*.bats`. Each test gets its own `HOME` and a fake `bin` folder at the front of `PATH`, where the `stub` helper fakes commands like pacman, yay and sudo", "`make check` (lint, then `make test`), or `coredesktop-dev check`", "[tests/test_helper.bash](https://gitea.federated.computer/Federated_Computer/coredesktop/src/branch/main/tests/test_helper.bash)"]
- ["Smoketests", "`install.sh` and `update` end to end, on a real Arch + GNOME virtual machine: what fakes can't check", "`coredesktop-dev smoketest run`", "[smoketest/README.md](https://gitea.federated.computer/Federated_Computer/coredesktop/src/branch/main/smoketest/README.md)"]
- ["Sibling projects", "A sibling's install and update, in a throwaway home with `sibling add` pointed at a local clone", "By hand, as the guide shows", "[skills/sibling-project-format.md](https://gitea.federated.computer/Federated_Computer/coredesktop/src/branch/main/skills/sibling-project-format.md#testing)"]
- type: callout
text: "**Tests must not start session services.** A throwaway `HOME` doesn't isolate you from the live GNOME session: `/run/user/<uid>` is shared. A test that replaced the keyring daemon once left the real keyring locked and hung Bitwarden. Anything that starts session daemons needs its own `XDG_RUNTIME_DIR`, no display and `dbus-run-session`, which is what `coredesktop-dev try` sets up. And remember that sudo, yay, pacman and systemctl ignore `HOME`: test those with stubs, or on a VM. More in [skills/coredesktop-dev-sibling.md](https://gitea.federated.computer/Federated_Computer/coredesktop/src/branch/main/skills/coredesktop-dev-sibling.md)."
- type: text
id: smoketests
kicker: "Smoketests"
headline: "Install and update, on real virtual machines."
body: |
The bats tests check the logic with fake commands. Smoketests check what fakes can't: pacman, yay, Flatpak, systemd, ufw, Snapper on btrfs, GNOME settings and a reboot. The scenarios live in CoreDesktop's `smoketest/scenarios/` (shared helpers in `smoketest/lib/scenario.sh`); coredesktop-dev provides the QEMU virtual machines that run them. They test your working copy's `HEAD`, so commit first.
```
coredesktop-dev smoketest list # the scenarios and their tier
coredesktop-dev smoketest run # the quick ones (tier pr)
coredesktop-dev smoketest run --tier all # everything, including a fresh install; hours
coredesktop-dev smoketest run 40 43 # just these
coredesktop-dev smoketest run --keep 40 # on failure, leave the VM up to look around
coredesktop-dev smoketest shell installed # SSH into a throwaway VM
```
Scenarios cover a fresh install, `refresh`, a no-op update, upgrading from an older release, `update` replacing itself, new and failing migrations, a failing hook, an unreachable upstream, local edits, low disk space, a month-old machine, skipped packages and siblings.
**How it works.** Each scenario runs on a throwaway copy of one of two images. *base* is Arch's cloud image with GNOME added as archinstall's desktop profile does it, and a user `tester` (password `tester`) who logs in automatically. *installed* is base after `install.sh` at the commit your branch started from; scenarios on it first `update` to the commit under test. Inside the VM, a bare repo at `/srv/smoketest/coredesktop.git` stands in for Gitea, so `install.sh` and `update` run unchanged. After a scenario, `fingerprint` describes the machine as text (packages, Flatpaks, services, firewall, files in `/etc`, `~/.bashrc`, GNOME settings). The baseline scenario installs an older commit, runs `update`, and checks the result matches a fresh install. If not, an `install.sh` change is probably missing its migration. The older commits are listed in `smoketest/baselines`. Their installers can no longer finish in a VM as they did then (a package that no longer builds, a dialog no one clicks), so the scenario installs each with small fixes on top, then sets the clone back to the commit itself. An install that fails is tried once more.
**What you need.** KVM (virtualization turned on in the firmware), about 8 GB of RAM and 4 CPUs per VM (`SMOKETEST_MEMORY`, `SMOKETEST_CPUS`), and about 45 GB in `~/.cache/coredesktop-dev/smoketest`. The images are kept between runs (the installed one is the biggest, around 35 GB), along with the shared package cache and each run's logs. A scenario's own disk only holds its changes to the image, and is deleted when the scenario ends. To free space, `coredesktop-dev smoketest clean` deletes old runs' logs, and `clean --all` deletes everything, so the next run rebuilds the images. The first run builds both images before any scenario runs: *base* in a few minutes, *installed* in an hour or more. Later runs reuse them; rebuild *installed* now and then with `coredesktop-dev smoketest images installed`. Arch packages are cached and shared between VMs; Flatpaks aren't. To watch a VM's screen, set `SMOKETEST_VNC=1` and connect a VNC viewer to `127.0.0.1:5901`.
**Following a run.** While a VM boots, or a command such as `install.sh` runs in it, the terminal says once a minute what it's still waiting for, or which command is still running and its latest line of output. The logs are in `~/.cache/coredesktop-dev/smoketest`: `build.log` and the VM's console, `serial.log`, in `build-base/` and `build-installed/` while an image builds, and each scenario's logs in `runs/<date>-<time>/<scenario>/`. Each command's log is written as it runs, so you can follow it with `tail -f`.
Not covered: NVIDIA drivers, firmware updates, and anything that needs a real Core, a Tailscale login or a Claude login. Check those by hand.
- type: text
kicker: "Migrations"
headline: "Getting a change to existing machines."
body: |
Changes to `install.sh` only reach new installs. If existing machines need the change too, also add a migration: a script named after the current time,
```
migrations/$(date +%s).sh
```
that `update` runs once on each machine. It may also run on fresh installs, so make it safe to repeat.
- type: text
id: license
kicker: "License"
headline: "MIT, the whole project."
body: |
Copyright 2026 Federated Computer, Inc. Permission is granted, free of charge, to anyone who gets a copy of this software to use, copy, modify, merge, publish, distribute, sublicense and sell it, as long as the copyright and permission notice are included. The software is provided as is, without warranty of any kind.
Read the full text in [LICENSE.md](https://gitea.federated.computer/Federated_Computer/coredesktop/src/branch/main/LICENSE.md).
- type: text
kicker: "Thanks"
headline: "Standing on good shoulders."
body: |
Most of the heavy lifting is done by [Arch Linux](https://archlinux.org), and to that distribution we send much gratitude. Arch lets us get on with building, instead of waiting for upstream changes and fixes.
These scripts are based on the initial work of [Typecraft](https://www.youtube.com/@typecraft_dev).
- type: final-cta
headline: "Ready when you are."
ctas:
- label: "Install CoreDesktop"
url: "/install/"
style: primary
- label: "View the source"
url: "https://gitea.federated.computer/Federated_Computer/coredesktop"
style: ghost
---