統一スラッシュ構文のための syntactic Scalafix rule

in

build.sbt を統一スラッシュ構文へと変換する syntactic Scalafix rule をちゃちゃっと作ったのでここで紹介する。

用法

プロジェクトが git で管理されているか、バックアップを取ること。

$ cs install scalafix
$ export PATH="$PATH:$HOME/Library/Application Support/Coursier/bin"
$ scalafix --rules=https://gist.githubusercontent.com/eed3si9n/57e83f5330592d968ce49f0d5030d4d5/raw/7f576f16a90e432baa49911c9a66204c354947bb/Sbt0_13BuildSyntax.scala *.sbt project/*.scala

完全には正確じゃないが、手動で全部やるよりはマシだと思う。

scala/scala の git bisect

git bisect はバグの入った場所を特定するのに有用なテクニックだ。
特に scala/scala の場合は、bisect.sh はビルド済みのコンパイラを Scala CI Artifactory から利用することで時間を節約できる。

sbt-strict-update を用いた Semantic Versioning の施行

in
ThisBuild / scalaVersion := "2.13.3"
ThisBuild / libraryDependencySchemes += "org.typelevel" %% "cats-effect" % "early-semver"
 
lazy val root = (project in file("."))
  .settings(
    name := "demo",
    libraryDependencies ++= List(
      "org.http4s" %% "http4s-blaze-server" % "0.21.11",
      "org.typelevel" %% "cats-effect" % "3.0-8096649",
    ),
  )

もし Rob さんが上のビルドを compile しようとすると以下のように失敗するはずだ:

sbt:demo> compile
[warn] There may be incompatibilities among your library dependencies; run 'evicted' to see detailed eviction warnings.
[error] stack trace is suppressed; run last update for the full output
[error] (update) found version conflict(s) in library dependencies; some are suspected to be binary incompatible:
[error]
[error]   * org.typelevel:cats-effect_2.13:3.0-8096649 (early-semver) is selected over {2.2.0, 2.0.0, 2.0.0, 2.2.0}
[error]       +- demo:demo_2.13:0.1.0-SNAPSHOT                      (depends on 3.0-8096649)
[error]       +- org.http4s:http4s-core_2.13:0.21.11                (depends on 2.2.0)
[error]       +- io.chrisdavenport:vault_2.13:2.0.0                 (depends on 2.0.0)
[error]       +- io.chrisdavenport:unique_2.13:2.0.0                (depends on 2.0.0)
[error]       +- co.fs2:fs2-core_2.13:2.4.5                         (depends on 2.2.0)
[error] Total time: 0 s, completed Dec 13, 2020 11:53:31 PM

GitHub Actions からの sbt プラグインの自動公開

in
name: Release
on:
  push:
    tags:
      - '*'
jobs:
  build:
    runs-on: ubuntu-latest
    env:
      # define Java options for both official sbt and sbt-extras
      JAVA_OPTS: -Xms2048M -Xmx2048M -Xss6M -XX:ReservedCodeCacheSize=256M -Dfile.encoding=UTF-8
      JVM_OPTS:  -Xms2048M -Xmx2048M -Xss6M -XX:ReservedCodeCacheSize=256M -Dfile.encoding=UTF-8
    steps:
    - name: Checkout
      uses: actions/checkout@v2
    - name: Setup Scala
      uses: olafurpg/setup-scala@v10
      with:
        java-version: "adopt@1.8"
    - name: Coursier cache
      uses: coursier/cache-action@v5
    - name: Test
      run: |
        sbt test packagedArtifacts
    - name: Release
      env:
        BINTRAY_USER: ${{ secrets.BINTRAY_USER }}
        BINTRAY_PASS: ${{ secrets.BINTRAY_PASS }}
        PGP_PASSPHRASE: ${{ secrets.PGP_PASSPHRASE }}
        PGP_SECRET: ${{ secrets.PGP_SECRET }}
        CI_CLEAN: clean
        CI_RELEASE: publishSigned
        CI_SONATYPE_RELEASE: version
      run: |
        .github/decodekey.sh
        sbt ci-release

scopt 4

in

scopt 4.0.0 は以下のビルドマトリックスに対してクロスパブリッシュされている:

Scala JVM JS (1.x) JS (0.6.x) Native (0.4.0-M2) Native (0.3.x)
3.0.0-M2 n/a n/a n/a
3.0.0-M1 n/a n/a n/a
2.13.x n/a n/a
2.12.x n/a n/a
2.11.x

scopt 4 における関数型 DSL は以下のようになる:

import scopt.OParser
val builder = OParser.builder[Config]
val parser1 = {
  import builder._
  OParser.sequence(
    programName("scopt"),
    head("scopt", "4.x"),
    // option -f, --foo
    opt[Int]('f', "foo")
      .action((x, c) => c.copy(foo = x))
      .text("foo is an integer property"),
    // more options here...
  )
}
 
// OParser.parse returns Option[Config]
OParser.parse(parser1, args, Config()) match {
  case Some(config) =>
    // do something
  case _ =>
    // arguments are bad, error message will have been displayed
}

OptionParser 内でメソッドを呼ぶのではなく、関数型 DSL はまず特定の Config データ型に対するビルダーを作って、opt[A](...) など Oparser[A, Config] を返す関数を呼ぶ。

これらの OParser[A, Config] パーサーは OParser.sequence(...) を用いて合成できる。

最初は for 内包表記を使ってこの合成を表すことも考えていたが、その見た目に慣れて人にとっては分かりづらいと思ったので sequence 関数を作った。

Bintray を用いた sbt ビルドのリモートキャッシュ

in

今すぐリモートキャッシュを使ってみたいという人のために、sbt-bintray のスピンオフとして sbt-bintray-remote-cache というプラグインを作った。

使うには以下を project/plugins.sbt に追加する:

addSbtPlugin("org.foundweekends" % "sbt-bintray-remote-cache" % "0.6.1")

sbt 1.4.1

sbt 1.4.1 パッチリリースをアナウンスする。リリースノートの完全版はここにある - https://github.com/sbt/sbt/releases/tag/v1.4.1

アップグレード方法

公式 sbt ランチャーを SDKMAN か https://www.scala-sbt.org/download.html からダウンロードしてくる。このインストーラーには sbtn のバイナリが含まれている。

次に、使いたいビルドの project/build.properties ファイルに以下のように書く:

sbt.version=1.4.1

この機構によって使いたいビルドにだけ sbt 1.4.1 が使えるようになっている。

ScalaMatsuri 2020 におけるハッカソンの仮想化

in

本稿は ScalaMatsuri Day 2 アンカンファレンスで OSS ハッカソンを仮想化したことのレポートだ。誰かがアンカンファレンスのトピックとして提案したらしく、僕は朝会でファシリテーターとして申し出ただけなので事前準備は特に無し。元々は 4時間 (JST 正午 - 4pm、EDT 11pm - 3am) で枠をもらったが、うまく回ったのでコーヒーブレイクの後も数時間続いた。

アンカンファレンスをやるときにいつも強調してるのは「二本足の法則」で:

いつでも自分にとってその場からの「学び」や自分から場への「貢献」が無いなと感じた場合: 自分の二本足を使って別の場へ移動すること

オンラインのアンカンファレンスで、複数のセッションが行われているので別のトークを見るために抜けたり途中から参加することは自由であることを事前に伝えた。

Syndicate content