issuableId: getMrGqlId()

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) {