- Running the daemon
- Using the CLI client
- Using Curl to hit the API
- Code style
- Running the tests
- Creating a release
Hacking on Pebble is easy. It's written in Go, so install or download a copy of the latest version of Go. Pebble uses Go modules for managing dependencies, so all of the standard Go tooling just works.
To compile and run Pebble, use the go run
command on the cmd/pebble
directory. The first time you run it, it will download dependencies and build packages, so will take a few seconds (but after that be very fast):
$ go run ./cmd/pebble
Pebble lets you control services and perform management actions on
the system that is running them.
Usage: pebble <command> [<options>...]
...
If you want to build and install the executable to your ~/go/bin
directory (which you may want to add to your path), use go install
:
$ go install ./cmd/pebble
However, during development it's easiest just to use go run
, as that will automatically recompile if you've made any changes.
To run the Pebble daemon, set the $PEBBLE
environment variable and use the pebble run
sub-command, something like this:
$ mkdir ~/pebble
$ export PEBBLE=~/pebble
$ go run ./cmd/pebble run
2021-09-15T01:37:23.962Z [pebble] Started daemon.
...
The use the Pebble command line client, run one of the other Pebble sub-commands, such as pebble plan
or pebble services
(if the server is running in one terminal, do this in another):
$ export PEBBLE=~/pebble
$ go run ./cmd/pebble plan
services:
snappass:
override: replace
command: sleep 60
$ go run ./cmd/pebble services
Service Startup Current
snappass disabled inactive
For debugging, you can also use curl in unix socket mode to hit the Pebble API:
$ curl --unix-socket ~/pebble/.pebble.socket 'http://localhost/v1/services?names=snappass' | jq
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 120 100 120 0 0 117k 0 --:--:-- --:--:-- --:--:-- 117k
{
"type": "sync",
"status-code": 200,
"status": "OK",
"result": [
{
"name": "snappass",
"startup": "disabled",
"current": "inactive"
}
]
}
Please format your commits following the conventional commit style.
Optionally, use the brackets to scope to a particular component where applicable.
See below for some examples of commit headings:
feat: checks inherit context from services
test: increase unit test stability
feat(daemon): foo the bar correctly in the baz
test(daemon): ensure the foo bars correctly in the baz
ci(snap): upload the snap artefacts to Github
chore(deps): update go.mod dependencies
Recommended prefixes are: fix:
, feat:
, build:
, chore:
, ci:
, docs:
, style:
, refactor:
,perf:
and test:
Pebble imports should be arranged in three groups:
- standard library imports
- third-party / non-Pebble imports
- Pebble imports (i.e. those prefixed with
github.com/canonical/pebble
)
Imports should be sorted alphabetically within each group.
We use the gopkg.in/check.v1
package for testing. Inside a test file, import this as follows:
. "gopkg.in/check.v1"
so that identifiers from that package will be added to the local namespace.
Here is an example of correctly arranged imports:
import (
"fmt"
"net"
"os"
"github.com/gorilla/mux"
. "gopkg.in/check.v1"
"github.com/canonical/pebble/internals/systemd"
"github.com/canonical/pebble/internals/testutil"
)
Log messages (that is, those passed to logger.Noticef
or logger.Debugf
) should begin with a capital letter, and use "Cannot X" rather than "Error Xing":
logger.Noticef("Cannot marshal logs to JSON: %v", err)
Error messages should be lowercase, and again use "cannot ..." instead of "error ...":
fmt.Errorf("cannot create log client: %w", err)
Pebble has a suite of Go unit tests, which you can run using the regular go test
command. To test all packages in the Pebble repository:
$ go test ./...
ok github.com/canonical/pebble/client (cached)
? github.com/canonical/pebble/cmd [no test files]
ok github.com/canonical/pebble/cmd/pebble 0.095s
...
To test a single package, simply pass the package path to go test
:
$ go test ./cmd/pebble
ok github.com/canonical/pebble/cmd/pebble 0.115s
To run a single suite or a single test, pass the suite or test name to the gocheck test runner:
$ go test ./cmd/pebble -v -check.v -check.f PebbleSuite
=== RUN Test
PASS: cmd_add_test.go:38: PebbleSuite.TestAdd 0.002s
PASS: format_test.go:52: PebbleSuite.TestCanUnicode 0.000s
...
PASS: cmd_version_test.go:26: PebbleSuite.TestVersionCommand 0.000s
OK: 20 passed
--- PASS: Test (0.02s)
PASS
ok github.com/canonical/pebble/cmd/pebble 0.022s
$ go test ./cmd/pebble -v -check.v -check.f PebbleSuite.TestAdd
=== RUN Test
PASS: cmd_add_test.go:38: PebbleSuite.TestAdd 0.002s
OK: 1 passed
--- PASS: Test (0.00s)
PASS
ok github.com/canonical/pebble/cmd/pebble 0.007s
Note that during CI we run the tests with -race
to catch data races:
$ go test -race ./...
ok github.com/canonical/pebble/client (cached)
? github.com/canonical/pebble/cmd [no test files]
ok github.com/canonical/pebble/cmd/pebble 0.165s
...
Pebble also has a suite of integration tests for testing things like pebble run
. To run them, use the "integration" build constraint:
$ go test -count=1 -tags=integration ./tests/
ok github.com/canonical/pebble/tests 4.774s
We use sphinx
to build the docs with styles preconfigured by the Canonical Documentation Starter Pack.
To build the docs, run tox
under the docs/
folder.
To pull in the latest style and dependencies from the starter pack, clone the Canonical Documentation Starter Pack repository, and follow the README there. TL;DR:
- Copy the content into the
docs/
folder. - Remove unnecessary files (like Makefile, cheat sheets, etc.)
- Under the
docs/
folder, runpython3 build_requirements.py
. This generates the latestrequirements.txt
under the.sphinx/
folder. - Under the
docs/
folder, runtox -e docs-dep
to compile a pinned requirements file for tox environments.
To create a new tagged release, go to the GitHub Releases page and:
- Update
Version
incmd/version.go
to the version you're about to publish, for examplev1.9.0
. Push this to master (or open a PR to do so). - Click "Draft a new release".
- Enter the version tag (eg:
v1.9.0
) and select "Create new tag: on publish". - Enter a release title: include the version tag and a short summary of the release.
- Write release notes: describe new features and bug fixes, and include a link to the full list of commits.
- Click "Publish release".
- Once the release GitHub Actions have finished, and the new Snap has been successfully built, update
Version
again tov1.{next}.0-dev
(for examplev1.10.0-dev
).
Binaries will be created and uploaded automatically to this release by the binaries.yml GitHub Actions job. In addition, a new Snap version is built and uploaded to the Snap Store.