Skip to content

fix: parse the status JSON, pass superseded runs, derive GitHub context - #11

Merged
finalerock44 merged 6 commits into
mainfrom
fix/status-parsing-and-ci-context
Sep 24, 2026
Merged

finalerock44 merged 6 commits into
mainfrom
fix/status-parsing-and-ci-context

Conversation

@finalerock44

Copy link
Copy Markdown
Contributor

Summary

Four fixes to step.sh, from the 23 Sep docs-vs-production audit (plan section E1).

  1. Status outputs were always empty. dcd status --json prints pretty JSON (JSON.stringify(obj, null, 2)), and the compact-JSON greps ('"status":"..."') never matched it. So DEVICE_CLOUD_UPLOAD_STATUS, DEVICE_CLOUD_FLOW_RESULTS and DEVICE_CLOUD_APP_BINARY_ID were empty on every run. The step now reads the document with node, which is always there because the step runs the CLI through npx.

  2. Superseded runs pass. With cancel_previous, the older run's queued tests are cancelled, and /uploads/status rolls them up to FAILED. The status now carries supersededBy: <uploadId> (dcd C2, not live yet). When that field is present the step:

    • logs Superseded by <id> and the newer run's console link;
    • sets DEVICE_CLOUD_UPLOAD_STATUS=SUPERSEDED;
    • exits 0, whatever dcd exited with.

    This mirrors dcd cloud 5.6.0. Nothing changes when the field is absent.

  3. The API key is no longer printed. Both the variables dump and the echoed command line printed it; they now show [REDACTED].

  4. GitHub context is derived from Bitrise env vars. GitHub checks need gh_repo + gh_sha, and cancel_previous needs gh_repo + a PR or branch. Until now the step only sent gh_check_name, so neither worked on Bitrise. For github.com repositories it now attaches:

    • gh_repo from GIT_REPOSITORY_URL (https, ssh and scp-style remotes);
    • gh_sha from BITRISE_GIT_COMMIT, else GIT_CLONE_COMMIT_HASH;
    • gh_branch from BITRISE_GIT_BRANCH;
    • gh_pr_number and gh_pr_url from BITRISE_PULL_REQUEST.

    For any repository it also attaches gh_run_id, from BITRISEIO_PIPELINE_ID (the "ID of the running Pipeline build", which every workflow in the pipeline shares), else BITRISE_BUILD_SLUG. The server treats uploads with the same run id as siblings, so parallel workflows of one pipeline don't cancel each other.

    • Keys set in metadata win.
    • A new include_github_context input (default true) turns it all off.

Behaviour changes to note

  • json_file: true now fails failed runs. dcd cloud --json-file exits 0 on a failed run, so while the status was unparsed, those builds went green on failures. They now fail on a FAILED status.
    • A json_file run whose status can't be read now fails too, instead of passing. Async runs are the exception.
    • A superseded run still passes.
  • Checks may start appearing. Orgs that have the DeviceCloud GitHub App installed will start getting checks from Bitrise builds of GitHub repos. check_name names those checks, and include_github_context: "false" opts out.
  • ERROR is a new status value, reported when the status call returns no JSON at all. The verdict then comes from dcd's exit code, as before.
  • DEVICE_CLOUD_FLOW_RESULTS has a fixed shape: [{name, status, failReason?}].

Tests

