This is the multi-page printable view of this section. Click here to print.

Return to the regular view of this page.

Developer Workflow

Contributing to ClusterCockpit using GitHub Flow with git rebase.

Overview

ClusterCockpit uses GitHub Flow: main is always deployable, all work happens on short-lived feature branches, and every change lands via a pull request. History is kept linear by rebasing — no merge commits from feature branches.

BranchPurpose
mainActive development; source for the next release
release/v1.xPersistent; created per minor release, receives backported fixes

External contributors fork the repository and add the upstream as a second remote. Core team members clone upstream directly and replace upstream with origin in the commands below.

One-time git configuration

git config --global pull.rebase true
git config --global rebase.autoStash true

Branch Naming

<type>/<issue-number>-<short-description>
PrefixUse for
feat/New features
fix/Bug fixes
sec/Security fixes
doc/Documentation
fix/backport-Backports to a release branch

Examples: feat/123-auto-job-tagging, fix/backport-423-wal-rotation-v1.3

Persistent release branches: release/v1.x (minor version only).


Development Cycle

  1. Sync main before starting:

    git fetch upstream && git rebase upstream/main
    
  2. Branch off main:

    git checkout -b feat/123-my-feature main
    
  3. Commit freely — informal messages are fine during development; they will be cleaned up before the PR. Reference issue numbers where relevant.

  4. Push, and use --force-with-lease (never --force) after any rebase:

    git push -u origin feat/123-my-feature
    git push --force-with-lease origin feat/123-my-feature  # after rebase
    
  5. Rebase onto main whenever the base branch has moved:

    git fetch upstream && git rebase upstream/main
    

Interactive Rebase Before Opening a PR

Clean up the branch history so each commit is a logical unit with a proper prefix message before requesting review:

git rebase -i upstream/main

Squash WIP commits with squash / fixup, polish messages with reword. See Commit Message Conventions for the required prefixes. Push with --force-with-lease afterwards.


Pre-PR Checklist

  • Rebased on current main, no merge commits in the branch
  • Commit messages follow prefix conventions
  • make test passes (see Unit Tests)
  • Frontend build passes if frontend files changed (see Frontend Development Setup)
  • No debug output or temporary code committed
  • Issue number referenced in a commit message or PR description
  • Docs updated if user-facing behaviour changed (see Contributing to Documentation)

Pull Requests

