Use Scala CLI in GitHub Actions
Preparing simple aplication
scala-cli
lets you run, test, and package Scala code in various environments, including GitHub CI.
To use Scala CLI features in a simple way you can use the GitHub Actions scala-cli-setup that installs everything necessary to run your Scala CLI application and more.
For example, here's a simple ls
application printing the files in a given directory:
//> using scala "2.13"
//> using lib "com.lihaoyi::os-lib:0.7.8"
@main def hello(args: String*) =
val path = args.headOption match
case Some(p) => os.Path(p, os.pwd)
case _ => os.pwd
if (os.isDir(path)) println(os.list(path).mkString(","))
else System.err.println("Expected directory path as an input")
and some tests for ls
application:
//> using lib "org.scalameta::munit::0.7.27"
import scala.util.Properties
class TestsLs extends munit.FunSuite {
test("ls") {
// prepare test directory
val tempDir = os.temp.dir()
// create files
val expectedFiles = Seq("Ls", "Hello").map(tempDir / _)
expectedFiles.foreach(os.write(_, "Hello"))
// check
val scalaCLILauncher = if(Properties.isWin) "scala-cli.bat" else "scala-cli"
val foundFiles =
os.proc(scalaCLILauncher, "Ls.scala", "--", tempDir).call().out.trim()
expectedFiles.map(_.toString).foreach { file =>
assert(foundFiles.contains(file))
}
}
}
Run tests in Github CI
The following configuration of ci.yml
contains a definition of job that runs tests using scala-cli
for every platform defined in matrix.OS
.
jobs:
build:
runs-on: ${{ matrix.OS }}
strategy:
matrix:
OS: ["ubuntu-latest", "macos-latest", "windows-latest"]
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0
- uses: coursier/cache-action@v6.3
- uses: VirtusLab/scala-cli-setup@v0.1
- run: scala-cli test .
Check your Scala code format
To check the code style of your sources, you can use Scalafmt.
To check your code format in GitHub CI by adding new job format
:
format:
runs-on: "ubuntu-latest"
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0
- uses: coursier/cache-action@v6.3
- uses: VirtusLab/scala-cli-setup@v0.1
- name: Scalafmt check
run: |
scala-cli fmt --check . || (
echo "To format code run"
echo " scala-cli fmt ."
exit 1
)
If the scala-cli fmt --check .
command fails, it can be easily fixed by running scala-cli fmt .
, which correctly formats your code.
Package your application
Scala CLI allows to build native executable applications using GraalVM, which can be uploaded as GitHub release artifacts.
- name: Package app
run: scala-cli .github/scripts/package.sc
Given this simple Scala Script package.sc
to package application to every platform:
//> using scala "3.1.2"
//> using lib "com.lihaoyi::os-lib:0.8.0"
import scala.util.Properties
val platformSuffix: String = {
val os =
if (Properties.isWin) "pc-win32"
else if (Properties.isLinux) "pc-linux"
else if (Properties.isMac) "apple-darwin"
else sys.error(s"Unrecognized OS: ${sys.props("os.name")}")
os
}
val artifactsPath = os.Path("artifacts", os.pwd)
val destPath =
if (Properties.isWin) artifactsPath / s"ls-$platformSuffix.exe"
else artifactsPath / s"ls-$platformSuffix"
val scalaCLILauncher =
if (Properties.isWin) "scala-cli.bat" else "scala-cli"
os.makeDir(artifactsPath)
os.proc(scalaCLILauncher, "package", ".", "-o", destPath, "--native-image")
.call(cwd = os.pwd)
.out
.text()
.trim
Distribute generated native application
To upload generated native executable applications to artifacts you can use upload-artifact GitHub Actions.
- uses: actions/upload-artifact@v3
with:
name: launchers
path: artifacts
if-no-files-found: error
retention-days: 2
When release CI pass, you should be able to download artifacts that contain native launchers of your applications.
Here you can find examples of a CI that contains generated launcher based on this cookbook.
You can find the code of this cookbook here.