Skip to content
Draft
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
88 changes: 75 additions & 13 deletions .github/workflows/_build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -52,10 +52,38 @@ jobs:
version: latest
install-mode: goinstall

# The workspace is prepared once, and every job after this one builds it, so
# what is tested is what is released.
prepare:
name: Prepare the gaia workspace
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6

- uses: actions/setup-go@v6
with:
go-version-file: go.mod

- name: Install gaia
run: |
. packaging/versions.env
go install "github.com/cs3org/gaia@$GAIA_VERSION"

# gaia calls api.github.com without a token, and panics when the call
# fails. A shared runner can run out of its calls, so retry once.
- name: Prepare
run: packaging/prepare.sh || { sleep 60; packaging/prepare.sh; }

- uses: actions/upload-artifact@v7
with:
name: workspace
path: ws/
if-no-files-found: error

# ── Build ────────────────────────────────────────────────────────────────────
build:
name: Build (${{ matrix.os }})
needs: [lint]
needs: [prepare]
runs-on: ${{ matrix.os }}
strategy:
matrix:
Expand All @@ -69,24 +97,32 @@ jobs:
steps:
- uses: actions/checkout@v6

- uses: actions/download-artifact@v7
with:
name: workspace
path: ws

- uses: actions/setup-go@v6
with:
go-version-file: go.mod
go-version-file: ws/go.mod
cache-dependency-path: ws/go.sum

- name: Build
if: runner.os != 'Windows'
run: make build

- name: Build (Windows)
if: runner.os == 'Windows'
run: go build -o cernbox.exe ./cmd/cernbox
working-directory: ws
env:
GOWORK: "off"
CGO_ENABLED: "0"
run: go build -trimpath -ldflags "-s -w $(cat bflags)" -o ../cernbox${{ runner.os == 'Windows' && '.exe' || '' }} .

# A binary that cannot print its own help is broken in a way no unit test
# would catch: cobra panics on a duplicate flag shorthand at startup, not
# at compile time.
# at compile time. The version and the brand check catch a build that
# lost the ldflags or the embedded brand.
- name: Smoke test
run: |
./cernbox version
./cernbox version --plugins | tee version.txt
grep -q '^version=[^ ]' version.txt
grep -q '^brand=cernbox ' version.txt
./cernbox --help
./cernbox ls --help
./cernbox completion bash > /dev/null
Expand Down Expand Up @@ -133,9 +169,25 @@ jobs:
steps:
- uses: actions/checkout@v6

- uses: actions/download-artifact@v7
with:
name: workspace
path: ws

- uses: actions/setup-go@v6
with:
go-version-file: go.mod
go-version-file: ws/go.mod
cache-dependency-path: |
go.sum
ws/go.sum

# The suite tests the binary that the release ships.
- name: Build cernbox
working-directory: ws
env:
GOWORK: "off"
CGO_ENABLED: "0"
run: go build -trimpath -ldflags "-s -w $(cat bflags)" -o ../cernbox .

# The EOS image alone is over 6GB, and a runner has around 14GB free, so
# the stack fills the disk and EOS then fails every write with "no space
Expand Down Expand Up @@ -171,7 +223,7 @@ jobs:
# as a pass. Here the realm is always present, so demand it.
env:
CERNBOX_REQUIRE_KERBEROS: "1"
run: go test -tags integration -count=1 -timeout 20m ./integration/...
run: CERNBOX_BINARY="$PWD/cernbox" go test -tags integration -count=1 -timeout 20m ./integration/...

# The revad and EOS logs are the only way to tell a client bug from a
# server one when a test fails, and the containers are gone by the time
Expand Down Expand Up @@ -207,9 +259,19 @@ jobs:
with:
fetch-depth: 0

- uses: actions/download-artifact@v7
with:
name: workspace
path: ws

- uses: actions/setup-go@v6
with:
go-version-file: go.mod
go-version-file: ws/go.mod
cache-dependency-path: ws/go.sum

# goreleaser puts these in the ldflags of every build (.goreleaser.yaml).
- name: Read the version flags of the workspace
run: echo "BFLAGS=$(cat ws/bflags)" >> "$GITHUB_ENV"

- name: Move the nightly tag to this commit
if: inputs.version == 'nightly'
Expand Down
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@
/cernbox
/dist/

# The gaia workspace of the build (packaging/prepare.sh)
/ws/

# Generated shell completions
/packaging/completions/

Expand Down
33 changes: 20 additions & 13 deletions .goreleaser.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,31 +2,38 @@ version: 2

project_name: cernbox-cli

# goreleaser cross-compiles the gaia workspace in ws/. BFLAGS is the content
# of ws/bflags. goreleaser reads the environment before any hook runs, so
# prepare runs before goreleaser, not as a hook:
#
# packaging/prepare.sh
# BFLAGS="$(cat ws/bflags)" goreleaser release --clean

env:
# A go.work above ws/ would replace the module of the workspace.
- GOWORK=off

