mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 17:28:26 -04:00
parent
15dc75cc51
commit
92e70ca7c0
4 changed files with 166 additions and 68 deletions
|
@ -169,7 +169,7 @@
|
|||
"@elastic/javascript-typescript-langserver": "^0.1.23",
|
||||
"@elastic/lsp-extension": "^0.1.1",
|
||||
"@elastic/node-crypto": "^1.0.0",
|
||||
"@elastic/nodegit": "0.25.0-alpha.19",
|
||||
"@elastic/nodegit": "0.25.0-alpha.20",
|
||||
"@elastic/numeral": "2.3.3",
|
||||
"@kbn/babel-preset": "1.0.0",
|
||||
"@kbn/elastic-idx": "1.0.0",
|
||||
|
|
|
@ -8,7 +8,7 @@ import Git from '@elastic/nodegit';
|
|||
import fs from 'fs';
|
||||
import mkdirp from 'mkdirp';
|
||||
import path from 'path';
|
||||
// import rimraf from 'rimraf';
|
||||
import rimraf from 'rimraf';
|
||||
import sinon from 'sinon';
|
||||
|
||||
import assert from 'assert';
|
||||
|
@ -39,15 +39,16 @@ const packagejson = `
|
|||
}
|
||||
`;
|
||||
describe('lsp_service tests', () => {
|
||||
let firstCommitSha = '';
|
||||
let secondCommitSha = '';
|
||||
async function prepareProject(repoPath: string) {
|
||||
mkdirp.sync(repoPath);
|
||||
const repo = await Git.Repository.init(repoPath, 0);
|
||||
const helloContent = "console.log('hello world');";
|
||||
fs.writeFileSync(path.join(repo.workdir(), filename), helloContent, 'utf8');
|
||||
fs.writeFileSync(path.join(repo.workdir(), 'package.json'), packagejson, 'utf8');
|
||||
const index = await repo.refreshIndex();
|
||||
|
||||
let index = await repo.refreshIndex();
|
||||
await index.addByPath(filename);
|
||||
await index.addByPath('package.json');
|
||||
index.write();
|
||||
const treeId = await index.writeTree();
|
||||
const committer = Git.Signature.create('tester', 'test@test.com', Date.now() / 1000, 60);
|
||||
|
@ -59,8 +60,22 @@ describe('lsp_service tests', () => {
|
|||
treeId,
|
||||
[]
|
||||
);
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(`created commit ${commit.tostrS()}`);
|
||||
firstCommitSha = commit.tostrS();
|
||||
fs.writeFileSync(path.join(repo.workdir(), 'package.json'), packagejson, 'utf8');
|
||||
index = await repo.refreshIndex();
|
||||
await index.addByPath('package.json');
|
||||
index.write();
|
||||
const treeId2 = await index.writeTree();
|
||||
const commit2 = await repo.createCommit(
|
||||
'HEAD',
|
||||
committer,
|
||||
committer,
|
||||
'commit2 for test',
|
||||
treeId2,
|
||||
[commit]
|
||||
);
|
||||
secondCommitSha = commit2.tostrS();
|
||||
|
||||
return repo;
|
||||
}
|
||||
|
||||
|
@ -109,11 +124,9 @@ describe('lsp_service tests', () => {
|
|||
return path.resolve(pa) === path.resolve(pb);
|
||||
}
|
||||
|
||||
it('process a hover request', async () => {
|
||||
function mockLspService() {
|
||||
const esClient = mockEsClient();
|
||||
const revision = 'master';
|
||||
|
||||
const lspservice = new LspService(
|
||||
return new LspService(
|
||||
'127.0.0.1',
|
||||
serverOptions,
|
||||
esClient,
|
||||
|
@ -121,24 +134,34 @@ describe('lsp_service tests', () => {
|
|||
new ConsoleLoggerFactory(),
|
||||
new RepositoryConfigController(esClient)
|
||||
);
|
||||
}
|
||||
|
||||
async function sendHoverRequest(lspservice: LspService, revision: string) {
|
||||
const method = 'textDocument/hover';
|
||||
|
||||
const params = {
|
||||
textDocument: {
|
||||
uri: `git://${repoUri}/blob/${revision}/${filename}`,
|
||||
},
|
||||
position: {
|
||||
line: 0,
|
||||
character: 1,
|
||||
},
|
||||
};
|
||||
return await lspservice.sendRequest(method, params);
|
||||
}
|
||||
|
||||
it('process a hover request', async () => {
|
||||
const lspservice = mockLspService();
|
||||
try {
|
||||
const params = {
|
||||
textDocument: {
|
||||
uri: `git://${repoUri}/blob/${revision}/${filename}`,
|
||||
},
|
||||
position: {
|
||||
line: 0,
|
||||
character: 1,
|
||||
},
|
||||
};
|
||||
const workspaceHandler = lspservice.workspaceHandler;
|
||||
const wsSpy = sinon.spy(workspaceHandler, 'handleRequest');
|
||||
const controller = lspservice.controller;
|
||||
const ctrlSpy = sinon.spy(controller, 'handleRequest');
|
||||
|
||||
const method = 'textDocument/hover';
|
||||
const revision = 'master';
|
||||
|
||||
const response = await lspservice.sendRequest(method, params);
|
||||
const response = await sendHoverRequest(lspservice, revision);
|
||||
assert.ok(response);
|
||||
assert.ok(response.result.contents);
|
||||
|
||||
|
@ -172,30 +195,11 @@ describe('lsp_service tests', () => {
|
|||
}).timeout(10000);
|
||||
|
||||
it('unload a workspace', async () => {
|
||||
const esClient = mockEsClient();
|
||||
const revision = 'master';
|
||||
const lspservice = new LspService(
|
||||
'127.0.0.1',
|
||||
serverOptions,
|
||||
esClient,
|
||||
installManager,
|
||||
new ConsoleLoggerFactory(),
|
||||
new RepositoryConfigController(esClient)
|
||||
);
|
||||
const lspservice = mockLspService();
|
||||
try {
|
||||
const params = {
|
||||
textDocument: {
|
||||
uri: `git://${repoUri}/blob/${revision}/${filename}`,
|
||||
},
|
||||
position: {
|
||||
line: 0,
|
||||
character: 1,
|
||||
},
|
||||
};
|
||||
|
||||
const method = 'textDocument/hover';
|
||||
const revision = 'master';
|
||||
// send a dummy request to open a workspace;
|
||||
const response = await lspservice.sendRequest(method, params);
|
||||
const response = await sendHoverRequest(lspservice, revision);
|
||||
assert.ok(response);
|
||||
const workspacePath = path.resolve(serverOptions.workspacePath, repoUri, revision);
|
||||
const workspaceFolderExists = fs.existsSync(workspacePath);
|
||||
|
@ -228,4 +232,65 @@ describe('lsp_service tests', () => {
|
|||
}
|
||||
// @ts-ignore
|
||||
}).timeout(10000);
|
||||
|
||||
it('should work if a worktree exists', async () => {
|
||||
const lspservice = mockLspService();
|
||||
try {
|
||||
const revision = 'master';
|
||||
// send a dummy request to open a workspace;
|
||||
const response = await sendHoverRequest(lspservice, revision);
|
||||
assert.ok(response);
|
||||
const workspacePath = path.resolve(serverOptions.workspacePath, repoUri, revision);
|
||||
const workspaceFolderExists = fs.existsSync(workspacePath);
|
||||
// workspace is opened
|
||||
assert.ok(workspaceFolderExists);
|
||||
const bareRepoWorktree = path.join(
|
||||
serverOptions.repoPath,
|
||||
repoUri,
|
||||
'worktrees',
|
||||
`workspace-${revision}`
|
||||
);
|
||||
// worktree is exists
|
||||
const bareRepoWorktreeExists = fs.existsSync(bareRepoWorktree);
|
||||
assert.ok(bareRepoWorktreeExists);
|
||||
// delete the workspace folder but leave worktree
|
||||
rimraf.sync(workspacePath);
|
||||
// send a dummy request to open it again
|
||||
await sendHoverRequest(lspservice, revision);
|
||||
assert.ok(fs.existsSync(workspacePath));
|
||||
|
||||
return;
|
||||
} finally {
|
||||
await lspservice.shutdown();
|
||||
}
|
||||
// @ts-ignore
|
||||
}).timeout(10000);
|
||||
|
||||
it('should update if a worktree is not the newest', async () => {
|
||||
const lspservice = mockLspService();
|
||||
try {
|
||||
const revision = 'master';
|
||||
// send a dummy request to open a workspace;
|
||||
const response = await sendHoverRequest(lspservice, revision);
|
||||
assert.ok(response);
|
||||
const workspacePath = path.resolve(serverOptions.workspacePath, repoUri, revision);
|
||||
const workspaceRepo = await Git.Repository.open(workspacePath);
|
||||
// workspace is newest now
|
||||
assert.strictEqual((await workspaceRepo.getHeadCommit()).sha(), secondCommitSha);
|
||||
const firstCommit = await workspaceRepo.getCommit(firstCommitSha);
|
||||
// reset workspace to an older one
|
||||
// @ts-ignore
|
||||
await Git.Reset.reset(workspaceRepo, firstCommit, Git.Reset.TYPE.HARD, {});
|
||||
assert.strictEqual((await workspaceRepo.getHeadCommit()).sha(), firstCommitSha);
|
||||
|
||||
// send a request again;
|
||||
await sendHoverRequest(lspservice, revision);
|
||||
// workspace_handler should update workspace to the newest one
|
||||
assert.strictEqual((await workspaceRepo.getHeadCommit()).sha(), secondCommitSha);
|
||||
return;
|
||||
} finally {
|
||||
await lspservice.shutdown();
|
||||
}
|
||||
// @ts-ignore
|
||||
}).timeout(10000);
|
||||
});
|
||||
|
|
|
@ -93,10 +93,10 @@ export class WorkspaceHandler {
|
|||
revision = defaultBranch;
|
||||
}
|
||||
let workspaceRepo: Repository;
|
||||
if (await this.workspaceExists(repositoryUri, revision)) {
|
||||
if (await this.workspaceExists(bareRepo, repositoryUri, revision)) {
|
||||
workspaceRepo = await this.updateWorkspace(repositoryUri, revision, targetCommit);
|
||||
} else {
|
||||
workspaceRepo = await this.cloneWorkspace(bareRepo, repositoryUri, revision);
|
||||
workspaceRepo = await this.cloneWorkspace(bareRepo, repositoryUri, revision, targetCommit);
|
||||
}
|
||||
|
||||
const workspaceHeadCommit = await workspaceRepo.getHeadCommit();
|
||||
|
@ -122,13 +122,9 @@ export class WorkspaceHandler {
|
|||
.filter(isDir);
|
||||
}
|
||||
|
||||
public async clearWorkspace(repoUri: string, revision?: string) {
|
||||
public async clearWorkspace(repoUri: string) {
|
||||
const workspaceDir = await this.workspaceDir(repoUri);
|
||||
if (revision) {
|
||||
await del([await this.revisionDir(repoUri, revision)], { force: true });
|
||||
} else {
|
||||
await del([workspaceDir], { force: true });
|
||||
}
|
||||
await del([workspaceDir], { force: true });
|
||||
}
|
||||
|
||||
public async handleRequest(request: LspRequest): Promise<void> {
|
||||
|
@ -341,9 +337,14 @@ export class WorkspaceHandler {
|
|||
}
|
||||
}
|
||||
|
||||
private async workspaceExists(repositoryUri: string, revision: string) {
|
||||
const workspaceDir = await this.revisionDir(repositoryUri, revision);
|
||||
return fs.existsSync(workspaceDir);
|
||||
private async workspaceExists(bareRepo: Repository, repositoryUri: string, revision: string) {
|
||||
const workTreeName = this.workspaceWorktreeBranchName(revision);
|
||||
const wt = this.getWorktree(bareRepo, workTreeName);
|
||||
if (wt) {
|
||||
const workspaceDir = await this.revisionDir(repositoryUri, revision);
|
||||
return fs.existsSync(workspaceDir);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private async revisionDir(repositoryUri: string, revision: string) {
|
||||
|
@ -388,12 +389,12 @@ export class WorkspaceHandler {
|
|||
private async cloneWorkspace(
|
||||
bareRepo: Repository,
|
||||
repositoryUri: string,
|
||||
revision: string
|
||||
revision: string,
|
||||
targetCommit: Commit
|
||||
): Promise<Repository> {
|
||||
const workspaceDir = await this.revisionDir(repositoryUri, revision);
|
||||
this.log.info(`Create workspace ${workspaceDir} from url ${bareRepo.path()}`);
|
||||
const parentDir = path.dirname(workspaceDir);
|
||||
const mainBranchName = path.basename(workspaceDir);
|
||||
// on windows, git clone will failed if parent folder is not exists;
|
||||
await new Promise((resolve, reject) =>
|
||||
mkdirp(parentDir, err => {
|
||||
|
@ -404,15 +405,47 @@ export class WorkspaceHandler {
|
|||
}
|
||||
})
|
||||
);
|
||||
const workTreeName = this.workspaceWorktreeBranchName(revision);
|
||||
await this.pruneWorktree(bareRepo, workTreeName);
|
||||
// Create the worktree and open it as Repository.
|
||||
const wt = await Worktree.add(
|
||||
bareRepo,
|
||||
this.workspaceWorktreeBranchName(mainBranchName),
|
||||
workspaceDir,
|
||||
{}
|
||||
);
|
||||
const wt = await Worktree.add(bareRepo, workTreeName, workspaceDir, { lock: 0, version: 1 });
|
||||
// @ts-ignore
|
||||
return await Repository.openFromWorktree(wt);
|
||||
const workspaceRepo = await Repository.openFromWorktree(wt);
|
||||
const workspaceHeadCommit = await workspaceRepo.getHeadCommit();
|
||||
// when we start supporting multi-revision, targetCommit may not be head
|
||||
if (workspaceHeadCommit.sha() !== targetCommit.sha()) {
|
||||
const commit = await workspaceRepo.getCommit(targetCommit.sha());
|
||||
this.log.info(`checkout ${workspaceRepo.workdir()} to commit ${targetCommit.sha()}`);
|
||||
// @ts-ignore
|
||||
const result = await Reset.reset(workspaceRepo, commit, Reset.TYPE.HARD, {});
|
||||
if (result !== undefined && result !== GitError.CODE.OK) {
|
||||
throw Boom.internal(`checkout workspace to commit ${targetCommit.sha()} failed.`);
|
||||
}
|
||||
}
|
||||
return workspaceRepo;
|
||||
}
|
||||
|
||||
private async getWorktree(bareRepo: Repository, workTreeName: string) {
|
||||
try {
|
||||
const wt: Worktree = await Worktree.lookup(bareRepo, workTreeName);
|
||||
return wt;
|
||||
} catch (e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private async pruneWorktree(bareRepo: Repository, workTreeName: string) {
|
||||
const wt = await this.getWorktree(bareRepo, workTreeName);
|
||||
if (wt) {
|
||||
wt.prune({ flags: 1 });
|
||||
try {
|
||||
// try delete the worktree branch
|
||||
const ref = await bareRepo.getReference(`refs/heads/${workTreeName}`);
|
||||
ref.delete();
|
||||
} catch (e) {
|
||||
// it doesn't matter if branch is not exists
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private setWorkspaceRevision(workspaceRepo: Repository, headCommit: Commit) {
|
||||
|
|
|
@ -1478,10 +1478,10 @@
|
|||
resolved "https://registry.yarnpkg.com/@elastic/node-crypto/-/node-crypto-1.0.0.tgz#4d325df333fe1319556bb4d54214098ada1171d4"
|
||||
integrity sha512-bbjbEyILPRTRt0xnda18OttLtlkJBPuXx3CjISUSn9jhWqHoFMzfOaZ73D5jxZE2SaFZUrJYfPpqXP6qqPufAQ==
|
||||
|
||||
"@elastic/nodegit@0.25.0-alpha.19":
|
||||
version "0.25.0-alpha.19"
|
||||
resolved "https://registry.yarnpkg.com/@elastic/nodegit/-/nodegit-0.25.0-alpha.19.tgz#a05a712dedbdbd7fe649cb970eb5677c5ec4ada8"
|
||||
integrity sha512-fOG7tXkf8wmZEVMld+tkZtS3BRsUlrh95sRNUglHDd0G3g+ow9YDjV3dFHlLST0pTWirKyJuxrow2KgpLoWplA==
|
||||
"@elastic/nodegit@0.25.0-alpha.20":
|
||||
version "0.25.0-alpha.20"
|
||||
resolved "https://registry.yarnpkg.com/@elastic/nodegit/-/nodegit-0.25.0-alpha.20.tgz#74f36cb8c137386aeebacded574d1d6a4e6d9a01"
|
||||
integrity sha512-wvBTfKVAhFkTMh/N6oO/5NOa+m+cRiZLrIPHpC3ITPBQiDAUP+g2/NzKVGh/5vx5D/Y9ucy7VsbP13zU9rSi0g==
|
||||
dependencies:
|
||||
fs-extra "^7.0.0"
|
||||
json5 "^2.1.0"
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue