Skip to content

Commit eac7332

Browse files
authored
Merge pull request #72 from Blazity/revert-70-feat/jira-app
Revert "feat/jira-app"
2 parents 899938b + 0f319df commit eac7332

7 files changed

Lines changed: 13 additions & 244 deletions

File tree

.env.example

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,6 @@ COLUMN_BACKLOG=Backlog
1313
# Without this, dispatch falls back to ~60s cron polling on every ticket.
1414
JIRA_WEBHOOK_SECRET=
1515

16-
# Forge bridge (alternative to JIRA_WEBHOOK_SECRET; replaces the personal
17-
# API-token comment author with the ai-workflow-jira-app Forge app user).
18-
# Set both when running the companion ai-workflow-jira-app:
19-
# - FORGE_SHARED_SECRET: same value passed to `forge variables set --encrypt SHARED_SECRET ...`
20-
# - FORGE_COMMENT_URL: the `post-comment` URL printed by `forge webtrigger`
21-
# When unset, /jira/dispatch returns 503 and postComment uses Basic auth.
22-
FORGE_SHARED_SECRET=
23-
FORGE_COMMENT_URL=
24-
2516
# VCS — choose one provider by setting VCS_KIND to "github" or "gitlab".
2617
# Only ONE VCS_KIND line should be active in this file.
2718
VCS_KIND=github

env.ts

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -116,13 +116,6 @@ export const env = createEnv({
116116
// Jira Webhook
117117
JIRA_WEBHOOK_SECRET: z.string().min(1).optional(),
118118

119-
// Forge bridge — when both are set, /jira/dispatch authenticates the
120-
// X-Forge-Secret header and JiraAdapter.postComment routes through the
121-
// ai-workflow-jira-app Forge web trigger so comments are authored by
122-
// the Forge app user instead of a personal Atlassian account.
123-
FORGE_SHARED_SECRET: z.string().min(1).optional(),
124-
FORGE_COMMENT_URL: z.string().url().optional(),
125-
126119
// Redis (run registry)
127120
AI_WORKFLOW_KV_REST_API_URL: z.string().url(),
128121
AI_WORKFLOW_KV_REST_API_TOKEN: z.string().min(1),

src/adapters/issue-tracker/jira.test.ts

Lines changed: 0 additions & 105 deletions
Original file line numberDiff line numberDiff line change
@@ -493,109 +493,4 @@ describe("JiraAdapter", () => {
493493
expect(collectText(body.body)).not.toContain("\n");
494494
});
495495
});
496-
497-
describe("postComment via Forge bridge", () => {
498-
function forgeAdapter() {
499-
return new JiraAdapter({
500-
baseUrl: "https://test.atlassian.net",
501-
email: "test@example.com",
502-
apiToken: "token",
503-
projectKey: "PROJ",
504-
forgeCommentUrl: "https://forge.example/x/post-comment",
505-
forgeSharedSecret: "shh",
506-
});
507-
}
508-
509-
it("POSTs to the Forge web trigger with shared-secret header and plain-text body", async () => {
510-
mockFetch.mockResolvedValueOnce({
511-
ok: true,
512-
status: 200,
513-
statusText: "OK",
514-
json: async () => ({ id: "55555", permalinkPath: "?focusedCommentId=55555" }),
515-
});
516-
517-
const url = await forgeAdapter().postComment("PROJ-1", "hello\nworld");
518-
519-
expect(mockFetch).toHaveBeenCalledTimes(1);
520-
const [calledUrl, init] = mockFetch.mock.calls[0];
521-
expect(calledUrl).toBe("https://forge.example/x/post-comment");
522-
const headers = init.headers as Record<string, string>;
523-
expect(headers["x-shared-secret"]).toBe("shh");
524-
expect(headers["Content-Type"]).toBe("application/json");
525-
expect(JSON.parse(init.body)).toEqual({
526-
issueKey: "PROJ-1",
527-
body: "hello\nworld",
528-
});
529-
expect(url).toBe(
530-
"https://test.atlassian.net/browse/PROJ-1?focusedCommentId=55555",
531-
);
532-
});
533-
534-
it("returns null when Forge response omits id or permalinkPath", async () => {
535-
mockFetch.mockResolvedValueOnce({
536-
ok: true,
537-
status: 200,
538-
statusText: "OK",
539-
json: async () => ({ id: null, permalinkPath: null }),
540-
});
541-
542-
const url = await forgeAdapter().postComment("PROJ-1", "hi");
543-
expect(url).toBeNull();
544-
});
545-
546-
it("maps 404 from Forge to IssueTrackerNotFoundError", async () => {
547-
mockFetch.mockResolvedValueOnce({
548-
ok: false,
549-
status: 404,
550-
statusText: "Not Found",
551-
json: async () => ({ error: "jira_error", status: 404 }),
552-
});
553-
554-
await expect(forgeAdapter().postComment("PROJ-9", "x")).rejects.toBeInstanceOf(
555-
IssueTrackerNotFoundError,
556-
);
557-
});
558-
559-
it("throws on other non-2xx Forge responses", async () => {
560-
mockFetch.mockResolvedValueOnce({
561-
ok: false,
562-
status: 502,
563-
statusText: "Bad Gateway",
564-
json: async () => ({ error: "jira_error", status: 500 }),
565-
});
566-
567-
await expect(forgeAdapter().postComment("PROJ-1", "x")).rejects.toThrow(
568-
/Forge postComment error: 502/,
569-
);
570-
});
571-
572-
it("falls back to direct Basic-auth path when only one Forge field is set", async () => {
573-
mockFetch.mockResolvedValueOnce({
574-
ok: true,
575-
json: async () => ({ id: "98765" }),
576-
});
577-
578-
const adapter = new JiraAdapter({
579-
baseUrl: "https://test.atlassian.net",
580-
email: "test@example.com",
581-
apiToken: "token",
582-
projectKey: "PROJ",
583-
forgeCommentUrl: "https://forge.example/x/post-comment",
584-
// forgeSharedSecret intentionally omitted
585-
});
586-
587-
const url = await adapter.postComment("PROJ-1", "hi");
588-
589-
const [calledUrl, init] = mockFetch.mock.calls[0];
590-
expect(calledUrl).toBe(
591-
"https://test.atlassian.net/rest/api/3/issue/PROJ-1/comment",
592-
);
593-
expect((init.headers as Record<string, string>).Authorization).toMatch(
594-
/^Basic /,
595-
);
596-
expect(url).toBe(
597-
"https://test.atlassian.net/browse/PROJ-1?focusedCommentId=98765",
598-
);
599-
});
600-
});
601496
});

