Loading src/status_bar.test.ts +14 −18 Original line number Diff line number Diff line Loading @@ -69,7 +69,7 @@ describe('status_bar', () => { await statusBar.refresh(createBranchInfo({ pipeline })); expect(getPipelineItem().show).toHaveBeenCalled(); expect(getPipelineItem().hide).not.toHaveBeenCalled(); expect(getPipelineItem().text).toBe('$(check) GitLab: Pipeline passed'); expect(getPipelineItem().text).toBe('$(check) Pipeline passed'); }); it('prints jobs for running pipeline', async () => { Loading @@ -93,9 +93,7 @@ describe('status_bar', () => { await statusBar.refresh( createBranchInfo({ pipeline: { ...pipeline, status: 'running' }, jobs }), ); expect(getPipelineItem().text).toBe( '$(pulse) GitLab: Pipeline running (Unit Tests, Integration Tests)', ); expect(getPipelineItem().text).toBe('$(pulse) Pipeline running'); }); it('sorts by created time (starts with newer) and deduplicates jobs for running pipeline', async () => { Loading @@ -122,24 +120,22 @@ describe('status_bar', () => { await statusBar.refresh( createBranchInfo({ pipeline: { ...pipeline, status: 'running' }, jobs }), ); expect(getPipelineItem().text).toBe( '$(pulse) GitLab: Pipeline running (Unit Tests, Integration Tests)', ); expect(getPipelineItem().text).toBe('$(pulse) Pipeline running'); }); it('shows no pipeline text when there is no pipeline', async () => { await statusBar.refresh(createBranchInfo()); expect(getPipelineItem().text).toBe('GitLab: No pipeline.'); expect(getPipelineItem().text).toBe('No pipeline'); }); it.each` status | itemText ${'running'} | ${'$(pulse) GitLab: Pipeline running'} ${'success'} | ${'$(check) GitLab: Pipeline passed'} ${'pending'} | ${'$(clock) GitLab: Pipeline pending'} ${'failed'} | ${'$(x) GitLab: Pipeline failed'} ${'canceled'} | ${'$(circle-slash) GitLab: Pipeline canceled'} ${'skipped'} | ${'$(diff-renamed) GitLab: Pipeline skipped'} ${'running'} | ${'$(pulse) Pipeline running'} ${'success'} | ${'$(check) Pipeline passed'} ${'pending'} | ${'$(clock) Pipeline pending'} ${'failed'} | ${'$(x) Pipeline failed'} ${'canceled'} | ${'$(circle-slash) Pipeline canceled'} ${'skipped'} | ${'$(diff-renamed) Pipeline skipped'} `('shows $itemText for pipeline with status $status', async ({ status, itemText }) => { await statusBar.refresh(createBranchInfo({ pipeline: { ...pipeline, status } })); expect(getPipelineItem().text).toBe(itemText); Loading @@ -151,7 +147,7 @@ describe('status_bar', () => { await statusBar.refresh(createBranchInfo({ mr })); expect(getMrItem().show).toHaveBeenCalled(); expect(getMrItem().hide).not.toHaveBeenCalled(); expect(getMrItem().text).toBe('$(git-pull-request) GitLab: MR !2000'); expect(getMrItem().text).toBe('$(git-pull-request) !2000'); const command = getMrItem().command as vscode.Command; expect(command.command).toBe('gl.showRichContent'); expect(command.arguments?.[0]).toEqual(mr); Loading @@ -159,7 +155,7 @@ describe('status_bar', () => { it('shows create MR text when there is no MR', async () => { await statusBar.refresh(createBranchInfo()); expect(getMrItem().text).toBe('$(git-pull-request) GitLab: Create MR.'); expect(getMrItem().text).toBe('$(git-pull-request) Create MR'); expect(getMrItem().command).toBe(USER_COMMANDS.OPEN_CREATE_NEW_MR); }); }); Loading @@ -169,7 +165,7 @@ describe('status_bar', () => { await statusBar.refresh(createBranchInfo({ mr, issues: [issue] })); expect(getClosingIssueItem().show).toHaveBeenCalled(); expect(getClosingIssueItem().hide).not.toHaveBeenCalled(); expect(getClosingIssueItem().text).toBe('$(code) GitLab: Issue #1000'); expect(getClosingIssueItem().text).toBe('$(code) #1000'); const command = getClosingIssueItem().command as vscode.Command; expect(command.command).toBe('gl.showRichContent'); expect(command.arguments?.[0]).toEqual(issue); Loading @@ -177,7 +173,7 @@ describe('status_bar', () => { it('shows no issue when there is not a closing issue', async () => { await statusBar.refresh(createBranchInfo({ mr, issues: [] })); expect(getClosingIssueItem().text).toBe('$(code) GitLab: No issue.'); expect(getClosingIssueItem().text).toBe('$(code) No issue'); expect(getClosingIssueItem().command).toBe(undefined); }); Loading src/status_bar.ts +11 −51 Original line number Diff line number Diff line import * as vscode from 'vscode'; import assert = require('assert'); import * as openers from './commands/openers'; import { UserFriendlyError } from './errors/user_friendly_error'; import { log } from './log'; import { PROGRAMMATIC_COMMANDS, USER_COMMANDS } from './command_names'; import { currentBranchRefresher, TreeState } from './current_branch_refresher'; import { ProjectInRepository } from './gitlab/new_project'; import { createStatusBarItem } from './utils/create_status_bar_item'; const MAXIMUM_DISPLAYED_JOBS = 4; // FIXME: if you are touching this configuration statement, move the configuration to extension_configuration.ts const { showStatusBarLinks, Loading @@ -29,39 +25,12 @@ const iconForStatus: Record<string, { icon: string; text?: string } | undefined> const getStatusText = (status: string) => iconForStatus[status]?.text || status; const createStatusTextFromJobs = (jobs: RestJob[], status: string) => { let statusText = getStatusText(status); const jobNames = jobs.filter(job => job.status === status).map(job => job.name); if (jobNames.length > MAXIMUM_DISPLAYED_JOBS) { statusText += ' ('; statusText += jobNames.slice(0, MAXIMUM_DISPLAYED_JOBS).join(', '); statusText += `, +${jobNames.length - MAXIMUM_DISPLAYED_JOBS} jobs`; statusText += ')'; } else if (jobNames.length > 0) { statusText += ` (${jobNames.join(', ')})`; } return statusText; }; const openIssuableInWebview = (issuable: RestIssuable, rootFsPath: string): vscode.Command => ({ title: '', command: PROGRAMMATIC_COMMANDS.SHOW_RICH_CONTENT, arguments: [issuable, rootFsPath], }); const sortAndDeduplicate = (jobs: RestJob[]): RestJob[] => { const alreadyProcessedJob = new Set(); const compareTimeNewFirst = (a: RestJob, b: RestJob) => Date.parse(a.created_at) < Date.parse(b.created_at) ? -1 : 1; return jobs.sort(compareTimeNewFirst).filter(job => { if (alreadyProcessedJob.has(job.name)) { return false; } alreadyProcessedJob.add(job.name); return true; }); }; export class StatusBar { pipelineStatusBarItem?: vscode.StatusBarItem; Loading Loading @@ -101,31 +70,22 @@ export class StatusBar { ): Promise<void> { if (!this.pipelineStatusBarItem) return; if (!pipeline) { this.pipelineStatusBarItem.text = 'GitLab: No pipeline.'; this.pipelineStatusBarItem.text = 'No pipeline'; this.pipelineStatusBarItem.show(); this.firstRun = false; return; } const { status } = pipeline; let statusText = getStatusText(status); if (status === 'running' || status === 'failed') { try { const processedJobs = sortAndDeduplicate(jobs); statusText = createStatusTextFromJobs(processedJobs, status); } catch (e) { log.error(new UserFriendlyError('Failed to fetch jobs for pipeline.', e)); } } const statusText = getStatusText(status); const msg = `$(${iconForStatus[status]?.icon}) GitLab: Pipeline ${statusText}`; const msg = `$(${iconForStatus[status]?.icon}) Pipeline ${statusText}`; if ( showPipelineUpdateNotifications && this.pipelineStatusBarItem.text !== msg && !this.firstRun ) { const message = `Pipeline ${statusText}.`; const message = `Pipeline ${statusText}`; await vscode.window .showInformationMessage(message, { modal: false }, 'View in Gitlab') Loading @@ -148,12 +108,12 @@ export class StatusBar { ): void { if (!this.mrIssueStatusBarItem) return; if (mr) { let text = `$(code) GitLab: No issue.`; let text = `$(code) No issue`; let command; const firstIssue = closingIssues[0]; if (firstIssue) { text = `$(code) GitLab: Issue #${firstIssue.iid}`; text = `$(code) #${firstIssue.iid}`; command = openIssuableInWebview(firstIssue, rootFsPath); } Loading @@ -172,8 +132,8 @@ export class StatusBar { ? openIssuableInWebview(mr, rootFsPath) : USER_COMMANDS.OPEN_CREATE_NEW_MR; this.mrStatusBarItem.text = mr ? `$(git-pull-request) GitLab: MR !${mr.iid}` : '$(git-pull-request) GitLab: Create MR.'; ? `$(git-pull-request) !${mr.iid}` : '$(git-pull-request) Create MR'; } init(): void { Loading @@ -184,7 +144,7 @@ export class StatusBar { priority: 2, id: 'gl.status.pipeline', name: 'GitLab Workflow: Pipeline', initialText: '$(info) GitLab: Fetching pipeline...', initialText: '$(info) Fetching pipeline...', command: USER_COMMANDS.PIPELINE_ACTIONS, }); if (showMrStatusOnStatusBar) { Loading @@ -192,14 +152,14 @@ export class StatusBar { priority: 1, id: 'gl.status.mr', name: 'GitLab Workflow: Merge Request', initialText: '$(info) GitLab: Finding MR...', initialText: '$(info) Finding MR...', }); if (showIssueLinkOnStatusBar) { this.mrIssueStatusBarItem = createStatusBarItem({ priority: 0, id: 'gl.status.issue', name: 'GitLab Workflow: Issue', initialText: '$(info) GitLab: Fetching closing issue...', initialText: '$(info) Fetching closing issue...', }); } } Loading test/integration/status_bar.test.js +1 −1 Original line number Diff line number Diff line Loading @@ -52,7 +52,7 @@ describe('GitLab status bar', () => { assert.strictEqual(vscode.window.createStatusBarItem.firstCall.firstArg, 'gl.status.pipeline'); const pipelineItem = statusBar.pipelineStatusBarItem; assert.strictEqual(pipelineItem.text, '$(check) GitLab: Pipeline passed'); assert.strictEqual(pipelineItem.text, '$(check) Pipeline passed'); assert.strictEqual(pipelineItem.show.called, true); assert.strictEqual(pipelineItem.hide.called, false); assert.strictEqual(pipelineItem.command, USER_COMMANDS.PIPELINE_ACTIONS); Loading Loading
src/status_bar.test.ts +14 −18 Original line number Diff line number Diff line Loading @@ -69,7 +69,7 @@ describe('status_bar', () => { await statusBar.refresh(createBranchInfo({ pipeline })); expect(getPipelineItem().show).toHaveBeenCalled(); expect(getPipelineItem().hide).not.toHaveBeenCalled(); expect(getPipelineItem().text).toBe('$(check) GitLab: Pipeline passed'); expect(getPipelineItem().text).toBe('$(check) Pipeline passed'); }); it('prints jobs for running pipeline', async () => { Loading @@ -93,9 +93,7 @@ describe('status_bar', () => { await statusBar.refresh( createBranchInfo({ pipeline: { ...pipeline, status: 'running' }, jobs }), ); expect(getPipelineItem().text).toBe( '$(pulse) GitLab: Pipeline running (Unit Tests, Integration Tests)', ); expect(getPipelineItem().text).toBe('$(pulse) Pipeline running'); }); it('sorts by created time (starts with newer) and deduplicates jobs for running pipeline', async () => { Loading @@ -122,24 +120,22 @@ describe('status_bar', () => { await statusBar.refresh( createBranchInfo({ pipeline: { ...pipeline, status: 'running' }, jobs }), ); expect(getPipelineItem().text).toBe( '$(pulse) GitLab: Pipeline running (Unit Tests, Integration Tests)', ); expect(getPipelineItem().text).toBe('$(pulse) Pipeline running'); }); it('shows no pipeline text when there is no pipeline', async () => { await statusBar.refresh(createBranchInfo()); expect(getPipelineItem().text).toBe('GitLab: No pipeline.'); expect(getPipelineItem().text).toBe('No pipeline'); }); it.each` status | itemText ${'running'} | ${'$(pulse) GitLab: Pipeline running'} ${'success'} | ${'$(check) GitLab: Pipeline passed'} ${'pending'} | ${'$(clock) GitLab: Pipeline pending'} ${'failed'} | ${'$(x) GitLab: Pipeline failed'} ${'canceled'} | ${'$(circle-slash) GitLab: Pipeline canceled'} ${'skipped'} | ${'$(diff-renamed) GitLab: Pipeline skipped'} ${'running'} | ${'$(pulse) Pipeline running'} ${'success'} | ${'$(check) Pipeline passed'} ${'pending'} | ${'$(clock) Pipeline pending'} ${'failed'} | ${'$(x) Pipeline failed'} ${'canceled'} | ${'$(circle-slash) Pipeline canceled'} ${'skipped'} | ${'$(diff-renamed) Pipeline skipped'} `('shows $itemText for pipeline with status $status', async ({ status, itemText }) => { await statusBar.refresh(createBranchInfo({ pipeline: { ...pipeline, status } })); expect(getPipelineItem().text).toBe(itemText); Loading @@ -151,7 +147,7 @@ describe('status_bar', () => { await statusBar.refresh(createBranchInfo({ mr })); expect(getMrItem().show).toHaveBeenCalled(); expect(getMrItem().hide).not.toHaveBeenCalled(); expect(getMrItem().text).toBe('$(git-pull-request) GitLab: MR !2000'); expect(getMrItem().text).toBe('$(git-pull-request) !2000'); const command = getMrItem().command as vscode.Command; expect(command.command).toBe('gl.showRichContent'); expect(command.arguments?.[0]).toEqual(mr); Loading @@ -159,7 +155,7 @@ describe('status_bar', () => { it('shows create MR text when there is no MR', async () => { await statusBar.refresh(createBranchInfo()); expect(getMrItem().text).toBe('$(git-pull-request) GitLab: Create MR.'); expect(getMrItem().text).toBe('$(git-pull-request) Create MR'); expect(getMrItem().command).toBe(USER_COMMANDS.OPEN_CREATE_NEW_MR); }); }); Loading @@ -169,7 +165,7 @@ describe('status_bar', () => { await statusBar.refresh(createBranchInfo({ mr, issues: [issue] })); expect(getClosingIssueItem().show).toHaveBeenCalled(); expect(getClosingIssueItem().hide).not.toHaveBeenCalled(); expect(getClosingIssueItem().text).toBe('$(code) GitLab: Issue #1000'); expect(getClosingIssueItem().text).toBe('$(code) #1000'); const command = getClosingIssueItem().command as vscode.Command; expect(command.command).toBe('gl.showRichContent'); expect(command.arguments?.[0]).toEqual(issue); Loading @@ -177,7 +173,7 @@ describe('status_bar', () => { it('shows no issue when there is not a closing issue', async () => { await statusBar.refresh(createBranchInfo({ mr, issues: [] })); expect(getClosingIssueItem().text).toBe('$(code) GitLab: No issue.'); expect(getClosingIssueItem().text).toBe('$(code) No issue'); expect(getClosingIssueItem().command).toBe(undefined); }); Loading
src/status_bar.ts +11 −51 Original line number Diff line number Diff line import * as vscode from 'vscode'; import assert = require('assert'); import * as openers from './commands/openers'; import { UserFriendlyError } from './errors/user_friendly_error'; import { log } from './log'; import { PROGRAMMATIC_COMMANDS, USER_COMMANDS } from './command_names'; import { currentBranchRefresher, TreeState } from './current_branch_refresher'; import { ProjectInRepository } from './gitlab/new_project'; import { createStatusBarItem } from './utils/create_status_bar_item'; const MAXIMUM_DISPLAYED_JOBS = 4; // FIXME: if you are touching this configuration statement, move the configuration to extension_configuration.ts const { showStatusBarLinks, Loading @@ -29,39 +25,12 @@ const iconForStatus: Record<string, { icon: string; text?: string } | undefined> const getStatusText = (status: string) => iconForStatus[status]?.text || status; const createStatusTextFromJobs = (jobs: RestJob[], status: string) => { let statusText = getStatusText(status); const jobNames = jobs.filter(job => job.status === status).map(job => job.name); if (jobNames.length > MAXIMUM_DISPLAYED_JOBS) { statusText += ' ('; statusText += jobNames.slice(0, MAXIMUM_DISPLAYED_JOBS).join(', '); statusText += `, +${jobNames.length - MAXIMUM_DISPLAYED_JOBS} jobs`; statusText += ')'; } else if (jobNames.length > 0) { statusText += ` (${jobNames.join(', ')})`; } return statusText; }; const openIssuableInWebview = (issuable: RestIssuable, rootFsPath: string): vscode.Command => ({ title: '', command: PROGRAMMATIC_COMMANDS.SHOW_RICH_CONTENT, arguments: [issuable, rootFsPath], }); const sortAndDeduplicate = (jobs: RestJob[]): RestJob[] => { const alreadyProcessedJob = new Set(); const compareTimeNewFirst = (a: RestJob, b: RestJob) => Date.parse(a.created_at) < Date.parse(b.created_at) ? -1 : 1; return jobs.sort(compareTimeNewFirst).filter(job => { if (alreadyProcessedJob.has(job.name)) { return false; } alreadyProcessedJob.add(job.name); return true; }); }; export class StatusBar { pipelineStatusBarItem?: vscode.StatusBarItem; Loading Loading @@ -101,31 +70,22 @@ export class StatusBar { ): Promise<void> { if (!this.pipelineStatusBarItem) return; if (!pipeline) { this.pipelineStatusBarItem.text = 'GitLab: No pipeline.'; this.pipelineStatusBarItem.text = 'No pipeline'; this.pipelineStatusBarItem.show(); this.firstRun = false; return; } const { status } = pipeline; let statusText = getStatusText(status); if (status === 'running' || status === 'failed') { try { const processedJobs = sortAndDeduplicate(jobs); statusText = createStatusTextFromJobs(processedJobs, status); } catch (e) { log.error(new UserFriendlyError('Failed to fetch jobs for pipeline.', e)); } } const statusText = getStatusText(status); const msg = `$(${iconForStatus[status]?.icon}) GitLab: Pipeline ${statusText}`; const msg = `$(${iconForStatus[status]?.icon}) Pipeline ${statusText}`; if ( showPipelineUpdateNotifications && this.pipelineStatusBarItem.text !== msg && !this.firstRun ) { const message = `Pipeline ${statusText}.`; const message = `Pipeline ${statusText}`; await vscode.window .showInformationMessage(message, { modal: false }, 'View in Gitlab') Loading @@ -148,12 +108,12 @@ export class StatusBar { ): void { if (!this.mrIssueStatusBarItem) return; if (mr) { let text = `$(code) GitLab: No issue.`; let text = `$(code) No issue`; let command; const firstIssue = closingIssues[0]; if (firstIssue) { text = `$(code) GitLab: Issue #${firstIssue.iid}`; text = `$(code) #${firstIssue.iid}`; command = openIssuableInWebview(firstIssue, rootFsPath); } Loading @@ -172,8 +132,8 @@ export class StatusBar { ? openIssuableInWebview(mr, rootFsPath) : USER_COMMANDS.OPEN_CREATE_NEW_MR; this.mrStatusBarItem.text = mr ? `$(git-pull-request) GitLab: MR !${mr.iid}` : '$(git-pull-request) GitLab: Create MR.'; ? `$(git-pull-request) !${mr.iid}` : '$(git-pull-request) Create MR'; } init(): void { Loading @@ -184,7 +144,7 @@ export class StatusBar { priority: 2, id: 'gl.status.pipeline', name: 'GitLab Workflow: Pipeline', initialText: '$(info) GitLab: Fetching pipeline...', initialText: '$(info) Fetching pipeline...', command: USER_COMMANDS.PIPELINE_ACTIONS, }); if (showMrStatusOnStatusBar) { Loading @@ -192,14 +152,14 @@ export class StatusBar { priority: 1, id: 'gl.status.mr', name: 'GitLab Workflow: Merge Request', initialText: '$(info) GitLab: Finding MR...', initialText: '$(info) Finding MR...', }); if (showIssueLinkOnStatusBar) { this.mrIssueStatusBarItem = createStatusBarItem({ priority: 0, id: 'gl.status.issue', name: 'GitLab Workflow: Issue', initialText: '$(info) GitLab: Fetching closing issue...', initialText: '$(info) Fetching closing issue...', }); } } Loading
test/integration/status_bar.test.js +1 −1 Original line number Diff line number Diff line Loading @@ -52,7 +52,7 @@ describe('GitLab status bar', () => { assert.strictEqual(vscode.window.createStatusBarItem.firstCall.firstArg, 'gl.status.pipeline'); const pipelineItem = statusBar.pipelineStatusBarItem; assert.strictEqual(pipelineItem.text, '$(check) GitLab: Pipeline passed'); assert.strictEqual(pipelineItem.text, '$(check) Pipeline passed'); assert.strictEqual(pipelineItem.show.called, true); assert.strictEqual(pipelineItem.hide.called, false); assert.strictEqual(pipelineItem.command, USER_COMMANDS.PIPELINE_ACTIONS); Loading