Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ Close reviews that are ready to close.
`Upsource: Refresh`
Fetches reviews and refreshes upsource custom view.

`Upsource: Add participant to Review`
Add a participan to the current review.

## Settings

`upsource.checkForOpenReviewsOnLaunch`
Expand Down
5 changes: 5 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
"onCommand:upsource.showReviews",
"onCommand:upsource.createReview",
"onCommand:upsource.closeReview",
"onCommand:upsource.addParticipantToReview",
"workspaceContains:upsource.json",
"onView:upsourceView"
],
Expand All @@ -70,6 +71,10 @@
"dark": "resources/dark/plus.svg"
}
},
{
"command": "upsource.addParticipantToReview",
"title": "Upsource: Add participant to Review"
},
{
"command": "upsource.closeReviewAndRefresh",
"title": "Upsource: Close Review"
Expand Down
12 changes: 11 additions & 1 deletion src/Config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,11 @@ export default class Config {
prompt: question + 'project ID',
placeHolder: defaultConfig.projectId || 'Project ID',
password: false
},
{
prompt: question + 'reviewers comma separated',
placeHolder: 'Reviewers',
password: false
}
];

Expand All @@ -74,7 +79,12 @@ export default class Config {
if (typeof input == 'undefined') return;
if (input) settings.projectId = input;

this.createAndOpenConfigFileIfNotExists(settings);
vscode.window.showInputBox(steps[4]).then(input => {
if (typeof input == 'undefined') return;
if (input) settings.reviewers = input.split(',').map(reviewer => reviewer.trim());

this.createAndOpenConfigFileIfNotExists(settings);
});
});
});
});
Expand Down
56 changes: 56 additions & 0 deletions src/Upsource.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ import { ReviewIdDTO } from './models/ReviewIdDTO';
import { ReviewListDTO } from './models/ReviewListDTO';
import { RevisionDescriptorListDTO } from './models/RevisionDescriptorListDTO';
import { UpsConfig } from './models/UpsConfig';
import { UsersForReviewDTO } from './models/UsersForReviewDTO';
import { UsersOthersDTO } from './models/UsersOthersDTO';
import { UserInfoResponseDTO } from './models/UserInfoResponseDTO';
import { RoleInReviewEnum } from './models/Enums';

const Config = new ConfigService;

Expand Down Expand Up @@ -132,6 +136,58 @@ export default class Upsource {
});
}

public addParticipantToReview(reviewId: ReviewIdDTO, participant: ParticipantInReviewDTO): Promise<any> {
let params = {
reviewId,
participant
};

return new Promise<any>((resolve, reject) => {
this.sendAPIRequest('addParticipantToReview', 'POST', params).then(
res => resolve(),
err => reject(err)
);
});
}

public getUsersForReview(reviewId: ReviewIdDTO): Promise<UsersOthersDTO> {
const params = {
'reviewId': reviewId,
'role': RoleInReviewEnum.Reviewer,
'limit': 99
}
return new Promise<any>((resolve, reject) => {
this.sendAPIRequest('getUsersForReview', 'POST', params).then(
res => resolve(res.result.result),
err => reject(err)
);
});
}

public getUserInfo(ids: string[]): Promise<UserInfoResponseDTO> {
const params = {
'ids': ids
}
return new Promise<any>((resolve, reject) => {
this.sendAPIRequest('getUserInfo', 'POST', params).then(
res => resolve(res.result),
err => reject(err)
);
});
}

public getUsersInfoForReview(reviewId: ReviewIdDTO): Promise<UserInfoResponseDTO> {

return new Promise<any>((resolve, reject) => {
this.getUsersForReview(reviewId).then((users) => {
this.getUserInfo(users.others).then(
res => resolve(res),
err => reject(err)
);
});
});
}

