Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
2eb4002
fix(asset): add missing KindDisplayName case for "team"
mmanciop Aug 17, 2026
96ae5bc
feat(experimental): support gating a single flag, not just a whole co…
mmanciop Aug 17, 2026
87c9d0e
refactor(asset): extract shared non-hidden-YAML-file discovery
mmanciop Aug 17, 2026
516445d
feat(apply): add --since/--force for git-history-based deletion sync
mmanciop Aug 17, 2026
f0da968
test(apply): add declarative git-scenario fixtures and testcontainers…
mmanciop Aug 17, 2026
746717e
docs(apply): track --since follow-ups surfaced by doc review
mmanciop Aug 17, 2026
bebb102
feat(apply): unify --dry-run's output and add agent-mode JSON
mmanciop Aug 17, 2026
1428e57
chore: add changelog entry for apply --since/--force
mmanciop Aug 17, 2026
5505509
chore: reference PR #253 in changelog entry
mmanciop Aug 17, 2026
6481548
test(apply): add roundtrip tests for apply --since against a live env…
mmanciop Aug 17, 2026
ca0e56e
fix(apply): consistent file grouping for --since deletions under a su…
mmanciop Aug 17, 2026
70600be
docs(apply): document --since/--force
mmanciop Aug 17, 2026
eb28d79
fix(apply): support --since when every asset under -f's target was de…
mmanciop Aug 24, 2026
8248010
fix(apply): always attempt both endpoints when deleting a PrometheusR…
mmanciop Aug 24, 2026
5eebd14
fix(apply): delete a PrometheusRule CRD's recording rule when its las…
mmanciop Aug 24, 2026
0e18638
fix(apply): tolerate a concurrently-deleted asset during --since with…
mmanciop Aug 24, 2026
ef5dcf0
feat(apply): add --accept-non-ancestor-ref to decouple it from --force
mmanciop Aug 24, 2026
10fbb27
fix(apply): stop reporting an already-deleted asset as also just deleted
mmanciop Aug 24, 2026
202f2c7
fix(asset): derive a distinct check-rule id per alert in multi-alert …
mmanciop Aug 24, 2026
913a5a3
fix(apply): include asset kind and --since ref in agent-mode --dry-ru…
mmanciop Aug 24, 2026
f34e6aa
fix(apply): clearer errors for not-a-git-repo and insufficient-histor…
mmanciop Aug 24, 2026
bf6533c
fix(apply): resolve --since single-file targets and vanished-target r…
mmanciop Aug 24, 2026
c8a8ade
fix(apply,asset): fix multi-alert PrometheusRule check-rule id deriva…
mmanciop Aug 24, 2026
e58e439
fix(apply): use os.Stat consistently when walking up for --since's ne…
mmanciop Aug 24, 2026
f4b6367
perf(apply): stop re-reading git blobs already read while building --…
mmanciop Aug 24, 2026
ff04283
style(apply): drop an over-explanatory inline comment in nearestExist…
mmanciop Aug 24, 2026
794a5eb
build: drop the local dash0-api-client-go replace directive
nicolastakashi Aug 26, 2026
f449126
test(apply): cover --dry-run's PrometheusRule alert-deletion branch
nicolastakashi Aug 26, 2026
34bffb6
refactor(apply): extract --dry-run's flat-row helper
nicolastakashi Aug 27, 2026
3fb0d4c
docs(changelog): record apply --dry-run's output change as breaking
nicolastakashi Aug 27, 2026
61b38c3
fix(apply): give --since's errors agent-mode-parseable hints
nicolastakashi Aug 27, 2026
1072354
fix(apply): stop --since deleting a check rule still declared on disk
nicolastakashi Aug 27, 2026
e267639
fix(apply): bound --since's alert-deletion name lookup
nicolastakashi Aug 27, 2026
7b44094
fix(apply): delete a check rule --since's id scheme abandons
nicolastakashi Aug 27, 2026
c9c9622
fix(git): list paths at a ref with -z so non-ASCII names survive
nicolastakashi Aug 27, 2026
82f19a8
fix(apply): refuse --since against a sparse checkout
nicolastakashi Aug 27, 2026
b75f4e7
perf(git): read a ref's files with bounded concurrency
nicolastakashi Aug 27, 2026
c45d77d
fix(apply): extract only the identifier a kind is upserted by
nicolastakashi Aug 27, 2026
5b5f6c6
fix(test): build the e2e binary with CGO_ENABLED=0
nicolastakashi Aug 27, 2026
a0a7538
chore(nix): update vendorHash for dependency change
github-actions[bot] Aug 27, 2026
a81d3ea
test(roundtrip): assert the Team display name, not the raw kind
nicolastakashi Aug 27, 2026
e5e5371
chore(nix): update vendorHash for dependency change
github-actions[bot] Aug 27, 2026
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 .chloggen/feat_sync-action.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# Use this changelog template to create an entry for release notes.

