Dashboard › craft › Session 0wUxvyF8Cenq
0wUxvyF8Cenq6Sc1pRead-only review only. The previous reviewer stalled; independently assess this proposed backwards-compatible design across these worktrees: /home/byk/Code/getsentry/craft-workspace-action-propagation and /home/byk/Code/getsentry/publish-workspace-acceptance.
Goal: replace JSON workspace title markers with a compact title that uses an optional trailing path-like segment. A new Craft request will put the materialized release branch in its issue body. For new requests that carry this field, Publish should check out that exact release branch, then inspect its .craft.yml: if the single trailing title segment is a configured workspace, interpret it as workspace from checkout root; otherwise interpret it as existing checkout path. Existing issues without the new body field must remain legacy path interpretation. Craft must reject action path+workspace combinations and workspace config with github.projectPath to keep new title meaning unambiguous.
Inspect actual code/tests/workflows and return concise adversarial findings with severity, exact file:line citations, concrete minimal corrections, plus MERGE/DO-NOT-MERGE design verdict. Analyze security, title collisions, branch trust/selection, workflow dispatch/CI compatibility, config resolution, state path identity, legacy behavior, and testability. Do not edit anything. Return only the review report.
<path>/home/byk/Code/getsentry/craft-workspace-action-propagation</path> <type>directory</type> <entries> .craft.yml .dockerignore .eslintcache .git .github/ .gitignore .lore.md .nojekyll .npmignore .prettierignore .prettierrc.yml .tsbuildinfo .vscode/ action.yml AGENTS.md blog-post-draft.md build.mjs CHANGELOG.md CONTRIBUTING.md dist/ Dockerfile docs/ eslint.config.mjs img/ LICENSE node_modules/ package.json pnpm-lock.yaml README.md src/ tsconfig.build.json tsconfig.json vitest.config.mts (33 entries) </entries>
<path>/home/byk/Code/getsentry/publish-workspace-acceptance</path> <type>directory</type> <entries> .eslintrc.js .git .github/ .gitignore AGENTS.md auto-approve-repos.txt docs/ LICENSE node_modules/ package.json README.md src/ vitest.config.js yarn.lock (14 entries) </entries>
<path>/home/byk/Code/getsentry/craft-workspace-action-propagation/AGENTS.md</path> <type>file</type> <content> 1: # AGENTS.md 2: 3: This file provides guidance for AI coding assistants working with the Craft codebase. 4: 5: ## Package Management 6: 7: - **Always use `pnpm`** for package management. Never use `npm` or `yarn`. 8: - Node.js version is managed by [Volta](https://volta.sh/) (currently v22.12.0). 9: - Install dependencies with `pnpm install --frozen-lockfile`. 10: 11: ## Development Commands 12: 13: | Command | Description | 14: | ------------ | ------------------------------------------- | 15: | `pnpm build` | Build the project (outputs to `dist/craft`) | 16: | `pnpm test` | Run tests | 17: | `pnpm lint` | Run ESLint | 18: | `pnpm fix` | Auto-fix lint issues | 19: 20: To manually test changes: 21: 22: ```bash 23: pnpm build && ...
<path>/home/byk/Code/getsentry/publish-workspace-acceptance/AGENTS.md</path> <type>file</type> <content> 1: # AGENTS.md - Coding Agent Guidelines 2: 3: This document provides guidelines for AI coding agents working in this repository. 4: 5: ## Project Overview 6: 7: This is the **Sentry Publish Repository** - a GitHub Actions-based approval system for publishing releases across multiple Sentry projects using [Craft](https://github.com/getsentry/craft). It's a pure JavaScript (Node.js 24.0.0) project using CommonJS modules. 8: 9: ## Build/Lint/Test Commands 10: 11: ### Package Manager 12: 13: - **Yarn 1.22.22** (classic) - Do NOT use npm 14: - Version management via Volta (pinned in package.json) 15: 16: ### Commands 17: 18: ```bash 19: # Install dependencies 20: yarn install 21: 22: # Run all tests 23: yarn test 24: 25: # Run tests in watch mode 26: yarn test:watch 27: 28: # Run a single test file 29: yarn test src/modules/__tests__/update-issue.js 30: 31: # Run tests ...
6dae341 feat: propagate release workspaces 21270a1 feat(config): add release workspaces 32f5462 fix(git): prevent fatal error for missing 'origin' remote (#871) 5d0ec43 fix(registry): retry registry push with backoff on concurrent updates (#870) 35e8063 meta: Bump new development version b2524ef Merge branch 'release/2.30.1' cd1e829 release: 2.30.1 06180e3 fix(vercel): pass prebuilt output directory 29ad5c3 meta: Bump new development version c02eb03 Merge branch 'release/2.30.0' c79aff0 release: 2.30.0 76adb48 feat(vercel): allow project ID in target config (#867) 78bc73b meta: Bump new development version be1613d Merge branch 'release/2.29.0' 50bb44a release: 2.29.0 e5a7f97 fix(deps): bump vulnerable packages and add overrides (#866) .github/workflows/release.yml | 9 + CHANGELOG.md | 26 +++ action.yml | 35 ++- docs/package.json | 4 +- docs/pnpm-lock.yaml | 24 ...
fatal: ambiguous argument 'master..HEAD': unknown revision or path not in the working tree. Use '--' to separate paths from revisions, like this: 'git <command> [<revision>...] -- [<file>...]'
feat/workspace-acceptance chore/fix-security-advisories * feat/workspace-acceptance fix/add-workflow-permissions + main + opencode/tidy-orchid security/dual-write-publish-state security/remove-legacy-publish-state-write remotes/origin/HEAD -> origin/main remotes/origin/add-agents-md remotes/origin/chore/fix-security-advisories remotes/origin/ci/switch-to-sentry-internal-app remotes/origin/docs/deprecate-action-prepare-release remotes/origin/docs/mermaid-release-flow remotes/origin/feat/ci-poller-variable-gate remotes/origin/feat/ci-status-poller remotes/origin/feat/workspace-acceptance remotes/origin/fix/add-packages-write-permission remotes/origin/fix/add-workflow-permissions remotes/origin/fix/auto-approve-token remotes/origin/fix/ci-poller-gh-token remotes/origin/fix/ci-poller-variable-auth remotes/origin/fix/react-native-release-8-14-craft-config remotes/origin/fix/undici-security-vulnerability ...
.github/workflows/cocoapods-keepalive.yml | 2 +- .github/workflows/publish.yml | 27 ++- README.md | 5 + docs/publish-issue-format.md | 81 +++++++++ src/modules/__tests__/details-from-context.js | 230 +++++++++++++++++++++++++- src/modules/__tests__/publish-workflow.js | 82 +++++++++ src/modules/__tests__/update-issue.js | 15 +- src/modules/details-from-context.js | 33 +++- src/modules/update-issue.js | 54 +++--- 9 files changed, 488 insertions(+), 41 deletions(-) .github/workflows/cocoapods-keepalive.yml .github/workflows/publish.yml README.md docs/publish-issue-format.md src/modules/__tests__/details-from-context.js src/modules/__tests__/publish-workflow.js src/modules/__tests__/update-issue.js src/modules/details-from-context.js src/modules/update-issue.js
Found 27 matches
/home/byk/Code/getsentry/craft-workspace-action-propagation/action.yml:
Line 34: workspace:
Line 35: description: Named Craft release workspace to prepare and publish
Line 53: description: The release branch name
Line 56: description: The commit SHA on the release branch
Line 74: - name: Validate workspace
Line 77: WORKSPACE: ${{ inputs.workspace }}
Line 178: WORKSPACE: ${{ inputs.workspace }}
Line 190: CRAFT_ARGS+=("--workspace=$WORKSPACE")
Line 207: WORKSPACE: ${{ inputs.workspace }}
Line 211: CRAFT_ARGS=("--workspace=$WORKSPACE")
Line 236: WORKSPACE: ${{ inputs.workspace }}
Line 257: # the body template (~2 KB of surrounding markdown).
Line 260: CHANGELOG="${CHANGELOG:0:$MAX_CHANGELOG_CHARS}"$'\n\n---\n*Changelog truncated for issue body.*'
Line 263: workspace_title=""
Line 266: workspace_json=$(jq -Rn --arg workspace ...
<path>/home/byk/Code/getsentry/craft-workspace-action-propagation/action.yml</path>
<type>file</type>
<content>
1: name: 'Craft Prepare Release'
2: description: 'Prepare a new release using Craft'
3:
4: inputs:
5: version:
6: description: >
7: Version to release. Can be a semver string (e.g., "1.2.3"),
8: a bump type ("major", "minor", "patch"), or "auto" for automatic detection.
9: required: false
10: merge_target:
11: description: Target branch to merge into. Uses the default branch as a fallback. ...
<path>/home/byk/Code/getsentry/craft-workspace-action-propagation/src/config.ts</path>
<type>file</type>
<content>
1: import { existsSync, lstatSync, readFileSync } from 'fs';
2: import path from 'path';
3:
4: import { load } from 'js-yaml';
5: import GitUrlParse from 'git-url-parse';
6: import { createGitClient } from './utils/git';
7: import { ZodError } from 'zod';
8:
9: import { logger } from './logger';
10: import {
11: CraftProjectConfig,
12: CraftProjectConfigSchema,
13: GitHubGlobalConfig,
14: ArtifactProviderName,
15: StatusProviderName,
16: TargetConfig,
17: ChangelogPolicy,
18: VersioningPolicy,
19: Workspace,
20: } from './schemas/project_config';
21: import { ConfigurationError } from './utils/errors';
22: import { isCompiledGitHubAction } from './utils/detection';
23: import {
24: getPackageVersion,
25: parseVersion,
26: versionGreaterOrEqualThan,
27: SemVer,
28: } from './utils/version';
29: // Note: We import getTargetByName lazily in ...
<path>/home/byk/Code/getsentry/craft-workspace-action-propagation/src/schemas/project_config.ts</path>
<type>file</type>
<content>
1: import { z } from 'zod';
2:
3: /**
4: * DEPRECATED: Use changelog.policy instead. Different policies for changelog management
5: */
6: export const enum ChangelogPolicy {
7: Auto = 'auto',
8: Simple = 'simple',
9: None = 'none',
10: }
11:
12: /**
13: * Name of the status provider
14: */
15: export const enum StatusProviderName {
16: GitHub = 'github',
17: }
18:
19: /**
20: * Name of the artifact provider
21: */
22: export const enum ArtifactProviderName {
23: GCS = 'gcs',
24: GitHub = 'github',
25: None = 'none',
26: }
27:
28: /**
29: * Default versioning policy when no version argument is provided. ...
<path>/home/byk/Code/getsentry/publish-workspace-acceptance/src/modules/details-from-context.js</path>
<type>file</type>
<content>
1: /**
2: * Matches the entire "Targets" section of a github publish issue body.
3: */
4: const TARGETS_SECTION_PARSER_REGEX =
5: /^(?!### Targets$\s)(?: *- \[[ xX]\] \S+\s*$(?:\r?\n)?)+/m;
6:
7: /**
8: * Matches all targets of a github publish issue body in a section that was already matched and extracted with `TARGETS_PARSER_REGEX`.
9: * The "id" of the targets is captured within a capture group.
10: */
11: const TARGETS_PARSER_REGEX = /^\s*- \[[ x]\] (\S+)/gim;
12:
13: /**
14: * Matches checked targets of a github publish issue body in a section that was already matched and extracted with `TARGETS_PARSER_REGEX`.
15: * The "id" of the targets is captured within a capture group.
16: */
17: const CHECKED_TARGETS_PARSER_REGEX = /^\s*- \[x\] (\S+)/gim;
18:
19: async function detailsFromContext({ context }) {
20: if (!context || ...
<path>/home/byk/Code/getsentry/publish-workspace-acceptance/src/modules/update-issue.js</path>
<type>file</type>
<content>
1: const fs = require("fs");
2: const {
3: TARGETS_SECTION_PARSER_REGEX,
4: TARGETS_PARSER_REGEX,
5: } = require("./details-from-context");
6:
7: async function updateTargets({
8: octokit,
9: stateFilePath,
10: publishRepo,
11: issue_number,
12: }) {
13: if (!stateFilePath || !fs.existsSync(stateFilePath)) {
14: return;
15: }
16:
17: const issueRequest = octokit.rest.issues.get({
18: ...publishRepo,
19: issue_number,
20: });
21:
22: const craftStateRequest = fs.promises
23: .readFile(stateFilePath, { encoding: "utf-8" })
24: .then((data) => JSON.parse(data));
25:
26: const [{ data: issue }, craftState] = await Promise.all([
27: issueRequest,
28: craftStateRequest,
29: ]);
30:
31: const newIssueBody = transformIssueBody(craftState, issue.body);
32:
33: await octokit.rest.issues.update({
34: ...
<path>/home/byk/Code/getsentry/publish-workspace-acceptance/.github/workflows/publish.yml</path>
<type>file</type>
<content>
1: name: Publish
2: on:
3: issues:
4: types: [labeled]
5:
6: concurrency:
7: # Use the issue title (e.g. "publish: getsentry/foo@1.2.3") so duplicate
8: # issues for the same repo@version share a concurrency group.
9: group: ${{ github.event.issue.title }}
10: cancel-in-progress: false
11:
12: permissions:
13: contents: read
14: issues: write
15: packages: write
16:
17: jobs:
18: # When accepted is added to a publish issue:
19: # - Add ci-pending (and remove ci-failed if retrying)
20: # - Enable the poller via CI_POLLER_HAS_PENDING=true
21: # - Comment on the issue
22: # - Trigger the poller immediately so we don't wait for the next cron tick
23: # The publish job below requires ci-ready, so it will not fire until the
24: # poller flips ci-pending → ci-ready (which also prevents publishing without
25: # CI ...
<path>/home/byk/Code/getsentry/publish-workspace-acceptance/src/publish/inputs.js</path>
<type>file</type>
<content>
1: const github = require('@actions/github');
2: const core = require('@actions/core');
3: const { detailsFromContext } = require('../modules/details-from-context');
4:
5: async function inputs() {
6: const result = await detailsFromContext({
7: context: github.context,
8: });
9: core.setOutput('result', result);
10: }
11:
12:
13: inputs();
(End of file - total 13 lines)
</content>
commit 6dae341f9bc1378abde7a9022108caded2d22226
Author: Burak Yigit Kaya <byk@sentry.io>
AuthorDate: Wed Aug 26 14:16:47 2026 +0000
Commit: Burak Yigit Kaya <byk@sentry.io>
CommitDate: Wed Aug 26 14:16:47 2026 +0000
feat: propagate release workspaces
.github/workflows/release.yml | 9 +++
action.yml | 35 +++++++-
src/__tests__/action.test.ts | 144 +++++++++++++++++++++++++++++++++
src/commands/__tests__/publish.test.ts | 47 +++++++++++
src/commands/publish.ts | 33 +++++++-
5 files changed, 263 insertions(+), 5 deletions(-)
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 4e6c11e..323e8ba 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -1,142 +1,151 @@
name: Release
concurrency: ${{ github.workflow }}-${{ github.ref }}
on:
# For Craft's own releases (dogfooding)
workflow_dispatch:
inputs:
version:
...
commit 33de3f1df5bdb9a6a480e9217d566df7b5a48b8e
Author: Burak Yigit Kaya <byk@sentry.io>
AuthorDate: Wed Aug 26 14:15:22 2026 +0000
Commit: Burak Yigit Kaya <byk@sentry.io>
CommitDate: Wed Aug 26 14:15:22 2026 +0000
feat: accept workspace publish requests
.github/workflows/publish.yml | 27 +++-
src/modules/__tests__/details-from-context.js | 212 +++++++++++++++++++++++++-
src/modules/__tests__/publish-workflow.js | 82 ++++++++++
src/modules/__tests__/update-issue.js | 15 +-
src/modules/details-from-context.js | 27 +++-
src/modules/update-issue.js | 54 ++++---
6 files changed, 377 insertions(+), 40 deletions(-)
commit b658ffa0299fedf78c9dd9a2121cd740691ca157
Author: Burak Yigit Kaya <byk@sentry.io>
AuthorDate: Thu Aug 27 09:14:38 2026 +0000
Commit: Burak Yigit Kaya <byk@sentry.io>
CommitDate: Thu Aug 27 09:14:38 2026 +0000
fix: validate publish workspace JSON
...
<path>/home/byk/Code/getsentry/craft-workspace-action-propagation/src/__tests__/action.test.ts</path>
<type>file</type>
<content>
1: import {
2: chmodSync,
3: mkdtempSync,
4: mkdirSync,
5: readFileSync,
6: rmSync,
7: writeFileSync,
8: } from 'fs';
9: import { tmpdir } from 'os';
10: import { join } from 'path';
11: import { spawnSync } from 'child_process';
12:
13: import { load } from 'js-yaml';
14: import { afterEach, expect, test } from 'vitest';
15:
16: interface ActionStep {
17: env?: Record<string, string>;
18: name?: string;
19: run?: string;
20: }
21:
22: function getActionSteps(): ActionStep[] {
23: const action = load(
24: readFileSync(join(__dirname, '../../action.yml'), 'utf8'),
25: ) as {
26: runs?: { steps?: ActionStep[] };
27: };
28: return action.runs?.steps || [];
29: }
30:
31: function getActionStep(name: string): ActionStep {
32: const step = getActionSteps().find(step => step.name === name);
33: if (!step?.run) {
34: ...
<path>/home/byk/Code/getsentry/craft-workspace-action-propagation/src/__tests__/config.test.ts</path>
<type>file</type>
<content>
1: import { describe, test, expect, vi, afterEach } from 'vitest';
2: /**
3: * Tests of our ability to read craft config files. (This is NOT general test
4: * configuration).
5: */
6:
7: import {
8: getGitTagPrefix,
9: loadConfigurationFromString,
10: validateConfiguration,
11: setActiveWorkspace,
12: getActiveWorkspace,
13: getVersioningPolicy,
14: WORKSPACES_MIN_VERSION,
15: } from '../config';
16: import { CraftProjectConfigSchema } from '../schemas/project_config';
17: import { logger } from '../logger';
18:
19: describe('validateConfiguration', () => {
20: test('parses minimal configuration', () => {
21: const data = { github: { owner: 'getsentry', repo: 'craft' } };
22:
23: expect(validateConfiguration(data)).toEqual(data);
24: });
25:
26: test('parses configuration with targets', () => {
27: const data = {
28: ...
<path>/home/byk/Code/getsentry/craft-workspace-action-propagation/src/index.ts</path>
<type>file</type>
<content>
1: #!/usr/bin/env node
2: // Import Sentry instrumentation first, before any other code
3: import './instrument';
4:
5: import isCI from 'is-ci';
6: import yargs from 'yargs';
7:
8: import { logger, LogLevel } from './logger';
9: import {
10: sanitizeDynamicLinkerEnv,
11: warnIfCraftEnvFileExists,
12: } from './utils/env';
13: import {
14: envToBool,
15: setGlobals,
16: extractWorkspaceSelection,
17: } from './utils/helpers';
18: import { getPackageVersion } from './utils/version';
19: import { withTracing } from './utils/tracing';
20: import { setActiveWorkspace } from './config';
21:
22: // Commands
23: import * as prepare from './commands/prepare';
24: import * as publish from './commands/publish';
25: import * as targets from './commands/targets';
26: import * as config from './commands/config';
27: import * as artifacts from './commands/artifacts';
28: ...
<path>/home/byk/Code/getsentry/craft-workspace-action-propagation/src/utils/helpers.ts</path>
<type>file</type>
<content>
1: import { appendFileSync, mkdirSync, writeFileSync } from 'fs';
2: import path from 'path';
3: import { parseArgs } from 'node:util';
4:
5: import prompts from 'prompts';
6: import { logger, LogLevel, setLevel } from '../logger';
7:
8: /**
9: * Maximum size (in bytes) for step output values passed through GITHUB_OUTPUT.
10: * Values exceeding this are truncated to avoid E2BIG errors when GitHub Actions
11: * expands them into environment variables for subsequent steps.
12: *
13: * 64 KB is well under the ~2 MB ARG_MAX kernel limit and also under GitHub's
14: * ~65 536-character issue body limit, so truncated changelogs still render. ...
<path>/home/byk/Code/getsentry/publish-workspace-acceptance/src/modules/__tests__/details-from-context.js</path>
<type>file</type>
<content>
1: import { test, expect } from "vitest";
2:
3: const { detailsFromContext } = require("../details-from-context.js");
4:
5: const inputsArgs = {
6: context: {
7: repo: { owner: "getsentry", repo: "publish" },
8: payload: {
9: issue: {
10: number: "223",
11: title: "publish: getsentry/sentry@21.3.1",
12: body: `
13: Requested by: @BYK
14:
15: Merge target: custom-branch
16:
17: Quick links:
18: - [View changes](https://github.com/getsentry/sentry/compare/21.3.0...refs/heads/releases/21.3.1)
19: - [View check runs](https://github.com/getsentry/sentry/commit/7e5ca7ed5581552de066e2a8bc295b8306be38ac/checks/)
20:
21: Assign the **accepted** label to this issue to approve the release. ...
<path>/home/byk/Code/getsentry/publish-workspace-acceptance/src/modules/__tests__/publish-workflow.js</path>
<type>file</type>
<content>
1: import { spawnSync } from "child_process";
2: import { mkdtempSync, readFileSync, rmSync, writeFileSync } from "fs";
3: import { tmpdir } from "os";
4: import { join } from "path";
5:
6: import { afterEach, expect, test } from "vitest";
7:
8: const temporaryDirectories = [];
9:
10: function getSetTargetsScript() {
11: const workflow = readFileSync(
12: join(__dirname, "../../../.github/workflows/publish.yml"),
13: "utf8"
14: );
15: const section = workflow.match(
16: / {6}- name: Set targets[\s\S]*? {8}run: \|\n(?<script>[\s\S]*?)\n {6}- uses: docker:\/\/getsentry\/craft:latest/
17: );
18: if (!section?.groups?.script) {
19: throw new Error("Missing Set targets workflow script");
20: }
21: return section.groups.script.replace(/^ {10}/gm, "");
22: }
23:
24: function runSetTargets({ path, repo, version, workspace = ...
<path>/home/byk/Code/getsentry/craft-workspace-action-propagation/src/utils/publishState.ts</path> <type>file</type> <content> 1: /** 2: * Helpers for locating Craft's publish-state file in a path that is NOT 3: * writable by the repository being published. 4: * 5: * Background: `craft publish` writes a small JSON file listing targets 6: * that have completed so a resumed run can skip them. Before this module 7: * existed, the file lived at `.craft-publish-<version>.json` in the 8: * project's cwd. That path is inside the repository checkout, so any 9: * committed file at the same path (or any earlier CI step) could 10: * pre-populate the "published" set and trick Craft into silently 11: * skipping targets. 12: * 13: * The file now lives under `$XDG_STATE_HOME/craft/` (falling back to 14: * `$HOME/.local/state/craft/`). The filename is keyed on 15: * owner, repo, a hash of cwd (to disambiguate monorepo subpaths), and 16: * the version being published. ...
<path>/home/byk/Code/getsentry/publish-workspace-acceptance/.github/workflows/ci-poller.yml</path> <type>file</type> <content> 1: name: CI Status Poller 2: 3: on: 4: schedule: 5: - cron: "*/5 * * * *" 6: workflow_dispatch: 7: inputs: 8: attempt: 9: description: Self-dispatch attempt counter (internal use) 10: required: false 11: default: "0" 12: 13: permissions: 14: contents: read 15: issues: read 16: 17: jobs: 18: check-ci: 19: runs-on: ubuntu-latest 20: environment: production 21: # Skip entirely (no runner provisioned) when there's nothing to check. 22: # Set to "true" by ci-pending.yml, reset to "false" here when done. 23: # Always allow workflow_dispatch for manual recovery. 24: if: vars.CI_POLLER_HAS_PENDING == 'true' || github.event_name == 'workflow_dispatch' 25: concurrency: 26: group: ci-status-poller 27: cancel-in-progress: false 28: steps: 29: # sentry-internal-app token ...
Found 20 matches /home/byk/Code/getsentry/craft-workspace-action-propagation/.github/workflows/docs-preview.yml: Line 45: # Try to fetch the gh-pages branch Line 51: echo "Adding .nojekyll to existing gh-pages branch" Line 60: # Branch doesn't exist, create it as an orphan branch Line 61: echo "Creating gh-pages branch with .nojekyll" Line 75: preview-branch: gh-pages /home/byk/Code/getsentry/craft-workspace-action-propagation/.github/workflows/build.yml: Line 4: branches: /home/byk/Code/getsentry/craft-workspace-action-propagation/.github/workflows/enforce-license-compliance.yml: Line 5: branches: [master] Line 7: branches: [master] /home/byk/Code/getsentry/craft-workspace-action-propagation/.github/workflows/image.yml: Line 6: branches: [master, release/**, test-me-*] /home/byk/Code/getsentry/craft-workspace-action-propagation/.github/workflows/lint.yml: Line 4: branches: ...
<path>/home/byk/Code/getsentry/publish-workspace-acceptance/docs/publish-issue-format.md</path> <type>file</type> <content> 1: # Publish Issue Format 2: 3: The Publish workflow treats a publish issue as a release request. The title identifies 4: the release; the body supplies the merge target and selected targets. Do not edit the 5: title by hand unless it remains valid under this format. 6: 7: ## Title 8: 9: Every title starts with `publish: `. 10: 11: Legacy releases without a workspace use this form: 12: 13: ```text 14: publish: getsentry/<repository><optional-path>@<version> 15: ``` 16: 17: Workspace releases use this form: 18: 19: ```text 20: publish: getsentry/<repository><optional-path> [workspace: <json-string>] @<version> 21: ``` 22: 23: Examples: 24: 25: ```text 26: publish: getsentry/sentry@21.3.1 27: publish: getsentry/toolkit/cli@1.2.3 28: publish: getsentry/toolkit/cli [workspace: "cli/v2"] @1.2.3 29: publish: getsentry/toolkit [workspace: "cli [preview] ...
List issues in a GitHub repository. By default, this only lists open issues. The search query syntax is documented here: <https://docs.github.com/en/search-github/searching-on-github/searching-issues-and-pull-requests> On supported GitHub hosts, advanced issue search syntax can be used in the `--search` query. For more information about advanced issue search, see: <https://docs.github.com/en/issues/tracking-your-work-with-issues/using-issues/filtering-and-searching-issues-and-pull-requests#building-advanced-filters-for-issues> For more information about output formatting flags, see `gh help formatting`. ...
Found 24 matches
/home/byk/Code/getsentry/craft-workspace-action-propagation/src/targets/pypi.ts:
Line 65: const pyprojectPath = join(rootDir, 'pyproject.toml');
Line 66: if (!existsSync(pyprojectPath)) {
Line 70: const content = readFileSync(pyprojectPath, 'utf-8');
Line 87: return PypiTarget.bumpDirectToml(pyprojectPath, content, newVersion);
Line 139: pyprojectPath: string,
Line 161: logger.debug(`Updating version in ${pyprojectPath} to ${newVersion}`);
Line 162: writeFileSync(pyprojectPath, newContent);
/home/byk/Code/getsentry/craft-workspace-action-propagation/src/schemas/project_config.ts:
Line 46: projectPath: z.string().optional(),
Line 205: * just `projectPath` (or `owner`/`repo`) while inheriting the rest from the
/home/byk/Code/getsentry/craft-workspace-action-propagation/src/config.ts:
Line 106: * - `github` is shallow-merged (owner/repo/projectPath) so a workspace can
Line 107: * override just ...
Found 1 matches /home/byk/Code/getsentry/craft-workspace-action-propagation/CHANGELOG.md: Line 1574: - feat: Add projectPath config option to GitHub (#220)
Found 24 matches /home/byk/Code/getsentry/craft-workspace-action-propagation/src/schemas/project_config.ts: Line 46: projectPath: z.string().optional(), Line 205: * just `projectPath` (or `owner`/`repo`) while inheriting the rest from the /home/byk/Code/getsentry/craft-workspace-action-propagation/src/config.ts: Line 106: * - `github` is shallow-merged (owner/repo/projectPath) so a workspace can Line 107: * override just `projectPath` while inheriting owner/repo. Line 139: // (e.g. just projectPath) while inheriting owner/repo from the base. Line 148: // sets projectPath without a base github relies on git detection for /home/byk/Code/getsentry/craft-workspace-action-propagation/src/commands/__tests__/publish.test.ts: Line 172: projectPath: 'packages/cli', /home/byk/Code/getsentry/craft-workspace-action-propagation/src/targets/pypi.ts: Line 65: const pyprojectPath = join(rootDir, 'pyproject.toml'); Line 66: if ...
Found 97 matches
/home/byk/Code/getsentry/craft-workspace-action-propagation/src/utils/helpers.ts:
Line 198: * GitHub (e.g. the CHANGELOG.md file on the release branch) so readers of the
/home/byk/Code/getsentry/craft-workspace-action-propagation/src/utils/git.ts:
Line 120: const branchName = branch || '';
Line 122: if (branchName.startsWith(remotePrefix)) {
Line 123: return branchName.slice(remotePrefix.length);
Line 125: return branchName;
Line 228: * @param prefix The release branch prefix to search for
Line 261: // A release branch is "<prefix>/<version>". Treat the prefix as an opaque
/home/byk/Code/getsentry/craft-workspace-action-propagation/src/utils/detection.ts:
Line 42: * but need it in release branches for the action to work. Merging the release
/home/byk/Code/getsentry/craft-workspace-action-propagation/src/schemas/project_config.ts:
Line 185: releaseBranchPrefix: z.string().optional(),
Line 193: * Do not merge the ...
<path>/home/byk/Code/getsentry/craft-workspace-action-propagation/src/commands/publish.ts</path>
<type>file</type>
<content>
590: logger.info(`Running the post-release command...`);
591: await spawnProcess(sysCommand as string, args as string[], {
592: env: buildReleaseCommandEnv({ CRAFT_RELEASED_VERSION: newVersion }),
593: });
594: return true;
595: }
596:
597: /**
598: * Body of 'publish' command
599: *
600: * @param argv Command-line arguments
601: */
602: export async function publishMain(argv: PublishOptions): Promise<any> {
603: // Get publishing configuration
604: const config = getConfiguration() || {};
605:
606: const newVersion = argv.newVersion;
607:
608: logger.info(`Publishing version: "${newVersion}"`);
609:
610: const git = await getGitClient();
611:
612: // Check for dirty repository state before any git operations
613: if (argv.noGitChecks) {
614: logger.info('Not checking the status of the local repository');
615: } else ...
<path>/home/byk/Code/getsentry/publish-workspace-acceptance/package.json</path>
<type>file</type>
<content>
1: {
2: "name": "publish",
3: "private": true,
4: "version": "0.0.1",
5: "description": "Approval-based publishing system for Sentry",
6: "main": "index.js",
7: "repository": "git@github.com:getsentry/publish.git",
8: "author": "Sentry Open Source <oss@sentry.io>",
9: "license": "Apache-2.0",
10: "volta": {
11: "node": "24.0.0",
12: "yarn": "1.22.22"
13: },
14: "resolutions": {
15: "undici": "^6.23.0"
16: },
17: "scripts": {
18: "test": "vitest run",
19: "test:watch": "vitest",
20: "lint": "eslint src .github --ignore-pattern '!.github'",
21: "prettier": "prettier --write src"
22: },
23: "devDependencies": {
24: "eslint": "^8.9.0",
25: "eslint-config-prettier": "^8.3.0",
26: "eslint-plugin-yml": "^0.13.0",
27: "prettier": "^2.2.1",
28: "vitest": "^4.1.0"
29: },
30: "dependencies": {
31: ...
No files found
Found 57 matches
/home/byk/Code/getsentry/publish-workspace-acceptance/src/publish/update-issue.js:
Line 7: const inputs = JSON.parse(process.env.PUBLISH_ARGS);
/home/byk/Code/getsentry/publish-workspace-acceptance/src/publish/post-result.js:
Line 7: const inputs = JSON.parse(process.env.PUBLISH_ARGS);
/home/byk/Code/getsentry/publish-workspace-acceptance/src/publish/inputs.js:
Line 3: const { detailsFromContext } = require('../modules/details-from-context');
Line 6: const result = await detailsFromContext({
/home/byk/Code/getsentry/publish-workspace-acceptance/src/modules/details-from-context.js:
Line 19: async function detailsFromContext({ context }) {
Line 25: /^publish: (?:getsentry\/)?(?<repo>[A-Za-z0-9_.-]+)(?<path>\/[\w./-]+)?(?: \[workspace: (?<workspace>"(?:[^"\\]|\\.)*")\] )?@(?<version>[\w.+-]+)$/;
Line 32: const { workspace: workspaceJson, ...titleDetails } = titleMatch.groups;
Line 33: let workspace = "";
Line 34: if ...
<path>/home/byk/Code/getsentry/publish-workspace-acceptance/.github/workflows/publish.yml</path>
<type>file</type>
<content>
1: name: Publish
2: on:
3: issues:
4: types: [labeled]
5:
6: concurrency:
7: # Use the issue title (e.g. "publish: getsentry/foo@1.2.3") so duplicate
8: # issues for the same repo@version share a concurrency group.
9: group: ${{ github.event.issue.title }}
10: cancel-in-progress: false
11:
12: permissions:
13: contents: read
14: issues: write
15: packages: write
16:
17: jobs:
18: # When accepted is added to a publish issue:
19: # - Add ci-pending (and remove ci-failed if retrying)
20: # - Enable the poller via CI_POLLER_HAS_PENDING=true
21: # - Comment on the issue
22: # - Trigger the poller immediately so we don't wait for the next cron tick
23: # The publish job below requires ci-ready, so it will not fire until the
24: # poller flips ci-pending → ci-ready (which also prevents publishing without
25: # CI ...
<path>/home/byk/Code/getsentry/publish-workspace-acceptance/.github/workflows/publish.yml</path>
<type>file</type>
<content>
281: NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
282: GEM_HOST_API_KEY: ${{ secrets.GEM_HOST_API_KEY }}
283: AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
284: AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
285: NUGET_API_TOKEN: ${{ secrets.NUGET_API_TOKEN }}
286: POWERSHELL_API_KEY: ${{ secrets.POWERSHELL_API_KEY }}
287: GPG_PRIVATE_KEY: ${{ secrets.GPG_PRIVATE_KEY }}
288: GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }}
289: OSSRH_USERNAME: ${{ secrets.OSSRH_USERNAME }}
290: OSSRH_PASSWORD: ${{ secrets.OSSRH_PASSWORD }}
291: PUBDEV_ACCESS_TOKEN: ${{ secrets.PUBDEV_ACCESS_TOKEN }}
292: PUBDEV_REFRESH_TOKEN: ${{ secrets.PUBDEV_REFRESH_TOKEN }}
293: VERCEL_ORG_ID: ${{ vars.VERCEL_ORG_ID }}
294: VERCEL_TOKEN: ${{ ...
<path>/home/byk/Code/getsentry/craft-workspace-action-propagation/action.yml</path>
<type>file</type>
<content>
1: name: 'Craft Prepare Release'
2: description: 'Prepare a new release using Craft'
3:
4: inputs:
5: version:
6: description: >
7: Version to release. Can be a semver string (e.g., "1.2.3"),
8: a bump type ("major", "minor", "patch"), or "auto" for automatic detection.
9: required: false
10: merge_target:
11: description: Target branch to merge into. Uses the default branch as a fallback. ...
<path>/home/byk/Code/getsentry/craft-workspace-action-propagation/action.yml</path>
<type>file</type>
<content>
331: body="Requested by: @${GITHUB_ACTOR}
332:
333: Merge target: ${MERGE_TARGET}
334:
335: Quick links:
336: - [View changes](https://github.com/${GITHUB_REPOSITORY}/compare/${RELEASE_PREVIOUS_TAG}...${RELEASE_BRANCH})
337: - [View check runs](https://github.com/${GITHUB_REPOSITORY}/commit/${RELEASE_SHA}/checks/)
338:
339: Assign the **accepted** label to this issue to approve the release.
340:
341: ### Targets
342:
343: ${TARGETS}
344:
345: Checked targets will be skipped (either already published or user-requested skip). Uncheck to retry a target. ...
<path>/home/byk/Code/getsentry/craft-workspace-action-propagation/src/config.ts</path>
<type>file</type>
<content>
75:
76: /**
77: * Selects the active workspace for subsequent configuration reads.
78: *
79: * Passing `undefined` (or omitting) clears the selection (default behavior).
80: * Must be called before the configuration is first resolved/cached; it clears
81: * the caches so a later read re-resolves against the new selection.
82: */
83: export function setActiveWorkspace(name: string | undefined): void {
84: _activeWorkspaceName = name;
85: // Invalidate resolved caches so the next read applies the new selection.
86: _configCache = undefined as unknown as CraftProjectConfig;
87: _globalGitHubConfigCache = undefined;
88: }
89:
90: /**
91: * Returns the name of the currently-selected workspace, if any. ...
<path>/home/byk/Code/getsentry/craft-workspace-action-propagation/src/schemas/project_config.ts</path>
<type>file</type>
<content>
1: import { z } from 'zod';
2:
3: /**
4: * DEPRECATED: Use changelog.policy instead. Different policies for changelog management
5: */
6: export const enum ChangelogPolicy {
7: Auto = 'auto',
8: Simple = 'simple',
9: None = 'none',
10: }
11:
12: /**
13: * Name of the status provider
14: */
15: export const enum StatusProviderName {
16: GitHub = 'github',
17: }
18:
19: /**
20: * Name of the artifact provider
21: */
22: export const enum ArtifactProviderName {
23: GCS = 'gcs',
24: GitHub = 'github',
25: None = 'none',
26: }
27:
28: /**
29: * Default versioning policy when no version argument is provided. ...
<path>/home/byk/Code/getsentry/publish-workspace-acceptance/src/modules/details-from-context.js</path>
<type>file</type>
<content>
1: /**
2: * Matches the entire "Targets" section of a github publish issue body.
3: */
4: const TARGETS_SECTION_PARSER_REGEX =
5: /^(?!### Targets$\s)(?: *- \[[ xX]\] \S+\s*$(?:\r?\n)?)+/m;
6:
7: /**
8: * Matches all targets of a github publish issue body in a section that was already matched and extracted with `TARGETS_PARSER_REGEX`.
9: * The "id" of the targets is captured within a capture group.
10: */
11: const TARGETS_PARSER_REGEX = /^\s*- \[[ x]\] (\S+)/gim;
12:
13: /**
14: * Matches checked targets of a github publish issue body in a section that was already matched and extracted with `TARGETS_PARSER_REGEX`.
15: * The "id" of the targets is captured within a capture group.
16: */
17: const CHECKED_TARGETS_PARSER_REGEX = /^\s*- \[x\] (\S+)/gim;
18:
19: async function detailsFromContext({ context }) {
20: if (!context || ...
Found 15 matches
/home/byk/Code/getsentry/craft-workspace-action-propagation/.github/workflows/release.yml:
Line 86: if: github.repository == 'getsentry/craft'
Line 110: if: github.event_name == 'workflow_dispatch' && github.repository == 'getsentry/craft'
Line 124: if: github.repository == 'getsentry/craft'
Line 136: if: github.repository != 'getsentry/craft'
Line 138: uses: getsentry/craft@v2
/home/byk/Code/getsentry/craft-workspace-action-propagation/.github/workflows/image.yml:
Line 20: img=ghcr.io/getsentry/craft-builder:latest
Line 35: img=ghcr.io/getsentry/craft:latest
Line 56: craft_builder=ghcr.io/getsentry/craft-builder:latest
Line 57: craft_latest=ghcr.io/getsentry/craft:latest
Line 58: craft_versioned="ghcr.io/getsentry/craft:${GITHUB_SHA}"
/home/byk/Code/getsentry/craft-workspace-action-propagation/.github/workflows/changelog-preview.yml:
Line 33: # ...
<path>/home/byk/Code/getsentry/craft-workspace-action-propagation/.github/workflows/release.yml</path>
<type>file</type>
<content>
1: name: Release
2: concurrency: ${{ github.workflow }}-${{ github.ref }}
3:
4: on:
5: # For Craft's own releases (dogfooding)
6: workflow_dispatch:
7: inputs:
8: version:
9: description: Version to release
10: required: true
11: default: 'auto'
12: force:
13: description: Force a release even when there are release-blockers (optional)
14: required: false
15: workspace:
16: description: Named Craft release workspace to prepare and publish
17: required: false
18:
19: # For external repos to call this workflow
20: workflow_call:
21: inputs:
22: version:
23: description: Version to release (semver, bump type, or "auto")
24: type: string
25: required: false
26: force:
27: description: Force a release even when there are ...
Found 58 matches
/home/byk/Code/getsentry/craft-workspace-action-propagation/src/utils/changelog.ts:
Line 11: getGlobalGitHubConfig,
Line 39: const { repo, owner } = await getGlobalGitHubConfig();
Line 1846: const { repo, owner } = await getGlobalGitHubConfig();
Line 2078: const { repo, owner } = await getGlobalGitHubConfig();
/home/byk/Code/getsentry/craft-workspace-action-propagation/src/utils/__tests__/fixtures/changelog-mocks.ts:
Line 15: export let getGlobalGitHubConfigMock: MockedFunction<any>;
Line 37: getGlobalGitHubConfigMock = config.getGlobalGitHubConfig as MockedFunction<
Line 38: typeof config.getGlobalGitHubConfig
Line 50: getGlobalGitHubConfigMock.mockResolvedValue({
/home/byk/Code/getsentry/craft-workspace-action-propagation/src/utils/__tests__/changelog-semver-warning.test.ts:
Line 9: getGlobalGitHubConfig: ...
<path>/home/byk/Code/getsentry/craft-workspace-action-propagation/src/config.ts</path>
<type>file</type>
<content>
430: export function requiresMinVersion(requiredVersion: string): boolean {
431: const config = getConfiguration();
432: return isVersionGteMinVersion(config.minVersion, requiredVersion);
433: }
434:
435: /** Minimum craft version required for auto-versioning and CalVer */
436: const AUTO_VERSION_MIN_VERSION = '2.14.0';
437:
438: /**
439: * Returns the effective versioning policy for the project.
440: *
441: * The policy determines how versions are resolved when no explicit version
442: * is provided to `craft prepare`:
443: * - 'auto': Analyze commits to determine the bump type
444: * - 'manual': Require an explicit version argument
445: * - 'calver': Use calendar versioning
446: *
447: * If not explicitly configured, defaults to:
448: * - 'auto' if minVersion >= 2.14.0
449: * - 'manual' otherwise (for backward compatibility)
450: *
451: * @returns The ...
<path>/home/byk/Code/getsentry/craft-workspace-action-propagation/src/commands/prepare.ts</path>
<type>file</type>
<content>
790: *
791: * @param argv Command-line arguments
792: */
793: export async function prepareMain(argv: PrepareOptions): Promise<any> {
794: let git = await getGitClient();
795:
796: // Handle --config-from: load config from remote branch. The caller
797: // is responsible for ensuring the branch is trusted — the remote
798: // config's preReleaseCommand will be executed by Craft.
799: if (argv.configFrom) {
800: logger.warn(
801: `Loading .craft.yml from remote branch "${argv.configFrom}". ` +
802: `Its preReleaseCommand will be executed by Craft — ensure the ` +
803: `branch is trusted.`,
804: );
805: try {
806: await git.fetch([argv.remote, argv.configFrom]);
807: const configContent = await git.show([
808: `${argv.remote}/${argv.configFrom}:${CONFIG_FILE_NAME}`,
809: ]);
810: ...
Found 2 matches
/home/byk/Code/getsentry/craft-workspace-action-propagation/src/__tests__/action.test.ts:
Line 109: '${{ inputs.workspace }}',
Line 112: '${{ inputs.workspace }}',
<path>/home/byk/Code/getsentry/craft-workspace-action-propagation/src/__tests__/action.test.ts</path>
<type>file</type>
<content>
1: import {
2: chmodSync,
3: mkdtempSync,
4: mkdirSync,
5: readFileSync,
6: rmSync,
7: writeFileSync,
8: } from 'fs';
9: import { tmpdir } from 'os';
10: import { join } from 'path';
11: import { spawnSync } from 'child_process';
12:
13: import { load } from 'js-yaml';
14: import { afterEach, expect, test } from 'vitest';
15:
16: interface ActionStep {
17: env?: Record<string, string>;
18: name?: string;
19: run?: string;
20: }
21:
22: function getActionSteps(): ActionStep[] {
23: const action = load(
24: readFileSync(join(__dirname, '../../action.yml'), 'utf8'),
25: ) as {
26: runs?: { steps?: ActionStep[] };
27: };
28: return action.runs?.steps || [];
29: }
30:
31: function getActionStep(name: string): ActionStep {
32: const step = getActionSteps().find(step => step.name === name);
33: if (!step?.run) {
34: ...
<path>/home/byk/Code/getsentry/publish-workspace-acceptance/src/modules/__tests__/details-from-context.js</path>
<type>file</type>
<content>
1: import { test, expect } from "vitest";
2:
3: const { detailsFromContext } = require("../details-from-context.js");
4:
5: const inputsArgs = {
6: context: {
7: repo: { owner: "getsentry", repo: "publish" },
8: payload: {
9: issue: {
10: number: "223",
11: title: "publish: getsentry/sentry@21.3.1",
12: body: `
13: Requested by: @BYK
14:
15: Merge target: custom-branch
16:
17: Quick links:
18: - [View changes](https://github.com/getsentry/sentry/compare/21.3.0...refs/heads/releases/21.3.1)
19: - [View check runs](https://github.com/getsentry/sentry/commit/7e5ca7ed5581552de066e2a8bc295b8306be38ac/checks/)
20:
21: Assign the **accepted** label to this issue to approve the release. ...
No files found
Found 4 matches
/home/byk/Code/getsentry/craft-workspace-action-propagation/docs/src/content/docs/targets/gcs.md:
Line 33: - path: release/{{version}}/download
Line 36: - path: release/{{revision}}/platform/package
/home/byk/Code/getsentry/craft-workspace-action-propagation/docs/src/content/docs/getting-started.md:
Line 271: path: |
/home/byk/Code/getsentry/craft-workspace-action-propagation/docs/src/content/docs/targets/brew.md:
Line 44: path: HomebrewFormula
Found 2 matches /home/byk/Code/getsentry/craft-workspace-action-propagation/README.md: Line 44: - **Workspace Support** - Handle monorepos with NPM/Yarn workspaces Line 69: | `npm` | NPM registry (with workspace support) |
<path>/home/byk/Code/getsentry/craft-workspace-action-propagation/src/utils/publishState.ts</path> <type>file</type> <content> 1: /** 2: * Helpers for locating Craft's publish-state file in a path that is NOT 3: * writable by the repository being published. 4: * 5: * Background: `craft publish` writes a small JSON file listing targets 6: * that have completed so a resumed run can skip them. Before this module 7: * existed, the file lived at `.craft-publish-<version>.json` in the 8: * project's cwd. That path is inside the repository checkout, so any 9: * committed file at the same path (or any earlier CI step) could 10: * pre-populate the "published" set and trick Craft into silently 11: * skipping targets. 12: * 13: * The file now lives under `$XDG_STATE_HOME/craft/` (falling back to 14: * `$HOME/.local/state/craft/`). The filename is keyed on 15: * owner, repo, a hash of cwd (to disambiguate monorepo subpaths), and 16: * the version being published. ...
<path>/home/byk/Code/getsentry/craft-workspace-action-propagation/src/commands/__tests__/publish.test.ts</path>
<type>file</type>
<content>
1: import { vi, describe, test, expect, beforeEach, type Mock } from 'vitest';
2: import { join as pathJoin } from 'path';
3: import { spawnProcess, hasExecutable } from '../../utils/system';
4: import {
5: getPublishStateGitHubConfig,
6: runPostReleaseCommand,
7: handleReleaseBranch,
8: MergeConflictError,
9: PushError,
10: } from '../publish';
11: import { getPublishStateFilename } from '../../utils/publishState';
12: import type { SimpleGit } from 'simple-git';
13:
14: vi.mock('../../utils/system');
15: vi.mock('../../utils/git', () => ({
16: getDefaultBranch: vi.fn().mockResolvedValue('main'),
17: getGitClient: vi.fn(),
18: isRepoDirty: vi.fn(),
19: findReleaseBranches: vi.fn(),
20: }));
21:
22: describe('runPostReleaseCommand', () => {
23: const newVersion = '2.3.4';
24: const mockedSpawnProcess = spawnProcess as ...
<path>/home/byk/Code/getsentry/craft-workspace-action-propagation/src/commands/publish.ts</path>
<type>file</type>
<content>
270: (ar.mimeType && ar.mimeType.split(';')[0]) || '',
271: ]);
272: // sort alphabetically by filename
273: artifactData.sort((a1, a2) => (a1[0] < a2[0] ? -1 : a1[0] > a2[0] ? 1 : 0));
274: const table = formatTable(
275: {
276: head: ['File Name', 'Size', 'Updated', 'ContentType'],
277: style: { head: ['cyan'] },
278: },
279: artifactData,
280: );
281: logger.info(' ');
282: logger.info(`Available artifacts: \n${table.toString()}\n`);
283: } else {
284: const config = getConfiguration();
285: const artifactsConfig = config?.artifactProvider?.config?.artifacts;
286: if (artifactsConfig) {
287: const configSnippet = formatArtifactConfigForError(artifactsConfig);
288: reportError(
289: `No artifacts found for the revision, but your .craft.yml defines artifact ...
<path>/home/byk/Code/getsentry/craft-workspace-action-propagation/src/utils/helpers.ts</path>
<type>file</type>
<content>
1: import { appendFileSync, mkdirSync, writeFileSync } from 'fs';
2: import path from 'path';
3: import { parseArgs } from 'node:util';
4:
5: import prompts from 'prompts';
6: import { logger, LogLevel, setLevel } from '../logger';
7:
8: /**
9: * Maximum size (in bytes) for step output values passed through GITHUB_OUTPUT.
10: * Values exceeding this are truncated to avoid E2BIG errors when GitHub Actions
11: * expands them into environment variables for subsequent steps.
12: *
13: * 64 KB is well under the ~2 MB ARG_MAX kernel limit and also under GitHub's
14: * ~65 536-character issue body limit, so truncated changelogs still render. ...
<path>/home/byk/Code/getsentry/craft-workspace-action-propagation/src/index.ts</path>
<type>file</type>
<content>
1: #!/usr/bin/env node
2: // Import Sentry instrumentation first, before any other code
3: import './instrument';
4:
5: import isCI from 'is-ci';
6: import yargs from 'yargs';
7:
8: import { logger, LogLevel } from './logger';
9: import {
10: sanitizeDynamicLinkerEnv,
11: warnIfCraftEnvFileExists,
12: } from './utils/env';
13: import {
14: envToBool,
15: setGlobals,
16: extractWorkspaceSelection,
17: } from './utils/helpers';
18: import { getPackageVersion } from './utils/version';
19: import { withTracing } from './utils/tracing';
20: import { setActiveWorkspace } from './config';
21:
22: // Commands
23: import * as prepare from './commands/prepare';
24: import * as publish from './commands/publish';
25: import * as targets from './commands/targets';
26: import * as config from './commands/config';
27: import * as artifacts from './commands/artifacts';
28: ...
(no output)
No files found
Found 24 matches
/home/byk/Code/getsentry/craft-workspace-action-propagation/src/config.ts:
Line 106: * - `github` is shallow-merged (owner/repo/projectPath) so a workspace can
Line 107: * override just `projectPath` while inheriting owner/repo.
Line 139: // (e.g. just projectPath) while inheriting owner/repo from the base.
Line 148: // sets projectPath without a base github relies on git detection for
/home/byk/Code/getsentry/craft-workspace-action-propagation/src/commands/__tests__/publish.test.ts:
Line 172: projectPath: 'packages/cli',
/home/byk/Code/getsentry/craft-workspace-action-propagation/src/targets/pypi.ts:
Line 65: const pyprojectPath = join(rootDir, 'pyproject.toml');
Line 66: if (!existsSync(pyprojectPath)) {
Line 70: const content = readFileSync(pyprojectPath, 'utf-8');
Line 87: return PypiTarget.bumpDirectToml(pyprojectPath, content, newVersion);
Line 139: pyprojectPath: string,
Line 161: ...
<path>/home/byk/Code/getsentry/craft-workspace-action-propagation/src/config.ts</path>
<type>file</type>
<content>
180: }
181: return versionGreaterOrEqualThan(
182: withoutBuildMetadata(configuredMinVersion),
183: withoutBuildMetadata(required),
184: );
185: }
186:
187: /**
188: * SemVer build metadata does not affect precedence, but the comparison helper
189: * intentionally rejects versions carrying it. Strip it before compatibility
190: * checks so config values such as `2.29.0+linux` remain valid.
191: */
192: function withoutBuildMetadata(version: SemVer): SemVer {
193: return version.build ? { ...version, build: undefined } : version;
194: }
195:
196: /**
197: * Applies workspace selection + validation to a freshly-parsed config.
198: *
199: * - No `workspaces` in config, no active selection → returns the config as-is.
200: * - `workspaces` present but no selection → error (must pick one explicitly). ...
<path>/home/byk/Code/getsentry/publish-workspace-acceptance/src/publish/update-issue.js</path>
<type>file</type>
<content>
1: const { updateIssue } = require('../modules/update-issue.js');
2: const {getGitHubToken} = require('../libs/github');
3: const github = require('@actions/github');
4:
5: const context = github.context;
6: const octokit = github.getOctokit(getGitHubToken());
7: const inputs = JSON.parse(process.env.PUBLISH_ARGS);
8:
9: updateIssue({ context, octokit, inputs });
(End of file - total 9 lines)
</content>
<path>/home/byk/Code/getsentry/publish-workspace-acceptance/.github</path> <type>directory</type> <entries> CODEOWNERS workflows/ (2 entries) </entries>
<path>/home/byk/Code/getsentry/publish-workspace-acceptance/.github/workflows</path> <type>directory</type> <entries> auto-approve.yml ci-poller.yml cocoapods-keepalive.yml publish.yml test.yml (5 entries) </entries>
<path>/home/byk/Code/getsentry/publish-workspace-acceptance/.github/workflows/ci-poller.yml</path> <type>file</type> <content> 1: name: CI Status Poller 2: 3: on: 4: schedule: 5: - cron: "*/5 * * * *" 6: workflow_dispatch: 7: inputs: 8: attempt: 9: description: Self-dispatch attempt counter (internal use) 10: required: false 11: default: "0" 12: 13: permissions: 14: contents: read 15: issues: read 16: 17: jobs: 18: check-ci: 19: runs-on: ubuntu-latest 20: environment: production 21: # Skip entirely (no runner provisioned) when there's nothing to check. 22: # Set to "true" by ci-pending.yml, reset to "false" here when done. 23: # Always allow workflow_dispatch for manual recovery. 24: if: vars.CI_POLLER_HAS_PENDING == 'true' || github.event_name == 'workflow_dispatch' 25: concurrency: 26: group: ci-status-poller 27: cancel-in-progress: false 28: steps: 29: # sentry-internal-app token ...
<path>/home/byk/Code/getsentry/publish-workspace-acceptance/.github/workflows/ci-poller.yml</path>
<type>file</type>
<content>
260: --label accepted \
261: --limit 1 \
262: --json number -q 'length')
263: echo "count=${count}" >> "$GITHUB_OUTPUT"
264:
265: # Update the poller variable to match reality:
266: # - Remaining issues → ensure variable is "true" (important when
267: # workflow_dispatch bypassed the gate while variable was "false")
268: # - No remaining issues → set to "false" to stop the cron
269: # Placed after CI check so a token failure can't block CI checking.
270: - name: Get poller app token
271: if: always()
272: id: poller-token
273: uses: actions/create-github-app-token@v3
274: with:
275: client-id: ${{ vars.CI_POLLER_APP_CLIENT_ID }}
276: private-key: ${{ secrets.CI_POLLER_APP_PRIVATE_KEY }}
277:
278: - name: Sync poller ...
(no output)
<path>/home/byk/Code/getsentry/craft-workspace-action-propagation/src/commands/publish.ts</path>
<type>file</type>
<content>
1: import { Arguments, Argv, CommandBuilder } from 'yargs';
2: import chalk from 'chalk';
3: import { existsSync, mkdirSync, readFileSync } from 'fs';
4:
5: import { safeFs } from '../utils/dryRun';
6: import { dirname, join } from 'path';
7: import * as shellQuote from 'shell-quote';
8: import stringLength from 'string-length';
9:
10: import {
11: getConfiguration,
12: getStatusProviderFromConfig,
13: getArtifactProviderFromConfig,
14: DEFAULT_RELEASE_BRANCH_NAME,
15: getGlobalGitHubConfig,
16: expandWorkspaceTargets,
17: getNoMergeConfig,
18: getActiveWorkspace,
19: } from '../config';
20: import { formatTable, logger } from '../logger';
21: import {
22: type GitHubGlobalConfig,
23: TargetConfig,
24: } from '../schemas/project_config';
25: import { getAllTargetNames, getTargetByName, SpecialTarget } from '../targets';
26: import { ...
<path>/home/byk/Code/getsentry/craft-workspace-action-propagation/src/commands/publish.ts</path>
<type>file</type>
<content>
170: }
171:
172: /**
173: * The Publish controller prepopulates a secure state file using the issue's
174: * checkout repository. That can differ from a workspace's release GitHub
175: * configuration, so this override is deliberately limited to state identity.
176: */
177: export function getPublishStateGitHubConfig(
178: githubConfig: GitHubGlobalConfig | null,
179: stateRepository: string | undefined = process.env
180: .CRAFT_PUBLISH_STATE_GITHUB_REPO,
181: ): GitHubGlobalConfig | null {
182: if (!stateRepository) {
183: return githubConfig;
184: }
185:
186: const match = stateRepository.match(
187: /^(?<owner>[A-Za-z0-9_.-]+)\/(?<repo>[A-Za-z0-9_.-]+)$/,
188: );
189: if (!match?.groups) {
190: throw new ConfigurationError(
191: 'CRAFT_PUBLISH_STATE_GITHUB_REPO must be a GitHub owner/repository pair.',
192: ...
CRITICAL — CI can approve a different ref from the one Publish executes.
The new issue-body branch field is mutable. The poller currently validates a SHA from the body, then independently derives a branch from check suites (publish/.github/workflows/ci-poller.yml:107-154). Checkout currently permits only the default branch or a protected allowlist (publish/.github/workflows/publish.yml:144-184).
Fix: bind branch, SHA, and CI status to one authenticated, immutable request record. At publish time, reject any branch/SHA mismatch and ensure CI passed for the exact checked-out branch head.
HIGH — Workspace classification happens too late for publish-state setup.
Inputs are parsed before the target checkout (publish.yml:134-136), while Set targets derives its state path and workspace from those inputs (publish.yml:186-234). Craft keys state by both cwd and active workspace (craft/src/commands/publish.ts:726-730, src/utils/publishState.ts:82-99). A suffix first parsed as a path, then classified as a root workspace, pre-seeds a different state file and can republish checked targets.
Fix: after checkout, resolve one validated { branch, path, workspace } object and use it for state setup, cd, CRAFT_WORKSPACE, and Craft invocation. Add exact filename parity tests for new workspace and legacy path requests.
HIGH — Compact titles collide with legacy path releases.
publish: getsentry/repo/cli@1.2.3 can mean either legacy path cli or workspace cli. Craft currently deduplicates by title alone (craft/action.yml:270-276) and reuses or overwrites the matching issue (action.yml:348-356); Publish also serializes by title (publish.yml:6-10). A new workspace request can therefore reuse a legacy issue with different semantics. The issue list also defaults to 30 results. ...
Date: Aug 27, 2026 * 🟡 (14:29) Assistant performed an adversarial design review of the publish/workspace-action-propagation changes and issued a **DO-NOT-MERGE** verdict. * 🟡 (14:29) Review finding 1 (CRITICAL): CI can approve a different ref than Publish executes because the mutable issue-body branch field is separate from the SHA validated by the poller and the branch derived from check suite…
Date: Aug 27, 2026 * 🟡 (14:24) `src/commands/publish.ts` imports workspace-aware configuration utilities `getConfiguration`, `getActiveWorkspace`, and `expandWorkspaceTargets`; release-command environment builder `buildReleaseCommandEnv` from `src/utils/releaseCommandEnv`; and publish-state path generator `getPublishStatePath` from `src/utils/publishState`. * 🟡 (14:24) `src/commands/publish.ts`…
Date: Aug 27, 2026 * 🟡 (14:09) `src/utils/publishState.ts` moves resumable `craft publish` completed-target JSON state out of the repository checkout—previously `.craft-publish-<version>.json` in cwd could be pre-populated by committed content or earlier CI steps to silently skip targets—to `$XDG_STATE_HOME/craft/`, falling back to `$HOME/.local/state/craft/`. In `getsentry/publish` Docker, `HOM…
Date: Aug 27, 2026 * 🟡 (14:07) `publish-workspace-acceptance/src/modules/details-from-context.js` parses GitHub publish-issue titles with `titleParser`: `^publish: (?:getsentry\/)?(?<repo>[A-Za-z0-9_.-]+)(?<path>\/[\w./-]+)?(?: \[workspace: (?<workspace>"(?:[^"\\]|\\.)*")\] )?@(?<version>[\w.+-]+)$`. It accepts an optional JSON-quoted `[workspace: "..."]` segment immediately before `@version`, s…
Date: Aug 27, 2026 * 🟡 (14:03) Search returned `57` workspace-related matches in `publish-workspace-acceptance`, including `src/modules/details-from-context.js`, `src/modules/__tests__/details-from-context.js`, `src/modules/__tests__/publish-workflow.js`, `src/publish/inputs.js`, `src/publish/update-issue.js`, and `src/publish/post-result.js`. * 🔴 (14:03) User stated that the CI poller always a…
Date: Aug 27, 2026 * 🔴 (13:46) User stated that new Craft-created publish requests always include the checkout repository identity. * 🟡 (13:46) `docs/publish-issue-format.md` defines publish issues as release requests: title identifies the release, body supplies merge target and selected targets; titles must start `publish: ` and should not be manually edited unless still valid. * 🟡 (13:46) Pu…
Date: Aug 27, 2026 * 🔴 (13:41) User stated that `workflow_dispatch` must always be allowed for manual recovery. * 🟡 (13:41) `.github/workflows/ci-status-poller.yml` is scheduled with cron `*/5 * * * *`, uses concurrency group `ci-status-poller`, and documents that `workflow_dispatch` remains enabled for manual recovery. * 🟡 (13:41) The CI-status poller checks only issues carrying both `ci-pend…
Date: Aug 27, 2026 * 🔴 (13:33) User stated that an option following `--workspace` (for example, `--workspace --dry-run`) must never be mistaken for a workspace name. * 🟡 (13:33) `src/index.ts` resolves the active workspace before yargs parsing via `setActiveWorkspace(extractWorkspaceSelection(argv))`, because yargs command builders run before middleware and `publish` derives `--target` choices …
Date: Aug 27, 2026 * 🟡 (13:33) Commit `33de3f1df5bdb9a6a480e9217d566df7b5a48b8e`, `feat: accept workspace publish requests`, was authored and committed by Burak Yigit Kaya `<byk@sentry.io>` on Aug 26, 2026 at 14:15:22 UTC. It changed `.github/workflows/publish.yml`, `src/modules/__tests__/details-from-context.js`, `src/modules/__tests__/publish-workflow.js`, `src/modules/__tests__/update-issue.j…
Date: Aug 27, 2026 * 🔴 (13:32) User stated the CI poller always adds the `ci-ready` label. * 🟡 (13:32) `publish-workspace-acceptance/src/publish/inputs.js` imports `@actions/github`, `@actions/core`, and `detailsFromContext` from `../modules/details-from-context`; `inputs()` calls `detailsFromContext({ context: github.context })` and writes its result to the `result` action output via `core.set…
Date: Aug 27, 2026 * 🔴 (13:32) User directive for the Craft repository: always use `pnpm` for package management; never use `npm` or `yarn`. * 🟡 (13:32) Craft repository package-management/configuration documentation states Node.js is Volta-managed at v22.12.0 and dependencies must be installed with `pnpm install --frozen-lockfile`. * 🟡 (13:32) Craft repository TypeScript layout: `src/__mocks_…
Date: Aug 27, 2026 * 🟡 (13:31) `publish-workspace-acceptance/AGENTS.md` identifies this repository as the Sentry Publish Repository: a GitHub Actions-based approval system for publishing releases across multiple Sentry projects using Craft; it is a pure JavaScript CommonJS project pinned via Volta to Node.js 24.0.0. * 🟡 (13:31) Sentry Publish Repository package-management directive: use Yarn cl…
Date: Aug 27, 2026 * 🟡 (13:30) Tool listed `/home/byk/Code/getsentry/publish-workspace-acceptance` as a directory with 14 entries: `.eslintrc.js`, `.git`, `.github/`, `.gitignore`, `AGENTS.md`, `auto-approve-repos.txt`, `docs/`, `LICENSE`, `node_modules/`, `package.json`, `README.md`, `src/`, `vitest.config.js`, `yarn.lock`. * 🔴 (13:30) User directive for the Craft codebase: always use `pnpm` f…
Date: Aug 27, 2026 * 🟡 (13:30) Tool listed `/home/byk/Code/getsentry/craft-workspace-action-propagation` as a directory with 33 entries: `.craft.yml`, `.dockerignore`, `.eslintcache`, `.git`, `.github/`, `.gitignore`, `.lore.md`, `.nojekyll`, `.npmignore`, `.prettierignore`, `.prettierrc.yml`, `.tsbuildinfo`, `.vscode/`, `action.yml`, `AGENTS.md`, `blog-post-draft.md`, `build.mjs`, `CHANGELOG.md…
Date: Aug 27, 2026 * 🔴 [requested-review] (13:30) User requested a read-only, independent adversarial review of a proposed backwards-compatible design across worktrees `/home/byk/Code/getsentry/craft-workspace-action-propagation` and `/home/byk/Code/getsentry/publish-workspace-acceptance`; stated previous reviewer stalled. User explicitly instructed not to edit anything and to return only a conc…