src/adapters/issue-tracker/jira.ts

Lines changed: 13 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,6 @@ export interface JiraConfig {
1111
email: string;
1212
apiToken: string;
1313
projectKey: string;
14-
forgeCommentUrl?: string;
15-
forgeSharedSecret?: string;
1614
}
1715

1816
export class JiraAdapter implements IssueTrackerAdapter {
@@ -41,9 +39,7 @@ export class JiraAdapter implements IssueTrackerAdapter {
4139
if (res.status === 404) {
4240
throw new IssueTrackerNotFoundError("Jira resource", path);
4341
}
44-
throw new Error(
45-
`Jira API error: ${res.status} ${res.statusText} on ${path}`,
46-
);
42+
throw new Error(`Jira API error: ${res.status} ${res.statusText} on ${path}`);
4743
}
4844
if (res.status === 204) return null;
4945
try {
@@ -73,19 +69,17 @@ export class JiraAdapter implements IssueTrackerAdapter {
7369
),
7470
labels: data.fields.labels ?? [],
7571
trackerStatus: data.fields.status?.name ?? "",
76-
attachments: (data.fields.attachment ?? []).map(
77-
(a: any): TicketAttachment => {
78-
const contentUrl =
79-
a.content == null ? undefined : String(a.content).trim();
80-
return {
81-
id: String(a.id),
82-
filename: a.filename ?? "",
83-
mimeType: a.mimeType ?? "application/octet-stream",
84-
size: sanitizeAttachmentSize(a.size),
85-
contentUrl: contentUrl || undefined,
86-
};
87-
},
88-
),
72+
attachments: (data.fields.attachment ?? []).map((a: any): TicketAttachment => {
73+
const contentUrl =
74+
a.content == null ? undefined : String(a.content).trim();
75+
return {
76+
id: String(a.id),
77+
filename: a.filename ?? "",
78+
mimeType: a.mimeType ?? "application/octet-stream",
79+
size: sanitizeAttachmentSize(a.size),
80+
contentUrl: contentUrl || undefined,
81+
};
82+
}),
8983
};
9084
}
9185

