Runs tests, coverage, binary compatibility, formatting and Scaladoc on every push and pull request.
Replaces the handwritten ci.yml that each project used to carry.
Create .github/workflows/ci.yml:
name: CI
on:
push:
branches: [ master ]
pull_request:
jobs:
test:
uses: evolution-gaming/scala-github-actions/.github/workflows/ci.yml@<sha> # v6.2.0Nothing else is required if the project uses the defaults below.
Two things about that snippet are deliberate, both because SonarQube Cloud's quality gate rejects the alternatives and drops the security rating to C:
-
the workflow is pinned to a full commit SHA, with the tag in a trailing comment. The snippet writes it as
<sha>on purpose, so this README cannot go stale every timev6moves. Resolve the current value with:gh api repos/evolution-gaming/scala-github-actions/git/tags/$( gh api repos/evolution-gaming/scala-github-actions/git/ref/tags/v6 --jq .object.sha ) --jq .object.sha
-
there is no
secrets: inherit. It is not needed —GITHUB_TOKENis available to a called workflow automatically, and that is what the Coveralls upload uses. Only the optional Sonar scan needs a secret.
| input | default | notes |
|---|---|---|
scala_versions |
'["2.13.18", "3.3.8"]' |
JSON array; becomes the build matrix |
java_version |
'17' |
|
java_distribution |
'temurin' |
|
test_task |
auto | testFull on sbt 2, test on sbt 1, read from project/build.properties |
coverage |
true |
collect coverage and upload to Coveralls |
version_policy_check |
true |
requires sbt-version-policy |
scalafmt_check |
true |
|
doc_check |
true |
runs Compile/doc |
sonar |
false |
run a SonarQube Cloud scan, see below |
sonar_project_key |
<owner>_<repo> |
|
sonar_args |
'' |
extra -D arguments for the scanner |
Example for a project without sbt-version-policy and on a different Scala set:
jobs:
test:
uses: evolution-gaming/scala-github-actions/.github/workflows/ci.yml@<sha> # v6.2.0
with:
scala_versions: '["2.13.18", "3.3.7"]'
version_policy_check: falseTwo sbt 2 behaviours make a naive coverage setup report nothing while still passing:
- sbt 2's compile cache is not keyed on scoverage's instrumentation. If a plain compile runs first, the coverage build reuses those uninstrumented classes and the report comes out empty. The coverage build therefore runs before the formatting, binary-compatibility and scaladoc checks.
sbt/setup-sbtrestores~/.cache/sbtacross runs by default, which reintroduces the same problem on any run whose build files did not change. This workflow setsdisk-cache: falsewhenever coverage is enabled.
The workflow also fails if the produced Cobertura report has no valid lines, so a silently empty report is an error rather than a green build.
Binary compatibility, formatting and Scaladoc run as explicit sbt tasks, not via a project-local
check alias. An alias can be stubbed out (addCommandAlias("check", "show version")), which makes
the gate silently guarantee nothing.
The workflow checks out with fetch-depth: 0. Without tags sbt-dynver reports the version as
0.0.0, versionPolicyCheck then has no previous version to compare against, and the binary
compatibility check passes without checking anything.
Most repositories should not use the sonar input. Analysis is done server-side by SonarQube
Cloud's Automatic Analysis, which needs no token, no CI step and no repository configuration — that is
how kafka-journal and the other analysed repositories work. The sonar input exists for the
CI-based scanner, which is the mutually exclusive alternative.
If you do enable it, it scans once, on the first Scala version, importing scoverage's per-module
reports. Configuration is passed as scanner arguments, so no per-repo sonar-project.properties is
needed.
Three prerequisites, all outside this repo:
- A
SONAR_TOKENorganization secret. It does not exist yet, sosonar: truewill fail until it is added. - The project must already exist on SonarQube Cloud — the scanner reports to a project, it does not create one.
- Automatic Analysis must be turned off for that project. It and CI-based scanning are mutually exclusive, and Automatic Analysis wins, so the scan will be rejected while it is on.
The scanner also needs the token passed through, which the caller must do explicitly now that
secrets: inherit is gone:
secrets:
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}Note that the SonarQube Cloud GitHub App creates a check suite on every commit even in repositories it never analyses, which leaves a check permanently queued and reporting no result. Repositories not being analysed should have the app removed rather than left in that state.
To use Scala Release workflow have to set up project:
- add latest sbt-dynver plugin
- add Evolution's artifactory plugin sbt-artifactory-plugin
- defined command alias
checkwhich runs code quality checks, for example: scalafmt and scalafix, and binary compatibility check by sbt-version-policy:as very minimum "no-op" placeholder:addCommandAlias("fmt", "all scalafmtAll scalafmtSbt; scalafixEnable; scalafixAll") // optional: for development addCommandAlias("check", "all versionPolicyCheck Compile/doc scalafmtCheckAll scalafmtSbtCheck; scalafixEnable; scalafixAll --check") addCommandAlias("build", "all compile test") // optional: for development
addCommandAlias("check", "show version")
- direct
publishToto Evolution's artifactory (for publishing artifacts usingsbt-artifactory-plugin):publishTo := Some(Resolver.evolutionReleases)
- create
release.ymlfile with content:name: Publish Release on: push: tags: - 'v*' jobs: release: uses: evolution-gaming/scala-github-actions/.github/workflows/release.yml@v5 secrets: inherit
In project's repo:
- push tag as separate activity
- crate new version tag, like
git tag v1.2.3 -a -m "release v1.2.3" - push the tag,
git push origin tag v1.2.3
The above sequence will start Release workflow, which will:
- run SBT commands
+clean; +check; +all test packageto verify the build - run SBT command
+publishto publish packaged artifacts - if any of above steps will fail, the workflow will remove git tag - improve code and push fix, later tag again
- workflow will auto-generate release notes and will publish them
- go to
Codeand navigate toReleases - review release notes and amend, if required
The v4 version additionally allows overriding SBT commands used by the release job.
It is especially useful for projects which have mixed Scala versions in submodules and for which the +, +all
SBT features might not work properly:
jobs:
release:
uses: evolution-gaming/scala-github-actions/.github/workflows/release.yml@v4
secrets: inherit
with:
# override sbt commands so they don't use "+" because the project uses mixed Scala versions with sbt-projectmatrix
verify_sbt_command: 'clean; check; all test package'
publish_sbt_command: 'publish'Replaced by v3 because GitHub excluded SBT from ubuntu-latest (details).
To use Scala Release workflow have to set up project:
- add latest sbt-release plugin
- add Evolution's artifactory plugin sbt-artifactory-plugin
- defined command alias
checkwhich runs code quality checks, for example: scalafmt and scalafix, and binary compatibility check by sbt-version-policy:as very minimum "no-op" placeholder:addCommandAlias("fmt", "all scalafmtAll scalafmtSbt; scalafixEnable; scalafixAll") // optional: for development addCommandAlias("check", "all versionPolicyCheck Compile/doc scalafmtCheckAll scalafmtSbtCheck; scalafixEnable; scalafixAll --check") addCommandAlias("build", "all compile test") // optional: for development
addCommandAlias("check", "show version")
- direct
publishToto Evolution's artifactory (forsbt-releaseusingsbt-artifactory-plugin):publishTo := Some(Resolver.evolutionReleases)
- create
release.ymlfile with content:name: Publish Release on: release: types: [published] branches: [main] jobs: release: uses: evolution-gaming/scala-github-actions/.github/workflows/release.yml@v1 secrets: inherit
On GitHub:
- go to
Releasespage - press
Draft a new releasebutton - make sure that
version.sbtfile in root of project have correct version string, like1.2.3 - in
Choose a tagcreate a new tag (v1.2.3) - set
Release titleto the same string (v1.2.3) - press
Generate release notesand review them - press
Publish releasebutton - navigate to
Actions- there it is possible to follow build's progress
The above sequence will start Release workflow, which will:
- validate consistency of git tag and version
- run SBT commands
clean; +all check test packageto make sure that code quality is good - run SBT command
+publishto publish packaged artifacts - if any of above steps will fail, the workflow will remove git tag and GitHub will mark release notes as
draftand it will be possible to adjust code on main branch and attempt publishing again by navigating to drafted release and pressingPublish releasebutton again
When release is published, make sure to amend version.sbt file with next version string.
Minimal configuration requires usage of plugin like:
addSbtPlugin("org.scalameta" % "sbt-scalafmt" % "<latest version>")Minimal configuration requires usage of plugin like:
addSbtPlugin("ch.epfl.scala" % "sbt-scalafix" % "<latest version>")Requires usage of sbt-version-policy plugin like:
addSbtPlugin("ch.epfl.scala" % "sbt-version-policy" % "<latest version>")Evolution's plugin with very strict settings for Scala 2.12 and 2.13 projects
addSbtPlugin("com.evolution" % "sbt-scalac-opts-plugin" % "<latest version>")