private sendAPIRequest(path: string, method: string, params: Object = {}): Promise<any> {
return new Promise<any>((resolve, reject) => {
Config.get().then(
Expand Down
86 changes: 66 additions & 20 deletions src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { ReviewListDTO } from './models/ReviewListDTO';
import { ReviewStateEnum, RoleInReviewEnum } from './models/Enums';
import { ReviewTreeItem } from './models/ReviewTreeItem';
import { UpsConfig } from './models/UpsConfig';
import { ParticipantInReviewDTO } from './models/ParticipantInReviewDTO';

const { rootPath } = vscode.workspace;
const Upsource = new UpsourceService;
Expand All @@ -34,7 +35,8 @@ export function activate(context: vscode.ExtensionContext) {
{ name: 'setup', callback: showSetupDialog },
{ name: 'showReviews', callback: showReviews },
{ name: 'createReview', callback: showCreateReviewQuickPicks },
{ name: 'closeReview', callback: showCloseReviewQuickPicks }
{ name: 'closeReview', callback: showCloseReviewQuickPicks },
{ name: 'addParticipantToReview', callback: showParticipantsQuickPicks }
];


Expand Down Expand Up @@ -96,6 +98,11 @@ function setRefreshInterval(): void {
function showReviews(): void {
let customQueries = <any[]>vscode.workspace.getConfiguration().get('upsource.customQueries'),
items: any[] = [
{
label: 'Current',
description: 'Current branch',
query: git.branch(rootPath)
},
{
label: 'All',
description: 'All open & closed reviews',
Expand Down Expand Up @@ -298,7 +305,6 @@ function showRevisionsQuickPicks(): void {
revisions: [revision.revisionId]
};
});

vscode.window.showQuickPick(items).then(selectedItem => {
if (!selectedItem) return;
createReview(null, selectedItem.revisions);
Expand All @@ -308,27 +314,37 @@ function showRevisionsQuickPicks(): void {
);
}

function createReview(branch = null, revisions = null): void {
Upsource.createReview(branch, revisions).then(
review => {
if (!review) return;

vscode.window.showInformationMessage(
"Review '" + review.reviewId.reviewId + "' successfully created."
);
const createReview = async(branch = null, revisions = null) => {
const review = await Upsource.createReview(branch, revisions);
if (!review) return;
vscode.window.showInformationMessage(
"Review '" + review.reviewId.reviewId + "' successfully created."
);

let resetParticipants = <boolean>vscode.workspace.getConfiguration('upsource').get('resetParticipantsOnCreate');
if (resetParticipants) {
let participants = review.participants.filter((participant) => participant.role != RoleInReviewEnum.Author);
participants.forEach((participant) => {
Upsource.removeParticipantFromReview(review.reviewId, participant);
});
}
let resetParticipants = <boolean>vscode.workspace.getConfiguration('upsource').get('resetParticipantsOnCreate');
if (resetParticipants) {
let participants = review.participants.filter((participant) => participant.role != RoleInReviewEnum.Author);
participants.forEach((participant) => {
Upsource.removeParticipantFromReview(review.reviewId, participant);
});
}

_reviewDataProvider.refresh();
},
err => showError(err)
const config:UpsConfig = await Config.get();
const users = await Upsource.getUsersInfoForReview(review.reviewId);
const validUsers = users.infos.filter( user =>
config.reviewers.find(reviewer => reviewer.toLowerCase() === user.name.toLowerCase())
);
const all = await Promise.all(validUsers.map(user => {
return <ParticipantInReviewDTO>{
userId: user.userId,
role: RoleInReviewEnum.Reviewer
};
}).map((participant) => Upsource.addParticipantToReview(review.reviewId, participant))
);
vscode.window.showInformationMessage(
`Reviewers '${validUsers.map((user)=>user.name).join(', ')}' successfully added to review.`
);
_reviewDataProvider.refresh();
}

function closeReview(review: ReviewDescriptorDTO) {
Expand All @@ -342,6 +358,36 @@ function closeReview(review: ReviewDescriptorDTO) {
);
}

const showParticipantsQuickPicks = async() => {
const res = await Upsource.getReviewList(git.branch(rootPath));
if (res.totalCount !== 1 ) {
vscode.window.showErrorMessage("Please create a review for the current branch first");
return;
}
const review = res.reviews[0];
const users = await Upsource.getUsersInfoForReview(review.reviewId);
/*
* Construct the menu with possible reviewers.
*/
const selectedItem = await vscode.window.showQuickPick(users.infos.map(user =>
({
label: user.name,
description: user.email,
user: user
}))
);
if(!selectedItem) {
return;
}

await Upsource.addParticipantToReview(review.reviewId, <ParticipantInReviewDTO>{
userId: selectedItem.user.userId,
role: RoleInReviewEnum.Reviewer
});
vscode.window.showInformationMessage(`Participant '${selectedItem.user.name}' successfully added to review '${review.reviewId.reviewId}'.`);
}


function showError(err) {
vscode.window.showErrorMessage(err);
}
Expand Down
2 changes: 1 addition & 1 deletion src/models/ParticipantInReviewDTO.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,6 @@ export class ParticipantInReviewDTO {
constructor(
public userId: string,
public role: RoleInReviewEnum,
public state: ParticipantStateEnum,
public state?: ParticipantStateEnum,
) {}
};
1 change: 1 addition & 0 deletions src/models/UpsConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,6 @@ export class UpsConfig {
public login: string = '',
public projectId: string = '',
public password: string = '',
public reviewers: string[] = []
) {}
};
7 changes: 7 additions & 0 deletions src/models/UsersForReviewDTO.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { UsersOthersDTO } from './UsersOthersDTO';

export class UsersForReviewDTO {
constructor(
public ids: UsersOthersDTO
) {}
};
6 changes: 6 additions & 0 deletions src/models/UsersOthersDTO.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export class UsersOthersDTO {
constructor(
public others: string[],
public hasMore: boolean
) {}
};