@@ -106,9 +100,6 @@ export class JiraAdapter implements IssueTrackerAdapter {
106100
}
107101

108102
async postComment(id: string, comment: string): Promise<string | null> {
109-
if (this.config.forgeCommentUrl && this.config.forgeSharedSecret) {
110-
return this.postCommentViaForge(id, comment);
111-
}
112103
const data = await this.request(`/rest/api/3/issue/${id}/comment`, {
113104
method: "POST",
114105
body: JSON.stringify({
@@ -124,34 +115,6 @@ export class JiraAdapter implements IssueTrackerAdapter {
124115
return `${this.baseUrl}/browse/${encodeURIComponent(id)}?focusedCommentId=${encodeURIComponent(commentId)}`;
125116
}
126117

127-
private async postCommentViaForge(
128-
id: string,
129-
comment: string,
130-
): Promise<string | null> {
131-
const res = await fetch(this.config.forgeCommentUrl!, {
132-
method: "POST",
133-
headers: {
134-
"Content-Type": "application/json",
135-
"x-shared-secret": this.config.forgeSharedSecret!,
136-
},
137-
body: JSON.stringify({ issueKey: id, body: comment }),
138-
});
139-
if (res.status === 404) {
140-
throw new IssueTrackerNotFoundError("Jira issue", id);
141-
}
142-
if (!res.ok) {
143-
throw new Error(
144-
`Forge postComment error: ${res.status} ${res.statusText}`,
145-
);
146-
}
147-
const data = (await res.json()) as {
148-
id?: string | null;
149-
permalinkPath?: string | null;
150-
};
151-
if (!data?.id || !data?.permalinkPath) return null;
152-
return `${this.baseUrl}/browse/${encodeURIComponent(id)}${data.permalinkPath}`;
153-
}
154-
155118
async downloadAttachment(
156119
url: string,
157120
opts: { timeoutMs?: number } = {},
@@ -238,9 +201,7 @@ function extractAdfText(adf: any): string {
238201

239202
function extractAcceptanceCriteria(description: any): string {
240203
const text = extractAdfText(description);
241-
const match = text.match(
242-
/acceptance criteria[:\s]*([\s\S]*?)(?:\n\n|\n#|$)/i,
243-
);
204+
const match = text.match(/acceptance criteria[:\s]*([\s\S]*?)(?:\n\n|\n#|$)/i);
244205
return match?.[1]?.trim() ?? "";
245206
}
246207

src/lib/adapters.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,6 @@ export function createAdapters(): Adapters {
4040
email: env.JIRA_EMAIL,
4141
apiToken: env.JIRA_API_TOKEN,
4242
projectKey: env.JIRA_PROJECT_KEY,
43-
forgeCommentUrl: env.FORGE_COMMENT_URL,
44-
forgeSharedSecret: env.FORGE_SHARED_SECRET,
4543
}),
4644
vcs: createVCS(),
4745
messaging,

src/lib/step-adapters.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,6 @@ export function createStepAdapters(): StepAdapters {
3737
email: env.JIRA_EMAIL,
3838
apiToken: env.JIRA_API_TOKEN,
3939
projectKey: env.JIRA_PROJECT_KEY,
40-
forgeCommentUrl: env.FORGE_COMMENT_URL,
41-
forgeSharedSecret: env.FORGE_SHARED_SECRET,
4240
}),
4341
vcs: createVCS(),
4442
messaging,

src/routes/jira/dispatch.post.ts

Lines changed: 0 additions & 67 deletions
This file was deleted.

0 commit comments

Comments
 (0)