# One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix'
change_type: enhancement

# The name of the component, or a single word describing the area of concern (e.g. dashboards, config, apply)
component: apply

# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`).
note: "Add `apply --since <ref>` and `--force` for git-history-based deletion sync"

# Mandatory: One or more tracking issues related to the change. You can use the PR number here if no issue exists.
issues: [253]

# (Optional) One or more lines of additional information to render under the primary note.
# These lines will be padded with 2 spaces and then inserted directly into the document.
# Use pipe (|) for multiline entries.
subtext: |
Deletes assets whose definition existed at `<ref>` but is no longer present in `-f`'s
current contents, detected by identifier (id or origin), never by file path. Requires
`--experimental`/`-X`. `--dry-run --since` previews the deletion plan, merged with the
existing create/update preview into one per-file listing, and now also resolves deleted
assets' names from git history instead of only showing their id. Agent mode emits
`--dry-run`'s preview as JSON.

Also, while stabilizing this feature ahead of release:
- `--since` now correctly detects an all-deletions run, whether `-f`'s target survives
empty or was removed entirely, instead of failing outright.
- Deleting a PrometheusRule CRD always cleans up both its check rule and its recording
rule, instead of trusting a single git snapshot that could undercount which endpoints
the CRD ever used.
- A CRD's recording rule is deleted when its last `record:` entry is removed, even
though the CRD's own identifier survives via a remaining `alert:` entry.
- An asset already deleted by someone else no longer fails the whole run; this no
longer requires `--force`, which keeps its own separate job of skipping confirmation
prompts.
- New `--accept-non-ancestor-ref` flag accepts a non-ancestor `--since` ref (e.g. after
a force-push) without also skipping every per-asset deletion confirmation, which
`--force` alone used to do together.
- A concurrently-deleted asset is now reported once, not as both "already deleted" and
"deleted".
- Fixed a pre-existing, `--since`-independent bug in `apply`/`check-rules create`: a
PrometheusRule CRD with 2+ alerting rules and a `dash0.com/id` label silently
collapsed to one check rule (the last alert applied overwrote the rest under the
shared id). Each alert now upserts its own derived id. Re-applying an existing
multi-alert CRD leaves an orphaned duplicate at the literal `dash0.com/id`; delete it
by hand once the new per-alert check rules look correct.

# If your change doesn't affect end users or the exported elements of any package,
# you should instead start your pull request title with "chore" or use the "Skip Changelog" label.
# Optional: The change log or logs in which this entry should be included.
# e.g. '[user]' or '[user, api]'
# Include 'user' if the change is relevant to end users.
# Default: '[user]'
change_logs: []
47 changes: 47 additions & 0 deletions .chloggen/feat_sync-action_dryrun_output.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# Use this changelog template to create an entry for release notes.

# One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix'
change_type: breaking

# The name of the component, or a single word describing the area of concern (e.g. dashboards, config, apply)
component: apply

# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`).
note: "`apply --dry-run` changed its output shape, including without `--since`"

# Mandatory: One or more tracking issues related to the change. You can use the PR number here if no issue exists.
issues: [253]

# (Optional) One or more lines of additional information to render under the primary note.
# These lines will be padded with 2 spaces and then inserted directly into the document.
# Use pipe (|) for multiline entries.
subtext: |
`--since` renders its deletions in the same listing as creates and updates, so that
listing had to name each row's operation and order the two kinds of row together. Plain
`--dry-run` shares the renderer and therefore changed too, in three ways:

- Each row is now prefixed with `*` and its operation instead of a per-file ordinal:
`1. Dashboard "Production Overview" (a1b2c3d4-...)` becomes
`* Apply Dashboard "Production Overview" (a1b2c3d4-...)`.
- Rows within a file are ordered by identifier rather than by their position in the
file, so a document's row can move relative to its siblings.
- In agent mode, `--dry-run` now emits the documented JSON array of
`{path, changes: [{op, kind, name, originOrId}]}` instead of the human-readable text,
matching every other command's agent-mode contract.

Separately, `Dash0Team` now renders as `Team` wherever an asset kind is displayed, so
`apply` reports `Team "Backend Team" created` instead of `Dash0Team "Backend Team"
created`. Every other kind already had a human-readable display name; teams fell
through to the raw kind identifier, which also contradicted the `--- Team (before)`
header their own update diff printed.

Scripts that parsed `--dry-run`'s text output, or grepped for `Dash0Team`, need
updating. Agent-mode callers should read the JSON rather than parsing text.

