From 47ebd16733b4e89b25193145c288e445f2510352 Mon Sep 17 00:00:00 2001 From: Trang Le Date: Mon, 27 Sep 2021 11:46:20 +0700 Subject: [PATCH 01/62] feat: add helper for fetching default branch from Github --- packages/netlify-cms-backend-github/src/API.ts | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/packages/netlify-cms-backend-github/src/API.ts b/packages/netlify-cms-backend-github/src/API.ts index 3472dd858fd3..108fc6589737 100644 --- a/packages/netlify-cms-backend-github/src/API.ts +++ b/packages/netlify-cms-backend-github/src/API.ts @@ -42,6 +42,7 @@ type GitHubCompareCommit = Octokit.ReposCompareCommitsResponseCommitsItem; type GitHubAuthor = Octokit.GitCreateCommitResponseAuthor; type GitHubCommitter = Octokit.GitCreateCommitResponseCommitter; type GitHubPull = Octokit.PullsListResponseItem; +type GithubRepo = Octokit.ReposGetResponse export const API_NAME = 'GitHub'; @@ -1188,6 +1189,18 @@ export default class API { return result; } + async newGetDefaultBranch() { + try { + const result: GithubRepo = await this.request( + `${this.originRepoURL}` + ) + return result.default_branch + } catch (e) { + console.error('Problem fetching repo data from Github') + return null + } + } + async backupBranch(branchName: string) { try { const existingBranch = await this.getBranch(branchName); From 61904c8a8d4937b5b3df5ff43d093b9f081df34e Mon Sep 17 00:00:00 2001 From: Trang Le Date: Mon, 27 Sep 2021 11:59:13 +0700 Subject: [PATCH 02/62] feat: add method for setting default branch --- .../src/implementation.tsx | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/packages/netlify-cms-backend-github/src/implementation.tsx b/packages/netlify-cms-backend-github/src/implementation.tsx index 4b4e1b3c590e..b6fbb53ab701 100644 --- a/packages/netlify-cms-backend-github/src/implementation.tsx +++ b/packages/netlify-cms-backend-github/src/implementation.tsx @@ -180,6 +180,20 @@ export default class GitHub implements Implementation { : this.authenticate(user); } + async setDefaultBranch() { + try { + const masterBranch = await this.api!.getBranch('master') + if (!masterBranch) { + // Get default branch of the repo + const defaultBranch = await this.api!.newGetDefaultBranch() + this.branch = defaultBranch || '' + } else { + this.branch = 'master' + } + } catch (e) { + console.warn(e) + } + } async pollUntilForkExists({ repo, token }: { repo: string; token: string }) { const pollDelay = 250; // milliseconds let repoExists = false; From c3f1fc080d0f54db692fabeb9078f0187ee093d1 Mon Sep 17 00:00:00 2001 From: Trang Le Date: Mon, 27 Sep 2021 16:09:25 +0700 Subject: [PATCH 03/62] fix: set default branch after user has authenticated successfully --- .../netlify-cms-backend-github/src/implementation.tsx | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/packages/netlify-cms-backend-github/src/implementation.tsx b/packages/netlify-cms-backend-github/src/implementation.tsx index b6fbb53ab701..f41ca6282670 100644 --- a/packages/netlify-cms-backend-github/src/implementation.tsx +++ b/packages/netlify-cms-backend-github/src/implementation.tsx @@ -116,7 +116,7 @@ export default class GitHub implements Implementation { this.repo = this.originRepo = config.backend.repo || ''; } this.alwaysForkEnabled = config.backend.always_fork || false; - this.branch = config.backend.branch?.trim() || 'master'; + this.branch = config.backend.branch?.trim() || ''; this.apiRoot = config.backend.api_root || 'https://api.github.com'; this.token = ''; this.squashMerges = config.backend.squash_merges || false; @@ -345,7 +345,14 @@ export default class GitHub implements Implementation { if (!isCollab) { throw new Error('Your GitHub user account does not have access to this repo.'); } + // In the constructor, `this.branch` is set by reading the config file + // If it is an empty string at this point, + // it means there is no `branch` property set in the config + if (this.branch === '') { + await this.setDefaultBranch() + } + // Authorized user return { ...user, token: state.token as string, useOpenAuthoring: this.useOpenAuthoring }; } From 90c9f9cbab743a884a958f36e4f2e0a5df3ba5b8 Mon Sep 17 00:00:00 2001 From: Trang Le Date: Mon, 27 Sep 2021 16:25:56 +0700 Subject: [PATCH 04/62] fix: format code --- .../netlify-cms-backend-github/src/API.ts | 12 +++++----- .../src/implementation.tsx | 22 +++++++++---------- 2 files changed, 16 insertions(+), 18 deletions(-) diff --git a/packages/netlify-cms-backend-github/src/API.ts b/packages/netlify-cms-backend-github/src/API.ts index 108fc6589737..92d07aacfcc4 100644 --- a/packages/netlify-cms-backend-github/src/API.ts +++ b/packages/netlify-cms-backend-github/src/API.ts @@ -42,7 +42,7 @@ type GitHubCompareCommit = Octokit.ReposCompareCommitsResponseCommitsItem; type GitHubAuthor = Octokit.GitCreateCommitResponseAuthor; type GitHubCommitter = Octokit.GitCreateCommitResponseCommitter; type GitHubPull = Octokit.PullsListResponseItem; -type GithubRepo = Octokit.ReposGetResponse +type GithubRepo = Octokit.ReposGetResponse; export const API_NAME = 'GitHub'; @@ -1191,13 +1191,11 @@ export default class API { async newGetDefaultBranch() { try { - const result: GithubRepo = await this.request( - `${this.originRepoURL}` - ) - return result.default_branch + const result: GithubRepo = await this.request(`${this.originRepoURL}`); + return result.default_branch; } catch (e) { - console.error('Problem fetching repo data from Github') - return null + console.error('Problem fetching repo data from Github'); + return null; } } diff --git a/packages/netlify-cms-backend-github/src/implementation.tsx b/packages/netlify-cms-backend-github/src/implementation.tsx index f41ca6282670..b4d69d5ef761 100644 --- a/packages/netlify-cms-backend-github/src/implementation.tsx +++ b/packages/netlify-cms-backend-github/src/implementation.tsx @@ -182,16 +182,16 @@ export default class GitHub implements Implementation { async setDefaultBranch() { try { - const masterBranch = await this.api!.getBranch('master') + const masterBranch = await this.api!.getBranch('master'); if (!masterBranch) { - // Get default branch of the repo - const defaultBranch = await this.api!.newGetDefaultBranch() - this.branch = defaultBranch || '' + // Get default branch of the repo + const defaultBranch = await this.api!.newGetDefaultBranch(); + this.branch = defaultBranch || ''; } else { - this.branch = 'master' - } + this.branch = 'master'; + } } catch (e) { - console.warn(e) + console.warn(e); } } async pollUntilForkExists({ repo, token }: { repo: string; token: string }) { @@ -349,10 +349,10 @@ export default class GitHub implements Implementation { // If it is an empty string at this point, // it means there is no `branch` property set in the config - if (this.branch === '') { - await this.setDefaultBranch() - } - + if (this.branch === '') { + await this.setDefaultBranch(); + } + // Authorized user return { ...user, token: state.token as string, useOpenAuthoring: this.useOpenAuthoring }; } From 43fbe2d30402e748770ff40488a3f2bca34788bf Mon Sep 17 00:00:00 2001 From: Trang Le Date: Thu, 30 Sep 2021 14:57:20 +0700 Subject: [PATCH 05/62] feat: add unit test for getting default branch name --- .../src/__tests__/API.spec.js | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/packages/netlify-cms-backend-github/src/__tests__/API.spec.js b/packages/netlify-cms-backend-github/src/__tests__/API.spec.js index 2537589e7bd6..072057477098 100644 --- a/packages/netlify-cms-backend-github/src/__tests__/API.spec.js +++ b/packages/netlify-cms-backend-github/src/__tests__/API.spec.js @@ -347,6 +347,21 @@ describe('github API', () => { }); }); + describe('newGetDefaultBranch', () => { + it('should return a non-empty value for the default branch', async () => { + const defaultBranch = 'main'; + const repo = `owner/my-repo`; + const api = new API({ branch: defaultBranch, repo }); + const responses = { + '/repos/owner/my-repo': () => ({ default_branch: defaultBranch }), + }; + mockAPI(api, responses); + + await expect(api.newGetDefaultBranch()).resolves.toBe(defaultBranch); + expect(api.request).toHaveBeenCalledTimes(1); + expect(api.request.mock.calls[0]).toEqual([`/repos/${repo}`]); + }); + }); describe('migratePullRequest', () => { it('should migrate to pull request labels when no version', async () => { const api = new API({ branch: 'master', repo: 'owner/repo' }); From 84364431182024736d3e96b99eafc88c68831e50 Mon Sep 17 00:00:00 2001 From: Trang Le Date: Mon, 11 Oct 2021 12:02:15 +0700 Subject: [PATCH 06/62] feat: add helpers for parsing API responses --- packages/netlify-cms-lib-util/src/API.ts | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/packages/netlify-cms-lib-util/src/API.ts b/packages/netlify-cms-lib-util/src/API.ts index f328cf78292e..a4495f882ef4 100644 --- a/packages/netlify-cms-lib-util/src/API.ts +++ b/packages/netlify-cms-lib-util/src/API.ts @@ -40,6 +40,26 @@ class RateLimitError extends Error { } } +async function parseJsonResponse(response: Response) { + const json = await response.json(); + if (!response.ok) { + return Promise.reject(json); + } + return json; +} + +export function parseResponse(response: Response) { + const contentType = response.headers.get('Content-Type') + if (contentType && contentType.match(/json/)) { + return parseJsonResponse(response) + } + const textPromise = response.text().then(text => { + if (!response.ok) return Promise.reject(text) + return text + }) + return textPromise +} + export async function requestWithBackoff( api: API, req: ApiRequest, From 3edc3cef1eeb905af25010e50524925c2748603e Mon Sep 17 00:00:00 2001 From: Trang Le Date: Mon, 11 Oct 2021 15:11:33 +0700 Subject: [PATCH 07/62] feat(lib-util): add helper for constructing request headers --- packages/netlify-cms-lib-util/src/API.ts | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/packages/netlify-cms-lib-util/src/API.ts b/packages/netlify-cms-lib-util/src/API.ts index a4495f882ef4..9301869a8358 100644 --- a/packages/netlify-cms-lib-util/src/API.ts +++ b/packages/netlify-cms-lib-util/src/API.ts @@ -116,6 +116,20 @@ export async function requestWithBackoff( } } +type HeaderObj = Record + +type HeaderConfig = { + headers?: HeaderObj, + token?: string +} +async function constructRequestHeaders(headerConfig: HeaderConfig) { + const { token, headers } = headerConfig + const baseHeaders: HeaderObj = {'Content-Type': 'application/json; charset=utf-8', ...headers} + if (token) { + baseHeaders['Authorization'] = `token ${token}` + } + return Promise.resolve(baseHeaders) +} export async function readFile( id: string | null | undefined, fetchContent: () => Promise, From 7ccbac6becf8622a4d2e0a4745ca305b2fcd2dc8 Mon Sep 17 00:00:00 2001 From: Trang Le Date: Mon, 11 Oct 2021 15:14:29 +0700 Subject: [PATCH 08/62] feat(lib-util): add helper for constructing full URL for API request --- packages/netlify-cms-lib-util/src/API.ts | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/packages/netlify-cms-lib-util/src/API.ts b/packages/netlify-cms-lib-util/src/API.ts index 9301869a8358..366eaa394a02 100644 --- a/packages/netlify-cms-lib-util/src/API.ts +++ b/packages/netlify-cms-lib-util/src/API.ts @@ -116,12 +116,29 @@ export async function requestWithBackoff( } } +type Param = string | number + +type ParamObject = Record + type HeaderObj = Record type HeaderConfig = { headers?: HeaderObj, token?: string } +function constructUrl(url: string, params?: ParamObject) { + if (params) { + const paramList = [] + for (const key in params) { + paramList.push(`${key}=${encodeURIComponent(params[key])}`) + } + if (paramList.length) { + url += `?${paramList.join('&')}` + } + } + return url +} + async function constructRequestHeaders(headerConfig: HeaderConfig) { const { token, headers } = headerConfig const baseHeaders: HeaderObj = {'Content-Type': 'application/json; charset=utf-8', ...headers} From e5407c35db5b29faa2acafe6e2a8727732b8f257 Mon Sep 17 00:00:00 2001 From: Trang Le Date: Mon, 11 Oct 2021 15:20:49 +0700 Subject: [PATCH 09/62] feat(lib-util): store base URLs for each backend --- packages/netlify-cms-lib-util/src/API.ts | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/packages/netlify-cms-lib-util/src/API.ts b/packages/netlify-cms-lib-util/src/API.ts index 366eaa394a02..9e630f05f410 100644 --- a/packages/netlify-cms-lib-util/src/API.ts +++ b/packages/netlify-cms-lib-util/src/API.ts @@ -116,6 +116,9 @@ export async function requestWithBackoff( } } +// Options is an object which contains all the standard network request properties +// for modifying HTTP requests and may contains `params` property + type Param = string | number type ParamObject = Record @@ -126,6 +129,12 @@ type HeaderConfig = { headers?: HeaderObj, token?: string } +export const rootApi = { + github: 'https://api.github.com', + gitlab: 'https://gitlab.com/api/v4', + bitbucket: 'https://api.bitbucket.org/2.0' +} + function constructUrl(url: string, params?: ParamObject) { if (params) { const paramList = [] From 3f0e7119e823bfd1439e72397ac2f176aab20faa Mon Sep 17 00:00:00 2001 From: Trang Le Date: Mon, 11 Oct 2021 15:32:09 +0700 Subject: [PATCH 10/62] feat(lib-util): add type annotation for the request config This requestConfig object will be passed to a helper for making API request --- packages/netlify-cms-lib-util/src/API.ts | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/packages/netlify-cms-lib-util/src/API.ts b/packages/netlify-cms-lib-util/src/API.ts index 9e630f05f410..0b64ce57b5d5 100644 --- a/packages/netlify-cms-lib-util/src/API.ts +++ b/packages/netlify-cms-lib-util/src/API.ts @@ -129,6 +129,21 @@ type HeaderConfig = { headers?: HeaderObj, token?: string } + +type Backend = "github" | "gitlab" | "bitbucket" + +// RequestConfig contains all the standard properties of a Request object and +// several custom properties: +// - "headers" property is an object whose properties and values are string types +// - `token` property to allow passing tokens for users using a private repo. +// - `params` property for customizing response +// - `backend`(compulsory) to specify which backend to be used: Github, Gitlab etc. + +type RequestConfig = Omit & HeaderConfig & { + backend: Backend, + params?: ParamObject, +} + export const rootApi = { github: 'https://api.github.com', gitlab: 'https://gitlab.com/api/v4', From a506b5d46f9ddebe262308c10b850ec0d323f1fa Mon Sep 17 00:00:00 2001 From: Trang Le Date: Mon, 11 Oct 2021 15:59:12 +0700 Subject: [PATCH 11/62] feat(lib-util): add helper for handle API request error --- packages/netlify-cms-lib-util/src/API.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/packages/netlify-cms-lib-util/src/API.ts b/packages/netlify-cms-lib-util/src/API.ts index 0b64ce57b5d5..44cead1bf099 100644 --- a/packages/netlify-cms-lib-util/src/API.ts +++ b/packages/netlify-cms-lib-util/src/API.ts @@ -171,6 +171,11 @@ async function constructRequestHeaders(headerConfig: HeaderConfig) { } return Promise.resolve(baseHeaders) } + +function handleRequestError(error: FetchError, responseStatus: number, backend: Backend) { + throw new APIError(error.message, responseStatus, backend) +} + export async function readFile( id: string | null | undefined, fetchContent: () => Promise, From cc5f53a7d7a9f86cab47884f5eee05570bf61a16 Mon Sep 17 00:00:00 2001 From: Trang Le Date: Mon, 11 Oct 2021 16:23:11 +0700 Subject: [PATCH 12/62] feat(lib-util): add config for making api request --- packages/netlify-cms-lib-util/src/API.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/packages/netlify-cms-lib-util/src/API.ts b/packages/netlify-cms-lib-util/src/API.ts index 44cead1bf099..e7531ffe5ffd 100644 --- a/packages/netlify-cms-lib-util/src/API.ts +++ b/packages/netlify-cms-lib-util/src/API.ts @@ -150,6 +150,12 @@ export const rootApi = { bitbucket: 'https://api.bitbucket.org/2.0' } +const api = { + buildRequest(req: ApiRequest) { + return req + } +} + function constructUrl(url: string, params?: ParamObject) { if (params) { const paramList = [] From cec8fbbda3ac221220d640aefaf11802010889ed Mon Sep 17 00:00:00 2001 From: Trang Le Date: Mon, 11 Oct 2021 16:27:14 +0700 Subject: [PATCH 13/62] feat(lib-util): add api request generator --- packages/netlify-cms-lib-util/src/API.ts | 25 ++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/packages/netlify-cms-lib-util/src/API.ts b/packages/netlify-cms-lib-util/src/API.ts index e7531ffe5ffd..82c55ec25f9d 100644 --- a/packages/netlify-cms-lib-util/src/API.ts +++ b/packages/netlify-cms-lib-util/src/API.ts @@ -182,6 +182,31 @@ function handleRequestError(error: FetchError, responseStatus: number, backend: throw new APIError(error.message, responseStatus, backend) } +export async function apiRequest( + path: string, + config: RequestConfig, + parser = (response: Response) => parseResponse(response) +) { + const { token, backend, ...props } = config + const options = {cache: 'no-cache', ...props} + const headers = await constructRequestHeaders({ headers: options.headers || {}, token }) + const baseUrl = rootApi[backend] + const url = constructUrl(`${baseUrl}${path}`, options.params) + let responseStatus = 500 + try { + const req = unsentRequest.fromFetchArguments(url, { + ...options, + headers + }) as unknown as ApiRequest + const response = await requestWithBackoff(api, req) + responseStatus = response.status + const parsedResponse = await parser(response) + return parsedResponse + } catch(error) { + return handleRequestError(error, responseStatus, backend) + } +} + export async function readFile( id: string | null | undefined, fetchContent: () => Promise, From 69d124a96cc854c6d381d18ecad522c06801d835 Mon Sep 17 00:00:00 2001 From: Trang Le Date: Mon, 11 Oct 2021 16:28:42 +0700 Subject: [PATCH 14/62] feat(lib-util): add helper for getting default branch name Include switch clause to construct API urls for different backends --- packages/netlify-cms-lib-util/src/API.ts | 28 ++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/packages/netlify-cms-lib-util/src/API.ts b/packages/netlify-cms-lib-util/src/API.ts index 82c55ec25f9d..e6a58926b9fe 100644 --- a/packages/netlify-cms-lib-util/src/API.ts +++ b/packages/netlify-cms-lib-util/src/API.ts @@ -207,6 +207,34 @@ export async function apiRequest( } } +export async function getDefaultBranchName(configs: { backend: Backend, repo: string, token?: string}) { + let apiPath + const { token, backend, repo } = configs + switch(backend) { + case "gitlab": { + apiPath = `/projects/${encodeURIComponent(repo)}` + break + } + case "bitbucket": { + apiPath = `/repositories/${repo}` + break + } + default: { + apiPath = `/repos/${repo}` + } + } + const repoInfo = await apiRequest(apiPath, {token, backend}) + let defaultBranchName + if (backend === 'bitbucket') { + const { mainbranch: { name } } = repoInfo + defaultBranchName = name + } else { + const { default_branch } = repoInfo + defaultBranchName = default_branch + } + return defaultBranchName || null +} + export async function readFile( id: string | null | undefined, fetchContent: () => Promise, From c726ee08f0c15e59c287781f2dfa60dc72cdd29c Mon Sep 17 00:00:00 2001 From: Trang Le Date: Mon, 11 Oct 2021 16:30:43 +0700 Subject: [PATCH 15/62] feat(lib-util): export method for getting default branch name --- packages/netlify-cms-lib-util/src/index.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/netlify-cms-lib-util/src/index.ts b/packages/netlify-cms-lib-util/src/index.ts index a5c5c101c1b4..b20afb368bf5 100644 --- a/packages/netlify-cms-lib-util/src/index.ts +++ b/packages/netlify-cms-lib-util/src/index.ts @@ -34,6 +34,7 @@ import { getPreviewStatus, PreviewState, requestWithBackoff, + getDefaultBranchName, throwOnConflictingBranches, } from './API'; import { @@ -148,6 +149,7 @@ export const NetlifyCmsLibUtil = { contentKeyFromBranch, blobToFileObj, requestWithBackoff, + getDefaultBranchName, allEntriesByFolder, AccessTokenError, throwOnConflictingBranches, @@ -204,6 +206,7 @@ export { contentKeyFromBranch, blobToFileObj, requestWithBackoff, + getDefaultBranchName, allEntriesByFolder, AccessTokenError, throwOnConflictingBranches, From bbafe77eb54109b25e7c4ac8a4b759e477bcb66e Mon Sep 17 00:00:00 2001 From: Trang Le Date: Mon, 11 Oct 2021 16:32:36 +0700 Subject: [PATCH 16/62] feat(gh-backend): add a boolean property to check if branch is configured The property is needed so that we'll only set default branch when branch prop is missing in config --- packages/netlify-cms-backend-github/src/implementation.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/netlify-cms-backend-github/src/implementation.tsx b/packages/netlify-cms-backend-github/src/implementation.tsx index b4d69d5ef761..7b490fa64fea 100644 --- a/packages/netlify-cms-backend-github/src/implementation.tsx +++ b/packages/netlify-cms-backend-github/src/implementation.tsx @@ -69,6 +69,7 @@ export default class GitHub implements Implementation { initialWorkflowStatus: string; }; originRepo: string; + isBranchConfigured: boolean; repo?: string; openAuthoringEnabled: boolean; useOpenAuthoring?: boolean; @@ -103,7 +104,7 @@ export default class GitHub implements Implementation { } this.api = this.options.API || null; - + this.isBranchConfigured = config.backend.branch ? true : false; this.openAuthoringEnabled = config.backend.open_authoring || false; if (this.openAuthoringEnabled) { if (!this.options.useWorkflow) { From 11e187cd959a996ef4066c56e7b1f534973d56f2 Mon Sep 17 00:00:00 2001 From: Trang Le Date: Mon, 11 Oct 2021 16:36:12 +0700 Subject: [PATCH 17/62] feat(gh-backend): set prop `branch` as `master` when it's missing in config This is needed so that this property won't be empty when authorization is revoked. --- packages/netlify-cms-backend-github/src/implementation.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/netlify-cms-backend-github/src/implementation.tsx b/packages/netlify-cms-backend-github/src/implementation.tsx index 7b490fa64fea..15aa7f466e30 100644 --- a/packages/netlify-cms-backend-github/src/implementation.tsx +++ b/packages/netlify-cms-backend-github/src/implementation.tsx @@ -117,7 +117,7 @@ export default class GitHub implements Implementation { this.repo = this.originRepo = config.backend.repo || ''; } this.alwaysForkEnabled = config.backend.always_fork || false; - this.branch = config.backend.branch?.trim() || ''; + this.branch = config.backend.branch?.trim() || 'master'; this.apiRoot = config.backend.api_root || 'https://api.github.com'; this.token = ''; this.squashMerges = config.backend.squash_merges || false; From 67904b174fdef659fd25fdf840d3e455b1486b30 Mon Sep 17 00:00:00 2001 From: Trang Le Date: Mon, 11 Oct 2021 16:42:46 +0700 Subject: [PATCH 18/62] feat(gh-backend): set branch name when it's missing in config --- .../src/implementation.tsx | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/packages/netlify-cms-backend-github/src/implementation.tsx b/packages/netlify-cms-backend-github/src/implementation.tsx index 15aa7f466e30..69c8df90a243 100644 --- a/packages/netlify-cms-backend-github/src/implementation.tsx +++ b/packages/netlify-cms-backend-github/src/implementation.tsx @@ -20,6 +20,7 @@ import { contentKeyFromBranch, unsentRequest, branchFromContentKey, + getDefaultBranchName, } from 'netlify-cms-lib-util'; import AuthenticationPage from './AuthenticationPage'; @@ -346,12 +347,14 @@ export default class GitHub implements Implementation { if (!isCollab) { throw new Error('Your GitHub user account does not have access to this repo.'); } - // In the constructor, `this.branch` is set by reading the config file - // If it is an empty string at this point, - // it means there is no `branch` property set in the config - if (this.branch === '') { - await this.setDefaultBranch(); + // Only set default branch name when the `branch` property is missing + // in the config file + if (!this.isBranchConfigured) { + const defaultBranchName = await getDefaultBranchName({backend: 'github', repo: this.originRepo, token: this.token}); + if (defaultBranchName) { + this.branch = defaultBranchName + } } // Authorized user From 37531e125b39bb13a5d98cb5e531073b2933e24f Mon Sep 17 00:00:00 2001 From: Trang Le Date: Tue, 12 Oct 2021 15:28:38 +0700 Subject: [PATCH 19/62] feat(gitlab-backend): set branch when it's not in the config --- .../netlify-cms-backend-gitlab/src/implementation.ts | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/packages/netlify-cms-backend-gitlab/src/implementation.ts b/packages/netlify-cms-backend-gitlab/src/implementation.ts index b6b9127c6482..87ee646993f8 100644 --- a/packages/netlify-cms-backend-gitlab/src/implementation.ts +++ b/packages/netlify-cms-backend-gitlab/src/implementation.ts @@ -21,6 +21,7 @@ import { allEntriesByFolder, filterByExtension, branchFromContentKey, + getDefaultBranchName, } from 'netlify-cms-lib-util'; import AuthenticationPage from './AuthenticationPage'; @@ -53,6 +54,7 @@ export default class GitLab implements Implementation { initialWorkflowStatus: string; }; repo: string; + isBranchConfigured: boolean; branch: string; apiRoot: string; token: string | null; @@ -82,6 +84,7 @@ export default class GitLab implements Implementation { this.repo = config.backend.repo || ''; this.branch = config.backend.branch || 'master'; + this.isBranchConfigured = config.backend.branch ? true : false; this.apiRoot = config.backend.api_root || 'https://gitlab.com/api/v4'; this.token = ''; this.squashMerges = config.backend.squash_merges || false; @@ -144,6 +147,12 @@ export default class GitLab implements Implementation { throw new Error('Your GitLab user account does not have access to this repo.'); } + if (!this.isBranchConfigured) { + const defaultBranchName = await getDefaultBranchName({ backend: 'gitlab', repo: this.repo, token: this.token}) + if (defaultBranchName) { + this.branch = defaultBranchName + } + } // Authorized user return { ...user, login: user.username, token: state.token as string }; } From b118aea65ea8ebf258c5d1f0020279715d335b99 Mon Sep 17 00:00:00 2001 From: Trang Le Date: Tue, 12 Oct 2021 15:31:48 +0700 Subject: [PATCH 20/62] feat(bitbucket-backend): set branch when it's not specified in config --- .../src/implementation.ts | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/packages/netlify-cms-backend-bitbucket/src/implementation.ts b/packages/netlify-cms-backend-bitbucket/src/implementation.ts index 30375ad6715a..cdd55006242c 100644 --- a/packages/netlify-cms-backend-bitbucket/src/implementation.ts +++ b/packages/netlify-cms-backend-bitbucket/src/implementation.ts @@ -25,6 +25,7 @@ import { allEntriesByFolder, AccessTokenError, branchFromContentKey, + getDefaultBranchName } from 'netlify-cms-lib-util'; import { NetlifyAuthenticator } from 'netlify-cms-lib-auth'; @@ -72,6 +73,7 @@ export default class BitbucketBackend implements Implementation { initialWorkflowStatus: string; }; repo: string; + isBranchConfigured: boolean; branch: string; apiRoot: string; baseUrl: string; @@ -111,6 +113,7 @@ export default class BitbucketBackend implements Implementation { this.repo = config.backend.repo || ''; this.branch = config.backend.branch || 'master'; + this.isBranchConfigured = config.backend.branch ? true : false; this.apiRoot = config.backend.api_root || 'https://api.bitbucket.org/2.0'; this.baseUrl = config.base_url || ''; this.siteId = config.site_id || ''; @@ -216,7 +219,12 @@ export default class BitbucketBackend implements Implementation { if (!isCollab) { throw new Error('Your BitBucket user account does not have access to this repo.'); } - + if (!this.isBranchConfigured) { + const defaultBranchName = await getDefaultBranchName({ backend: 'bitbucket', repo: this.repo, token: this.token}) + if (defaultBranchName) { + this.branch = defaultBranchName + } + } const user = await this.api.user(); // Authorized user From fa8e03caddafc2cd90cc9976e38e7f0c8b2876a3 Mon Sep 17 00:00:00 2001 From: Trang Le Date: Tue, 12 Oct 2021 15:33:50 +0700 Subject: [PATCH 21/62] feat(lib-util): allow token type to be undefined Reason: Requesting information from a public repo doesn't require token --- packages/netlify-cms-lib-util/src/API.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/netlify-cms-lib-util/src/API.ts b/packages/netlify-cms-lib-util/src/API.ts index e6a58926b9fe..98b0b6d0f340 100644 --- a/packages/netlify-cms-lib-util/src/API.ts +++ b/packages/netlify-cms-lib-util/src/API.ts @@ -127,7 +127,7 @@ type HeaderObj = Record type HeaderConfig = { headers?: HeaderObj, - token?: string + token?: string | undefined } type Backend = "github" | "gitlab" | "bitbucket" From a2add4a4954aafa420f217af1d68867cc786e33a Mon Sep 17 00:00:00 2001 From: Trang Le Date: Tue, 12 Oct 2021 16:12:14 +0700 Subject: [PATCH 22/62] fix: format codes --- .../src/implementation.ts | 10 +- .../src/implementation.tsx | 8 +- .../src/implementation.ts | 8 +- packages/netlify-cms-lib-util/src/API.ts | 135 +++++++++--------- 4 files changed, 90 insertions(+), 71 deletions(-) diff --git a/packages/netlify-cms-backend-bitbucket/src/implementation.ts b/packages/netlify-cms-backend-bitbucket/src/implementation.ts index cdd55006242c..8e1986713a80 100644 --- a/packages/netlify-cms-backend-bitbucket/src/implementation.ts +++ b/packages/netlify-cms-backend-bitbucket/src/implementation.ts @@ -25,7 +25,7 @@ import { allEntriesByFolder, AccessTokenError, branchFromContentKey, - getDefaultBranchName + getDefaultBranchName, } from 'netlify-cms-lib-util'; import { NetlifyAuthenticator } from 'netlify-cms-lib-auth'; @@ -220,9 +220,13 @@ export default class BitbucketBackend implements Implementation { throw new Error('Your BitBucket user account does not have access to this repo.'); } if (!this.isBranchConfigured) { - const defaultBranchName = await getDefaultBranchName({ backend: 'bitbucket', repo: this.repo, token: this.token}) + const defaultBranchName = await getDefaultBranchName({ + backend: 'bitbucket', + repo: this.repo, + token: this.token, + }); if (defaultBranchName) { - this.branch = defaultBranchName + this.branch = defaultBranchName; } } const user = await this.api.user(); diff --git a/packages/netlify-cms-backend-github/src/implementation.tsx b/packages/netlify-cms-backend-github/src/implementation.tsx index 69c8df90a243..e8e9f929ff6b 100644 --- a/packages/netlify-cms-backend-github/src/implementation.tsx +++ b/packages/netlify-cms-backend-github/src/implementation.tsx @@ -351,9 +351,13 @@ export default class GitHub implements Implementation { // Only set default branch name when the `branch` property is missing // in the config file if (!this.isBranchConfigured) { - const defaultBranchName = await getDefaultBranchName({backend: 'github', repo: this.originRepo, token: this.token}); + const defaultBranchName = await getDefaultBranchName({ + backend: 'github', + repo: this.originRepo, + token: this.token, + }); if (defaultBranchName) { - this.branch = defaultBranchName + this.branch = defaultBranchName; } } diff --git a/packages/netlify-cms-backend-gitlab/src/implementation.ts b/packages/netlify-cms-backend-gitlab/src/implementation.ts index 87ee646993f8..bd3e2c42bacf 100644 --- a/packages/netlify-cms-backend-gitlab/src/implementation.ts +++ b/packages/netlify-cms-backend-gitlab/src/implementation.ts @@ -148,9 +148,13 @@ export default class GitLab implements Implementation { } if (!this.isBranchConfigured) { - const defaultBranchName = await getDefaultBranchName({ backend: 'gitlab', repo: this.repo, token: this.token}) + const defaultBranchName = await getDefaultBranchName({ + backend: 'gitlab', + repo: this.repo, + token: this.token, + }); if (defaultBranchName) { - this.branch = defaultBranchName + this.branch = defaultBranchName; } } // Authorized user diff --git a/packages/netlify-cms-lib-util/src/API.ts b/packages/netlify-cms-lib-util/src/API.ts index 98b0b6d0f340..d28129b0f640 100644 --- a/packages/netlify-cms-lib-util/src/API.ts +++ b/packages/netlify-cms-lib-util/src/API.ts @@ -49,15 +49,15 @@ async function parseJsonResponse(response: Response) { } export function parseResponse(response: Response) { - const contentType = response.headers.get('Content-Type') + const contentType = response.headers.get('Content-Type'); if (contentType && contentType.match(/json/)) { - return parseJsonResponse(response) + return parseJsonResponse(response); } const textPromise = response.text().then(text => { - if (!response.ok) return Promise.reject(text) - return text - }) - return textPromise + if (!response.ok) return Promise.reject(text); + return text; + }); + return textPromise; } export async function requestWithBackoff( @@ -119,18 +119,18 @@ export async function requestWithBackoff( // Options is an object which contains all the standard network request properties // for modifying HTTP requests and may contains `params` property -type Param = string | number +type Param = string | number; -type ParamObject = Record +type ParamObject = Record; -type HeaderObj = Record +type HeaderObj = Record; type HeaderConfig = { - headers?: HeaderObj, - token?: string | undefined -} + headers?: HeaderObj; + token?: string | undefined; +}; -type Backend = "github" | "gitlab" | "bitbucket" +type Backend = 'github' | 'gitlab' | 'bitbucket'; // RequestConfig contains all the standard properties of a Request object and // several custom properties: @@ -139,100 +139,107 @@ type Backend = "github" | "gitlab" | "bitbucket" // - `params` property for customizing response // - `backend`(compulsory) to specify which backend to be used: Github, Gitlab etc. -type RequestConfig = Omit & HeaderConfig & { - backend: Backend, - params?: ParamObject, -} +type RequestConfig = Omit & + HeaderConfig & { + backend: Backend; + params?: ParamObject; + }; export const rootApi = { github: 'https://api.github.com', gitlab: 'https://gitlab.com/api/v4', - bitbucket: 'https://api.bitbucket.org/2.0' -} + bitbucket: 'https://api.bitbucket.org/2.0', +}; const api = { buildRequest(req: ApiRequest) { - return req - } -} + return req; + }, +}; function constructUrl(url: string, params?: ParamObject) { if (params) { - const paramList = [] + const paramList = []; for (const key in params) { - paramList.push(`${key}=${encodeURIComponent(params[key])}`) + paramList.push(`${key}=${encodeURIComponent(params[key])}`); } if (paramList.length) { - url += `?${paramList.join('&')}` + url += `?${paramList.join('&')}`; } } - return url + return url; } async function constructRequestHeaders(headerConfig: HeaderConfig) { - const { token, headers } = headerConfig - const baseHeaders: HeaderObj = {'Content-Type': 'application/json; charset=utf-8', ...headers} + const { token, headers } = headerConfig; + const baseHeaders: HeaderObj = { 'Content-Type': 'application/json; charset=utf-8', ...headers }; if (token) { - baseHeaders['Authorization'] = `token ${token}` + baseHeaders['Authorization'] = `token ${token}`; } - return Promise.resolve(baseHeaders) + return Promise.resolve(baseHeaders); } function handleRequestError(error: FetchError, responseStatus: number, backend: Backend) { - throw new APIError(error.message, responseStatus, backend) + throw new APIError(error.message, responseStatus, backend); } export async function apiRequest( path: string, config: RequestConfig, - parser = (response: Response) => parseResponse(response) + parser = (response: Response) => parseResponse(response), ) { - const { token, backend, ...props } = config - const options = {cache: 'no-cache', ...props} - const headers = await constructRequestHeaders({ headers: options.headers || {}, token }) - const baseUrl = rootApi[backend] - const url = constructUrl(`${baseUrl}${path}`, options.params) - let responseStatus = 500 + const { token, backend, ...props } = config; + const options = { cache: 'no-cache', ...props }; + const headers = await constructRequestHeaders({ headers: options.headers || {}, token }); + const baseUrl = rootApi[backend]; + const url = constructUrl(`${baseUrl}${path}`, options.params); + let responseStatus = 500; try { const req = unsentRequest.fromFetchArguments(url, { ...options, - headers - }) as unknown as ApiRequest - const response = await requestWithBackoff(api, req) - responseStatus = response.status - const parsedResponse = await parser(response) - return parsedResponse - } catch(error) { - return handleRequestError(error, responseStatus, backend) + headers, + }) as unknown as ApiRequest; + const response = await requestWithBackoff(api, req); + responseStatus = response.status; + const parsedResponse = await parser(response); + return parsedResponse; + } catch (error) { + return handleRequestError(error, responseStatus, backend); } } -export async function getDefaultBranchName(configs: { backend: Backend, repo: string, token?: string}) { - let apiPath - const { token, backend, repo } = configs - switch(backend) { - case "gitlab": { - apiPath = `/projects/${encodeURIComponent(repo)}` - break +export async function getDefaultBranchName(configs: { + backend: Backend; + repo: string; + token?: string; +}) { + let apiPath; + const { token, backend, repo } = configs; + switch (backend) { + case 'gitlab': { + apiPath = `/projects/${encodeURIComponent(repo)}`; + break; } - case "bitbucket": { - apiPath = `/repositories/${repo}` - break + case 'bitbucket': { + apiPath = `/repositories/${repo}`; + break; } default: { - apiPath = `/repos/${repo}` + apiPath = `/repos/${repo}`; } } - const repoInfo = await apiRequest(apiPath, {token, backend}) - let defaultBranchName + const repoInfo = await apiRequest(apiPath, { token, backend }); + let defaultBranchName; if (backend === 'bitbucket') { - const { mainbranch: { name } } = repoInfo - defaultBranchName = name + const { + mainbranch: { name }, + } = repoInfo; + defaultBranchName = name; } else { - const { default_branch } = repoInfo - defaultBranchName = default_branch + const { default_branch } = repoInfo; + defaultBranchName = default_branch; } - return defaultBranchName || null + return defaultBranchName || null; } export async function readFile( From 8319d4b53032dd98ba46dfa4aac42d828629ef8e Mon Sep 17 00:00:00 2001 From: Trang Le Date: Sat, 12 Mar 2022 17:50:53 +0700 Subject: [PATCH 23/62] feat(github): removed setDefaultBranch function Reason: Default branch is already set when calling `authenticate` function --- .../src/implementation.tsx | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/packages/netlify-cms-backend-github/src/implementation.tsx b/packages/netlify-cms-backend-github/src/implementation.tsx index e8e9f929ff6b..5cc0b47b9ef1 100644 --- a/packages/netlify-cms-backend-github/src/implementation.tsx +++ b/packages/netlify-cms-backend-github/src/implementation.tsx @@ -182,20 +182,6 @@ export default class GitHub implements Implementation { : this.authenticate(user); } - async setDefaultBranch() { - try { - const masterBranch = await this.api!.getBranch('master'); - if (!masterBranch) { - // Get default branch of the repo - const defaultBranch = await this.api!.newGetDefaultBranch(); - this.branch = defaultBranch || ''; - } else { - this.branch = 'master'; - } - } catch (e) { - console.warn(e); - } - } async pollUntilForkExists({ repo, token }: { repo: string; token: string }) { const pollDelay = 250; // milliseconds let repoExists = false; From 87350d964022fe620f88cf138b56494e91673824 Mon Sep 17 00:00:00 2001 From: Trang Le Date: Sat, 12 Mar 2022 18:07:33 +0700 Subject: [PATCH 24/62] feat(github): remove function for getting default branch --- packages/netlify-cms-backend-github/src/API.ts | 10 ---------- .../src/__tests__/API.spec.js | 15 --------------- 2 files changed, 25 deletions(-) diff --git a/packages/netlify-cms-backend-github/src/API.ts b/packages/netlify-cms-backend-github/src/API.ts index 92d07aacfcc4..1209a5032591 100644 --- a/packages/netlify-cms-backend-github/src/API.ts +++ b/packages/netlify-cms-backend-github/src/API.ts @@ -1189,16 +1189,6 @@ export default class API { return result; } - async newGetDefaultBranch() { - try { - const result: GithubRepo = await this.request(`${this.originRepoURL}`); - return result.default_branch; - } catch (e) { - console.error('Problem fetching repo data from Github'); - return null; - } - } - async backupBranch(branchName: string) { try { const existingBranch = await this.getBranch(branchName); diff --git a/packages/netlify-cms-backend-github/src/__tests__/API.spec.js b/packages/netlify-cms-backend-github/src/__tests__/API.spec.js index 072057477098..2537589e7bd6 100644 --- a/packages/netlify-cms-backend-github/src/__tests__/API.spec.js +++ b/packages/netlify-cms-backend-github/src/__tests__/API.spec.js @@ -347,21 +347,6 @@ describe('github API', () => { }); }); - describe('newGetDefaultBranch', () => { - it('should return a non-empty value for the default branch', async () => { - const defaultBranch = 'main'; - const repo = `owner/my-repo`; - const api = new API({ branch: defaultBranch, repo }); - const responses = { - '/repos/owner/my-repo': () => ({ default_branch: defaultBranch }), - }; - mockAPI(api, responses); - - await expect(api.newGetDefaultBranch()).resolves.toBe(defaultBranch); - expect(api.request).toHaveBeenCalledTimes(1); - expect(api.request.mock.calls[0]).toEqual([`/repos/${repo}`]); - }); - }); describe('migratePullRequest', () => { it('should migrate to pull request labels when no version', async () => { const api = new API({ branch: 'master', repo: 'owner/repo' }); From 3694c75cb491f3fe34b60e3f0d3846df3aa7c630 Mon Sep 17 00:00:00 2001 From: Trang Le Date: Sat, 12 Mar 2022 22:57:01 +0700 Subject: [PATCH 25/62] fix (github): removed GithubRepo object because it was never used --- packages/netlify-cms-backend-github/src/API.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/netlify-cms-backend-github/src/API.ts b/packages/netlify-cms-backend-github/src/API.ts index 5a5c9625bde4..bc77336407da 100644 --- a/packages/netlify-cms-backend-github/src/API.ts +++ b/packages/netlify-cms-backend-github/src/API.ts @@ -42,7 +42,6 @@ type GitHubCompareCommit = Octokit.ReposCompareCommitsResponseCommitsItem; type GitHubAuthor = Octokit.GitCreateCommitResponseAuthor; type GitHubCommitter = Octokit.GitCreateCommitResponseCommitter; type GitHubPull = Octokit.PullsListResponseItem; -type GithubRepo = Octokit.ReposGetResponse; export const API_NAME = 'GitHub'; From 346ac8ba710a5c174bc5d03003d2ab78681e53d6 Mon Sep 17 00:00:00 2001 From: Trang Le Date: Mon, 14 Mar 2022 20:21:32 +0700 Subject: [PATCH 26/62] fix (gitlab test): Repeat response for getting project info 2 times Reason: The endpoint for getting Gitlab project info is called twice. Need to specify the number of times to repeat the same response as 2, or Nock will throw an error. --- .../src/__tests__/gitlab.spec.js | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/packages/netlify-cms-backend-gitlab/src/__tests__/gitlab.spec.js b/packages/netlify-cms-backend-gitlab/src/__tests__/gitlab.spec.js index f5c361d149c2..978e062fb266 100644 --- a/packages/netlify-cms-backend-gitlab/src/__tests__/gitlab.spec.js +++ b/packages/netlify-cms-backend-gitlab/src/__tests__/gitlab.spec.js @@ -194,7 +194,15 @@ describe('gitlab backend', () => { .reply(200, userResponse || resp.user.success); api - .get(expectedRepoUrl) + // The `authenticate` method of the API class from netlify-cms-backend-gitlab + // calls the same endpoint twice for gettng a single project. + // First time through `this.api.hasWriteAccess() + // Second time through the method `getDefaultBranchName` from lib-util + // As a result, we need to repeat the same response twice. + // Otherwise, we'll get an error: "No match for request to + // https://gitlab.com/api/v4" + + .get(expectedRepoUrl).times(2) .query(true) .reply(200, projectResponse || resp.project.success); } From 714a57efe1b6dd15a4c9fbb2de753c73ffa9d2d5 Mon Sep 17 00:00:00 2001 From: Trang Le Date: Mon, 14 Mar 2022 22:02:28 +0700 Subject: [PATCH 27/62] fix(gitlab test): add property `default_branch` to project response REASON: Getting a single project through `/projects/:id` returns an object which contains `default_branch` property, among many other props. The mock response needs to convey that. --- packages/netlify-cms-backend-gitlab/src/__tests__/gitlab.spec.js | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/netlify-cms-backend-gitlab/src/__tests__/gitlab.spec.js b/packages/netlify-cms-backend-gitlab/src/__tests__/gitlab.spec.js index 978e062fb266..e1904778352e 100644 --- a/packages/netlify-cms-backend-gitlab/src/__tests__/gitlab.spec.js +++ b/packages/netlify-cms-backend-gitlab/src/__tests__/gitlab.spec.js @@ -109,6 +109,7 @@ const resp = { access_level: 30, }, }, + default_branch: 'main', }, readOnly: { permissions: { From f77dba5caadf824dd230a1eb9dcd1458a51046f9 Mon Sep 17 00:00:00 2001 From: Trang Le Date: Mon, 14 Mar 2022 22:06:07 +0700 Subject: [PATCH 28/62] fix(gitlab test): reformat codes --- .../src/__tests__/gitlab.spec.js | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/packages/netlify-cms-backend-gitlab/src/__tests__/gitlab.spec.js b/packages/netlify-cms-backend-gitlab/src/__tests__/gitlab.spec.js index e1904778352e..941906d50669 100644 --- a/packages/netlify-cms-backend-gitlab/src/__tests__/gitlab.spec.js +++ b/packages/netlify-cms-backend-gitlab/src/__tests__/gitlab.spec.js @@ -195,15 +195,16 @@ describe('gitlab backend', () => { .reply(200, userResponse || resp.user.success); api - // The `authenticate` method of the API class from netlify-cms-backend-gitlab - // calls the same endpoint twice for gettng a single project. - // First time through `this.api.hasWriteAccess() - // Second time through the method `getDefaultBranchName` from lib-util - // As a result, we need to repeat the same response twice. - // Otherwise, we'll get an error: "No match for request to - // https://gitlab.com/api/v4" - - .get(expectedRepoUrl).times(2) + // The `authenticate` method of the API class from netlify-cms-backend-gitlab + // calls the same endpoint twice for gettng a single project. + // First time through `this.api.hasWriteAccess() + // Second time through the method `getDefaultBranchName` from lib-util + // As a result, we need to repeat the same response twice. + // Otherwise, we'll get an error: "No match for request to + // https://gitlab.com/api/v4" + + .get(expectedRepoUrl) + .times(2) .query(true) .reply(200, projectResponse || resp.project.success); } From 9c14584bdf57da485d20e74a82c1f701b0e114a3 Mon Sep 17 00:00:00 2001 From: Trang Le Date: Thu, 17 Mar 2022 11:43:10 +0700 Subject: [PATCH 29/62] feat(lib util api): change function name Change from `constructUrl` to `constructUrlWithParams` to indicate that the returned url may contain query string --- packages/netlify-cms-lib-util/src/API.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/netlify-cms-lib-util/src/API.ts b/packages/netlify-cms-lib-util/src/API.ts index d28129b0f640..52ac6a7fc7e3 100644 --- a/packages/netlify-cms-lib-util/src/API.ts +++ b/packages/netlify-cms-lib-util/src/API.ts @@ -157,7 +157,7 @@ const api = { }, }; -function constructUrl(url: string, params?: ParamObject) { +function constructUrlWithParams(url: string, params?: ParamObject) { if (params) { const paramList = []; for (const key in params) { @@ -192,7 +192,7 @@ export async function apiRequest( const options = { cache: 'no-cache', ...props }; const headers = await constructRequestHeaders({ headers: options.headers || {}, token }); const baseUrl = rootApi[backend]; - const url = constructUrl(`${baseUrl}${path}`, options.params); + const url = constructUrlWithParams(`${baseUrl}${path}`, options.params); let responseStatus = 500; try { const req = unsentRequest.fromFetchArguments(url, { From acd47a8ea934982bd7ebe1325f225acf02aefdf3 Mon Sep 17 00:00:00 2001 From: Trang Le Date: Thu, 17 Mar 2022 11:45:32 +0700 Subject: [PATCH 30/62] feat(lib-util api): Change variable name for storing API roots Change from `rootApi` to `apiRoots` to indicate that the varible contains multiple values --- packages/netlify-cms-lib-util/src/API.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/netlify-cms-lib-util/src/API.ts b/packages/netlify-cms-lib-util/src/API.ts index 52ac6a7fc7e3..e345d8bb615e 100644 --- a/packages/netlify-cms-lib-util/src/API.ts +++ b/packages/netlify-cms-lib-util/src/API.ts @@ -145,7 +145,7 @@ type RequestConfig = Omit & params?: ParamObject; }; -export const rootApi = { +export const apiRoots = { github: 'https://api.github.com', gitlab: 'https://gitlab.com/api/v4', bitbucket: 'https://api.bitbucket.org/2.0', @@ -191,7 +191,7 @@ export async function apiRequest( const { token, backend, ...props } = config; const options = { cache: 'no-cache', ...props }; const headers = await constructRequestHeaders({ headers: options.headers || {}, token }); - const baseUrl = rootApi[backend]; + const baseUrl = apiRoots[backend]; const url = constructUrlWithParams(`${baseUrl}${path}`, options.params); let responseStatus = 500; try { From 98541a30fa56724c12da725e28a39f4a3df1f994 Mon Sep 17 00:00:00 2001 From: Trang Le Date: Thu, 17 Mar 2022 11:47:53 +0700 Subject: [PATCH 31/62] feat(lib-util api): Add varialbe for storing endpoint constants --- packages/netlify-cms-lib-util/src/API.ts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/packages/netlify-cms-lib-util/src/API.ts b/packages/netlify-cms-lib-util/src/API.ts index e345d8bb615e..f5d8ba0863dc 100644 --- a/packages/netlify-cms-lib-util/src/API.ts +++ b/packages/netlify-cms-lib-util/src/API.ts @@ -151,6 +151,14 @@ export const apiRoots = { bitbucket: 'https://api.bitbucket.org/2.0', }; +export const endpointConstants = { + singleRepo: { + bitbucket: '/repositories', + github: '/repos', + gitlab: '/projects', + } +} + const api = { buildRequest(req: ApiRequest) { return req; From 7dc9daea531407fe9094277f6412392739fb1608 Mon Sep 17 00:00:00 2001 From: Trang Le Date: Thu, 17 Mar 2022 11:53:08 +0700 Subject: [PATCH 32/62] feat(lib-util api): Change the returned value for `getDefaultBranchName` Reason: There's no `null` value for default_branch --- packages/netlify-cms-lib-util/src/API.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/netlify-cms-lib-util/src/API.ts b/packages/netlify-cms-lib-util/src/API.ts index f5d8ba0863dc..d65c18047cb5 100644 --- a/packages/netlify-cms-lib-util/src/API.ts +++ b/packages/netlify-cms-lib-util/src/API.ts @@ -247,7 +247,7 @@ export async function getDefaultBranchName(configs: { const { default_branch } = repoInfo; defaultBranchName = default_branch; } - return defaultBranchName || null; + return defaultBranchName; } export async function readFile( From 1ecd9469b753086c7a2f69a0cbc91266474d8ad2 Mon Sep 17 00:00:00 2001 From: Trang Le Date: Thu, 17 Mar 2022 11:59:57 +0700 Subject: [PATCH 33/62] feat(api test): Import Nock module for mocking API requests --- packages/netlify-cms-lib-util/src/__tests__/api.spec.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/packages/netlify-cms-lib-util/src/__tests__/api.spec.js b/packages/netlify-cms-lib-util/src/__tests__/api.spec.js index 675ff0458e36..e1b2116f3ffc 100644 --- a/packages/netlify-cms-lib-util/src/__tests__/api.spec.js +++ b/packages/netlify-cms-lib-util/src/__tests__/api.spec.js @@ -1,4 +1,11 @@ +import nock from "nock"; + import * as api from '../API'; + +function mockApi(backend) { + return nock(backend.apiRoot) +} + describe('Api', () => { describe('getPreviewStatus', () => { it('should return preview status on matching context', () => { From efa741f1ab640ca6e70559994e50307441209ec3 Mon Sep 17 00:00:00 2001 From: Trang Le Date: Thu, 17 Mar 2022 12:01:56 +0700 Subject: [PATCH 34/62] feat(api test): Add default values for mocking API Default values include: default branch name, mock tokens and mock repo slug --- packages/netlify-cms-lib-util/src/__tests__/api.spec.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/netlify-cms-lib-util/src/__tests__/api.spec.js b/packages/netlify-cms-lib-util/src/__tests__/api.spec.js index e1b2116f3ffc..73fa5f6973bb 100644 --- a/packages/netlify-cms-lib-util/src/__tests__/api.spec.js +++ b/packages/netlify-cms-lib-util/src/__tests__/api.spec.js @@ -2,6 +2,10 @@ import nock from "nock"; import * as api from '../API'; +const branchProp = { default_branch: 'master' } +const MOCK_CREDENTIALS = { token: 'MOCK_TOKEN' } +const REPO_PATH = 'foo/bar' + function mockApi(backend) { return nock(backend.apiRoot) } From 7bf6724c01f5358486f470354b7bc0f94d6a6864 Mon Sep 17 00:00:00 2001 From: Trang Le Date: Thu, 17 Mar 2022 12:03:01 +0700 Subject: [PATCH 35/62] feat(api test): Add mock response to getting a single repo --- .../src/__tests__/api.spec.js | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/packages/netlify-cms-lib-util/src/__tests__/api.spec.js b/packages/netlify-cms-lib-util/src/__tests__/api.spec.js index 73fa5f6973bb..477bad8a59d1 100644 --- a/packages/netlify-cms-lib-util/src/__tests__/api.spec.js +++ b/packages/netlify-cms-lib-util/src/__tests__/api.spec.js @@ -3,6 +3,31 @@ import nock from "nock"; import * as api from '../API'; const branchProp = { default_branch: 'master' } + +const repoResp = { + github: { + ...branchProp, + permissions: { + pull: true, + push: true, + admin: true + } + }, + gitlab: { + ...branchProp, + permissions: { + project_access: { + access_level: 10 + } + } + }, + bitbucket: { + mainbranch: { + name: "master" + } + } +} + const MOCK_CREDENTIALS = { token: 'MOCK_TOKEN' } const REPO_PATH = 'foo/bar' From 2dfa3f65893fa296a0bcdb3c3d2837a3f12126c3 Mon Sep 17 00:00:00 2001 From: Trang Le Date: Thu, 17 Mar 2022 12:05:20 +0700 Subject: [PATCH 36/62] feat(api test): Add function for itnercepting request to get single repo --- packages/netlify-cms-lib-util/src/__tests__/api.spec.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/packages/netlify-cms-lib-util/src/__tests__/api.spec.js b/packages/netlify-cms-lib-util/src/__tests__/api.spec.js index 477bad8a59d1..a00253d46507 100644 --- a/packages/netlify-cms-lib-util/src/__tests__/api.spec.js +++ b/packages/netlify-cms-lib-util/src/__tests__/api.spec.js @@ -35,6 +35,14 @@ function mockApi(backend) { return nock(backend.apiRoot) } +export function interceptRepo(backend) { + const api = mockApi(backend) + api + .get(backend.repoEndpoint) + .query(true) + .reply(200, repoResp[backend.backendName]) +} + describe('Api', () => { describe('getPreviewStatus', () => { it('should return preview status on matching context', () => { From ef664f6db4cb5bd3756dc4fa5aea288d1921b2c3 Mon Sep 17 00:00:00 2001 From: Trang Le Date: Thu, 17 Mar 2022 12:06:45 +0700 Subject: [PATCH 37/62] feat(api test): Add test for gettingDefaultBranchName --- .../src/__tests__/api.spec.js | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/packages/netlify-cms-lib-util/src/__tests__/api.spec.js b/packages/netlify-cms-lib-util/src/__tests__/api.spec.js index a00253d46507..e2249fe14e1f 100644 --- a/packages/netlify-cms-lib-util/src/__tests__/api.spec.js +++ b/packages/netlify-cms-lib-util/src/__tests__/api.spec.js @@ -53,4 +53,22 @@ describe('Api', () => { expect(api.getPreviewStatus([{ context: 'other' }])).toBeUndefined(); }); }); + describe('getDefaultBranchName', () => { + it('should return non-empty string as default branch', async () => { + const { apiRoots, endpointConstants: { singleRepo: staticRepoEndpoints } } = api + let normalizedRepoPath + for (const backendName in apiRoots) { + if (backendName === 'gitlab') { + // Gitlab API requires the repo slug to be url-encoded + normalizedRepoPath = encodeURIComponent(REPO_PATH) + } else { + normalizedRepoPath = REPO_PATH + } + const repoEndpoint = `${staticRepoEndpoints[backendName]}/${normalizedRepoPath}` + interceptRepo({ apiRoot: apiRoots[backendName], repoEndpoint, backendName }) + const defaultBranchName = await api.getDefaultBranchName({ backend: backendName, repo: REPO_PATH, token: MOCK_CREDENTIALS.token }) + expect(defaultBranchName).not.toBe('') + } + }) + }) }); From 89a2806292f5524cb86cdf319b0f8fc67997a159 Mon Sep 17 00:00:00 2001 From: Trang Le Date: Thu, 17 Mar 2022 12:18:03 +0700 Subject: [PATCH 38/62] feat(lib-util): reformat codes --- packages/netlify-cms-lib-util/src/API.ts | 4 +- .../src/__tests__/api.spec.js | 62 ++++++++++--------- 2 files changed, 35 insertions(+), 31 deletions(-) diff --git a/packages/netlify-cms-lib-util/src/API.ts b/packages/netlify-cms-lib-util/src/API.ts index d65c18047cb5..277f045d3603 100644 --- a/packages/netlify-cms-lib-util/src/API.ts +++ b/packages/netlify-cms-lib-util/src/API.ts @@ -156,8 +156,8 @@ export const endpointConstants = { bitbucket: '/repositories', github: '/repos', gitlab: '/projects', - } -} + }, +}; const api = { buildRequest(req: ApiRequest) { diff --git a/packages/netlify-cms-lib-util/src/__tests__/api.spec.js b/packages/netlify-cms-lib-util/src/__tests__/api.spec.js index e2249fe14e1f..f715e1693454 100644 --- a/packages/netlify-cms-lib-util/src/__tests__/api.spec.js +++ b/packages/netlify-cms-lib-util/src/__tests__/api.spec.js @@ -1,8 +1,8 @@ -import nock from "nock"; +import nock from 'nock'; import * as api from '../API'; -const branchProp = { default_branch: 'master' } +const branchProp = { default_branch: 'master' }; const repoResp = { github: { @@ -10,37 +10,34 @@ const repoResp = { permissions: { pull: true, push: true, - admin: true - } + admin: true, + }, }, gitlab: { ...branchProp, permissions: { project_access: { - access_level: 10 - } - } + access_level: 10, + }, + }, }, bitbucket: { mainbranch: { - name: "master" - } - } -} + name: 'master', + }, + }, +}; -const MOCK_CREDENTIALS = { token: 'MOCK_TOKEN' } -const REPO_PATH = 'foo/bar' +const MOCK_CREDENTIALS = { token: 'MOCK_TOKEN' }; +const REPO_PATH = 'foo/bar'; function mockApi(backend) { - return nock(backend.apiRoot) + return nock(backend.apiRoot); } export function interceptRepo(backend) { - const api = mockApi(backend) - api - .get(backend.repoEndpoint) - .query(true) - .reply(200, repoResp[backend.backendName]) + const api = mockApi(backend); + api.get(backend.repoEndpoint).query(true).reply(200, repoResp[backend.backendName]); } describe('Api', () => { @@ -55,20 +52,27 @@ describe('Api', () => { }); describe('getDefaultBranchName', () => { it('should return non-empty string as default branch', async () => { - const { apiRoots, endpointConstants: { singleRepo: staticRepoEndpoints } } = api - let normalizedRepoPath + const { + apiRoots, + endpointConstants: { singleRepo: staticRepoEndpoints }, + } = api; + let normalizedRepoPath; for (const backendName in apiRoots) { if (backendName === 'gitlab') { // Gitlab API requires the repo slug to be url-encoded - normalizedRepoPath = encodeURIComponent(REPO_PATH) + normalizedRepoPath = encodeURIComponent(REPO_PATH); } else { - normalizedRepoPath = REPO_PATH + normalizedRepoPath = REPO_PATH; } - const repoEndpoint = `${staticRepoEndpoints[backendName]}/${normalizedRepoPath}` - interceptRepo({ apiRoot: apiRoots[backendName], repoEndpoint, backendName }) - const defaultBranchName = await api.getDefaultBranchName({ backend: backendName, repo: REPO_PATH, token: MOCK_CREDENTIALS.token }) - expect(defaultBranchName).not.toBe('') + const repoEndpoint = `${staticRepoEndpoints[backendName]}/${normalizedRepoPath}`; + interceptRepo({ apiRoot: apiRoots[backendName], repoEndpoint, backendName }); + const defaultBranchName = await api.getDefaultBranchName({ + backend: backendName, + repo: REPO_PATH, + token: MOCK_CREDENTIALS.token, + }); + expect(defaultBranchName).not.toBe(''); } - }) - }) + }); + }); }); From 183a0c33e71523340651d2dcee497596f98bedac Mon Sep 17 00:00:00 2001 From: Trang Le Date: Mon, 11 Apr 2022 16:26:47 +0700 Subject: [PATCH 39/62] feat(jest config): add moduleNameMapper for GitHub and BitBucket Required for the test that checks setDefaultBranchName is called in lib-util to work --- jest.config.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/jest.config.js b/jest.config.js index 1fe3c136dbc4..1646831982ce 100644 --- a/jest.config.js +++ b/jest.config.js @@ -5,6 +5,8 @@ module.exports = { 'netlify-cms-lib-util': '/packages/netlify-cms-lib-util/src/index.ts', 'netlify-cms-ui-default': '/packages/netlify-cms-ui-default/src/index.js', 'netlify-cms-backend-github': '/packages/netlify-cms-backend-github/src/index.ts', + 'netlify-cms-backend-gitlab': '/packages/netlify-cms-backend-gitlab/src/index.ts', + 'netlify-cms-backend-bitbucket': '/packages/netlify-cms-backend-bitbucket/src/index.ts', 'netlify-cms-lib-widgets': '/packages/netlify-cms-lib-widgets/src/index.ts', 'netlify-cms-widget-object': '/packages/netlify-cms-widget-object/src/index.js', '\\.(css|less)$': '/__mocks__/styleMock.js', From 02ef43ca11688f2e483daa4954bb285826ee647a Mon Sep 17 00:00:00 2001 From: Trang Le Date: Mon, 11 Apr 2022 16:29:00 +0700 Subject: [PATCH 40/62] feat(lib-util test): return some modules from backend core for testing --- packages/netlify-cms-lib-util/src/__tests__/api.spec.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/netlify-cms-lib-util/src/__tests__/api.spec.js b/packages/netlify-cms-lib-util/src/__tests__/api.spec.js index f715e1693454..7a918bddf6a6 100644 --- a/packages/netlify-cms-lib-util/src/__tests__/api.spec.js +++ b/packages/netlify-cms-lib-util/src/__tests__/api.spec.js @@ -2,6 +2,8 @@ import nock from 'nock'; import * as api from '../API'; +const { Backend, LocalStorageAuthStore } = jest.requireActual('netlify-cms-core/src/backend') + const branchProp = { default_branch: 'master' }; const repoResp = { From 5d1855c9f9fafe96304af140625b1651a24b62a3 Mon Sep 17 00:00:00 2001 From: Trang Le Date: Mon, 11 Apr 2022 16:31:50 +0700 Subject: [PATCH 41/62] feat(lib-util test): add owner login value for Github's repo response The authenticate method of Github API wrapper extracts owner.login from repo resp --- packages/netlify-cms-lib-util/src/__tests__/api.spec.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/netlify-cms-lib-util/src/__tests__/api.spec.js b/packages/netlify-cms-lib-util/src/__tests__/api.spec.js index 7a918bddf6a6..250d849865cd 100644 --- a/packages/netlify-cms-lib-util/src/__tests__/api.spec.js +++ b/packages/netlify-cms-lib-util/src/__tests__/api.spec.js @@ -9,6 +9,9 @@ const branchProp = { default_branch: 'master' }; const repoResp = { github: { ...branchProp, + owner: { + login: 'owner' + }, permissions: { pull: true, push: true, From b03d6a8dca0eb37dcfc1d55113b62425ba709afd Mon Sep 17 00:00:00 2001 From: Trang Le Date: Mon, 11 Apr 2022 16:34:22 +0700 Subject: [PATCH 42/62] feat(lib-util test): change access level for Gitlab to 30 Reason: If access level is under 30, Gitlab package will throw error --- packages/netlify-cms-lib-util/src/__tests__/api.spec.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/netlify-cms-lib-util/src/__tests__/api.spec.js b/packages/netlify-cms-lib-util/src/__tests__/api.spec.js index 250d849865cd..b3b08c4036a3 100644 --- a/packages/netlify-cms-lib-util/src/__tests__/api.spec.js +++ b/packages/netlify-cms-lib-util/src/__tests__/api.spec.js @@ -22,7 +22,10 @@ const repoResp = { ...branchProp, permissions: { project_access: { - access_level: 10, + access_level: 30, // This means the user is at least a developer + // and can be a maintainer or owner. If this number is below + // 30, user is not a collaborator and Gitlab API will throw + // an error }, }, }, From 13f0863261539f9030619d59008f9d42dcd6b7a8 Mon Sep 17 00:00:00 2001 From: Trang Le Date: Mon, 11 Apr 2022 16:38:02 +0700 Subject: [PATCH 43/62] feat(lib-util test): add mock response for getting a user The authenticate method of each backend requires this --- .../src/__tests__/api.spec.js | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/packages/netlify-cms-lib-util/src/__tests__/api.spec.js b/packages/netlify-cms-lib-util/src/__tests__/api.spec.js index b3b08c4036a3..d5a9d7b249e9 100644 --- a/packages/netlify-cms-lib-util/src/__tests__/api.spec.js +++ b/packages/netlify-cms-lib-util/src/__tests__/api.spec.js @@ -36,6 +36,31 @@ const repoResp = { }, }; +const userResp = { + github: { + success: { + id: 1 + } + }, + gitlab: { + success: { + id: 1 + } + }, + bitbucket: { + success: { + id: 1, + display_name: 'Test Account', + username: 'test', + links: { + avatar: { + href: 'https://example.com' + } + } + } + } +} + const MOCK_CREDENTIALS = { token: 'MOCK_TOKEN' }; const REPO_PATH = 'foo/bar'; From 1aba0da317ae6a47abaf49c5f6b99ebad18d185a Mon Sep 17 00:00:00 2001 From: Trang Le Date: Mon, 11 Apr 2022 16:39:19 +0700 Subject: [PATCH 44/62] feat(lib-util test): add default config for backend field --- packages/netlify-cms-lib-util/src/__tests__/api.spec.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/packages/netlify-cms-lib-util/src/__tests__/api.spec.js b/packages/netlify-cms-lib-util/src/__tests__/api.spec.js index d5a9d7b249e9..6575ef0bd2eb 100644 --- a/packages/netlify-cms-lib-util/src/__tests__/api.spec.js +++ b/packages/netlify-cms-lib-util/src/__tests__/api.spec.js @@ -63,6 +63,12 @@ const userResp = { const MOCK_CREDENTIALS = { token: 'MOCK_TOKEN' }; const REPO_PATH = 'foo/bar'; +const defaultConfig = { + backend: { + name: 'github', + repo: REPO_PATH + } +} function mockApi(backend) { return nock(backend.apiRoot); From 1f76df9613985c1e666db22b292fce2b207c2346 Mon Sep 17 00:00:00 2001 From: Trang Le Date: Mon, 11 Apr 2022 17:40:07 +0700 Subject: [PATCH 45/62] feat(lib-util test): rewrite function for mocking API --- packages/netlify-cms-lib-util/src/__tests__/api.spec.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/netlify-cms-lib-util/src/__tests__/api.spec.js b/packages/netlify-cms-lib-util/src/__tests__/api.spec.js index 6575ef0bd2eb..cd8b8708b4e0 100644 --- a/packages/netlify-cms-lib-util/src/__tests__/api.spec.js +++ b/packages/netlify-cms-lib-util/src/__tests__/api.spec.js @@ -71,7 +71,7 @@ const defaultConfig = { } function mockApi(backend) { - return nock(backend.apiRoot); + return nock(backend.implementation.apiRoot); } export function interceptRepo(backend) { From 394dc9b1b72380b052bb106d66789519745f026c Mon Sep 17 00:00:00 2001 From: Trang Le Date: Mon, 11 Apr 2022 17:50:20 +0700 Subject: [PATCH 46/62] feat(lib-util test): rewrite function for mocking request for repo --- packages/netlify-cms-lib-util/src/__tests__/api.spec.js | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/packages/netlify-cms-lib-util/src/__tests__/api.spec.js b/packages/netlify-cms-lib-util/src/__tests__/api.spec.js index cd8b8708b4e0..73ef9484a39b 100644 --- a/packages/netlify-cms-lib-util/src/__tests__/api.spec.js +++ b/packages/netlify-cms-lib-util/src/__tests__/api.spec.js @@ -75,8 +75,15 @@ function mockApi(backend) { } export function interceptRepo(backend) { +export function interceptRepo(backend, urlPath) { + // A URL path given to Nock needs to start with a forward slash. + if (urlPath[0] !== '/') { + urlPath = `/${urlPath}` + } const api = mockApi(backend); - api.get(backend.repoEndpoint).query(true).reply(200, repoResp[backend.backendName]); + api.get(urlPath).query(true).reply(200, repoResp[backend.backendName]); +} + } describe('Api', () => { From 0fc96abf6980ed2ddf3516f50c3e27636669e118 Mon Sep 17 00:00:00 2001 From: Trang Le Date: Mon, 11 Apr 2022 17:52:00 +0700 Subject: [PATCH 47/62] test(lib-util): rewrite test for the function getDefaultBranchName --- .../netlify-cms-lib-util/src/__tests__/api.spec.js | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/packages/netlify-cms-lib-util/src/__tests__/api.spec.js b/packages/netlify-cms-lib-util/src/__tests__/api.spec.js index 73ef9484a39b..b06d39cc5919 100644 --- a/packages/netlify-cms-lib-util/src/__tests__/api.spec.js +++ b/packages/netlify-cms-lib-util/src/__tests__/api.spec.js @@ -97,11 +97,11 @@ describe('Api', () => { }); }); describe('getDefaultBranchName', () => { + const { + apiRoots, + endpointConstants: { singleRepo: staticRepoEndpoints }, + } = api; it('should return non-empty string as default branch', async () => { - const { - apiRoots, - endpointConstants: { singleRepo: staticRepoEndpoints }, - } = api; let normalizedRepoPath; for (const backendName in apiRoots) { if (backendName === 'gitlab') { @@ -111,7 +111,9 @@ describe('Api', () => { normalizedRepoPath = REPO_PATH; } const repoEndpoint = `${staticRepoEndpoints[backendName]}/${normalizedRepoPath}`; - interceptRepo({ apiRoot: apiRoots[backendName], repoEndpoint, backendName }); + const backendConfig = set(defaultConfig, 'backend.name', backendName) + backend = resolveBackend(backendConfig) + interceptRepo(backend, repoEndpoint); const defaultBranchName = await api.getDefaultBranchName({ backend: backendName, repo: REPO_PATH, From 6eb2ac328bf26cff03093e1e02f2e6053df5618e Mon Sep 17 00:00:00 2001 From: Trang Le Date: Mon, 11 Apr 2022 17:52:56 +0700 Subject: [PATCH 48/62] test(lib-util): add function for resolving backend --- .../src/__tests__/api.spec.js | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/packages/netlify-cms-lib-util/src/__tests__/api.spec.js b/packages/netlify-cms-lib-util/src/__tests__/api.spec.js index b06d39cc5919..522ce2d374a9 100644 --- a/packages/netlify-cms-lib-util/src/__tests__/api.spec.js +++ b/packages/netlify-cms-lib-util/src/__tests__/api.spec.js @@ -84,6 +84,38 @@ export function interceptRepo(backend, urlPath) { api.get(urlPath).query(true).reply(200, repoResp[backend.backendName]); } +let authStore, backend + +function resolveBackend(config = defaultConfig) { + const { backend: { name } } = config + authStore = new LocalStorageAuthStore() + const options = { backendName: name, config, authStore } + switch(name) { + case 'gitlab': + return new Backend( + { + init: (...args) => new GitLab(...args) + }, + options + ) + case 'bitbucket': + return new Backend( + { + init: (...args) => new BitBucket(...args) + }, + options + ) + default: + return new Backend( + { + init: (...args) => { + return new GitHub(...args) + } + }, + options + ) + } + } describe('Api', () => { From 6bfcf09c0f13b7fb77aae8283b748de4974a0a6a Mon Sep 17 00:00:00 2001 From: Trang Le Date: Mon, 11 Apr 2022 17:54:19 +0700 Subject: [PATCH 49/62] test(lib-util): import 'set' module from Lodash --- packages/netlify-cms-lib-util/src/__tests__/api.spec.js | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/netlify-cms-lib-util/src/__tests__/api.spec.js b/packages/netlify-cms-lib-util/src/__tests__/api.spec.js index 522ce2d374a9..5f46d8d2e654 100644 --- a/packages/netlify-cms-lib-util/src/__tests__/api.spec.js +++ b/packages/netlify-cms-lib-util/src/__tests__/api.spec.js @@ -1,4 +1,5 @@ import nock from 'nock'; +import { set } from 'lodash' import * as api from '../API'; From 53f143ae53498cacc29f5ba5c3fd17a8c957b43c Mon Sep 17 00:00:00 2001 From: Trang Le Date: Mon, 11 Apr 2022 17:56:23 +0700 Subject: [PATCH 50/62] test(lib-util): add helper for constructing url path for each backend --- .../netlify-cms-lib-util/src/__tests__/api.spec.js | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/packages/netlify-cms-lib-util/src/__tests__/api.spec.js b/packages/netlify-cms-lib-util/src/__tests__/api.spec.js index 5f46d8d2e654..d7b719c4ec4e 100644 --- a/packages/netlify-cms-lib-util/src/__tests__/api.spec.js +++ b/packages/netlify-cms-lib-util/src/__tests__/api.spec.js @@ -76,6 +76,16 @@ function mockApi(backend) { } export function interceptRepo(backend) { +function getRepoEndpoint(backendName, repo = REPO_PATH) { + const prefix = api.endpointConstants['singleRepo'][backendName] + switch(backendName) { + case 'gitlab': + return `${prefix}/${encodeURIComponent(repo)}` + default: + return `${prefix}/${repo}` + } +} + export function interceptRepo(backend, urlPath) { // A URL path given to Nock needs to start with a forward slash. if (urlPath[0] !== '/') { From 38f73a4f8f1c95c00367a3b585b9d744681fe7cb Mon Sep 17 00:00:00 2001 From: Trang Le Date: Mon, 11 Apr 2022 17:57:52 +0700 Subject: [PATCH 51/62] test(lib-util): add function for intercepting API request to authenticate --- .../src/__tests__/api.spec.js | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/packages/netlify-cms-lib-util/src/__tests__/api.spec.js b/packages/netlify-cms-lib-util/src/__tests__/api.spec.js index d7b719c4ec4e..ef226e198710 100644 --- a/packages/netlify-cms-lib-util/src/__tests__/api.spec.js +++ b/packages/netlify-cms-lib-util/src/__tests__/api.spec.js @@ -75,7 +75,23 @@ function mockApi(backend) { return nock(backend.implementation.apiRoot); } -export function interceptRepo(backend) { +function interceptAuth(backend, { userResponse, projectResponse } = {}) { + const { backendName, implementation: { repo } } = backend + const repoEndpoint = getRepoEndpoint(backendName, repo) + console.log(repoEndpoint) + const api = mockApi(backend) + console.log(repoResp[backendName]) + api + .get('/user') + .query(true) + .reply(200, userResponse || userResp[backendName]['success']) + api + .get(repoEndpoint) + .times(2) + .query(true) + .reply(200, projectResponse || repoResp[backendName]) +} + function getRepoEndpoint(backendName, repo = REPO_PATH) { const prefix = api.endpointConstants['singleRepo'][backendName] switch(backendName) { From af9cd9b96236b1873134022b2f432c67af048f41 Mon Sep 17 00:00:00 2001 From: Trang Le Date: Mon, 11 Apr 2022 17:58:41 +0700 Subject: [PATCH 52/62] test(lib-util): import each backend module --- packages/netlify-cms-lib-util/src/__tests__/api.spec.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/netlify-cms-lib-util/src/__tests__/api.spec.js b/packages/netlify-cms-lib-util/src/__tests__/api.spec.js index ef226e198710..b8aa4c39bce5 100644 --- a/packages/netlify-cms-lib-util/src/__tests__/api.spec.js +++ b/packages/netlify-cms-lib-util/src/__tests__/api.spec.js @@ -1,5 +1,8 @@ import nock from 'nock'; import { set } from 'lodash' +import { GitLabBackend as GitLab } from 'netlify-cms-backend-gitlab' +import { GitHubBackend as GitHub } from 'netlify-cms-backend-github' +import { BitbucketBackend as BitBucket } from 'netlify-cms-backend-bitbucket'; import * as api from '../API'; From 14ddaa79128b83cb18f82d65dbdd18a9e23a8a48 Mon Sep 17 00:00:00 2001 From: Trang Le Date: Wed, 13 Apr 2022 16:29:22 +0700 Subject: [PATCH 53/62] test(lib-util): add tests that check each backend calls getDefaultBranchName --- .../src/__tests__/api.spec.js | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/packages/netlify-cms-lib-util/src/__tests__/api.spec.js b/packages/netlify-cms-lib-util/src/__tests__/api.spec.js index b8aa4c39bce5..c9e08cf64b36 100644 --- a/packages/netlify-cms-lib-util/src/__tests__/api.spec.js +++ b/packages/netlify-cms-lib-util/src/__tests__/api.spec.js @@ -184,5 +184,22 @@ describe('Api', () => { expect(defaultBranchName).not.toBe(''); } }); + + describe('getDefaultBranchName is called by each backend', () => { + for (const b in repoResp) { + it(`getDefaultBranchName is called by ${b} backend`, async () => { + const backendConfig = set(defaultConfig, 'backend.name', b) + const spy = jest.spyOn(api, 'getDefaultBranchName') + backend = resolveBackend(backendConfig) + const { backendName, implementation: { repo } } = backend + interceptAuth(backend) + await backend.authenticate(MOCK_CREDENTIALS) + const args = { backend: backendName, repo, ...MOCK_CREDENTIALS } + expect(spy).toHaveBeenCalledWith(args) + spy.mockRestore() + expect(1).toEqual(1) + }) + } + }) }); }); From 1789e6fe41f594e65192baa2e51f3d52c5974f17 Mon Sep 17 00:00:00 2001 From: erezrokah Date: Wed, 13 Apr 2022 13:00:11 +0300 Subject: [PATCH 54/62] style: format files --- jest.config.js | 3 +- .../src/__tests__/api.spec.js | 129 +++++++++--------- 2 files changed, 70 insertions(+), 62 deletions(-) diff --git a/jest.config.js b/jest.config.js index 1646831982ce..9b0960daa44f 100644 --- a/jest.config.js +++ b/jest.config.js @@ -6,7 +6,8 @@ module.exports = { 'netlify-cms-ui-default': '/packages/netlify-cms-ui-default/src/index.js', 'netlify-cms-backend-github': '/packages/netlify-cms-backend-github/src/index.ts', 'netlify-cms-backend-gitlab': '/packages/netlify-cms-backend-gitlab/src/index.ts', - 'netlify-cms-backend-bitbucket': '/packages/netlify-cms-backend-bitbucket/src/index.ts', + 'netlify-cms-backend-bitbucket': + '/packages/netlify-cms-backend-bitbucket/src/index.ts', 'netlify-cms-lib-widgets': '/packages/netlify-cms-lib-widgets/src/index.ts', 'netlify-cms-widget-object': '/packages/netlify-cms-widget-object/src/index.js', '\\.(css|less)$': '/__mocks__/styleMock.js', diff --git a/packages/netlify-cms-lib-util/src/__tests__/api.spec.js b/packages/netlify-cms-lib-util/src/__tests__/api.spec.js index c9e08cf64b36..82480d1b5f55 100644 --- a/packages/netlify-cms-lib-util/src/__tests__/api.spec.js +++ b/packages/netlify-cms-lib-util/src/__tests__/api.spec.js @@ -1,12 +1,12 @@ import nock from 'nock'; -import { set } from 'lodash' -import { GitLabBackend as GitLab } from 'netlify-cms-backend-gitlab' -import { GitHubBackend as GitHub } from 'netlify-cms-backend-github' +import { set } from 'lodash'; +import { GitLabBackend as GitLab } from 'netlify-cms-backend-gitlab'; +import { GitHubBackend as GitHub } from 'netlify-cms-backend-github'; import { BitbucketBackend as BitBucket } from 'netlify-cms-backend-bitbucket'; import * as api from '../API'; -const { Backend, LocalStorageAuthStore } = jest.requireActual('netlify-cms-core/src/backend') +const { Backend, LocalStorageAuthStore } = jest.requireActual('netlify-cms-core/src/backend'); const branchProp = { default_branch: 'master' }; @@ -14,7 +14,7 @@ const repoResp = { github: { ...branchProp, owner: { - login: 'owner' + login: 'owner', }, permissions: { pull: true, @@ -43,13 +43,13 @@ const repoResp = { const userResp = { github: { success: { - id: 1 - } + id: 1, + }, }, gitlab: { success: { - id: 1 - } + id: 1, + }, }, bitbucket: { success: { @@ -58,94 +58,98 @@ const userResp = { username: 'test', links: { avatar: { - href: 'https://example.com' - } - } - } - } -} + href: 'https://example.com', + }, + }, + }, + }, +}; const MOCK_CREDENTIALS = { token: 'MOCK_TOKEN' }; const REPO_PATH = 'foo/bar'; const defaultConfig = { backend: { name: 'github', - repo: REPO_PATH - } -} + repo: REPO_PATH, + }, +}; function mockApi(backend) { return nock(backend.implementation.apiRoot); } function interceptAuth(backend, { userResponse, projectResponse } = {}) { - const { backendName, implementation: { repo } } = backend - const repoEndpoint = getRepoEndpoint(backendName, repo) - console.log(repoEndpoint) - const api = mockApi(backend) - console.log(repoResp[backendName]) + const { + backendName, + implementation: { repo }, + } = backend; + const repoEndpoint = getRepoEndpoint(backendName, repo); + console.log(repoEndpoint); + const api = mockApi(backend); + console.log(repoResp[backendName]); api .get('/user') .query(true) - .reply(200, userResponse || userResp[backendName]['success']) + .reply(200, userResponse || userResp[backendName]['success']); api .get(repoEndpoint) .times(2) .query(true) - .reply(200, projectResponse || repoResp[backendName]) + .reply(200, projectResponse || repoResp[backendName]); } function getRepoEndpoint(backendName, repo = REPO_PATH) { - const prefix = api.endpointConstants['singleRepo'][backendName] - switch(backendName) { + const prefix = api.endpointConstants['singleRepo'][backendName]; + switch (backendName) { case 'gitlab': - return `${prefix}/${encodeURIComponent(repo)}` + return `${prefix}/${encodeURIComponent(repo)}`; default: - return `${prefix}/${repo}` + return `${prefix}/${repo}`; } } export function interceptRepo(backend, urlPath) { - // A URL path given to Nock needs to start with a forward slash. + // A URL path given to Nock needs to start with a forward slash. if (urlPath[0] !== '/') { - urlPath = `/${urlPath}` + urlPath = `/${urlPath}`; } const api = mockApi(backend); api.get(urlPath).query(true).reply(200, repoResp[backend.backendName]); } -let authStore, backend +let authStore, backend; function resolveBackend(config = defaultConfig) { - const { backend: { name } } = config - authStore = new LocalStorageAuthStore() - const options = { backendName: name, config, authStore } - switch(name) { + const { + backend: { name }, + } = config; + authStore = new LocalStorageAuthStore(); + const options = { backendName: name, config, authStore }; + switch (name) { case 'gitlab': return new Backend( { - init: (...args) => new GitLab(...args) + init: (...args) => new GitLab(...args), }, - options - ) + options, + ); case 'bitbucket': return new Backend( { - init: (...args) => new BitBucket(...args) + init: (...args) => new BitBucket(...args), }, - options - ) + options, + ); default: return new Backend( { init: (...args) => { - return new GitHub(...args) - } + return new GitHub(...args); + }, }, - options - ) + options, + ); } - } describe('Api', () => { @@ -173,8 +177,8 @@ describe('Api', () => { normalizedRepoPath = REPO_PATH; } const repoEndpoint = `${staticRepoEndpoints[backendName]}/${normalizedRepoPath}`; - const backendConfig = set(defaultConfig, 'backend.name', backendName) - backend = resolveBackend(backendConfig) + const backendConfig = set(defaultConfig, 'backend.name', backendName); + backend = resolveBackend(backendConfig); interceptRepo(backend, repoEndpoint); const defaultBranchName = await api.getDefaultBranchName({ backend: backendName, @@ -188,18 +192,21 @@ describe('Api', () => { describe('getDefaultBranchName is called by each backend', () => { for (const b in repoResp) { it(`getDefaultBranchName is called by ${b} backend`, async () => { - const backendConfig = set(defaultConfig, 'backend.name', b) - const spy = jest.spyOn(api, 'getDefaultBranchName') - backend = resolveBackend(backendConfig) - const { backendName, implementation: { repo } } = backend - interceptAuth(backend) - await backend.authenticate(MOCK_CREDENTIALS) - const args = { backend: backendName, repo, ...MOCK_CREDENTIALS } - expect(spy).toHaveBeenCalledWith(args) - spy.mockRestore() - expect(1).toEqual(1) - }) + const backendConfig = set(defaultConfig, 'backend.name', b); + const spy = jest.spyOn(api, 'getDefaultBranchName'); + backend = resolveBackend(backendConfig); + const { + backendName, + implementation: { repo }, + } = backend; + interceptAuth(backend); + await backend.authenticate(MOCK_CREDENTIALS); + const args = { backend: backendName, repo, ...MOCK_CREDENTIALS }; + expect(spy).toHaveBeenCalledWith(args); + spy.mockRestore(); + expect(1).toEqual(1); + }); } - }) + }); }); }); From 34375f4c6cb2880bed3c900fe26f68119b1de56a Mon Sep 17 00:00:00 2001 From: Trang Le Date: Tue, 17 May 2022 13:58:35 +0700 Subject: [PATCH 55/62] fix: query branch name before setting Github API service --- .../src/implementation.tsx | 30 +++++++++++-------- 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/packages/netlify-cms-backend-github/src/implementation.tsx b/packages/netlify-cms-backend-github/src/implementation.tsx index 5cc0b47b9ef1..6992c89a521a 100644 --- a/packages/netlify-cms-backend-github/src/implementation.tsx +++ b/packages/netlify-cms-backend-github/src/implementation.tsx @@ -302,6 +302,18 @@ export default class GitHub implements Implementation { async authenticate(state: Credentials) { this.token = state.token as string; + // Query the default branch name when the `branch` property is missing + // in the config file + if (!this.isBranchConfigured) { + const repoInfo = await fetch(`${this.apiRoot}/repos/${this.originRepo}`, { + headers: { Authorization: `token ${this.token}`} + }) + .then(res => res.json()) + .catch(() => null) + if (repoInfo && repoInfo.default_branch) { + this.branch = repoInfo.default_branch + } + } const apiCtor = this.useGraphql ? GraphQLAPI : API; this.api = new apiCtor({ token: this.token, @@ -334,18 +346,12 @@ export default class GitHub implements Implementation { throw new Error('Your GitHub user account does not have access to this repo.'); } - // Only set default branch name when the `branch` property is missing - // in the config file - if (!this.isBranchConfigured) { - const defaultBranchName = await getDefaultBranchName({ - backend: 'github', - repo: this.originRepo, - token: this.token, - }); - if (defaultBranchName) { - this.branch = defaultBranchName; - } - } + // if (!this.isBranchConfigured) { + // const defaultBranchName = await this.api.getDefaultBranchName() + // if (defaultBranchName) { + // this.branch = defaultBranchName; + // } + // } // Authorized user return { ...user, token: state.token as string, useOpenAuthoring: this.useOpenAuthoring }; From 7f6de72c728d7ebfb213a2aefc3bd587233e0dda Mon Sep 17 00:00:00 2001 From: Trang Le Date: Tue, 17 May 2022 14:02:00 +0700 Subject: [PATCH 56/62] fix: reformat implementation module of Github backend --- packages/netlify-cms-backend-github/src/implementation.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/netlify-cms-backend-github/src/implementation.tsx b/packages/netlify-cms-backend-github/src/implementation.tsx index 6992c89a521a..6cd651a12496 100644 --- a/packages/netlify-cms-backend-github/src/implementation.tsx +++ b/packages/netlify-cms-backend-github/src/implementation.tsx @@ -306,12 +306,12 @@ export default class GitHub implements Implementation { // in the config file if (!this.isBranchConfigured) { const repoInfo = await fetch(`${this.apiRoot}/repos/${this.originRepo}`, { - headers: { Authorization: `token ${this.token}`} + headers: { Authorization: `token ${this.token}` }, }) .then(res => res.json()) - .catch(() => null) + .catch(() => null); if (repoInfo && repoInfo.default_branch) { - this.branch = repoInfo.default_branch + this.branch = repoInfo.default_branch; } } const apiCtor = this.useGraphql ? GraphQLAPI : API; From ec0ff89371aa0629eb7b3e0745e708a0fb854fd8 Mon Sep 17 00:00:00 2001 From: Trang Le Date: Tue, 17 May 2022 16:50:11 +0700 Subject: [PATCH 57/62] fix: remove importing of getDefaultBranchName from lib --- packages/netlify-cms-backend-github/src/implementation.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/netlify-cms-backend-github/src/implementation.tsx b/packages/netlify-cms-backend-github/src/implementation.tsx index 6cd651a12496..5eaa37379680 100644 --- a/packages/netlify-cms-backend-github/src/implementation.tsx +++ b/packages/netlify-cms-backend-github/src/implementation.tsx @@ -20,7 +20,6 @@ import { contentKeyFromBranch, unsentRequest, branchFromContentKey, - getDefaultBranchName, } from 'netlify-cms-lib-util'; import AuthenticationPage from './AuthenticationPage'; From 48e71755531625c318e2735cee931268f832fe59 Mon Sep 17 00:00:00 2001 From: Trang Le Date: Thu, 19 May 2022 18:09:20 +0700 Subject: [PATCH 58/62] fix: removed test for getDefaultBranchName in lib packages --- .../src/__tests__/api.spec.js | 47 ------------------- 1 file changed, 47 deletions(-) diff --git a/packages/netlify-cms-lib-util/src/__tests__/api.spec.js b/packages/netlify-cms-lib-util/src/__tests__/api.spec.js index 82480d1b5f55..a9519dd0c03d 100644 --- a/packages/netlify-cms-lib-util/src/__tests__/api.spec.js +++ b/packages/netlify-cms-lib-util/src/__tests__/api.spec.js @@ -162,51 +162,4 @@ describe('Api', () => { expect(api.getPreviewStatus([{ context: 'other' }])).toBeUndefined(); }); }); - describe('getDefaultBranchName', () => { - const { - apiRoots, - endpointConstants: { singleRepo: staticRepoEndpoints }, - } = api; - it('should return non-empty string as default branch', async () => { - let normalizedRepoPath; - for (const backendName in apiRoots) { - if (backendName === 'gitlab') { - // Gitlab API requires the repo slug to be url-encoded - normalizedRepoPath = encodeURIComponent(REPO_PATH); - } else { - normalizedRepoPath = REPO_PATH; - } - const repoEndpoint = `${staticRepoEndpoints[backendName]}/${normalizedRepoPath}`; - const backendConfig = set(defaultConfig, 'backend.name', backendName); - backend = resolveBackend(backendConfig); - interceptRepo(backend, repoEndpoint); - const defaultBranchName = await api.getDefaultBranchName({ - backend: backendName, - repo: REPO_PATH, - token: MOCK_CREDENTIALS.token, - }); - expect(defaultBranchName).not.toBe(''); - } - }); - - describe('getDefaultBranchName is called by each backend', () => { - for (const b in repoResp) { - it(`getDefaultBranchName is called by ${b} backend`, async () => { - const backendConfig = set(defaultConfig, 'backend.name', b); - const spy = jest.spyOn(api, 'getDefaultBranchName'); - backend = resolveBackend(backendConfig); - const { - backendName, - implementation: { repo }, - } = backend; - interceptAuth(backend); - await backend.authenticate(MOCK_CREDENTIALS); - const args = { backend: backendName, repo, ...MOCK_CREDENTIALS }; - expect(spy).toHaveBeenCalledWith(args); - spy.mockRestore(); - expect(1).toEqual(1); - }); - } - }); - }); }); From 676631fd489f0f0f3a265d970c61bc7b9917c643 Mon Sep 17 00:00:00 2001 From: Trang Le Date: Thu, 19 May 2022 18:22:10 +0700 Subject: [PATCH 59/62] fix: removed unused vars in api test for lib package --- .../src/__tests__/api.spec.js | 152 ------------------ 1 file changed, 152 deletions(-) diff --git a/packages/netlify-cms-lib-util/src/__tests__/api.spec.js b/packages/netlify-cms-lib-util/src/__tests__/api.spec.js index a9519dd0c03d..6cf5e07806d0 100644 --- a/packages/netlify-cms-lib-util/src/__tests__/api.spec.js +++ b/packages/netlify-cms-lib-util/src/__tests__/api.spec.js @@ -1,157 +1,5 @@ -import nock from 'nock'; -import { set } from 'lodash'; -import { GitLabBackend as GitLab } from 'netlify-cms-backend-gitlab'; -import { GitHubBackend as GitHub } from 'netlify-cms-backend-github'; -import { BitbucketBackend as BitBucket } from 'netlify-cms-backend-bitbucket'; - import * as api from '../API'; -const { Backend, LocalStorageAuthStore } = jest.requireActual('netlify-cms-core/src/backend'); - -const branchProp = { default_branch: 'master' }; - -const repoResp = { - github: { - ...branchProp, - owner: { - login: 'owner', - }, - permissions: { - pull: true, - push: true, - admin: true, - }, - }, - gitlab: { - ...branchProp, - permissions: { - project_access: { - access_level: 30, // This means the user is at least a developer - // and can be a maintainer or owner. If this number is below - // 30, user is not a collaborator and Gitlab API will throw - // an error - }, - }, - }, - bitbucket: { - mainbranch: { - name: 'master', - }, - }, -}; - -const userResp = { - github: { - success: { - id: 1, - }, - }, - gitlab: { - success: { - id: 1, - }, - }, - bitbucket: { - success: { - id: 1, - display_name: 'Test Account', - username: 'test', - links: { - avatar: { - href: 'https://example.com', - }, - }, - }, - }, -}; - -const MOCK_CREDENTIALS = { token: 'MOCK_TOKEN' }; -const REPO_PATH = 'foo/bar'; -const defaultConfig = { - backend: { - name: 'github', - repo: REPO_PATH, - }, -}; - -function mockApi(backend) { - return nock(backend.implementation.apiRoot); -} - -function interceptAuth(backend, { userResponse, projectResponse } = {}) { - const { - backendName, - implementation: { repo }, - } = backend; - const repoEndpoint = getRepoEndpoint(backendName, repo); - console.log(repoEndpoint); - const api = mockApi(backend); - console.log(repoResp[backendName]); - api - .get('/user') - .query(true) - .reply(200, userResponse || userResp[backendName]['success']); - api - .get(repoEndpoint) - .times(2) - .query(true) - .reply(200, projectResponse || repoResp[backendName]); -} - -function getRepoEndpoint(backendName, repo = REPO_PATH) { - const prefix = api.endpointConstants['singleRepo'][backendName]; - switch (backendName) { - case 'gitlab': - return `${prefix}/${encodeURIComponent(repo)}`; - default: - return `${prefix}/${repo}`; - } -} - -export function interceptRepo(backend, urlPath) { - // A URL path given to Nock needs to start with a forward slash. - if (urlPath[0] !== '/') { - urlPath = `/${urlPath}`; - } - const api = mockApi(backend); - api.get(urlPath).query(true).reply(200, repoResp[backend.backendName]); -} - -let authStore, backend; - -function resolveBackend(config = defaultConfig) { - const { - backend: { name }, - } = config; - authStore = new LocalStorageAuthStore(); - const options = { backendName: name, config, authStore }; - switch (name) { - case 'gitlab': - return new Backend( - { - init: (...args) => new GitLab(...args), - }, - options, - ); - case 'bitbucket': - return new Backend( - { - init: (...args) => new BitBucket(...args), - }, - options, - ); - default: - return new Backend( - { - init: (...args) => { - return new GitHub(...args); - }, - }, - options, - ); - } -} - describe('Api', () => { describe('getPreviewStatus', () => { it('should return preview status on matching context', () => { From 614a5b0bb5de9ee45031270bf47c8e73871059f8 Mon Sep 17 00:00:00 2001 From: Trang Le Date: Thu, 26 May 2022 17:01:18 +0700 Subject: [PATCH 60/62] feat: retrieve default branch before creating Bitbucket AI instance --- .../src/implementation.ts | 35 +++++++++++++------ 1 file changed, 24 insertions(+), 11 deletions(-) diff --git a/packages/netlify-cms-backend-bitbucket/src/implementation.ts b/packages/netlify-cms-backend-bitbucket/src/implementation.ts index 8e1986713a80..c6f9e55d85d7 100644 --- a/packages/netlify-cms-backend-bitbucket/src/implementation.ts +++ b/packages/netlify-cms-backend-bitbucket/src/implementation.ts @@ -25,7 +25,6 @@ import { allEntriesByFolder, AccessTokenError, branchFromContentKey, - getDefaultBranchName, } from 'netlify-cms-lib-util'; import { NetlifyAuthenticator } from 'netlify-cms-lib-auth'; @@ -61,6 +60,8 @@ type BitbucketStatusComponent = { status: string; }; +const { fetchWithTimeout: fetch } = unsentRequest + // Implementation wrapper class export default class BitbucketBackend implements Implementation { lock: AsyncLock; @@ -193,6 +194,18 @@ export default class BitbucketBackend implements Implementation { async authenticate(state: Credentials) { this.token = state.token as string; + if (!this.isBranchConfigured) { + const repo = await fetch(`${this.apiRoot}/repositories/${this.repo}`, { + headers: { + Authorization: `token ${this.token}` + } + }) + .then(res => res.json()) + .catch(() => null) + if (repo) { + this.branch = repo.mainbranch.name + } + } this.refreshToken = state.refresh_token; this.api = new API({ requestFunction: this.apiRequestFunction, @@ -219,16 +232,16 @@ export default class BitbucketBackend implements Implementation { if (!isCollab) { throw new Error('Your BitBucket user account does not have access to this repo.'); } - if (!this.isBranchConfigured) { - const defaultBranchName = await getDefaultBranchName({ - backend: 'bitbucket', - repo: this.repo, - token: this.token, - }); - if (defaultBranchName) { - this.branch = defaultBranchName; - } - } + // if (!this.isBranchConfigured) { + // const defaultBranchName = await getDefaultBranchName({ + // backend: 'bitbucket', + // repo: this.repo, + // token: this.token, + // }); + // if (defaultBranchName) { + // this.branch = defaultBranchName; + // } + // } const user = await this.api.user(); // Authorized user From 20caf5ff762ab7df1ccf00c2eb162d5d5c7f3172 Mon Sep 17 00:00:00 2001 From: Trang Le Date: Thu, 26 May 2022 17:07:19 +0700 Subject: [PATCH 61/62] fix: reformat codes in Bitbucket implementation module --- .../src/implementation.ts | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/packages/netlify-cms-backend-bitbucket/src/implementation.ts b/packages/netlify-cms-backend-bitbucket/src/implementation.ts index c6f9e55d85d7..31ebe488e537 100644 --- a/packages/netlify-cms-backend-bitbucket/src/implementation.ts +++ b/packages/netlify-cms-backend-bitbucket/src/implementation.ts @@ -60,7 +60,7 @@ type BitbucketStatusComponent = { status: string; }; -const { fetchWithTimeout: fetch } = unsentRequest +const { fetchWithTimeout: fetch } = unsentRequest; // Implementation wrapper class export default class BitbucketBackend implements Implementation { @@ -197,14 +197,14 @@ export default class BitbucketBackend implements Implementation { if (!this.isBranchConfigured) { const repo = await fetch(`${this.apiRoot}/repositories/${this.repo}`, { headers: { - Authorization: `token ${this.token}` - } + Authorization: `token ${this.token}`, + }, }) .then(res => res.json()) - .catch(() => null) - if (repo) { - this.branch = repo.mainbranch.name - } + .catch(() => null); + if (repo) { + this.branch = repo.mainbranch.name; + } } this.refreshToken = state.refresh_token; this.api = new API({ From c6b05f8c6a7cb4bf067f40e785366ac7da2e74d6 Mon Sep 17 00:00:00 2001 From: Anze Demsar Date: Tue, 2 Apr 2024 08:59:21 +0200 Subject: [PATCH 62/62] fix: add missing import --- packages/decap-cms-backend-gitlab/src/implementation.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/decap-cms-backend-gitlab/src/implementation.ts b/packages/decap-cms-backend-gitlab/src/implementation.ts index e79fc116e413..769257f0bea3 100644 --- a/packages/decap-cms-backend-gitlab/src/implementation.ts +++ b/packages/decap-cms-backend-gitlab/src/implementation.ts @@ -21,6 +21,7 @@ import { allEntriesByFolder, filterByExtension, branchFromContentKey, + getDefaultBranchName, } from 'decap-cms-lib-util'; import AuthenticationPage from './AuthenticationPage';