From a562b24b8281fa647da505df1cec9fbe2ee8235f Mon Sep 17 00:00:00 2001 From: felix bear Date: Tue, 9 Jun 2026 18:28:05 +0900 Subject: [PATCH] feat(github): configure issue provider api base url #5749 (#8183) Co-authored-by: cocojojo5213 --- .../github-issue-provider/i18n/en.json | 1 + .../github-issue-provider/src/plugin.ts | 31 ++++++++++++++----- 2 files changed, 24 insertions(+), 8 deletions(-) diff --git a/packages/plugin-dev/github-issue-provider/i18n/en.json b/packages/plugin-dev/github-issue-provider/i18n/en.json index 912c7c73bb..291c658a1f 100644 --- a/packages/plugin-dev/github-issue-provider/i18n/en.json +++ b/packages/plugin-dev/github-issue-provider/i18n/en.json @@ -2,6 +2,7 @@ "CFG": { "REPO": "Repository (owner/repo)", "TOKEN": "Personal Access Token (required for private repos/optional for public repos)", + "API_BASE_URL": "GitHub API base URL (default: https://api.github.com)", "FILTER_USERNAME": "Filter username (ignore own comments for update detection)", "BACKLOG_QUERY": "Backlog query (default: \"sort:updated state:open assignee:@me\" with token, otherwise \"sort:updated state:open\" — without a token all open issues are imported, not just yours)", "INCLUDE_PULL_REQUESTS": "Include pull requests (search and backlog return PRs alongside issues)", diff --git a/packages/plugin-dev/github-issue-provider/src/plugin.ts b/packages/plugin-dev/github-issue-provider/src/plugin.ts index f506ec3cb2..47ad3310b3 100644 --- a/packages/plugin-dev/github-issue-provider/src/plugin.ts +++ b/packages/plugin-dev/github-issue-provider/src/plugin.ts @@ -11,11 +11,12 @@ declare const PluginAPI: { translate(key: string, params?: Record): string; }; -const API_BASE = 'https://api.github.com'; +const DEFAULT_API_BASE = 'https://api.github.com'; interface GithubConfig { repo: string; token?: string; + apiBaseUrl?: string; filterUsername?: string; backlogQuery?: string; includePullRequests?: boolean; @@ -81,6 +82,9 @@ const parseRepo = (config: GithubConfig): { owner: string; repo: string } => { return { owner: parts[0], repo: parts[1] }; }; +const getApiBaseUrl = (config: GithubConfig): string => + (config.apiBaseUrl || '').trim().replace(/\/+$/, '') || DEFAULT_API_BASE; + const mapSearchResult = (issue: GithubIssueResponse): PluginSearchResult => ({ id: String(issue.number), title: `#${issue.number} ${issue.title}`, @@ -132,6 +136,13 @@ PluginAPI.registerIssueProvider({ label: t('CFG.HOW_TO_GET_TOKEN'), url: 'https://github.com/super-productivity/super-productivity/blob/master/docs/github-access-token-instructions.md', }, + { + key: 'apiBaseUrl', + type: 'input', + label: t('CFG.API_BASE_URL'), + required: false, + advanced: true, + }, { key: 'filterUsername', type: 'input', @@ -178,7 +189,7 @@ PluginAPI.registerIssueProvider({ searchTerm.includes('is:issue') || searchTerm.includes('is:pull-request'); const typeFilter = hasTypeFilter || cfg.includePullRequests ? '' : ' is:issue'; const q = encodeGithubQuery(`repo:${owner}/${repo}${typeFilter} ${searchTerm}`); - const url = `${API_BASE}/search/issues?q=${q}&per_page=50&advanced_search=true`; + const url = `${getApiBaseUrl(cfg)}/search/issues?q=${q}&per_page=50&advanced_search=true`; const response = await http.get(url); return (response.items || []).map(mapSearchResult); }, @@ -190,7 +201,7 @@ PluginAPI.registerIssueProvider({ ): Promise { const cfg = config as unknown as GithubConfig; const { owner, repo } = parseRepo(cfg); - const issueUrl = `${API_BASE}/repos/${owner}/${repo}/issues/${issueId}`; + const issueUrl = `${getApiBaseUrl(cfg)}/repos/${owner}/${repo}/issues/${issueId}`; const issue = await http.get(issueUrl); const labels = (issue.labels || []).map((l) => (typeof l === 'string' ? l : l.name)); @@ -261,9 +272,10 @@ PluginAPI.registerIssueProvider({ config: Record, http: PluginHttp, ): Promise { - const { owner, repo } = parseRepo(config as unknown as GithubConfig); + const cfg = config as unknown as GithubConfig; + const { owner, repo } = parseRepo(cfg); try { - await http.get(`${API_BASE}/repos/${owner}/${repo}`); + await http.get(`${getApiBaseUrl(cfg)}/repos/${owner}/${repo}`); return true; } catch { return false; @@ -284,7 +296,7 @@ PluginAPI.registerIssueProvider({ (cfg.token ? 'sort:updated state:open assignee:@me' : 'sort:updated state:open'); const typeFilter = cfg.includePullRequests ? '' : ' is:issue'; const q = encodeGithubQuery(`repo:${owner}/${repo}${typeFilter} ${query}`); - const url = `${API_BASE}/search/issues?q=${q}&per_page=50&advanced_search=true`; + const url = `${getApiBaseUrl(cfg)}/search/issues?q=${q}&per_page=50&advanced_search=true`; const response = await http.get(url); return (response.items || []).map(mapSearchResult); }, @@ -358,7 +370,10 @@ PluginAPI.registerIssueProvider({ } const { owner, repo } = parseRepo(cfg); try { - await http.patch(`${API_BASE}/repos/${owner}/${repo}/issues/${id}`, changes); + await http.patch( + `${getApiBaseUrl(cfg)}/repos/${owner}/${repo}/issues/${id}`, + changes, + ); } catch (e) { throw isAuthOrNotFoundError(e) ? new Error(t('ERRORS.INSUFFICIENT_PERMISSIONS')) @@ -379,7 +394,7 @@ PluginAPI.registerIssueProvider({ let response: GithubIssueResponse; try { response = await http.post( - `${API_BASE}/repos/${owner}/${repo}/issues`, + `${getApiBaseUrl(cfg)}/repos/${owner}/${repo}/issues`, { title }, ); } catch (e) {