@commandable/integration-data 0.0.6 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/credentials-index.d.ts.map +1 -1
- package/dist/credentials-index.js +130 -0
- package/dist/credentials-index.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/loader.d.ts +48 -0
- package/dist/loader.d.ts.map +1 -1
- package/dist/loader.js +46 -4
- package/dist/loader.js.map +1 -1
- package/integrations/__tests__/liveHarness.ts +16 -3
- package/integrations/airtable/.env.test +9 -0
- package/integrations/airtable/.env.test.example +11 -0
- package/integrations/airtable/README.md +27 -0
- package/integrations/airtable/__tests__/get_handlers.test.ts +43 -5
- package/integrations/airtable/credentials.json +2 -1
- package/integrations/confluence/.env.test +25 -0
- package/integrations/confluence/.env.test.example +36 -0
- package/integrations/confluence/README.md +28 -0
- package/integrations/confluence/__tests__/get_handlers.test.ts +121 -0
- package/integrations/confluence/__tests__/usage_parity.test.ts +14 -0
- package/integrations/confluence/__tests__/write_handlers.test.ts +131 -0
- package/integrations/confluence/credentials.json +39 -0
- package/integrations/confluence/credentials_hint.md +4 -0
- package/integrations/confluence/credentials_hint_api_token.md +9 -0
- package/integrations/confluence/credentials_hint_oauth_token.md +8 -0
- package/integrations/confluence/handlers/add_comment.js +19 -0
- package/integrations/confluence/handlers/add_label.js +16 -0
- package/integrations/confluence/handlers/create_page.js +22 -0
- package/integrations/confluence/handlers/delete_page.js +17 -0
- package/integrations/confluence/handlers/get_comments.js +33 -0
- package/integrations/confluence/handlers/get_page_children.js +30 -0
- package/integrations/confluence/handlers/get_space.js +22 -0
- package/integrations/confluence/handlers/list_spaces.js +39 -0
- package/integrations/confluence/handlers/read_page.js +49 -0
- package/integrations/confluence/handlers/search_pages.js +42 -0
- package/integrations/confluence/handlers/update_page.js +42 -0
- package/integrations/confluence/manifest.json +85 -0
- package/integrations/confluence/prompt.md +55 -0
- package/integrations/confluence/schemas/add_comment.json +22 -0
- package/integrations/confluence/schemas/add_label.json +19 -0
- package/integrations/confluence/schemas/create_page.json +33 -0
- package/integrations/confluence/schemas/delete_page.json +23 -0
- package/integrations/confluence/schemas/empty.json +6 -0
- package/integrations/confluence/schemas/get_comments.json +24 -0
- package/integrations/confluence/schemas/get_page_children.json +28 -0
- package/integrations/confluence/schemas/get_space.json +18 -0
- package/integrations/confluence/schemas/list_spaces.json +36 -0
- package/integrations/confluence/schemas/read_page.json +28 -0
- package/integrations/confluence/schemas/search_pages.json +26 -0
- package/integrations/confluence/schemas/update_page.json +31 -0
- package/integrations/github/.env.test +16 -0
- package/integrations/github/.env.test.example +17 -0
- package/integrations/github/README.md +75 -0
- package/integrations/github/__tests__/get_handlers.test.ts +5 -5
- package/integrations/github/__tests__/write_handlers.test.ts +176 -58
- package/integrations/github/credentials.json +4 -2
- package/integrations/github/handlers/create_file.js +46 -0
- package/integrations/github/handlers/delete_file.js +14 -1
- package/integrations/github/handlers/edit_file.js +52 -0
- package/integrations/github/handlers/edit_files.js +107 -0
- package/integrations/github/manifest.json +74 -47
- package/integrations/github/prompt.md +36 -0
- package/integrations/github/schemas/create_file.json +13 -0
- package/integrations/github/schemas/delete_file.json +2 -2
- package/integrations/github/schemas/edit_file.json +26 -0
- package/integrations/github/schemas/edit_files.json +39 -0
- package/integrations/google-calendar/.env.test.example +11 -0
- package/integrations/google-calendar/README.md +41 -0
- package/integrations/google-calendar/__tests__/write_and_admin_handlers.test.ts +7 -7
- package/integrations/google-calendar/credentials.json +4 -2
- package/integrations/google-calendar/credentials_hint.md +1 -1
- package/integrations/google-calendar/manifest.json +27 -17
- package/integrations/google-docs/README.md +30 -0
- package/integrations/google-docs/credentials_hint.md +1 -1
- package/integrations/google-drive/README.md +26 -0
- package/integrations/google-drive/credentials.json +4 -2
- package/integrations/google-gmail/.env.test.example +11 -0
- package/integrations/google-gmail/README.md +49 -0
- package/integrations/google-gmail/credentials.json +4 -2
- package/integrations/google-gmail/handlers/create_draft_email.js +1 -1
- package/integrations/google-gmail/handlers/read_email.js +1 -1
- package/integrations/google-gmail/handlers/send_email.js +1 -1
- package/integrations/google-gmail/manifest.json +36 -25
- package/integrations/google-sheet/README.md +27 -0
- package/integrations/google-sheet/credentials_hint.md +1 -1
- package/integrations/google-slides/README.md +28 -0
- package/integrations/google-slides/credentials_hint.md +1 -1
- package/integrations/hubspot/.env.test.example +20 -0
- package/integrations/hubspot/README.md +48 -0
- package/integrations/hubspot/__tests__/get_handlers.test.ts +151 -0
- package/integrations/hubspot/__tests__/usage_parity.test.ts +10 -0
- package/integrations/hubspot/__tests__/write_handlers.test.ts +244 -0
- package/integrations/hubspot/credentials.json +50 -0
- package/integrations/hubspot/credentials_hint.md +20 -0
- package/integrations/hubspot/credentials_hint_oauth_token.md +16 -0
- package/integrations/hubspot/handlers/archive_company.js +13 -0
- package/integrations/hubspot/handlers/archive_contact.js +13 -0
- package/integrations/hubspot/handlers/archive_deal.js +13 -0
- package/integrations/hubspot/handlers/archive_ticket.js +13 -0
- package/integrations/hubspot/handlers/create_association.js +18 -0
- package/integrations/hubspot/handlers/create_company.js +13 -0
- package/integrations/hubspot/handlers/create_contact.js +14 -0
- package/integrations/hubspot/handlers/create_deal.js +16 -0
- package/integrations/hubspot/handlers/create_note.js +44 -0
- package/integrations/hubspot/handlers/create_task.js +48 -0
- package/integrations/hubspot/handlers/create_ticket.js +15 -0
- package/integrations/hubspot/handlers/get_associations.js +14 -0
- package/integrations/hubspot/handlers/get_company.js +18 -0
- package/integrations/hubspot/handlers/get_contact.js +18 -0
- package/integrations/hubspot/handlers/get_deal.js +18 -0
- package/integrations/hubspot/handlers/get_ticket.js +20 -0
- package/integrations/hubspot/handlers/list_owners.js +12 -0
- package/integrations/hubspot/handlers/list_pipelines.js +5 -0
- package/integrations/hubspot/handlers/list_properties.js +11 -0
- package/integrations/hubspot/handlers/remove_association.js +22 -0
- package/integrations/hubspot/handlers/search_companies.js +43 -0
- package/integrations/hubspot/handlers/search_contacts.js +43 -0
- package/integrations/hubspot/handlers/search_deals.js +43 -0
- package/integrations/hubspot/handlers/search_notes.js +43 -0
- package/integrations/hubspot/handlers/search_tasks.js +43 -0
- package/integrations/hubspot/handlers/search_tickets.js +43 -0
- package/integrations/hubspot/handlers/update_company.js +13 -0
- package/integrations/hubspot/handlers/update_contact.js +14 -0
- package/integrations/hubspot/handlers/update_deal.js +16 -0
- package/integrations/hubspot/handlers/update_task.js +17 -0
- package/integrations/hubspot/handlers/update_ticket.js +15 -0
- package/integrations/hubspot/manifest.json +230 -0
- package/integrations/hubspot/prompt.md +69 -0
- package/integrations/hubspot/schemas/archive_company.json +13 -0
- package/integrations/hubspot/schemas/archive_contact.json +13 -0
- package/integrations/hubspot/schemas/archive_deal.json +9 -0
- package/integrations/hubspot/schemas/archive_ticket.json +9 -0
- package/integrations/hubspot/schemas/create_association.json +24 -0
- package/integrations/hubspot/schemas/create_company.json +14 -0
- package/integrations/hubspot/schemas/create_contact.json +15 -0
- package/integrations/hubspot/schemas/create_deal.json +20 -0
- package/integrations/hubspot/schemas/create_note.json +37 -0
- package/integrations/hubspot/schemas/create_task.json +51 -0
- package/integrations/hubspot/schemas/create_ticket.json +16 -0
- package/integrations/hubspot/schemas/empty.json +6 -0
- package/integrations/hubspot/schemas/get_associations.json +30 -0
- package/integrations/hubspot/schemas/get_company.json +27 -0
- package/integrations/hubspot/schemas/get_contact.json +27 -0
- package/integrations/hubspot/schemas/get_deal.json +20 -0
- package/integrations/hubspot/schemas/get_ticket.json +20 -0
- package/integrations/hubspot/schemas/list_owners.json +25 -0
- package/integrations/hubspot/schemas/list_pipelines.json +13 -0
- package/integrations/hubspot/schemas/list_properties.json +17 -0
- package/integrations/hubspot/schemas/remove_association.json +24 -0
- package/integrations/hubspot/schemas/search_companies.json +56 -0
- package/integrations/hubspot/schemas/search_contacts.json +56 -0
- package/integrations/hubspot/schemas/search_deals.json +43 -0
- package/integrations/hubspot/schemas/search_notes.json +43 -0
- package/integrations/hubspot/schemas/search_tasks.json +43 -0
- package/integrations/hubspot/schemas/search_tickets.json +43 -0
- package/integrations/hubspot/schemas/update_company.json +20 -0
- package/integrations/hubspot/schemas/update_contact.json +21 -0
- package/integrations/hubspot/schemas/update_deal.json +19 -0
- package/integrations/hubspot/schemas/update_task.json +31 -0
- package/integrations/hubspot/schemas/update_ticket.json +18 -0
- package/integrations/jira/.env.test +46 -0
- package/integrations/jira/.env.test.example +41 -0
- package/integrations/jira/README.md +46 -0
- package/integrations/jira/__tests__/get_handlers.test.ts +193 -0
- package/integrations/jira/__tests__/usage_parity.test.ts +14 -0
- package/integrations/jira/__tests__/write_handlers.test.ts +157 -0
- package/integrations/jira/credentials.json +39 -0
- package/integrations/jira/credentials_hint.md +4 -0
- package/integrations/jira/credentials_hint_api_token.md +6 -0
- package/integrations/jira/credentials_hint_oauth_token.md +6 -0
- package/integrations/jira/handlers/add_comment.js +9 -0
- package/integrations/jira/handlers/assign_issue.js +11 -0
- package/integrations/jira/handlers/create_issue.js +37 -0
- package/integrations/jira/handlers/create_sprint.js +19 -0
- package/integrations/jira/handlers/delete_issue.js +10 -0
- package/integrations/jira/handlers/get_backlog_issues.js +13 -0
- package/integrations/jira/handlers/get_board.js +6 -0
- package/integrations/jira/handlers/get_issue.js +63 -0
- package/integrations/jira/handlers/get_issue_comments.js +31 -0
- package/integrations/jira/handlers/get_myself.js +14 -0
- package/integrations/jira/handlers/get_project.js +28 -0
- package/integrations/jira/handlers/get_sprint.js +5 -0
- package/integrations/jira/handlers/get_sprint_issues.js +13 -0
- package/integrations/jira/handlers/get_transitions.js +23 -0
- package/integrations/jira/handlers/list_boards.js +34 -0
- package/integrations/jira/handlers/list_projects.js +29 -0
- package/integrations/jira/handlers/list_sprints.js +29 -0
- package/integrations/jira/handlers/move_issues_to_sprint.js +11 -0
- package/integrations/jira/handlers/search_issues.js +43 -0
- package/integrations/jira/handlers/search_users.js +21 -0
- package/integrations/jira/handlers/transition_issue.js +44 -0
- package/integrations/jira/handlers/update_issue.js +40 -0
- package/integrations/jira/handlers/update_sprint.js +20 -0
- package/integrations/jira/manifest.json +204 -0
- package/integrations/jira/prompt.md +80 -0
- package/integrations/jira/schemas/add_comment.json +16 -0
- package/integrations/jira/schemas/assign_issue.json +16 -0
- package/integrations/jira/schemas/create_issue.json +49 -0
- package/integrations/jira/schemas/create_sprint.json +29 -0
- package/integrations/jira/schemas/delete_issue.json +12 -0
- package/integrations/jira/schemas/empty.json +6 -0
- package/integrations/jira/schemas/get_backlog_issues.json +33 -0
- package/integrations/jira/schemas/get_board.json +13 -0
- package/integrations/jira/schemas/get_issue.json +23 -0
- package/integrations/jira/schemas/get_issue_comments.json +23 -0
- package/integrations/jira/schemas/get_project.json +17 -0
- package/integrations/jira/schemas/get_sprint.json +13 -0
- package/integrations/jira/schemas/get_sprint_issues.json +33 -0
- package/integrations/jira/schemas/get_transitions.json +12 -0
- package/integrations/jira/schemas/list_boards.json +27 -0
- package/integrations/jira/schemas/list_projects.json +22 -0
- package/integrations/jira/schemas/list_sprints.json +29 -0
- package/integrations/jira/schemas/move_issues_to_sprint.json +19 -0
- package/integrations/jira/schemas/search_issues.json +28 -0
- package/integrations/jira/schemas/search_users.json +18 -0
- package/integrations/jira/schemas/transition_issue.json +38 -0
- package/integrations/jira/schemas/update_issue.json +47 -0
- package/integrations/jira/schemas/update_sprint.json +33 -0
- package/integrations/new_integration_prompt.md +173 -2
- package/integrations/notion/.env.test +10 -0
- package/integrations/notion/.env.test.example +13 -0
- package/integrations/notion/README.md +42 -0
- package/integrations/notion/credentials.json +2 -1
- package/integrations/notion/manifest.json +64 -35
- package/integrations/trello/.env.test +6 -0
- package/integrations/trello/.env.test.example +9 -0
- package/integrations/trello/README.md +50 -0
- package/integrations/trello/credentials.json +2 -1
- package/package.json +7 -3
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
import { beforeAll, describe, expect, it } from 'vitest'
|
|
2
|
+
import { createCredentialStore, createIntegrationNode, createProxy, createToolbox, hasEnv } from '../../__tests__/liveHarness.js'
|
|
3
|
+
|
|
4
|
+
// LIVE Jira read tests using credentials
|
|
5
|
+
//
|
|
6
|
+
// Variant: api_token
|
|
7
|
+
// - JIRA_DOMAIN
|
|
8
|
+
// - JIRA_EMAIL
|
|
9
|
+
// - JIRA_API_TOKEN
|
|
10
|
+
//
|
|
11
|
+
// Optional (improves coverage):
|
|
12
|
+
// - JIRA_TEST_PROJECT_KEY
|
|
13
|
+
|
|
14
|
+
const env = process.env as Record<string, string | undefined>
|
|
15
|
+
|
|
16
|
+
const suiteOrSkip = hasEnv('JIRA_DOMAIN', 'JIRA_EMAIL', 'JIRA_API_TOKEN') ? describe : describe.skip
|
|
17
|
+
|
|
18
|
+
suiteOrSkip('jira read handlers (live)', () => {
|
|
19
|
+
describe('variant: api_token', () => {
|
|
20
|
+
const ctx: {
|
|
21
|
+
projectKey?: string
|
|
22
|
+
issueKey?: string
|
|
23
|
+
boardId?: number
|
|
24
|
+
sprintId?: number
|
|
25
|
+
} = {}
|
|
26
|
+
|
|
27
|
+
let jira: ReturnType<typeof createToolbox>
|
|
28
|
+
|
|
29
|
+
beforeAll(async () => {
|
|
30
|
+
const credentialStore = createCredentialStore(async () => ({
|
|
31
|
+
domain: env.JIRA_DOMAIN!,
|
|
32
|
+
email: env.JIRA_EMAIL!,
|
|
33
|
+
apiToken: env.JIRA_API_TOKEN!,
|
|
34
|
+
}))
|
|
35
|
+
const proxy = createProxy(credentialStore)
|
|
36
|
+
jira = createToolbox('jira', proxy, createIntegrationNode('jira', { label: 'Jira', credentialId: 'jira-creds', credentialVariant: 'api_token' }), 'api_token')
|
|
37
|
+
|
|
38
|
+
try {
|
|
39
|
+
const list_projects = jira.read('list_projects')
|
|
40
|
+
const projectsResp = await list_projects({ maxResults: 5 })
|
|
41
|
+
const first = projectsResp?.projects?.[0]
|
|
42
|
+
ctx.projectKey = env.JIRA_TEST_PROJECT_KEY || first?.key
|
|
43
|
+
}
|
|
44
|
+
catch {}
|
|
45
|
+
|
|
46
|
+
try {
|
|
47
|
+
if (ctx.projectKey) {
|
|
48
|
+
const search_issues = jira.read('search_issues')
|
|
49
|
+
const issuesResp = await search_issues({
|
|
50
|
+
jql: `project = ${ctx.projectKey} ORDER BY updated DESC`,
|
|
51
|
+
fields: ['summary', 'updated'],
|
|
52
|
+
maxResults: 1,
|
|
53
|
+
})
|
|
54
|
+
const firstIssue = issuesResp?.issues?.[0]
|
|
55
|
+
ctx.issueKey = firstIssue?.key
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
catch {}
|
|
59
|
+
|
|
60
|
+
try {
|
|
61
|
+
const list_boards = jira.read('list_boards')
|
|
62
|
+
const boardsResp = await list_boards({ maxResults: 5 })
|
|
63
|
+
const firstBoard = boardsResp?.boards?.[0]
|
|
64
|
+
ctx.boardId = typeof firstBoard?.id === 'number' ? firstBoard.id : undefined
|
|
65
|
+
}
|
|
66
|
+
catch {}
|
|
67
|
+
|
|
68
|
+
try {
|
|
69
|
+
if (ctx.boardId) {
|
|
70
|
+
const list_sprints = jira.read('list_sprints')
|
|
71
|
+
const sprintsResp = await list_sprints({ boardId: ctx.boardId, maxResults: 5 })
|
|
72
|
+
const firstSprint = sprintsResp?.sprints?.[0]
|
|
73
|
+
ctx.sprintId = typeof firstSprint?.id === 'number' ? firstSprint.id : undefined
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
catch {}
|
|
77
|
+
}, 60000)
|
|
78
|
+
|
|
79
|
+
it('get_myself returns authenticated user', async () => {
|
|
80
|
+
const get_myself = jira.read('get_myself')
|
|
81
|
+
const me = await get_myself({})
|
|
82
|
+
expect(me?.accountId).toBeTruthy()
|
|
83
|
+
}, 30000)
|
|
84
|
+
|
|
85
|
+
it('list_projects returns projects', async () => {
|
|
86
|
+
const list_projects = jira.read('list_projects')
|
|
87
|
+
const res = await list_projects({ maxResults: 5 })
|
|
88
|
+
expect(res?.projects).toBeTruthy()
|
|
89
|
+
expect(Array.isArray(res.projects)).toBe(true)
|
|
90
|
+
}, 30000)
|
|
91
|
+
|
|
92
|
+
it('get_project returns issueTypes when available', async () => {
|
|
93
|
+
if (!ctx.projectKey)
|
|
94
|
+
return expect(true).toBe(true)
|
|
95
|
+
const get_project = jira.read('get_project')
|
|
96
|
+
const project = await get_project({ projectIdOrKey: ctx.projectKey, expandIssueTypes: true })
|
|
97
|
+
expect(project?.key?.toUpperCase?.()).toBe(ctx.projectKey.toUpperCase())
|
|
98
|
+
expect(Array.isArray(project?.issueTypes)).toBe(true)
|
|
99
|
+
}, 30000)
|
|
100
|
+
|
|
101
|
+
it('search_issues returns issue list (best effort)', async () => {
|
|
102
|
+
if (!ctx.projectKey)
|
|
103
|
+
return expect(true).toBe(true)
|
|
104
|
+
const search_issues = jira.read('search_issues')
|
|
105
|
+
const res = await search_issues({ jql: `project = ${ctx.projectKey} ORDER BY updated DESC`, maxResults: 5 })
|
|
106
|
+
expect(res?.issues).toBeTruthy()
|
|
107
|
+
expect(Array.isArray(res.issues)).toBe(true)
|
|
108
|
+
}, 30000)
|
|
109
|
+
|
|
110
|
+
it('get_issue returns issue details (if any issue key discovered)', async () => {
|
|
111
|
+
if (!ctx.issueKey)
|
|
112
|
+
return expect(true).toBe(true)
|
|
113
|
+
const get_issue = jira.read('get_issue')
|
|
114
|
+
const issue = await get_issue({ issueIdOrKey: ctx.issueKey })
|
|
115
|
+
expect(issue?.key).toBe(ctx.issueKey)
|
|
116
|
+
}, 30000)
|
|
117
|
+
|
|
118
|
+
it('get_issue_comments returns comments (if any issue key discovered)', async () => {
|
|
119
|
+
if (!ctx.issueKey)
|
|
120
|
+
return expect(true).toBe(true)
|
|
121
|
+
const get_issue_comments = jira.read('get_issue_comments')
|
|
122
|
+
const comments = await get_issue_comments({ issueIdOrKey: ctx.issueKey, maxResults: 5 })
|
|
123
|
+
expect(comments?.comments).toBeTruthy()
|
|
124
|
+
expect(Array.isArray(comments.comments)).toBe(true)
|
|
125
|
+
}, 30000)
|
|
126
|
+
|
|
127
|
+
it('get_transitions returns transitions (if any issue key discovered)', async () => {
|
|
128
|
+
if (!ctx.issueKey)
|
|
129
|
+
return expect(true).toBe(true)
|
|
130
|
+
const get_transitions = jira.read('get_transitions')
|
|
131
|
+
const res = await get_transitions({ issueIdOrKey: ctx.issueKey })
|
|
132
|
+
expect(Array.isArray(res?.transitions)).toBe(true)
|
|
133
|
+
}, 30000)
|
|
134
|
+
|
|
135
|
+
it('search_users returns users (best effort)', async () => {
|
|
136
|
+
const get_myself = jira.read('get_myself')
|
|
137
|
+
const me = await get_myself({})
|
|
138
|
+
const query = me?.displayName || 'a'
|
|
139
|
+
const search_users = jira.read('search_users')
|
|
140
|
+
const res = await search_users({ query, maxResults: 5 })
|
|
141
|
+
expect(Array.isArray(res?.users)).toBe(true)
|
|
142
|
+
}, 30000)
|
|
143
|
+
|
|
144
|
+
it('boards: list_boards works (best effort)', async () => {
|
|
145
|
+
const list_boards = jira.read('list_boards')
|
|
146
|
+
const res = await list_boards({ maxResults: 5 })
|
|
147
|
+
expect(res?.boards).toBeTruthy()
|
|
148
|
+
expect(Array.isArray(res.boards)).toBe(true)
|
|
149
|
+
}, 30000)
|
|
150
|
+
|
|
151
|
+
it('boards: get_board works when boardId is available', async () => {
|
|
152
|
+
if (!ctx.boardId)
|
|
153
|
+
return expect(true).toBe(true)
|
|
154
|
+
const get_board = jira.read('get_board')
|
|
155
|
+
const board = await get_board({ boardId: ctx.boardId })
|
|
156
|
+
expect(board?.id).toBe(ctx.boardId)
|
|
157
|
+
}, 30000)
|
|
158
|
+
|
|
159
|
+
it('boards: list_sprints works when boardId is available', async () => {
|
|
160
|
+
if (!ctx.boardId)
|
|
161
|
+
return expect(true).toBe(true)
|
|
162
|
+
const list_sprints = jira.read('list_sprints')
|
|
163
|
+
const res = await list_sprints({ boardId: ctx.boardId, maxResults: 5 })
|
|
164
|
+
expect(res?.sprints).toBeTruthy()
|
|
165
|
+
expect(Array.isArray(res.sprints)).toBe(true)
|
|
166
|
+
}, 30000)
|
|
167
|
+
|
|
168
|
+
it('boards: get_sprint works when sprintId is available', async () => {
|
|
169
|
+
if (!ctx.sprintId)
|
|
170
|
+
return expect(true).toBe(true)
|
|
171
|
+
const get_sprint = jira.read('get_sprint')
|
|
172
|
+
const sprint = await get_sprint({ sprintId: ctx.sprintId })
|
|
173
|
+
expect(sprint?.id).toBe(ctx.sprintId)
|
|
174
|
+
}, 30000)
|
|
175
|
+
|
|
176
|
+
it('boards: get_sprint_issues works when sprintId is available', async () => {
|
|
177
|
+
if (!ctx.sprintId)
|
|
178
|
+
return expect(true).toBe(true)
|
|
179
|
+
const get_sprint_issues = jira.read('get_sprint_issues')
|
|
180
|
+
const res = await get_sprint_issues({ sprintId: ctx.sprintId, maxResults: 5 })
|
|
181
|
+
expect(res).toBeTruthy()
|
|
182
|
+
}, 30000)
|
|
183
|
+
|
|
184
|
+
it('boards: get_backlog_issues works when boardId is available', async () => {
|
|
185
|
+
if (!ctx.boardId)
|
|
186
|
+
return expect(true).toBe(true)
|
|
187
|
+
const get_backlog_issues = jira.read('get_backlog_issues')
|
|
188
|
+
const res = await get_backlog_issues({ boardId: ctx.boardId, maxResults: 5 })
|
|
189
|
+
expect(res).toBeTruthy()
|
|
190
|
+
}, 30000)
|
|
191
|
+
})
|
|
192
|
+
})
|
|
193
|
+
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest'
|
|
2
|
+
import { getMissingToolUsages } from '../../__tests__/usageParity.js'
|
|
3
|
+
|
|
4
|
+
describe('jira static usage parity', () => {
|
|
5
|
+
it('every api_token tool is referenced in tests', () => {
|
|
6
|
+
const missing = getMissingToolUsages({
|
|
7
|
+
integrationName: 'jira',
|
|
8
|
+
importMetaUrl: import.meta.url,
|
|
9
|
+
credentialVariant: 'api_token',
|
|
10
|
+
})
|
|
11
|
+
expect(missing, `Missing handler usages in tests: ${missing.join(', ')}`).toEqual([])
|
|
12
|
+
})
|
|
13
|
+
})
|
|
14
|
+
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
import { afterAll, beforeAll, describe, expect, it } from 'vitest'
|
|
2
|
+
import { createCredentialStore, createIntegrationNode, createProxy, createToolbox, hasEnv, safeCleanup } from '../../__tests__/liveHarness.js'
|
|
3
|
+
|
|
4
|
+
// LIVE Jira write tests using credentials
|
|
5
|
+
//
|
|
6
|
+
// Required for write tests:
|
|
7
|
+
// - JIRA_TEST_PROJECT_KEY
|
|
8
|
+
//
|
|
9
|
+
// Variant: api_token
|
|
10
|
+
// - JIRA_DOMAIN
|
|
11
|
+
// - JIRA_EMAIL
|
|
12
|
+
// - JIRA_API_TOKEN
|
|
13
|
+
//
|
|
14
|
+
// Optional:
|
|
15
|
+
// - JIRA_TEST_TRANSITION_NAME (enables transition_issue)
|
|
16
|
+
// - JIRA_TEST_BOARD_ID (enables sprint roundtrip: create_sprint -> update_sprint -> move_issues_to_sprint -> update_sprint)
|
|
17
|
+
|
|
18
|
+
const env = process.env as Record<string, string | undefined>
|
|
19
|
+
|
|
20
|
+
const suiteOrSkip = (hasEnv('JIRA_DOMAIN', 'JIRA_EMAIL', 'JIRA_API_TOKEN') && hasEnv('JIRA_TEST_PROJECT_KEY'))
|
|
21
|
+
? describe
|
|
22
|
+
: describe.skip
|
|
23
|
+
|
|
24
|
+
suiteOrSkip('jira write handlers (live)', () => {
|
|
25
|
+
describe('variant: api_token', () => {
|
|
26
|
+
const ctx: {
|
|
27
|
+
createdIssueKey?: string
|
|
28
|
+
createdSprintId?: number
|
|
29
|
+
} = {}
|
|
30
|
+
|
|
31
|
+
let jira: ReturnType<typeof createToolbox>
|
|
32
|
+
|
|
33
|
+
beforeAll(async () => {
|
|
34
|
+
const credentialStore = createCredentialStore(async () => ({
|
|
35
|
+
domain: env.JIRA_DOMAIN!,
|
|
36
|
+
email: env.JIRA_EMAIL!,
|
|
37
|
+
apiToken: env.JIRA_API_TOKEN!,
|
|
38
|
+
}))
|
|
39
|
+
const proxy = createProxy(credentialStore)
|
|
40
|
+
jira = createToolbox('jira', proxy, createIntegrationNode('jira', { label: 'Jira', credentialId: 'jira-creds', credentialVariant: 'api_token' }), 'api_token')
|
|
41
|
+
}, 60000)
|
|
42
|
+
|
|
43
|
+
afterAll(async () => {
|
|
44
|
+
await safeCleanup(async () => {
|
|
45
|
+
if (!ctx.createdSprintId)
|
|
46
|
+
return
|
|
47
|
+
const update_sprint = jira.write('update_sprint')
|
|
48
|
+
await update_sprint({ sprintId: ctx.createdSprintId, state: 'closed' })
|
|
49
|
+
})
|
|
50
|
+
await safeCleanup(async () => {
|
|
51
|
+
if (!ctx.createdIssueKey)
|
|
52
|
+
return
|
|
53
|
+
const delete_issue = jira.write('delete_issue')
|
|
54
|
+
await delete_issue({ issueIdOrKey: ctx.createdIssueKey })
|
|
55
|
+
})
|
|
56
|
+
}, 60000)
|
|
57
|
+
|
|
58
|
+
it('create_issue -> get_issue -> update_issue -> add_comment -> get_issue_comments (and optional assign/transition) roundtrip', async () => {
|
|
59
|
+
const get_myself = jira.read('get_myself')
|
|
60
|
+
const me = await get_myself({})
|
|
61
|
+
expect(me?.accountId).toBeTruthy()
|
|
62
|
+
|
|
63
|
+
const get_project = jira.read('get_project')
|
|
64
|
+
const project = await get_project({ projectIdOrKey: env.JIRA_TEST_PROJECT_KEY, expandIssueTypes: true })
|
|
65
|
+
const issueTypes = Array.isArray(project?.issueTypes) ? project.issueTypes : []
|
|
66
|
+
const picked = issueTypes.find((t: any) => t && t.subtask === false) || issueTypes[0]
|
|
67
|
+
if (!picked?.id && !picked?.name)
|
|
68
|
+
return expect(true).toBe(true)
|
|
69
|
+
|
|
70
|
+
const create_issue = jira.write('create_issue')
|
|
71
|
+
const created = await create_issue({
|
|
72
|
+
projectKey: env.JIRA_TEST_PROJECT_KEY,
|
|
73
|
+
issueTypeId: picked?.id || undefined,
|
|
74
|
+
issueTypeName: picked?.id ? undefined : (picked?.name || undefined),
|
|
75
|
+
summary: `CmdTest ${Date.now()}`,
|
|
76
|
+
descriptionText: 'Created by integration tests.',
|
|
77
|
+
assigneeAccountId: me.accountId,
|
|
78
|
+
labels: ['cmdtest'],
|
|
79
|
+
})
|
|
80
|
+
const issueKey = created?.key || created?.id
|
|
81
|
+
expect(issueKey).toBeTruthy()
|
|
82
|
+
ctx.createdIssueKey = created?.key || created?.id
|
|
83
|
+
|
|
84
|
+
const get_issue = jira.read('get_issue')
|
|
85
|
+
const got = await get_issue({ issueIdOrKey: issueKey })
|
|
86
|
+
expect(got?.key).toBeTruthy()
|
|
87
|
+
|
|
88
|
+
const update_issue = jira.write('update_issue')
|
|
89
|
+
const updated = await update_issue({
|
|
90
|
+
issueIdOrKey: issueKey,
|
|
91
|
+
summary: `CmdTest Updated ${Date.now()}`,
|
|
92
|
+
descriptionText: 'Updated by integration tests.',
|
|
93
|
+
})
|
|
94
|
+
expect(updated?.success === true || updated).toBeTruthy()
|
|
95
|
+
|
|
96
|
+
const add_comment = jira.write('add_comment')
|
|
97
|
+
const commentText = `Test comment ${Date.now()}`
|
|
98
|
+
const comment = await add_comment({ issueIdOrKey: issueKey, bodyText: commentText })
|
|
99
|
+
expect(comment?.id).toBeTruthy()
|
|
100
|
+
|
|
101
|
+
const get_issue_comments = jira.read('get_issue_comments')
|
|
102
|
+
const comments = await get_issue_comments({ issueIdOrKey: issueKey, maxResults: 20 })
|
|
103
|
+
const found = (comments?.comments || []).some((c: any) =>
|
|
104
|
+
(c?.bodyMarkdown && String(c.bodyMarkdown).includes('Test comment'))
|
|
105
|
+
|| (c?.bodyText && String(c.bodyText).includes('Test comment')),
|
|
106
|
+
)
|
|
107
|
+
expect(found).toBe(true)
|
|
108
|
+
|
|
109
|
+
const assign_issue = jira.write('assign_issue')
|
|
110
|
+
const assigned = await assign_issue({ issueIdOrKey: issueKey, accountId: me.accountId })
|
|
111
|
+
expect(assigned?.success === true || assigned).toBeTruthy()
|
|
112
|
+
const unassigned = await assign_issue({ issueIdOrKey: issueKey, accountId: null })
|
|
113
|
+
expect(unassigned?.success === true || unassigned).toBeTruthy()
|
|
114
|
+
|
|
115
|
+
if (env.JIRA_TEST_TRANSITION_NAME) {
|
|
116
|
+
const transition_issue = jira.write('transition_issue')
|
|
117
|
+
const transitioned = await transition_issue({
|
|
118
|
+
issueIdOrKey: issueKey,
|
|
119
|
+
transitionName: env.JIRA_TEST_TRANSITION_NAME,
|
|
120
|
+
commentText: 'Transitioned by integration tests.',
|
|
121
|
+
})
|
|
122
|
+
expect(transitioned?.success === true || transitioned).toBeTruthy()
|
|
123
|
+
}
|
|
124
|
+
}, 120000)
|
|
125
|
+
|
|
126
|
+
it('sprint roundtrip: create_sprint -> update_sprint (start) -> move_issues_to_sprint -> update_sprint (close) (optional)', async () => {
|
|
127
|
+
if (!env.JIRA_TEST_BOARD_ID || !ctx.createdIssueKey)
|
|
128
|
+
return expect(true).toBe(true)
|
|
129
|
+
const boardId = Number(env.JIRA_TEST_BOARD_ID)
|
|
130
|
+
if (!Number.isFinite(boardId))
|
|
131
|
+
return expect(true).toBe(true)
|
|
132
|
+
|
|
133
|
+
const create_sprint = jira.write('create_sprint')
|
|
134
|
+
const name = `CmdTest Sprint ${Date.now()}`
|
|
135
|
+
const sprint = await create_sprint({ boardId, name })
|
|
136
|
+
const sprintId = sprint?.id
|
|
137
|
+
expect(typeof sprintId).toBe('number')
|
|
138
|
+
ctx.createdSprintId = sprintId
|
|
139
|
+
|
|
140
|
+
const update_sprint = jira.write('update_sprint')
|
|
141
|
+
const today = new Date().toISOString().slice(0, 10)
|
|
142
|
+
const twoWeeks = new Date(Date.now() + 14 * 24 * 60 * 60 * 1000).toISOString().slice(0, 10)
|
|
143
|
+
const started = await update_sprint({ sprintId, state: 'active', startDate: today, endDate: twoWeeks })
|
|
144
|
+
expect(started?.state === 'active' || started?.id === sprintId || started).toBeTruthy()
|
|
145
|
+
|
|
146
|
+
const move_issues_to_sprint = jira.write('move_issues_to_sprint')
|
|
147
|
+
const moved = await move_issues_to_sprint({ sprintId, issueKeys: [ctx.createdIssueKey] })
|
|
148
|
+
expect(moved?.success === true || moved).toBeTruthy()
|
|
149
|
+
|
|
150
|
+
const closed = await update_sprint({ sprintId, state: 'closed' })
|
|
151
|
+
expect(closed?.state === 'closed' || closed?.id === sprintId || closed).toBeTruthy()
|
|
152
|
+
ctx.createdSprintId = undefined
|
|
153
|
+
}, 120000)
|
|
154
|
+
|
|
155
|
+
})
|
|
156
|
+
})
|
|
157
|
+
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
{
|
|
2
|
+
"variants": {
|
|
3
|
+
"api_token": {
|
|
4
|
+
"label": "API Token (Email + Token)",
|
|
5
|
+
"schema": {
|
|
6
|
+
"type": "object",
|
|
7
|
+
"properties": {
|
|
8
|
+
"domain": {
|
|
9
|
+
"type": "string",
|
|
10
|
+
"title": "Jira site domain",
|
|
11
|
+
"description": "The subdomain of your Jira Cloud site. Example: for https://mycompany.atlassian.net, enter 'mycompany'."
|
|
12
|
+
},
|
|
13
|
+
"email": {
|
|
14
|
+
"type": "string",
|
|
15
|
+
"title": "Atlassian account email",
|
|
16
|
+
"description": "Email address of the Atlassian account that owns the API token."
|
|
17
|
+
},
|
|
18
|
+
"apiToken": {
|
|
19
|
+
"type": "string",
|
|
20
|
+
"title": "Atlassian API token",
|
|
21
|
+
"description": "Atlassian API token for Jira Cloud. Combined with your email to form the Basic auth header."
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
"required": ["domain", "email", "apiToken"],
|
|
25
|
+
"additionalProperties": false
|
|
26
|
+
},
|
|
27
|
+
"baseUrlTemplate": "https://{{domain}}.atlassian.net",
|
|
28
|
+
"injection": {
|
|
29
|
+
"headers": {
|
|
30
|
+
"Authorization": "Basic {{base64(email + \":\" + apiToken)}}",
|
|
31
|
+
"Accept": "application/json"
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
"healthCheck": { "path": "/rest/api/3/myself" }
|
|
35
|
+
}
|
|
36
|
+
},
|
|
37
|
+
"default": "api_token"
|
|
38
|
+
}
|
|
39
|
+
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
1. Open your Jira Cloud site in the browser (it looks like `https://YOUR_DOMAIN.atlassian.net`).
|
|
2
|
+
2. Copy `YOUR_DOMAIN` (the subdomain) and use it as `domain`.
|
|
3
|
+
3. Create an Atlassian API token at `https://id.atlassian.com/manage-profile/security/api-tokens`.
|
|
4
|
+
4. Use the same Atlassian account email as `email` and paste the token as `apiToken`.
|
|
5
|
+
5. Ensure the Atlassian account has access to the Jira projects you want to work with.
|
|
6
|
+
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
1. Create an OAuth 2.0 (3LO) app in the Atlassian developer console.
|
|
2
|
+
2. Add Jira scopes (typical minimum): `read:jira-work`, `write:jira-work`, `read:jira-user` (and `offline_access` if you want refresh tokens).
|
|
3
|
+
3. Complete the OAuth flow to obtain an access token.
|
|
4
|
+
4. Discover your `cloudId` by calling `GET https://api.atlassian.com/oauth/token/accessible-resources` with `Authorization: Bearer <access_token>` and using the returned `id`.
|
|
5
|
+
5. Paste `cloudId` and the current OAuth `token` here.
|
|
6
|
+
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
async (input) => {
|
|
2
|
+
const res = await integration.fetch(`/rest/api/3/issue/${encodeURIComponent(input.issueIdOrKey)}/assignee`, {
|
|
3
|
+
method: 'PUT',
|
|
4
|
+
body: { accountId: input.accountId },
|
|
5
|
+
})
|
|
6
|
+
|
|
7
|
+
if (res.status === 204)
|
|
8
|
+
return { success: true }
|
|
9
|
+
return await res.json()
|
|
10
|
+
}
|
|
11
|
+
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
async (input) => {
|
|
2
|
+
const fields = {
|
|
3
|
+
project: { key: input.projectKey },
|
|
4
|
+
summary: input.summary,
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
if (input.descriptionText)
|
|
8
|
+
fields.description = utils.adf?.fromMarkdown(input.descriptionText)
|
|
9
|
+
|
|
10
|
+
if (input.issueTypeId) {
|
|
11
|
+
fields.issuetype = { id: String(input.issueTypeId) }
|
|
12
|
+
}
|
|
13
|
+
else if (input.issueTypeName) {
|
|
14
|
+
fields.issuetype = { name: String(input.issueTypeName) }
|
|
15
|
+
}
|
|
16
|
+
else {
|
|
17
|
+
throw new Error(`Missing issue type. Provide issueTypeId or issueTypeName (call get_project to discover available issue types).`)
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
if (input.priorityId)
|
|
21
|
+
fields.priority = { id: input.priorityId }
|
|
22
|
+
else if (input.priorityName)
|
|
23
|
+
fields.priority = { name: input.priorityName }
|
|
24
|
+
|
|
25
|
+
if (Array.isArray(input.labels))
|
|
26
|
+
fields.labels = input.labels
|
|
27
|
+
|
|
28
|
+
if (input.assigneeAccountId)
|
|
29
|
+
fields.assignee = { accountId: input.assigneeAccountId }
|
|
30
|
+
|
|
31
|
+
const res = await integration.fetch('/rest/api/3/issue', {
|
|
32
|
+
method: 'POST',
|
|
33
|
+
body: { fields },
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
return await res.json()
|
|
37
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
async (input) => {
|
|
2
|
+
const body = {
|
|
3
|
+
originBoardId: input.boardId,
|
|
4
|
+
name: input.name,
|
|
5
|
+
}
|
|
6
|
+
if (input.startDate)
|
|
7
|
+
body.startDate = input.startDate
|
|
8
|
+
if (input.endDate)
|
|
9
|
+
body.endDate = input.endDate
|
|
10
|
+
if (input.goal)
|
|
11
|
+
body.goal = input.goal
|
|
12
|
+
|
|
13
|
+
const res = await integration.fetch('/rest/agile/1.0/sprint', {
|
|
14
|
+
method: 'POST',
|
|
15
|
+
body,
|
|
16
|
+
})
|
|
17
|
+
return await res.json()
|
|
18
|
+
}
|
|
19
|
+
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
async (input) => {
|
|
2
|
+
const params = new URLSearchParams()
|
|
3
|
+
if (input.jql)
|
|
4
|
+
params.set('jql', input.jql)
|
|
5
|
+
if (Array.isArray(input.fields) && input.fields.length)
|
|
6
|
+
params.set('fields', input.fields.join(','))
|
|
7
|
+
params.set('startAt', String(input.startAt ?? 0))
|
|
8
|
+
params.set('maxResults', String(input.maxResults ?? 50))
|
|
9
|
+
|
|
10
|
+
const res = await integration.fetch(`/rest/agile/1.0/board/${encodeURIComponent(String(input.boardId))}/backlog?${params.toString()}`)
|
|
11
|
+
return await res.json()
|
|
12
|
+
}
|
|
13
|
+
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
async (input) => {
|
|
2
|
+
const defaultFields = [
|
|
3
|
+
'summary',
|
|
4
|
+
'status',
|
|
5
|
+
'assignee',
|
|
6
|
+
'priority',
|
|
7
|
+
'issuetype',
|
|
8
|
+
'project',
|
|
9
|
+
'description',
|
|
10
|
+
'created',
|
|
11
|
+
'updated',
|
|
12
|
+
'labels',
|
|
13
|
+
]
|
|
14
|
+
|
|
15
|
+
const fields = Array.isArray(input.fields) && input.fields.length ? input.fields : defaultFields
|
|
16
|
+
const params = new URLSearchParams()
|
|
17
|
+
if (fields?.length)
|
|
18
|
+
params.set('fields', fields.join(','))
|
|
19
|
+
if (Array.isArray(input.expand) && input.expand.length)
|
|
20
|
+
params.set('expand', input.expand.join(','))
|
|
21
|
+
|
|
22
|
+
const path = `/rest/api/3/issue/${encodeURIComponent(input.issueIdOrKey)}${params.toString() ? `?${params.toString()}` : ''}`
|
|
23
|
+
const res = await integration.fetch(path)
|
|
24
|
+
const data = await res.json()
|
|
25
|
+
|
|
26
|
+
const descAdf = data?.fields?.description
|
|
27
|
+
const descMarkdown = utils.adf?.toMarkdown(descAdf) || ''
|
|
28
|
+
const descText = descMarkdown ? '' : (utils.adf?.toPlainText(descAdf) || '')
|
|
29
|
+
|
|
30
|
+
return {
|
|
31
|
+
id: data.id ?? null,
|
|
32
|
+
key: data.key ?? null,
|
|
33
|
+
self: data.self ?? null,
|
|
34
|
+
summary: data.fields?.summary ?? null,
|
|
35
|
+
status: data.fields?.status
|
|
36
|
+
? {
|
|
37
|
+
id: data.fields.status.id ?? null,
|
|
38
|
+
name: data.fields.status.name ?? null,
|
|
39
|
+
category: data.fields.status.statusCategory
|
|
40
|
+
? {
|
|
41
|
+
key: data.fields.status.statusCategory.key ?? null,
|
|
42
|
+
name: data.fields.status.statusCategory.name ?? null,
|
|
43
|
+
}
|
|
44
|
+
: null,
|
|
45
|
+
}
|
|
46
|
+
: null,
|
|
47
|
+
assignee: data.fields?.assignee
|
|
48
|
+
? {
|
|
49
|
+
accountId: data.fields.assignee.accountId ?? null,
|
|
50
|
+
displayName: data.fields.assignee.displayName ?? null,
|
|
51
|
+
}
|
|
52
|
+
: null,
|
|
53
|
+
priority: data.fields?.priority ? { id: data.fields.priority.id ?? null, name: data.fields.priority.name ?? null } : null,
|
|
54
|
+
issueType: data.fields?.issuetype ? { id: data.fields.issuetype.id ?? null, name: data.fields.issuetype.name ?? null } : null,
|
|
55
|
+
project: data.fields?.project ? { id: data.fields.project.id ?? null, key: data.fields.project.key ?? null, name: data.fields.project.name ?? null } : null,
|
|
56
|
+
labels: Array.isArray(data.fields?.labels) ? data.fields.labels : [],
|
|
57
|
+
descriptionMarkdown: descMarkdown || null,
|
|
58
|
+
descriptionText: descMarkdown ? null : (descText || null),
|
|
59
|
+
created: data.fields?.created ?? null,
|
|
60
|
+
updated: data.fields?.updated ?? null,
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
async (input) => {
|
|
2
|
+
const params = new URLSearchParams()
|
|
3
|
+
params.set('startAt', String(input.startAt ?? 0))
|
|
4
|
+
params.set('maxResults', String(input.maxResults ?? 50))
|
|
5
|
+
|
|
6
|
+
const path = `/rest/api/3/issue/${encodeURIComponent(input.issueIdOrKey)}/comment?${params.toString()}`
|
|
7
|
+
const res = await integration.fetch(path)
|
|
8
|
+
const data = await res.json()
|
|
9
|
+
const comments = Array.isArray(data.comments) ? data.comments : []
|
|
10
|
+
|
|
11
|
+
return {
|
|
12
|
+
startAt: data.startAt ?? (input.startAt ?? 0),
|
|
13
|
+
maxResults: data.maxResults ?? (input.maxResults ?? 50),
|
|
14
|
+
total: data.total ?? comments.length,
|
|
15
|
+
comments: comments.map((c) => {
|
|
16
|
+
const md = utils.adf?.toMarkdown(c.body) || ''
|
|
17
|
+
const text = md ? '' : (utils.adf?.toPlainText(c.body) || '')
|
|
18
|
+
return {
|
|
19
|
+
id: c.id ?? null,
|
|
20
|
+
created: c.created ?? null,
|
|
21
|
+
updated: c.updated ?? null,
|
|
22
|
+
author: c.author
|
|
23
|
+
? { accountId: c.author.accountId ?? null, displayName: c.author.displayName ?? null }
|
|
24
|
+
: null,
|
|
25
|
+
bodyMarkdown: md || null,
|
|
26
|
+
bodyText: md ? null : (text || null),
|
|
27
|
+
}
|
|
28
|
+
}),
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
async (_input) => {
|
|
2
|
+
const res = await integration.fetch('/rest/api/3/myself')
|
|
3
|
+
const data = await res.json()
|
|
4
|
+
|
|
5
|
+
return {
|
|
6
|
+
accountId: data.accountId ?? null,
|
|
7
|
+
displayName: data.displayName ?? null,
|
|
8
|
+
active: data.active ?? null,
|
|
9
|
+
timeZone: data.timeZone ?? null,
|
|
10
|
+
locale: data.locale ?? null,
|
|
11
|
+
emailAddress: data.emailAddress ?? null,
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|