概要
GitBucket は、GitHub のようにネットワーク上で Git リポジトリを共有できる Web サービスです。
- Apache-2.0 ライセンスで配布されている。
- Scala で開発されており、Java 17 実行環境があれば、起動可能。
- お試しであれば、内臓のH2データベースエンジンが利用できる。
- 実運用には、PostgreSQL や MariaDB などのリレーショナルデータベースサーバーの利用を推奨
- 非常に簡単にセルフホストが可能です。
現在、GitBucket の issue に以下の項目を設定可能にし、ガントチャートへ反映できる GitBucket Flexible Gantt Plugin を開発中です。
- 開始日
- 終了日
- 進捗
- 依存 issue (issue 番号をカンマ区切りで複数指定可能)
今回は、0.2.0 でマイルストーンやラベルでフィルタリングを可能にした話です。
前回の記事
メニューからマイルストーンを選択するとタスクが絞り込まれます
ガントチャートの上に Filter メニューを配置しました。
Milestone から絞り込みたいマイルストーンを選択するとタスクが絞り込まれます。
以下、ソースの修正について、説明します。
まずはマイルストーンによる絞り込みを行うデータベースアクセスを
IssuePeriodService に getIssuePeriodsByMilestone メソッドを追加しました。
def getIssuePeriodsByMilestone(
userName: String,
repositoryName: String,
milestoneId: Int
)(implicit session: Session): List[(gitbucket.core.model.Issue, io.github.yasumichi.gfg.model.IssuePeriod)] = {
Issues
.filter(_.byMilestone(userName, repositoryName, milestoneId))
.join(IssuePeriods)
.on { case (t1: Issues, t2: IssuePeriods) =>
t1.userName === t2.userName && t1.repositoryName === t2.repositoryName && t1.issueId === t2.issueId
}
.list
}
ISSUE テーブルをマイルストーンIDで絞り込み、ISSUE_PERIOD と結合し、リスト化しています。
絞り込み条件を渡すため twirl テンプレートを修正
絞り込み条件を渡すため src/main/twirl/flexiblegantt/flexiblegantt.scala.html の引数を追加します。
@(
repository: gitbucket.core.service.RepositoryService.RepositoryInfo,
milestoneId: Int,
labelName: String,
isManageable: Boolean
)(implicit context: gitbucket.core.controller.Context)
後で追加するラベル名もここで追加しておきます。
twirl テンプレートにマイルストーンIDを渡すメソッドをコントローラーに作成
FlexibleGanttController に /:owner/:repository/flexible-gantt/milestones/:milestoneId という URL を処理するメソッドを追加します。
get("/:owner/:repository/flexible-gantt/milestones/:milestoneId") {
referrersOnly { repository: RepositoryInfo =>
{
implicit val session: Session = Database.getSession(context.request)
html.flexiblegantt(repository, params("milestoneId").toInt, "", isIssueManageable(repository))
}
}
}
さらにマイルストーンIDで絞り込んだタスクのリストを返すメソッドを作成
さらに FlexibleGanttController に /:owner/:repository/flexible-gantt/issues/milestones/:milestoneId という URL を処理するメソッドを追加します。
ajaxGet("/:owner/:repository/flexible-gantt/issues/milestones/:milestoneId")(readableUsersOnly { repository =>
implicit val session: Session = Database.getSession(context.request)
contentType = formats("json")
org.json4s.jackson.Serialization.write(
"list" ->
getIssuePeriodsByMilestone(repository.owner, repository.name, params("milestoneId").toInt)
.map { t =>
Map(
"id" -> t._1.issueId.toString(),
"name" -> t._1.title,
"start" -> t._2.startDate,
"end" -> t._2.endDate,
"progress" -> t._2.progress,
"dependencies" -> t._2.dependencies
)
}
)
})
フィルタリング条件に応じてタスクのリストを取得する URL を変更する仕組みを作る
Twirl テンプレート src/main/twirl/flexiblegantt/flexiblegantt.scala.html をさらに修正します。
@if(milestoneId == 0 && labelName == "") {
<script>
var taskUrl = "@context.baseUrl/@repository.owner/@repository.name/flexible-gantt/issues";
</script>
} else if (milestoneId > 0) {
<script>
var taskUrl = "@context.baseUrl/@repository.owner/@repository.name/flexible-gantt/issues/milestones/@milestoneId";
</script>
} else if (labelName != "") {
<script>
var taskUrl = "@context.baseUrl/@repository.owner/@repository.name/flexible-gantt/issues/labels/@labelName";
</script>
}
コントローラーから渡された引数に応じて、取得URLを切り替えています。
ラベルによる絞り込みも同様に修正していますがデータベース操作の部分だけ紹介します
IssuePeriodService に getIssuePeriodsByLabel メソッドを追加しました。
def getIssuePeriodsByLabel(
userName: String,
repositoryName: String,
labelName: String
)(implicit session: Session): List[(gitbucket.core.model.Issue, io.github.yasumichi.gfg.model.IssuePeriod)] = {
val issueIds: Query[Rep[Int], Int, Seq] = Labels.filter(_.byLabel(userName, repositoryName, labelName)).join(IssueLabels).on {case (t1: Labels, t2: IssueLabels) => t1.labelId === t2.labelId && t1.userName === t2.userName && t1.repositoryName === t2.repositoryName}.map{case (t1: Labels, t2: IssueLabels) => t2.issueId}
Issues
.filter(_.byRepository(userName, repositoryName))
.filter(_.issueId in issueIds)
.join(IssuePeriods)
.on { case (t1: Issues, t2: IssuePeriods) =>
t1.userName === t2.userName && t1.repositoryName === t2.repositoryName && t1.issueId === t2.issueId
}
.list
}
Slick の理解が不足しており、3つのテーブルを結合しようとするとなかなかコンパイルエラーが解消できなかったため、方向を変えました。
まずは、LABEL テーブルをラベル名で絞り込み、ISSUE_LABEL テーブルと結合し、ISSUE_ID を絞り込みます。
次に ISSUE テーブルをユーザー名とリポジトリ名で絞り込み、さらに絞り込んだ ISSUE_ID で絞り込み、ISSUE_PERIOD テーブルと結合し、リスト化して返します。

