Skip to content
Merged
Show file tree
Hide file tree
Changes from 64 commits
Commits
Show all changes
75 commits
Select commit Hold shift + click to select a range
d0ba5d6
Merge pull request #798 from otomatty/main
otomatty May 2, 2026
e2a1751
fix(mobile): widen bottom-nav item padding and add bottom margin (#799)
otomatty May 3, 2026
117d46d
chore(deps): bump the minor-and-patch group with 2 updates (#800)
dependabot[bot] May 4, 2026
05357a8
feat(api): add Sentry error capture (#810)
otomatty May 4, 2026
c9a3696
feat: add api_errors table and service for Sentry error aggregation (…
otomatty May 4, 2026
e351898
feat: Add Sentry webhook receiver and admin error management API (#812)
otomatty May 4, 2026
5bb767e
feat: Add API errors admin page with real-time polling and Sentry int…
otomatty May 4, 2026
9237966
feat(api): repository_dispatch + AI analysis callback (#805) (#814)
otomatty May 5, 2026
7dae05e
feat: Add Claude AI error analysis workflow (Epic #616 Phase 2) (#815)
otomatty May 5, 2026
4252952
feat: implement SSE streaming for real-time API error updates (#816)
otomatty May 5, 2026
3375128
feat: implement auto-file GitHub Issue on high/medium severity (Epic …
otomatty May 5, 2026
8363b55
feat(api): add email-only notifier for high/medium API errors (#809) …
otomatty May 6, 2026
64586ab
Add thumbnail garbage collection on page deletion (#819)
otomatty May 7, 2026
cfa1452
feat(api): add default note ("マイノート") foundation (#821)
otomatty May 8, 2026
49ba374
chore(deps): bump tauri (#822)
dependabot[bot] May 8, 2026
fe64082
feat(api): migrate personal pages into default note and drop note_pag…
otomatty May 9, 2026
b30fa8f
Retire /home, introduce /notes/me landing with default note resolutio…
otomatty May 9, 2026
ff076dd
feat: implement clipUrl hand-off for Chrome extension via /notes/me (…
otomatty May 10, 2026
c516e0d
feat: add note switcher dropdown to header (issue #827) (#834)
otomatty May 10, 2026
cd7c22f
feat(frontend): generalize HomePageCount to NotePageCount(noteId) (#8…
otomatty May 10, 2026
0d68034
Update Zedi Web Clipper to use /notes/me endpoint (#836)
otomatty May 10, 2026
d85ae21
feat(frontend): warn before flipping default note to public/unlisted …
otomatty May 10, 2026
d8fd505
Unify note and personal page grids with context-aware PageGrid (#838)
otomatty May 10, 2026
d027318
Refactor thumbnail deletion to use shared GC service with referential…
otomatty May 10, 2026
5f502ec
chore(deps): bump actions/create-github-app-token from 2 to 3 (#840)
dependabot[bot] May 11, 2026
1410a02
chore(deps): bump @anthropic-ai/sdk from 0.92.0 to 0.95.1 in the mino…
dependabot[bot] May 11, 2026
7dfaa15
chore(deps-dev): bump @commitlint/cli from 20.5.3 to 21.0.0 (#842)
dependabot[bot] May 11, 2026
3d6b02c
chore(deps): bump react-day-picker from 9.14.0 to 10.0.0 (#843)
dependabot[bot] May 11, 2026
fdba957
chore(deps): resolve dependabot conflicts for genai 2.0.1 and config-…
otomatty May 11, 2026
718984d
feat(notes): title switcher, settings redesign, remove share modal (#…
otomatty May 11, 2026
4651cbf
Dedupe note API calls and optimize page listing queries (#855)
otomatty May 11, 2026
c67d23c
perf(notes): Epic #847 phases 4-6 — shared image cache, virtualizatio…
otomatty May 11, 2026
0d8511a
fix(api): coerce MAX(pages.updated_at) to Date in GET /api/notes/:id …
otomatty May 13, 2026
9f6a0d1
feat(pdf): foundation for local PDF knowledge ingestion (#389) (#858)
otomatty May 13, 2026
478fce4
fix(api): restore content_preview in GET /api/notes/:id (#860 Phase 0…
otomatty May 13, 2026
12151a7
feat(api): keyset pagination + index for note pages (#860 Phase 1/2) …
otomatty May 13, 2026
b6230c7
feat: implement keyset cursor pagination for note pages (issue #860 P…
otomatty May 13, 2026
27a33e7
feat: add note-scoped SSE event channel for page list (#860 Phase 4) …
otomatty May 14, 2026
cc57e30
chore(notes): drop pages[] from note shell; add /page-titles + /pages…
otomatty May 14, 2026
e1598e6
fix(editor): suppress slash menu inside inline code and code blocks (…
otomatty May 14, 2026
e527235
feat(pdf): implement pdf.js viewer with highlights and derive-page se…
otomatty May 16, 2026
5f99095
test(e2e): add PDF knowledge ingestion E2E suite for #863 (#871)
otomatty May 16, 2026
be80392
feat(search): surface PDF highlight bodies in Global Search (#864) (#…
otomatty May 16, 2026
922f9e9
fix(pdf): disable isEvalSupported in getPdfDocument (#872) (#874)
otomatty May 16, 2026
a79b499
feat(note): remove note-scoped page search bar from NoteView (#875)
otomatty May 16, 2026
e68479c
fix(hocuspocus): repair WebSocket auth after note_pages removal (#876)
otomatty May 16, 2026
933a826
fix(api): add missing page snapshots migration (#877)
otomatty May 16, 2026
8f0527a
ci: Add Drizzle schema drift detection across entire repository (#879)
otomatty May 16, 2026
72679d5
feat(notes): add read-only share-settings entry for editor/viewer (#6…
otomatty May 16, 2026
74fcd6d
feat: implement issue #880 Phase B & C - wiki link graph sync (#882)
otomatty May 16, 2026
56e263b
fix: Add ON DELETE CASCADE to user FKs in invite link tables (#885)
otomatty May 16, 2026
f742cf1
refactor: unify page-detail toolbar into shared PageEditorHeader (#886)
otomatty May 16, 2026
dcdc83d
fix: Move WikiLink mark normalization to server-side (Issue #880 Phas…
otomatty May 16, 2026
f2388b0
Add metadata-only PUT endpoint and read-only GET endpoint for pages (…
otomatty May 16, 2026
0221bd8
feat(#890): align NotePageView toolbar with /pages/:id (history/expor…
otomatty May 17, 2026
d2e4e71
refactor(note): introduce NotePagePublicView for read-only guests (#8…
otomatty May 17, 2026
7885a59
refactor: consolidate page editor into note-centric architecture (Iss…
otomatty May 17, 2026
15aebce
refactor(api): retire GET/PUT /api/pages/:id/content (Issue #889 Phas…
otomatty May 17, 2026
eae01d1
feat: Add `/health` endpoint with Postgres pool saturation monitoring…
otomatty May 17, 2026
1329e28
feat: Add tag filter bar to note page list (#897)
otomatty May 17, 2026
aa1a22e
fix: align NoteMeRedirect skeleton with PageGrid layout (#898)
otomatty May 17, 2026
8da5d91
chore(deps): bump cloudflare/wrangler-action from 3 to 4
dependabot[bot] May 18, 2026
b40f7d1
chore(deps): bump the minor-and-patch group with 2 updates
dependabot[bot] May 18, 2026
5773b9d
chore(deps): sync bun.lock with package.json changes
github-actions[bot] May 18, 2026
8c75aa8
chore(deps): bump pdfjs-dist from 4.10.38 to 5.7.284
dependabot[bot] May 18, 2026
90bdd03
chore(deps): sync bun.lock with package.json changes
github-actions[bot] May 18, 2026
4b27153
feat(editor): replace collaboration loading spinner with skeleton UI …
otomatty May 18, 2026
8e42cdb
refactor: remove FAB "add existing page" feature and orphan copy hook…
otomatty May 18, 2026
c1417f9
refactor(page): remove mobile-only delete button from PageCard (#904)
otomatty May 18, 2026
86e3f5e
feat: add ErrorScreen component with ErrorBoundary integration (#907)
otomatty May 18, 2026
0d11e14
fix: PR #905 レビュー指摘のフォローアップ (#908)
otomatty May 18, 2026
baa1c1f
Merge pull request #899 from otomatty/dependabot/github_actions/devel…
otomatty May 18, 2026
692e434
Merge pull request #900 from otomatty/dependabot/npm_and_yarn/develop…
otomatty May 18, 2026
d678880
Merge pull request #901 from otomatty/dependabot/npm_and_yarn/develop…
otomatty May 18, 2026
212edb7
fix: clarify admin error response payload (#910)
otomatty May 18, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
8 changes: 8 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,14 @@ POLAR_PRO_YEARLY_PRODUCT_ID=YOUR_POLAR_YEARLY_PRODUCT_ID
# NOTE: MCP JWT は `BETTER_AUTH_SECRET` を署名鍵として共有する (audience で分離)。
# MCP JWTs are signed with `BETTER_AUTH_SECRET` (audience-scoped to `zedi-mcp`).

# Sentry DSNs (Epic #616). Each surface uses its own DSN so events are routed to
# the correct project. Leave unset locally — the SDKs no-op when DSN is empty.
# 各サーフェス(Web / 管理画面 / API)はそれぞれ別の DSN を使用する。
# 未設定でも SDK は no-op のため、ローカルでは空のままで良い。
# VITE_SENTRY_DSN_WEB=https://<public-key>@o0.ingest.sentry.io/<project>
# VITE_ADMIN_SENTRY_DSN=https://<public-key>@o0.ingest.sentry.io/<project>
# SENTRY_DSN_API=https://<public-key>@o0.ingest.sentry.io/<project>

# Docker Compose (docker-compose.dev.yml)
# Override defaults for local dev; required in shared/production. Do not commit real secrets.
# POSTGRES_USER=zedi
Expand Down
295 changes: 295 additions & 0 deletions .github/actions/claude-analyze/README.md

Large diffs are not rendered by default.

557 changes: 557 additions & 0 deletions .github/actions/claude-analyze/__tests__/autoIssue.test.mjs

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"severity": "critical",
"ai_summary": "Severity is not one of the allowed enum values."
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"severity": "medium",
"ai_root_cause": "ai_summary is missing"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"severity": "high",
"ai_summary": "Suspected files entry is missing the required path.",
"ai_suspected_files": [
{
"reason": "no path means this entry is invalid"
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"severity": "high",
"ai_summary": "Claude returned 6 suspected files, exceeding the documented 5-entry cap.",
"ai_suspected_files": [
{ "path": "src/a.ts" },
{ "path": "src/b.ts" },
{ "path": "src/c.ts" },
{ "path": "src/d.ts" },
{ "path": "src/e.ts" },
{ "path": "src/f.ts" }
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"severity": "high",
"ai_summary": "Database migration failed mid-flight, leaving rows with NULL note_id and breaking page lookups.",
"ai_root_cause": "Migration 0042 added a NOT NULL constraint without backfilling. Existing rows pre-dating the migration have NULL and the SELECT path crashes.",
"ai_suggested_fix": "Backfill note_id from pages.owner_id where NULL, then re-apply the NOT NULL constraint in a follow-up migration.",
"ai_suspected_files": [
{
"path": "server/api/drizzle/0042_add_note_id.sql",
"reason": "Introduced the NOT NULL constraint without a backfill step.",
"line": 12
},
{
"path": "server/api/src/services/pageService.ts",
"reason": "SELECT path that throws when note_id is NULL."
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"severity": "low",
"ai_summary": "Transient network blip while contacting the third-party clipper service. Retried automatically.",
"ai_root_cause": null,
"ai_suggested_fix": null,
"ai_suspected_files": null
}
123 changes: 123 additions & 0 deletions .github/actions/claude-analyze/__tests__/schema.test.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
/**
* Fixture-driven tests for the Claude analysis output schema. Issue #806.
*
* 実行方法 / How to run:
* `node --test .github/actions/claude-analyze/__tests__/schema.test.mjs`
*
* vitest を新たに追加するのは workspace の test:run が肥大化するので、
* Node 24 の組み込みテストランナーを使う。CI への組み込みは README 参照。
*
* Uses Node 24's built-in test runner instead of adding a new vitest workspace
* — keeps the action self-contained and avoids touching the monorepo's
* `test:run` aggregator. CI wiring guidance lives in the action README.
*/
import { test } from "node:test";
import assert from "node:assert/strict";
import { readFile } from "node:fs/promises";
import path from "node:path";

import {
analysisOutputSchema,
parseAndValidate,
SEVERITIES,
suspectedFileSchema,
} from "../schema.mjs";

const FIXTURES = path.join(import.meta.dirname, "fixtures");

/**
* @param {string} name
* @returns {Promise<string>}
*/
async function loadFixtureRaw(name) {
return readFile(path.join(FIXTURES, name), "utf8");
}

test("SEVERITIES matches the server-side ApiErrorSeverity enum", () => {
assert.deepEqual([...SEVERITIES], ["high", "medium", "low", "unknown"]);
});

test("valid-high.json passes the schema and round-trips through parseAndValidate", async () => {
const raw = await loadFixtureRaw("valid-high.json");
const parsed = JSON.parse(raw);
assert.equal(analysisOutputSchema.safeParse(parsed).success, true);
const validated = parseAndValidate(raw);
assert.equal(validated.severity, "high");
assert.equal(Array.isArray(validated.ai_suspected_files), true);
assert.equal(validated.ai_suspected_files?.length, 2);
assert.equal(validated.ai_suspected_files?.[0]?.path.includes("0042_add_note_id"), true);
});

test("valid-low-nulls.json accepts explicit nulls for optional fields", async () => {
const raw = await loadFixtureRaw("valid-low-nulls.json");
const validated = parseAndValidate(raw);
assert.equal(validated.severity, "low");
assert.equal(validated.ai_root_cause, null);
assert.equal(validated.ai_suggested_fix, null);
assert.equal(validated.ai_suspected_files, null);
});

test("invalid-bad-severity.json is rejected with a severity-mention message", async () => {
const raw = await loadFixtureRaw("invalid-bad-severity.json");
assert.throws(() => parseAndValidate(raw), /severity/i);
});

test("invalid-missing-summary.json is rejected when ai_summary is absent", async () => {
const raw = await loadFixtureRaw("invalid-missing-summary.json");
assert.throws(() => parseAndValidate(raw), /ai_summary/);
});

test("invalid-suspected-file.json is rejected when an entry has no path", async () => {
const raw = await loadFixtureRaw("invalid-suspected-file.json");
assert.throws(() => parseAndValidate(raw), /path/);
});

test("invalid-too-many-files.json is rejected when ai_suspected_files exceeds 5 entries", async () => {
const raw = await loadFixtureRaw("invalid-too-many-files.json");
assert.throws(() => parseAndValidate(raw), /ai_suspected_files.*5|at most 5/);
});

test("parseAndValidate strips Claude's ```json``` fence and prose preamble", () => {
const wrapped = [
"Sure, here is the analysis:",
"```json",
JSON.stringify({
severity: "medium",
ai_summary: "wrapped in fence",
ai_root_cause: null,
ai_suggested_fix: null,
ai_suspected_files: null,
}),
"```",
].join("\n");
const validated = parseAndValidate(wrapped);
assert.equal(validated.severity, "medium");
assert.equal(validated.ai_summary, "wrapped in fence");
});

test("parseAndValidate throws when no JSON object is present", () => {
assert.throws(() => parseAndValidate("nope, no braces here"), /JSON object/);
});

test("parseAndValidate throws on empty input", () => {
assert.throws(() => parseAndValidate(""), /empty/);
});

test("suspectedFileSchema requires a non-empty path", () => {
assert.equal(suspectedFileSchema.safeParse({ path: "" }).success, false);
assert.equal(suspectedFileSchema.safeParse({ path: "src/foo.ts" }).success, true);
});

test("suspectedFileSchema rejects non-integer line numbers", () => {
assert.equal(suspectedFileSchema.safeParse({ path: "src/foo.ts", line: 12.5 }).success, false);
assert.equal(suspectedFileSchema.safeParse({ path: "src/foo.ts", line: 12 }).success, true);
});

test("analysisOutputSchema rejects unknown top-level keys (strict mode)", () => {
const bad = {
severity: "low",
ai_summary: "ok",
extra_field: "should not be here",
};
assert.equal(analysisOutputSchema.safeParse(bad).success, false);
});
192 changes: 192 additions & 0 deletions .github/actions/claude-analyze/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,192 @@
# `.github/actions/claude-analyze` — Composite action that runs the Claude
# AI error analysis script and PUTs the validated result back to the API
# callback endpoint. Epic #616 Phase 2 / issue #806.
#
# This action is invoked by `.github/workflows/analyze-error.yml` on
# `repository_dispatch` (`event_type: analyze-error`). See README.md for the
# full client_payload contract and a workflow_dispatch dry-run recipe.
name: Claude analyze API error
description: >
Analyze a Sentry-reported API error with Claude and PUT the structured
result back to the Zedi API callback endpoint. / Sentry が検知した API エラーを
Claude で解析し、構造化結果を Zedi API のコールバックへ書き戻す。

inputs:
api_error_id:
description: "`api_errors.id` (UUID) for the row to update."
required: true
sentry_issue_id:
description: Sentry issue id from the dispatch client_payload.
required: true
title:
description: Short error title from Sentry.
required: true
route:
description: Route where the error fired (may be empty).
required: false
default: ""
callback_base_url:
description: >
Base URL for the API callback (e.g. https://api.example.com).
The action appends `/api/webhooks/github/ai-result/<id>`.
required: true
installation_token:
description: GitHub App installation access token used as the bearer for the callback PUT.
required: true
anthropic_api_key:
description: Anthropic API key for the Claude call.
required: true
model:
description: Override Claude model id (defaults to claude-sonnet-4-6).
required: false
default: ""
dry_run:
description: When "true", skip the Anthropic call and emit a stub payload (for workflow_dispatch testing).
required: false
default: "false"
skip_callback:
description: When "true", validate locally but do not PUT to the API (pairs with dry_run for fixture validation).
required: false
default: "false"
skip_issue:
description: >
When "true", skip the auto-issue (create / comment) step. Pairs with
`dry_run` / `skip_callback` for fixture validation. Epic #616 Phase 3.
required: false
default: "false"

outputs:
severity:
description: AI-assigned severity (high | medium | low | unknown).
value: ${{ steps.analyze.outputs.severity }}
output_path:
description: Path to the validated analysis JSON written by the script.
value: ${{ steps.analyze.outputs.output_path }}
issue_action:
description: >
Outcome of the auto-issue step: `skipped`, `created`, or `commented`.
Empty when `skip_issue=true`. Epic #616 Phase 3 / Issue #808.
value: ${{ steps.auto-issue.outputs.action }}
issue_number:
description: GitHub Issue number created or commented on (empty when skipped).
value: ${{ steps.auto-issue.outputs.issue_number }}
issue_html_url:
description: HTML URL of the created Issue or recurrence comment (empty when skipped).
value: ${{ steps.auto-issue.outputs.issue_html_url }}

runs:
using: composite
steps:
- name: Setup Node
uses: actions/setup-node@v6
with:
node-version-file: .nvmrc

- name: Setup Bun
uses: oven-sh/setup-bun@v2
with:
bun-version: "1.3"

- name: Install dependencies
shell: bash
run: bun install --frozen-lockfile

- name: Run analyze script
id: analyze
shell: bash
env:
CLAUDE_ANALYZE_API_ERROR_ID: ${{ inputs.api_error_id }}
CLAUDE_ANALYZE_SENTRY_ISSUE_ID: ${{ inputs.sentry_issue_id }}
CLAUDE_ANALYZE_TITLE: ${{ inputs.title }}
CLAUDE_ANALYZE_ROUTE: ${{ inputs.route }}
CLAUDE_ANALYZE_REPOSITORY: ${{ github.repository }}
ANTHROPIC_API_KEY: ${{ inputs.anthropic_api_key }}
CLAUDE_MODEL: ${{ inputs.model }}
CLAUDE_ANALYZE_DRY_RUN: ${{ inputs.dry_run }}
CLAUDE_ANALYZE_OUTPUT: ${{ runner.temp }}/analyze-output.json
run: |
node "${{ github.action_path }}/analyze.mjs"
echo "output_path=${CLAUDE_ANALYZE_OUTPUT}" >> "$GITHUB_OUTPUT"
# severity を outputs に拾う。Node スクリプトに依存させず、jq で抜き出す。
# Pull severity into outputs via jq — keeps the script's only contract
# the JSON file, no out-of-band stdout protocol to maintain.
SEVERITY=$(jq -r '.severity' "${CLAUDE_ANALYZE_OUTPUT}")
echo "severity=${SEVERITY}" >> "$GITHUB_OUTPUT"
echo "::notice title=AI severity::${SEVERITY}"

- name: PUT analysis to API callback
if: inputs.skip_callback != 'true'
shell: bash
env:
CALLBACK_URL: ${{ inputs.callback_base_url }}/api/webhooks/github/ai-result/${{ inputs.api_error_id }}
INSTALLATION_TOKEN: ${{ inputs.installation_token }}
OUTPUT_PATH: ${{ steps.analyze.outputs.output_path }}
run: |
set -euo pipefail
# API のコールバックに PUT。失敗時は最大 2 回までリトライ(issue #806 の
# 「workflow 内で 1〜2 回まで」要件)。HTTP ステータスを判定し、
# 5xx / ネットワークエラーのみリトライ、4xx は即失敗(auth 不正など)。
#
# PUT to the API callback. Retry up to 2 attempts (issue #806's "1〜2 回
# まで"). Only retry on transient 5xx / network errors; 4xx (auth, bad
# payload) is final so misconfiguration surfaces immediately.
attempt=1
max_attempts=2
while true; do
echo "PUT ${CALLBACK_URL} (attempt ${attempt}/${max_attempts})"
# `--connect-timeout` で TCP 接続待ちを 10 秒、`--max-time` でリクエスト
# 全体を 30 秒に制限する。ハングした session が retry ループの背圧になる
# のを防ぐ(Job timeout の 10 分を一発で食い潰すのを避ける目的)。
# `--connect-timeout` caps TCP connect at 10 s; `--max-time` caps the
# total request at 30 s. Without these, a hung session would block the
# retry loop and could burn the entire 10-minute job timeout on a
# single PUT.
http_status=$(curl -sS -o /tmp/callback-response.txt -w "%{http_code}" \
-X PUT "${CALLBACK_URL}" \
-H "Authorization: Bearer ${INSTALLATION_TOKEN}" \
-H "Content-Type: application/json" \
--connect-timeout 10 \
--max-time 30 \
--data-binary "@${OUTPUT_PATH}" || echo "000")
echo "HTTP ${http_status}"
if [ "${http_status}" -ge 200 ] && [ "${http_status}" -lt 300 ]; then
cat /tmp/callback-response.txt
echo
echo "Callback succeeded."
break
fi
if [ "${http_status}" -ge 400 ] && [ "${http_status}" -lt 500 ]; then
echo "::error title=Callback rejected (${http_status})::$(cat /tmp/callback-response.txt)"
exit 1
fi
if [ "${attempt}" -ge "${max_attempts}" ]; then
echo "::error title=Callback failed after ${max_attempts} attempts (${http_status})::$(cat /tmp/callback-response.txt)"
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Outdated
exit 1
fi
attempt=$((attempt + 1))
sleep 5
done

- name: Auto-file or comment GitHub Issue
# Epic #616 Phase 3 / Issue #808: severity が high / medium のときだけ
# Issue を起票し、同一 sentry_issue_id に既存オープン Issue があれば
# コメント追記で再発を表現する(連続 100 回でも 1 件に集約)。`skip_issue`
# は `workflow_dispatch` のドライラン用フラグ。
#
# Files a GitHub Issue when AI severity is high / medium, or appends a
# recurrence comment when an open Issue with the matching
# `sentry-issue:<id>` label already exists. Honors `skip_issue` so
# workflow_dispatch dry runs cannot accidentally create Issues.
if: inputs.skip_issue != 'true'
id: auto-issue
shell: bash
env:
AUTO_ISSUE_OUTPUT_PATH: ${{ steps.analyze.outputs.output_path }}
AUTO_ISSUE_SENTRY_ISSUE_ID: ${{ inputs.sentry_issue_id }}
AUTO_ISSUE_API_ERROR_ID: ${{ inputs.api_error_id }}
AUTO_ISSUE_TITLE: ${{ inputs.title }}
AUTO_ISSUE_ROUTE: ${{ inputs.route }}
AUTO_ISSUE_REPOSITORY: ${{ github.repository }}
AUTO_ISSUE_TOKEN: ${{ inputs.installation_token }}
AUTO_ISSUE_WORKFLOW_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
run: node "${{ github.action_path }}/autoIssueRunner.mjs"
Loading
Loading