Skip to content

Commit

Permalink
feat(bitbucket): BitBucket OAuth integration
Browse files Browse the repository at this point in the history
  • Loading branch information
jkuri authored and irmana committed Apr 30, 2018
1 parent a89a622 commit f432310
Show file tree
Hide file tree
Showing 14 changed files with 261 additions and 110 deletions.
39 changes: 25 additions & 14 deletions src/api/commit-status.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export function sendSuccessStatus(build: any, buildId: number): Promise<void> {
return setGitHubStatusSuccess(gitUrl, abstruseUrl,
build.repository.access_token);
} else if (build.repository.bitbucket_id) {
let sha = build.data.sha;
let sha = build.data.push.changes[0].commits[0].hash;
let name = build.data.repository.full_name;
let gitUrl = `https://api.bitbucket.org/2.0/repositories`
+ `/${name}/commit/${sha}/statuses/build`;
Expand Down Expand Up @@ -73,7 +73,7 @@ export function sendPendingStatus(buildData: any, buildId: number): Promise<void

return setGitHubStatusPending(gitUrl, abstruseUrl, buildData.repository.access_token);
} else if (buildData.repository.bitbucket_id) {
let sha = buildData.data.sha;
let sha = buildData.data.push.changes[0].commits[0].hash;
let name = buildData.data.repository.full_name;
let gitUrl = `https://api.bitbucket.org/2.0/repositories`
+ `/${name}/commit/${sha}/statuses/build`;
Expand Down Expand Up @@ -122,7 +122,7 @@ export function sendFailureStatus(buildData: any, buildId: number): Promise<void

return setGitHubStatusFailure(gitUrl, abstruseUrl, buildData.repository.access_token);
} else if (buildData.repository.bitbucket_id) {
let sha = buildData.data.sha;
let sha = buildData.data.push.changes[0].commits[0].hash;
let name = buildData.data.repository.full_name;
let gitUrl = `https://api.bitbucket.org/2.0/repositories`
+ `/${name}/commit/${sha}/statuses/build`;
Expand Down Expand Up @@ -154,7 +154,8 @@ export function sendFailureStatus(buildData: any, buildId: number): Promise<void
}

