in src/desktop/gitlab/gitlab_service.ts [617:744]
issuableId: getMrGqlId(mrId),
body,
position,
});
assert(
result?.createDiffNote?.note?.discussion,
`Response doesn't contain a note with discussion: ${JSON.stringify(result)}`,
);
return result.createDiffNote.note.discussion;
} catch (e) {
throw new UserFriendlyError(
`Unable to add comment. Try again.`,
new Error(`MR(${mrId}), ${JSON.stringify(position)}, ${e}`),
);
}
}
async validateCIConfig(project: GitLabProject, content: string): Promise<ValidationResponse> {
await this.validateVersion('CI config validation', REQUIRED_VERSIONS.CI_CONFIG_VALIDATIONS);
return this.#apiClient.postFetch(`/projects/${project.restId}/ci/lint`, 'CI validation', {
content,
});
}
async renderMarkdown(markdown: string, project: GitLabProject) {
const responseBody = await this.#apiClient.postFetch<{ html: string }>(
'/markdown',
'rendered markdown',
{
text: markdown,
project: project.namespaceWithPath,
gfm: 'true', // True needs to be a string for the API
},
);
return responseBody.html;
}
async createSnippet(
project: GitLabProject,
data: CreateSnippetOptions,
): Promise<{ web_url: string }> {
return this.#apiClient.postFetch(
`/projects/${project.restId}/snippets`,
'create snippet',
data,
);
}
async validateVersion(
featureName: string,
requiredVersion: string,
requireEnterprise: boolean = false,
) {
// TODO: Improve non-null assertion here. probably it should be upstream in getVersionAndEdition function
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const currentVersion = (await this.getVersionAndEdition())!;
ifVersionGte(
currentVersion.version,
requiredVersion,
() => undefined,
() => {
throw new UnsupportedVersionError(featureName, currentVersion.version, requiredVersion);
},
);
if (requireEnterprise && currentVersion && !currentVersion.enterprise) {
throw new Error(
`${featureName} is unavailable on GitLab Community Edition (${currentVersion.version}).`,
);
}
}
async getFirstUserByUsername(username: string): Promise<RestUser | undefined> {
const users = await this.#apiClient.fetch('/users', { username }, 'users');
return (users as RestUser[])[0];
}
async handleCurrentUser<S extends string | undefined>(username: S): Promise<S> {
if (username === '<current_user>') {
const user = await this.fetchFromApi(currentUserRequest);
return user.username as S;
}
return username;
}
async getIssuables(params: CustomQuery, project: GitLabProject) {
const { type, scope, state, author, assignee, wip, draft, reviewer } = params;
let { searchIn } = params;
const config = {
type: type || 'merge_requests',
scope: scope || 'all',
state: state || 'opened',
};
if (config.type === 'vulnerabilities' && config.scope !== 'dismissed') {
config.scope = 'all';
} else if (
(config.type === 'issues' || config.type === 'merge_requests') &&
config.scope !== 'assigned_to_me' &&
config.scope !== 'created_by_me'
) {
config.scope = 'all';
}
let path = '';
const search = new Map<string, string>();
search.set('state', config.state);
/**
* Set path based on config.type
*/
if (config.type === 'epics') {
path = `/groups/${project.groupRestId}/${config.type}`;
search.set('include_ancestor_groups', 'true');
} else {
const searchKind =
config.type === CustomQueryType.VULNERABILITY ? 'vulnerability_findings' : config.type;
path = `/projects/${project.restId}/${searchKind}`;
search.set('scope', config.scope);
}
/**
* Author parameters
*/
if (config.type === 'issues') {
if (author) {