diff --git a/src/actions/sync_backend.js b/src/actions/sync_backend.js index adb04bb7e..6a415f678 100644 --- a/src/actions/sync_backend.js +++ b/src/actions/sync_backend.js @@ -28,6 +28,7 @@ export const signOut = () => (dispatch, getState) => { break; case 'GitLab': persistField('gitLabProject', null); + persistField('gitLabHost', null); createGitlabOAuth().reset(); break; default: diff --git a/src/components/SyncServiceSignIn/index.js b/src/components/SyncServiceSignIn/index.js index 487466a94..14b96c0c7 100644 --- a/src/components/SyncServiceSignIn/index.js +++ b/src/components/SyncServiceSignIn/index.js @@ -113,9 +113,10 @@ function GitLab() { const defaultProject = 'https://gitlab.com/your/project'; const [project, setProject] = useState(defaultProject); const handleSubmit = (evt) => { - const projectId = gitLabProjectIdFromURL(project); + const [hostname, projectId] = gitLabProjectIdFromURL(project); if (projectId) { persistField('authenticatedSyncService', 'GitLab'); + persistField('gitLabHost', hostname); persistField('gitLabProject', projectId); createGitlabOAuth().fetchAuthorizationCode(); } else { diff --git a/src/sync_backend_clients/gitlab_sync_backend_client.js b/src/sync_backend_clients/gitlab_sync_backend_client.js index 92fefc7ee..13c518683 100644 --- a/src/sync_backend_clients/gitlab_sync_backend_client.js +++ b/src/sync_backend_clients/gitlab_sync_backend_client.js @@ -12,8 +12,8 @@ export const createGitlabOAuth = () => { let expiryPromise; let invalidGrantPromise; return new OAuth2AuthCodePKCE({ - authorizationUrl: 'https://gitlab.com/oauth/authorize', - tokenUrl: 'https://gitlab.com/oauth/token', + authorizationUrl: `https://${getPersistedField('gitLabHost')}/oauth/authorize`, + tokenUrl: `https://${getPersistedField('gitLabHost')}/oauth/token`, clientId: process.env.REACT_APP_GITLAB_CLIENT_ID, redirectUrl: window.location.origin, scopes: ['api'], @@ -64,8 +64,8 @@ export const gitLabProjectIdFromURL = (projectURL) => { // to a project. Reminder: a project path is not necessarily // /user/project because it may be under one or more groups such // as /user/group/subgroup/project. - if (url.hostname === 'gitlab.com' && path.split('/').length > 1) { - return encodeURIComponent(path); + if (path.split('/').length > 1) { + return [url.hostname, encodeURIComponent(path)]; } else { return undefined; } @@ -130,8 +130,6 @@ export const treeToDirectoryListing = (tree) => { ); }; -const API_URL = 'https://gitlab.com/api/v4'; - /** * GitLab sync backend, implemented using their REST API. * @@ -141,7 +139,9 @@ const API_URL = 'https://gitlab.com/api/v4'; export default (oauthClient) => { const decoratedFetch = oauthClient.decorateFetchHTTPClient(fetch); - const getProjectApi = () => `${API_URL}/projects/${getPersistedField('gitLabProject')}`; + const getApiUrl = () => `https://${getPersistedField('gitLabHost')}/api/v4`; + + const getProjectApi = () => `${getApiUrl()}/projects/${getPersistedField('gitLabProject')}`; const isSignedIn = async () => { if (!oauthClient.isAuthorized()) { @@ -174,7 +174,7 @@ export default (oauthClient) => { // commit. const [userResponse, membersResponse] = await Promise.all([ // https://docs.gitlab.com/ee/api/users.html#list-current-user-for-normal-users - decoratedFetch(`${API_URL}/user`), + decoratedFetch(`${getApiUrl()}/user`), // https://docs.gitlab.com/ee/api/members.html#list-all-members-of-a-group-or-project decoratedFetch(`${getProjectApi()}/members`), ]); diff --git a/src/sync_backend_clients/gitlab_sync_backend_client.test.js b/src/sync_backend_clients/gitlab_sync_backend_client.test.js index 24d285916..03c5faa57 100644 --- a/src/sync_backend_clients/gitlab_sync_backend_client.test.js +++ b/src/sync_backend_clients/gitlab_sync_backend_client.test.js @@ -7,9 +7,11 @@ import { test('Parses GitLab project from URL', () => { [ - ['https://gitlab.com/user/foo', 'user%2Ffoo'], - ['https://gitlab.com/group/subgroup/project', 'group%2Fsubgroup%2Fproject'], - ['gitlab.com/foo/bar', 'foo%2Fbar'], + ['https://gitlab.com/user/foo', ['gitlab.com', 'user%2Ffoo']], + ['https://gitlab.com/group/subgroup/project', ['gitlab.com', 'group%2Fsubgroup%2Fproject']], + ['https://gitlab.example.com/user/foo', ['gitlab.example.com', 'user%2Ffoo']], + ['gitlab.com/foo/bar', ['gitlab.com', 'foo%2Fbar']], + ['gitlab.example.com/foo/bar', ['gitlab.example.com', 'foo%2Fbar']], ['gitlab.com/user-but-no-project', undefined], ['', undefined], ].forEach(([input, expected]) => {