function setGitHubStatusSuccess(
gitUrl: string, abstruseUrl: string, token: string): Promise<any> {
gitUrl: string, abstruseUrl: string, token: string
): Promise<any> {
let data = {
'state': 'success',
'target_url': abstruseUrl,
Expand All @@ -171,7 +172,8 @@ function setGitHubStatusSuccess(
}

function setGitHubStatusPending(
gitUrl: string, abstruseUrl: string, token: string): Promise<any> {
gitUrl: string, abstruseUrl: string, token: string
): Promise<any> {
let data = {
'state': 'pending',
'target_url': abstruseUrl,
Expand All @@ -188,7 +190,8 @@ function setGitHubStatusPending(
}

function setGitHubStatusError(
gitUrl: string, abstruseUrl: string, token: string): Promise<any> {
gitUrl: string, abstruseUrl: string, token: string
): Promise<any> {
let data = {
'state': 'error',
'target_url': abstruseUrl,
Expand All @@ -205,7 +208,8 @@ function setGitHubStatusError(
}

function setGitHubStatusFailure(
gitUrl: string, abstruseUrl: string, token: string): Promise<any> {
gitUrl: string, abstruseUrl: string, token: string
): Promise<any> {
let data = {
'state': 'failure',
'target_url': abstruseUrl,
Expand All @@ -222,7 +226,8 @@ function setGitHubStatusFailure(
}

function setGitLabStatusSuccess(
gitUrl: string, abstruseUrl: string, token: string): Promise<any> {
gitUrl: string, abstruseUrl: string, token: string
): Promise<any> {
let data = {
'state': 'success',
'target_url': abstruseUrl,
Expand All @@ -238,7 +243,8 @@ function setGitLabStatusSuccess(
}

function setGitLabStatusPending(
gitUrl: string, abstruseUrl: string, token: string): Promise<any> {
gitUrl: string, abstruseUrl: string, token: string
): Promise<any> {
let data = {
'state': 'pending',
'target_url': abstruseUrl,
Expand All @@ -254,7 +260,8 @@ function setGitLabStatusPending(
}

function setGitLabStatusError(
gitUrl: string, abstruseUrl: string, token: string): Promise<any> {
gitUrl: string, abstruseUrl: string, token: string
): Promise<any> {
let data = {
'state': 'error',
'target_url': abstruseUrl,
Expand All @@ -270,7 +277,8 @@ function setGitLabStatusError(
}

function setGitLabStatusFailure(
gitUrl: string, abstruseUrl: string, token: string): Promise<any> {
gitUrl: string, abstruseUrl: string, token: string
): Promise<any> {
let data = {
'state': 'failure',
'target_url': abstruseUrl,
Expand All @@ -286,7 +294,8 @@ function setGitLabStatusFailure(
}

function setBitbucketStatusSuccess(
gitUrl: string, abstruseUrl: string, token: string): Promise<any> {
gitUrl: string, abstruseUrl: string, token: string
): Promise<any> {
return getBitBucketAccessToken(token)
.then(response => {
let access_token = response.access_token;
Expand All @@ -309,7 +318,8 @@ function setBitbucketStatusSuccess(
}

function setBitbucketStatusPending(
gitUrl: string, abstruseUrl: string, token: string): Promise<any> {
gitUrl: string, abstruseUrl: string, token: string
): Promise<any> {
return getBitBucketAccessToken(token)
.then(response => {
let access_token = response.access_token;
Expand All @@ -332,7 +342,8 @@ function setBitbucketStatusPending(
}

function setBitbucketStatusFailure(
gitUrl: string, abstruseUrl: string, token: string): Promise<any> {
gitUrl: string, abstruseUrl: string, token: string
): Promise<any> {
return getBitBucketAccessToken(token)
.then(response => {
let access_token = response.access_token;
Expand Down
27 changes: 18 additions & 9 deletions src/api/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ export interface Config {
export function getRemoteParsedConfig(repository: Repository): Promise<JobsAndEnv[]> {
return new Promise((resolve, reject) => {
let cloneUrl = repository.clone_url;
let branch = repository.type === 'bitbucket' ? 'master' : repository.branch;
let branch = repository.branch || 'master';
let sha = repository.sha || null;
let pr = repository.pr || null;
let cloneDir = null;
Expand All @@ -117,7 +117,13 @@ export function getRemoteParsedConfig(repository: Repository): Promise<JobsAndEn
createGitTmpDir()
.then(dir => cloneDir = dir)
.then(() => spawnGit(['clone', cloneUrl, '-b', branch, '--depth', '1', cloneDir]))
.then(() => checkoutShaOrPr(sha, pr, cloneDir, repository.type, repository.branch))
.then(() => {
if (sha || pr) {
return checkoutShaOrPr(sha, pr, cloneDir, repository.type, repository.branch);
} else {
return Promise.resolve();
}
})
.then(() => readGitDir(cloneDir))
.then(files => repository.file_tree = files)
.then(() => {
Expand Down Expand Up @@ -163,7 +169,7 @@ export function parseConfigFromRaw(repository: Repository, raw: string): Promise
export function checkRepositoryAccess(repository: Repository): Promise<boolean> {
return new Promise((resolve, reject) => {
let cloneUrl = repository.clone_url;
let branch = repository.branch;
let branch = repository.branch || 'master';
let cloneDir = null;

if (repository.access_token) {
Expand All @@ -181,7 +187,7 @@ export function checkRepositoryAccess(repository: Repository): Promise<boolean>
export function checkConfigPresence(repository: Repository): Promise<boolean> {
return new Promise((resolve, reject) => {
let cloneUrl = repository.clone_url;
let branch = repository.branch;
let branch = repository.branch || 'master';
let cloneDir = null;

if (repository.access_token) {
Expand All @@ -207,7 +213,7 @@ export function checkConfigPresence(repository: Repository): Promise<boolean> {
export function getConfigRawFile(repository: Repository): Promise<any> {
return new Promise((resolve, reject) => {
let cloneUrl = repository.clone_url;
let branch = repository.branch;
let branch = repository.branch || 'master';
let cloneDir = null;

if (repository.access_token) {
Expand Down Expand Up @@ -430,7 +436,7 @@ export function generateJobsAndEnv(repo: Repository, config: Config): JobsAndEnv
fetch = `git fetch origin pull/${repo.pr}/head:pr${repo.pr}`;
checkout = `git checkout pr${repo.pr}`;
} else if (repo.type === 'bitbucket') {
fetch = `git fetch origin ${repo.branch}:${repo.branch}`;
fetch = `git fetch origin ${repo.branch}`;
checkout = `git checkout FETCH_HEAD`;
}
} else if (repo.sha) {
Expand Down Expand Up @@ -602,13 +608,16 @@ function checkoutShaOrPr(
fetch = `${gitDir} fetch origin pull/${pr}/head:pr${pr}`;
checkout = `${gitDir} --work-tree ${dir} checkout pr${pr}`;
} else if (type === 'bitbucket') {
fetch = `${gitDir} fetch origin ${branch}:${branch}`;
fetch = `${gitDir} fetch origin ${branch}`;
checkout = `${gitDir} --work-tree ${dir} checkout FETCH_HEAD`;
}

} else if (sha) {
fetch = `${gitDir} fetch origin ${branch}`;
checkout = `${gitDir} --work-tree ${dir} checkout ${sha}`;
if (type === 'bitbucket') {
checkout = `${gitDir} --work-tree ${dir} checkout FETCH_HEAD`;
} else {
checkout = `${gitDir} --work-tree ${dir} checkout ${sha}`;
}
}

if (fetch && checkout) {
Expand Down
1 change: 1 addition & 0 deletions src/api/db/access-token.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ export function getAccessTokens(): Promise<any> {

const result = tokens.toJSON().map(token => {
delete token.token;
delete token.bitbucket_oauth_secret;
delete token.user.password;
return token;
});
Expand Down
23 changes: 16 additions & 7 deletions src/api/db/build.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Build, BuildRun, Job, JobRun } from './model';
import { getLastRun } from './job';
import { getBitBucketAccessToken } from '../utils';

export function getBuilds(
limit: number,
Expand Down Expand Up @@ -119,12 +120,6 @@ export function getBuild(id: number, userId?: number): Promise<any> {
return run;
});

if (build.repository.access_token && build.repository.access_token) {
build.repository.access_token = build.repository.access_token.token;
} else {
build.repository.access_token = null;
}

userId = parseInt(<any>userId, 10);
if (build.repository.permissions && build.repository.permissions.length) {
let index = build.repository.permissions.findIndex(p => p.users_id === userId);
Expand All @@ -137,7 +132,21 @@ export function getBuild(id: number, userId?: number): Promise<any> {
build.hasPermission = false;
}

return build;
if (typeof build.repository.access_token !== 'undefined') {
const token_data = build.repository.access_token;
if (token_data.type === 'bitbucket') {
build.repository.access_token = `${token_data.bitbucket_oauth_key}:${token_data.bitbucket_oauth_secret}`;
return Promise.resolve(build);
} else {
build.repository.access_token = build.repository.access_token && build.repository.access_token.token ?
build.repository.access_token.token : null;

return Promise.resolve(build);
}
} else {
build.repository.access_token = null;
return Promise.resolve(build);
}
})
.then(build => {
new BuildRun()
Expand Down
6 changes: 5 additions & 1 deletion src/api/db/migrations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,11 @@ export function create(): Promise<null> {
.then(() => schema.createTableIfNotExists('access_tokens', (t: knex.TableBuilder) => {
t.increments('id').unsigned().primary();
t.string('description').notNullable();
t.string('token').notNullable();
t.string('token');
t.string('bitbucket_client_id');
t.string('bitbucket_oauth_key');
t.string('bitbucket_oauth_secret');
t.enum('type', ['github', 'gitlab', 'bitbucket', 'gogs']);
t.integer('users_id').notNullable();
t.foreign('users_id').references('users.id');
t.timestamps();
Expand Down
25 changes: 19 additions & 6 deletions src/api/db/repository.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Repository, Build } from './model';
import { getHttpJsonResponse } from '../utils';
import { getHttpJsonResponse, getBitBucketAccessToken } from '../utils';
import { addRepositoryPermissionToEveryone } from './permission';
import { URL } from 'url';

Expand Down Expand Up @@ -90,11 +90,24 @@ export function getRepositoryOnly(id: number): Promise<any> {
reject(repo);
} else {
repo = repo.toJSON();

repo.access_token = repo.access_token && repo.access_token.token ?
repo.access_token.token : null;

resolve(repo);
if (typeof repo.access_token !== 'undefined') {
const token_data = repo.access_token;
if (token_data.type === 'bitbucket') {
const credentials = `${token_data.bitbucket_oauth_key}:${token_data.bitbucket_oauth_secret}`;
getBitBucketAccessToken(credentials)
.then(resp => {
repo.access_token = `${token_data.bitbucket_client_id}:${resp.access_token}`;
resolve(repo);
})
.catch(err => reject(err));
} else {
repo.access_token = repo.access_token && repo.access_token.token ? repo.access_token.token : null;
resolve(repo);
}
} else {
repo.access_token = null;
resolve(repo);
}
}
}).catch(err => reject(err));
});
Expand Down
1 change: 1 addition & 0 deletions src/api/logger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ export let logger: Subject<LogMessageType> = new Subject();
logger
.filter((msg: LogMessageType) => !!msg.message && msg.message !== '')
.mergeMap((msg: LogMessageType) => {
msg.message = typeof msg.message === 'object' ? JSON.stringify(msg.message) : msg.message;
let message = { message: msg.message, type: msg.type, notify: msg.notify };
return Observable.fromPromise(insertLog(colorizeMessage(message)));
})
Expand Down
Loading

0 comments on commit f432310

Please sign in to comment.