refactor: adjust code to new TSLint rules

This commit is contained in:
Karl-Philipp Wulfert
2019-11-19 12:06:54 +01:00
parent 8a9ab5c041
commit edca51be10
3 changed files with 113 additions and 108 deletions

View File

@@ -34,17 +34,12 @@ import {
TreeFile, TreeFile,
} from './types'; } from './types';
/**
* Instance of logger
*/
export const logger = new Logger();
/** /**
* Sleep for a number of milliseconds * Sleep for a number of milliseconds
* *
* @param ms Number of milliseconds to wait * @param ms Number of milliseconds to wait
*/ */
export function sleep(ms: number) { export async function sleep(ms: number): Promise<void> {
return new Promise((resolve) => setTimeout(resolve, ms)); return new Promise((resolve) => setTimeout(resolve, ms));
} }
@@ -55,7 +50,7 @@ export interface ApiRequestOptions {
/** /**
* Data to be sent with the request * Data to be sent with the request
*/ */
data?: any; data?: object | null;
/** /**
* HTTP verb to use for the request * HTTP verb to use for the request
@@ -124,10 +119,10 @@ export class Api {
* @param userId ID of the user * @param userId ID of the user
* @param accessLevel Access level for the new member in the scope * @param accessLevel Access level for the new member in the scope
*/ */
public addMember(scope: MembershipScope, public async addMember(scope: MembershipScope,
id: number, id: number,
userId: number, userId: number,
accessLevel: AccessLevel): Promise<Member> { accessLevel: AccessLevel): Promise<Member> {
return this.makeGitLabAPIRequest( return this.makeGitLabAPIRequest(
`${scope}/${id}/members`, `${scope}/${id}/members`,
{ {
@@ -137,7 +132,7 @@ export class Api {
}, },
method: 'POST', method: 'POST',
}, },
); ) as Promise<Member>;
} }
/** /**
@@ -147,7 +142,7 @@ export class Api {
* @param title Title of the issue * @param title Title of the issue
* @param description Description of the issue (can contain slash commands) * @param description Description of the issue (can contain slash commands)
*/ */
public createIssue(projectId: number, title: string, description: string): Promise<Issue> { public async createIssue(projectId: number, title: string, description: string): Promise<Issue> {
return this.makeGitLabAPIRequest( return this.makeGitLabAPIRequest(
`projects/${projectId}/issues`, `projects/${projectId}/issues`,
{ {
@@ -157,7 +152,7 @@ export class Api {
}, },
method: 'POST', method: 'POST',
}, },
); ) as Promise<Issue>;
} }
/** /**
@@ -168,22 +163,23 @@ export class Api {
* @param description Description of the label to create * @param description Description of the label to create
* @param color Color of the label to create * @param color Color of the label to create
*/ */
public createLabel(projectId: number, name: string, description?: string, color?: string): Promise<Label> { public async createLabel(projectId: number, name: string, description?: string, color?: string): Promise<Label> {
if (typeof color !== 'string' || !color.match(/^#[0-9a-fA-F]{3,6}$/)) { let _color = '#000000';
color = '#000000'; if (typeof color !== 'string' || !/^#[0-9a-fA-F]{3,6}$/.test(color)) {
_color = '#000000';
} }
return this.makeGitLabAPIRequest( return this.makeGitLabAPIRequest(
`projects/${projectId}/labels`, `projects/${projectId}/labels`,
{ {
data: { data: {
color: color, color: _color,
description: description, description,
name: name, name,
}, },
method: 'POST', method: 'POST',
}, },
); ) as Promise<Label>;
} }
/** /**
@@ -192,10 +188,10 @@ export class Api {
* @param projectId Project ID to create milestone in * @param projectId Project ID to create milestone in
* @param title Title of the milestone to create * @param title Title of the milestone to create
*/ */
public createMilestone(projectId: number, title: string): Promise<void> { public async createMilestone(projectId: number, title: string): Promise<void> {
return this.makeGitLabAPIRequest(`projects/${projectId}/milestones?title=${title}`, { return this.makeGitLabAPIRequest(`projects/${projectId}/milestones?title=${title}`, {
method: 'POST', method: 'POST',
}); }) as Promise<void>;
} }
/** /**
@@ -206,7 +202,7 @@ export class Api {
* @param iid IID of the issue/merge request to create the note in * @param iid IID of the issue/merge request to create the note in
* @param body Body of the note to create * @param body Body of the note to create
*/ */
public createNote(projectId: number, scope: Scope, iid: number, body: string): Promise<void> { public async createNote(projectId: number, scope: Scope, iid: number, body: string): Promise<void> {
return this.makeGitLabAPIRequest( return this.makeGitLabAPIRequest(
`projects/${projectId}/${scope}/${iid}/notes`, `projects/${projectId}/${scope}/${iid}/notes`,
{ {
@@ -215,7 +211,7 @@ export class Api {
}, },
method: 'POST', method: 'POST',
}, },
); ) as Promise<void>;
} }
/** /**
@@ -224,13 +220,13 @@ export class Api {
* @param projectId ID of the project to delete the label from * @param projectId ID of the project to delete the label from
* @param name Name of the label to delete * @param name Name of the label to delete
*/ */
public deleteLabel(projectId: number, name: string): Promise<void> { public async deleteLabel(projectId: number, name: string): Promise<void> {
return this.makeGitLabAPIRequest( return this.makeGitLabAPIRequest(
`projects/${projectId}/labels?name=${name}`, `projects/${projectId}/labels?name=${name}`,
{ {
method: 'DELETE', method: 'DELETE',
}, },
); ) as Promise<void>;
} }
/** /**
@@ -240,8 +236,8 @@ export class Api {
* @param id ID of the group or project * @param id ID of the group or project
* @param userId ID of the user * @param userId ID of the user
*/ */
public deleteMember(scope: MembershipScope, id: number, userId: number): Promise<void> { public async deleteMember(scope: MembershipScope, id: number, userId: number): Promise<void> {
return this.makeGitLabAPIRequest(`${scope}/${id}/members/${userId}`, {method: 'DELETE'}); return this.makeGitLabAPIRequest(`${scope}/${id}/members/${userId}`, {method: 'DELETE'}) as Promise<void>;
} }
/** /**
@@ -251,8 +247,8 @@ export class Api {
* @param name Name of the label to edit * @param name Name of the label to edit
* @param newValues New values for the label * @param newValues New values for the label
*/ */
public editLabel(projectId: number, name: string, newValues: Partial<Label>): Promise<Label> { public async editLabel(projectId: number, name: string, newValues: Partial<Label>): Promise<Label> {
if (typeof newValues.color === 'string' && !newValues.color.match(/^#[0-9a-fA-F]{3,6}$/)) { if (typeof newValues.color === 'string' && !/^#[0-9a-fA-F]{3,6}$/.test(newValues.color)) {
newValues.color = undefined; newValues.color = undefined;
} }
@@ -267,7 +263,7 @@ export class Api {
}, },
method: 'POST', method: 'POST',
}, },
); ) as Promise<Label>;
} }
/** /**
@@ -278,10 +274,10 @@ export class Api {
* @param userId ID of the user * @param userId ID of the user
* @param accessLevel Access level for the member in the scope * @param accessLevel Access level for the member in the scope
*/ */
public editMember(scope: MembershipScope, public async editMember(scope: MembershipScope,
id: number, id: number,
userId: number, userId: number,
accessLevel: AccessLevel): Promise<Member> { accessLevel: AccessLevel): Promise<Member> {
return this.makeGitLabAPIRequest( return this.makeGitLabAPIRequest(
`${scope}/${id}/members`, `${scope}/${id}/members`,
{ {
@@ -291,7 +287,7 @@ export class Api {
}, },
method: 'PUT', method: 'PUT',
}, },
); ) as Promise<Member>;
} }
/** /**
@@ -299,8 +295,8 @@ export class Api {
* *
* @param projectId Project ID to get branches for * @param projectId Project ID to get branches for
*/ */
public getBranchesForProject(projectId: number): Promise<Branch[]> { public async getBranchesForProject(projectId: number): Promise<Branch[]> {
return this.makeGitLabAPIRequest(`projects/${projectId}/repository/branches`); return this.makeGitLabAPIRequest(`projects/${projectId}/repository/branches`) as Promise<Branch[]>;
} }
/** /**
@@ -310,11 +306,11 @@ export class Api {
* @param filePath Path to the file - url encoded * @param filePath Path to the file - url encoded
* @param commitish Commitish of the file * @param commitish Commitish of the file
*/ */
public getFile(projectId: number, filePath: string, commitish: string): Promise<any> { public async getFile(projectId: number, filePath: string, commitish: string): Promise<unknown> {
return this.makeGitLabAPIRequest( const fileIdentifier = `${encodeURIComponent(filePath)
`projects/${projectId}/repository/files/` + .replace('.', '%2E')}/raw?ref=${encodeURIComponent(commitish)}`;
encodeURIComponent(filePath).replace('.', '%2E') + '/raw?ref=' + encodeURIComponent(commitish),
); return this.makeGitLabAPIRequest(`projects/${projectId}/repository/files/${fileIdentifier}`) as Promise<unknown>;
} }
/** /**
@@ -322,8 +318,8 @@ export class Api {
* *
* @param projectId ID of the project * @param projectId ID of the project
*/ */
public getFileList(projectId: number): Promise<TreeFile[]> { public async getFileList(projectId: number): Promise<TreeFile[]> {
return this.makeGitLabAPIRequest(`projects/${projectId}/repository/tree`); return this.makeGitLabAPIRequest(`projects/${projectId}/repository/tree`) as Promise<TreeFile[]>;
} }
/** /**
@@ -331,7 +327,7 @@ export class Api {
* *
* @param options Options to get issues * @param options Options to get issues
*/ */
public getIssues(options: ApiGetIssuesOptions = {}): Promise<Issue[]> { public async getIssues(options: ApiGetIssuesOptions = {}): Promise<Issue[]> {
// start to build request url // start to build request url
let requestUrl = 'issues'; let requestUrl = 'issues';
@@ -355,7 +351,7 @@ export class Api {
// divider = '&'; // divider = '&';
} }
return this.makeGitLabAPIRequest(requestUrl); return this.makeGitLabAPIRequest(requestUrl) as Promise<Issue[]>;
} }
/** /**
@@ -363,8 +359,8 @@ export class Api {
* *
* @param projectId ID of the project to get the labels for * @param projectId ID of the project to get the labels for
*/ */
public getLabels(projectId: number): Promise<Label[]> { public async getLabels(projectId: number): Promise<Label[]> {
return this.makeGitLabAPIRequest(`projects/${projectId}/labels`); return this.makeGitLabAPIRequest(`projects/${projectId}/labels`) as Promise<Label[]>;
} }
/** /**
@@ -373,8 +369,8 @@ export class Api {
* @param scope MembershipScope of the ID * @param scope MembershipScope of the ID
* @param id ID of the group or project * @param id ID of the group or project
*/ */
public getMembers(scope: MembershipScope, id: number): Promise<Member[]> { public async getMembers(scope: MembershipScope, id: number): Promise<Member[]> {
return this.makeGitLabAPIRequest(`${scope}/${id}/members`); return this.makeGitLabAPIRequest(`${scope}/${id}/members`) as Promise<Member[]>;
} }
/** /**
@@ -383,8 +379,9 @@ export class Api {
* @param projectId ID of the project the merge request belongs to * @param projectId ID of the project the merge request belongs to
* @param mergeRequestIid IID of the merge request * @param mergeRequestIid IID of the merge request
*/ */
public getMergeRequestApproval(projectId: number, mergeRequestIid: number): Promise<MergeRequestApproval> { public async getMergeRequestApproval(projectId: number, mergeRequestIid: number): Promise<MergeRequestApproval> {
return this.makeGitLabAPIRequest(`/projects/${projectId}/merge_requests/${mergeRequestIid}/approvals`); return this.makeGitLabAPIRequest(`/projects/${projectId}/merge_requests/${mergeRequestIid}/approvals`) as
Promise<MergeRequestApproval>;
} }
/** /**
@@ -393,10 +390,10 @@ export class Api {
* @param projectId ID of the project the merge request belongs to * @param projectId ID of the project the merge request belongs to
* @param mergeRequestIid IID of the merge request * @param mergeRequestIid IID of the merge request
*/ */
public getMergeRequestDiscussions(projectId: number, mergeRequestIid: number): Promise<Discussion[]> { public async getMergeRequestDiscussions(projectId: number, mergeRequestIid: number): Promise<Discussion[]> {
return this.makeGitLabAPIRequest( return this.makeGitLabAPIRequest(
`projects/${projectId}/merge_requests/${mergeRequestIid}/discussions`, `projects/${projectId}/merge_requests/${mergeRequestIid}/discussions`,
); ) as Promise<Discussion[]>;
} }
/** /**
@@ -406,15 +403,17 @@ export class Api {
* @param id ID of the group or project * @param id ID of the group or project
* @param state State to filter the merge requests by * @param state State to filter the merge requests by
*/ */
public getMergeRequests(scope: MembershipScope, public async getMergeRequests(scope: MembershipScope,
id: number, id: number,
state: MergeRequestState | MergeRequestState[]): Promise<MergeRequest[]> { state: MergeRequestState | MergeRequestState[]): Promise<MergeRequest[]> {
let _state = state;
// join a list of states with commas // join a list of states with commas
if (Array.isArray(state)) { if (Array.isArray(state)) {
state = state.join(',') as MergeRequestState; _state = state.join(',') as MergeRequestState;
} }
return this.makeGitLabAPIRequest(`${scope}/${id}/merge_requests?state=${state}`); return this.makeGitLabAPIRequest(`${scope}/${id}/merge_requests?state=${_state}`) as Promise<MergeRequest[]>;
} }
/** /**
@@ -422,8 +421,8 @@ export class Api {
* *
* @param projectId Project ID to get milestones for * @param projectId Project ID to get milestones for
*/ */
public getMilestonesForProject(projectId: number): Promise<Milestone[]> { public async getMilestonesForProject(projectId: number): Promise<Milestone[]> {
return this.makeGitLabAPIRequest(`projects/${projectId}/milestones`); return this.makeGitLabAPIRequest(`projects/${projectId}/milestones`) as Promise<Milestone[]>;
} }
/** /**
@@ -431,8 +430,8 @@ export class Api {
* *
* @param groupId Group ID to get projects for * @param groupId Group ID to get projects for
*/ */
public getProjectsForGroup(groupId: number): Promise<Project[]> { public async getProjectsForGroup(groupId: number): Promise<Project[]> {
return this.makeGitLabAPIRequest(`groups/${groupId}/projects`); return this.makeGitLabAPIRequest(`groups/${groupId}/projects`) as Promise<Project[]>;
} }
/** /**
@@ -440,8 +439,8 @@ export class Api {
* *
* @param groupId Group ID to get subgroups for * @param groupId Group ID to get subgroups for
*/ */
public getSubGroupsForGroup(groupId: number): Promise<Group[]> { public async getSubGroupsForGroup(groupId: number): Promise<Group[]> {
return this.makeGitLabAPIRequest(`/groups/${groupId}/subgroups`); return this.makeGitLabAPIRequest(`/groups/${groupId}/subgroups`) as Promise<Group[]>;
} }
/** /**
@@ -449,60 +448,60 @@ export class Api {
* *
* @param projectId ID of the project to get the tags for * @param projectId ID of the project to get the tags for
*/ */
public getTags(projectId: number): Promise<Tag[]> { public async getTags(projectId: number): Promise<Tag[]> {
return this.makeGitLabAPIRequest( return this.makeGitLabAPIRequest(
`projects/${projectId}/repository/tags`, `projects/${projectId}/repository/tags`,
); ) as Promise<Tag[]>;
} }
/** /**
* Query a GitLab API URL * Query a GitLab API URL
* *
* @param url GitLab API URL to query * @param url GitLab API URL to query
* @param _options HTTP method/verb * @param options HTTP method/verb
*/ */
public async makeGitLabAPIRequest(url: string, _options?: ApiRequestOptions): Promise<any> { public async makeGitLabAPIRequest(url: string, options?: ApiRequestOptions): Promise<unknown> {
// remove leading slash // remove leading slash
url = url.replace(/^\/+/g, ''); const _url = url.replace(/^\/+/g, '');
const options: Required<ApiRequestOptions> = { const _options: Required<ApiRequestOptions> = {
data: undefined, data: null,
method: 'GET', method: 'GET',
retryOnAnyError: false, retryOnAnyError: false,
tries: 5, tries: 5,
..._options, ...options,
}; };
if (typeof options.method === 'string' && ['DELETE', 'GET', 'POST', 'PUT'].indexOf(options.method) === -1) { if (['DELETE', 'GET', 'POST', 'PUT'].includes(_options.method)) {
options.method = 'GET'; _options.method = 'GET';
} }
let concatenator = '&'; let concatenator = '&';
if (url.indexOf('?') === -1) { if (_url.indexOf('?') === -1) {
concatenator = '?'; concatenator = '?';
} }
let apiResult: any; let apiResult: unknown;
let totalPages = 1; let totalPages = 1;
let currentPage = 0; let currentPage = 0;
while (++currentPage <= totalPages) { while (++currentPage <= totalPages) {
if (currentPage > 1) { if (currentPage > 1) {
logger.info(`Automatically paging call to '${url}'... Getting page ${currentPage} of ${totalPages}.`); Logger.info(`Automatically paging call to '${_url}'... Getting page ${currentPage} of ${totalPages}.`);
} }
let body; let body;
let tries = 0; let tries = 0;
while (typeof body === 'undefined' && tries++ < options.tries) { while (typeof body === 'undefined' && tries++ < _options.tries) {
try { try {
const requestUrl = url + concatenator + 'page=' + currentPage + '&per_page=100'; const requestUrl = `${_url}${concatenator}page=${currentPage}&per_page=100`;
body = await request(this.rootUrl + requestUrl, { body = await request(`${this.rootUrl}${requestUrl}`, {
form: typeof options.data !== 'undefined' ? options.data : undefined, form: _options.data !== null ? _options.data : undefined,
headers: {'PRIVATE-TOKEN': this.privateToken}, headers: {'PRIVATE-TOKEN': this.privateToken},
json: true, json: true,
method: options.method, method: _options.method,
timeout: 60000, timeout: 60000,
transform: (bodyToTransform, response) => { transform: (bodyToTransform, response) => {
const xTotalPages = response.headers['x-total-pages']; const xTotalPages = response.headers['x-total-pages'];
@@ -515,11 +514,12 @@ export class Api {
}, },
}); });
} catch (error) { } catch (error) {
if (error.error.includes('not responding') || options.retryOnAnyError) { if (error.error.includes('not responding') || _options.retryOnAnyError) {
const seconds = 5; const seconds = 5;
logger.warn(`GitLab was not responding. Waiting ${seconds}s and retrying...`); Logger.warn(`GitLab was not responding. Waiting ${seconds}s and retrying...`);
// tslint:disable-next-line:no-magic-numbers
await sleep(seconds * 1000); await sleep(seconds * 1000);
continue; continue;
@@ -529,7 +529,7 @@ export class Api {
} }
} }
if (options.method === 'DELETE') { if (_options.method === 'DELETE') {
return; return;
} }
@@ -551,14 +551,14 @@ export class Api {
* @param projectId ID of the project the branch belongs to * @param projectId ID of the project the branch belongs to
* @param branch Branch to protect * @param branch Branch to protect
*/ */
public protectBranch(projectId: number, branch: string): Promise<Branch> { public async protectBranch(projectId: number, branch: string): Promise<Branch> {
return this.makeGitLabAPIRequest( return this.makeGitLabAPIRequest(
/* tslint:disable-next-line:max-line-length */ /* tslint:disable-next-line:max-line-length */
`projects/${projectId}/repository/branches/${branch}/protect?developers_can_push=false&developers_can_merge=false`, `projects/${projectId}/repository/branches/${branch}/protect?developers_can_push=false&developers_can_merge=false`,
{ {
method: 'PUT', method: 'PUT',
}, },
); ) as Promise<Branch>;
} }
/** /**
@@ -567,13 +567,13 @@ export class Api {
* @param issue Issue to set milestone for * @param issue Issue to set milestone for
* @param userId ID of the milestone to set for the issue * @param userId ID of the milestone to set for the issue
*/ */
public setAssigneeForIssue(issue: Issue, userId: number): Promise<Issue> { public async setAssigneeForIssue(issue: Issue, userId: number): Promise<Issue> {
return this.makeGitLabAPIRequest( return this.makeGitLabAPIRequest(
`projects/${issue.project_id}/issues/${issue.iid}?assignee_ids=${userId}`, `projects/${issue.project_id}/issues/${issue.iid}?assignee_ids=${userId}`,
{ {
method: 'PUT', method: 'PUT',
}, },
); ) as Promise<Issue>;
} }
/** /**
@@ -582,14 +582,14 @@ export class Api {
* @param issue Issue to set milestone for * @param issue Issue to set milestone for
* @param milestoneId ID of the milestone to set for the issue * @param milestoneId ID of the milestone to set for the issue
*/ */
public setMilestoneForIssue(issue: Issue, milestoneId: number): Promise<Issue> { public async setMilestoneForIssue(issue: Issue, milestoneId: number): Promise<Issue> {
if (milestoneId === null) { if (milestoneId === null) {
return this.makeGitLabAPIRequest( return this.makeGitLabAPIRequest(
`projects/${issue.project_id}/issues/${issue.iid}?milestone_id=`, `projects/${issue.project_id}/issues/${issue.iid}?milestone_id=`,
{ {
method: 'PUT', method: 'PUT',
}, },
); ) as Promise<Issue>;
} }
return this.makeGitLabAPIRequest( return this.makeGitLabAPIRequest(
@@ -597,6 +597,6 @@ export class Api {
{ {
method: 'PUT', method: 'PUT',
}, },
); ) as Promise<Issue>;
} }
} }

View File

@@ -12,12 +12,14 @@
* You should have received a copy of the GNU General Public License along with * You should have received a copy of the GNU General Public License along with
* this program. If not, see <https://www.gnu.org/licenses/>. * this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
import {Logger} from '@openstapps/logger';
import * as commander from 'commander'; import * as commander from 'commander';
import {readFileSync} from 'fs'; import {readFileSync} from 'fs';
import {join} from 'path'; import {join} from 'path';
import {Api, ApiRequestOptions, logger} from './api'; import {Api, ApiRequestOptions} from './api';
const pkgJson = JSON.parse(readFileSync(join(__dirname, '..', 'package.json')).toString()); const pkgJson = JSON.parse(readFileSync(join(__dirname, '..', 'package.json'))
.toString());
commander commander
.version(pkgJson.version); .version(pkgJson.version);
@@ -38,7 +40,7 @@ if (typeof commander.call === 'undefined') {
if (typeof commander.token === 'undefined') { if (typeof commander.token === 'undefined') {
if (typeof process.env.GITLAB_PRIVATE_TOKEN === 'undefined') { if (typeof process.env.GITLAB_PRIVATE_TOKEN === 'undefined') {
logger.error('You have to supply '); Logger.warn('You probably want to supply a GitLab token either via option or environment variable (GITLAB_PRIVATE_TOKEN).');
} }
commander.token = process.env.GITLAB_PRIVATE_TOKEN; commander.token = process.env.GITLAB_PRIVATE_TOKEN;
@@ -56,10 +58,11 @@ if (typeof commander.data !== 'undefined') {
options.data = JSON.parse(commander.data); options.data = JSON.parse(commander.data);
} }
gitLabApi.makeGitLabAPIRequest(commander.call, options).then((result) => { gitLabApi.makeGitLabAPIRequest(commander.call, options)
logger.ok(result); .then((result) => {
process.exit(1); Logger.ok(result);
}, (err) => { process.exit(1);
logger.error(err); }, async (err) => {
process.exit(1); await Logger.error(err);
}); process.exit(1);
});

View File

@@ -13,6 +13,8 @@
* this program. If not, see <https://www.gnu.org/licenses/>. * this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
// tslint:disable:completed-docs
/** /**
* Scope of membership * Scope of membership
*/ */
@@ -160,7 +162,7 @@ export interface Project {
public_jobs: boolean; public_jobs: boolean;
request_access_enabled: boolean; request_access_enabled: boolean;
shared_runners_enabled: boolean; shared_runners_enabled: boolean;
shared_with_groups: any[]; shared_with_groups: unknown[];
snippets_enabled: boolean; snippets_enabled: boolean;
ssh_url_to_repo: string; ssh_url_to_repo: string;
star_count: number; star_count: number;
@@ -307,7 +309,7 @@ export interface MergeRequest extends ThingWithTimeStats {
export interface MergeRequestApproval { export interface MergeRequestApproval {
approvals_left: number; approvals_left: number;
approvals_required: number; approvals_required: number;
approved_by: Array<{ user: User }>; approved_by: Array<{ user: User; }>;
approver_groups: Group[]; approver_groups: Group[];
approvers: User[]; approvers: User[];
created_at: string; created_at: string;
@@ -381,7 +383,7 @@ export interface Note {
new_path: string; new_path: string;
old_line: number | null; old_line: number | null;
old_path: string; old_path: string;
position_type: string, position_type: string;
start_sha: string; start_sha: string;
}; };
resolvable: boolean; resolvable: boolean;