-
-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(extensions): Add Bitbucket Pipelines extension
- Loading branch information
1 parent
3a3c786
commit 12267a0
Showing
20 changed files
with
469 additions
and
23 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -90,3 +90,6 @@ typings/ | |
|
||
# Electron-Forge | ||
out/ | ||
|
||
# Intellij IDEA | ||
.idea/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
/** | ||
* @vitest-environment jsdom | ||
*/ | ||
import React from 'react'; | ||
import { render, fireEvent, screen } from '@testing-library/react'; | ||
import '@testing-library/jest-dom'; | ||
import { Bitbucket } from './'; | ||
import { faker } from '@faker-js/faker'; | ||
import { expect, describe, it, vi, beforeEach } from 'vitest'; | ||
|
||
vi.mock('@mui/material/TextField', () => ({ | ||
__esModule: true, | ||
default: (props: any) => <input data-testid={`textField-${props.label}`} {...props} />, | ||
})); | ||
|
||
describe('Bitbucket', () => { | ||
const expectedObservable = { | ||
owner: faker.lorem.word(), | ||
repo: faker.lorem.word(), | ||
workflowId: faker.lorem.word(), | ||
authToken: faker.lorem.word(), | ||
}; | ||
const expectedIndex = faker.number.int(); | ||
const updateFieldMock = vi.fn(); | ||
const translateMock = (val: string): string => val; | ||
beforeEach(() => { | ||
updateFieldMock.mockClear(); | ||
render( | ||
<Bitbucket | ||
observable={expectedObservable} | ||
index={expectedIndex} | ||
updateFieldWithValue={updateFieldMock} | ||
translate={translateMock} | ||
/> | ||
); | ||
}); | ||
describe.each([ | ||
['Workspace', 'workspace', undefined], | ||
['Repository', 'repo', undefined], | ||
['Branch', 'branch', undefined], | ||
['Authorization Token', 'authToken', 'password'], | ||
])('%s', (label: string, value: string, type: string) => { | ||
it('should have correct textfield attributes', () => { | ||
const textfield = screen.getByTestId(`textField-${label}`); | ||
expect(textfield).toHaveAttribute('label', label); | ||
expect(textfield).toHaveAttribute('variant', 'standard'); | ||
if (type) expect(textfield).toHaveAttribute('type', type); | ||
expect(textfield).toHaveAttribute('value', (expectedObservable as any)[value]); | ||
}); | ||
|
||
it('should call update field on change event', () => { | ||
const expectedValue = faker.lorem.word(); | ||
const textfield = screen.getByTestId(`textField-${label}`); | ||
fireEvent.change(textfield, { target: { value: expectedValue } }); | ||
expect(updateFieldMock).toBeCalledWith(value, expectedIndex, expectedValue); | ||
}); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
import React from 'react'; | ||
import TextField from '@mui/material/TextField'; | ||
|
||
export const Bitbucket = ({ observable, index, updateFieldWithValue, translate }: any) => ( | ||
<> | ||
<TextField | ||
label={translate('Workspace')} | ||
variant="standard" | ||
value={observable.workspace} | ||
onChange={(event: React.ChangeEvent<HTMLInputElement>) => | ||
updateFieldWithValue('workspace', index, event.target.value) | ||
} | ||
/> | ||
<TextField | ||
label={translate('Repository')} | ||
variant="standard" | ||
value={observable.repo} | ||
onChange={(event: React.ChangeEvent<HTMLInputElement>) => updateFieldWithValue('repo', index, event.target.value)} | ||
/> | ||
<TextField | ||
label={translate('Branch')} | ||
variant="standard" | ||
value={observable.branch} | ||
onChange={(event: React.ChangeEvent<HTMLInputElement>) => | ||
updateFieldWithValue('branch', index, event.target.value) | ||
} | ||
/> | ||
<TextField | ||
label={translate('Authorization Token')} | ||
variant="standard" | ||
type="password" | ||
value={observable.authToken} | ||
onChange={(event: React.ChangeEvent<HTMLInputElement>) => | ||
updateFieldWithValue('authToken', index, event.target.value) | ||
} | ||
/> | ||
</> | ||
); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,245 @@ | ||
import { faker } from '@faker-js/faker'; | ||
import { Status } from '../../../types/Status'; | ||
import { expect, describe, it, vi, beforeEach } from 'vitest'; | ||
import { BitbucketConfiguration } from '../../../types/BitbucketConfiguration'; | ||
import { Bitbucket } from './'; | ||
|
||
const fetchtMock = vi.fn(); | ||
vi.mock('electron-fetch', () => { | ||
return { | ||
__esModule: true, | ||
default: (...all: any) => fetchtMock(...all), | ||
}; | ||
}); | ||
|
||
describe('Bitbucket', () => { | ||
describe('getState', () => { | ||
let config: BitbucketConfiguration; | ||
let observer: Bitbucket; | ||
|
||
let expectedUrl: string; | ||
|
||
beforeEach(() => { | ||
fetchtMock.mockClear(); | ||
config = { | ||
type: 'bitbucket', | ||
workspace: faker.lorem.word(), | ||
repo: faker.lorem.word(), | ||
branch: faker.lorem.word(), | ||
authToken: faker.lorem.word(), | ||
alias: faker.lorem.word(), | ||
}; | ||
expectedUrl = `https://api.bitbucket.org/2.0/repositories/${config.workspace}/${config.repo}/pipelines?target.ref_name=${config.branch}&sort=-created_on`; | ||
observer = new Bitbucket(config); | ||
}); | ||
|
||
it('shoulds return NA status if request return different value than 200', async () => { | ||
fetchtMock.mockResolvedValue({ | ||
json: () => Promise.resolve('kaboom'), | ||
ok: false, | ||
}); | ||
const result = await observer.getState(); | ||
expect(fetchtMock).toBeCalledWith(expectedUrl, { | ||
method: 'GET', | ||
headers: { | ||
Authorization: `Bearer ${config.authToken}`, | ||
}, | ||
}); | ||
expect(result).toEqual({ | ||
name: config.alias, | ||
status: Status.NA, | ||
link: `https://bitbucket.org/${config.workspace}/${config.repo}/pipelines/results/branch/${config.branch}/page/1`, | ||
}); | ||
}); | ||
|
||
it('shoulds return NA status if request return no pipeline values', async () => { | ||
fetchtMock.mockResolvedValue({ | ||
json: () => Promise.resolve({ page: 1, values: [] }), | ||
ok: true, | ||
}); | ||
const result = await observer.getState(); | ||
expect(fetchtMock).toBeCalledWith(expectedUrl, { | ||
method: 'GET', | ||
headers: { | ||
Authorization: `Bearer ${config.authToken}`, | ||
}, | ||
}); | ||
expect(result).toEqual({ | ||
name: config.alias, | ||
status: Status.NA, | ||
link: `https://bitbucket.org/${config.workspace}/${config.repo}/pipelines/results/branch/${config.branch}/page/1`, | ||
}); | ||
}); | ||
|
||
it('shoulds return SUCCESS status if state is COMPLETED and result SUCCESSFUL', async () => { | ||
const buildNumber = faker.number.int(); | ||
fetchtMock.mockResolvedValue({ | ||
json: () => | ||
Promise.resolve({ | ||
page: 1, | ||
values: [ | ||
{ | ||
uuid: faker.lorem.word(), | ||
build_number: buildNumber, | ||
state: { | ||
name: 'COMPLETED', | ||
type: 'pipeline_state_completed', | ||
result: { | ||
name: 'SUCCESSFUL', | ||
type: 'pipeline_state_completed_successful', | ||
}, | ||
}, | ||
}, | ||
], | ||
}), | ||
ok: true, | ||
}); | ||
const result = await observer.getState(); | ||
expect(fetchtMock).toBeCalledWith(expectedUrl, { | ||
method: 'GET', | ||
headers: { | ||
Authorization: `Bearer ${config.authToken}`, | ||
}, | ||
}); | ||
expect(result).toEqual({ | ||
name: config.alias, | ||
status: Status.SUCCESS, | ||
link: `https://bitbucket.org/${config.workspace}/${config.repo}/pipelines/results/${buildNumber}`, | ||
}); | ||
}); | ||
|
||
it('shoulds return FAILURE status if state is COMPLETED and result FAILED', async () => { | ||
const buildNumber = faker.number.int(); | ||
fetchtMock.mockResolvedValue({ | ||
json: () => | ||
Promise.resolve({ | ||
page: 1, | ||
values: [ | ||
{ | ||
uuid: faker.lorem.word(), | ||
build_number: buildNumber, | ||
state: { | ||
name: 'COMPLETED', | ||
type: 'pipeline_state_completed', | ||
result: { | ||
name: 'FAILED', | ||
type: 'pipeline_state_completed_failed', | ||
}, | ||
}, | ||
}, | ||
], | ||
}), | ||
ok: true, | ||
}); | ||
const result = await observer.getState(); | ||
expect(fetchtMock).toBeCalledWith(expectedUrl, { | ||
method: 'GET', | ||
headers: { | ||
Authorization: `Bearer ${config.authToken}`, | ||
}, | ||
}); | ||
expect(result).toEqual({ | ||
name: config.alias, | ||
status: Status.FAILURE, | ||
link: `https://bitbucket.org/${config.workspace}/${config.repo}/pipelines/results/${buildNumber}`, | ||
}); | ||
}); | ||
|
||
it('shoulds return FAILURE status if state is COMPLETED and result ERROR', async () => { | ||
const buildNumber = faker.number.int(); | ||
fetchtMock.mockResolvedValue({ | ||
json: () => | ||
Promise.resolve({ | ||
page: 1, | ||
values: [ | ||
{ | ||
uuid: faker.lorem.word(), | ||
build_number: buildNumber, | ||
state: { | ||
name: 'COMPLETED', | ||
type: 'pipeline_state_completed', | ||
result: { | ||
name: 'ERROR', | ||
type: 'pipeline_state_completed_error', | ||
}, | ||
}, | ||
}, | ||
], | ||
}), | ||
ok: true, | ||
}); | ||
const result = await observer.getState(); | ||
expect(fetchtMock).toBeCalledWith(expectedUrl, { | ||
method: 'GET', | ||
headers: { | ||
Authorization: `Bearer ${config.authToken}`, | ||
}, | ||
}); | ||
expect(result).toEqual({ | ||
name: config.alias, | ||
status: Status.FAILURE, | ||
link: `https://bitbucket.org/${config.workspace}/${config.repo}/pipelines/results/${buildNumber}`, | ||
}); | ||
}); | ||
|
||
it('shoulds return CHECKING status if state is not COMPLETED', async () => { | ||
const buildNumber = faker.number.int(); | ||
fetchtMock.mockResolvedValue({ | ||
json: () => | ||
Promise.resolve({ | ||
page: 1, | ||
values: [ | ||
{ | ||
uuid: faker.lorem.word(), | ||
build_number: buildNumber, | ||
state: { | ||
name: 'IN_PROGRESS', | ||
type: 'pipeline_state_in_progress_running', | ||
stage: { | ||
name: 'RUNNING', | ||
type: 'pipeline_state_in_progress_running', | ||
}, | ||
}, | ||
}, | ||
], | ||
}), | ||
ok: true, | ||
}); | ||
const result = await observer.getState(); | ||
expect(fetchtMock).toBeCalledWith(expectedUrl, { | ||
method: 'GET', | ||
headers: { | ||
Authorization: `Bearer ${config.authToken}`, | ||
}, | ||
}); | ||
expect(result).toEqual({ | ||
name: config.alias, | ||
status: Status.CHECKING, | ||
link: `https://bitbucket.org/${config.workspace}/${config.repo}/pipelines/results/${buildNumber}`, | ||
}); | ||
}); | ||
|
||
it('shoulds return repo/branch if no alias', async () => { | ||
fetchtMock.mockResolvedValue({ | ||
json: () => | ||
Promise.resolve({ | ||
page: 1, | ||
values: [], | ||
}), | ||
ok: true, | ||
}); | ||
|
||
config = { | ||
type: 'bitbucket', | ||
workspace: faker.lorem.word(), | ||
repo: faker.lorem.word(), | ||
branch: faker.lorem.word(), | ||
authToken: faker.lorem.word(), | ||
alias: undefined, | ||
}; | ||
observer = new Bitbucket(config); | ||
const result = await observer.getState(); | ||
expect(result.name).toEqual(`Bitbucket: ${config.repo}/${config.branch}`); | ||
}); | ||
}); | ||
}); |
Oops, something went wrong.