Target main for new work; target release/v1.x for backports.

  • Title: use commit prefix conventions (feat: …, fix: …)
  • Description: what and why; how to test; closing keyword (Fixes #423)
  • Use GitHub Draft status for work in progress
  • Keep PRs small

Reference

1 - Commit Message Conventions

Prefix tags for release notes, issue linking, and goreleaser integration

Introduction

ClusterCockpit uses goreleaser for building and uploading releases. Release notes are generated automatically from commit messages using the prefix tags described below. GitHub also parses special keywords to link commits and PRs to issues.

Before opening a pull request, use interactive rebase to clean up your branch history and ensure the final commit messages follow these conventions.


Release Note Prefixes

Commits carrying one of the following prefixes appear in the generated release notes:

PrefixAppears under
feat:New features
fix:Bug fixes
sec:Security fixes (ClusterCockpit-specific)
doc:Documentation updates
feat dep: or fix dep:Dependency additions or changes

Commits without a recognised prefix are not included in the release notes.

Examples:

feat: add automatic job tagging
fix: correct WAL rotation on partial flush (#423)
sec: enforce API token expiry
doc: update rebase workflow guide
feat dep: upgrade to Go 1.22

Referencing Issues

It is good practice to create a GitHub issue for any notable change so that the motivation and discussion are preserved. Reference an issue in any commit message or PR description using the #<number> syntax:

This change contributes to #235

Automatically Closing Issues

GitHub closes an issue automatically when a PR containing one of the following keywords merges into the default branch:

  • close, closes, closed
  • fix, fixes, fixed
  • resolve, resolves, resolved

The issue is not closed until the commit appears on main. Example:

fix: correct WAL rotation on partial flush

Fixes #423

Place the closing keyword in the PR description rather than a WIP commit message, since commit messages are often rewritten with interactive rebase before the PR is merged.

2 - Unit Tests

Go test conventions and how to run the test suite locally

Overview

ClusterCockpit uses the standard Go testing environment. Run the full test suite locally before pushing to avoid CI failures — this is part of the pre-PR checklist.


Conventions

  • White-box unit tests — tests for internal (unexported) functionality are placed in the same file as the code under test, within the same package.
  • Black-box unit tests — tests for public interfaces are placed in a separate file named <package_name>_test.go and belong to the package <package_name>_test. There is at most one such file per package.
  • Integration tests — tests that exercise multiple components are also placed in the <package_name>_test.go file under the <package_name>_test package.
  • Test assets — any required fixture files are placed in a ./testdata/ directory within the package directory.

Running Tests

The project Makefile provides a test target that runs:

go clean -testcache
go build ./...
go vet ./...
go test ./...

Run it with:

make test

You can also run any of the individual commands directly from the command line.

For debugging individual tests, Visual Studio Code has excellent Go test integration including breakpoint support.


Further Reading

3 - Frontend Development Setup

How to set up cc-backend for fast frontend development iteration

Overview

The cc-backend web frontend is built with Svelte. By default, the compiled frontend assets are embedded directly in the Go binary. During frontend development this is impractical — use the setup below to enable fast rebuild-on-save iteration without recompiling the backend.

For all other aspects of the development process (branching, commits, PRs) follow the Developer Workflow guide.


Setup

1. Disable embedded static files

In config.json, set:

"embed-static-files": false,
"static-files": "./web/frontend/public/"

This tells cc-backend to serve assets from disk rather than from the embedded filesystem.

2. Start the frontend build in watch mode

In the ./web/frontend directory:

npm run dev

This starts the Rollup build in listen mode. Whenever you save a source file, the affected JavaScript targets are rebuilt automatically.

If the output is minified when you expect it not to be, set the production flag manually in ./web/frontend/rollup.config.mjs:

const production = false

This should normally be set automatically based on the npm script, but the override is available if needed.

3. Start cc-backend

From the repository root:

./cc-backend -server -dev

Because assets are served by cc-backend (not a separate dev server), you must reload the page in your browser manually after each frontend rebuild.


A common setup is three terminals running concurrently:

TerminalDirectoryCommand
1repository root./cc-backend -server -dev
2./web/frontendnpm run dev
3anyeditor / shell for source edits

4 - Contributing to Documentation

How to set up a local Hugo environment and contribute to the documentation website

The ClusterCockpit documentation is built with Hugo using the Docsy theme. Pages are written in Markdown. Hugo wraps them into a static site with navigation, search, and versioning.

All documentation contributions follow the same branch and PR workflow described in the Developer Workflow guide. The repository to fork or clone is ClusterCockpit/cc-doc.


Local Setup

You need the Hugo extended version (for SCSS support), at minimum Hugo 0.45 — the most recent available version is recommended.

Clone the repository with submodules (required for the Docsy theme):

git clone --recurse-submodules https://github.com/ClusterCockpit/cc-doc.git
cd cc-doc

Start the local development server:

hugo server

Your site is available at http://localhost:1313/. Hugo watches for file changes and automatically rebuilds and reloads the page.


Quick Edit via GitHub

For small corrections to an existing page, use the Edit this page link in the top-right corner of any documentation page. GitHub will prompt you to fork the repository if you have not already, open the file in edit mode, and guide you through creating a PR.


Creating an Issue

If you have found a problem but are not ready to fix it yourself, open an issue in the cc-doc repository. You can also use the Create Issue button in the top-right corner of any documentation page.


Useful Resources

5 - Preparing a Release

How to cut new releases and backport fixes using persistent release branches and goreleaser.

Branch Model

ClusterCockpit maintains two types of long-lived branches:

BranchPurpose
mainActive development; all new features and fixes land here first
release/v1.xPersistent branch for a minor release series; receives backported fixes

A release/v1.x branch is created once when cutting a new minor or major release and stays open indefinitely. All v1.x.y patch releases are tagged from this branch. Short-lived fix branches for backports are PRed into the release branch, not into main.

Every change — including urgent fixes — follows the same feature-branch/PR workflow described in the Developer Workflow guide. There is no “hotfix directly to main” shortcut.


Cutting a New Minor or Major Release

1. Prepare main

Ensure all PRs intended for the release are merged and CI is green on main.

2. Create the release branch

git checkout main
git pull --rebase
git checkout -b release/v1.x
git push -u origin release/v1.x

3. Bump the version

On a short-lived branch from release/v1.x, update the version in Makefile and prepare ReleaseNotes.md:

git checkout -b doc/release-v1.x.0 release/v1.x
# edit Makefile and ReleaseNotes.md
git add Makefile ReleaseNotes.md
git commit -m "doc: prepare release v1.x.0"
git push -u origin doc/release-v1.x.0

Open a PR targeting release/v1.x (not main), get it reviewed, and merge.

4. Tag the release

On a Linux host with repository push access:

git fetch origin
git checkout release/v1.x
git pull --rebase
git tag v1.x.0 -m "release v1.x.0"
git push origin v1.x.0

5. Run goreleaser

Ensure the GITHUB_TOKEN environment variable is set, then:

goreleaser release

goreleaser builds the release artifacts, generates release notes from commit prefixes, and publishes everything to the GitHub Releases page. See Commit Message Conventions for the prefix tags that control what appears in the release notes.

6. Post-release

  • Verify the release appears correctly on the GitHub Releases page.
  • Close the milestone for this release if one was used.
  • Announce the release in the appropriate channels.

Patch Releases — Backporting Fixes

Patch releases (v1.x.1, v1.x.2, …) are cut from the release/v1.x branch after backporting one or more fixes from main.

1. Develop the fix on main first

Follow the standard feature-branch workflow and merge the fix into main via a PR. Note the commit SHA(s) of the fix once merged.

2. Create a backport branch

git fetch origin
git checkout release/v1.x
git pull --rebase
git checkout -b fix/backport-<issue>-<description>

3. Cherry-pick the fix

git cherry-pick <commit-sha>

If the cherry-pick produces conflicts, resolve them, stage the files, then continue:

git add <resolved-files>
git cherry-pick --continue

4. Open a PR targeting the release branch

git push -u origin fix/backport-<issue>-<description>

Open the PR on GitHub and set the base branch to release/v1.x, not main. The PR description should reference the original issue and the commit SHA that was cherry-picked.

5. Tag the patch release

After the backport PR is merged:

git fetch origin
git checkout release/v1.x
git pull --rebase
git tag v1.x.1 -m "release v1.x.1"
git push origin v1.x.1
goreleaser release

Repeat steps 2–5 for each additional fix that needs to be included in the patch release before tagging.