# If your change doesn't affect end users or the exported elements of any package,
# you should instead start your pull request title with "chore" or use the "Skip Changelog" label.
# Optional: The change log or logs in which this entry should be included.
# e.g. '[user]' or '[user, api]'
# Include 'user' if the change is relevant to end users.
# Default: '[user]'
change_logs: []
19 changes: 19 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,25 @@ jobs:
path: build/dash0
retention-days: 1

test-e2e:
# Real dash0 binary + real git binary inside a container, proving
# --since's git-shell-out path works across a real process boundary --
# something in-process unit/integration tests can't cover. GitHub-hosted
# ubuntu-latest runners have a working Docker daemon natively, so no
# special runner capability (unlike self-hosted Docker-in-Docker) is
# needed here.
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1

- uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0
with:
go-version-file: go.mod

- name: Run end-to-end tests
run: make test-e2e

lint-go:
runs-on: ubuntu-latest
steps:
Expand Down
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ bin/
# Built binaries
build/

# Cross-compiled binary for the test-e2e Docker image (see test/e2e/setup_test.go)
test/e2e/dash0

# Tools binaries
.tools/

Expand Down
19 changes: 17 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
.PHONY: all build clean test test-unit test-integration test-roundtrip install lint lint-install lint-go-install lint-sh-install lint-go lint-sh chlog-install chlog-new chlog-validate chlog-preview chlog-update update-vendor-hash update-flake-lock skill-bundle skill-validate
.PHONY: all build clean test test-unit test-integration test-roundtrip test-e2e install lint lint-install lint-go-install lint-sh-install lint-go lint-sh chlog-install chlog-new chlog-validate chlog-preview chlog-update update-vendor-hash update-flake-lock skill-bundle skill-validate

all: lint test

Expand All @@ -17,7 +17,7 @@ CHLOGGEN=$(TOOLS_BIN_DIR)/chloggen
build:
(mkdir -p $(BUILD_DIR) || true) && go build -o $(BUILD_DIR)/$(BINARY_NAME) ./cmd/dash0

test: test-unit test-integration test-roundtrip
test: test-unit test-integration test-e2e test-roundtrip

test-unit:
go test -v ./...
Expand All @@ -28,6 +28,21 @@ test-integration:
test-roundtrip: build
bash test/roundtrip/run_all.sh

# End-to-end tests: the real dash0 binary + the real git binary inside a
# container, proving --since's git-shell-out path works across a real
# process boundary (in-process unit/integration tests can't). Gated behind
# Docker being available and kept separate from test-unit/test-integration
# given the added runtime cost and the Docker dependency.
#
# Colima users: testcontainers-go's Docker auto-detection doesn't recognize
# colima's non-standard socket forwarding. Export these first:
# export DOCKER_HOST="unix://$$HOME/.colima/default/docker.sock"
# export TESTCONTAINERS_DOCKER_SOCKET_OVERRIDE="/var/run/docker.sock"
test-e2e:
@command -v docker >/dev/null 2>&1 || { echo "Error: docker is required for test-e2e" >&2; exit 1; }
@docker version >/dev/null 2>&1 || { echo "Error: docker daemon is not reachable (is it running?)" >&2; exit 1; }
go test -v -tags=e2e ./test/e2e/...

install: build
cp $(BUILD_DIR)/$(BINARY_NAME) $(GOPATH)/bin/

Expand Down
12 changes: 12 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,10 @@ docker run ghcr.io/dash0hq/cli:latest [command]

Multi-architecture images (`linux/amd64`, `linux/arm64`) are published to GitHub Container Registry.

> [!NOTE]
> This image is built `FROM scratch` and has no shell or other tools installed, including `git`.
> Commands that shell out to `git` (currently `apply --since`) are unavailable from it.

### Nix / NixOS

The repository is a Nix flake that builds the CLI with `buildGoModule` and installs shell completions for Bash, Zsh, and Fish.
Expand Down Expand Up @@ -373,6 +377,14 @@ Validate without applying:
dash0 apply -f assets.yaml --dry-run
```

Sync a directory to match its state as of a git ref, deleting assets removed since then (experimental, requires `-X`):

```bash
dash0 -X apply -f dashboards/ --since HEAD~1 --force
```

See [Command Reference](docs/commands.md#apply---since-experimental) for the full `--since` reference, including the ref-resolution edge cases and the GitHub Actions invocation pattern.

**Note:** In Dash0, dashboards, views, synthetic checks and check rules are called "assets", rather than the more common "resources".
The reason for this is that the word "resource" is overloaded in OpenTelemetry, where it describes "where telemetry comes from".

Expand Down
Loading
Loading