Skip to content

Commit 64ad5b2

Browse files
authored
Merge pull request #810 from fcollonval/fcollonval/issue809
Fixes top repository refresh
2 parents c7cf93f + 0f923ad commit 64ad5b2

File tree

4 files changed

+134
-44
lines changed

4 files changed

+134
-44
lines changed

src/model.ts

Lines changed: 52 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -137,26 +137,18 @@ export class GitExtension implements IGitExtension {
137137
const currentReady = this._readyPromise;
138138
this._pendingReadyPromise += 1;
139139
this._readyPromise = Promise.all([currentReady, this.showTopLevel(v)])
140-
.then(r => {
141-
const results = r[1];
142-
if (results.code === 0) {
143-
this._pathRepository = results.top_repo_path;
144-
change.newValue = results.top_repo_path;
145-
} else {
146-
this._pathRepository = null;
147-
}
140+
.then(([_, path]) => {
141+
change.newValue = this._pathRepository = path;
148142

149143
if (change.newValue !== change.oldValue) {
150144
this.refresh().then(() => this._repositoryChanged.emit(change));
151145
}
146+
this._pendingReadyPromise -= 1;
152147
})
153148
.catch(reason => {
149+
this._pendingReadyPromise -= 1;
154150
console.error(`Fail to find Git top level for path ${v}.\n${reason}`);
155151
});
156-
157-
void this._readyPromise.then(() => {
158-
this._pendingReadyPromise -= 1;
159-
});
160152
}
161153
}
162154

@@ -865,15 +857,31 @@ export class GitExtension implements IGitExtension {
865857
* @throws {Git.GitResponseError} If the server response is not ok
866858
* @throws {ServerConnection.NetworkError} If the request cannot be made
867859
*/
868-
async showPrefix(path: string): Promise<Git.IShowPrefixResult> {
869-
return await this._taskHandler.execute<Git.IShowPrefixResult>(
870-
'git:fetch:prefix_path',
871-
async () => {
872-
return await requestAPI<Git.IShowPrefixResult>('show_prefix', 'POST', {
873-
current_path: path
874-
});
860+
async showPrefix(path: string): Promise<string | null> {
861+
try {
862+
const data = await this._taskHandler.execute<Git.IShowPrefixResult>(
863+
'git:fetch:prefix_path',
864+
async () => {
865+
return await requestAPI<Git.IShowPrefixResult>(
866+
'show_prefix',
867+
'POST',
868+
{
869+
current_path: path
870+
}
871+
);
872+
}
873+
);
874+
return data.under_repo_path || null;
875+
} catch (error) {
876+
if (
877+
error instanceof Git.GitResponseError &&
878+
error.response.status === 500 &&
879+
error.json.code === 128
880+
) {
881+
return null;
875882
}
876-
);
883+
throw error;
884+
}
877885
}
878886

879887
/**
@@ -885,19 +893,31 @@ export class GitExtension implements IGitExtension {
885893
* @throws {Git.GitResponseError} If the server response is not ok
886894
* @throws {ServerConnection.NetworkError} If the request cannot be made
887895
*/
888-
async showTopLevel(path: string): Promise<Git.IShowTopLevelResult> {
889-
return await this._taskHandler.execute<Git.IShowTopLevelResult>(
890-
'git:fetch:top_level_path',
891-
async () => {
892-
return await requestAPI<Git.IShowTopLevelResult>(
893-
'show_top_level',
894-
'POST',
895-
{
896-
current_path: path
897-
}
898-
);
896+
async showTopLevel(path: string): Promise<string | null> {
897+
try {
898+
const data = await this._taskHandler.execute<Git.IShowTopLevelResult>(
899+
'git:fetch:top_level_path',
900+
async () => {
901+
return await requestAPI<Git.IShowTopLevelResult>(
902+
'show_top_level',
903+
'POST',
904+
{
905+
current_path: path
906+
}
907+
);
908+
}
909+
);
910+
return data.top_repo_path || null;
911+
} catch (error) {
912+
if (
913+
error instanceof Git.GitResponseError &&
914+
error.response.status === 500 &&
915+
error.json.code === 128
916+
) {
917+
return null;
899918
}
900-
);
919+
throw error;
920+
}
901921
}
902922

903923
/**

src/tokens.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -374,7 +374,7 @@ export interface IGitExtension extends IDisposable {
374374
revertCommit(message: string, hash: string): Promise<void>;
375375

376376
/**
377-
* Make request for the prefix path of a directory 'path',
377+
* Get the prefix path of a directory 'path',
378378
* with respect to the root directory of repository
379379
*
380380
* @param path Path for which the prefix is searched for
@@ -383,17 +383,17 @@ export interface IGitExtension extends IDisposable {
383383
* @throws {Git.GitResponseError} If the server response is not ok
384384
* @throws {ServerConnection.NetworkError} If the request cannot be made
385385
*/
386-
showPrefix(path: string): Promise<Git.IShowPrefixResult>;
386+
showPrefix(path: string): Promise<string | null>;
387387

388388
/**
389-
* Make request for top level path of repository 'path'
389+
* Get the top level path of repository 'path'
390390
*
391391
* @param path Path from which the top Git repository needs to be found
392392
*
393393
* @throws {Git.GitResponseError} If the server response is not ok
394394
* @throws {ServerConnection.NetworkError} If the request cannot be made
395395
*/
396-
showTopLevel(path: string): Promise<Git.IShowTopLevelResult>;
396+
showTopLevel(path: string): Promise<string | null>;
397397

398398
/**
399399
* Make request to list all the tags present in the remote repo

tests/GitExtension.spec.tsx renamed to tests/model.spec.tsx

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,82 @@ describe('IGitExtension', () => {
119119
});
120120
});
121121

122+
describe('#showPrefix', () => {
123+
it('should return a string if the folder is a git repository', async () => {
124+
const fakeRepo = '/repo';
125+
mockResponses['show_prefix'] = {
126+
body: () => {
127+
return { code: 0, under_repo_path: fakeRepo };
128+
}
129+
};
130+
const topLevel = await model.showPrefix('/repo/cwd');
131+
expect(topLevel).toEqual(fakeRepo);
132+
});
133+
134+
it('should return null if the repository is not a git repository', async () => {
135+
mockResponses['show_prefix'] = {
136+
body: () => {
137+
return { code: 128 };
138+
},
139+
status: 500
140+
};
141+
const topLevel = await model.showPrefix('/repo/cwd');
142+
expect(topLevel).toBeNull();
143+
});
144+
145+
it('should throw an exception if the server otherwise', async () => {
146+
mockResponses['show_prefix'] = {
147+
body: () => {
148+
return { code: 128 };
149+
},
150+
status: 401
151+
};
152+
try {
153+
await model.showPrefix('/repo/cwd');
154+
} catch (error) {
155+
expect(error).toBeInstanceOf(Git.GitResponseError);
156+
}
157+
});
158+
});
159+
160+
describe('#showTopLevel', () => {
161+
it('should return a string if the folder is a git repository', async () => {
162+
const fakeRepo = '/path/to/repo';
163+
mockResponses['show_top_level'] = {
164+
body: () => {
165+
return { code: 0, top_repo_path: fakeRepo };
166+
}
167+
};
168+
const topLevel = await model.showTopLevel('/path/to/repo/cwd');
169+
expect(topLevel).toEqual(fakeRepo);
170+
});
171+
172+
it('should return null if the repository is not a git repository', async () => {
173+
mockResponses['show_top_level'] = {
174+
body: () => {
175+
return { code: 128 };
176+
},
177+
status: 500
178+
};
179+
const topLevel = await model.showTopLevel('/path/to/repo/cwd');
180+
expect(topLevel).toBeNull();
181+
});
182+
183+
it('should throw an exception if the server otherwise', async () => {
184+
mockResponses['show_top_level'] = {
185+
body: () => {
186+
return { code: 128 };
187+
},
188+
status: 401
189+
};
190+
try {
191+
await model.showTopLevel('/path/to/repo/cwd');
192+
} catch (error) {
193+
expect(error).toBeInstanceOf(Git.GitResponseError);
194+
}
195+
});
196+
});
197+
122198
describe('#status', () => {
123199
it('should be an empty list if not in a git repository', async () => {
124200
let status: Git.IStatusFileResult[] = [];

tests/plugin.spec.ts

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,7 @@ import { ISettingRegistry, SettingRegistry } from '@jupyterlab/settingregistry';
66
import { JupyterLab } from '@jupyterlab/application';
77
import { showErrorMessage } from '@jupyterlab/apputils';
88
import { URLExt } from '@jupyterlab/coreutils';
9-
import { ReadonlyJSONObject } from '@lumino/coreutils';
10-
import { mockedRequestAPI } from './utils';
9+
import { IMockedResponses, mockedRequestAPI } from './utils';
1110

1211
jest.mock('../src/git');
1312
jest.mock('@jupyterlab/application');
@@ -18,12 +17,7 @@ describe('plugin', () => {
1817
const mockGit = git as jest.Mocked<typeof git>;
1918
const fakeRoot = '/path/to/server';
2019
let app: jest.Mocked<JupyterLab>;
21-
let mockResponses: {
22-
[url: string]: {
23-
body?: (request: Object) => ReadonlyJSONObject;
24-
status?: number;
25-
};
26-
} = {};
20+
let mockResponses: IMockedResponses = {};
2721
let settingRegistry: jest.Mocked<ISettingRegistry>;
2822

2923
beforeAll(() => {

0 commit comments

Comments
 (0)