Dashboard › craft › Distillation
b9016272-a399-4175-8b7e-ded8d7b5a7fc["lore_tm_v1_DM08t73JYCWu87vAyYcwseHct9H877xTdvASNbtP-Co","lore_tm_v1_jbDKniSc5SAJS0DCVFD2LQWHuC0B2HMTfnBxlky1_30","lore_tm_v1_MCEBB5DBiroC9jycxM9QQw6Z9QcmN8yskA77Ap4SH7Y","lore_tm_v1_VtQo2ERoVMHoLtMh6apIl6ipvnmUxWd5WXJMtm8na_8","lore_tm_v1_6yFb-_NrI6lVjKjrULYPrIc_7Ji7FGb8f9fAvxVhhes","lore_tm_v1_AsJI6YZl8ibcNpUzhkSUnYeQvvshb49mGGEDvGEqTYk"]
Date: Sep 5, 2026
prepareMain(argv: PrepareOptions) in src/commands/prepare.ts supports argv.configFrom: warns that .craft.yml is being loaded from remote branch "${argv.configFrom}" and that its preReleaseCommand will execute, so caller must trust the branch; fetches [argv.remote, argv.configFrom], reads ${argv.remote}/${argv.configFrom}:${CONFIG_FILE_NAME} via git.show, obtains repository root via git.revparse(['--show-toplevel']), and calls loadConfigurationFromString(configContent, repositoryRoot.trim()). Any failure becomes ConfigurationError('Failed to load ${CONFIG_FILE_NAME} from branch "${argv.configFrom}": ${error.message}').--config-from loading, prepareMain() obtains config = getConfiguration() and githubConfig = await getGlobalGitHubConfig(), determines default branch with getDefaultBranch(git, argv.remote), chooses revision argv.rev || repoStatus.current || defaultBranch, skips checkGitStatus(repoStatus, rev) only when argv.noGitChecks (logging Not checking the status of the local repository), then resolves the release version through resolveVersion(git, { versionArg: argv.newVersion, calverOffset: argv.calverOffset }).getConfiguration(clearCache = false) in src/config.ts returns _configCache unless cleared; otherwise finds .craft.yml, YAML-loads it, calls validateConfiguration(rawConfig), applies checkMinimalConfigVersion(parsed), resolves selected workspace with applyWorkspaceSelection(parsed, path.dirname(configPath)), caches, and returns it.loadConfigurationFromString(configContent, workspaceDirectory = process.cwd()) YAML-loads remote/provided config, validates it, checks its minimum Craft version, applies workspace selection relative to workspaceDirectory, caches and returns the resolved configuration.getWorkspaceNames() loads and validates .craft.yml without applying workspace selection, expands names with getWorkspaceNamesFromConfig(parsed, path.dirname(configPath)), invokes checkWorkspacesMinVersion(parsed) only if one or more concrete names exist, and returns the names.validateConfiguration() parses through CraftProjectConfigSchema; Zod validation failures are transformed into ConfigurationError with newline-separated ${e.path.join('.')}: ${e.message} diagnostics.src/__tests__/action.test.ts test harness executes named shell steps from action.yml in temporary directories, using fake craft, git, and gh binaries. Fake craft fails if inherited CRAFT_WORKSPACE is nonempty, logs calls to $CRAFT_CALLS, and outputs ["github"] for craft targets; fake gh issue list outputs [], while gh issue create writes the --title argument to $GH_TITLES and returns https://github.com/getsentry/publish/issues/1.Validate workspace is the first action step; its PATH_INPUT environment is ${{ inputs.path }}, while Craft Prepare and Read Craft Targets receive WORKSPACE: ${{ inputs.workspace }}.cli\tnext), right-to-left override (cli\u202enext), Unicode line separator (cli\u2028next), paragraph separator (cli\u2029next), or non-ASCII (cli-é) before any git or craft side effect; cli-é is also rejected under LC_ALL=en_US.utf8.'', cli-v2, packages/cli, and packages/CLI; rejects unsafe checkout PATH_INPUT values ../outside, /tmp, ./packages/cli, packages//cli, and packages/../cli before side effects; and rejects providing both path='packages/cli' and workspace='cli'.cli\nnext, packages/*), reserved/unsafe workspace names ., .., __proto__, -foo, and --config, and unsafe paths ./packages/cli, packages//cli, packages/./cli, packages/../cli, packages/__proto__/cli, and packages/-cli, all before git or craft side effects.Request publish title uses the entire workspace path: root workspace produces publish: getsentry/toolkit@1.2.3; workspace packages/cli produces publish: getsentry/toolkit/packages/cli@1.2.3.Craft Prepare and Read Craft Targets clear inherited process.env.CRAFT_WORKSPACE='packages/cli': fake Craft succeeds and records exactly prepare\ntargets\n.src/__tests__/config.test.ts covers configuration schema acceptance for: minimal GitHub config { github: { owner: 'getsentry', repo: 'craft' } }; targets including { name: 'npm' } and GitHub tagPrefix: 'v'; changelog object { filePath: 'CHANGELOG.md', policy: 'auto', scopeGrouping: true }; changelog string 'CHANGELOG.md'; CalVer { offset: 14, format: '%y.%-m' }; and noMerge: true/false. It expects rejection of a GitHub config missing repo, invalid minVersion, and invalid changelog policy.WS_CONFIG has minVersion: ${WORKSPACES_MIN_VERSION}, top-level GitHub getsentry/toolkit, inherited changelog: CHANGELOG.md, and workspaces cli and mcp: cli overrides releaseBranchPrefix: release/cli and GitHub target tagPrefix: "cli@"; mcp overrides releaseBranchPrefix: release/mcp, versioning.policy: calver, and GitHub target tagPrefix: "mcp@".cli, override values win (releaseBranchPrefix='release/cli', getGitTagPrefix()='cli@') while top-level changelog='CHANGELOG.md' and GitHub owner/repo are inherited; resolved configuration strips workspaces. Selection mcp independently yields release/mcp, mcp@, and CalVer policy.defines workspaces; select one); require defined workspaces when a selection exists (no "workspaces" are defined); and reject unknown selected workspace nope plus prototype-named selections constructor, toString, and __proto__ as Unknown workspace.getWorkspaceNames() returns ['cli', 'mcp'] from literal workspace config without selection; if the same config has minVersion: 2.14.0, it throws requires minVersion >= ${WORKSPACES_MIN_VERSION}.packages/* expands only directories, yielding ['packages/cli', 'packages/mcp'] while ignoring packages/README.md; selecting packages/cli resolves its releaseBranchPrefix: 'release/package'. Remote string config glob expansion uses the explicitly passed repository-root directory even if current working directory is a nested directory.packages/[!a]* and packages/[^a]* yield ['packages/cli'] when directories are cli and api; braces packages/{cli,mcp} yield ['packages/cli', 'packages/mcp']; nested braces packages/{cli,{mcp,api}} yield sorted ['packages/api', 'packages/cli', 'packages/mcp']; packages/?li yields ['packages/cli']; packages/[cm]* yields ['packages/cli', 'packages/mcp']; and packages/**/cli yields ['packages/cli', 'packages/nested/cli'].packages/**/release, an internal directory packages/internal/release is returned but packages/external symlinked to an outside temporary directory is not traversed.{../outside/*,packages/*} and {/tmp/*,packages/*}), malformed brace globs packages/{cli, packages/{cli}, packages/{cli,{mcp}}, and packages/{cli,{{},mcp}}, and unsafe literal paths packages/./cli, packages/../cli, packages/__proto__/cli, packages/foo], packages/foo!, and packages/foo^, with Workspace paths must use safe ASCII segments..packages/cli matches both workspace patterns packages/* and packages/cli*, both getWorkspaceNames() and selected-workspace getConfiguration(true) throw an error identifying matches multiple workspace patterns: packages/*, packages/cli*.cli with minVersion: ${WORKSPACES_MIN_VERSION}+linux resolves successfully to release/cli; below-gate minVersion: 2.14.0 is rejected.setActiveWorkspace('cli') then loading WS_CONFIG produces Git tag prefix cli@; changing selection to setActiveWorkspace('mcp') and reloading produces mcp@, confirming cache/selection re-resolution.cli exposes its target array via resolved getConfiguration().targets as exactly [{ name: 'github', tagPrefix: 'cli@' }], because the publish builder reads this field to calculate --target choices and must not encounter the unselected-workspace error.cli@) return that prefix without warnings; conflicting prefixes cli@ versus mcp@, or one defined cli@ versus one omitted prefix, return the first cli@ and call logger.warn exactly once for ambiguous/different tagPrefix.