@gitkraken/core-gitlens 0.5.110 → 0.5.111
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/CHANGELOG.md +16 -1
- package/dist/git/cache.d.ts +111 -6
- package/dist/git/cache.d.ts.map +1 -1
- package/dist/git/cache.js +312 -43
- package/dist/git/cache.js.map +1 -1
- package/dist/git/context.d.ts +11 -0
- package/dist/git/context.d.ts.map +1 -1
- package/dist/git/context.js.map +1 -1
- package/dist/git/models/fileStatus.d.ts +1 -0
- package/dist/git/models/fileStatus.d.ts.map +1 -1
- package/dist/git/models/fileStatus.js +1 -0
- package/dist/git/models/fileStatus.js.map +1 -1
- package/dist/git/models/issue.d.ts +4 -0
- package/dist/git/models/issue.d.ts.map +1 -1
- package/dist/git/models/mergeConflicts.d.ts +2 -0
- package/dist/git/models/mergeConflicts.d.ts.map +1 -1
- package/dist/git/models/pullRequest.d.ts +38 -2
- package/dist/git/models/pullRequest.d.ts.map +1 -1
- package/dist/git/models/pullRequest.js +12 -1
- package/dist/git/models/pullRequest.js.map +1 -1
- package/dist/git/models/repository.d.ts +32 -5
- package/dist/git/models/repository.d.ts.map +1 -1
- package/dist/git/models/repository.js +58 -12
- package/dist/git/models/repository.js.map +1 -1
- package/dist/git/models/statusFile.d.ts.map +1 -1
- package/dist/git/models/statusFile.js +3 -0
- package/dist/git/models/statusFile.js.map +1 -1
- package/dist/git/providers/branches.d.ts +2 -0
- package/dist/git/providers/branches.d.ts.map +1 -1
- package/dist/git/providers/commits.d.ts +8 -0
- package/dist/git/providers/commits.d.ts.map +1 -1
- package/dist/git/providers/config.d.ts +19 -1
- package/dist/git/providers/config.d.ts.map +1 -1
- package/dist/git/providers/operations.d.ts +1 -0
- package/dist/git/providers/operations.d.ts.map +1 -1
- package/dist/git/providers/pausedOperations.d.ts +2 -0
- package/dist/git/providers/pausedOperations.d.ts.map +1 -1
- package/dist/git/providers/status.d.ts +1 -0
- package/dist/git/providers/status.d.ts.map +1 -1
- package/dist/git/utils/config.utils.d.ts +3 -0
- package/dist/git/utils/config.utils.d.ts.map +1 -0
- package/dist/git/utils/config.utils.js +8 -0
- package/dist/git/utils/config.utils.js.map +1 -0
- package/dist/git/utils/issue.utils.d.ts.map +1 -1
- package/dist/git/utils/issue.utils.js +2 -0
- package/dist/git/utils/issue.utils.js.map +1 -1
- package/dist/git/utils/pausedOperationStatus.utils.d.ts +14 -0
- package/dist/git/utils/pausedOperationStatus.utils.d.ts.map +1 -1
- package/dist/git/utils/pausedOperationStatus.utils.js +23 -0
- package/dist/git/utils/pausedOperationStatus.utils.js.map +1 -1
- package/dist/git/utils/pullRequest.utils.d.ts +14 -1
- package/dist/git/utils/pullRequest.utils.d.ts.map +1 -1
- package/dist/git/utils/pullRequest.utils.js +31 -0
- package/dist/git/utils/pullRequest.utils.js.map +1 -1
- package/dist/git/watching/changeEvent.d.ts +6 -1
- package/dist/git/watching/changeEvent.d.ts.map +1 -1
- package/dist/git/watching/classifyChange.d.ts.map +1 -1
- package/dist/git/watching/classifyChange.js +14 -1
- package/dist/git/watching/classifyChange.js.map +1 -1
- package/dist/git/watching/watchService.d.ts.map +1 -1
- package/dist/git/watching/watchService.js +18 -3
- package/dist/git/watching/watchService.js.map +1 -1
- package/dist/git/watching/watchSession.d.ts +8 -1
- package/dist/git/watching/watchSession.d.ts.map +1 -1
- package/dist/git/watching/watchSession.js +38 -6
- package/dist/git/watching/watchSession.js.map +1 -1
- package/dist/git/watching/watcherPatterns.d.ts +2 -2
- package/dist/git/watching/watcherPatterns.d.ts.map +1 -1
- package/dist/git/watching/watcherPatterns.js +1 -1
- package/dist/git/watching/watcherPatterns.js.map +1 -1
- package/dist/git-cli/exec/git.d.ts +1 -1
- package/dist/git-cli/exec/git.d.ts.map +1 -1
- package/dist/git-cli/exec/git.js +13 -3
- package/dist/git-cli/exec/git.js.map +1 -1
- package/dist/git-cli/providers/branches.d.ts +19 -0
- package/dist/git-cli/providers/branches.d.ts.map +1 -1
- package/dist/git-cli/providers/branches.js +282 -78
- package/dist/git-cli/providers/branches.js.map +1 -1
- package/dist/git-cli/providers/commits.d.ts +4 -0
- package/dist/git-cli/providers/commits.d.ts.map +1 -1
- package/dist/git-cli/providers/commits.js +84 -11
- package/dist/git-cli/providers/commits.js.map +1 -1
- package/dist/git-cli/providers/config.d.ts +42 -0
- package/dist/git-cli/providers/config.d.ts.map +1 -1
- package/dist/git-cli/providers/config.js +186 -5
- package/dist/git-cli/providers/config.js.map +1 -1
- package/dist/git-cli/providers/contributors.d.ts.map +1 -1
- package/dist/git-cli/providers/contributors.js +1 -1
- package/dist/git-cli/providers/contributors.js.map +1 -1
- package/dist/git-cli/providers/graph.d.ts +2 -2
- package/dist/git-cli/providers/graph.d.ts.map +1 -1
- package/dist/git-cli/providers/graph.js +27 -9
- package/dist/git-cli/providers/graph.js.map +1 -1
- package/dist/git-cli/providers/operations.d.ts.map +1 -1
- package/dist/git-cli/providers/operations.js +40 -12
- package/dist/git-cli/providers/operations.js.map +1 -1
- package/dist/git-cli/providers/pausedOperations.d.ts +5 -0
- package/dist/git-cli/providers/pausedOperations.d.ts.map +1 -1
- package/dist/git-cli/providers/pausedOperations.js +87 -16
- package/dist/git-cli/providers/pausedOperations.js.map +1 -1
- package/dist/git-cli/providers/refs.d.ts +5 -3
- package/dist/git-cli/providers/refs.d.ts.map +1 -1
- package/dist/git-cli/providers/refs.js +33 -4
- package/dist/git-cli/providers/refs.js.map +1 -1
- package/dist/git-cli/providers/status.d.ts +1 -0
- package/dist/git-cli/providers/status.d.ts.map +1 -1
- package/dist/git-cli/providers/status.js +18 -3
- package/dist/git-cli/providers/status.js.map +1 -1
- package/dist/git-cli/providers/worktrees.d.ts.map +1 -1
- package/dist/git-cli/providers/worktrees.js +4 -0
- package/dist/git-cli/providers/worktrees.js.map +1 -1
- package/dist/git-cli/service.d.ts.map +1 -1
- package/dist/git-cli/service.js.map +1 -1
- package/dist/plus/agents/providers/claudeCodeProvider.d.ts +39 -1
- package/dist/plus/agents/providers/claudeCodeProvider.d.ts.map +1 -1
- package/dist/plus/agents/providers/claudeCodeProvider.js +978 -71
- package/dist/plus/agents/providers/claudeCodeProvider.js.map +1 -1
- package/dist/plus/agents/providers/claudeCodeTranscript.d.ts +24 -2
- package/dist/plus/agents/providers/claudeCodeTranscript.d.ts.map +1 -1
- package/dist/plus/agents/providers/claudeCodeTranscript.js +84 -9
- package/dist/plus/agents/providers/claudeCodeTranscript.js.map +1 -1
- package/dist/plus/agents/types.d.ts +37 -2
- package/dist/plus/agents/types.d.ts.map +1 -1
- package/dist/plus/agents/types.js +2 -0
- package/dist/plus/agents/types.js.map +1 -1
- package/dist/plus/ai/errors.d.ts +10 -0
- package/dist/plus/ai/errors.d.ts.map +1 -1
- package/dist/plus/ai/errors.js +29 -0
- package/dist/plus/ai/errors.js.map +1 -1
- package/dist/plus/ai/models/model.d.ts +4 -0
- package/dist/plus/ai/models/model.d.ts.map +1 -1
- package/dist/plus/ai/models/model.js +51 -6
- package/dist/plus/ai/models/model.js.map +1 -1
- package/dist/plus/ai/models/promptTemplates.d.ts +1 -1
- package/dist/plus/ai/models/promptTemplates.d.ts.map +1 -1
- package/dist/plus/ai/models/provider.d.ts +60 -2
- package/dist/plus/ai/models/provider.d.ts.map +1 -1
- package/dist/plus/ai/prompts.d.ts +12 -0
- package/dist/plus/ai/prompts.d.ts.map +1 -1
- package/dist/plus/ai/prompts.js +177 -61
- package/dist/plus/ai/prompts.js.map +1 -1
- package/dist/plus/ai/providers/anthropicProvider.d.ts +10 -2
- package/dist/plus/ai/providers/anthropicProvider.d.ts.map +1 -1
- package/dist/plus/ai/providers/anthropicProvider.js +139 -46
- package/dist/plus/ai/providers/anthropicProvider.js.map +1 -1
- package/dist/plus/ai/providers/deepSeekProvider.d.ts +2 -0
- package/dist/plus/ai/providers/deepSeekProvider.d.ts.map +1 -1
- package/dist/plus/ai/providers/deepSeekProvider.js +10 -21
- package/dist/plus/ai/providers/deepSeekProvider.js.map +1 -1
- package/dist/plus/ai/providers/geminiProvider.d.ts +1 -0
- package/dist/plus/ai/providers/geminiProvider.d.ts.map +1 -1
- package/dist/plus/ai/providers/geminiProvider.js +19 -0
- package/dist/plus/ai/providers/geminiProvider.js.map +1 -1
- package/dist/plus/ai/providers/gitkrakenProvider.d.ts +5 -1
- package/dist/plus/ai/providers/gitkrakenProvider.d.ts.map +1 -1
- package/dist/plus/ai/providers/gitkrakenProvider.js +118 -3
- package/dist/plus/ai/providers/gitkrakenProvider.js.map +1 -1
- package/dist/plus/ai/providers/huggingFaceProvider.d.ts +1 -0
- package/dist/plus/ai/providers/huggingFaceProvider.d.ts.map +1 -1
- package/dist/plus/ai/providers/huggingFaceProvider.js +5 -0
- package/dist/plus/ai/providers/huggingFaceProvider.js.map +1 -1
- package/dist/plus/ai/providers/mistralProvider.d.ts +3 -1
- package/dist/plus/ai/providers/mistralProvider.d.ts.map +1 -1
- package/dist/plus/ai/providers/mistralProvider.js +99 -19
- package/dist/plus/ai/providers/mistralProvider.js.map +1 -1
- package/dist/plus/ai/providers/ollamaProvider.d.ts +4 -3
- package/dist/plus/ai/providers/ollamaProvider.d.ts.map +1 -1
- package/dist/plus/ai/providers/ollamaProvider.js +38 -3
- package/dist/plus/ai/providers/ollamaProvider.js.map +1 -1
- package/dist/plus/ai/providers/openAICompatibleProvider.d.ts +1 -0
- package/dist/plus/ai/providers/openAICompatibleProvider.d.ts.map +1 -1
- package/dist/plus/ai/providers/openAICompatibleProvider.js +4 -0
- package/dist/plus/ai/providers/openAICompatibleProvider.js.map +1 -1
- package/dist/plus/ai/providers/openAICompatibleProviderBase.d.ts +154 -5
- package/dist/plus/ai/providers/openAICompatibleProviderBase.d.ts.map +1 -1
- package/dist/plus/ai/providers/openAICompatibleProviderBase.js +259 -10
- package/dist/plus/ai/providers/openAICompatibleProviderBase.js.map +1 -1
- package/dist/plus/ai/providers/openRouterProvider.d.ts +4 -0
- package/dist/plus/ai/providers/openRouterProvider.d.ts.map +1 -1
- package/dist/plus/ai/providers/openRouterProvider.js +9 -0
- package/dist/plus/ai/providers/openRouterProvider.js.map +1 -1
- package/dist/plus/ai/providers/openaiProvider.d.ts +1 -0
- package/dist/plus/ai/providers/openaiProvider.d.ts.map +1 -1
- package/dist/plus/ai/providers/openaiProvider.js +1 -0
- package/dist/plus/ai/providers/openaiProvider.js.map +1 -1
- package/dist/plus/ai/providers/responseFormatCache.d.ts +8 -0
- package/dist/plus/ai/providers/responseFormatCache.d.ts.map +1 -0
- package/dist/plus/ai/providers/responseFormatCache.js +25 -0
- package/dist/plus/ai/providers/responseFormatCache.js.map +1 -0
- package/dist/plus/ai/providers/xaiProvider.d.ts +1 -0
- package/dist/plus/ai/providers/xaiProvider.d.ts.map +1 -1
- package/dist/plus/ai/providers/xaiProvider.js +10 -1
- package/dist/plus/ai/providers/xaiProvider.js.map +1 -1
- package/dist/plus/ai/utils/ai.utils.d.ts +3 -0
- package/dist/plus/ai/utils/ai.utils.d.ts.map +1 -1
- package/dist/plus/ai/utils/ai.utils.js +13 -0
- package/dist/plus/ai/utils/ai.utils.js.map +1 -1
- package/dist/plus/ai/utils/results.utils.d.ts +16 -2
- package/dist/plus/ai/utils/results.utils.d.ts.map +1 -1
- package/dist/plus/ai/utils/results.utils.js +204 -28
- package/dist/plus/ai/utils/results.utils.js.map +1 -1
- package/dist/plus/git-github/api/github.d.ts +55 -0
- package/dist/plus/git-github/api/github.d.ts.map +1 -1
- package/dist/plus/git-github/api/github.js +177 -4
- package/dist/plus/git-github/api/github.js.map +1 -1
- package/dist/plus/git-github/models.d.ts +16 -0
- package/dist/plus/git-github/models.d.ts.map +1 -1
- package/dist/plus/git-github/models.js +29 -3
- package/dist/plus/git-github/models.js.map +1 -1
- package/dist/plus/git-github/providers/github/status.d.ts +1 -0
- package/dist/plus/git-github/providers/github/status.d.ts.map +1 -1
- package/dist/plus/git-github/providers/github/status.js.map +1 -1
- package/dist/plus/integrations/context.d.ts +4 -0
- package/dist/plus/integrations/context.d.ts.map +1 -1
- package/dist/plus/integrations/index.d.ts.map +1 -1
- package/dist/plus/integrations/index.js +2 -0
- package/dist/plus/integrations/index.js.map +1 -1
- package/dist/plus/integrations/models/gitHostIntegration.d.ts +6 -3
- package/dist/plus/integrations/models/gitHostIntegration.d.ts.map +1 -1
- package/dist/plus/integrations/models/gitHostIntegration.js +12 -2
- package/dist/plus/integrations/models/gitHostIntegration.js.map +1 -1
- package/dist/plus/integrations/models/integration.d.ts +3 -1
- package/dist/plus/integrations/models/integration.d.ts.map +1 -1
- package/dist/plus/integrations/models/integration.js +2 -2
- package/dist/plus/integrations/models/integration.js.map +1 -1
- package/dist/plus/integrations/providers/accounts.d.ts.map +1 -1
- package/dist/plus/integrations/providers/accounts.js +4 -0
- package/dist/plus/integrations/providers/accounts.js.map +1 -1
- package/dist/plus/integrations/providers/azure/models.d.ts.map +1 -1
- package/dist/plus/integrations/providers/azure/models.js +3 -0
- package/dist/plus/integrations/providers/azure/models.js.map +1 -1
- package/dist/plus/integrations/providers/bitbucket/models.d.ts.map +1 -1
- package/dist/plus/integrations/providers/bitbucket/models.js +1 -0
- package/dist/plus/integrations/providers/bitbucket/models.js.map +1 -1
- package/dist/plus/integrations/providers/github.d.ts +14 -2
- package/dist/plus/integrations/providers/github.d.ts.map +1 -1
- package/dist/plus/integrations/providers/github.js +55 -3
- package/dist/plus/integrations/providers/github.js.map +1 -1
- package/dist/plus/integrations/providers/gitlab.d.ts.map +1 -1
- package/dist/plus/integrations/providers/gitlab.js.map +1 -1
- package/dist/plus/integrations/providers/models.d.ts.map +1 -1
- package/dist/plus/integrations/providers/models.js +30 -4
- package/dist/plus/integrations/providers/models.js.map +1 -1
- package/dist/plus/integrations/reads/broaden.d.ts.map +1 -1
- package/dist/plus/integrations/reads/broaden.js +6 -1
- package/dist/plus/integrations/reads/broaden.js.map +1 -1
- package/dist/plus/integrations/reads/drains.d.ts.map +1 -1
- package/dist/plus/integrations/reads/drains.js +7 -4
- package/dist/plus/integrations/reads/drains.js.map +1 -1
- package/dist/plus/integrations/reads/hierarchy.d.ts.map +1 -1
- package/dist/plus/integrations/reads/hierarchy.js +3 -1
- package/dist/plus/integrations/reads/hierarchy.js.map +1 -1
- package/dist/plus/integrations/reads/issueTracker.d.ts.map +1 -1
- package/dist/plus/integrations/reads/issueTracker.js +8 -3
- package/dist/plus/integrations/reads/issueTracker.js.map +1 -1
- package/dist/plus/integrations/reads/issues.d.ts.map +1 -1
- package/dist/plus/integrations/reads/issues.js +9 -4
- package/dist/plus/integrations/reads/issues.js.map +1 -1
- package/dist/plus/integrations/reads/pullRequests.d.ts.map +1 -1
- package/dist/plus/integrations/reads/pullRequests.js +9 -4
- package/dist/plus/integrations/reads/pullRequests.js.map +1 -1
- package/dist/utils/env/browser/base64.d.ts +1 -1
- package/dist/utils/env/browser/base64.d.ts.map +1 -1
- package/dist/utils/env/node/base64.d.ts +1 -1
- package/dist/utils/env/node/base64.d.ts.map +1 -1
- package/dist/utils/env/node/base64.js +2 -0
- package/dist/utils/env/node/base64.js.map +1 -1
- package/dist/utils/keys/chord.d.ts +52 -0
- package/dist/utils/keys/chord.d.ts.map +1 -0
- package/dist/utils/keys/chord.js +135 -0
- package/dist/utils/keys/chord.js.map +1 -0
- package/dist/utils/keys/keybinding.d.ts +53 -0
- package/dist/utils/keys/keybinding.d.ts.map +1 -0
- package/dist/utils/keys/keybinding.js +58 -0
- package/dist/utils/keys/keybinding.js.map +1 -0
- package/dist/utils/path.d.ts +11 -0
- package/dist/utils/path.d.ts.map +1 -1
- package/dist/utils/path.js +13 -0
- package/dist/utils/path.js.map +1 -1
- package/package.json +13 -5
- package/src/git/cache.ts +383 -47
- package/src/git/context.ts +11 -0
- package/src/git/models/fileStatus.ts +1 -0
- package/src/git/models/issue.ts +4 -0
- package/src/git/models/mergeConflicts.ts +3 -2
- package/src/git/models/pullRequest.ts +33 -1
- package/src/git/models/repository.ts +58 -17
- package/src/git/models/statusFile.ts +3 -0
- package/src/git/providers/branches.ts +6 -0
- package/src/git/providers/commits.ts +11 -0
- package/src/git/providers/config.ts +18 -0
- package/src/git/providers/operations.ts +1 -0
- package/src/git/providers/pausedOperations.ts +2 -0
- package/src/git/providers/status.ts +1 -0
- package/src/git/utils/config.utils.ts +8 -0
- package/src/git/utils/issue.utils.ts +2 -0
- package/src/git/utils/pausedOperationStatus.utils.ts +28 -0
- package/src/git/utils/pullRequest.utils.ts +36 -0
- package/src/git/watching/changeEvent.ts +6 -1
- package/src/git/watching/classifyChange.ts +15 -1
- package/src/git/watching/watchService.ts +20 -3
- package/src/git/watching/watchSession.ts +41 -6
- package/src/git/watching/watcherPatterns.ts +1 -1
- package/src/git-cli/exec/git.ts +13 -3
- package/src/git-cli/providers/branches.ts +384 -132
- package/src/git-cli/providers/commits.ts +106 -15
- package/src/git-cli/providers/config.ts +229 -8
- package/src/git-cli/providers/contributors.ts +5 -1
- package/src/git-cli/providers/graph.ts +26 -13
- package/src/git-cli/providers/operations.ts +45 -20
- package/src/git-cli/providers/pausedOperations.ts +109 -17
- package/src/git-cli/providers/refs.ts +33 -3
- package/src/git-cli/providers/status.ts +25 -4
- package/src/git-cli/providers/worktrees.ts +5 -0
- package/src/git-cli/service.ts +0 -1
- package/src/plus/agents/providers/claudeCodeProvider.ts +1130 -87
- package/src/plus/agents/providers/claudeCodeTranscript.ts +95 -9
- package/src/plus/agents/types.ts +46 -2
- package/src/plus/ai/errors.ts +30 -0
- package/src/plus/ai/models/model.ts +56 -6
- package/src/plus/ai/models/promptTemplates.ts +1 -1
- package/src/plus/ai/models/provider.ts +69 -2
- package/src/plus/ai/prompts.ts +186 -61
- package/src/plus/ai/providers/anthropicProvider.ts +155 -47
- package/src/plus/ai/providers/deepSeekProvider.ts +11 -21
- package/src/plus/ai/providers/geminiProvider.ts +19 -0
- package/src/plus/ai/providers/gitkrakenProvider.ts +126 -3
- package/src/plus/ai/providers/huggingFaceProvider.ts +6 -0
- package/src/plus/ai/providers/mistralProvider.ts +102 -19
- package/src/plus/ai/providers/ollamaProvider.ts +55 -4
- package/src/plus/ai/providers/openAICompatibleProvider.ts +5 -0
- package/src/plus/ai/providers/openAICompatibleProviderBase.ts +360 -17
- package/src/plus/ai/providers/openRouterProvider.ts +17 -0
- package/src/plus/ai/providers/openaiProvider.ts +1 -0
- package/src/plus/ai/providers/responseFormatCache.ts +39 -0
- package/src/plus/ai/providers/xaiProvider.ts +10 -1
- package/src/plus/ai/utils/ai.utils.ts +14 -0
- package/src/plus/ai/utils/results.utils.ts +255 -31
- package/src/plus/git-github/api/github.ts +291 -7
- package/src/plus/git-github/models.ts +48 -2
- package/src/plus/git-github/providers/github/status.ts +1 -0
- package/src/plus/integrations/context.ts +4 -0
- package/src/plus/integrations/index.ts +2 -0
- package/src/plus/integrations/models/gitHostIntegration.ts +25 -2
- package/src/plus/integrations/models/integration.ts +23 -13
- package/src/plus/integrations/providers/accounts.ts +4 -0
- package/src/plus/integrations/providers/azure/models.ts +3 -0
- package/src/plus/integrations/providers/bitbucket/models.ts +1 -0
- package/src/plus/integrations/providers/github.ts +85 -1
- package/src/plus/integrations/providers/gitlab.ts +2 -10
- package/src/plus/integrations/providers/models.ts +36 -4
- package/src/plus/integrations/reads/broaden.ts +6 -1
- package/src/plus/integrations/reads/drains.ts +7 -4
- package/src/plus/integrations/reads/hierarchy.ts +3 -1
- package/src/plus/integrations/reads/issueTracker.ts +9 -3
- package/src/plus/integrations/reads/issues.ts +9 -4
- package/src/plus/integrations/reads/pullRequests.ts +9 -4
- package/src/utils/env/browser/base64.ts +1 -1
- package/src/utils/env/node/base64.ts +3 -1
- package/src/utils/keys/chord.ts +184 -0
- package/src/utils/keys/keybinding.ts +116 -0
- package/src/utils/path.ts +14 -0
|
@@ -38,7 +38,7 @@ import {
|
|
|
38
38
|
} from '../../../git/utils/revision.utils.js';
|
|
39
39
|
import { chunk } from '../../../utils/array.js';
|
|
40
40
|
import { base64 } from '../../../utils/base64.js';
|
|
41
|
-
import { CancellationError } from '../../../utils/cancellation.js';
|
|
41
|
+
import { CancellationError, isCancellationError } from '../../../utils/cancellation.js';
|
|
42
42
|
import { trace } from '../../../utils/decorators/log.js';
|
|
43
43
|
import type { Event } from '../../../utils/event.js';
|
|
44
44
|
import { Emitter } from '../../../utils/event.js';
|
|
@@ -231,6 +231,85 @@ title
|
|
|
231
231
|
updatedAt
|
|
232
232
|
url
|
|
233
233
|
`;
|
|
234
|
+
/**
|
|
235
|
+
* Stacked-pull-request selections, appended to a pull request's selection set rather than baked into
|
|
236
|
+
* the fragments below: GitHub Enterprise Server schemas lag github.com, and selecting `stack` there
|
|
237
|
+
* fails the entire query with "Field 'stack' doesn't exist on type 'PullRequest'" — which would take
|
|
238
|
+
* every PR feature down with it, not just stacks. Always add these via `gqlPullRequestStackFragmentFor`.
|
|
239
|
+
*/
|
|
240
|
+
const gqlPullRequestStackFragment = `
|
|
241
|
+
stack {
|
|
242
|
+
id
|
|
243
|
+
number
|
|
244
|
+
size
|
|
245
|
+
baseRefName
|
|
246
|
+
}
|
|
247
|
+
stackEntry {
|
|
248
|
+
position
|
|
249
|
+
}
|
|
250
|
+
`;
|
|
251
|
+
|
|
252
|
+
function gqlPullRequestStackFragmentFor(options?: { baseUrl?: string }): string {
|
|
253
|
+
return isGitHubDotCom(options) ? gqlPullRequestStackFragment : '';
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
/** One layer of a stack, as returned by the stacks REST API. Ordered bottom to top. */
|
|
257
|
+
export interface GitHubStackLayer {
|
|
258
|
+
number: number;
|
|
259
|
+
state: string;
|
|
260
|
+
draft?: boolean;
|
|
261
|
+
merged_at?: string | null;
|
|
262
|
+
head: { ref: string; sha: string };
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
export interface GitHubStackResource {
|
|
266
|
+
id: string;
|
|
267
|
+
number: number;
|
|
268
|
+
/** The stack's trunk — what the bottom member targets. */
|
|
269
|
+
base: { ref: string; sha?: string };
|
|
270
|
+
/** False once every member has merged; such a stack can no longer be extended. */
|
|
271
|
+
open?: boolean;
|
|
272
|
+
/** Members ordered bottom to top. */
|
|
273
|
+
pull_requests: GitHubStackLayer[];
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
/** Result of the asynchronous merge used for stacked pull requests. */
|
|
277
|
+
interface GitHubAsyncMergeResult {
|
|
278
|
+
status: 'pending' | 'merged' | 'enqueued' | 'failed';
|
|
279
|
+
/** Everything but `status` is nested here — flattening it silently loses the poll ticket. */
|
|
280
|
+
details?: {
|
|
281
|
+
/** Always present; on `failed` it is the only explanation of why. */
|
|
282
|
+
message?: string;
|
|
283
|
+
/** Only while `pending` — the ticket to poll. */
|
|
284
|
+
uuid?: string;
|
|
285
|
+
/** Only once `merged`. */
|
|
286
|
+
sha?: string;
|
|
287
|
+
merge_method?: string;
|
|
288
|
+
merge_action?: string;
|
|
289
|
+
expected_head_sha?: string;
|
|
290
|
+
};
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
/**
|
|
294
|
+
* A 409 means a merge request is already in flight and carries its ticket, so it resumes rather than fails.
|
|
295
|
+
*
|
|
296
|
+
* The body has to be dug out of `original`: `requestCore` routes every 4xx through `handleRequestError`,
|
|
297
|
+
* which re-wraps octokit's `RequestError` in a `RequestClientError` carrying only `message` and `original`.
|
|
298
|
+
*/
|
|
299
|
+
function getAsyncMergeUuidFromConflict(ex: unknown): string | undefined {
|
|
300
|
+
const err = (RequestClientError.is(ex) ? ex.original : ex) as
|
|
301
|
+
| { status?: number; response?: { data?: GitHubAsyncMergeResult } }
|
|
302
|
+
| undefined;
|
|
303
|
+
if (err?.status !== 409) return undefined;
|
|
304
|
+
|
|
305
|
+
return err.response?.data?.details?.uuid;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
const asyncMergePollIntervalMs = 2000;
|
|
309
|
+
/** A stack merges one layer at a time and GitHub only promises "a few minutes", so the ceiling is
|
|
310
|
+
* generous — giving up early would report a failure for a merge still in progress. */
|
|
311
|
+
const maxAsyncMergePolls = 300;
|
|
312
|
+
|
|
234
313
|
const gqlPullRequestLiteFragment = `
|
|
235
314
|
${gqlIssueOrPullRequestFragment}
|
|
236
315
|
author {
|
|
@@ -295,6 +374,7 @@ assignees(first: 25) {
|
|
|
295
374
|
url
|
|
296
375
|
}
|
|
297
376
|
}
|
|
377
|
+
changedFiles
|
|
298
378
|
checksUrl
|
|
299
379
|
deletions
|
|
300
380
|
mergeable
|
|
@@ -324,6 +404,7 @@ reviewRequests(first: 25) {
|
|
|
324
404
|
}
|
|
325
405
|
}
|
|
326
406
|
commits(last: 1) {
|
|
407
|
+
totalCount
|
|
327
408
|
nodes {
|
|
328
409
|
commit {
|
|
329
410
|
statusCheckRollup {
|
|
@@ -415,6 +496,7 @@ export class GitHubApi {
|
|
|
415
496
|
|
|
416
497
|
interface QueryResult {
|
|
417
498
|
viewer: {
|
|
499
|
+
databaseId: number | null;
|
|
418
500
|
name: string | null;
|
|
419
501
|
email: string | null;
|
|
420
502
|
login: string | null;
|
|
@@ -425,6 +507,7 @@ export class GitHubApi {
|
|
|
425
507
|
try {
|
|
426
508
|
const query = `query getCurrentAccount($avatarSize: Int) {
|
|
427
509
|
viewer {
|
|
510
|
+
databaseId
|
|
428
511
|
name
|
|
429
512
|
email
|
|
430
513
|
login
|
|
@@ -437,7 +520,10 @@ export class GitHubApi {
|
|
|
437
520
|
|
|
438
521
|
return {
|
|
439
522
|
provider: provider,
|
|
440
|
-
id
|
|
523
|
+
// `id` is the provider's own id, as it is for every other provider, and `username` the handle
|
|
524
|
+
// filters and viewer matching key on. Falls back to the login only when GitHub omits the
|
|
525
|
+
// database id, which leaves the two equal rather than leaving `id` empty.
|
|
526
|
+
id: rsp.viewer.databaseId != null ? String(rsp.viewer.databaseId) : rsp.viewer.login,
|
|
441
527
|
name: rsp.viewer.name ?? undefined,
|
|
442
528
|
email: rsp.viewer.email ?? undefined,
|
|
443
529
|
// If we are GitHub Enterprise, we may need to convert the avatar URL since it might require authentication
|
|
@@ -997,6 +1083,7 @@ export class GitHubApi {
|
|
|
997
1083
|
repository(name: $repo, owner: $owner) {
|
|
998
1084
|
pullRequest(number: $number) {
|
|
999
1085
|
${gqlPullRequestLiteFragment}
|
|
1086
|
+
${gqlPullRequestStackFragmentFor(options)}
|
|
1000
1087
|
}
|
|
1001
1088
|
}
|
|
1002
1089
|
}`;
|
|
@@ -1077,6 +1164,7 @@ export class GitHubApi {
|
|
|
1077
1164
|
associatedPullRequests(first: $limit, orderBy: {field: UPDATED_AT, direction: DESC}, states: $include) {
|
|
1078
1165
|
nodes {
|
|
1079
1166
|
${gqlPullRequestLiteFragment}
|
|
1167
|
+
${gqlPullRequestStackFragmentFor(options)}
|
|
1080
1168
|
}
|
|
1081
1169
|
}
|
|
1082
1170
|
}
|
|
@@ -1170,6 +1258,7 @@ export class GitHubApi {
|
|
|
1170
1258
|
associatedPullRequests(first: 2, orderBy: {field: UPDATED_AT, direction: DESC}) {
|
|
1171
1259
|
nodes {
|
|
1172
1260
|
${gqlPullRequestLiteFragment}
|
|
1261
|
+
${gqlPullRequestStackFragmentFor(options)}
|
|
1173
1262
|
}
|
|
1174
1263
|
}
|
|
1175
1264
|
}
|
|
@@ -3307,6 +3396,40 @@ export class GitHubApi {
|
|
|
3307
3396
|
scope: ScopedLogger | undefined,
|
|
3308
3397
|
cancellation?: AbortSignal | undefined,
|
|
3309
3398
|
): Promise<Endpoints[R]['response']> {
|
|
3399
|
+
return (await this.requestCore(
|
|
3400
|
+
provider,
|
|
3401
|
+
token,
|
|
3402
|
+
route,
|
|
3403
|
+
options,
|
|
3404
|
+
scope,
|
|
3405
|
+
cancellation,
|
|
3406
|
+
)) as Endpoints[R]['response'];
|
|
3407
|
+
}
|
|
3408
|
+
|
|
3409
|
+
/**
|
|
3410
|
+
* REST call for routes `@octokit/types` doesn't describe yet — currently the stacked-pull-request
|
|
3411
|
+
* merge APIs, which are in public preview and absent from the generated endpoint map. Prefer
|
|
3412
|
+
* `request` for anything typed.
|
|
3413
|
+
*/
|
|
3414
|
+
private async requestPreview<T>(
|
|
3415
|
+
provider: Provider | undefined,
|
|
3416
|
+
token: GitHubTokenInfo,
|
|
3417
|
+
route: string,
|
|
3418
|
+
options: RequestParameters | undefined,
|
|
3419
|
+
scope: ScopedLogger | undefined,
|
|
3420
|
+
cancellation?: AbortSignal | undefined,
|
|
3421
|
+
): Promise<T> {
|
|
3422
|
+
return (await this.requestCore(provider, token, route, options, scope, cancellation)) as T;
|
|
3423
|
+
}
|
|
3424
|
+
|
|
3425
|
+
private async requestCore(
|
|
3426
|
+
provider: Provider | undefined,
|
|
3427
|
+
token: GitHubTokenInfo,
|
|
3428
|
+
route: string,
|
|
3429
|
+
options: RequestParameters | undefined,
|
|
3430
|
+
scope: ScopedLogger | undefined,
|
|
3431
|
+
cancellation?: AbortSignal | undefined,
|
|
3432
|
+
): Promise<unknown> {
|
|
3310
3433
|
const { accessToken } = token;
|
|
3311
3434
|
try {
|
|
3312
3435
|
let signal: AbortSignal | undefined;
|
|
@@ -3320,15 +3443,15 @@ export class GitHubApi {
|
|
|
3320
3443
|
// Retry transient gateway/network failures on idempotent reads only
|
|
3321
3444
|
const method = route.split(' ', 1)[0].toUpperCase();
|
|
3322
3445
|
const retryable = method === 'GET' || method === 'HEAD';
|
|
3323
|
-
return
|
|
3446
|
+
return await this.requestWithRetries(
|
|
3324
3447
|
() =>
|
|
3325
3448
|
this.config.wrapForForcedInsecureSSL(provider?.getIgnoreSSLErrors() ?? false, () =>
|
|
3326
|
-
this.getDefaults(accessToken, request)(route
|
|
3449
|
+
this.getDefaults(accessToken, request)(route, options),
|
|
3327
3450
|
),
|
|
3328
3451
|
retryable,
|
|
3329
3452
|
signal,
|
|
3330
3453
|
scope,
|
|
3331
|
-
)
|
|
3454
|
+
);
|
|
3332
3455
|
} catch (ex) {
|
|
3333
3456
|
if (ex instanceof RequestError || ex.name === 'AbortError') {
|
|
3334
3457
|
this.handleRequestError(provider, token, ex, scope);
|
|
@@ -3620,6 +3743,7 @@ export class GitHubApi {
|
|
|
3620
3743
|
nodes {
|
|
3621
3744
|
...on PullRequest {
|
|
3622
3745
|
${options?.summary ? gqlPullRequestLiteFragment : gqlPullRequestFragment}
|
|
3746
|
+
${gqlPullRequestStackFragmentFor(options)}
|
|
3623
3747
|
}
|
|
3624
3748
|
}
|
|
3625
3749
|
}
|
|
@@ -4503,6 +4627,7 @@ export class GitHubApi {
|
|
|
4503
4627
|
nodes {
|
|
4504
4628
|
... on PullRequest {
|
|
4505
4629
|
${gqlPullRequestFragment}
|
|
4630
|
+
${gqlPullRequestStackFragmentFor(options)}
|
|
4506
4631
|
}
|
|
4507
4632
|
}
|
|
4508
4633
|
}`,
|
|
@@ -4655,6 +4780,7 @@ export class GitHubApi {
|
|
|
4655
4780
|
nodes {
|
|
4656
4781
|
...on PullRequest {
|
|
4657
4782
|
${gqlPullRequestFragment}
|
|
4783
|
+
${gqlPullRequestStackFragmentFor(options)}
|
|
4658
4784
|
}
|
|
4659
4785
|
}
|
|
4660
4786
|
}
|
|
@@ -4714,6 +4840,164 @@ export class GitHubApi {
|
|
|
4714
4840
|
}
|
|
4715
4841
|
}
|
|
4716
4842
|
|
|
4843
|
+
/**
|
|
4844
|
+
* Every stack in the repository, each with its members bottom to top.
|
|
4845
|
+
*
|
|
4846
|
+
* One request regardless of how many pull requests are involved — which is what makes it the right
|
|
4847
|
+
* shape for list surfaces, whose pull requests arrive through the shared providers API and so carry no
|
|
4848
|
+
* stack membership of their own. Callers join the result by pull request number.
|
|
4849
|
+
*
|
|
4850
|
+
* A `404` means the repository isn't enrolled in the stacked-pull-requests preview; that's reported as
|
|
4851
|
+
* `undefined` rather than an error, since "no stacks" and "not available" both mean nothing to show.
|
|
4852
|
+
*/
|
|
4853
|
+
@trace({
|
|
4854
|
+
args: (provider, token, owner, repo) => ({
|
|
4855
|
+
provider: provider.name,
|
|
4856
|
+
token: `<token:${token.microHash}>`,
|
|
4857
|
+
owner: owner,
|
|
4858
|
+
repo: repo,
|
|
4859
|
+
}),
|
|
4860
|
+
})
|
|
4861
|
+
async getRepositoryStacks(
|
|
4862
|
+
provider: Provider,
|
|
4863
|
+
token: GitHubTokenInfo,
|
|
4864
|
+
owner: string,
|
|
4865
|
+
repo: string,
|
|
4866
|
+
options?: { baseUrl?: string },
|
|
4867
|
+
cancellation?: AbortSignal,
|
|
4868
|
+
): Promise<GitHubStackResource[] | undefined> {
|
|
4869
|
+
const scope = getScopedLogger();
|
|
4870
|
+
|
|
4871
|
+
try {
|
|
4872
|
+
const rsp = await this.requestPreview<{ data: GitHubStackResource[] }>(
|
|
4873
|
+
provider,
|
|
4874
|
+
token,
|
|
4875
|
+
'GET /repos/{owner}/{repo}/stacks',
|
|
4876
|
+
{ owner: owner, repo: repo, baseUrl: options?.baseUrl },
|
|
4877
|
+
scope,
|
|
4878
|
+
cancellation,
|
|
4879
|
+
);
|
|
4880
|
+
|
|
4881
|
+
return rsp.data;
|
|
4882
|
+
} catch (ex) {
|
|
4883
|
+
if (isCancellationError(ex)) throw ex;
|
|
4884
|
+
|
|
4885
|
+
Logger.warn(scope, `Unable to list stacks for ${owner}/${repo}: ${ex}`);
|
|
4886
|
+
return undefined;
|
|
4887
|
+
}
|
|
4888
|
+
}
|
|
4889
|
+
|
|
4890
|
+
/**
|
|
4891
|
+
* Merges a stacked pull request, and with it every layer below it.
|
|
4892
|
+
*
|
|
4893
|
+
* Stacks cannot go through `mergePullRequest` — GitHub rejects stacked pull requests on the legacy
|
|
4894
|
+
* synchronous merge endpoints and mutations. The replacement is asynchronous: submit, then poll a
|
|
4895
|
+
* ticket until it reaches a terminal state.
|
|
4896
|
+
*/
|
|
4897
|
+
@trace({
|
|
4898
|
+
args: (provider, token, owner, repo, pullNumber, expectedSourceSha) => ({
|
|
4899
|
+
provider: provider.name,
|
|
4900
|
+
token: `<token:${token.microHash}>`,
|
|
4901
|
+
owner: owner,
|
|
4902
|
+
repo: repo,
|
|
4903
|
+
pullNumber: pullNumber,
|
|
4904
|
+
expectedSourceSha: expectedSourceSha,
|
|
4905
|
+
}),
|
|
4906
|
+
})
|
|
4907
|
+
async mergeStackedPullRequest(
|
|
4908
|
+
provider: Provider,
|
|
4909
|
+
token: GitHubTokenInfo,
|
|
4910
|
+
owner: string,
|
|
4911
|
+
repo: string,
|
|
4912
|
+
pullNumber: number,
|
|
4913
|
+
expectedSourceSha: string,
|
|
4914
|
+
options?: { mergeMethod?: PullRequestMergeMethod; baseUrl?: string },
|
|
4915
|
+
cancellation?: AbortSignal,
|
|
4916
|
+
): Promise<boolean> {
|
|
4917
|
+
const scope = getScopedLogger();
|
|
4918
|
+
|
|
4919
|
+
try {
|
|
4920
|
+
let uuid: string | undefined;
|
|
4921
|
+
|
|
4922
|
+
try {
|
|
4923
|
+
const submitted = await this.requestPreview<{ data: GitHubAsyncMergeResult }>(
|
|
4924
|
+
provider,
|
|
4925
|
+
token,
|
|
4926
|
+
'PUT /repos/{owner}/{repo}/pulls/{pull_number}/merge-async',
|
|
4927
|
+
{
|
|
4928
|
+
owner: owner,
|
|
4929
|
+
repo: repo,
|
|
4930
|
+
pull_number: pullNumber,
|
|
4931
|
+
sha: expectedSourceSha,
|
|
4932
|
+
merge_method: options?.mergeMethod,
|
|
4933
|
+
baseUrl: options?.baseUrl,
|
|
4934
|
+
},
|
|
4935
|
+
scope,
|
|
4936
|
+
cancellation,
|
|
4937
|
+
);
|
|
4938
|
+
|
|
4939
|
+
// Already merged or rejected outright — nothing to poll for. `enqueued` lands via the merge
|
|
4940
|
+
// queue, which can take several merge groups to settle, so it's transitional like `pending`.
|
|
4941
|
+
if (submitted.data.status !== 'pending' && submitted.data.status !== 'enqueued') {
|
|
4942
|
+
if (submitted.data.status === 'failed') {
|
|
4943
|
+
Logger.warn(
|
|
4944
|
+
scope,
|
|
4945
|
+
`Stacked merge refused: ${submitted.data.details?.message ?? 'no reason given'}`,
|
|
4946
|
+
);
|
|
4947
|
+
}
|
|
4948
|
+
return submitted.data.status === 'merged';
|
|
4949
|
+
}
|
|
4950
|
+
|
|
4951
|
+
uuid = submitted.data.details?.uuid;
|
|
4952
|
+
} catch (ex) {
|
|
4953
|
+
// A merge request is already in flight (a retry, or a double-click) — adopt its ticket and
|
|
4954
|
+
// poll that instead of reporting a failure for a merge that is actually running.
|
|
4955
|
+
uuid = getAsyncMergeUuidFromConflict(ex);
|
|
4956
|
+
if (uuid == null) throw ex;
|
|
4957
|
+
}
|
|
4958
|
+
|
|
4959
|
+
if (uuid == null) return false;
|
|
4960
|
+
|
|
4961
|
+
// The stack merges server-side one layer at a time, so this can take a while. Poll on a
|
|
4962
|
+
// fixed interval and give up rather than hang forever if the ticket never settles.
|
|
4963
|
+
for (let attempt = 0; attempt < maxAsyncMergePolls; attempt++) {
|
|
4964
|
+
if (cancellation?.aborted) throw new CancellationError();
|
|
4965
|
+
|
|
4966
|
+
await new Promise(resolve => setTimeout(resolve, asyncMergePollIntervalMs));
|
|
4967
|
+
|
|
4968
|
+
const polled = await this.requestPreview<{ data: GitHubAsyncMergeResult }>(
|
|
4969
|
+
provider,
|
|
4970
|
+
token,
|
|
4971
|
+
'GET /repos/{owner}/{repo}/pulls/{pull_number}/merge-async/{uuid}',
|
|
4972
|
+
{
|
|
4973
|
+
owner: owner,
|
|
4974
|
+
repo: repo,
|
|
4975
|
+
pull_number: pullNumber,
|
|
4976
|
+
uuid: uuid,
|
|
4977
|
+
baseUrl: options?.baseUrl,
|
|
4978
|
+
},
|
|
4979
|
+
scope,
|
|
4980
|
+
cancellation,
|
|
4981
|
+
);
|
|
4982
|
+
|
|
4983
|
+
if (polled.data.status === 'pending' || polled.data.status === 'enqueued') continue;
|
|
4984
|
+
|
|
4985
|
+
if (polled.data.status === 'failed') {
|
|
4986
|
+
Logger.warn(scope, `Stacked merge failed: ${polled.data.details?.message ?? 'no reason given'}`);
|
|
4987
|
+
}
|
|
4988
|
+
return polled.data.status === 'merged';
|
|
4989
|
+
}
|
|
4990
|
+
|
|
4991
|
+
Logger.warn(scope, `Timed out waiting for stacked merge of ${owner}/${repo}#${pullNumber}`);
|
|
4992
|
+
return false;
|
|
4993
|
+
} catch (ex) {
|
|
4994
|
+
if (isCancellationError(ex)) throw ex;
|
|
4995
|
+
|
|
4996
|
+
Logger.error(ex, scope);
|
|
4997
|
+
throw this.handleException(ex, provider, scope);
|
|
4998
|
+
}
|
|
4999
|
+
}
|
|
5000
|
+
|
|
4717
5001
|
@trace({
|
|
4718
5002
|
args: (provider, token, nodeId, expectedSourceSha) => ({
|
|
4719
5003
|
provider: provider.name,
|
|
@@ -4732,7 +5016,7 @@ export class GitHubApi {
|
|
|
4732
5016
|
): Promise<boolean> {
|
|
4733
5017
|
const scope = getScopedLogger();
|
|
4734
5018
|
interface QueryResult {
|
|
4735
|
-
pullRequest:
|
|
5019
|
+
mergePullRequest: { pullRequest: { id: string } | null | undefined } | null | undefined;
|
|
4736
5020
|
}
|
|
4737
5021
|
|
|
4738
5022
|
let githubMergeStrategy;
|
|
@@ -4780,7 +5064,7 @@ export class GitHubApi {
|
|
|
4780
5064
|
cancellation,
|
|
4781
5065
|
);
|
|
4782
5066
|
|
|
4783
|
-
return rsp?.pullRequest?.id === nodeId;
|
|
5067
|
+
return rsp?.mergePullRequest?.pullRequest?.id === nodeId;
|
|
4784
5068
|
} catch (ex) {
|
|
4785
5069
|
throw this.handleException(ex, provider, scope);
|
|
4786
5070
|
}
|
|
@@ -2,7 +2,7 @@ import type { Endpoints } from '@octokit/types';
|
|
|
2
2
|
import { GitFileIndexStatus } from '../../git/models/fileStatus.js';
|
|
3
3
|
import type { IssueLabel } from '../../git/models/issue.js';
|
|
4
4
|
import { Issue, RepositoryAccessLevel } from '../../git/models/issue.js';
|
|
5
|
-
import type { PullRequestMember, PullRequestState } from '../../git/models/pullRequest.js';
|
|
5
|
+
import type { PullRequestMember, PullRequestStackInfo, PullRequestState } from '../../git/models/pullRequest.js';
|
|
6
6
|
import {
|
|
7
7
|
PullRequest,
|
|
8
8
|
PullRequestMergeableState,
|
|
@@ -165,6 +165,20 @@ export interface GitHubPullRequestLite extends Omit<GitHubIssueOrPullRequest, '_
|
|
|
165
165
|
url: string;
|
|
166
166
|
viewerPermission: GitHubViewerPermission;
|
|
167
167
|
};
|
|
168
|
+
|
|
169
|
+
/** Only selected against github.com — GitHub Enterprise Server schemas lag and reject the field. */
|
|
170
|
+
stack?: GitHubPullRequestStack | null;
|
|
171
|
+
/** Only selected against github.com — see `stack`. */
|
|
172
|
+
stackEntry?: { position: number } | null;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/** GitHub's stacked-pull-request object. Read-only; all stack mutations are REST-only. */
|
|
176
|
+
export interface GitHubPullRequestStack {
|
|
177
|
+
id: string;
|
|
178
|
+
number: number;
|
|
179
|
+
size: number;
|
|
180
|
+
/** The branch the bottom of the stack targets — the stack's trunk. */
|
|
181
|
+
baseRefName: string;
|
|
168
182
|
}
|
|
169
183
|
|
|
170
184
|
export interface GitHubIssue extends Omit<GitHubIssueOrPullRequest, '__typename'> {
|
|
@@ -206,6 +220,7 @@ export interface GitHubPullRequest extends GitHubPullRequestLite {
|
|
|
206
220
|
assignees: {
|
|
207
221
|
nodes: GitHubMember[];
|
|
208
222
|
};
|
|
223
|
+
changedFiles: number;
|
|
209
224
|
checksUrl: string;
|
|
210
225
|
deletions: number;
|
|
211
226
|
mergeable: GitHubPullRequestMergeableState;
|
|
@@ -226,6 +241,7 @@ export interface GitHubPullRequest extends GitHubPullRequestLite {
|
|
|
226
241
|
}[];
|
|
227
242
|
};
|
|
228
243
|
commits: {
|
|
244
|
+
totalCount: number;
|
|
229
245
|
nodes: {
|
|
230
246
|
commit: {
|
|
231
247
|
statusCheckRollup: {
|
|
@@ -250,7 +266,13 @@ export type GitHubViewerPermission =
|
|
|
250
266
|
function fromGitHubMemberOrGhost(member: GitHubMember | null | undefined): PullRequestMember {
|
|
251
267
|
if (member == null) return { id: 'ghost', name: 'ghost' };
|
|
252
268
|
|
|
253
|
-
return {
|
|
269
|
+
return {
|
|
270
|
+
id: member.login,
|
|
271
|
+
name: member.login,
|
|
272
|
+
username: member.login,
|
|
273
|
+
avatarUrl: member.avatarUrl,
|
|
274
|
+
url: member.url,
|
|
275
|
+
};
|
|
254
276
|
}
|
|
255
277
|
|
|
256
278
|
export function fromGitHubPullRequestLite(pr: GitHubPullRequestLite, provider: Provider): PullRequest {
|
|
@@ -299,6 +321,7 @@ export function fromGitHubPullRequestLite(pr: GitHubPullRequestLite, provider: P
|
|
|
299
321
|
isCrossRepository: pr.isCrossRepository,
|
|
300
322
|
},
|
|
301
323
|
pr.isDraft,
|
|
324
|
+
// The lite fragment selects nothing between `isDraft` and `stack`.
|
|
302
325
|
undefined, // additions
|
|
303
326
|
undefined, // deletions
|
|
304
327
|
undefined, // commentsCount
|
|
@@ -310,10 +333,26 @@ export function fromGitHubPullRequestLite(pr: GitHubPullRequestLite, provider: P
|
|
|
310
333
|
undefined, // statusCheckRollupState
|
|
311
334
|
undefined, // project
|
|
312
335
|
undefined, // version
|
|
336
|
+
undefined, // commitCount
|
|
337
|
+
fromGitHubPullRequestStack(pr),
|
|
338
|
+
undefined, // filesChanged
|
|
313
339
|
pr.body ?? undefined,
|
|
314
340
|
);
|
|
315
341
|
}
|
|
316
342
|
|
|
343
|
+
/** Both fields are absent on GitHub Enterprise Server (never selected) and `null` when unstacked. */
|
|
344
|
+
function fromGitHubPullRequestStack(pr: GitHubPullRequestLite): PullRequestStackInfo | undefined {
|
|
345
|
+
if (pr.stack == null || pr.stackEntry == null) return undefined;
|
|
346
|
+
|
|
347
|
+
return {
|
|
348
|
+
id: pr.stack.id,
|
|
349
|
+
number: pr.stack.number,
|
|
350
|
+
size: pr.stack.size,
|
|
351
|
+
position: pr.stackEntry.position,
|
|
352
|
+
baseRef: pr.stack.baseRefName,
|
|
353
|
+
};
|
|
354
|
+
}
|
|
355
|
+
|
|
317
356
|
export function fromGitHubIssueOrPullRequestState(state: GitHubPullRequestState): PullRequestState {
|
|
318
357
|
return state === 'MERGED' ? 'merged' : state === 'CLOSED' ? 'closed' : 'opened';
|
|
319
358
|
}
|
|
@@ -482,6 +521,7 @@ export function fromGitHubPullRequest(pr: GitHubPullRequest, provider: Provider)
|
|
|
482
521
|
reviewer: {
|
|
483
522
|
id: r.requestedReviewer.login,
|
|
484
523
|
name: r.requestedReviewer.login,
|
|
524
|
+
username: r.requestedReviewer.login,
|
|
485
525
|
avatarUrl: r.requestedReviewer.avatarUrl,
|
|
486
526
|
url: r.requestedReviewer.url,
|
|
487
527
|
},
|
|
@@ -498,12 +538,16 @@ export function fromGitHubPullRequest(pr: GitHubPullRequest, provider: Provider)
|
|
|
498
538
|
pr.assignees.nodes.map(r => ({
|
|
499
539
|
id: r.login,
|
|
500
540
|
name: r.login,
|
|
541
|
+
username: r.login,
|
|
501
542
|
avatarUrl: r.avatarUrl,
|
|
502
543
|
url: r.url,
|
|
503
544
|
})),
|
|
504
545
|
fromGitHubPullRequestStatusCheckRollupState(pr.commits.nodes?.[0]?.commit.statusCheckRollup?.state),
|
|
505
546
|
undefined, // project
|
|
506
547
|
undefined, // version
|
|
548
|
+
pr.commits.totalCount,
|
|
549
|
+
fromGitHubPullRequestStack(pr),
|
|
550
|
+
pr.changedFiles,
|
|
507
551
|
pr.body ?? undefined,
|
|
508
552
|
);
|
|
509
553
|
}
|
|
@@ -529,12 +573,14 @@ export function fromGitHubIssue(value: GitHubIssue, provider: Provider): Issue {
|
|
|
529
573
|
: {
|
|
530
574
|
id: value.author.login,
|
|
531
575
|
name: value.author.login,
|
|
576
|
+
username: value.author.login,
|
|
532
577
|
avatarUrl: value.author.avatarUrl,
|
|
533
578
|
url: value.author.url,
|
|
534
579
|
},
|
|
535
580
|
value.assignees.nodes.map(assignee => ({
|
|
536
581
|
id: assignee.login,
|
|
537
582
|
name: assignee.login,
|
|
583
|
+
username: assignee.login,
|
|
538
584
|
avatarUrl: assignee.avatarUrl,
|
|
539
585
|
url: assignee.url,
|
|
540
586
|
})),
|
|
@@ -155,6 +155,10 @@ export interface IntegrationCacheProvider {
|
|
|
155
155
|
cacheable: Cacheable<Account>,
|
|
156
156
|
options?: CacheExpiryOptions & { connectionId?: string; etag?: string },
|
|
157
157
|
): CacheResult<Account>;
|
|
158
|
+
/** Evicts every cached pull request. A merge invalidates more than the merged pull request alone —
|
|
159
|
+
* a stacked merge lands every layer below it and retargets every layer above — and no caller can
|
|
160
|
+
* name that full set. */
|
|
161
|
+
deletePullRequests(): void;
|
|
158
162
|
}
|
|
159
163
|
|
|
160
164
|
/**
|
|
@@ -73,6 +73,8 @@ const uncachedIntegrationCacheProvider: IntegrationCacheProvider = {
|
|
|
73
73
|
getIssueOrPullRequest: (_id, _type, _resource, _integration, loader) => loadUncached(loader),
|
|
74
74
|
getIssue: (_id, _resource, _integration, loader) => loadUncached(loader),
|
|
75
75
|
getCurrentAccount: (_integration, loader) => loadUncached(loader),
|
|
76
|
+
// Nothing is cached, so there is nothing to evict.
|
|
77
|
+
deletePullRequests: () => {},
|
|
76
78
|
};
|
|
77
79
|
|
|
78
80
|
function toIntegrationCacheProvider(cache: IntegrationManagerCacheProvider | undefined): IntegrationCacheProvider {
|
|
@@ -7,11 +7,13 @@ import type {
|
|
|
7
7
|
PullRequest,
|
|
8
8
|
PullRequestMergeMethod,
|
|
9
9
|
PullRequestSearchCriteria,
|
|
10
|
+
PullRequestStackInfo,
|
|
10
11
|
PullRequestStateFilter,
|
|
11
12
|
} from '../../../git/models/pullRequest.js';
|
|
12
13
|
import type { RepositoryMetadata } from '../../../git/models/repositoryMetadata.js';
|
|
13
14
|
import type { ResourceDescriptor } from '../../../git/models/resourceDescriptor.js';
|
|
14
15
|
import type { PullRequestUrlIdentity } from '../../../git/utils/pullRequest.utils.js';
|
|
16
|
+
import { isCancellationError } from '../../../utils/cancellation.js';
|
|
15
17
|
import { gate } from '../../../utils/decorators/gate.js';
|
|
16
18
|
import { trace } from '../../../utils/decorators/log.js';
|
|
17
19
|
import { first } from '../../../utils/iterable.js';
|
|
@@ -267,6 +269,14 @@ export abstract class GitHostIntegration<
|
|
|
267
269
|
connectionId?: string;
|
|
268
270
|
}): Promise<ProviderRepository | undefined>;
|
|
269
271
|
|
|
272
|
+
/** Stack membership for every stacked pull request in the repository, keyed by pull request number.
|
|
273
|
+
* Only hosts with a stacks concept implement this (currently GitHub). */
|
|
274
|
+
getStacksByPullRequestNumber?(
|
|
275
|
+
owner: string,
|
|
276
|
+
repo: string,
|
|
277
|
+
cancellation?: AbortSignal,
|
|
278
|
+
): Promise<Map<number, PullRequestStackInfo> | undefined>;
|
|
279
|
+
|
|
270
280
|
protected abstract getProviderDefaultBranch(
|
|
271
281
|
{ accessToken }: ProviderAuthenticationSession,
|
|
272
282
|
repo: T,
|
|
@@ -514,7 +524,11 @@ export abstract class GitHostIntegration<
|
|
|
514
524
|
options?: { cursor?: string },
|
|
515
525
|
): Promise<ProviderHierarchyResult<ProviderRepository> | undefined>;
|
|
516
526
|
|
|
517
|
-
async mergePullRequest(
|
|
527
|
+
async mergePullRequest(
|
|
528
|
+
pr: PullRequest,
|
|
529
|
+
options?: { mergeMethod?: PullRequestMergeMethod },
|
|
530
|
+
cancellation?: AbortSignal,
|
|
531
|
+
): Promise<boolean> {
|
|
518
532
|
const scope = getScopedLogger();
|
|
519
533
|
|
|
520
534
|
const connected = this.maybeConnected ?? (await this.isConnected());
|
|
@@ -523,12 +537,20 @@ export abstract class GitHostIntegration<
|
|
|
523
537
|
await this.refreshSessionIfExpired(scope);
|
|
524
538
|
|
|
525
539
|
try {
|
|
526
|
-
const result = await this.mergeProviderPullRequest(this._session!, pr, options);
|
|
540
|
+
const result = await this.mergeProviderPullRequest(this._session!, pr, options, cancellation);
|
|
527
541
|
this.resetRequestExceptionCount('mergePullRequest');
|
|
528
542
|
return result;
|
|
529
543
|
} catch (ex) {
|
|
544
|
+
if (isCancellationError(ex)) return false;
|
|
545
|
+
|
|
530
546
|
this.handleProviderException('mergePullRequest', ex, { scope: scope });
|
|
531
547
|
return false;
|
|
548
|
+
} finally {
|
|
549
|
+
// A merge attempt just changed the state of more than this pull request on the server (a
|
|
550
|
+
// stacked merge lands every layer below and retargets every layer above) whether it succeeded
|
|
551
|
+
// or failed partway through — so cached pull requests can't be trusted either way. Without
|
|
552
|
+
// this, ref pills and branch enrichment keep serving the pre-merge object until its expiry.
|
|
553
|
+
this.ctx.cache.deletePullRequests();
|
|
532
554
|
}
|
|
533
555
|
}
|
|
534
556
|
|
|
@@ -536,6 +558,7 @@ export abstract class GitHostIntegration<
|
|
|
536
558
|
session: ProviderAuthenticationSession,
|
|
537
559
|
pr: PullRequest,
|
|
538
560
|
options?: { mergeMethod?: PullRequestMergeMethod },
|
|
561
|
+
cancellation?: AbortSignal,
|
|
539
562
|
): Promise<boolean>;
|
|
540
563
|
|
|
541
564
|
@trace()
|