Dashboard › craft › Distillation
74bf6bb5-7aa7-4439-a002-a7aadcb36a4a["lore_tm_v1_YjStx8bMbHpy4fcOXmD-vHZNhafj69mKRUzKsgghyfE","lore_tm_v1_8rzOOGYLiCBXwhOwcRBXx_Px4yvQS_9rA-UAnO--PsQ","lore_tm_v1_KLJSDzfdumDgmthrqlxIFxH1RgCytYgVBkA_Irty8X8"]
Date: Aug 29, 2026
.github/workflows/release.yml, action.yml, docs/src/content/docs/targets/github.md, src/__tests__/action.test.ts, src/__tests__/config.test.ts, src/commands/__tests__/publish.test.ts, src/commands/publish.ts, src/config.ts, src/index.ts, and src/schemas/project_config.ts..github/workflows/release.yml adds optional workspace inputs to both workflow_dispatch and workflow_call, described as “Named Craft release workspace to prepare and publish”; it forwards github.event.inputs.workspace to the local ./ Prepare release action and inputs.workspace to the externally published getsentry/craft action.action.yml adds optional workspace input and a first composite-action step, Validate workspace, before release-blocker checks or other side effects. It rejects simultaneous nonempty WORKSPACE plus PATH_INPUT != '.' with The path and workspace inputs cannot be used together., and rejects workspace names not matching /^[A-Za-z0-9_.-]+$/ with Workspace names must use only ASCII letters, digits, periods, underscores, and hyphens..action.yml forwards inputs.workspace as WORKSPACE to Craft Prepare, Read Craft Targets, and Request publish. Craft Prepare appends "--workspace=$WORKSPACE" to CRAFT_ARGS; Read Craft Targets runs craft targets "${CRAFT_ARGS[@]}"; this inline --workspace= form ensures option-looking workspace strings are forwarded as values rather than separate CLI options.publish: ${GITHUB_REPOSITORY}${SUBDIRECTORY}${WORKSPACE:+/$WORKSPACE}@${RESOLVED_VERSION}. Example tested titles are publish: getsentry/toolkit@1.2.3 without a workspace and publish: getsentry/toolkit/cli@1.2.3 for workspace cli.src/__tests__/action.test.ts creates temporary mock craft, git, and gh executables and executes action shell steps directly. Tests verify --config-from=untrusted is passed as --workspace=--config-from=untrusted to both craft prepare and craft targets; verify workspace env forwarding; require Validate workspace as the first action step; reject tab control characters, RTL override \u202e, line separator \u2028, paragraph separator \u2029, and non-ASCII é before any git/Craft calls in both C and en_US.utf8 locales; accept '' and cli-v2; reject cli combined with packages/cli; and reject cli/v2.github.projectPath: WorkspaceSchema.github remains a partial GitHubGlobalConfigSchema but refines github.projectPath === undefined with Workspace github.projectPath is not supported.. Workspace github overrides may specify owner and/or repo, inherited shallowly from top-level configuration.WorkspaceNameSchema validates names against /^[A-Za-z0-9_.-]+$/ and explicitly rejects __proto__ with Workspace name "__proto__" is not supported. because assigning that key to a normal object mutates its prototype instead of adding an own workspace entry.CraftProjectConfigSchema now uses z.record(WorkspaceNameSchema, WorkspaceSchema) and a superRefine rule: nonempty workspaces cannot coexist with base github.projectPath; validation reports Workspace configurations cannot use github.projectPath. at ['github', 'projectPath']. An empty workspace map still permits base github.projectPath.src/config.ts updates workspace GitHub resolution to shallow-merge only owner and repo; it preserves the existing behavior of omitting incomplete merged GitHub config so getGlobalGitHubConfig() can fall back to Git remote detection.src/config.ts factors workspace-version gating into checkWorkspacesMinVersion(config), which throws Using "workspaces" requires minVersion >= ${WORKSPACES_MIN_VERSION} in the configuration file. when minVersion is insufficient.src/config.ts adds getWorkspaceNames(): string[], which reads the raw .craft.yml via getConfigFilePath(), validates it, checks minimal config version, returns Object.keys(parsed.workspaces || {}) without applying an active workspace selection, and enforces WORKSPACES_MIN_VERSION only when the workspace map is nonempty. Tests verify raw names ['cli', 'mcp'] can be discovered without selection and insufficient minVersion: 2.14.0 fails.src/index.ts imports * as workspace from './commands/workspace' and registers it through .command(workspace), adding the workspace command to Craft’s yargs CLI command set.src/commands/publish.ts adds getPublishStateGitHubConfig(githubConfig, stateRepository = process.env.CRAFT_PUBLISH_STATE_GITHUB_REPO). If CRAFT_PUBLISH_STATE_GITHUB_REPO is unset, it retains resolved workspace GitHub config; if set, it must match /^(?<owner>[A-Za-z0-9_.-]+)\/(?<repo>[A-Za-z0-9_.-]+)$/, otherwise throws CRAFT_PUBLISH_STATE_GITHUB_REPO must be a GitHub owner/repository pair.; valid values override only publish-state identity to { owner, repo }.publishMain() now passes getPublishStateGitHubConfig(publishStateGithubConfig) to getPublishStatePath(newVersion, ..., process.cwd(), getActiveWorkspace()), allowing a Publish controller’s secure state file to identify the issue checkout repository even when a workspace publishes to a different GitHub owner/repository.src/commands/__tests__/publish.test.ts verifies controller state identity: resolved workspace config { owner: 'release-owner', repo: 'release-repo', projectPath: 'packages/cli' } plus controller repository getsentry/toolkit resolves state config to { owner: 'getsentry', repo: 'toolkit' }, producing the same getPublishStateFilename('1.2.3', ..., '/github/workspace/__repo__/packages/cli', 'cli'); it also verifies no override retains object identity and malformed getsentry/toolkit/extra is rejected.publishMain() replaces direct git.raw('name-rev', '--name-only', '--no-undefined', rev).trim() with new exported getRevisionBranchName(git, revision). The helper returns the named ref when available but catches lookup errors and returns '', allowing a CI-approved SHA to be checked out detached via the revision itself; tests cover named ref release/1.2.3 for abc123 and rejected name-rev returning an empty string.