GitLabの類似イシュー(Similar issues)機能をソースコードから解析

### はじめに

GitLabでせっかくイシュー登録したのに、「それ既に登録されているよ」と言われ、
がっかりしたことありませんか。
類似イシューの重複登録防止策として、`Similar issues`機能がGitLabに備わっています。
これで似たようなトピックが複数登録される可能性が減り、管理者の手間も省けそうです。

類似イシュー表示機能がどのように実装されているか、ソースコードをのぞいてみました。

### その前に、`Similar issues`機能とは

GitLabの新規イシュー作成ページで、タイトルにキーワード(例えば、`パフォーマンス`)
を入力すると、`パフォーマンス`と関連する既存イシューのリストが表示されます。
例えば、

- パフォーマンスチューニング
- 画面表示が遅い原因の調査  (※ このイシューは、説明に`パフォーマンス`が含まれています)
- パフォーマンスの計測手順を作成

などのイシュー。

![スクリーンショット 2022-10-02 142815.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2523098/83e37db1-aae6-673c-a7b8-f777ab0d9b27.jpeg)

### `Similar issues`機能について、GitLab公式ドキュメントの定義

https://docs.gitlab.com/ee/user/project/issues/managing_issues.html#similar-issues

- 同じトピックのイシューが重複登録されないように、類似イシューを検索し表示する
- 新規イシューページでタイトルを入力すると、カレントプロジェクトのすべてのIssueのタイトルと説明に対して、検索が行われる
- 類似イシューとして、ユーザがアクセス権限を持つイシューを最大5件まで、更新日の新しい順に表示してくれる
- 前提として、`GraphQL`を有効にしておく必要あり

#### GraphQLが使用されているようですのでおさらいです

https://ja.wikipedia.org/wiki/GraphQL

- GraphQL(グラフQL)はAPI向けに作られたクエリ言語およびランタイム
- ウェブAPI開発に使用するRESTやその他Webサービスと比較し、効率的、堅牢、フレキシブルなアプローチを提供
- クライアントが必要なデータ構造を定義可能で、サーバーからは定義された同じ構造のデータが返される
    - したがって、必要以上に大きいデータが返されるのを防げる、クエリの効率が良い
- GraphQLは、型システム、クエリ言語、実行セマンティクス、静的な検証、型イントロスペクションから構成される
- GraphQLは、データの問い合わせ(query)、書き換え(mutation)、購読(subscription)をサポートする

### GitLabのソースコードについて

GitLabはRuby on Rails利用して開発されています。
GitLabがRuby on Railsを使い続ける理由に、
- 構造化されている
- 使いやすい

2点を、以下記事で取り上げています。

https://techracho.bpsinc.jp/hachi8833/2022_07_08/119527


### ソースコードから`Similar issues`の実装を確認

#### まず、Chromeデベロッパーツールなどで類似イシューの関連要素を確認


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2523098/b5d3fefd-ae0e-61ef-5c7b-fb6bc4cce815.png)

```
<div class="d-flex align-items-center"><!---->
<a href="https://gitlab.com/xxxxx/performance-test/-/issues/1"
rel="noopener" target="_blank" class="gl-link suggestion bold str-truncated-100 gl-text-gray-900!">
      パフォーマンスの計測手順を作成
    </a></div>
```

#### つぎ、上記要素を処理する`vue`ファイルを確認

- `title_suggestions_item.vue`

https://gitlab.com/gitlab-org/gitlab/-/blob/master/app/assets/javascripts/issues/new/components/title_suggestions_item.vue

```
... ...
    <div class="d-flex align-items-center">
      <gl-icon
        v-if="suggestion.confidential"
        v-gl-tooltip.bottom
        :title="__('Confidential')"
        name="eye-slash"
        class="gl-cursor-help gl-mr-2 gl-text-orange-500"
      />
      <gl-link
        :href="suggestion.webUrl"
        target="_blank"
        class="suggestion bold str-truncated-100 gl-text-gray-900!"
      >
        {{ suggestion.title }}
      </gl-link>
    </div>
... ...
```

画面上で類似イシューのタイトルは、`suggestion.title`フィールドで表しています。

- `title_suggestions.vue`

https://gitlab.com/gitlab-org/gitlab/-/blob/master/app/assets/javascripts/issues/new/components/title_suggestions.vue

```
import query from '../queries/issues.query.graphql';
import TitleSuggestionsItem from './title_suggestions_item.vue';
... ...
  apollo: {
    issues: {
      query,
      debounce: 1000,
      skip() {
        return this.isSearchEmpty;
      },
      update: (data) => data.project.issues.edges.map(({ node }) => node),
      variables() {
        return {
          fullPath: this.projectPath,
          search: this.search,
        };
      },
    },
  },
... ...
    <ul class="gl-list-style-none gl-m-0 gl-p-0">
      <li
        v-for="(suggestion, index) in issues"
        :key="suggestion.id"
        :class="{
          'gl-mb-3': index !== issues.length - 1,
        }"
      >
        <title-suggestions-item :suggestion="suggestion" />
      </li>
    </ul>
```

#### 類似イシューの検索に使用されるGraphQLクエリ

- `issues.query.graphql`

https://gitlab.com/gitlab-org/gitlab/-/blob/master/app/assets/javascripts/issues/new/queries/issues.query.graphql

```
query issueSuggestion($fullPath: ID!, $search: String) {
  project(fullPath: $fullPath) {
    id
    issues(search: $search, sort: updated_desc, first: 5) {
      edges {
        node {
          id
          iid
          title
          confidential
          userNotesCount
          upvotes
          webUrl
          state
          closedAt
          createdAt
          updatedAt
          author {
            id
            name
            username
            avatarUrl
            webUrl
          }
        }
      }
    }
  }
}
```

指定された検索キーワードを使用し、最大5件、更新日の新しい順に、イシューを検索しています。

### おわりに

GitLabの類似イシュー(Similar issues)機能を考察しました。
利便性もさることながら、その発想もいろいろ考えさせられるものがありました。