@commandable/integration-data 0.0.1 → 0.0.5
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 +4 -21
- package/dist/credentials-index.d.ts.map +1 -1
- package/dist/credentials-index.js +407 -215
- 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 +38 -2
- package/dist/loader.d.ts.map +1 -1
- package/dist/loader.js +70 -16
- package/dist/loader.js.map +1 -1
- package/integrations/__tests__/liveHarness.ts +84 -0
- package/integrations/__tests__/usageParity.ts +54 -0
- package/integrations/airtable/__tests__/get_handlers.test.ts +43 -31
- package/integrations/airtable/__tests__/usage_parity.test.ts +3 -29
- package/integrations/airtable/__tests__/write_and_admin_handlers.test.ts +20 -17
- package/integrations/airtable/credentials.json +21 -16
- package/integrations/github/__tests__/get_handlers.test.ts +101 -108
- package/integrations/github/__tests__/usage_parity.test.ts +15 -27
- package/integrations/github/__tests__/write_handlers.test.ts +223 -306
- package/integrations/github/credentials.json +40 -15
- package/integrations/github/credentials_hint_classic_pat.md +8 -0
- package/integrations/github/credentials_hint_fine_grained_pat.md +9 -0
- package/integrations/github/handlers/create_commit.js +2 -17
- package/integrations/github/manifest.json +2 -2
- package/integrations/google-calendar/__tests__/get_handlers.test.ts +21 -13
- package/integrations/google-calendar/__tests__/usage_parity.test.ts +3 -28
- package/integrations/google-calendar/__tests__/write_and_admin_handlers.test.ts +24 -17
- package/integrations/google-calendar/credentials.json +50 -29
- package/integrations/google-calendar/credentials_hint_oauth_token.md +8 -0
- package/integrations/google-calendar/credentials_hint_service_account.md +10 -0
- package/integrations/google-docs/__tests__/get_handlers.test.ts +87 -61
- package/integrations/google-docs/__tests__/usage_parity.test.ts +3 -28
- package/integrations/google-docs/__tests__/write_handlers.test.ts +251 -245
- package/integrations/google-docs/credentials.json +50 -29
- package/integrations/google-docs/credentials_hint_oauth_token.md +8 -0
- package/integrations/google-docs/credentials_hint_service_account.md +10 -0
- package/integrations/google-docs/handlers/insert_inline_image_after_first_match.js +1 -1
- package/integrations/google-docs/schemas/insert_inline_image_after_first_match.json +0 -1
- package/integrations/google-drive/__tests__/handlers.test.ts +102 -0
- package/integrations/google-drive/credentials.json +57 -0
- package/integrations/google-drive/credentials_hint_oauth_token.md +8 -0
- package/integrations/google-drive/credentials_hint_service_account.md +10 -0
- package/integrations/google-drive/handlers/create_file.js +15 -0
- package/integrations/google-drive/handlers/create_folder.js +15 -0
- package/integrations/google-drive/handlers/delete_file.js +14 -0
- package/integrations/google-drive/handlers/get_file.js +7 -0
- package/integrations/google-drive/handlers/move_file.js +12 -0
- package/integrations/google-drive/manifest.json +42 -0
- package/integrations/google-drive/schemas/create_file.json +12 -0
- package/integrations/google-drive/schemas/create_folder.json +11 -0
- package/integrations/google-drive/schemas/delete_file.json +10 -0
- package/integrations/google-drive/schemas/get_file.json +10 -0
- package/integrations/google-drive/schemas/move_file.json +12 -0
- package/integrations/google-sheet/__tests__/get_handlers.test.ts +48 -55
- package/integrations/google-sheet/__tests__/usage_parity.test.ts +3 -29
- package/integrations/google-sheet/__tests__/write_handlers.test.ts +65 -63
- package/integrations/google-sheet/credentials.json +50 -29
- package/integrations/google-sheet/credentials_hint_oauth_token.md +8 -0
- package/integrations/google-sheet/credentials_hint_service_account.md +10 -0
- package/integrations/google-slides/__tests__/get_handlers.test.ts +38 -36
- package/integrations/google-slides/__tests__/usage_parity.test.ts +3 -28
- package/integrations/google-slides/__tests__/write_handlers.test.ts +65 -59
- package/integrations/google-slides/credentials.json +50 -29
- package/integrations/google-slides/credentials_hint_oauth_token.md +8 -0
- package/integrations/google-slides/credentials_hint_service_account.md +10 -0
- package/integrations/notion/__tests__/get_handlers.test.ts +18 -15
- package/integrations/notion/__tests__/usage_parity.test.ts +3 -28
- package/integrations/notion/__tests__/write_and_admin_handlers.test.ts +56 -60
- package/integrations/notion/credentials.json +22 -17
- package/integrations/trello/__tests__/get_handlers.test.ts +58 -73
- package/integrations/trello/__tests__/usage_parity.test.ts +3 -28
- package/integrations/trello/__tests__/write_and_admin_handlers.test.ts +49 -67
- package/integrations/trello/credentials.json +26 -21
- package/integrations/trello/handlers/close_board.js +6 -0
- package/integrations/trello/handlers/create_board.js +11 -0
- package/integrations/trello/handlers/delete_board.js +13 -0
- package/integrations/trello/manifest.json +21 -0
- package/integrations/trello/schemas/close_board.json +10 -0
- package/integrations/trello/schemas/create_board.json +12 -0
- package/integrations/trello/schemas/delete_board.json +10 -0
- package/package.json +1 -1
|
@@ -1,311 +1,228 @@
|
|
|
1
1
|
import { beforeAll, describe, expect, it } from 'vitest'
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
//
|
|
6
|
-
//
|
|
7
|
-
// -
|
|
8
|
-
//
|
|
9
|
-
// -
|
|
10
|
-
// -
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
2
|
+
import { createCredentialStore, createIntegrationNode, createProxy, createToolbox, hasEnv } from '../../__tests__/liveHarness.js'
|
|
3
|
+
|
|
4
|
+
// LIVE GitHub write tests -- runs once per available credential variant.
|
|
5
|
+
// Required env vars (at least one):
|
|
6
|
+
// - GITHUB_CLASSIC_PAT (tests all write tools including create_repo/delete_repo)
|
|
7
|
+
// - GITHUB_FINE_GRAINED_PAT (tests write tools; create_repo/delete_repo are excluded for this variant)
|
|
8
|
+
// Plus:
|
|
9
|
+
// - GITHUB_TEST_OWNER
|
|
10
|
+
// - GITHUB_TEST_REPO
|
|
11
|
+
|
|
12
|
+
const env = process.env as Record<string, string | undefined>
|
|
13
|
+
|
|
14
|
+
interface VariantConfig {
|
|
15
|
+
key: string
|
|
16
|
+
token: string
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
-
const
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
)
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
path: `multi-test/file4-${timestamp}.txt`,
|
|
227
|
-
content: 'New file 4',
|
|
228
|
-
},
|
|
229
|
-
],
|
|
230
|
-
})
|
|
231
|
-
expect(commit2?.commit?.sha).toBeTruthy()
|
|
232
|
-
expect(commit2?.commit?.message).toBe(`Update and delete files ${timestamp}`)
|
|
233
|
-
}, 120000)
|
|
234
|
-
|
|
235
|
-
it('full PR workflow: create_branch -> create_commit -> create_pull_request -> merge_pull_request', async () => {
|
|
236
|
-
if (!ctx.owner || !ctx.repo)
|
|
237
|
-
return expect(true).toBe(true)
|
|
238
|
-
|
|
239
|
-
const timestamp = Date.now()
|
|
240
|
-
const branchName = `test-pr-workflow-${timestamp}`
|
|
241
|
-
|
|
242
|
-
// Create a new branch
|
|
243
|
-
const create_branch = buildWriteHandler('create_branch')
|
|
244
|
-
const branch = await create_branch({
|
|
245
|
-
owner: ctx.owner,
|
|
246
|
-
repo: ctx.repo,
|
|
247
|
-
branch: branchName,
|
|
248
|
-
})
|
|
249
|
-
expect(branch?.ref).toBe(`refs/heads/${branchName}`)
|
|
250
|
-
|
|
251
|
-
// Create multiple files using create_commit
|
|
252
|
-
const create_commit = buildWriteHandler('create_commit')
|
|
253
|
-
const commit = await create_commit({
|
|
254
|
-
owner: ctx.owner,
|
|
255
|
-
repo: ctx.repo,
|
|
256
|
-
branch: branchName,
|
|
257
|
-
message: `Add feature files ${timestamp}`,
|
|
258
|
-
files: [
|
|
259
|
-
{
|
|
260
|
-
path: `feature-${timestamp}/index.js`,
|
|
261
|
-
content: 'export default function() { return "Hello"; }',
|
|
262
|
-
},
|
|
263
|
-
{
|
|
264
|
-
path: `feature-${timestamp}/README.md`,
|
|
265
|
-
content: `# Feature ${timestamp}\n\nThis is a test feature.`,
|
|
266
|
-
},
|
|
267
|
-
],
|
|
268
|
-
})
|
|
269
|
-
expect(commit?.commit?.sha).toBeTruthy()
|
|
270
|
-
|
|
271
|
-
// Create a pull request
|
|
272
|
-
const create_pull_request = buildWriteHandler('create_pull_request')
|
|
273
|
-
const get_repo = buildReadHandler('get_repo')
|
|
274
|
-
const repoDetails = await get_repo({ owner: ctx.owner, repo: ctx.repo })
|
|
275
|
-
const defaultBranch = repoDetails?.default_branch || 'main'
|
|
276
|
-
const pr = await create_pull_request({
|
|
277
|
-
owner: ctx.owner,
|
|
278
|
-
repo: ctx.repo,
|
|
279
|
-
title: `Test PR workflow ${timestamp}`,
|
|
280
|
-
body: 'This PR was created by integration tests to test the full workflow',
|
|
281
|
-
head: branchName,
|
|
282
|
-
base: defaultBranch,
|
|
283
|
-
})
|
|
284
|
-
expect(pr?.number).toBeTruthy()
|
|
285
|
-
const prNumber = pr.number
|
|
286
|
-
|
|
287
|
-
// Add labels to the PR
|
|
288
|
-
const add_labels_to_issue = buildWriteHandler('add_labels_to_issue')
|
|
289
|
-
try {
|
|
290
|
-
await add_labels_to_issue({
|
|
291
|
-
owner: ctx.owner,
|
|
292
|
-
repo: ctx.repo,
|
|
293
|
-
issue_number: prNumber,
|
|
294
|
-
labels: ['test'],
|
|
295
|
-
})
|
|
296
|
-
} catch (e) {
|
|
297
|
-
// Label might not exist, that's ok for this test
|
|
298
|
-
console.log('Label add skipped (label may not exist)')
|
|
299
|
-
}
|
|
300
|
-
|
|
301
|
-
// Merge the pull request
|
|
302
|
-
const merge_pull_request = buildWriteHandler('merge_pull_request')
|
|
303
|
-
const merged = await merge_pull_request({
|
|
304
|
-
owner: ctx.owner,
|
|
305
|
-
repo: ctx.repo,
|
|
306
|
-
pull_number: prNumber,
|
|
307
|
-
merge_method: 'squash',
|
|
19
|
+
const variants: VariantConfig[] = [
|
|
20
|
+
{ key: 'classic_pat', token: env.GITHUB_CLASSIC_PAT || '' },
|
|
21
|
+
{ key: 'fine_grained_pat', token: env.GITHUB_FINE_GRAINED_PAT || '' },
|
|
22
|
+
].filter(v => v.token.trim().length > 0)
|
|
23
|
+
|
|
24
|
+
const hasWriteEnv = hasEnv('GITHUB_TEST_OWNER', 'GITHUB_TEST_REPO')
|
|
25
|
+
const suiteOrSkip = (variants.length > 0 && hasWriteEnv) ? describe : describe.skip
|
|
26
|
+
|
|
27
|
+
suiteOrSkip('github write handlers (live)', () => {
|
|
28
|
+
for (const variant of variants) {
|
|
29
|
+
describe(`variant: ${variant.key}`, () => {
|
|
30
|
+
const ctx = {
|
|
31
|
+
owner: env.GITHUB_TEST_OWNER,
|
|
32
|
+
repo: env.GITHUB_TEST_REPO,
|
|
33
|
+
}
|
|
34
|
+
let toolbox: ReturnType<typeof createToolbox>
|
|
35
|
+
|
|
36
|
+
beforeAll(async () => {
|
|
37
|
+
const credentialStore = createCredentialStore(async () => ({ token: variant.token }))
|
|
38
|
+
const proxy = createProxy(credentialStore)
|
|
39
|
+
const node = createIntegrationNode('github', { credentialVariant: variant.key })
|
|
40
|
+
toolbox = createToolbox('github', proxy, node, variant.key)
|
|
41
|
+
}, 30000)
|
|
42
|
+
|
|
43
|
+
it('create_issue -> update_issue -> comment_on_issue -> close_issue roundtrip', async () => {
|
|
44
|
+
if (!ctx.owner || !ctx.repo)
|
|
45
|
+
return expect(true).toBe(true)
|
|
46
|
+
|
|
47
|
+
const titleBase = `CmdTest Issue ${Date.now()}`
|
|
48
|
+
|
|
49
|
+
const create_issue = toolbox.write('create_issue')
|
|
50
|
+
const created = await create_issue({ owner: ctx.owner, repo: ctx.repo, title: titleBase, body: 'Initial body from test.' })
|
|
51
|
+
expect(created?.number).toBeTruthy()
|
|
52
|
+
const issue_number = created.number
|
|
53
|
+
|
|
54
|
+
const update_issue = toolbox.write('update_issue')
|
|
55
|
+
const updated = await update_issue({ owner: ctx.owner, repo: ctx.repo, issue_number, body: 'Updated body from test.' })
|
|
56
|
+
expect(updated?.number).toBe(issue_number)
|
|
57
|
+
|
|
58
|
+
const comment_on_issue = toolbox.write('comment_on_issue')
|
|
59
|
+
const comment = await comment_on_issue({ owner: ctx.owner, repo: ctx.repo, issue_number, body: 'A comment from test.' })
|
|
60
|
+
expect(comment?.id).toBeTruthy()
|
|
61
|
+
|
|
62
|
+
const close_issue = toolbox.write('close_issue')
|
|
63
|
+
const closed = await close_issue({ owner: ctx.owner, repo: ctx.repo, issue_number })
|
|
64
|
+
expect(closed?.state).toBe('closed')
|
|
65
|
+
}, 90000)
|
|
66
|
+
|
|
67
|
+
it('create_repo -> delete_repo lifecycle (classic_pat only)', async () => {
|
|
68
|
+
if (!toolbox.hasTool('write', 'create_repo')) {
|
|
69
|
+
return expect(true).toBe(true)
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const repoName = `cmdtest-repo-${Date.now()}`
|
|
73
|
+
|
|
74
|
+
const create_repo = toolbox.write('create_repo')
|
|
75
|
+
const created = await create_repo({
|
|
76
|
+
name: repoName,
|
|
77
|
+
description: 'Test repo created by integration tests',
|
|
78
|
+
private: true,
|
|
79
|
+
auto_init: true,
|
|
80
|
+
})
|
|
81
|
+
expect(created?.name).toBe(repoName)
|
|
82
|
+
|
|
83
|
+
// /user/repos creates under the authenticated user, not necessarily ctx.owner
|
|
84
|
+
const createdOwner = created?.owner?.login
|
|
85
|
+
expect(createdOwner).toBeTruthy()
|
|
86
|
+
expect(created?.full_name).toBe(`${createdOwner}/${repoName}`)
|
|
87
|
+
|
|
88
|
+
// GitHub needs a moment to finish provisioning the repo before it can be deleted
|
|
89
|
+
await new Promise(resolve => setTimeout(resolve, 3000))
|
|
90
|
+
|
|
91
|
+
const delete_repo = toolbox.write('delete_repo')
|
|
92
|
+
const deleted = await delete_repo({ owner: createdOwner, repo: repoName })
|
|
93
|
+
expect(deleted?.success).toBe(true)
|
|
94
|
+
expect(deleted?.status).toBe(204)
|
|
95
|
+
}, 90000)
|
|
96
|
+
|
|
97
|
+
it('create_or_update_file: single file commit', async () => {
|
|
98
|
+
if (!ctx.owner || !ctx.repo)
|
|
99
|
+
return expect(true).toBe(true)
|
|
100
|
+
|
|
101
|
+
const timestamp = Date.now()
|
|
102
|
+
const branchName = `test-single-file-${timestamp}`
|
|
103
|
+
|
|
104
|
+
const create_branch = toolbox.write('create_branch')
|
|
105
|
+
const branch = await create_branch({ owner: ctx.owner, repo: ctx.repo, branch: branchName })
|
|
106
|
+
expect(branch?.ref).toBe(`refs/heads/${branchName}`)
|
|
107
|
+
|
|
108
|
+
const create_or_update_file = toolbox.write('create_or_update_file')
|
|
109
|
+
const file = await create_or_update_file({
|
|
110
|
+
owner: ctx.owner,
|
|
111
|
+
repo: ctx.repo,
|
|
112
|
+
path: `test-single-${timestamp}.txt`,
|
|
113
|
+
message: `Add single test file ${timestamp}`,
|
|
114
|
+
content: `Test content with UTF-8: Hello 世界 🌍\nCreated at ${timestamp}`,
|
|
115
|
+
branch: branchName,
|
|
116
|
+
})
|
|
117
|
+
expect(file?.commit?.message).toBe(`Add single test file ${timestamp}`)
|
|
118
|
+
expect(file?.content?.path).toBe(`test-single-${timestamp}.txt`)
|
|
119
|
+
|
|
120
|
+
const updated = await create_or_update_file({
|
|
121
|
+
owner: ctx.owner,
|
|
122
|
+
repo: ctx.repo,
|
|
123
|
+
path: `test-single-${timestamp}.txt`,
|
|
124
|
+
message: `Update test file ${timestamp}`,
|
|
125
|
+
content: `Updated content at ${timestamp}`,
|
|
126
|
+
branch: branchName,
|
|
127
|
+
sha: file.content.sha,
|
|
128
|
+
})
|
|
129
|
+
expect(updated?.commit?.message).toBe(`Update test file ${timestamp}`)
|
|
130
|
+
}, 90000)
|
|
131
|
+
|
|
132
|
+
it('create_commit: multiple files in one commit', async () => {
|
|
133
|
+
if (!ctx.owner || !ctx.repo)
|
|
134
|
+
return expect(true).toBe(true)
|
|
135
|
+
|
|
136
|
+
const timestamp = Date.now()
|
|
137
|
+
const branchName = `test-multi-file-${timestamp}`
|
|
138
|
+
|
|
139
|
+
const create_branch = toolbox.write('create_branch')
|
|
140
|
+
const branch = await create_branch({ owner: ctx.owner, repo: ctx.repo, branch: branchName })
|
|
141
|
+
expect(branch?.ref).toBe(`refs/heads/${branchName}`)
|
|
142
|
+
|
|
143
|
+
const create_commit = toolbox.write('create_commit')
|
|
144
|
+
const commit = await create_commit({
|
|
145
|
+
owner: ctx.owner,
|
|
146
|
+
repo: ctx.repo,
|
|
147
|
+
branch: branchName,
|
|
148
|
+
message: `Add multiple files ${timestamp}`,
|
|
149
|
+
files: [
|
|
150
|
+
{ path: `multi-test/file1-${timestamp}.txt`, content: 'Content of file 1' },
|
|
151
|
+
{ path: `multi-test/file2-${timestamp}.txt`, content: 'Content of file 2' },
|
|
152
|
+
{ path: `multi-test/file3-${timestamp}.md`, content: '# Test File 3\n\nWith UTF-8: 你好 🚀' },
|
|
153
|
+
],
|
|
154
|
+
})
|
|
155
|
+
expect(commit?.commit?.sha).toBeTruthy()
|
|
156
|
+
expect(commit?.commit?.message).toBe(`Add multiple files ${timestamp}`)
|
|
157
|
+
expect(commit?.files?.length).toBe(3)
|
|
158
|
+
|
|
159
|
+
const commit2 = await create_commit({
|
|
160
|
+
owner: ctx.owner,
|
|
161
|
+
repo: ctx.repo,
|
|
162
|
+
branch: branchName,
|
|
163
|
+
message: `Update and delete files ${timestamp}`,
|
|
164
|
+
files: [
|
|
165
|
+
{ path: `multi-test/file1-${timestamp}.txt`, content: 'Updated content of file 1' },
|
|
166
|
+
{ path: `multi-test/file2-${timestamp}.txt` },
|
|
167
|
+
{ path: `multi-test/file4-${timestamp}.txt`, content: 'New file 4' },
|
|
168
|
+
],
|
|
169
|
+
})
|
|
170
|
+
expect(commit2?.commit?.sha).toBeTruthy()
|
|
171
|
+
expect(commit2?.commit?.message).toBe(`Update and delete files ${timestamp}`)
|
|
172
|
+
}, 120000)
|
|
173
|
+
|
|
174
|
+
it('full PR workflow: create_branch -> create_commit -> create_pull_request -> merge_pull_request', async () => {
|
|
175
|
+
if (!ctx.owner || !ctx.repo)
|
|
176
|
+
return expect(true).toBe(true)
|
|
177
|
+
|
|
178
|
+
const timestamp = Date.now()
|
|
179
|
+
const branchName = `test-pr-workflow-${timestamp}`
|
|
180
|
+
|
|
181
|
+
const create_branch = toolbox.write('create_branch')
|
|
182
|
+
const branch = await create_branch({ owner: ctx.owner, repo: ctx.repo, branch: branchName })
|
|
183
|
+
expect(branch?.ref).toBe(`refs/heads/${branchName}`)
|
|
184
|
+
|
|
185
|
+
const create_commit = toolbox.write('create_commit')
|
|
186
|
+
const commit = await create_commit({
|
|
187
|
+
owner: ctx.owner,
|
|
188
|
+
repo: ctx.repo,
|
|
189
|
+
branch: branchName,
|
|
190
|
+
message: `Add feature files ${timestamp}`,
|
|
191
|
+
files: [
|
|
192
|
+
{ path: `feature-${timestamp}/index.js`, content: 'export default function() { return "Hello"; }' },
|
|
193
|
+
{ path: `feature-${timestamp}/README.md`, content: `# Feature ${timestamp}\n\nThis is a test feature.` },
|
|
194
|
+
],
|
|
195
|
+
})
|
|
196
|
+
expect(commit?.commit?.sha).toBeTruthy()
|
|
197
|
+
|
|
198
|
+
const get_repo = toolbox.read('get_repo')
|
|
199
|
+
const repoDetails = await get_repo({ owner: ctx.owner, repo: ctx.repo })
|
|
200
|
+
const defaultBranch = repoDetails?.default_branch || 'main'
|
|
201
|
+
|
|
202
|
+
const create_pull_request = toolbox.write('create_pull_request')
|
|
203
|
+
const pr = await create_pull_request({
|
|
204
|
+
owner: ctx.owner,
|
|
205
|
+
repo: ctx.repo,
|
|
206
|
+
title: `Test PR workflow ${timestamp}`,
|
|
207
|
+
body: 'This PR was created by integration tests to test the full workflow',
|
|
208
|
+
head: branchName,
|
|
209
|
+
base: defaultBranch,
|
|
210
|
+
})
|
|
211
|
+
expect(pr?.number).toBeTruthy()
|
|
212
|
+
const prNumber = pr.number
|
|
213
|
+
|
|
214
|
+
const add_labels_to_issue = toolbox.write('add_labels_to_issue')
|
|
215
|
+
try {
|
|
216
|
+
await add_labels_to_issue({ owner: ctx.owner, repo: ctx.repo, issue_number: prNumber, labels: ['test'] })
|
|
217
|
+
}
|
|
218
|
+
catch {
|
|
219
|
+
// Label might not exist -- that's ok for this test
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
const merge_pull_request = toolbox.write('merge_pull_request')
|
|
223
|
+
const merged = await merge_pull_request({ owner: ctx.owner, repo: ctx.repo, pull_number: prNumber, merge_method: 'squash' })
|
|
224
|
+
expect(merged?.merged).toBe(true)
|
|
225
|
+
}, 150000)
|
|
308
226
|
})
|
|
309
|
-
|
|
310
|
-
}, 150000)
|
|
227
|
+
}
|
|
311
228
|
})
|
|
@@ -1,20 +1,45 @@
|
|
|
1
1
|
{
|
|
2
|
-
"
|
|
3
|
-
"
|
|
4
|
-
|
|
5
|
-
"
|
|
6
|
-
"type": "
|
|
7
|
-
"
|
|
8
|
-
|
|
2
|
+
"variants": {
|
|
3
|
+
"classic_pat": {
|
|
4
|
+
"label": "Classic Personal Access Token",
|
|
5
|
+
"schema": {
|
|
6
|
+
"type": "object",
|
|
7
|
+
"properties": {
|
|
8
|
+
"token": {
|
|
9
|
+
"type": "string",
|
|
10
|
+
"title": "Classic PAT",
|
|
11
|
+
"description": "GitHub classic personal access token. Supports all GitHub API operations including creating and deleting repositories."
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"required": ["token"],
|
|
15
|
+
"additionalProperties": false
|
|
16
|
+
},
|
|
17
|
+
"injection": {
|
|
18
|
+
"headers": {
|
|
19
|
+
"Authorization": "Bearer {{token}}"
|
|
20
|
+
}
|
|
9
21
|
}
|
|
10
22
|
},
|
|
11
|
-
"
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
23
|
+
"fine_grained_pat": {
|
|
24
|
+
"label": "Fine-Grained Personal Access Token",
|
|
25
|
+
"schema": {
|
|
26
|
+
"type": "object",
|
|
27
|
+
"properties": {
|
|
28
|
+
"token": {
|
|
29
|
+
"type": "string",
|
|
30
|
+
"title": "Fine-Grained PAT",
|
|
31
|
+
"description": "GitHub fine-grained personal access token scoped to specific repositories and permissions."
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
"required": ["token"],
|
|
35
|
+
"additionalProperties": false
|
|
36
|
+
},
|
|
37
|
+
"injection": {
|
|
38
|
+
"headers": {
|
|
39
|
+
"Authorization": "Bearer {{token}}"
|
|
40
|
+
}
|
|
41
|
+
}
|
|
17
42
|
}
|
|
18
|
-
}
|
|
43
|
+
},
|
|
44
|
+
"default": "classic_pat"
|
|
19
45
|
}
|
|
20
|
-
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
Create a GitHub Classic Personal Access Token:
|
|
2
|
+
|
|
3
|
+
1. Go to `https://github.com/settings/tokens` → **Tokens (classic)**
|
|
4
|
+
2. Click **Generate new token (classic)**
|
|
5
|
+
3. Select the scopes you need: `repo` (full repo access), `delete_repo` (if you want to delete repos), `read:user` etc.
|
|
6
|
+
4. Copy the token and paste it here.
|
|
7
|
+
|
|
8
|
+
Classic PATs support all GitHub API operations including creating and deleting repositories.
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
Create a GitHub Fine-Grained Personal Access Token:
|
|
2
|
+
|
|
3
|
+
1. Go to `https://github.com/settings/tokens` → **Fine-grained tokens**
|
|
4
|
+
2. Click **Generate new token**
|
|
5
|
+
3. Set the resource owner and repository access (specific repos or all repos)
|
|
6
|
+
4. Grant the permissions your use case requires (Contents, Issues, Pull Requests, etc.)
|
|
7
|
+
5. Copy the token and paste it here.
|
|
8
|
+
|
|
9
|
+
Note: Fine-grained PATs do not support user-level operations like creating or deleting repositories. Those tools will not be available with this token type.
|