before:
hooks:
- go mod tidy
# Completions are generated rather than committed, so they can never drift
# from the command tree they describe.
- mkdir -p packaging/completions
- sh -c "go run ./cmd/cernbox completion bash > packaging/completions/cernbox.bash"
- sh -c "go run ./cmd/cernbox completion zsh > packaging/completions/cernbox.zsh"
- sh -c "go run ./cmd/cernbox completion fish > packaging/completions/cernbox.fish"
- sh packaging/completions.sh

builds:
- id: cernbox
main: ./cmd/cernbox
dir: ws
main: .
binary: cernbox
# CGO off keeps the binary statically linkable, which is what lets one
# artifact run across AlmaLinux versions and inside minimal containers.
env:
- CGO_ENABLED=0
goos: [linux, darwin, windows]
goarch: [amd64, arm64]
flags:
- -trimpath
ldflags:
- -s -w
- -X main.version={{ .Version }}
- -X main.commit={{ .ShortCommit }}
- -X main.buildDate={{ .Date }}
- -s -w {{ .Env.BFLAGS }}

archives:
- id: default
Expand All @@ -40,7 +47,7 @@ archives:
files:
- README.md
- LICENSE
- docs/design.md
- docs/release-notes-2.0.md

# RPM for AlmaLinux, which is what lxplus runs. The site configuration is
# marked as a config file so a local edit survives an upgrade.
Expand All @@ -58,8 +65,8 @@ nfpms:
formats: [rpm, deb]
bindir: /usr/bin
contents:
- src: packaging/config.yaml
dst: /etc/cernbox/config.yaml
- src: packaging/config.toml
dst: /etc/cernbox/config.toml
type: config|noreplace
- src: packaging/completions/cernbox.bash
dst: /usr/share/bash-completion/completions/cernbox
Expand Down
45 changes: 27 additions & 18 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,22 +1,34 @@
BINARY := cernbox
CMD := ./cmd/cernbox
VERSION ?= $(shell git describe --tags --always --dirty 2>/dev/null || echo dev)
COMMIT ?= $(shell git rev-parse --short HEAD 2>/dev/null || echo unknown)
BUILD_DATE ?= $(shell date -u +%Y-%m-%dT%H:%M:%SZ)
LDFLAGS := -X main.version=$(VERSION) -X main.commit=$(COMMIT) -X main.buildDate=$(BUILD_DATE)
WS := ws
GORELEASER ?= goreleaser

# packaging/prepare.sh writes the gaia workspace ws/. For a local reva or
# reva-plugins, set REVA_DIR or REVA_PLUGINS_DIR. These go to prepare.sh only,
# not exported: cernbox warns about any REVA_* variable it sees.
PREPARE := GAIA="$(GAIA)" BRAND="$(BRAND)" REVA_DIR="$(REVA_DIR)" REVA_PLUGINS_DIR="$(REVA_PLUGINS_DIR)" \
REVA_VERSION="$(REVA_VERSION)" REVA_PLUGINS_VERSION="$(REVA_PLUGINS_VERSION)" packaging/prepare.sh

COMPOSE := docker compose -f dev/docker-compose.yaml

.PHONY: all build install test test-race test-cover test-integration test-all \
.PHONY: all prepare build install snapshot test test-race test-cover test-integration test-all \
lint vet fmt tidy clean completions dev-up dev-down dev-logs help

all: build

build: ## Build the cernbox binary
go build -ldflags "$(LDFLAGS)" -o $(BINARY) $(CMD)
prepare: ## Prepare the gaia workspace of cernbox (ws/)
$(PREPARE)

$(WS)/bflags:
$(PREPARE)

build: $(WS)/bflags ## Build cernbox for this machine from the workspace
cd $(WS) && GOWORK=off CGO_ENABLED=0 go build -trimpath -ldflags "-s -w $$(cat bflags)" -o ../$(BINARY) .

install: build ## Install cernbox into GOBIN
install -m 0755 $(BINARY) "$$(go env GOBIN | grep . || echo "$$(go env GOPATH)/bin")/$(BINARY)"

install: ## Install the cernbox binary into GOBIN
go install -ldflags "$(LDFLAGS)" $(CMD)
snapshot: $(WS)/bflags ## Build the release artefacts into dist/, without publishing
BFLAGS="$$(cat $(WS)/bflags)" $(GORELEASER) release --snapshot --clean --skip=publish

test: ## Run unit tests
go test ./...
Expand All @@ -29,8 +41,8 @@ test-cover: ## Run unit tests and write coverage.out / coverage.html
go tool cover -html=coverage.out -o coverage.html
@go tool cover -func=coverage.out | tail -1

test-integration: build ## Run integration tests (requires: make dev-up)
go test -tags integration -count=1 -timeout 20m ./integration/...
test-integration: build ## Run integration tests against ./cernbox (requires: make dev-up)
CERNBOX_BINARY=$(CURDIR)/$(BINARY) go test -tags integration -count=1 -timeout 20m ./integration/...

test-all: dev-up test test-integration ## Run every test suite

