Skip to content

feat(github-actions): add sync-assets composite action - #285

Merged
mmanciop merged 6 commits into
mainfrom
feat/sync-assets-action
Sep 14, 2026
Merged

feat(github-actions): add sync-assets composite action#285
mmanciop merged 6 commits into
mainfrom
feat/sync-assets-action

Conversation

@mmanciop

Copy link
Copy Markdown
Member

Wraps dash0 apply --since <ref> and resolves whether --since is safe to pass from the triggering GitHub Actions event, so a workflow doesn't have to hand-write the github.event.before gating that pattern otherwise requires (git's all-zeros SHA sentinel on a branch's first push, before being unset on workflow_dispatch/schedule/pull_request, and correct quoting).

@mmanciop
mmanciop requested a review from a team as a code owner September 10, 2026 17:48
@mmanciop
mmanciop marked this pull request as draft September 10, 2026 17:54
Wraps `dash0 apply --since <ref>` and resolves whether --since is safe to
pass from the triggering GitHub Actions event, so a workflow doesn't have
to hand-write the github.event.before gating that pattern otherwise
requires (git's all-zeros SHA sentinel on a branch's first push, before
being unset on workflow_dispatch/schedule/pull_request, and correct
quoting).

The since input has three states: auto (derive from the event, the
default), none (unconditionally disable deletion detection), or any other
value (an explicit comparison ref, for triggers with no before). An
explicit empty string or all-zeros SHA fails the job immediately instead
of being folded into the same "nothing to do" path as auto finding no
prior state -- unlike the event-derived case, an explicit override has no
routine excuse for either value and it's almost always a broken
expression.

Before invoking dash0, the action verifies a resolved ref both resolves
in the checkout and is an ancestor of HEAD, since the action always
passes --force (no TTY for a confirmation prompt in CI) -- once --force
is set, apply --since's own non-ancestor handling degrades to a
stderr-only warning, so this preflight restores a real backstop against a
force-pushed or rewritten branch. accept-non-ancestor-ref is the explicit
opt-out.

The action always runs a zero-API-call `apply --dry-run --agent-mode`
preflight first, exposing structured deletions/modifications outputs and
enforcing an optional max-deletions circuit breaker before any mutating
call -- dry-run combined with since: none needs no credentials at all.

