Dashboard › craft › Distillation
084f02ab-1ad8-44ad-bfd1-138ee0a8c4f4["lore_tm_v1_-OfjWX39LvbD1Rgc4FoCw9M31i9JNkUfZTopmPpiAeg","lore_tm_v1_T_WrY5fPo3UGRuZtovDLN76KKAx1odU7VZFtinePtGw","lore_tm_v1_5YHHxjWwiKLrMNSmodvoXFFeEYZ0SSOWrz8gnJz_z6I","lore_tm_v1_PzyriSnGZrk3_erdCHYEqWl55Y7ZajrdnF84Cul5CSQ","lore_tm_v1_4Lcs-FIkBdHVPx_LSrZk-rkEwTQjCnYFh7tjtYQc4f8","lore_tm_v1_y9xAYHGyKGSF8vP5SdzobbchpbLsy24tcv99-M8ZEmU","lore_tm_v1_Xr1g6l_HNm_qPJYLfpVTFE36cUb-aUwUFZbR55kKby8","lore_tm_v1_OhX_db1vMfjN02tJAU6vl_I9e36zce8xaHLf_ZBIUp8","lore_tm_v1_Zjh1ZO2lc-lv0K07_cJqjWk9UtF_9crTkkURulysyKY","lore_tm_v1_yimPAi5jdobCjwTyyhyPvjB-6_01wxzqoYoysUnoXG0"]
Date: Sep 8, 2026
workflow_dispatch for manual recovery; .github/workflows/ci-poller.yml check-ci gate is vars.CI_POLLER_HAS_PENDING == 'true' || github.event_name == 'workflow_dispatch'.ci-ready after checking CI; publish.yml relies on the fresh ci-ready labeled event to trigger publishing, while the prior waiting-for-CI flow removes any existing ci-ready..github/workflows/ci-poller.yml: upgraded publish-controller checkout from actions/checkout@v5 to actions/checkout@v7.printf '%s' "$issue" | jq -jr '.body' > "$body_file" into mktemp; PUBLISH_ISSUE_BODY_FILE is passed to src/publish/resolve-ci-poller-input.js; trap removes body_file, resolver_output_file, and updated_body_file on exit.resolver_output_file; jq -ejr 'if (.issueBody | type) == "string" then .issueBody else error("Expected issueBody string") end' writes updated_body_file; gh issue edit ... --body-file "$updated_body_file" replaces prior shell-string --body update. Parse/decode failures emit warnings and skip only that issue.continue to exit 0 within the new per-issue subshell, preventing malformed input/API failures/no CI artifacts from terminating or contaminating processing of other issues in the while pipeline.ci-pending and accepted; uses sentry-internal-app token for same-repo label changes and sentry-release-bot token for cross-repo status/check-suite/check-run APIs; resolves a release branch from original SHA check suites, then branch head SHA, falling back to issue SHA on nonfatal API failures..github/workflows/ci-poller.yml: at least one check run or commit status must exist; commit status must be success or have total_statuses == 0; pending_checks == 0; unsuccessful_checks == 0, where success, neutral, and skipped check conclusions pass. On ready, removes ci-pending, adds ci-ready, and comments that publishing is starting.ci-pending to ci-failed, remove accepted, and comment failed check names plus check-runs URL; a failing/error combined commit status with otherwise passing completed check runs performs the same label transition and comments failed status contexts/URLs. Retrying requires re-adding accepted after CI is fixed.ci-pending + accepted issues and synchronizes CI_POLLER_HAS_PENDING to "false" when zero or "true" otherwise using CI_POLLER_APP_* token; self-dispatches ci-poller.yml approximately every 30–60 seconds while pending, capped at 60 attempts (~30 minutes), then relies on cron fallback. Concurrency group ci-status-poller permits 1 running + 1 queued run.src/modules/release-revision.js was changed from hard-coded regex extraction/replacement to generated publish-issue-title parser rules: CheckRunsLinkCount must equal 1; ReleaseRevision yields details including repo, mergeTarget, and revision source offsets. New getReleaseRevisionDetails() validates repo match; getReleaseRevision() returns .revision.value; updateReleaseRevision() slices by .revision.start/.revision.end.updateReleaseRevision({ issueBody, repo, revision }) now rejects invalid revisions unless they match /^[0-9a-f]{40}$/, throwing "Release revision must be a lowercase 40-character SHA.".src/publish/resolve-ci-poller-input.js now supports lossless file-based issue bodies: reads PUBLISH_ISSUE_BODY_FILE with readFileSync(..., "utf8") when set, otherwise uses PUBLISH_ISSUE_BODY || ""; invokes getCiPollerInput({ issueBody, title: PUBLISH_TITLE || "", revision: PUBLISH_REVISION || "" }).src/modules/ci-poller-input.js validates parsed publish title repository, version, and path; obtains current release revision from the issue body; returns { repo: "getsentry/${repo}", revision: currentRevision, version } and includes updated issueBody only when a replacement revision was supplied.src/publish/inputs.js now uses core.setOutput('result', JSON.stringify(result)) rather than passing an object directly.src/publish/resolve-location.js now defaults malformed/missing JSON sources safely to PUBLISH_ARGS || "{}" and CRAFT_WORKSPACE_NAMES || "[]", verifies workspace names are an array, and serializes resolvePublishLocation(...) via JSON.stringify for the "result" output.src/publish/discover-location.js: requires PUBLISH_ARGS.path; if target checkout lacks .craft.yml, returns no workspace names; otherwise runs docker run --rm --volume ${path.resolve(repositoryDirectory)}:/github/workspace/__repo__ --workdir /github/workspace/__repo__ getsentry/craft:latest workspace list, JSON-parses and validates an array, then calls resolvePublishLocation. Defaults PUBLISH_REPOSITORY_DIRECTORY to "__repo__" and exports discoverLocation and getWorkspaceNames.publish.yml now invokes node .__publish__/src/publish/discover-location.js with PUBLISH_REPOSITORY_DIRECTORY: __repo__, replacing inline shell-based Craft workspace discovery.src/modules/publish-location.js resolves "." as { path: "." }; for a valid ./... path matching a discovered workspace name, resolves to { path: ".", workspace }; otherwise returns { path }. Valid path/workspace segments match /^[A-Za-z0-9_.-]+$/, cannot be ., .., __proto__, or begin with -.src/publish/resolve-release-revision.js now defaults PUBLISH_ARGS to "{}" and explicitly throws "Publish input must define a repository." when repo is absent before extracting the canonical release revision.src/modules/details-from-context.js parses/validates publish issue title repository, release version, and path; derives dry_run as "1" when label dry-run exists (otherwise ""); derives merge_target as "" for "(default)"; parses checked targets from the issue-body Targets section; returns title details plus dry_run, merge_target, normalized path, and targets.