bats test/test.bats: 38 tests pass, under bash 5.2 and under macOS bash 3.2.

  • The two skipped [known bug] tests are unskipped.
  • New fixture tests (test/fixtures/*.json, pretty-printed like the real CLI) cover passing, failed and superseded runs.
  • The json_file cases are FAILED → fails, PASSED → passes, superseded → passes, and unreadable status → fails.
  • Also covered: an older CLI exiting 2 on a superseded run, compact and noisy output, no JSON at all, the API key never appearing in the step's own output, and GitHub context derivation (remote formats, other hosts, metadata overrides, opt-out).

The npx stub mimics --json-file (exit 2 → 0). I checked the new tests against the old step.sh and they fail there. shellcheck --shell=bash step.sh reports only the 47 existing advisory findings.

Not run: the bitrise.yml test workflow (it needs a real API key and a sample app), and stepman audit (the bitrise CLI isn't installed). step.yml parses, and all 46 inputs have a title and summary.

Release

Don't release yet. The plan is 1.4.0, including cancel_previous, once the steplib approves 1.3.0 (bitrise-io/bitrise-steplib#5260). The supersededBy branch only takes effect once dcd returns the field.

🤖 Generated with Claude Code

`dcd status --json` prints pretty JSON (JSON.stringify(obj, null, 2)), so
the compact-JSON greps ('"status":"...') never matched and
DEVICE_CLOUD_UPLOAD_STATUS, DEVICE_CLOUD_FLOW_RESULTS and
DEVICE_CLOUD_APP_BINARY_ID were always empty. Read the document with node,
which is always present because the step runs the CLI through npx.

- DEVICE_CLOUD_FLOW_RESULTS is now a JSON array of {name, status,
  failReason?}.
- A status call that returns no JSON reports ERROR; the verdict then rests
  on the CLI exit code, as before.
- The verdict logic is unchanged, but a FAILED status now actually fails the
  step. That matters with json_file: `dcd cloud --json-file` exits 0 on a
  failed run, so until now those runs passed the step. For the same reason,
  json_file runs whose status cannot be read now fail instead of passing
  (async submissions excepted).

Unskips the two known-bug tests and adds fixture tests for passing,
failing, json_file, compact and noisy status output.
With cancel_previous, a newer run from the same CI context cancels the
older run's queued tests. /uploads/status rolls those cancelled tests up to
FAILED, so the older build went red for work nobody is waiting on. The
status now carries `supersededBy: <uploadId>` for such a run: log
"Superseded by <id>" with the newer run's console link, set
DEVICE_CLOUD_UPLOAD_STATUS to SUPERSEDED and exit 0, whatever dcd exited
with (an older CLI exits 2 for it). This mirrors `dcd cloud` 5.6.0, which
exits 0 for a superseded run.

Nothing changes when the field is absent, as it is on every other run and
on APIs that predate it.
The variables dump and the echoed command line both printed api_key in
full. Print [REDACTED] instead; the key is still passed to the CLI.
GitHub checks need gh_repo + gh_sha on the run, and cancel_previous
groups runs by gh_repo + gh_pr_number/gh_branch (+ gh_check_name). The
step only ever sent gh_check_name, so on Bitrise neither worked unless
users hand-wrote the keys into `metadata`.

For a github.com repository the step now attaches:
- gh_repo from GIT_REPOSITORY_URL (https, ssh:// and scp-style remotes;
  other hosts, including GitHub Enterprise, get no gh_repo)
- gh_sha from BITRISE_GIT_COMMIT, else GIT_CLONE_COMMIT_HASH
- gh_branch from BITRISE_GIT_BRANCH
- gh_pr_number and gh_pr_url from BITRISE_PULL_REQUEST

and, for any repository, gh_run_id from BITRISEIO_PIPELINE_ID (the
pipeline build, shared by every workflow in it), else BITRISE_BUILD_SLUG.
The server treats uploads with the same run id as siblings, so parallel
iOS/Android workflows of one pipeline no longer cancel each other.

A key already set in the metadata input wins; gh_pr_url is only built
alongside a derived gh_repo. A new include_github_context input (default
true) turns all of it off.
- README: the outputs and their values (including SUPERSEDED and ERROR),
  the gh_* context derived from Bitrise env vars, and how to run the tests
  (bash 4.1+, since bash 3.2 lets a mid-test [[ ]] assertion pass).
- step.yml: android_no_snapshot is automatic from API 34, not 35; json no
  longer claims to force exit code 0; json_file writes
  <upload_id>_dcd.json and still fails a failed run.
Share config for bitrise run share-this-step: the step version was never bumped from 1.0.0, and the fork URL pointed at this repo instead of the devicecloud-dev/bitrise-steplib fork the 1.3.0 steplib PR came from.
@finalerock44 finalerock44 self-assigned this Sep 24, 2026
@finalerock44
finalerock44 merged commit e1508b4 into main Sep 24, 2026
4 checks passed
@finalerock44
finalerock44 deleted the fix/status-parsing-and-ci-context branch September 24, 2026 15:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant