diff --git a/src/commands/create_snippet.js b/src/commands/create_snippet.js deleted file mode 100644 index 6ffd6c5d0db3e7fcc80e1b44876da5e9cd980289..0000000000000000000000000000000000000000 --- a/src/commands/create_snippet.js +++ /dev/null @@ -1,115 +0,0 @@ -const vscode = require('vscode'); -const openers = require('../openers'); -const gitLabService = require('../gitlab_service'); -const gitlabProjectInput = require('../gitlab_project_input'); -const { gitExtensionWrapper } = require('../git/git_extension_wrapper'); -const { logError } = require('../log'); - -const visibilityOptions = [ - { - label: 'Public', - type: 'public', - }, - { - label: 'Internal', - type: 'internal', - }, - { - label: 'Private', - type: 'private', - }, -]; - -const contextOptions = [ - { - label: 'Snippet from file', - type: 'file', - }, - { - label: 'Snippet from selection', - type: 'selection', - }, -]; - -async function uploadSnippet(project, editor, visibility, context, repositoryRoot) { - let content = ''; - const fileName = editor.document.fileName.split('/').reverse()[0]; - - if (context === 'selection' && editor.selection) { - const { start, end } = editor.selection; - const endLine = end.line + 1; - const startPos = new vscode.Position(start.line, 0); - const endPos = new vscode.Position(endLine, 0); - const range = new vscode.Range(startPos, endPos); - content = editor.document.getText(range); - } else { - content = editor.document.getText(); - } - - const data = { - title: fileName, - file_name: fileName, - visibility, - }; - - data.content = content; - - if (project) { - data.id = project.restId; - } - - const snippet = await gitLabService.createSnippet(repositoryRoot, data); - - openers.openUrl(snippet.web_url); -} - -async function createSnippet() { - const editor = vscode.window.activeTextEditor; - let repositoryRoot = null; - let project = null; - - if (editor) { - const repository = gitExtensionWrapper.getActiveRepository(); - repositoryRoot = repository && repository.rootFsPath; - try { - project = repository && (await repository.getProject()); - } catch (e) { - logError(e); - } - - // FIXME: the empty `uri` representing user's snippets is not correctly handled - if (!project) { - repositoryRoot = await gitlabProjectInput.show( - [ - { - label: "User's Snippets", - uri: '', - }, - ], - "Select a Gitlab Project or use the User's Snippets", - ); - try { - const selectedRepository = gitExtensionWrapper.getRepository(repositoryRoot); - project = selectedRepository && (await selectedRepository.getProject()); - } catch (e) { - logError(e); - } - } - - const visibility = await vscode.window.showQuickPick(visibilityOptions); - - if (visibility) { - const context = await vscode.window.showQuickPick(contextOptions); - - if (context) { - uploadSnippet(project, editor, visibility.type, context.type, repositoryRoot); - } - } - } else { - vscode.window.showInformationMessage('GitLab Workflow: No open file.'); - } -} - -module.exports = { - createSnippet, -}; diff --git a/src/commands/create_snippet.ts b/src/commands/create_snippet.ts new file mode 100644 index 0000000000000000000000000000000000000000..5648cb7166374d18099cc39348969b8aff4e7ff4 --- /dev/null +++ b/src/commands/create_snippet.ts @@ -0,0 +1,92 @@ +import * as vscode from 'vscode'; +import * as openers from '../openers'; +import * as gitLabService from '../gitlab_service'; +import { gitExtensionWrapper } from '../git/git_extension_wrapper'; +import { GitLabProject } from '../gitlab/gitlab_project'; + +const visibilityOptions = [ + { + label: 'Public', + type: 'public', + }, + { + label: 'Internal', + type: 'internal', + }, + { + label: 'Private', + type: 'private', + }, +]; + +const contextOptions = [ + { + label: 'Snippet from file', + type: 'file', + }, + { + label: 'Snippet from selection', + type: 'selection', + }, +]; + +async function uploadSnippet( + project: GitLabProject, + editor: vscode.TextEditor, + visibility: string, + context: string, + repositoryRoot: string, +) { + let content = ''; + const fileName = editor.document.fileName.split('/').reverse()[0]; + + if (context === 'selection' && editor.selection) { + const { start, end } = editor.selection; + const endLine = end.line + 1; + const startPos = new vscode.Position(start.line, 0); + const endPos = new vscode.Position(endLine, 0); + const range = new vscode.Range(startPos, endPos); + content = editor.document.getText(range); + } else { + content = editor.document.getText(); + } + + const data = { + id: project.restId, + title: fileName, + file_name: fileName, + visibility, + content, + }; + + const snippet = await gitLabService.createSnippet(repositoryRoot, data); + + await openers.openUrl(snippet.web_url); +} + +export async function createSnippet() { + const editor = vscode.window.activeTextEditor; + + if (!editor) { + vscode.window.showInformationMessage('GitLab Workflow: No open file.'); + return; + } + const repository = await gitExtensionWrapper.getActiveRepositoryOrSelectOne(); + if (!repository) return; + const project = await repository.getProject(); + + if (!project) { + vscode.window.showInformationMessage( + 'GitLab Workflow: Repository does not contain GitLab project.', + ); + return; + } + + const visibility = await vscode.window.showQuickPick(visibilityOptions); + if (!visibility) return; + + const context = await vscode.window.showQuickPick(contextOptions); + if (!context) return; + + await uploadSnippet(project, editor, visibility.type, context.type, repository.rootFsPath); +} diff --git a/src/gitlab_project_input.js b/src/gitlab_project_input.js deleted file mode 100644 index 40d5eaf5be1f0ff0f2720dcee9dd58928576cde2..0000000000000000000000000000000000000000 --- a/src/gitlab_project_input.js +++ /dev/null @@ -1,29 +0,0 @@ -const vscode = require('vscode'); -const gitLabService = require('./gitlab_service'); - -async function showPicker(additionalEntries = [], placeHolder = 'Select a Gitlab Project') { - const repositoryRootOptions = await gitLabService.getAllGitlabProjects(); - - additionalEntries.forEach(additionalEntry => { - repositoryRootOptions.push(additionalEntry); - }); - - if (repositoryRootOptions.length === 0) { - return null; - } - if (repositoryRootOptions.length === 1) { - return repositoryRootOptions[0]; - } - - const repositoryRoot = await vscode.window.showQuickPick(repositoryRootOptions, { - placeHolder, - }); - - if (repositoryRoot) { - return repositoryRoot.uri; - } - - return null; -} - -exports.show = showPicker; diff --git a/src/gitlab_service.ts b/src/gitlab_service.ts index 90f118ef86945df2623bded8aee36b2dd4fed129..eb8d4e862e1f7b4c9c237b55d703613a10271f1b 100644 --- a/src/gitlab_service.ts +++ b/src/gitlab_service.ts @@ -475,22 +475,13 @@ export async function fetchMRIssues(mrId: number, repositoryRoot: string): Promi } // TODO specify the correct interface when we convert `create_snippet.js` -export async function createSnippet(repositoryRoot: string, data: { id: string }) { - let snippet; - let path = '/snippets'; - - if (data.id) { - path = `/projects/${data.id}/snippets`; - } - +export async function createSnippet(repositoryRoot: string, data: { id: number }) { try { - const { response } = await fetch(repositoryRoot, path, 'POST', data); - snippet = response; + const { response } = await fetch(repositoryRoot, `/projects/${data.id}/snippets`, 'POST', data); + return response; } catch (e) { - handleError(new UserFriendlyError('Failed to create your snippet.', e)); + throw new UserFriendlyError('Failed to create your snippet.', e); } - - return snippet; } export async function validateCIConfig(repositoryRoot: string, content: string): Promise { diff --git a/test/integration/create_snippet.test.js b/test/integration/create_snippet.test.js new file mode 100644 index 0000000000000000000000000000000000000000..a12c971b3eff0e8f5b9acd266776eba3e3aecddc --- /dev/null +++ b/test/integration/create_snippet.test.js @@ -0,0 +1,56 @@ +const sinon = require('sinon'); +const vscode = require('vscode'); +const { createSnippet } = require('../../src/commands/create_snippet'); +const { tokenService } = require('../../src/services/token_service'); +const { getServer, createPostEndpoint } = require('./test_infrastructure/mock_server'); +const { GITLAB_URL } = require('./test_infrastructure/constants'); +const { + createAndOpenFile, + closeAndDeleteFile, + simulateQuickPickChoice, + getRepositoryRoot, +} = require('./test_infrastructure/helpers'); + +describe('Create snippet', async () => { + let server; + let testFileUri; + const sandbox = sinon.createSandbox(); + const snippetUrl = `${GITLAB_URL}/gitlab-org/gitlab/snippets/1`; + + before(async () => { + server = getServer([ + createPostEndpoint('/projects/278964/snippets', { + web_url: snippetUrl, + }), + ]); + await tokenService.setToken(GITLAB_URL, 'abcd-secret'); + }); + + beforeEach(async () => { + server.resetHandlers(); + testFileUri = vscode.Uri.parse(`${getRepositoryRoot()}/newfile.js`); + await createAndOpenFile(testFileUri); + }); + + afterEach(async () => { + sandbox.restore(); + await closeAndDeleteFile(testFileUri); + }); + + after(async () => { + server.close(); + await tokenService.setToken(GITLAB_URL, undefined); + }); + + it('creates snippet form the file', async () => { + simulateQuickPickChoice(sandbox, 0); + const expectation = sandbox + .mock(vscode.commands) + .expects('executeCommand') + .once() + .withArgs('vscode.open', vscode.Uri.parse(snippetUrl)); + + await createSnippet(); + expectation.verify(); + }); +});