Includes README, docs/github-actions.md and docs/github-actions-maintenance.md
updates, sync-docs transformation entries, a changelog entry (tracking
issue #277), and a test workflow covering ref resolution and its explicit-
empty/all-zeros hard failures, the ancestry preflight and its opt-out,
dry-run plan outputs, the max-deletions circuit breaker, and a real
end-to-end create/delete cycle.
@mmanciop
mmanciop force-pushed the feat/sync-assets-action branch from 9cf7eb7 to 4d989cb Compare September 10, 2026 18:08
Squashing the branch history dropped three fixes made against CI
feedback on PR #285; reapplying them on top of the new base commit:

- arm64 job invoked the action with path: ci-scratch without ever
  creating that directory, so the real (non-wrapped) CLI failed with
  "no such file or directory". Add the same scratch-fixture step every
  other ci-scratch job already has.
- End-to-end deletion check used `dashboards get`, but Dash0 soft-deletes
  assets (dash0.com/deleted-at), so get by id still returns a deleted
  dashboard. Switch to `dashboards list --all -o json`, matching how
  test/roundtrip/test_dashboard_roundtrip.sh already verifies deletion.
- Four job names started lowercase because they led with a code
  identifier (since, accept-non-ancestor-ref, dry-run, max-deletions);
  capitalized them to match every other job name in the file.
@mmanciop
mmanciop marked this pull request as ready for review September 10, 2026 18:16
Comment thread .github/actions/sync-assets/action.yaml
Comment thread .github/actions/sync-assets/action.yaml Outdated
Comment thread .github/actions/sync-assets/action.yaml
Comment thread .github/actions/sync-assets/action.yaml Outdated
Comment thread .github/actions/sync-assets/action.yaml Outdated
Comment thread .github/actions/sync-assets/action.yaml Outdated
Comment thread .github/actions/sync-assets/action.yaml Outdated
Comment thread .github/workflows/test-sync-assets-action.yml
Comment thread .github/actions/sync-assets/README.md Outdated
Comment thread .github/actions/sync-assets/README.md Outdated
Comment thread .github/actions/sync-assets/README.md
Comment thread .chloggen/feat_sync-assets-action.yaml Outdated
- since: auto no longer derives a comparison ref on pull_request events,
  even though synchronize sets github.event.before -- with real
  credentials and dry-run: false, that before was resolvable and an
  ancestor, so a PR that temporarily removed an asset file would delete
  the live asset via the action's internal --force. auto now only
  derives from a push event; pull_request/workflow_dispatch/schedule
  always need an explicit since ref for deletion detection.
- cli-version's minimum is 1.17.0, not 1.1.0: this action depends on
  apply --since and --dry-run --agent-mode JSON output, both introduced
  there. resolve-cli-version.sh gained an optional MIN_VERSION override
  (default unchanged at 1.1.0) so sync-assets can enforce its own floor
  without affecting setup/send-log-event.
- Profile detection now reads `dash0 config show -o json` instead of
  grepping the human-readable output, which agent-mode auto-detection
  (e.g. GITHUB_COPILOT) can silently switch to JSON, causing this
  action to overwrite an existing same-named profile instead of
  updating it.
- git merge-base --is-ancestor's exit code is now checked precisely:
  only exit 1 (genuinely not an ancestor) is treated as a possible
  force-push; any other nonzero exit is always a hard failure, since
  accept-non-ancestor-ref should never mask an unrelated git error.
- The unresolvable-ref error message now also names a force-push/rebase
  orphaning history as a possible cause, since no checkout depth
  fetches commits unreachable from any branch or tag.
- max-deletions now validates its value is a non-negative integer
  before use, with a clear ::error:: instead of an opaque `integer
  expression expected` failure under set -e.
- Fixed lazy "deletion(s)"/"asset(s)" pluralization in the action and
  README per docs/code-style.md.
- Dropped a test assertion on a composite step's outputs after that
  same step intentionally failed (unclear whether GitHub Actions
  guarantees those get published); the sibling failure tests already
  assert only on outcome.
- README bullets trimmed to state observable behavior; the rationale
  moved to docs/github-actions-maintenance.md.
- Shrunk the changelog subtext.
- Added a regression test asserting since: auto omits --since when
  this workflow itself runs on a pull_request trigger.
Removed redundant explanation about the 'since' input states and preflight checks.
sync-assets and send-log-event each had an almost-identical inline
"Create or update Dash0 profile" step. Extract it to
.github/actions/lib/ensure-profile.sh, following the existing
resolve-cli-version.sh/download-cli.sh pattern.

This also fixes send-log-event's copy of the agent-mode profile
detection bug (grepping dash0 config show's human-readable output,
which agent mode -- auto-detected from env vars like GITHUB_COPILOT --
switches to JSON) that was already fixed in sync-assets but not
propagated to its sibling.

REQUIRE_PROFILE parameterizes the one real behavioral difference:
send-log-event always needs credentials (hard error), sync-assets has
a credential-free dry-run path (soft warning).
ensure-profile.sh's dash0 config show -o json unconditionally broke
send-log-event's own supported floor (CLI 1.1.0): -o json for config
show landed in v1.8.0 alongside agent mode itself, so an older CLI
rejects the unknown -o flag outright, and the script (set -e) died
silently with no output. sync-assets was unaffected since its own
floor is already 1.17.0.

Falls back to the old human-readable-output parsing when -o json
itself fails. Safe by construction: a CLI old enough to lack -o json
also lacks agent-mode auto-detection, so the JSON-output trap that
`-o json` exists to dodge cannot occur on that fallback path.
@mmanciop
mmanciop merged commit 0b45e80 into main Sep 14, 2026
36 checks passed
@mmanciop
mmanciop deleted the feat/sync-assets-action branch September 14, 2026 08:28
@github-actions github-actions Bot locked and limited conversation to collaborators Sep 14, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants