@commandable/integration-data 0.0.1
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 +30 -0
- package/dist/credentials-index.d.ts.map +1 -0
- package/dist/credentials-index.js +292 -0
- package/dist/credentials-index.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -0
- package/dist/loader.d.ts +69 -0
- package/dist/loader.d.ts.map +1 -0
- package/dist/loader.js +164 -0
- package/dist/loader.js.map +1 -0
- package/integrations/README.md +52 -0
- package/integrations/airtable/__tests__/get_handlers.test.ts +137 -0
- package/integrations/airtable/__tests__/usage_parity.test.ts +35 -0
- package/integrations/airtable/__tests__/write_and_admin_handlers.test.ts +113 -0
- package/integrations/airtable/credentials.json +20 -0
- package/integrations/airtable/credentials_hint.md +4 -0
- package/integrations/airtable/handlers/create_record.js +12 -0
- package/integrations/airtable/handlers/delete_record.js +7 -0
- package/integrations/airtable/handlers/get_record.js +4 -0
- package/integrations/airtable/handlers/get_table_schema.js +6 -0
- package/integrations/airtable/handlers/list_bases.js +4 -0
- package/integrations/airtable/handlers/list_records.js +25 -0
- package/integrations/airtable/handlers/list_table_fields.js +6 -0
- package/integrations/airtable/handlers/list_tables.js +4 -0
- package/integrations/airtable/handlers/list_views.js +6 -0
- package/integrations/airtable/handlers/search_records.js +6 -0
- package/integrations/airtable/handlers/update_record.js +11 -0
- package/integrations/airtable/manifest.json +83 -0
- package/integrations/airtable/schemas/create_record.json +12 -0
- package/integrations/airtable/schemas/delete_record.json +11 -0
- package/integrations/airtable/schemas/empty.json +6 -0
- package/integrations/airtable/schemas/get_record.json +11 -0
- package/integrations/airtable/schemas/id_base.json +9 -0
- package/integrations/airtable/schemas/id_base_table.json +10 -0
- package/integrations/airtable/schemas/list_records.json +26 -0
- package/integrations/airtable/schemas/search_records.json +12 -0
- package/integrations/airtable/schemas/update_record.json +13 -0
- package/integrations/github/__tests__/get_handlers.test.ts +117 -0
- package/integrations/github/__tests__/usage_parity.test.ts +34 -0
- package/integrations/github/__tests__/write_handlers.test.ts +311 -0
- package/integrations/github/credentials.json +20 -0
- package/integrations/github/credentials_hint.md +7 -0
- package/integrations/github/handlers/add_labels_to_issue.js +12 -0
- package/integrations/github/handlers/close_issue.js +5 -0
- package/integrations/github/handlers/comment_on_issue.js +5 -0
- package/integrations/github/handlers/create_branch.js +33 -0
- package/integrations/github/handlers/create_commit.js +91 -0
- package/integrations/github/handlers/create_issue.js +10 -0
- package/integrations/github/handlers/create_or_update_file.js +21 -0
- package/integrations/github/handlers/create_pull_request.js +16 -0
- package/integrations/github/handlers/create_repo.js +11 -0
- package/integrations/github/handlers/delete_repo.js +6 -0
- package/integrations/github/handlers/get_issue.js +4 -0
- package/integrations/github/handlers/get_repo.js +4 -0
- package/integrations/github/handlers/list_branches.js +4 -0
- package/integrations/github/handlers/list_commits.js +12 -0
- package/integrations/github/handlers/list_issues.js +12 -0
- package/integrations/github/handlers/list_pull_requests.js +8 -0
- package/integrations/github/handlers/list_repos_install.js +4 -0
- package/integrations/github/handlers/list_repos_user.js +4 -0
- package/integrations/github/handlers/merge_pull_request.js +14 -0
- package/integrations/github/handlers/update_issue.js +15 -0
- package/integrations/github/manifest.json +26 -0
- package/integrations/github/schemas/add_labels_to_issue.json +12 -0
- package/integrations/github/schemas/close_issue.json +10 -0
- package/integrations/github/schemas/comment_on_issue.json +11 -0
- package/integrations/github/schemas/create_branch.json +12 -0
- package/integrations/github/schemas/create_commit.json +25 -0
- package/integrations/github/schemas/create_issue.json +13 -0
- package/integrations/github/schemas/create_or_update_file.json +15 -0
- package/integrations/github/schemas/create_pull_request.json +15 -0
- package/integrations/github/schemas/create_repo.json +12 -0
- package/integrations/github/schemas/delete_repo.json +10 -0
- package/integrations/github/schemas/empty.json +5 -0
- package/integrations/github/schemas/get_issue.json +10 -0
- package/integrations/github/schemas/get_repo.json +9 -0
- package/integrations/github/schemas/list_commits.json +12 -0
- package/integrations/github/schemas/list_issues.json +12 -0
- package/integrations/github/schemas/list_pull_requests.json +10 -0
- package/integrations/github/schemas/merge_pull_request.json +14 -0
- package/integrations/github/schemas/owner_repo.json +9 -0
- package/integrations/github/schemas/update_issue.json +15 -0
- package/integrations/google-calendar/__tests__/get_handlers.test.ts +112 -0
- package/integrations/google-calendar/__tests__/usage_parity.test.ts +34 -0
- package/integrations/google-calendar/__tests__/write_and_admin_handlers.test.ts +161 -0
- package/integrations/google-calendar/credentials.json +36 -0
- package/integrations/google-calendar/credentials_hint.md +9 -0
- package/integrations/google-calendar/handlers/create_event.js +6 -0
- package/integrations/google-calendar/handlers/delete_acl.js +6 -0
- package/integrations/google-calendar/handlers/delete_event.js +7 -0
- package/integrations/google-calendar/handlers/freebusy_query.js +4 -0
- package/integrations/google-calendar/handlers/get_acl.js +5 -0
- package/integrations/google-calendar/handlers/get_calendar.js +4 -0
- package/integrations/google-calendar/handlers/get_event.js +5 -0
- package/integrations/google-calendar/handlers/insert_acl.js +6 -0
- package/integrations/google-calendar/handlers/list_acl.js +5 -0
- package/integrations/google-calendar/handlers/list_calendars.js +4 -0
- package/integrations/google-calendar/handlers/list_colors.js +4 -0
- package/integrations/google-calendar/handlers/list_events.js +21 -0
- package/integrations/google-calendar/handlers/list_settings.js +4 -0
- package/integrations/google-calendar/handlers/move_event.js +6 -0
- package/integrations/google-calendar/handlers/patch_event.js +5 -0
- package/integrations/google-calendar/handlers/quick_add.js +6 -0
- package/integrations/google-calendar/handlers/update_acl.js +7 -0
- package/integrations/google-calendar/handlers/update_event.js +5 -0
- package/integrations/google-calendar/manifest.json +26 -0
- package/integrations/google-calendar/schemas/create_event.json +34 -0
- package/integrations/google-calendar/schemas/delete_acl.json +9 -0
- package/integrations/google-calendar/schemas/empty.json +1 -0
- package/integrations/google-calendar/schemas/freebusy_query.json +13 -0
- package/integrations/google-calendar/schemas/get_acl.json +9 -0
- package/integrations/google-calendar/schemas/id_calendar.json +8 -0
- package/integrations/google-calendar/schemas/id_calendar_event.json +9 -0
- package/integrations/google-calendar/schemas/insert_acl.json +18 -0
- package/integrations/google-calendar/schemas/list_events.json +15 -0
- package/integrations/google-calendar/schemas/move_event.json +10 -0
- package/integrations/google-calendar/schemas/patch_event.json +10 -0
- package/integrations/google-calendar/schemas/quick_add.json +9 -0
- package/integrations/google-calendar/schemas/update_acl.json +10 -0
- package/integrations/google-calendar/schemas/update_event.json +10 -0
- package/integrations/google-docs/__tests__/get_handlers.test.ts +72 -0
- package/integrations/google-docs/__tests__/usage_parity.test.ts +34 -0
- package/integrations/google-docs/__tests__/write_handlers.test.ts +249 -0
- package/integrations/google-docs/credentials.json +36 -0
- package/integrations/google-docs/credentials_hint.md +9 -0
- package/integrations/google-docs/handlers/append_text.js +12 -0
- package/integrations/google-docs/handlers/batch_update.js +13 -0
- package/integrations/google-docs/handlers/create_document.js +9 -0
- package/integrations/google-docs/handlers/delete_first_match.js +50 -0
- package/integrations/google-docs/handlers/get_document.js +12 -0
- package/integrations/google-docs/handlers/get_document_structured.js +6 -0
- package/integrations/google-docs/handlers/get_document_text.js +17 -0
- package/integrations/google-docs/handlers/insert_inline_image_after_first_match.js +41 -0
- package/integrations/google-docs/handlers/insert_page_break_after_first_match.js +49 -0
- package/integrations/google-docs/handlers/insert_table_after_first_match.js +49 -0
- package/integrations/google-docs/handlers/insert_text_after_first_match.js +51 -0
- package/integrations/google-docs/handlers/replace_all_text.js +8 -0
- package/integrations/google-docs/handlers/style_first_match.js +42 -0
- package/integrations/google-docs/handlers/update_document_style.js +8 -0
- package/integrations/google-docs/handlers/update_paragraph_style_for_first_match.js +48 -0
- package/integrations/google-docs/manifest.json +58 -0
- package/integrations/google-docs/schemas/append_text.json +10 -0
- package/integrations/google-docs/schemas/apply_text_style.json +13 -0
- package/integrations/google-docs/schemas/batch_update.json +16 -0
- package/integrations/google-docs/schemas/create_document.json +8 -0
- package/integrations/google-docs/schemas/delete_content_range.json +11 -0
- package/integrations/google-docs/schemas/delete_first_match.json +10 -0
- package/integrations/google-docs/schemas/get_document.json +11 -0
- package/integrations/google-docs/schemas/get_document_structured.json +9 -0
- package/integrations/google-docs/schemas/get_document_text.json +9 -0
- package/integrations/google-docs/schemas/insert_inline_image.json +12 -0
- package/integrations/google-docs/schemas/insert_inline_image_after_first_match.json +13 -0
- package/integrations/google-docs/schemas/insert_page_break.json +10 -0
- package/integrations/google-docs/schemas/insert_page_break_after_first_match.json +11 -0
- package/integrations/google-docs/schemas/insert_table.json +12 -0
- package/integrations/google-docs/schemas/insert_table_after_first_match.json +13 -0
- package/integrations/google-docs/schemas/insert_text_after_first_match.json +12 -0
- package/integrations/google-docs/schemas/insert_text_at.json +11 -0
- package/integrations/google-docs/schemas/replace_all_text.json +12 -0
- package/integrations/google-docs/schemas/style_first_match.json +12 -0
- package/integrations/google-docs/schemas/update_document_style.json +11 -0
- package/integrations/google-docs/schemas/update_paragraph_style.json +13 -0
- package/integrations/google-docs/schemas/update_paragraph_style_for_first_match.json +12 -0
- package/integrations/google-sheet/__tests__/get_handlers.test.ts +129 -0
- package/integrations/google-sheet/__tests__/usage_parity.test.ts +35 -0
- package/integrations/google-sheet/__tests__/write_handlers.test.ts +171 -0
- package/integrations/google-sheet/credentials.json +36 -0
- package/integrations/google-sheet/credentials_hint.md +9 -0
- package/integrations/google-sheet/handlers/append_values.js +18 -0
- package/integrations/google-sheet/handlers/batch_clear_values.js +6 -0
- package/integrations/google-sheet/handlers/batch_clear_values_by_data_filter.js +6 -0
- package/integrations/google-sheet/handlers/batch_get_values.js +16 -0
- package/integrations/google-sheet/handlers/batch_update.js +14 -0
- package/integrations/google-sheet/handlers/batch_update_values.js +16 -0
- package/integrations/google-sheet/handlers/batch_update_values_by_data_filter.js +16 -0
- package/integrations/google-sheet/handlers/clear_values.js +6 -0
- package/integrations/google-sheet/handlers/copy_to_spreadsheet.js +6 -0
- package/integrations/google-sheet/handlers/create_spreadsheet.js +5 -0
- package/integrations/google-sheet/handlers/get_developer_metadata.js +6 -0
- package/integrations/google-sheet/handlers/get_spreadsheet.js +12 -0
- package/integrations/google-sheet/handlers/get_spreadsheet_by_data_filter.js +10 -0
- package/integrations/google-sheet/handlers/get_values.js +14 -0
- package/integrations/google-sheet/handlers/get_values_by_data_filter.js +14 -0
- package/integrations/google-sheet/handlers/search_developer_metadata.js +7 -0
- package/integrations/google-sheet/handlers/update_values.js +16 -0
- package/integrations/google-sheet/manifest.json +125 -0
- package/integrations/google-sheet/schemas/append_values.json +16 -0
- package/integrations/google-sheet/schemas/batch_clear_values.json +10 -0
- package/integrations/google-sheet/schemas/batch_clear_values_by_data_filter.json +10 -0
- package/integrations/google-sheet/schemas/batch_get_values.json +13 -0
- package/integrations/google-sheet/schemas/batch_update.json +13 -0
- package/integrations/google-sheet/schemas/batch_update_values.json +25 -0
- package/integrations/google-sheet/schemas/batch_update_values_by_data_filter.json +25 -0
- package/integrations/google-sheet/schemas/clear_values.json +10 -0
- package/integrations/google-sheet/schemas/copy_to_spreadsheet.json +11 -0
- package/integrations/google-sheet/schemas/create_spreadsheet.json +11 -0
- package/integrations/google-sheet/schemas/get_developer_metadata.json +10 -0
- package/integrations/google-sheet/schemas/get_spreadsheet.json +15 -0
- package/integrations/google-sheet/schemas/get_spreadsheet_by_data_filter.json +11 -0
- package/integrations/google-sheet/schemas/get_values.json +13 -0
- package/integrations/google-sheet/schemas/get_values_by_data_filter.json +17 -0
- package/integrations/google-sheet/schemas/search_developer_metadata.json +14 -0
- package/integrations/google-sheet/schemas/update_values.json +15 -0
- package/integrations/google-slides/__tests__/get_handlers.test.ts +69 -0
- package/integrations/google-slides/__tests__/usage_parity.test.ts +34 -0
- package/integrations/google-slides/__tests__/write_handlers.test.ts +125 -0
- package/integrations/google-slides/credentials.json +36 -0
- package/integrations/google-slides/credentials_hint.md +9 -0
- package/integrations/google-slides/handlers/append_text_to_title_of_first_slide.js +17 -0
- package/integrations/google-slides/handlers/batch_update.js +15 -0
- package/integrations/google-slides/handlers/create_presentation.js +8 -0
- package/integrations/google-slides/handlers/create_slide_after_first_match.js +20 -0
- package/integrations/google-slides/handlers/get_page_thumbnail.js +12 -0
- package/integrations/google-slides/handlers/get_presentation.js +6 -0
- package/integrations/google-slides/handlers/insert_image_after_first_match.js +19 -0
- package/integrations/google-slides/handlers/insert_shape_after_first_match.js +21 -0
- package/integrations/google-slides/handlers/replace_text_first_match.js +9 -0
- package/integrations/google-slides/handlers/set_background_color_for_slide_index.js +15 -0
- package/integrations/google-slides/handlers/style_text_first_match.js +48 -0
- package/integrations/google-slides/manifest.json +41 -0
- package/integrations/google-slides/schemas/append_text_to_title_of_first_slide.json +11 -0
- package/integrations/google-slides/schemas/batch_update.json +13 -0
- package/integrations/google-slides/schemas/create_presentation.json +8 -0
- package/integrations/google-slides/schemas/create_slide_after_first_match.json +11 -0
- package/integrations/google-slides/schemas/get_page_thumbnail.json +12 -0
- package/integrations/google-slides/schemas/get_presentation.json +9 -0
- package/integrations/google-slides/schemas/insert_image_after_first_match.json +13 -0
- package/integrations/google-slides/schemas/insert_shape_after_first_match.json +13 -0
- package/integrations/google-slides/schemas/replace_text_first_match.json +12 -0
- package/integrations/google-slides/schemas/set_background_color_for_slide_index.json +11 -0
- package/integrations/google-slides/schemas/style_text_first_match.json +12 -0
- package/integrations/new_integration_prompt.md +41 -0
- package/integrations/notion/__tests__/get_handlers.test.ts +153 -0
- package/integrations/notion/__tests__/usage_parity.test.ts +34 -0
- package/integrations/notion/__tests__/write_and_admin_handlers.test.ts +190 -0
- package/integrations/notion/credentials.json +21 -0
- package/integrations/notion/credentials_hint.md +5 -0
- package/integrations/notion/handlers/append_block_children.js +7 -0
- package/integrations/notion/handlers/create_comment.js +10 -0
- package/integrations/notion/handlers/create_database.js +11 -0
- package/integrations/notion/handlers/create_page.js +13 -0
- package/integrations/notion/handlers/delete_block.js +8 -0
- package/integrations/notion/handlers/get_me.js +4 -0
- package/integrations/notion/handlers/list_block_children.js +10 -0
- package/integrations/notion/handlers/list_comments.js +14 -0
- package/integrations/notion/handlers/list_users.js +10 -0
- package/integrations/notion/handlers/query_database.js +10 -0
- package/integrations/notion/handlers/retrieve_block.js +4 -0
- package/integrations/notion/handlers/retrieve_database.js +4 -0
- package/integrations/notion/handlers/retrieve_page.js +4 -0
- package/integrations/notion/handlers/retrieve_page_property_item.js +10 -0
- package/integrations/notion/handlers/retrieve_user.js +4 -0
- package/integrations/notion/handlers/search.js +11 -0
- package/integrations/notion/handlers/update_block.js +7 -0
- package/integrations/notion/handlers/update_database.js +10 -0
- package/integrations/notion/handlers/update_page_properties.js +10 -0
- package/integrations/notion/manifest.json +139 -0
- package/integrations/notion/prompt.md +26 -0
- package/integrations/notion/schemas/append_block_children.json +10 -0
- package/integrations/notion/schemas/create_comment.json +18 -0
- package/integrations/notion/schemas/create_database.json +18 -0
- package/integrations/notion/schemas/create_page.json +22 -0
- package/integrations/notion/schemas/delete_block.json +9 -0
- package/integrations/notion/schemas/empty.json +6 -0
- package/integrations/notion/schemas/id_block.json +9 -0
- package/integrations/notion/schemas/id_database.json +9 -0
- package/integrations/notion/schemas/id_page.json +9 -0
- package/integrations/notion/schemas/id_user.json +9 -0
- package/integrations/notion/schemas/list_block_children.json +11 -0
- package/integrations/notion/schemas/list_comments.json +15 -0
- package/integrations/notion/schemas/list_users.json +9 -0
- package/integrations/notion/schemas/query_database.json +13 -0
- package/integrations/notion/schemas/retrieve_page_property_item.json +12 -0
- package/integrations/notion/schemas/search.json +27 -0
- package/integrations/notion/schemas/update_block.json +10 -0
- package/integrations/notion/schemas/update_database.json +13 -0
- package/integrations/notion/schemas/update_page_properties.json +13 -0
- package/integrations/trello/__tests__/get_handlers.test.ts +240 -0
- package/integrations/trello/__tests__/usage_parity.test.ts +34 -0
- package/integrations/trello/__tests__/write_and_admin_handlers.test.ts +189 -0
- package/integrations/trello/credentials.json +26 -0
- package/integrations/trello/credentials_hint.md +4 -0
- package/integrations/trello/handlers/add_checklist_to_card.js +5 -0
- package/integrations/trello/handlers/add_member_to_card.js +5 -0
- package/integrations/trello/handlers/archive_list.js +5 -0
- package/integrations/trello/handlers/create_card.js +13 -0
- package/integrations/trello/handlers/create_list.js +7 -0
- package/integrations/trello/handlers/delete_card.js +9 -0
- package/integrations/trello/handlers/get_board.js +4 -0
- package/integrations/trello/handlers/get_board_cards.js +4 -0
- package/integrations/trello/handlers/get_board_custom_fields.js +4 -0
- package/integrations/trello/handlers/get_board_labels.js +4 -0
- package/integrations/trello/handlers/get_board_lists.js +4 -0
- package/integrations/trello/handlers/get_board_members.js +4 -0
- package/integrations/trello/handlers/get_board_memberships.js +4 -0
- package/integrations/trello/handlers/get_card.js +4 -0
- package/integrations/trello/handlers/get_card_actions.js +4 -0
- package/integrations/trello/handlers/get_card_attachments.js +4 -0
- package/integrations/trello/handlers/get_card_checklists.js +4 -0
- package/integrations/trello/handlers/get_card_custom_field_items.js +4 -0
- package/integrations/trello/handlers/get_card_members.js +4 -0
- package/integrations/trello/handlers/get_list.js +4 -0
- package/integrations/trello/handlers/get_list_cards.js +4 -0
- package/integrations/trello/handlers/get_member.js +4 -0
- package/integrations/trello/handlers/get_member_boards.js +4 -0
- package/integrations/trello/handlers/get_member_organizations.js +4 -0
- package/integrations/trello/handlers/get_organization.js +4 -0
- package/integrations/trello/handlers/get_organization_boards.js +4 -0
- package/integrations/trello/handlers/move_card_to_list.js +5 -0
- package/integrations/trello/handlers/remove_member_from_card.js +9 -0
- package/integrations/trello/handlers/search.js +5 -0
- package/integrations/trello/handlers/update_card.js +19 -0
- package/integrations/trello/handlers/update_list.js +11 -0
- package/integrations/trello/manifest.json +231 -0
- package/integrations/trello/schemas/add_checklist_to_card.json +10 -0
- package/integrations/trello/schemas/add_member_to_card.json +10 -0
- package/integrations/trello/schemas/archive_list.json +9 -0
- package/integrations/trello/schemas/create_card.json +13 -0
- package/integrations/trello/schemas/create_list.json +11 -0
- package/integrations/trello/schemas/delete_card.json +9 -0
- package/integrations/trello/schemas/display_trello_cards.json +45 -0
- package/integrations/trello/schemas/empty.json +5 -0
- package/integrations/trello/schemas/get_member.json +5 -0
- package/integrations/trello/schemas/id_board.json +8 -0
- package/integrations/trello/schemas/id_card.json +8 -0
- package/integrations/trello/schemas/id_list.json +8 -0
- package/integrations/trello/schemas/id_org.json +8 -0
- package/integrations/trello/schemas/move_card_to_list.json +10 -0
- package/integrations/trello/schemas/remove_member_from_card.json +10 -0
- package/integrations/trello/schemas/search.json +8 -0
- package/integrations/trello/schemas/update_card.json +16 -0
- package/integrations/trello/schemas/update_list.json +12 -0
- package/package.json +45 -0
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import { beforeAll, describe, expect, it } from 'vitest'
|
|
2
|
+
import { IntegrationProxy } from '../../../src/integrations/proxy.js'
|
|
3
|
+
import { loadIntegrationTools } from '../../../src/integrations/dataLoader.js'
|
|
4
|
+
|
|
5
|
+
// LIVE GitHub integration tests using managed OAuth
|
|
6
|
+
// Required env vars:
|
|
7
|
+
// - COMMANDABLE_MANAGED_OAUTH_BASE_URL
|
|
8
|
+
// - COMMANDABLE_MANAGED_OAUTH_SECRET_KEY
|
|
9
|
+
// - GITHUB_TEST_CONNECTION_ID (managed OAuth connection for provider 'github')
|
|
10
|
+
|
|
11
|
+
interface Ctx {
|
|
12
|
+
owner?: string
|
|
13
|
+
repo?: string
|
|
14
|
+
issue_number?: number
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const env = process.env as Record<string, string>
|
|
18
|
+
const hasEnv = (...keys: string[]) => keys.every(k => !!env[k] && env[k].trim().length > 0)
|
|
19
|
+
const suite = hasEnv('COMMANDABLE_MANAGED_OAUTH_BASE_URL', 'COMMANDABLE_MANAGED_OAUTH_SECRET_KEY', 'GITHUB_TEST_CONNECTION_ID')
|
|
20
|
+
? describe
|
|
21
|
+
: describe.skip
|
|
22
|
+
|
|
23
|
+
suite('github read handlers (live)', () => {
|
|
24
|
+
const ctx: Ctx = {}
|
|
25
|
+
let buildHandler: (name: string) => ((input: any) => Promise<any>)
|
|
26
|
+
|
|
27
|
+
beforeAll(async () => {
|
|
28
|
+
const { COMMANDABLE_MANAGED_OAUTH_BASE_URL, COMMANDABLE_MANAGED_OAUTH_SECRET_KEY, GITHUB_TEST_CONNECTION_ID } = env
|
|
29
|
+
|
|
30
|
+
const proxy = new IntegrationProxy({
|
|
31
|
+
managedOAuthBaseUrl: COMMANDABLE_MANAGED_OAUTH_BASE_URL,
|
|
32
|
+
managedOAuthSecretKey: COMMANDABLE_MANAGED_OAUTH_SECRET_KEY,
|
|
33
|
+
})
|
|
34
|
+
const integrationNode = { id: 'node-github', type: 'github', label: 'GitHub', connectionId: GITHUB_TEST_CONNECTION_ID } as any
|
|
35
|
+
|
|
36
|
+
const tools = loadIntegrationTools('github')
|
|
37
|
+
expect(tools).toBeTruthy()
|
|
38
|
+
|
|
39
|
+
buildHandler = (name: string) => {
|
|
40
|
+
const tool = tools!.read.find(t => t.name === name)
|
|
41
|
+
expect(tool, `tool ${name} exists`).toBeTruthy()
|
|
42
|
+
const integration = {
|
|
43
|
+
fetch: (path: string, init?: RequestInit) => proxy.call(integrationNode, path, init),
|
|
44
|
+
}
|
|
45
|
+
const build = new Function('integration', `return (${tool!.handlerCode});`)
|
|
46
|
+
return build(integration) as (input: any) => Promise<any>
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// Discover owner/repo/issue for tests
|
|
50
|
+
const list_repos = buildHandler('list_repos')
|
|
51
|
+
const repos = await list_repos({})
|
|
52
|
+
const first = Array.isArray(repos) ? repos[0] : repos?.[0]
|
|
53
|
+
ctx.owner = first?.owner?.login || first?.owner || first?.full_name?.split?.('/')[0]
|
|
54
|
+
ctx.repo = first?.name || first?.full_name?.split?.('/')[1]
|
|
55
|
+
|
|
56
|
+
if (ctx.owner && ctx.repo) {
|
|
57
|
+
const list_issues = buildHandler('list_issues')
|
|
58
|
+
const issues = await list_issues({ owner: ctx.owner, repo: ctx.repo, state: 'all' })
|
|
59
|
+
const firstIssue = Array.isArray(issues) ? issues.find((i: any) => typeof i.number === 'number') : undefined
|
|
60
|
+
ctx.issue_number = firstIssue?.number
|
|
61
|
+
}
|
|
62
|
+
}, 60000)
|
|
63
|
+
|
|
64
|
+
it('list_repos returns repositories', async () => {
|
|
65
|
+
const handler = buildHandler('list_repos')
|
|
66
|
+
const result = await handler({})
|
|
67
|
+
expect(result).toBeTruthy()
|
|
68
|
+
}, 30000)
|
|
69
|
+
|
|
70
|
+
it('get_repo returns repo details', async () => {
|
|
71
|
+
if (!ctx.owner || !ctx.repo)
|
|
72
|
+
return expect(true).toBe(true)
|
|
73
|
+
const handler = buildHandler('get_repo')
|
|
74
|
+
const result = await handler({ owner: ctx.owner, repo: ctx.repo })
|
|
75
|
+
expect(result?.name?.toLowerCase?.()).toBe(ctx.repo?.toLowerCase?.())
|
|
76
|
+
}, 30000)
|
|
77
|
+
|
|
78
|
+
it('list_issues returns issues for repo', async () => {
|
|
79
|
+
if (!ctx.owner || !ctx.repo)
|
|
80
|
+
return expect(true).toBe(true)
|
|
81
|
+
const handler = buildHandler('list_issues')
|
|
82
|
+
const result = await handler({ owner: ctx.owner, repo: ctx.repo, state: 'all' })
|
|
83
|
+
expect(Array.isArray(result)).toBe(true)
|
|
84
|
+
}, 30000)
|
|
85
|
+
|
|
86
|
+
it('get_issue returns a single issue if available', async () => {
|
|
87
|
+
if (!ctx.owner || !ctx.repo || !ctx.issue_number)
|
|
88
|
+
return expect(true).toBe(true)
|
|
89
|
+
const handler = buildHandler('get_issue')
|
|
90
|
+
const result = await handler({ owner: ctx.owner, repo: ctx.repo, issue_number: ctx.issue_number })
|
|
91
|
+
expect(result?.number).toBe(ctx.issue_number)
|
|
92
|
+
}, 30000)
|
|
93
|
+
|
|
94
|
+
it('list_pull_requests returns PRs', async () => {
|
|
95
|
+
if (!ctx.owner || !ctx.repo)
|
|
96
|
+
return expect(true).toBe(true)
|
|
97
|
+
const handler = buildHandler('list_pull_requests')
|
|
98
|
+
const result = await handler({ owner: ctx.owner, repo: ctx.repo, state: 'all' })
|
|
99
|
+
expect(Array.isArray(result)).toBe(true)
|
|
100
|
+
}, 30000)
|
|
101
|
+
|
|
102
|
+
it('list_branches returns branches', async () => {
|
|
103
|
+
if (!ctx.owner || !ctx.repo)
|
|
104
|
+
return expect(true).toBe(true)
|
|
105
|
+
const handler = buildHandler('list_branches')
|
|
106
|
+
const result = await handler({ owner: ctx.owner, repo: ctx.repo })
|
|
107
|
+
expect(Array.isArray(result)).toBe(true)
|
|
108
|
+
}, 30000)
|
|
109
|
+
|
|
110
|
+
it('list_commits returns commits', async () => {
|
|
111
|
+
if (!ctx.owner || !ctx.repo)
|
|
112
|
+
return expect(true).toBe(true)
|
|
113
|
+
const handler = buildHandler('list_commits')
|
|
114
|
+
const result = await handler({ owner: ctx.owner, repo: ctx.repo })
|
|
115
|
+
expect(Array.isArray(result)).toBe(true)
|
|
116
|
+
}, 30000)
|
|
117
|
+
})
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { existsSync, readdirSync, readFileSync } from 'node:fs'
|
|
2
|
+
import { resolve } from 'node:path'
|
|
3
|
+
import { fileURLToPath } from 'node:url'
|
|
4
|
+
import { describe, expect, it } from 'vitest'
|
|
5
|
+
import { loadIntegrationManifest } from '../../../src/integrations/dataLoader.js'
|
|
6
|
+
|
|
7
|
+
function escapeRegExp(str: string): string {
|
|
8
|
+
return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
describe('github static usage parity', () => {
|
|
12
|
+
it('every manifest tool is referenced in tests via build*(name)', () => {
|
|
13
|
+
const manifest = loadIntegrationManifest('github')!
|
|
14
|
+
const toolNames = (manifest.tools as any[]).map(t => t.name)
|
|
15
|
+
|
|
16
|
+
const testsDir = fileURLToPath(new URL('.', import.meta.url))
|
|
17
|
+
expect(existsSync(testsDir)).toBe(true)
|
|
18
|
+
const testFiles = readdirSync(testsDir)
|
|
19
|
+
.filter(f => /\.test\.(t|j)s$/.test(f) && !f.includes('usage_parity.test'))
|
|
20
|
+
.map(f => resolve(testsDir, f))
|
|
21
|
+
|
|
22
|
+
const fileContents = testFiles.map(f => readFileSync(f, 'utf8'))
|
|
23
|
+
|
|
24
|
+
const missing: string[] = []
|
|
25
|
+
for (const name of toolNames) {
|
|
26
|
+
const nameRe = new RegExp(`build(?:Read|Write|Admin)?(?:Handler)?\\(\\s*['"\`]${escapeRegExp(name)}['"\`]\\s*\\)`, 'm')
|
|
27
|
+
const found = fileContents.some(src => nameRe.test(src))
|
|
28
|
+
if (!found)
|
|
29
|
+
missing.push(name)
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
expect(missing, `Missing handler usages in tests: ${missing.join(', ')}`).toEqual([])
|
|
33
|
+
})
|
|
34
|
+
})
|
|
@@ -0,0 +1,311 @@
|
|
|
1
|
+
import { beforeAll, describe, expect, it } from 'vitest'
|
|
2
|
+
import { IntegrationProxy } from '../../../src/integrations/proxy.js'
|
|
3
|
+
import { loadIntegrationTools } from '../../../src/integrations/dataLoader.js'
|
|
4
|
+
|
|
5
|
+
// LIVE GitHub write tests using managed OAuth
|
|
6
|
+
// Required env vars for write tests:
|
|
7
|
+
// - COMMANDABLE_MANAGED_OAUTH_BASE_URL
|
|
8
|
+
// - COMMANDABLE_MANAGED_OAUTH_SECRET_KEY
|
|
9
|
+
// - GITHUB_TEST_CONNECTION_ID (managed OAuth connection for provider 'github')
|
|
10
|
+
// - GITHUB_TEST_OWNER (owner to use for write tests)
|
|
11
|
+
// - GITHUB_TEST_REPO (repo to use for write tests)
|
|
12
|
+
|
|
13
|
+
interface Ctx {
|
|
14
|
+
owner?: string
|
|
15
|
+
repo?: string
|
|
16
|
+
issue_number?: number
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const env = process.env as Record<string, string>
|
|
20
|
+
const hasEnv = (...keys: string[]) => keys.every(k => !!env[k] && env[k].trim().length > 0)
|
|
21
|
+
const suite = hasEnv(
|
|
22
|
+
'COMMANDABLE_MANAGED_OAUTH_BASE_URL',
|
|
23
|
+
'COMMANDABLE_MANAGED_OAUTH_SECRET_KEY',
|
|
24
|
+
'GITHUB_TEST_CONNECTION_ID',
|
|
25
|
+
'GITHUB_TEST_OWNER',
|
|
26
|
+
'GITHUB_TEST_REPO',
|
|
27
|
+
)
|
|
28
|
+
? describe
|
|
29
|
+
: describe.skip
|
|
30
|
+
|
|
31
|
+
suite('github write handlers (live)', () => {
|
|
32
|
+
const ctx: Ctx = {}
|
|
33
|
+
let buildWriteHandler: (name: string) => ((input: any) => Promise<any>)
|
|
34
|
+
let buildReadHandler: (name: string) => ((input: any) => Promise<any>)
|
|
35
|
+
|
|
36
|
+
beforeAll(async () => {
|
|
37
|
+
const {
|
|
38
|
+
COMMANDABLE_MANAGED_OAUTH_BASE_URL,
|
|
39
|
+
COMMANDABLE_MANAGED_OAUTH_SECRET_KEY,
|
|
40
|
+
GITHUB_TEST_CONNECTION_ID,
|
|
41
|
+
GITHUB_TEST_OWNER,
|
|
42
|
+
GITHUB_TEST_REPO,
|
|
43
|
+
} = env
|
|
44
|
+
|
|
45
|
+
const proxy = new IntegrationProxy({
|
|
46
|
+
managedOAuthBaseUrl: COMMANDABLE_MANAGED_OAUTH_BASE_URL,
|
|
47
|
+
managedOAuthSecretKey: COMMANDABLE_MANAGED_OAUTH_SECRET_KEY,
|
|
48
|
+
})
|
|
49
|
+
const integrationNode = { id: 'node-github', type: 'github', label: 'GitHub', connectionId: GITHUB_TEST_CONNECTION_ID } as any
|
|
50
|
+
|
|
51
|
+
const tools = loadIntegrationTools('github')
|
|
52
|
+
expect(tools).toBeTruthy()
|
|
53
|
+
|
|
54
|
+
buildWriteHandler = (name: string) => {
|
|
55
|
+
const tool = tools!.write.find(t => t.name === name)
|
|
56
|
+
expect(tool, `write tool ${name} exists`).toBeTruthy()
|
|
57
|
+
const integration = { fetch: (path: string, init?: RequestInit) => proxy.call(integrationNode, path, init) }
|
|
58
|
+
const build = new Function('integration', `return (${tool!.handlerCode});`)
|
|
59
|
+
return build(integration) as (input: any) => Promise<any>
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
buildReadHandler = (name: string) => {
|
|
63
|
+
const tool = tools!.read.find(t => t.name === name)
|
|
64
|
+
expect(tool, `read tool ${name} exists`).toBeTruthy()
|
|
65
|
+
const integration = { fetch: (path: string, init?: RequestInit) => proxy.call(integrationNode, path, init) }
|
|
66
|
+
const build = new Function('integration', `return (${tool!.handlerCode});`)
|
|
67
|
+
return build(integration) as (input: any) => Promise<any>
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
ctx.owner = GITHUB_TEST_OWNER
|
|
71
|
+
ctx.repo = GITHUB_TEST_REPO
|
|
72
|
+
}, 60000)
|
|
73
|
+
|
|
74
|
+
it('create_issue -> update_issue -> comment_on_issue -> close_issue roundtrip', async () => {
|
|
75
|
+
if (!ctx.owner || !ctx.repo)
|
|
76
|
+
return expect(true).toBe(true)
|
|
77
|
+
|
|
78
|
+
const titleBase = `CmdTest Issue ${Date.now()}`
|
|
79
|
+
|
|
80
|
+
// Create
|
|
81
|
+
const create_issue = buildWriteHandler('create_issue')
|
|
82
|
+
const created = await create_issue({ owner: ctx.owner, repo: ctx.repo, title: titleBase, body: 'Initial body from test.' })
|
|
83
|
+
expect(created?.number).toBeTruthy()
|
|
84
|
+
ctx.issue_number = created.number
|
|
85
|
+
|
|
86
|
+
// Update
|
|
87
|
+
const update_issue = buildWriteHandler('update_issue')
|
|
88
|
+
const updated = await update_issue({ owner: ctx.owner, repo: ctx.repo, issue_number: ctx.issue_number, body: 'Updated body from test.' })
|
|
89
|
+
expect(updated?.number).toBe(ctx.issue_number)
|
|
90
|
+
|
|
91
|
+
// Comment
|
|
92
|
+
const comment_on_issue = buildWriteHandler('comment_on_issue')
|
|
93
|
+
const comment = await comment_on_issue({ owner: ctx.owner, repo: ctx.repo, issue_number: ctx.issue_number, body: 'A comment from test.' })
|
|
94
|
+
expect(comment?.id).toBeTruthy()
|
|
95
|
+
|
|
96
|
+
// Close
|
|
97
|
+
const close_issue = buildWriteHandler('close_issue')
|
|
98
|
+
const closed = await close_issue({ owner: ctx.owner, repo: ctx.repo, issue_number: ctx.issue_number })
|
|
99
|
+
expect(closed?.state).toBe('closed')
|
|
100
|
+
}, 90000)
|
|
101
|
+
|
|
102
|
+
it('create_repo -> delete_repo lifecycle', async () => {
|
|
103
|
+
if (!ctx.owner)
|
|
104
|
+
return expect(true).toBe(true)
|
|
105
|
+
|
|
106
|
+
const repoName = `cmdtest-repo-${Date.now()}`
|
|
107
|
+
|
|
108
|
+
// Create
|
|
109
|
+
const create_repo = buildWriteHandler('create_repo')
|
|
110
|
+
const created = await create_repo({
|
|
111
|
+
name: repoName,
|
|
112
|
+
description: 'Test repo created by integration tests',
|
|
113
|
+
private: true,
|
|
114
|
+
auto_init: true,
|
|
115
|
+
})
|
|
116
|
+
expect(created?.name).toBe(repoName)
|
|
117
|
+
expect(created?.full_name).toBe(`${ctx.owner}/${repoName}`)
|
|
118
|
+
|
|
119
|
+
// Delete
|
|
120
|
+
const delete_repo = buildWriteHandler('delete_repo')
|
|
121
|
+
const deleted = await delete_repo({ owner: ctx.owner, repo: repoName })
|
|
122
|
+
expect(deleted?.success).toBe(true)
|
|
123
|
+
expect(deleted?.status).toBe(204)
|
|
124
|
+
}, 90000)
|
|
125
|
+
|
|
126
|
+
it('create_or_update_file: single file commit', async () => {
|
|
127
|
+
if (!ctx.owner || !ctx.repo)
|
|
128
|
+
return expect(true).toBe(true)
|
|
129
|
+
|
|
130
|
+
const timestamp = Date.now()
|
|
131
|
+
const branchName = `test-single-file-${timestamp}`
|
|
132
|
+
|
|
133
|
+
// Create a new branch
|
|
134
|
+
const create_branch = buildWriteHandler('create_branch')
|
|
135
|
+
const branch = await create_branch({
|
|
136
|
+
owner: ctx.owner,
|
|
137
|
+
repo: ctx.repo,
|
|
138
|
+
branch: branchName,
|
|
139
|
+
})
|
|
140
|
+
expect(branch?.ref).toBe(`refs/heads/${branchName}`)
|
|
141
|
+
|
|
142
|
+
// Create a file using create_or_update_file
|
|
143
|
+
const create_or_update_file = buildWriteHandler('create_or_update_file')
|
|
144
|
+
const file = await create_or_update_file({
|
|
145
|
+
owner: ctx.owner,
|
|
146
|
+
repo: ctx.repo,
|
|
147
|
+
path: `test-single-${timestamp}.txt`,
|
|
148
|
+
message: `Add single test file ${timestamp}`,
|
|
149
|
+
content: `Test content with UTF-8: Hello 世界 🌍\nCreated at ${timestamp}`,
|
|
150
|
+
branch: branchName,
|
|
151
|
+
})
|
|
152
|
+
expect(file?.commit?.message).toBe(`Add single test file ${timestamp}`)
|
|
153
|
+
expect(file?.content?.path).toBe(`test-single-${timestamp}.txt`)
|
|
154
|
+
|
|
155
|
+
// Update the same file
|
|
156
|
+
const updated = await create_or_update_file({
|
|
157
|
+
owner: ctx.owner,
|
|
158
|
+
repo: ctx.repo,
|
|
159
|
+
path: `test-single-${timestamp}.txt`,
|
|
160
|
+
message: `Update test file ${timestamp}`,
|
|
161
|
+
content: `Updated content at ${timestamp}`,
|
|
162
|
+
branch: branchName,
|
|
163
|
+
sha: file.content.sha,
|
|
164
|
+
})
|
|
165
|
+
expect(updated?.commit?.message).toBe(`Update test file ${timestamp}`)
|
|
166
|
+
}, 90000)
|
|
167
|
+
|
|
168
|
+
it('create_commit: multiple files in one commit', async () => {
|
|
169
|
+
if (!ctx.owner || !ctx.repo)
|
|
170
|
+
return expect(true).toBe(true)
|
|
171
|
+
|
|
172
|
+
const timestamp = Date.now()
|
|
173
|
+
const branchName = `test-multi-file-${timestamp}`
|
|
174
|
+
|
|
175
|
+
// Create a new branch
|
|
176
|
+
const create_branch = buildWriteHandler('create_branch')
|
|
177
|
+
const branch = await create_branch({
|
|
178
|
+
owner: ctx.owner,
|
|
179
|
+
repo: ctx.repo,
|
|
180
|
+
branch: branchName,
|
|
181
|
+
})
|
|
182
|
+
expect(branch?.ref).toBe(`refs/heads/${branchName}`)
|
|
183
|
+
|
|
184
|
+
// Create multiple files in one commit using create_commit
|
|
185
|
+
const create_commit = buildWriteHandler('create_commit')
|
|
186
|
+
const commit = await create_commit({
|
|
187
|
+
owner: ctx.owner,
|
|
188
|
+
repo: ctx.repo,
|
|
189
|
+
branch: branchName,
|
|
190
|
+
message: `Add multiple files ${timestamp}`,
|
|
191
|
+
files: [
|
|
192
|
+
{
|
|
193
|
+
path: `multi-test/file1-${timestamp}.txt`,
|
|
194
|
+
content: 'Content of file 1',
|
|
195
|
+
},
|
|
196
|
+
{
|
|
197
|
+
path: `multi-test/file2-${timestamp}.txt`,
|
|
198
|
+
content: 'Content of file 2',
|
|
199
|
+
},
|
|
200
|
+
{
|
|
201
|
+
path: `multi-test/file3-${timestamp}.md`,
|
|
202
|
+
content: '# Test File 3\n\nWith UTF-8: 你好 🚀',
|
|
203
|
+
},
|
|
204
|
+
],
|
|
205
|
+
})
|
|
206
|
+
expect(commit?.commit?.sha).toBeTruthy()
|
|
207
|
+
expect(commit?.commit?.message).toBe(`Add multiple files ${timestamp}`)
|
|
208
|
+
expect(commit?.files?.length).toBe(3)
|
|
209
|
+
|
|
210
|
+
// Update and delete files in another commit
|
|
211
|
+
const commit2 = await create_commit({
|
|
212
|
+
owner: ctx.owner,
|
|
213
|
+
repo: ctx.repo,
|
|
214
|
+
branch: branchName,
|
|
215
|
+
message: `Update and delete files ${timestamp}`,
|
|
216
|
+
files: [
|
|
217
|
+
{
|
|
218
|
+
path: `multi-test/file1-${timestamp}.txt`,
|
|
219
|
+
content: 'Updated content of file 1',
|
|
220
|
+
},
|
|
221
|
+
{
|
|
222
|
+
path: `multi-test/file2-${timestamp}.txt`,
|
|
223
|
+
// Omit content to delete the file
|
|
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',
|
|
308
|
+
})
|
|
309
|
+
expect(merged?.merged).toBe(true)
|
|
310
|
+
}, 150000)
|
|
311
|
+
})
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schema": {
|
|
3
|
+
"type": "object",
|
|
4
|
+
"properties": {
|
|
5
|
+
"token": {
|
|
6
|
+
"type": "string",
|
|
7
|
+
"title": "Personal Access Token",
|
|
8
|
+
"description": "GitHub personal access token (classic or fine-grained) with appropriate scopes."
|
|
9
|
+
}
|
|
10
|
+
},
|
|
11
|
+
"required": ["token"],
|
|
12
|
+
"additionalProperties": false
|
|
13
|
+
},
|
|
14
|
+
"injection": {
|
|
15
|
+
"headers": {
|
|
16
|
+
"Authorization": "Bearer {{token}}"
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
Create a GitHub personal access token and paste it here.
|
|
2
|
+
|
|
3
|
+
- Fine-grained PAT: Settings → Developer settings → Personal access tokens → Fine-grained tokens
|
|
4
|
+
- Classic PAT: Settings → Developer settings → Personal access tokens → Tokens (classic)
|
|
5
|
+
|
|
6
|
+
Minimum scopes depend on the tools you use (repo read/write, issues, pull requests, etc.).
|
|
7
|
+
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
async (input) => {
|
|
2
|
+
// First, get the SHA of the branch to create from
|
|
3
|
+
let fromRef = input.from_branch || 'main'
|
|
4
|
+
|
|
5
|
+
// Try to get the ref, fallback to master if main doesn't exist
|
|
6
|
+
let refRes
|
|
7
|
+
try {
|
|
8
|
+
refRes = await integration.fetch(`/repos/${input.owner}/${input.repo}/git/refs/heads/${fromRef}`)
|
|
9
|
+
} catch (e) {
|
|
10
|
+
if (fromRef === 'main') {
|
|
11
|
+
fromRef = 'master'
|
|
12
|
+
refRes = await integration.fetch(`/repos/${input.owner}/${input.repo}/git/refs/heads/${fromRef}`)
|
|
13
|
+
} else {
|
|
14
|
+
throw e
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const refData = await refRes.json()
|
|
19
|
+
const sha = refData.object.sha
|
|
20
|
+
|
|
21
|
+
// Create the new branch
|
|
22
|
+
const body = {
|
|
23
|
+
ref: `refs/heads/${input.branch}`,
|
|
24
|
+
sha: sha,
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const res = await integration.fetch(`/repos/${input.owner}/${input.repo}/git/refs`, {
|
|
28
|
+
method: 'POST',
|
|
29
|
+
body
|
|
30
|
+
})
|
|
31
|
+
return await res.json()
|
|
32
|
+
}
|
|
33
|
+
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
async (input) => {
|
|
2
|
+
const { owner, repo, branch, message, files } = input
|
|
3
|
+
|
|
4
|
+
// 1. Get the current commit SHA for the branch
|
|
5
|
+
const refRes = await integration.fetch(`/repos/${owner}/${repo}/git/refs/heads/${branch}`)
|
|
6
|
+
const refData = await refRes.json()
|
|
7
|
+
const currentCommitSha = refData.object.sha
|
|
8
|
+
|
|
9
|
+
// 2. Get the current commit to get its tree
|
|
10
|
+
const commitRes = await integration.fetch(`/repos/${owner}/${repo}/git/commits/${currentCommitSha}`)
|
|
11
|
+
const commitData = await commitRes.json()
|
|
12
|
+
const currentTreeSha = commitData.tree.sha
|
|
13
|
+
|
|
14
|
+
// 3. Create blobs for each file with content
|
|
15
|
+
const tree = []
|
|
16
|
+
for (const file of files) {
|
|
17
|
+
if (file.content !== undefined && file.content !== null) {
|
|
18
|
+
// Create a blob for this file
|
|
19
|
+
const contentBase64 = typeof Buffer !== 'undefined'
|
|
20
|
+
? Buffer.from(file.content).toString('base64')
|
|
21
|
+
: btoa(unescape(encodeURIComponent(file.content)))
|
|
22
|
+
|
|
23
|
+
const blobRes = await integration.fetch(`/repos/${owner}/${repo}/git/blobs`, {
|
|
24
|
+
method: 'POST',
|
|
25
|
+
body: {
|
|
26
|
+
content: contentBase64,
|
|
27
|
+
encoding: 'base64',
|
|
28
|
+
},
|
|
29
|
+
})
|
|
30
|
+
const blobData = await blobRes.json()
|
|
31
|
+
|
|
32
|
+
tree.push({
|
|
33
|
+
path: file.path,
|
|
34
|
+
mode: file.mode || '100644',
|
|
35
|
+
type: 'blob',
|
|
36
|
+
sha: blobData.sha,
|
|
37
|
+
})
|
|
38
|
+
} else {
|
|
39
|
+
// File deletion (null sha means delete)
|
|
40
|
+
tree.push({
|
|
41
|
+
path: file.path,
|
|
42
|
+
mode: '100644',
|
|
43
|
+
type: 'blob',
|
|
44
|
+
sha: null,
|
|
45
|
+
})
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// 4. Create a new tree
|
|
50
|
+
const treeRes = await integration.fetch(`/repos/${owner}/${repo}/git/trees`, {
|
|
51
|
+
method: 'POST',
|
|
52
|
+
body: {
|
|
53
|
+
base_tree: currentTreeSha,
|
|
54
|
+
tree: tree,
|
|
55
|
+
},
|
|
56
|
+
})
|
|
57
|
+
const treeData = await treeRes.json()
|
|
58
|
+
|
|
59
|
+
// 5. Create the commit
|
|
60
|
+
const newCommitRes = await integration.fetch(`/repos/${owner}/${repo}/git/commits`, {
|
|
61
|
+
method: 'POST',
|
|
62
|
+
body: {
|
|
63
|
+
message: message,
|
|
64
|
+
tree: treeData.sha,
|
|
65
|
+
parents: [currentCommitSha],
|
|
66
|
+
},
|
|
67
|
+
})
|
|
68
|
+
const newCommitData = await newCommitRes.json()
|
|
69
|
+
|
|
70
|
+
// 6. Update the branch reference
|
|
71
|
+
const updateRefRes = await integration.fetch(`/repos/${owner}/${repo}/git/refs/heads/${branch}`, {
|
|
72
|
+
method: 'PATCH',
|
|
73
|
+
body: {
|
|
74
|
+
sha: newCommitData.sha,
|
|
75
|
+
},
|
|
76
|
+
})
|
|
77
|
+
await updateRefRes.json()
|
|
78
|
+
|
|
79
|
+
return {
|
|
80
|
+
commit: {
|
|
81
|
+
sha: newCommitData.sha,
|
|
82
|
+
url: newCommitData.html_url,
|
|
83
|
+
message: newCommitData.message,
|
|
84
|
+
},
|
|
85
|
+
tree: {
|
|
86
|
+
sha: treeData.sha,
|
|
87
|
+
},
|
|
88
|
+
files: files.map(f => ({ path: f.path })),
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
async (input) => {
|
|
2
|
+
const body = {
|
|
3
|
+
title: input.title,
|
|
4
|
+
body: input.body,
|
|
5
|
+
assignees: input.assignees,
|
|
6
|
+
labels: input.labels,
|
|
7
|
+
}
|
|
8
|
+
const res = await integration.fetch(`/repos/${input.owner}/${input.repo}/issues`, { method: 'POST', body })
|
|
9
|
+
return await res.json()
|
|
10
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
async (input) => {
|
|
2
|
+
// GitHub API expects content to be base64 encoded
|
|
3
|
+
// Use btoa with proper UTF-8 encoding for browser/Node.js compatibility
|
|
4
|
+
const contentBase64 = typeof Buffer !== 'undefined'
|
|
5
|
+
? Buffer.from(input.content).toString('base64')
|
|
6
|
+
: btoa(unescape(encodeURIComponent(input.content)))
|
|
7
|
+
|
|
8
|
+
const body = {
|
|
9
|
+
message: input.message,
|
|
10
|
+
content: contentBase64,
|
|
11
|
+
branch: input.branch,
|
|
12
|
+
sha: input.sha,
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const res = await integration.fetch(`/repos/${input.owner}/${input.repo}/contents/${input.path}`, {
|
|
16
|
+
method: 'PUT',
|
|
17
|
+
body
|
|
18
|
+
})
|
|
19
|
+
return await res.json()
|
|
20
|
+
}
|
|
21
|
+
|