Expand All @@ -47,15 +59,12 @@ fmt: ## Format the code
tidy: ## Tidy go.mod
go mod tidy

completions: ## Generate shell completion scripts for packaging
@mkdir -p packaging/completions
go run $(CMD) completion bash > packaging/completions/cernbox.bash
go run $(CMD) completion zsh > packaging/completions/cernbox.zsh
go run $(CMD) completion fish > packaging/completions/cernbox.fish
completions: build ## Generate shell completion scripts for packaging
packaging/completions.sh ./$(BINARY)

clean: ## Remove build and test artifacts
rm -f $(BINARY) coverage.out coverage.html
rm -rf packaging/completions
rm -rf packaging/completions $(WS) dist

dev-up: ## Start the dev environment (revad + EOS)
$(COMPOSE) up -d --build
Expand Down
25 changes: 16 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

Work with your CERNBox files from the command line: browse them, move them between your computer and CERNBox, move them between two computers, and share them.

> **2.0 is a new program under the old name.** `cernbox` is now reva's command line client, built for CERNBox, and this repository packages it. The JSON output, the exit codes and some flags changed: read [docs/release-notes-2.0.md](docs/release-notes-2.0.md) before you upgrade a machine that runs scripts. The rest of this README, `docs/configuration.md` and `docs/behaviour.md` still describe 1.x, and are being rewritten.

```console
$ cernbox ls /eos/user/g/gdelmont
$ cernbox cp ./report.pdf cb:/eos/user/g/gdelmont/Documents/
Expand All @@ -16,13 +18,13 @@ curl cli.cernbox.cern.ch | sh

That fetches the release built for your system, checks it against the published checksum, and installs it where you can write — `/usr/local/bin` if that is yours, otherwise `~/.local/bin`, telling you what to add to `PATH`. It never asks for a password. `CERNBOX_VERSION` pins a version and `CERNBOX_INSTALL_DIR` chooses where it goes.

From source, or from a package:
From source, with [gaia](https://github.com/cs3org/gaia) and the versions in `packaging/versions.env`:

```bash
go install github.com/cernbox/cernbox-cli/cmd/cernbox@latest
make build # or: gaia build --binary reva --brand cernbox.toml --with github.com/cernbox/reva-plugins/cli -o cernbox
```

RPM and deb packages are attached to each release.
RPM and deb packages (`cernbox-cli`) are attached to each release.

On Windows, download `cernbox-cli_<version>_windows_amd64.zip` (or `_arm64`) from the [latest release](https://github.com/cernbox/cernbox-cli/releases/latest) and put `cernbox.exe` somewhere on your `PATH`. It runs in PowerShell, `cmd` and Windows Terminal alike.

Expand Down Expand Up @@ -347,10 +349,10 @@ A trash listing covers a stretch of time rather than the whole bin, because that
`--output json` and `--output csv` turn any listing into something a program can read, and informational messages go to standard error so a pipe sees only data.

```bash
cernbox --output json ls data | jq -r '.[] | select(.size > 1e9) | .name'
cernbox --output json ls data | jq -r '.[] | select((.size // "0" | tonumber) > 1e9) | .name'
```

Exit codes distinguish the cases worth branching on: `0` success, `2` a mistake in the command, `3` a credentials problem, `4` not allowed, `5` not found.
The JSON is the CS3 JSON of each resource, in which 64-bit numbers are strings. Exit codes: `0` success, `1` an error, `2` a mistake in the command.

## Shell completion

Expand All @@ -362,20 +364,25 @@ TAB then completes CERNBox paths as you type them, along with space names, share

## Development

The client is in [cs3org/reva](https://github.com/cs3org/reva) (`cmd/reva`, `pkg/cli`) and the CERNBox plugins and brand in [cernbox/reva-plugins](https://github.com/cernbox/reva-plugins) (`cli/`). This repository builds and ships them: see [docs/packaging.md](docs/packaging.md).

```bash
make build # build
make test # unit tests
make prepare # the gaia workspace, ws/ (REVA_DIR, REVA_PLUGINS_DIR for local checkouts)
make build # ./cernbox for this machine
make snapshot # the release artefacts in dist/, with goreleaser
make dev-up # start a local CERNBox to test against
make test-integration # run the tests that need it
make test-integration # run the end-to-end tests against ./cernbox
```

`make help` lists the rest.

## More

- [docs/release-notes-2.0.md](docs/release-notes-2.0.md): what changed in 2.0, and how to move scripts and configuration over
- [docs/packaging.md](docs/packaging.md): how a release is built, and the plan for the code of 1.x
- [docs/configuration.md](docs/configuration.md) — the configuration file: where it goes, every setting, and the environment variables
- [docs/behaviour.md](docs/behaviour.md) — what the client does when the server is awkward, and what each kind of transfer actually costs
- [docs/design.md](docs/design.md) — the architecture and the decisions behind it
- [docs/design.md](docs/design.md): the architecture of 1.x and the decisions behind it

## Licence

Expand Down
Loading
Loading