From b2a7d1a85877c838457979bc72ed0b21cf1cef1c Mon Sep 17 00:00:00 2001 From: Thijs Broersen Date: Thu, 17 Oct 2024 22:02:26 +0200 Subject: [PATCH 1/5] refactor: migrate to zio-json --- .github/workflows/ci.yml | 379 +++++++++--------- README.md | 14 +- docs/index.md | 14 +- project/Versions.scala | 8 +- project/build.properties | 2 +- project/plugins.sbt | 17 +- zio-sbt-ci/build.sbt | 5 +- .../main/scala/zio/sbt/ZioSbtCiPlugin.scala | 280 ++++++------- zio-sbt-ecosystem/build.sbt | 14 +- .../scala/zio/sbt/ScalaCompilerSettings.scala | 5 +- .../src/main/scala/zio/sbt/Versions.scala | 8 +- .../.github/workflows/ci.yml | 2 +- zio-sbt-githubactions/build.sbt | 5 +- .../zio/sbt/githubactions/ScalaWorkflow.scala | 81 ++-- .../scala/zio/sbt/githubactions/model.scala | 332 +++++++-------- .../scala/zio/sbt/githubactions/package.scala | 5 + zio-sbt-website/build.sbt | 7 +- 17 files changed, 609 insertions(+), 569 deletions(-) create mode 100644 zio-sbt-githubactions/src/main/scala/zio/sbt/githubactions/package.scala diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b177da0f..3c69b756 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -5,16 +5,15 @@ name: CI env: JDK_JAVA_OPTIONS: -XX:+PrintCommandLineFlags 'on': - workflow_dispatch: {} release: types: - - published - push: - branches: - - main + - published pull_request: branches-ignore: - - gh-pages + - gh-pages + push: + branches: + - main concurrency: group: ${{ github.workflow }}-${{ github.ref == format('refs/heads/{0}', github.event.repository.default_branch) && github.run_id || github.ref }} cancel-in-progress: true @@ -24,234 +23,234 @@ jobs: runs-on: ubuntu-latest continue-on-error: true steps: - - name: Git Checkout - uses: actions/checkout@v4 - with: - fetch-depth: '0' - - name: Install libuv - run: sudo apt-get update && sudo apt-get install -y libuv1-dev - - name: Setup Scala - uses: actions/setup-java@v4 - with: - distribution: corretto - java-version: '17' - check-latest: true - - name: Cache Dependencies - uses: coursier/cache-action@v6 - - name: Check all code compiles - run: sbt +Test/compile - - name: Check artifacts build process - run: sbt +publishLocal - - name: Check website build process - run: sbt docs/clean; sbt docs/buildWebsite + - name: Git Checkout + uses: actions/checkout@v4 + with: + fetch-depth: '0' + - name: Install libuv + run: sudo apt-get update && sudo apt-get install -y libuv1-dev + - name: Setup Scala + uses: actions/setup-java@v4 + with: + distribution: corretto + java-version: '17' + check-latest: 'true' + - name: Cache Dependencies + uses: coursier/cache-action@v6 + - name: Check all code compiles + run: sbt +Test/compile + - name: Check artifacts build process + run: sbt +publishLocal + - name: Check website build process + run: sbt docs/clean; sbt docs/buildWebsite lint: name: Lint runs-on: ubuntu-latest continue-on-error: false steps: - - name: Git Checkout - uses: actions/checkout@v4 - with: - fetch-depth: '0' - - name: Install libuv - run: sudo apt-get update && sudo apt-get install -y libuv1-dev - - name: Setup Scala - uses: actions/setup-java@v4 - with: - distribution: corretto - java-version: '17' - check-latest: true - - name: Cache Dependencies - uses: coursier/cache-action@v6 - - name: Check if the site workflow is up to date - run: sbt ciCheckGithubWorkflow - - name: Lint - run: sbt lint + - name: Git Checkout + uses: actions/checkout@v4 + with: + fetch-depth: '0' + - name: Install libuv + run: sudo apt-get update && sudo apt-get install -y libuv1-dev + - name: Setup Scala + uses: actions/setup-java@v4 + with: + distribution: corretto + java-version: '17' + check-latest: 'true' + - name: Cache Dependencies + uses: coursier/cache-action@v6 + - name: Check if the site workflow is up to date + run: sbt ciCheckGithubWorkflow + - name: Lint + run: sbt lint test: name: Test runs-on: ubuntu-latest continue-on-error: false strategy: - fail-fast: false matrix: java: - - '11' - - '17' - - '21' + - '11' + - '17' + - '21' + fail-fast: false steps: - - name: Install libuv - run: sudo apt-get update && sudo apt-get install -y libuv1-dev - - name: Setup Scala - uses: actions/setup-java@v4 - with: - distribution: corretto - java-version: ${{ matrix.java }} - check-latest: true - - name: Cache Dependencies - uses: coursier/cache-action@v6 - - name: Git Checkout - uses: actions/checkout@v4 - with: - fetch-depth: '0' - - name: Test - run: sbt +test + - name: Install libuv + run: sudo apt-get update && sudo apt-get install -y libuv1-dev + - name: Setup Scala + uses: actions/setup-java@v4 + with: + distribution: corretto + java-version: ${{ matrix.java }} + check-latest: 'true' + - name: Cache Dependencies + uses: coursier/cache-action@v6 + - name: Git Checkout + uses: actions/checkout@v4 + with: + fetch-depth: '0' + - name: Test + run: sbt +test update-readme: name: Update README runs-on: ubuntu-latest continue-on-error: false if: ${{ github.event_name == 'push' }} steps: - - name: Git Checkout - uses: actions/checkout@v4 - with: - fetch-depth: '0' - - name: Install libuv - run: sudo apt-get update && sudo apt-get install -y libuv1-dev - - name: Setup Scala - uses: actions/setup-java@v4 - with: - distribution: corretto - java-version: '17' - check-latest: true - - name: Cache Dependencies - uses: coursier/cache-action@v6 - - name: Generate Readme - run: sbt docs/generateReadme - - name: Commit Changes - run: | - git config --local user.email "zio-assistant[bot]@users.noreply.github.com" - git config --local user.name "ZIO Assistant" - git add README.md - git commit -m "Update README.md" || echo "No changes to commit" - - name: Generate Token - id: generate-token - uses: zio/generate-github-app-token@v1.0.0 - with: - app_id: ${{ secrets.APP_ID }} - app_private_key: ${{ secrets.APP_PRIVATE_KEY }} - - name: Create Pull Request - id: cpr - uses: peter-evans/create-pull-request@v6 - with: - body: |- - Autogenerated changes after running the `sbt docs/generateReadme` command of the [zio-sbt-website](https://zio.dev/zio-sbt) plugin. + - name: Git Checkout + uses: actions/checkout@v4 + with: + fetch-depth: '0' + - name: Install libuv + run: sudo apt-get update && sudo apt-get install -y libuv1-dev + - name: Setup Scala + uses: actions/setup-java@v4 + with: + distribution: corretto + java-version: '17' + check-latest: 'true' + - name: Cache Dependencies + uses: coursier/cache-action@v6 + - name: Generate Readme + run: sbt docs/generateReadme + - name: Commit Changes + run: | + git config --local user.email "zio-assistant[bot]@users.noreply.github.com" + git config --local user.name "ZIO Assistant" + git add README.md + git commit -m "Update README.md" || echo "No changes to commit" + - name: Generate Token + id: generate-token + uses: zio/generate-github-app-token@v1.0.0 + with: + app_id: ${{ secrets.APP_ID }} + app_private_key: ${{ secrets.APP_PRIVATE_KEY }} + - name: Create Pull Request + id: cpr + uses: peter-evans/create-pull-request@v6 + with: + body: |- + Autogenerated changes after running the `sbt docs/generateReadme` command of the [zio-sbt-website](https://zio.dev/zio-sbt) plugin. - I will automatically update the README.md file whenever there is new change for README.md, e.g. - - After each release, I will update the version in the installation section. - - After any changes to the "docs/index.md" file, I will update the README.md file accordingly. - branch: zio-sbt-website/update-readme - commit-message: Update README.md - token: ${{ steps.generate-token.outputs.token }} - delete-branch: true - title: Update README.md - - name: Approve PR - if: ${{ steps.cpr.outputs.pull-request-number }} - run: gh pr review "$PR_URL" --approve - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - PR_URL: ${{ steps.cpr.outputs.pull-request-url }} - - name: Enable Auto-Merge - if: ${{ steps.cpr.outputs.pull-request-number }} - run: gh pr merge --auto --squash "$PR_URL" || gh pr merge --squash "$PR_URL" - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - PR_URL: ${{ steps.cpr.outputs.pull-request-url }} + I will automatically update the README.md file whenever there is new change for README.md, e.g. + - After each release, I will update the version in the installation section. + - After any changes to the "docs/index.md" file, I will update the README.md file accordingly. + branch: zio-sbt-website/update-readme + commit-message: Update README.md + token: ${{ steps.generate-token.outputs.token }} + delete-branch: 'true' + title: Update README.md + - name: Approve PR + if: ${{ steps.cpr.outputs.pull-request-number }} + run: gh pr review "$PR_URL" --approve + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + PR_URL: ${{ steps.cpr.outputs.pull-request-url }} + - name: Enable Auto-Merge + if: ${{ steps.cpr.outputs.pull-request-number }} + run: gh pr merge --auto --squash "$PR_URL" || gh pr merge --squash "$PR_URL" + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + PR_URL: ${{ steps.cpr.outputs.pull-request-url }} ci: name: ci runs-on: ubuntu-latest continue-on-error: false needs: - - lint - - test - - build + - lint + - test + - build steps: - - name: Report Successful CI - run: echo "ci passed" + - name: Report Successful CI + run: echo "ci passed" release: name: Release runs-on: ubuntu-latest continue-on-error: false needs: - - ci + - ci if: ${{ github.event_name != 'pull_request' }} steps: - - name: Git Checkout - uses: actions/checkout@v4 - with: - fetch-depth: '0' - - name: Install libuv - run: sudo apt-get update && sudo apt-get install -y libuv1-dev - - name: Setup Scala - uses: actions/setup-java@v4 - with: - distribution: corretto - java-version: '17' - check-latest: true - - name: Cache Dependencies - uses: coursier/cache-action@v6 - - name: Release - run: sbt ci-release - env: - PGP_PASSPHRASE: ${{ secrets.PGP_PASSPHRASE }} - PGP_SECRET: ${{ secrets.PGP_SECRET }} - SONATYPE_PASSWORD: ${{ secrets.SONATYPE_PASSWORD }} - SONATYPE_USERNAME: ${{ secrets.SONATYPE_USERNAME }} + - name: Git Checkout + uses: actions/checkout@v4 + with: + fetch-depth: '0' + - name: Install libuv + run: sudo apt-get update && sudo apt-get install -y libuv1-dev + - name: Setup Scala + uses: actions/setup-java@v4 + with: + distribution: corretto + java-version: '17' + check-latest: 'true' + - name: Cache Dependencies + uses: coursier/cache-action@v6 + - name: Release + run: sbt ci-release + env: + PGP_PASSPHRASE: ${{ secrets.PGP_PASSPHRASE }} + PGP_SECRET: ${{ secrets.PGP_SECRET }} + SONATYPE_PASSWORD: ${{ secrets.SONATYPE_PASSWORD }} + SONATYPE_USERNAME: ${{ secrets.SONATYPE_USERNAME }} release-docs: name: Release Docs runs-on: ubuntu-latest continue-on-error: false needs: - - release + - release if: ${{ ((github.event_name == 'release') && (github.event.action == 'published')) || (github.event_name == 'workflow_dispatch') }} steps: - - name: Git Checkout - uses: actions/checkout@v4 - with: - fetch-depth: '0' - - name: Install libuv - run: sudo apt-get update && sudo apt-get install -y libuv1-dev - - name: Setup Scala - uses: actions/setup-java@v4 - with: - distribution: corretto - java-version: '17' - check-latest: true - - name: Cache Dependencies - uses: coursier/cache-action@v6 - - name: Setup NodeJs - uses: actions/setup-node@v4 - with: - node-version: 16.x - registry-url: https://registry.npmjs.org - - name: Publish Docs to NPM Registry - run: sbt docs/publishToNpm - env: - NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} + - name: Git Checkout + uses: actions/checkout@v4 + with: + fetch-depth: '0' + - name: Install libuv + run: sudo apt-get update && sudo apt-get install -y libuv1-dev + - name: Setup Scala + uses: actions/setup-java@v4 + with: + distribution: corretto + java-version: '17' + check-latest: 'true' + - name: Cache Dependencies + uses: coursier/cache-action@v6 + - name: Setup NodeJs + uses: actions/setup-node@v4 + with: + node-version: 16.x + registry-url: https://registry.npmjs.org + - name: Publish Docs to NPM Registry + run: sbt docs/publishToNpm + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} notify-docs-release: name: Notify Docs Release runs-on: ubuntu-latest continue-on-error: false needs: - - release-docs + - release-docs if: ${{ (github.event_name == 'release') && (github.event.action == 'published') }} steps: - - name: Git Checkout - uses: actions/checkout@v4 - with: - fetch-depth: '0' - - name: notify the main repo about the new release of docs package - run: | - PACKAGE_NAME=$(cat docs/package.json | grep '"name"' | awk -F'"' '{print $4}') - PACKAGE_VERSION=$(npm view $PACKAGE_NAME version) - curl -L \ - -X POST \ - -H "Accept: application/vnd.github+json" \ - -H "Authorization: token ${{ secrets.PAT_TOKEN }}"\ - https://api.github.com/repos/zio/zio/dispatches \ - -d '{ - "event_type":"update-docs", - "client_payload":{ - "package_name":"'"${PACKAGE_NAME}"'", - "package_version": "'"${PACKAGE_VERSION}"'" - } - }' + - name: Git Checkout + uses: actions/checkout@v4 + with: + fetch-depth: '0' + - name: notify the main repo about the new release of docs package + run: | + PACKAGE_NAME=$(cat docs/package.json | grep '"name"' | awk -F'"' '{print $4}') + PACKAGE_VERSION=$(npm view $PACKAGE_NAME version) + curl -L \ + -X POST \ + -H "Accept: application/vnd.github+json" \ + -H "Authorization: token ${{ secrets.PAT_TOKEN }}"\ + https://api.github.com/repos/zio/zio/dispatches \ + -d '{ + "event_type":"update-docs", + "client_payload":{ + "package_name":"'"${PACKAGE_NAME}"'", + "package_version": "'"${PACKAGE_VERSION}"'" + } + }' diff --git a/README.md b/README.md index a619532d..7e49c0e9 100644 --- a/README.md +++ b/README.md @@ -168,12 +168,12 @@ In some cases, we may have multiple submodules in our project and we want to tes The `ciTargetScalaVersions` setting key is used to define a mapping of project names to the Scala versions that should be used for testing phase of continuous integration (CI). -For example, suppose we have a project with the name "submoduleA" and we want to test it against Scala `2.12.19`, and for the "submoduleB" we want to test it against Scala `2.12.19` and `2.13.13` and `3.3.3`, We can define the `ciTargetScalaVersions` setting as follows: +For example, suppose we have a project with the name "submoduleA" and we want to test it against Scala `2.12.20`, and for the "submoduleB" we want to test it against Scala `2.12.20` and `2.13.15` and `3.3.4`, We can define the `ciTargetScalaVersions` setting as follows: ```scala ThisBuild / ciTargetScalaVersions := Map( - "submoduleA" -> Seq("2.12.19"), - "submoduleB" -> Seq("2.12.19", "2.13.13", "3.3.3") + "submoduleA" -> Seq("2.12.20"), + "submoduleB" -> Seq("2.12.20", "2.13.15", "3.3.4") ) ``` @@ -206,10 +206,10 @@ test: matrix: java: ['11', '17', '21'] scala-project: - - ++2.12.19 submoduleA - - ++2.12.19 submoduleB - - ++2.13.13 submoduleB - - ++3.3.3 submoduleB + - ++2.12.20 submoduleA + - ++2.12.20 submoduleB + - ++2.13.15 submoduleB + - ++3.3.4 submoduleB steps: - name: Install libuv run: sudo apt-get update && sudo apt-get install -y libuv1-dev diff --git a/docs/index.md b/docs/index.md index 31d06d14..5489d349 100644 --- a/docs/index.md +++ b/docs/index.md @@ -167,12 +167,12 @@ In some cases, we may have multiple submodules in our project and we want to tes The `ciTargetScalaVersions` setting key is used to define a mapping of project names to the Scala versions that should be used for testing phase of continuous integration (CI). -For example, suppose we have a project with the name "submoduleA" and we want to test it against Scala `2.12.19`, and for the "submoduleB" we want to test it against Scala `2.12.19` and `2.13.13` and `3.3.3`, We can define the `ciTargetScalaVersions` setting as follows: +For example, suppose we have a project with the name "submoduleA" and we want to test it against Scala `2.12.20`, and for the "submoduleB" we want to test it against Scala `2.12.20` and `2.13.15` and `3.3.4`, We can define the `ciTargetScalaVersions` setting as follows: ```scala ThisBuild / ciTargetScalaVersions := Map( - "submoduleA" -> Seq("2.12.19"), - "submoduleB" -> Seq("2.12.19", "2.13.13", "3.3.3") + "submoduleA" -> Seq("2.12.20"), + "submoduleB" -> Seq("2.12.20", "2.13.15", "3.3.4") ) ``` @@ -205,10 +205,10 @@ test: matrix: java: ['11', '17', '21'] scala-project: - - ++2.12.19 submoduleA - - ++2.12.19 submoduleB - - ++2.13.13 submoduleB - - ++3.3.3 submoduleB + - ++2.12.20 submoduleA + - ++2.12.20 submoduleB + - ++2.13.15 submoduleB + - ++3.3.4 submoduleB steps: - name: Install libuv run: sudo apt-get update && sudo apt-get install -y libuv1-dev diff --git a/project/Versions.scala b/project/Versions.scala index 03da9412..7a8351bf 100644 --- a/project/Versions.scala +++ b/project/Versions.scala @@ -1,6 +1,6 @@ object Versions { - val Scala212 = "2.12.19" - val Scala213 = "2.13.13" - val Scala3 = "3.3.3" - val zio = "2.0.21" + val Scala212 = "2.12.20" + val Scala213 = "2.13.15" + val Scala3 = "3.3.4" + val zio = "2.1.9" } diff --git a/project/build.properties b/project/build.properties index ee4c672c..23f7d979 100644 --- a/project/build.properties +++ b/project/build.properties @@ -1 +1 @@ -sbt.version=1.10.1 +sbt.version = 1.10.2 diff --git a/project/plugins.sbt b/project/plugins.sbt index b9292898..8260121f 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -1,9 +1,9 @@ // Build Server Plugins -addSbtPlugin("ch.epfl.scala" % "sbt-bloop" % "1.6.0") +addSbtPlugin("ch.epfl.scala" % "sbt-bloop" % "2.0.3") // Linting Plugins addSbtPlugin("org.scalameta" % "sbt-scalafmt" % "2.5.2") -addSbtPlugin("ch.epfl.scala" % "sbt-scalafix" % "0.12.1") +addSbtPlugin("ch.epfl.scala" % "sbt-scalafix" % "0.13.0") addSbtPlugin("com.github.cb372" % "sbt-explicit-dependencies" % "0.3.1") // Versioning and Release Plugins @@ -11,20 +11,21 @@ addSbtPlugin("com.eed3si9n" % "sbt-buildinfo" % "0.12.0") addSbtPlugin("com.github.sbt" % "sbt-ci-release" % "1.5.12") // Docs Plugins -addSbtPlugin("org.scalameta" % "sbt-mdoc" % "2.5.4") +addSbtPlugin("org.scalameta" % "sbt-mdoc" % "2.6.1") addSbtPlugin("com.github.sbt" % "sbt-unidoc" % "0.5.0") addSbtPlugin("de.heikoseeberger" % "sbt-header" % "5.10.0") // Cross-Compiler Plugins -addSbtPlugin("org.scala-js" % "sbt-scalajs" % "1.16.0") +addSbtPlugin("org.scala-js" % "sbt-scalajs" % "1.17.0") addSbtPlugin("org.portable-scala" % "sbt-scalajs-crossproject" % "1.3.2") -addSbtPlugin("org.scala-native" % "sbt-scala-native" % "0.5.4") +addSbtPlugin("org.scala-native" % "sbt-scala-native" % "0.5.5") addSbtPlugin("org.portable-scala" % "sbt-scala-native-crossproject" % "1.3.2") addSbtPlugin("org.portable-scala" % "sbt-platform-deps" % "1.0.2") // Benchmarking Plugins addSbtPlugin("pl.project13.scala" % "sbt-jmh" % "0.4.7") -libraryDependencies += "org.snakeyaml" % "snakeyaml-engine" % "2.7" -libraryDependencies += "dev.zio" %% "zio" % "2.1.8" -libraryDependencies += "io.circe" %% "circe-yaml" % "0.16.0" +libraryDependencies += "org.snakeyaml" % "snakeyaml-engine" % "2.8" +libraryDependencies += "dev.zio" %% "zio" % "2.1.9" +libraryDependencies += "dev.zio" %% "zio-json" % "0.7.3" +libraryDependencies += "dev.zio" %% "zio-json-yaml" % "0.7.3" diff --git a/zio-sbt-ci/build.sbt b/zio-sbt-ci/build.sbt index b7d36a60..938d170c 100644 --- a/zio-sbt-ci/build.sbt +++ b/zio-sbt-ci/build.sbt @@ -1,2 +1,3 @@ -libraryDependencies += "dev.zio" %% "zio" % "2.1.8" -libraryDependencies += "io.circe" %% "circe-yaml" % "0.16.0" +libraryDependencies += "dev.zio" %% "zio" % "2.1.9" +libraryDependencies += "dev.zio" %% "zio-json" % "0.7.3" +libraryDependencies += "dev.zio" %% "zio-json-yaml" % "0.7.3" diff --git a/zio-sbt-ci/src/main/scala/zio/sbt/ZioSbtCiPlugin.scala b/zio-sbt-ci/src/main/scala/zio/sbt/ZioSbtCiPlugin.scala index 70371ac6..b6d29217 100644 --- a/zio-sbt-ci/src/main/scala/zio/sbt/ZioSbtCiPlugin.scala +++ b/zio-sbt-ci/src/main/scala/zio/sbt/ZioSbtCiPlugin.scala @@ -15,14 +15,14 @@ */ package zio.sbt +import scala.collection.immutable.ListMap import scala.language.experimental.macros import scala.sys.process._ -import io.circe._ -import io.circe.syntax._ -import io.circe.yaml.Printer.{LineBreak, YamlVersion} import sbt.{Def, io => _, _} +import zio.json._ +import zio.json.yaml._ import zio.sbt.githubactions.Step.SingleStep import zio.sbt.githubactions.{Job, Step, _} @@ -100,8 +100,7 @@ object ZioSbtCiPlugin extends AutoPlugin { val checkWebsiteBuildProcess = ciCheckWebsiteBuildProcess.value Seq( - Job( - id = "build", + "build" -> JobValue( name = "Build", continueOnError = true, steps = { @@ -111,7 +110,9 @@ object ZioSbtCiPlugin extends AutoPlugin { SetupLibuv, SetupJava(javaVersion), CacheDependencies - ) ++ checkAllCodeCompiles ++ checkArtifactBuildProcess ++ checkWebsiteBuildProcess + ) ++ checkAllCodeCompiles.flatMap(_.flatten) ++ checkArtifactBuildProcess.flatMap( + _.flatten + ) ++ checkWebsiteBuildProcess.flatMap(_.flatten) } ) ) @@ -126,11 +127,12 @@ object ZioSbtCiPlugin extends AutoPlugin { val lint = Lint.value Seq( - Job( - id = "lint", + "lint" -> JobValue( name = "Lint", steps = (if (swapSizeGB > 0) Seq(setSwapSpace) else Seq.empty) ++ - Seq(checkout, SetupLibuv, SetupJava(javaVersion), CacheDependencies) ++ checkGithubWorkflow ++ Seq(lint) + Seq(checkout, SetupLibuv, SetupJava(javaVersion), CacheDependencies) ++ checkGithubWorkflow.flatMap( + _.flatten + ) ++ Seq(lint) ) ) } @@ -154,8 +156,7 @@ object ZioSbtCiPlugin extends AutoPlugin { versions.contains(scalaVersion) }.map(e => e._1 + "/test").mkString(" ")}" - Job( - id = "test", + "test" -> JobValue( name = "Test", strategy = Some( Strategy( @@ -177,7 +178,7 @@ object ZioSbtCiPlugin extends AutoPlugin { scalaVersionMatrix.values.toSeq.flatten.distinct.map { scalaVersion: String => Step.SingleStep( name = "Test", - condition = Some(Condition.Expression(s"matrix.scala == '$scalaVersion'")), + `if` = Some(Condition.Expression(s"matrix.scala == '$scalaVersion'")), run = Some( prefixJobs + "sbt ++${{ matrix.scala }}" + makeTests( scalaVersion @@ -200,7 +201,7 @@ object ZioSbtCiPlugin extends AutoPlugin { Seq( Step.SingleStep( name = "Test", - condition = Some( + `if` = Some( Condition.Expression(s"matrix.java == '$javaPlatform'") && Condition.Expression( s"matrix.scala == '$scalaVersion'" ) @@ -217,8 +218,7 @@ object ZioSbtCiPlugin extends AutoPlugin { } val FlattenTests = - Job( - id = "test", + "test" -> JobValue( name = "Test", strategy = Some( Strategy( @@ -252,46 +252,45 @@ object ZioSbtCiPlugin extends AutoPlugin { SetupLibuv, SetupJava("${{ matrix.java }}"), CacheDependencies, - checkout, + checkout + ) ++ ( if (javaPlatformMatrix.values.toSet.isEmpty) { - Step.SingleStep( - name = "Test", - run = Some(prefixJobs + "sbt ${{ matrix.scala-project }}/test") + Seq( + Step.SingleStep( + name = "Test", + run = Some(prefixJobs + "sbt ${{ matrix.scala-project }}/test") + ) ) } else { - Step.StepSequence( - Seq( - Step.SingleStep( - name = "Java 11 Tests", - condition = Some(Condition.Expression("matrix.java == '11'")), - run = Some( - prefixJobs + "sbt ${{ matrix.scala-project-java11 }}/test" - ) - ), - Step.SingleStep( - name = "Java 17 Tests", - condition = Some(Condition.Expression("matrix.java == '17'")), - run = Some( - prefixJobs + "sbt ${{ matrix.scala-project-java17 }}/test" - ) - ), - Step.SingleStep( - name = "Java 21 Tests", - condition = Some(Condition.Expression("matrix.java == '21'")), - run = Some( - prefixJobs + "sbt ${{ matrix.scala-project-java21 }}/test" - ) + Seq( + Step.SingleStep( + name = "Java 11 Tests", + `if` = Some(Condition.Expression("matrix.java == '11'")), + run = Some( + prefixJobs + "sbt ${{ matrix.scala-project-java11 }}/test" + ) + ), + Step.SingleStep( + name = "Java 17 Tests", + `if` = Some(Condition.Expression("matrix.java == '17'")), + run = Some( + prefixJobs + "sbt ${{ matrix.scala-project-java17 }}/test" + ) + ), + Step.SingleStep( + name = "Java 21 Tests", + `if` = Some(Condition.Expression("matrix.java == '21'")), + run = Some( + prefixJobs + "sbt ${{ matrix.scala-project-java21 }}/test" ) ) ) - } ) ) val DefaultTestStrategy = - Job( - id = "test", + "test" -> JobValue( name = "Test", strategy = Some( Strategy( @@ -323,10 +322,9 @@ object ZioSbtCiPlugin extends AutoPlugin { val pullRequestApprovalJobs = ciPullRequestApprovalJobs.value Seq( - Job( - id = "ci", + "ci" -> JobValue( name = "ci", - need = pullRequestApprovalJobs, + needs = Some(pullRequestApprovalJobs), steps = Seq( SingleStep( name = "Report Successful CI", @@ -346,10 +344,9 @@ object ZioSbtCiPlugin extends AutoPlugin { val generateReadme = GenerateReadme.value Seq( - Job( - id = "update-readme", + "update-readme" -> JobValue( name = "Update README", - condition = updateReadmeCondition orElse Some(Condition.Expression("github.event_name == 'push'")), + `if` = updateReadmeCondition orElse Some(Condition.Expression("github.event_name == 'push'")), steps = (if (swapSizeGB > 0) Seq(setSwapSpace) else Seq.empty) ++ Seq( checkout, @@ -369,44 +366,52 @@ object ZioSbtCiPlugin extends AutoPlugin { name = "Generate Token", id = Some("generate-token"), uses = Some(ActionRef(V("zio/generate-github-app-token"))), - parameters = Map( - "app_id" -> "${{ secrets.APP_ID }}".asJson, - "app_private_key" -> "${{ secrets.APP_PRIVATE_KEY }}".asJson + `with` = Some( + Map( + "app_id" -> "${{ secrets.APP_ID }}", + "app_private_key" -> "${{ secrets.APP_PRIVATE_KEY }}" + ) ) ), Step.SingleStep( name = "Create Pull Request", id = Some("cpr"), uses = Some(ActionRef(V("peter-evans/create-pull-request"))), - parameters = Map( - "title" -> "Update README.md".asJson, - "commit-message" -> "Update README.md".asJson, - "branch" -> "zio-sbt-website/update-readme".asJson, - "delete-branch" -> true.asJson, - "body" -> - """|Autogenerated changes after running the `sbt docs/generateReadme` command of the [zio-sbt-website](https://zio.dev/zio-sbt) plugin. - | - |I will automatically update the README.md file whenever there is new change for README.md, e.g. - | - After each release, I will update the version in the installation section. - | - After any changes to the "docs/index.md" file, I will update the README.md file accordingly.""".stripMargin.asJson, - "token" -> "${{ steps.generate-token.outputs.token }}".asJson + `with` = Some( + Map( + "title" -> "Update README.md", + "commit-message" -> "Update README.md", + "branch" -> "zio-sbt-website/update-readme", + "delete-branch" -> "true", + "body" -> + """|Autogenerated changes after running the `sbt docs/generateReadme` command of the [zio-sbt-website](https://zio.dev/zio-sbt) plugin. + | + |I will automatically update the README.md file whenever there is new change for README.md, e.g. + | - After each release, I will update the version in the installation section. + | - After any changes to the "docs/index.md" file, I will update the README.md file accordingly.""".stripMargin, + "token" -> "${{ steps.generate-token.outputs.token }}" + ) ) ), Step.SingleStep( name = "Approve PR", - condition = Some(Condition.Expression("steps.cpr.outputs.pull-request-number")), - env = Map( - "GITHUB_TOKEN" -> "${{ secrets.GITHUB_TOKEN }}", - "PR_URL" -> "${{ steps.cpr.outputs.pull-request-url }}" + `if` = Some(Condition.Expression("steps.cpr.outputs.pull-request-number")), + env = Some( + Map( + "GITHUB_TOKEN" -> "${{ secrets.GITHUB_TOKEN }}", + "PR_URL" -> "${{ steps.cpr.outputs.pull-request-url }}" + ) ), run = Some("gh pr review \"$PR_URL\" --approve") ), Step.SingleStep( name = "Enable Auto-Merge", - condition = Some(Condition.Expression("steps.cpr.outputs.pull-request-number")), - env = Map( - "GITHUB_TOKEN" -> "${{ secrets.GITHUB_TOKEN }}", - "PR_URL" -> "${{ steps.cpr.outputs.pull-request-url }}" + `if` = Some(Condition.Expression("steps.cpr.outputs.pull-request-number")), + env = Some( + Map( + "GITHUB_TOKEN" -> "${{ secrets.GITHUB_TOKEN }}", + "PR_URL" -> "${{ steps.cpr.outputs.pull-request-url }}" + ) ), run = Some("gh pr merge --auto --squash \"$PR_URL\" || gh pr merge --squash \"$PR_URL\"") ) @@ -424,11 +429,10 @@ object ZioSbtCiPlugin extends AutoPlugin { val jobs = ciReleaseApprovalJobs.value Seq( - Job( - id = "release", + "release" -> JobValue( name = "Release", - need = jobs, - condition = Some(Condition.Expression("github.event_name != 'pull_request'")), + needs = Some(jobs), + `if` = Some(Condition.Expression("github.event_name != 'pull_request'")), steps = (if (swapSizeGB > 0) Seq(setSwapSpace) else Seq.empty) ++ Seq( checkout, @@ -449,11 +453,10 @@ object ZioSbtCiPlugin extends AutoPlugin { val publishToNpmRegistry = PublishToNpmRegistry.value Seq( - Job( - id = "release-docs", + "release-docs" -> JobValue( name = "Release Docs", - need = Seq("release"), - condition = Some( + needs = Some(Seq("release")), + `if` = Some( Condition.Expression("github.event_name == 'release'") && Condition.Expression("github.event.action == 'published'") || Condition.Expression( "github.event_name == 'workflow_dispatch'" @@ -461,23 +464,18 @@ object ZioSbtCiPlugin extends AutoPlugin { ), steps = (if (swapSizeGB > 0) Seq(setSwapSpace) else Seq.empty) ++ Seq( - Step.StepSequence( - Seq( - checkout, - SetupLibuv, - SetupJava(javaVersion), - CacheDependencies, - SetupNodeJs, - publishToNpmRegistry - ) - ) + checkout, + SetupLibuv, + SetupJava(javaVersion), + CacheDependencies, + SetupNodeJs, + publishToNpmRegistry ) ), - Job( - id = "notify-docs-release", + "notify-docs-release" -> JobValue( name = "Notify Docs Release", - need = Seq("release-docs"), - condition = Some( + needs = Some(Seq("release-docs")), + `if` = Some( Condition.Expression("github.event_name == 'release'") && Condition.Expression("github.event.action == 'published'") ), @@ -520,40 +518,46 @@ object ZioSbtCiPlugin extends AutoPlugin { val jvmOptions = Seq("-XX:+PrintCommandLineFlags") ++ ciJvmOptions.value val nodeOptions = ciNodeOptions.value - val jvmMap = Map( + val jvmMap = ListMap( "JDK_JAVA_OPTIONS" -> jvmOptions.mkString(" ") ) - val nodeMap: Map[String, String] = - if (nodeOptions.nonEmpty) Map("NODE_OPTIONS" -> nodeOptions.mkString(" ")) else Map.empty - - val workflow = yaml - .Printer( - preserveOrder = true, - dropNullKeys = true, - splitLines = false, - lineBreak = LineBreak.Unix, - version = YamlVersion.Auto + val nodeMap: ListMap[String, String] = + if (nodeOptions.nonEmpty) ListMap("NODE_OPTIONS" -> nodeOptions.mkString(" ")) else ListMap.empty + + val yamlOptions = + YamlOptions.default.copy( + dropNulls = true, + lineBreak = org.yaml.snakeyaml.DumperOptions.LineBreak.UNIX, + maxScalarWidth = Some(1024) ) - .pretty( - Workflow( - name = workflowName, - env = jvmMap ++ nodeMap, - triggers = Seq( - Trigger.WorkflowDispatch(), - Trigger.Release(Seq("published")), - Trigger.Push(branches = enabledBranches.map(Branch.Named)), - Trigger.PullRequest(ignoredBranches = Seq(Branch.Named("gh-pages"))) - ), - jobs = - buildJobs ++ lintJobs ++ testJobs ++ updateReadmeJobs ++ reportSuccessful ++ releaseJobs ++ postReleaseJobs - ).asJson + + val workflow = + Workflow( + name = workflowName, + env = jvmMap ++ nodeMap, + on = Some( + Triggers( + release = Some(Triggers.Release(Seq(Triggers.ReleaseType.Published))), + push = Some(Triggers.Push(branches = Some(enabledBranches.map(Branch.Named)).filter(_.nonEmpty))), + pullRequest = Some(Triggers.PullRequest(branchesIgnore = Some(Seq(Branch.Named("gh-pages"))))) + ) + ), + jobs = ListMap.empty[ + String, + JobValue + ] ++ buildJobs ++ lintJobs ++ testJobs ++ updateReadmeJobs ++ reportSuccessful ++ releaseJobs ++ postReleaseJobs ) + val yaml: String = workflow.toJsonAST.flatMap(_.toYaml(yamlOptions).left.map(_.getMessage())) match { + case Right(value) => value + case Left(error) => sys.error(s"Error generating workflow yaml: $error") + } + val template = s"""|# This file was autogenerated using `zio-sbt-ci` plugin via `sbt ciGenerateGithubWorkflow` |# task and should be included in the git repository. Please do not edit it manually. | - |$workflow""".stripMargin + |$yaml""".stripMargin IO.write(new File(s".github/workflows/${ciWorkflowName.value.toLowerCase}.yml"), template) } @@ -641,7 +645,7 @@ object ZioSbtCiPlugin extends AutoPlugin { Step.SingleStep( name = "Set Swap Space", uses = Some(ActionRef(V("pierotofy/set-swap-space"))), - parameters = Map("swap-size-gb" -> swapSizeGB.asJson) + `with` = Some(Map("swap-size-gb" -> swapSizeGB.toString)) ) } @@ -650,7 +654,7 @@ object ZioSbtCiPlugin extends AutoPlugin { Step.SingleStep( name = "Git Checkout", uses = Some(ActionRef(V("actions/checkout"))), - parameters = Map("fetch-depth" -> "0".asJson) + `with` = Some(Map("fetch-depth" -> "0")) ) } @@ -662,10 +666,12 @@ object ZioSbtCiPlugin extends AutoPlugin { def SetupJava(version: String = "17"): Step.SingleStep = Step.SingleStep( name = "Setup Scala", uses = Some(ActionRef(V("actions/setup-java"))), - parameters = Map( - "distribution" -> "corretto".asJson, - "java-version" -> version.asJson, - "check-latest" -> true.asJson + `with` = Some( + Map( + "distribution" -> "corretto", + "java-version" -> version, + "check-latest" -> "true" + ) ) ) @@ -705,11 +711,13 @@ object ZioSbtCiPlugin extends AutoPlugin { Step.SingleStep( name = "Release", run = Some(prefixJobs + "sbt ci-release"), - env = Map( - "PGP_PASSPHRASE" -> "${{ secrets.PGP_PASSPHRASE }}", - "PGP_SECRET" -> "${{ secrets.PGP_SECRET }}", - "SONATYPE_PASSWORD" -> "${{ secrets.SONATYPE_PASSWORD }}", - "SONATYPE_USERNAME" -> "${{ secrets.SONATYPE_USERNAME }}" + env = Some( + Map( + "PGP_PASSPHRASE" -> "${{ secrets.PGP_PASSPHRASE }}", + "PGP_SECRET" -> "${{ secrets.PGP_SECRET }}", + "SONATYPE_PASSWORD" -> "${{ secrets.SONATYPE_PASSWORD }}", + "SONATYPE_USERNAME" -> "${{ secrets.SONATYPE_USERNAME }}" + ) ) ) } @@ -717,9 +725,11 @@ object ZioSbtCiPlugin extends AutoPlugin { val SetupNodeJs: Step.SingleStep = Step.SingleStep( name = "Setup NodeJs", uses = Some(ActionRef(V("actions/setup-node"))), - parameters = Map( - "node-version" -> "16.x".asJson, - "registry-url" -> "https://registry.npmjs.org".asJson + `with` = Some( + Map( + "node-version" -> "16.x", + "registry-url" -> "https://registry.npmjs.org" + ) ) ) @@ -732,7 +742,7 @@ object ZioSbtCiPlugin extends AutoPlugin { Step.SingleStep( name = "Publish Docs to NPM Registry", run = Some(prefixJobs + s"sbt docs/${docsVersioning.npmCommand}"), - env = Map("NODE_AUTH_TOKEN" -> "${{ secrets.NPM_TOKEN }}") + env = Some(Map("NODE_AUTH_TOKEN" -> "${{ secrets.NPM_TOKEN }}")) ) } diff --git a/zio-sbt-ecosystem/build.sbt b/zio-sbt-ecosystem/build.sbt index c673cdb8..83e9efb2 100644 --- a/zio-sbt-ecosystem/build.sbt +++ b/zio-sbt-ecosystem/build.sbt @@ -1,9 +1,9 @@ // Build Server Plugins -addSbtPlugin("ch.epfl.scala" % "sbt-bloop" % "1.6.0") +addSbtPlugin("ch.epfl.scala" % "sbt-bloop" % "2.0.2") // Linting Plugins addSbtPlugin("org.scalameta" % "sbt-scalafmt" % "2.5.2") -addSbtPlugin("ch.epfl.scala" % "sbt-scalafix" % "0.12.1") +addSbtPlugin("ch.epfl.scala" % "sbt-scalafix" % "0.13.0") addSbtPlugin("com.github.cb372" % "sbt-explicit-dependencies" % "0.3.1") // Versioning and Release Plugins @@ -11,12 +11,12 @@ addSbtPlugin("com.eed3si9n" % "sbt-buildinfo" % "0.12.0") addSbtPlugin("com.github.sbt" % "sbt-ci-release" % "1.5.12") // Docs Plugins -addSbtPlugin("org.scalameta" % "sbt-mdoc" % "2.5.4") +addSbtPlugin("org.scalameta" % "sbt-mdoc" % "2.6.1") addSbtPlugin("com.github.sbt" % "sbt-unidoc" % "0.5.0") addSbtPlugin("de.heikoseeberger" % "sbt-header" % "5.10.0") // Cross-Compiler Plugins -addSbtPlugin("org.scala-js" % "sbt-scalajs" % "1.16.0") +addSbtPlugin("org.scala-js" % "sbt-scalajs" % "1.17.0") addSbtPlugin("org.portable-scala" % "sbt-scalajs-crossproject" % "1.3.2") addSbtPlugin("org.scala-native" % "sbt-scala-native" % "0.5.4") addSbtPlugin("org.portable-scala" % "sbt-scala-native-crossproject" % "1.3.2") @@ -29,6 +29,6 @@ addSbtPlugin("pl.project13.scala" % "sbt-jcstress" % "0.2.0") // Binary Compatibility Plugin addSbtPlugin("com.typesafe" % "sbt-mima-plugin" % "1.1.3") -libraryDependencies += "org.snakeyaml" % "snakeyaml-engine" % "2.7" -libraryDependencies += "dev.zio" %% "zio" % "2.1.8" -libraryDependencies += "io.circe" %% "circe-yaml" % "0.16.0" +libraryDependencies += "dev.zio" %% "zio" % "2.1.9" +libraryDependencies += "dev.zio" %% "zio-json" % "0.7.3" +libraryDependencies += "dev.zio" %% "zio-json-yaml" % "0.7.3" diff --git a/zio-sbt-ecosystem/src/main/scala/zio/sbt/ScalaCompilerSettings.scala b/zio-sbt-ecosystem/src/main/scala/zio/sbt/ScalaCompilerSettings.scala index 1fc5b90a..43ba56c3 100644 --- a/zio-sbt-ecosystem/src/main/scala/zio/sbt/ScalaCompilerSettings.scala +++ b/zio-sbt-ecosystem/src/main/scala/zio/sbt/ScalaCompilerSettings.scala @@ -190,7 +190,7 @@ trait ScalaCompilerSettings { ) } else Seq.empty }, - Test / parallelExecution := scalaBinaryVersion.value != "3", + Test / parallelExecution := scalaBinaryVersion.value != "3", // why not parallel execution for Scala 3? incOptions ~= (_.withLogRecompileOnMacro(false)), autoAPIMappings := true, unusedCompileDependenciesFilter -= moduleFilter("org.scala-js", "scalajs-library") @@ -233,8 +233,7 @@ trait ScalaCompilerSettings { libraryDependencies ++= Seq( "dev.zio" %%% "zio-test" % ZioSbtEcosystemPlugin.autoImport.zioVersion.value % Test, "dev.zio" %%% "zio-test-sbt" % ZioSbtEcosystemPlugin.autoImport.zioVersion.value % Test - ), - testFrameworks += new TestFramework("zio.test.sbt.ZTestFramework") + ) ) else Seq.empty) ++ { if (enableStreaming) diff --git a/zio-sbt-ecosystem/src/main/scala/zio/sbt/Versions.scala b/zio-sbt-ecosystem/src/main/scala/zio/sbt/Versions.scala index 0a971aa1..815b9619 100644 --- a/zio-sbt-ecosystem/src/main/scala/zio/sbt/Versions.scala +++ b/zio-sbt-ecosystem/src/main/scala/zio/sbt/Versions.scala @@ -22,11 +22,11 @@ object Versions { val KindProjectorVersion = "0.13.3" val ScaluzziVersion = "0.1.23" - val scala3 = "3.3.3" - val scala212 = "2.12.19" - val scala213 = "2.13.13" + val scala3 = "3.3.4" + val scala212 = "2.12.20" + val scala213 = "2.13.15" - val zioVersion = "2.0.21" + val zioVersion = "2.1.9" lazy val betterMonadFor: ModuleID = "com.olegpy" %% "better-monadic-for" % "0.3.1" } diff --git a/zio-sbt-ecosystem/src/sbt-test/zio-sbt-ecosystem/verifySettingsWithCI/.github/workflows/ci.yml b/zio-sbt-ecosystem/src/sbt-test/zio-sbt-ecosystem/verifySettingsWithCI/.github/workflows/ci.yml index f861c9d0..b02f9e67 100644 --- a/zio-sbt-ecosystem/src/sbt-test/zio-sbt-ecosystem/verifySettingsWithCI/.github/workflows/ci.yml +++ b/zio-sbt-ecosystem/src/sbt-test/zio-sbt-ecosystem/verifySettingsWithCI/.github/workflows/ci.yml @@ -22,7 +22,7 @@ jobs: matrix: java: ['11', '17', '21'] # These version must be different than the versions in V.scala to verify that we are reading from the ci.yml file. - scala: ['2.12.19', '2.13.13', '3.3.3' ] + scala: ['2.12.20', '2.13.15', '3.3.4' ] steps: - uses: actions/checkout@v4.1.1 - uses: actions/setup-java@v3.13.0 diff --git a/zio-sbt-githubactions/build.sbt b/zio-sbt-githubactions/build.sbt index b7d36a60..938d170c 100644 --- a/zio-sbt-githubactions/build.sbt +++ b/zio-sbt-githubactions/build.sbt @@ -1,2 +1,3 @@ -libraryDependencies += "dev.zio" %% "zio" % "2.1.8" -libraryDependencies += "io.circe" %% "circe-yaml" % "0.16.0" +libraryDependencies += "dev.zio" %% "zio" % "2.1.9" +libraryDependencies += "dev.zio" %% "zio-json" % "0.7.3" +libraryDependencies += "dev.zio" %% "zio-json-yaml" % "0.7.3" diff --git a/zio-sbt-githubactions/src/main/scala/zio/sbt/githubactions/ScalaWorkflow.scala b/zio-sbt-githubactions/src/main/scala/zio/sbt/githubactions/ScalaWorkflow.scala index a9270149..f895e3cd 100644 --- a/zio-sbt-githubactions/src/main/scala/zio/sbt/githubactions/ScalaWorkflow.scala +++ b/zio-sbt-githubactions/src/main/scala/zio/sbt/githubactions/ScalaWorkflow.scala @@ -16,8 +16,7 @@ package zio.sbt.githubactions -import io.circe.syntax._ - +import zio.json._ import zio.sbt.githubactions.ScalaWorkflow.JavaVersion.JDK11 // The original code of the githubactions package was originally copied from the zio-aws-codegen project: @@ -29,8 +28,10 @@ object ScalaWorkflow { SingleStep( name = "Checkout current branch", uses = Some(ActionRef("actions/checkout@v2")), - parameters = Map( - "fetch-depth" := fetchDepth + `with` = Some( + Map( + "fetch-depth" -> fetchDepth.toJson + ) ) ) @@ -38,11 +39,13 @@ object ScalaWorkflow { SingleStep( name = "Setup Java and Scala", uses = Some(ActionRef("olafurpg/setup-scala@v11")), - parameters = Map( - "java-version" := (javaVersion match { - case None => "${{ matrix.java }}" - case Some(version) => version.asString - }) + `with` = Some( + Map( + "java-version" -> (javaVersion match { + case None => "${{ matrix.java }}" + case Some(version) => version.asString + }) + ) ) ) @@ -50,12 +53,14 @@ object ScalaWorkflow { SingleStep( name = "Setup NodeJS", uses = Some(ActionRef("actions/setup-node@v3")), - parameters = Map( - "node-version" := (javaVersion match { - case None => "16.x" - case Some(version) => version.asString - }), - "registry-url" := "https://registry.npmjs.org" + `with` = Some( + Map( + "node-version" -> (javaVersion match { + case None => "16.x" + case Some(version) => version.asString + }), + "registry-url" -> "https://registry.npmjs.org" + ) ) ) @@ -75,14 +80,16 @@ object ScalaWorkflow { SingleStep( name = "Cache SBT", uses = Some(ActionRef("actions/cache@v2")), - parameters = Map( - "path" := Seq( - "~/.ivy2/cache", - "~/.sbt", - "~/.coursier/cache/v1", - "~/.cache/coursier/v1" - ).mkString("\n"), - "key" := s"$osS-sbt-$scalaS-$${{ hashFiles('**/*.sbt') }}-$${{ hashFiles('**/build.properties') }}" + `with` = Some( + Map( + "path" -> Seq( + "~/.ivy2/cache", + "~/.sbt", + "~/.coursier/cache/v1", + "~/.cache/coursier/v1" + ).mkString("\n"), + "key" -> s"$osS-sbt-$scalaS-$${{ hashFiles('**/*.sbt') }}-$${{ hashFiles('**/build.properties') }}" + ) ) ) } @@ -105,7 +112,7 @@ object ScalaWorkflow { run = Some( s"sbt -J-XX:+UseG1GC -J-Xmx${heapGb}g -J-Xms${heapGb}g -J-Xss${stackMb}m ${parameters.mkString(" ")}" ), - env = env + env = Some(env).filter(_.nonEmpty) ) def storeTargets( @@ -130,9 +137,11 @@ object ScalaWorkflow { SingleStep( s"Upload $id targets", uses = Some(ActionRef("actions/upload-artifact@v2")), - parameters = Map( - "name" := s"target-$id-$osS-$scalaS-$javaS", - "path" := "targets.tar" + `with` = Some( + Map( + "name" -> s"target-$id-$osS-$scalaS-$javaS", + "path" -> "targets.tar" + ) ) ) ) @@ -154,8 +163,10 @@ object ScalaWorkflow { SingleStep( s"Download stored $id targets", uses = Some(ActionRef("actions/download-artifact@v2")), - parameters = Map( - "name" := s"target-$id-$osS-$scalaS-$javaS" + `with` = Some( + Map( + "name" -> s"target-$id-$osS-$scalaS-$javaS" + ) ) ), SingleStep( @@ -182,15 +193,17 @@ object ScalaWorkflow { SingleStep( "Load PGP secret", run = Some(".github/import-key.sh"), - env = Map("PGP_SECRET" -> "${{ secrets.PGP_SECRET }}") + env = Some(Map("PGP_SECRET" -> "${{ secrets.PGP_SECRET }}")) ) def turnstyle(): Step = SingleStep( "Turnstyle", uses = Some(ActionRef("softprops/turnstyle@v1")), - env = Map( - "GITHUB_TOKEN" -> "${{ secrets.ADMIN_GITHUB_TOKEN }}" + env = Some( + Map( + "GITHUB_TOKEN" -> "${{ secrets.ADMIN_GITHUB_TOKEN }}" + ) ) ) @@ -231,12 +244,12 @@ object ScalaWorkflow { val JDK21: JavaVersion = CorrettoJDK("21") } - implicit class JobOps(job: Job) { + implicit class JobOps(job: JobValue) { def matrix( scalaVersions: Seq[ScalaVersion], operatingSystems: Seq[OS] = Seq(OS.UbuntuLatest), javaVersions: Seq[JavaVersion] = Seq(JDK11) - ): Job = + ): JobValue = job.copy( strategy = Some( Strategy( diff --git a/zio-sbt-githubactions/src/main/scala/zio/sbt/githubactions/model.scala b/zio-sbt-githubactions/src/main/scala/zio/sbt/githubactions/model.scala index a3a6d142..96d364be 100644 --- a/zio-sbt-githubactions/src/main/scala/zio/sbt/githubactions/model.scala +++ b/zio-sbt-githubactions/src/main/scala/zio/sbt/githubactions/model.scala @@ -16,10 +16,10 @@ package zio.sbt.githubactions -import io.circe._ -import io.circe.syntax._ +import scala.collection.immutable.ListMap +import scala.util.{Failure, Success, Try} -import zio.sbt.githubactions.Step.StepSequence +import zio.json._ sealed trait OS { val asString: String @@ -33,96 +33,119 @@ object Branch { case object All extends Branch case class Named(name: String) extends Branch - implicit val encoder: Encoder[Branch] = { - case All => Json.fromString("*") - case Named(name) => Json.fromString(name) - } + implicit val codec: JsonCodec[Branch] = JsonCodec.string.transform( + { + case "*" => All + case name => Named(name) + }, + { + case All => "*" + case Named(name) => name + } + ) } -sealed trait Trigger { - def toKeyValuePair: (String, Json) -} +@jsonMemberNames(SnakeCase) +case class Triggers( + workflowDispatch: Option[Triggers.WorkflowDispatch] = None, + release: Option[Triggers.Release] = None, + pullRequest: Option[Triggers.PullRequest] = None, + push: Option[Triggers.Push] = None, + create: Option[Triggers.Create] = None +) -case class Input(key: String, description: String, required: Boolean, defaultValue: String) +object Triggers { + case class InputValue(description: String, required: Boolean, default: String) + object InputValue { + implicit val jsonCodec: JsonCodec[InputValue] = DeriveJsonCodec.gen[InputValue] + } -object Trigger { case class WorkflowDispatch( - inputs: Seq[Input] = Seq.empty - ) extends Trigger { - override def toKeyValuePair: (String, Json) = - "workflow_dispatch" := inputs.map { i => - i.key -> - Json.obj( - ("description", i.description.asJson), - ("required", i.required.asJson), - ("default", i.defaultValue.asJson) - ) - }.toMap.asJson + inputs: ListMap[String, InputValue] = ListMap.empty + ) + + object WorkflowDispatch { + implicit def listMapCodec[K: JsonFieldDecoder: JsonFieldEncoder, V: JsonCodec]: JsonCodec[ListMap[K, V]] = + JsonCodec( + JsonEncoder.keyValueIterable[K, V, ListMap], + JsonDecoder.keyValueChunk[K, V].map(c => ListMap(c: _*)) + ) + + implicit val jsonCodec: JsonCodec[WorkflowDispatch] = DeriveJsonCodec.gen[WorkflowDispatch] } case class Release( - releaseTypes: Seq[String] = Seq.empty - ) extends Trigger { - override def toKeyValuePair: (String, Json) = - "release" := Json.obj("types" := releaseTypes) + types: Seq[ReleaseType] = Seq.empty + ) + + object Release { + implicit val jsonCodec: JsonCodec[Release] = DeriveJsonCodec.gen[Release] } + sealed trait ReleaseType + object ReleaseType { + case object Created extends ReleaseType + case object Published extends ReleaseType + case object Prereleased extends ReleaseType + + implicit val codec: JsonCodec[ReleaseType] = JsonCodec.string.transformOrFail( + { + case "created" => Right(Created) + case "published" => Right(Published) + case "prereleased" => Right(Prereleased) + case other => Left(s"Invalid release type: $other") + }, + { + case Created => "created" + case Published => "published" + case Prereleased => "prereleased" + } + ) + } + + @jsonMemberNames(KebabCase) case class PullRequest( - branches: Seq[Branch] = Seq.empty, - ignoredBranches: Seq[Branch] = Seq.empty - ) extends Trigger { - override def toKeyValuePair: (String, Json) = - "pull_request" := Json.obj( - Seq( - "branches" := branches, - "branches-ignore" := ignoredBranches - ).filter { case (_, data) => data.asArray.exists(_.nonEmpty) }: _* - ) + // types: Option[Seq[PullRequestType]] = None, + branches: Option[Seq[Branch]] = None, + branchesIgnore: Option[Seq[Branch]] = None, + paths: Option[Seq[String]] = None + ) + + object PullRequest { + implicit val jsonCodec: JsonCodec[PullRequest] = DeriveJsonCodec.gen[PullRequest] } case class Push( - branches: Seq[Branch] = Seq.empty, - ignoredBranches: Seq[Branch] = Seq.empty - ) extends Trigger { - override def toKeyValuePair: (String, Json) = - "push" := Json.obj( - Seq( - "branches" := branches, - "branches-ignore" := ignoredBranches - ).filter { case (_, data) => data.asArray.exists(_.nonEmpty) }: _* - ) + branches: Option[Seq[Branch]] = None, + branchesIgnore: Option[Seq[Branch]] = None + ) + + object Push { + implicit val jsonCodec: JsonCodec[Push] = DeriveJsonCodec.gen[Push] } case class Create( - branches: Seq[Branch] = Seq.empty, - ignoredBranches: Seq[Branch] = Seq.empty - ) extends Trigger { - override def toKeyValuePair: (String, Json) = - "create" := Json.obj( - Seq( - "branches" := branches, - "branches-ignore" := ignoredBranches - ).filter { case (_, data) => data.asArray.exists(_.nonEmpty) }: _* - ) + branches: Option[Seq[Branch]] = None, + branchesIgnore: Option[Seq[Branch]] = None + ) + + object Create { + implicit val jsonCodec: JsonCodec[Create] = DeriveJsonCodec.gen[Create] } + + implicit val codec: JsonCodec[Triggers] = DeriveJsonCodec.gen[Triggers] } +@jsonMemberNames(KebabCase) case class Strategy(matrix: Map[String, List[String]], maxParallel: Option[Int] = None, failFast: Boolean = true) object Strategy { - implicit val encoder: Encoder[Strategy] = - (s: Strategy) => - Json.obj( - "fail-fast" := s.failFast, - "max-parallel" := s.maxParallel, - "matrix" := s.matrix - ) + implicit val codec: JsonCodec[Strategy] = DeriveJsonCodec.gen[Strategy] } case class ActionRef(ref: String) object ActionRef { - implicit val encoder: Encoder[ActionRef] = - (action: ActionRef) => Json.fromString(action.ref) + implicit val codec: JsonCodec[ActionRef] = JsonCodec.string.transform(ActionRef(_), _.ref) } sealed trait Condition { @@ -152,6 +175,10 @@ object Condition { def asString: String = s"$${{ $expression }}" } + object Expression { + implicit val codec: JsonCodec[Expression] = JsonCodec.string.transform(Expression(_), _.asString) + } + case class Function(expression: String) extends Condition { def &&(other: Condition): Condition = throw new IllegalArgumentException("Not supported currently") @@ -162,8 +189,17 @@ object Condition { def asString: String = expression } - implicit val encoder: Encoder[Condition] = - (c: Condition) => Json.fromString(c.asString) + object Function { + implicit val codec: JsonCodec[Function] = JsonCodec.string.transform(Function(_), _.expression) + } + + implicit val codec: JsonCodec[Condition] = JsonCodec.string.transform( + { + case expression if expression.startsWith("${{") => Expression(expression) + case expression => Function(expression) + }, + _.asString + ) } sealed trait Step { @@ -175,17 +211,21 @@ object Step { name: String, id: Option[String] = None, uses: Option[ActionRef] = None, - condition: Option[Condition] = None, - parameters: Map[String, Json] = Map.empty, + `if`: Option[Condition] = None, + `with`: Option[Map[String, String]] = None, run: Option[String] = None, - env: Map[String, String] = Map.empty + env: Option[Map[String, String]] = None ) extends Step { override def when(condition: Condition): Step = - copy(condition = Some(condition)) + copy(`if` = Some(condition)) override def flatten: Seq[Step.SingleStep] = Seq(this) } + object SingleStep { + implicit val codec: JsonCodec[SingleStep] = DeriveJsonCodec.gen[SingleStep] + } + case class StepSequence(steps: Seq[Step]) extends Step { override def when(condition: Condition): Step = copy(steps = steps.map(_.when(condition))) @@ -194,31 +234,25 @@ object Step { steps.flatMap(_.flatten) } - implicit val encoder: Encoder[SingleStep] = - (s: SingleStep) => - Json - .obj( - "name" := s.name, - "id" := s.id, - "uses" := s.uses, - "if" := s.condition, - "with" := (if (s.parameters.nonEmpty) s.parameters.asJson - else Json.Null), - "run" := s.run, - "env" := (if (s.env.nonEmpty) s.env.asJson else Json.Null) - ) + implicit val codec: JsonCodec[Step] = DeriveJsonCodec.gen[Step] } case class ImageRef(ref: String) object ImageRef { - implicit val encoder: Encoder[ImageRef] = - (image: ImageRef) => Json.fromString(image.ref) + implicit val codec: JsonCodec[ImageRef] = JsonCodec.string.transform(ImageRef(_), _.ref) } case class ServicePort(inner: Int, outer: Int) object ServicePort { - implicit val encoder: Encoder[ServicePort] = - (sp: ServicePort) => Json.fromString(s"${sp.inner}:${sp.outer}") + implicit val codec: JsonCodec[ServicePort] = JsonCodec.string.transformOrFail( + v => + Try(v.split(":", 2).map(_.toInt).toList) match { + case Success(inner :: outer :: Nil) => Right(ServicePort(inner.toInt, outer.toInt)) + case Success(_) => Left("Invalid service port format: " + v) + case Failure(_) => Left("Invalid service port format: " + v) + }, + sp => s"${sp.inner}:${sp.outer}" + ) } case class Service( @@ -228,100 +262,76 @@ case class Service( ports: Seq[ServicePort] = Seq.empty ) object Service { - implicit val encoder: Encoder[Service] = - (s: Service) => - Json.obj( - "image" := s.image, - "env" := s.env, - "ports" := s.ports - ) + implicit val codec: JsonCodec[Service] = DeriveJsonCodec.gen[Service] } -case class Job( - id: String, +@jsonMemberNames(KebabCase) +case class JobValue( name: String, runsOn: String = "ubuntu-latest", - timeoutMinutes: Int = 30, + timeoutMinutes: Option[Int] = None, continueOnError: Boolean = false, strategy: Option[Strategy] = None, - steps: Seq[Step] = Seq.empty, - need: Seq[String] = Seq.empty, - services: Seq[Service] = Seq.empty, - condition: Option[Condition] = None + needs: Option[Seq[String]] = None, + services: Option[Seq[Service]] = None, + `if`: Option[Condition] = None, + steps: Seq[Step.SingleStep] = Seq.empty ) { - def withStrategy(strategy: Strategy): Job = + def withStrategy(strategy: Strategy): JobValue = copy(strategy = Some(strategy)) - def withSteps(steps: Step*): Job = - copy(steps = steps) + def withSteps(steps: Step*): JobValue = steps match { + case steps: Step.StepSequence => + copy(steps = steps.flatten) + case step: Step.SingleStep => + copy(steps = step :: Nil) + } - def withServices(services: Service*): Job = - copy(services = services) + def withServices(services: Service*): JobValue = + copy(services = Some(services)) } -object Job { - implicit val encoder: Encoder[Job] = - (job: Job) => - Json - .obj( - "name" := job.name, - "runs-on" := job.runsOn, - "continue-on-error" := job.continueOnError, - "strategy" := job.strategy, - "needs" := (if (job.need.nonEmpty) job.need.asJson - else Json.Null), - "services" := (if (job.services.nonEmpty) { - Json.obj( - job.services.map(svc => svc.name := svc): _* - ) - } else { - Json.Null - }), - "if" := job.condition, - "steps" := StepSequence(job.steps).flatten - ) +object JobValue { + implicit val codec: JsonCodec[JobValue] = DeriveJsonCodec.gen[JobValue] +} + +@jsonMemberNames(KebabCase) +case class Concurrency( + group: String, + cancelInProgress: Boolean = true +) + +object Concurrency { + implicit val codec: JsonCodec[Concurrency] = DeriveJsonCodec.gen[Concurrency] } case class Workflow( name: String, - env: Map[String, String] = Map.empty, - triggers: Seq[Trigger] = Seq.empty, - jobs: Seq[Job] = Seq.empty + env: ListMap[String, String] = ListMap.empty, + on: Option[Triggers] = None, + concurrency: Concurrency = Concurrency( + "${{ github.workflow }}-${{ github.ref == format('refs/heads/{0}', github.event.repository.default_branch) && github.run_id || github.ref }}" + ), + jobs: ListMap[String, JobValue] = ListMap.empty ) { - def on(triggers: Trigger*): Workflow = - copy(triggers = triggers) + def withOn(on: Triggers): Workflow = + copy(on = Some(on)) - def withJobs(jobs: Job*): Workflow = - copy(jobs = jobs) + def withJobs(jobs: (String, JobValue)*): Workflow = + copy(jobs = ListMap(jobs: _*)) - def addJob(job: Job): Workflow = - copy(jobs = jobs :+ job) + def addJob(job: (String, JobValue)): Workflow = + copy(jobs = jobs + job) - def addJobs(newJobs: Seq[Job]): Workflow = + def addJobs(newJobs: (String, JobValue)*): Workflow = copy(jobs = jobs ++ newJobs) } object Workflow { - implicit val encoder: Encoder[Workflow] = - (wf: Workflow) => - Json - .obj( - "name" := wf.name, - "env" := wf.env, - "on" := (if (wf.triggers.isEmpty) - Json.Null - else { - Json.obj( - wf.triggers - .map(_.toKeyValuePair): _* - ) - }), - "concurrency" := Json.obj( - "group" := Json.fromString( - "${{ github.workflow }}-${{ github.ref == format('refs/heads/{0}', github.event.repository.default_branch) && github.run_id || github.ref }}" - ), - "cancel-in-progress" := true - ), - "jobs" := Json.obj(wf.jobs.map(job => job.id := job): _*) - ) + implicit def listMapCodec[K: JsonFieldDecoder: JsonFieldEncoder, V: JsonCodec]: JsonCodec[ListMap[K, V]] = + JsonCodec( + JsonEncoder.keyValueIterable[K, V, ListMap], + JsonDecoder.keyValueChunk[K, V].map(c => ListMap(c: _*)) + ) + implicit val codec: JsonCodec[Workflow] = DeriveJsonCodec.gen[Workflow] } diff --git a/zio-sbt-githubactions/src/main/scala/zio/sbt/githubactions/package.scala b/zio-sbt-githubactions/src/main/scala/zio/sbt/githubactions/package.scala new file mode 100644 index 00000000..9f1e009c --- /dev/null +++ b/zio-sbt-githubactions/src/main/scala/zio/sbt/githubactions/package.scala @@ -0,0 +1,5 @@ +package zio.sbt + +package object githubactions { + type Job = (String, JobValue) +} diff --git a/zio-sbt-website/build.sbt b/zio-sbt-website/build.sbt index f45bd37d..f6ebeff3 100644 --- a/zio-sbt-website/build.sbt +++ b/zio-sbt-website/build.sbt @@ -1,6 +1,7 @@ -addSbtPlugin("org.scalameta" % "sbt-mdoc" % "2.5.4") +addSbtPlugin("org.scalameta" % "sbt-mdoc" % "2.6.1") addSbtPlugin("com.github.sbt" % "sbt-unidoc" % "0.5.0") addSbtPlugin("com.thoughtworks.sbt-api-mappings" % "sbt-api-mappings" % "3.0.2") -libraryDependencies += "dev.zio" %% "zio" % "2.1.8" -libraryDependencies += "io.circe" %% "circe-yaml" % "0.16.0" +libraryDependencies += "dev.zio" %% "zio" % "2.1.9" +libraryDependencies += "dev.zio" %% "zio-json" % "0.7.3" +libraryDependencies += "dev.zio" %% "zio-json-yaml" % "0.7.3" From 3fe9f88f355fd463ccb2b4ed1da7ca83c853f7bc Mon Sep 17 00:00:00 2001 From: Thijs Broersen Date: Wed, 27 Nov 2024 21:00:17 +0100 Subject: [PATCH 2/5] updates and dedup scalaworkflow --- .github/workflows/ci.yml | 21 +-- .sbtopts | 1 + project/Versions.scala | 2 +- project/build.properties | 2 +- project/plugins.sbt | 2 +- zio-sbt-ci/build.sbt | 2 +- zio-sbt-ci/src/main/scala/zio/sbt/V.scala | 2 +- .../main/scala/zio/sbt/ZioSbtCiPlugin.scala | 98 ++++++------ zio-sbt-ecosystem/build.sbt | 2 +- .../src/main/scala/zio/sbt/Versions.scala | 2 +- zio-sbt-githubactions/build.sbt | 2 +- .../zio/sbt/githubactions/ScalaWorkflow.scala | 71 +++++---- .../scala/zio/sbt/githubactions/model.scala | 143 +++++++++++------- .../scala/zio/sbt/githubactions/package.scala | 5 - zio-sbt-website/build.sbt | 2 +- 15 files changed, 202 insertions(+), 155 deletions(-) create mode 100644 .sbtopts delete mode 100644 zio-sbt-githubactions/src/main/scala/zio/sbt/githubactions/package.scala diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3c69b756..8cf9a0a4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -5,6 +5,7 @@ name: CI env: JDK_JAVA_OPTIONS: -XX:+PrintCommandLineFlags 'on': + workflow_dispatch: {} release: types: - published @@ -34,7 +35,7 @@ jobs: with: distribution: corretto java-version: '17' - check-latest: 'true' + check-latest: true - name: Cache Dependencies uses: coursier/cache-action@v6 - name: Check all code compiles @@ -59,7 +60,7 @@ jobs: with: distribution: corretto java-version: '17' - check-latest: 'true' + check-latest: true - name: Cache Dependencies uses: coursier/cache-action@v6 - name: Check if the site workflow is up to date @@ -85,7 +86,7 @@ jobs: with: distribution: corretto java-version: ${{ matrix.java }} - check-latest: 'true' + check-latest: true - name: Cache Dependencies uses: coursier/cache-action@v6 - name: Git Checkout @@ -111,7 +112,7 @@ jobs: with: distribution: corretto java-version: '17' - check-latest: 'true' + check-latest: true - name: Cache Dependencies uses: coursier/cache-action@v6 - name: Generate Readme @@ -132,17 +133,17 @@ jobs: id: cpr uses: peter-evans/create-pull-request@v6 with: + title: Update README.md + commit-message: Update README.md + branch: zio-sbt-website/update-readme + delete-branch: true body: |- Autogenerated changes after running the `sbt docs/generateReadme` command of the [zio-sbt-website](https://zio.dev/zio-sbt) plugin. I will automatically update the README.md file whenever there is new change for README.md, e.g. - After each release, I will update the version in the installation section. - After any changes to the "docs/index.md" file, I will update the README.md file accordingly. - branch: zio-sbt-website/update-readme - commit-message: Update README.md token: ${{ steps.generate-token.outputs.token }} - delete-branch: 'true' - title: Update README.md - name: Approve PR if: ${{ steps.cpr.outputs.pull-request-number }} run: gh pr review "$PR_URL" --approve @@ -185,7 +186,7 @@ jobs: with: distribution: corretto java-version: '17' - check-latest: 'true' + check-latest: true - name: Cache Dependencies uses: coursier/cache-action@v6 - name: Release @@ -214,7 +215,7 @@ jobs: with: distribution: corretto java-version: '17' - check-latest: 'true' + check-latest: true - name: Cache Dependencies uses: coursier/cache-action@v6 - name: Setup NodeJs diff --git a/.sbtopts b/.sbtopts new file mode 100644 index 00000000..3b630f6a --- /dev/null +++ b/.sbtopts @@ -0,0 +1 @@ +-Dsbt.io.implicit.relative.glob.conversion=allow diff --git a/project/Versions.scala b/project/Versions.scala index 7a8351bf..ff018dfb 100644 --- a/project/Versions.scala +++ b/project/Versions.scala @@ -2,5 +2,5 @@ object Versions { val Scala212 = "2.12.20" val Scala213 = "2.13.15" val Scala3 = "3.3.4" - val zio = "2.1.9" + val zio = "2.1.13" } diff --git a/project/build.properties b/project/build.properties index 23f7d979..1767a6f8 100644 --- a/project/build.properties +++ b/project/build.properties @@ -1 +1 @@ -sbt.version = 1.10.2 +sbt.version = 1.10.5 diff --git a/project/plugins.sbt b/project/plugins.sbt index 8260121f..1586863d 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -1,5 +1,5 @@ // Build Server Plugins -addSbtPlugin("ch.epfl.scala" % "sbt-bloop" % "2.0.3") +addSbtPlugin("ch.epfl.scala" % "sbt-bloop" % "2.0.5") // Linting Plugins addSbtPlugin("org.scalameta" % "sbt-scalafmt" % "2.5.2") diff --git a/zio-sbt-ci/build.sbt b/zio-sbt-ci/build.sbt index 938d170c..f959f826 100644 --- a/zio-sbt-ci/build.sbt +++ b/zio-sbt-ci/build.sbt @@ -1,3 +1,3 @@ -libraryDependencies += "dev.zio" %% "zio" % "2.1.9" +libraryDependencies += "dev.zio" %% "zio" % "2.1.13" libraryDependencies += "dev.zio" %% "zio-json" % "0.7.3" libraryDependencies += "dev.zio" %% "zio-json-yaml" % "0.7.3" diff --git a/zio-sbt-ci/src/main/scala/zio/sbt/V.scala b/zio-sbt-ci/src/main/scala/zio/sbt/V.scala index d123c12a..f71e1f18 100644 --- a/zio-sbt-ci/src/main/scala/zio/sbt/V.scala +++ b/zio-sbt-ci/src/main/scala/zio/sbt/V.scala @@ -5,7 +5,7 @@ object V { Map( "peter-evans/create-pull-request" -> "v6", "zio/generate-github-app-token" -> "v1.0.0", - "pierotofy/set-swap-space" -> "master", + "pierotofy/set-swap-space" -> "49819abfb41bd9b44fb781159c033dba90353a7c", // 1.0, "actions/checkout" -> "v4", "coursier/cache-action" -> "v6", "actions/setup-java" -> "v4", diff --git a/zio-sbt-ci/src/main/scala/zio/sbt/ZioSbtCiPlugin.scala b/zio-sbt-ci/src/main/scala/zio/sbt/ZioSbtCiPlugin.scala index b6d29217..562fb65e 100644 --- a/zio-sbt-ci/src/main/scala/zio/sbt/ZioSbtCiPlugin.scala +++ b/zio-sbt-ci/src/main/scala/zio/sbt/ZioSbtCiPlugin.scala @@ -100,7 +100,7 @@ object ZioSbtCiPlugin extends AutoPlugin { val checkWebsiteBuildProcess = ciCheckWebsiteBuildProcess.value Seq( - "build" -> JobValue( + Job( name = "Build", continueOnError = true, steps = { @@ -127,7 +127,7 @@ object ZioSbtCiPlugin extends AutoPlugin { val lint = Lint.value Seq( - "lint" -> JobValue( + Job( name = "Lint", steps = (if (swapSizeGB > 0) Seq(setSwapSpace) else Seq.empty) ++ Seq(checkout, SetupLibuv, SetupJava(javaVersion), CacheDependencies) ++ checkGithubWorkflow.flatMap( @@ -156,13 +156,13 @@ object ZioSbtCiPlugin extends AutoPlugin { versions.contains(scalaVersion) }.map(e => e._1 + "/test").mkString(" ")}" - "test" -> JobValue( + Job( name = "Test", strategy = Some( Strategy( - matrix = Map( - "java" -> javaPlatforms.toList, - "scala" -> scalaVersionMatrix.values.flatten.toSet.toList + matrix = ListMap( + "java" -> javaPlatforms.toList.sorted, + "scala" -> scalaVersionMatrix.values.flatten.toList.distinct.sorted ), maxParallel = matrixMaxParallel, failFast = false @@ -218,15 +218,15 @@ object ZioSbtCiPlugin extends AutoPlugin { } val FlattenTests = - "test" -> JobValue( + Job( name = "Test", strategy = Some( Strategy( - matrix = Map( - "java" -> javaPlatforms.toList + matrix = ListMap( + "java" -> javaPlatforms.toList.sorted ) ++ (if (javaPlatformMatrix.isEmpty) { - Map("scala-project" -> scalaVersionMatrix.flatMap { case (moduleName, versions) => + ListMap("scala-project" -> scalaVersionMatrix.flatMap { case (moduleName, versions) => versions.map { version => s"++$version $moduleName" } @@ -290,11 +290,13 @@ object ZioSbtCiPlugin extends AutoPlugin { ) val DefaultTestStrategy = - "test" -> JobValue( + Job( name = "Test", strategy = Some( Strategy( - matrix = Map("java" -> javaPlatforms.toList), + matrix = ListMap( + "java" -> javaPlatforms.toList.sorted + ), maxParallel = matrixMaxParallel, failFast = false ) @@ -322,7 +324,7 @@ object ZioSbtCiPlugin extends AutoPlugin { val pullRequestApprovalJobs = ciPullRequestApprovalJobs.value Seq( - "ci" -> JobValue( + Job( name = "ci", needs = Some(pullRequestApprovalJobs), steps = Seq( @@ -344,7 +346,7 @@ object ZioSbtCiPlugin extends AutoPlugin { val generateReadme = GenerateReadme.value Seq( - "update-readme" -> JobValue( + Job( name = "Update README", `if` = updateReadmeCondition orElse Some(Condition.Expression("github.event_name == 'push'")), steps = (if (swapSizeGB > 0) Seq(setSwapSpace) else Seq.empty) ++ @@ -367,9 +369,9 @@ object ZioSbtCiPlugin extends AutoPlugin { id = Some("generate-token"), uses = Some(ActionRef(V("zio/generate-github-app-token"))), `with` = Some( - Map( - "app_id" -> "${{ secrets.APP_ID }}", - "app_private_key" -> "${{ secrets.APP_PRIVATE_KEY }}" + ListMap( + "app_id" -> "${{ secrets.APP_ID }}".toJsonAST.right.get, + "app_private_key" -> "${{ secrets.APP_PRIVATE_KEY }}".toJsonAST.right.get ) ) ), @@ -378,18 +380,18 @@ object ZioSbtCiPlugin extends AutoPlugin { id = Some("cpr"), uses = Some(ActionRef(V("peter-evans/create-pull-request"))), `with` = Some( - Map( - "title" -> "Update README.md", - "commit-message" -> "Update README.md", - "branch" -> "zio-sbt-website/update-readme", - "delete-branch" -> "true", + ListMap( + "title" -> "Update README.md".toJsonAST.right.get, + "commit-message" -> "Update README.md".toJsonAST.right.get, + "branch" -> "zio-sbt-website/update-readme".toJsonAST.right.get, + "delete-branch" -> true.toJsonAST.right.get, "body" -> """|Autogenerated changes after running the `sbt docs/generateReadme` command of the [zio-sbt-website](https://zio.dev/zio-sbt) plugin. | |I will automatically update the README.md file whenever there is new change for README.md, e.g. | - After each release, I will update the version in the installation section. - | - After any changes to the "docs/index.md" file, I will update the README.md file accordingly.""".stripMargin, - "token" -> "${{ steps.generate-token.outputs.token }}" + | - After any changes to the "docs/index.md" file, I will update the README.md file accordingly.""".stripMargin.toJsonAST.right.get, + "token" -> "${{ steps.generate-token.outputs.token }}".toJsonAST.right.get ) ) ), @@ -397,7 +399,7 @@ object ZioSbtCiPlugin extends AutoPlugin { name = "Approve PR", `if` = Some(Condition.Expression("steps.cpr.outputs.pull-request-number")), env = Some( - Map( + ListMap( "GITHUB_TOKEN" -> "${{ secrets.GITHUB_TOKEN }}", "PR_URL" -> "${{ steps.cpr.outputs.pull-request-url }}" ) @@ -408,7 +410,7 @@ object ZioSbtCiPlugin extends AutoPlugin { name = "Enable Auto-Merge", `if` = Some(Condition.Expression("steps.cpr.outputs.pull-request-number")), env = Some( - Map( + ListMap( "GITHUB_TOKEN" -> "${{ secrets.GITHUB_TOKEN }}", "PR_URL" -> "${{ steps.cpr.outputs.pull-request-url }}" ) @@ -429,7 +431,7 @@ object ZioSbtCiPlugin extends AutoPlugin { val jobs = ciReleaseApprovalJobs.value Seq( - "release" -> JobValue( + Job( name = "Release", needs = Some(jobs), `if` = Some(Condition.Expression("github.event_name != 'pull_request'")), @@ -453,7 +455,7 @@ object ZioSbtCiPlugin extends AutoPlugin { val publishToNpmRegistry = PublishToNpmRegistry.value Seq( - "release-docs" -> JobValue( + Job( name = "Release Docs", needs = Some(Seq("release")), `if` = Some( @@ -472,7 +474,7 @@ object ZioSbtCiPlugin extends AutoPlugin { publishToNpmRegistry ) ), - "notify-docs-release" -> JobValue( + Job( name = "Notify Docs Release", needs = Some(Seq("release-docs")), `if` = Some( @@ -534,18 +536,18 @@ object ZioSbtCiPlugin extends AutoPlugin { val workflow = Workflow( name = workflowName, - env = jvmMap ++ nodeMap, + env = Some(jvmMap ++ nodeMap), on = Some( Triggers( - release = Some(Triggers.Release(Seq(Triggers.ReleaseType.Published))), - push = Some(Triggers.Push(branches = Some(enabledBranches.map(Branch.Named)).filter(_.nonEmpty))), - pullRequest = Some(Triggers.PullRequest(branchesIgnore = Some(Seq(Branch.Named("gh-pages"))))) + release = Some(Trigger.Release(Seq(Trigger.ReleaseType.Published))), + push = Some(Trigger.Push(branches = Some(enabledBranches.map(Branch.Named)).filter(_.nonEmpty))), + pullRequest = Some(Trigger.PullRequest(branchesIgnore = Some(Seq(Branch.Named("gh-pages"))))) ) ), - jobs = ListMap.empty[ - String, - JobValue - ] ++ buildJobs ++ lintJobs ++ testJobs ++ updateReadmeJobs ++ reportSuccessful ++ releaseJobs ++ postReleaseJobs + jobs = ListMap( + (buildJobs ++ lintJobs ++ testJobs ++ updateReadmeJobs ++ reportSuccessful ++ releaseJobs ++ postReleaseJobs) + .map(job => job.id -> job): _* + ) ) val yaml: String = workflow.toJsonAST.flatMap(_.toYaml(yamlOptions).left.map(_.getMessage())) match { @@ -645,7 +647,7 @@ object ZioSbtCiPlugin extends AutoPlugin { Step.SingleStep( name = "Set Swap Space", uses = Some(ActionRef(V("pierotofy/set-swap-space"))), - `with` = Some(Map("swap-size-gb" -> swapSizeGB.toString)) + `with` = Some(ListMap("swap-size-gb" -> swapSizeGB.toString.toJsonAST.right.get)) ) } @@ -654,7 +656,7 @@ object ZioSbtCiPlugin extends AutoPlugin { Step.SingleStep( name = "Git Checkout", uses = Some(ActionRef(V("actions/checkout"))), - `with` = Some(Map("fetch-depth" -> "0")) + `with` = Some(ListMap("fetch-depth" -> "0".toJsonAST.right.get)) ) } @@ -667,10 +669,10 @@ object ZioSbtCiPlugin extends AutoPlugin { name = "Setup Scala", uses = Some(ActionRef(V("actions/setup-java"))), `with` = Some( - Map( - "distribution" -> "corretto", - "java-version" -> version, - "check-latest" -> "true" + ListMap( + "distribution" -> "corretto".toJsonAST.right.get, + "java-version" -> version.toJsonAST.right.get, + "check-latest" -> true.toJsonAST.right.get ) ) ) @@ -712,7 +714,7 @@ object ZioSbtCiPlugin extends AutoPlugin { name = "Release", run = Some(prefixJobs + "sbt ci-release"), env = Some( - Map( + ListMap( "PGP_PASSPHRASE" -> "${{ secrets.PGP_PASSPHRASE }}", "PGP_SECRET" -> "${{ secrets.PGP_SECRET }}", "SONATYPE_PASSWORD" -> "${{ secrets.SONATYPE_PASSWORD }}", @@ -726,9 +728,9 @@ object ZioSbtCiPlugin extends AutoPlugin { name = "Setup NodeJs", uses = Some(ActionRef(V("actions/setup-node"))), `with` = Some( - Map( - "node-version" -> "16.x", - "registry-url" -> "https://registry.npmjs.org" + ListMap( + "node-version" -> "16.x".toJsonAST.right.get, + "registry-url" -> "https://registry.npmjs.org".toJsonAST.right.get ) ) ) @@ -742,7 +744,7 @@ object ZioSbtCiPlugin extends AutoPlugin { Step.SingleStep( name = "Publish Docs to NPM Registry", run = Some(prefixJobs + s"sbt docs/${docsVersioning.npmCommand}"), - env = Some(Map("NODE_AUTH_TOKEN" -> "${{ secrets.NPM_TOKEN }}")) + env = Some(ListMap("NODE_AUTH_TOKEN" -> "${{ secrets.NPM_TOKEN }}")) ) } diff --git a/zio-sbt-ecosystem/build.sbt b/zio-sbt-ecosystem/build.sbt index 83e9efb2..3cf71721 100644 --- a/zio-sbt-ecosystem/build.sbt +++ b/zio-sbt-ecosystem/build.sbt @@ -27,7 +27,7 @@ addSbtPlugin("pl.project13.scala" % "sbt-jmh" % "0.4.7") addSbtPlugin("pl.project13.scala" % "sbt-jcstress" % "0.2.0") // Binary Compatibility Plugin -addSbtPlugin("com.typesafe" % "sbt-mima-plugin" % "1.1.3") +libraryDependencies += "dev.zio" %% "zio" % "2.1.13" libraryDependencies += "dev.zio" %% "zio" % "2.1.9" libraryDependencies += "dev.zio" %% "zio-json" % "0.7.3" diff --git a/zio-sbt-ecosystem/src/main/scala/zio/sbt/Versions.scala b/zio-sbt-ecosystem/src/main/scala/zio/sbt/Versions.scala index 815b9619..5da8b57a 100644 --- a/zio-sbt-ecosystem/src/main/scala/zio/sbt/Versions.scala +++ b/zio-sbt-ecosystem/src/main/scala/zio/sbt/Versions.scala @@ -26,7 +26,7 @@ object Versions { val scala212 = "2.12.20" val scala213 = "2.13.15" - val zioVersion = "2.1.9" + val zioVersion = "2.1.13" lazy val betterMonadFor: ModuleID = "com.olegpy" %% "better-monadic-for" % "0.3.1" } diff --git a/zio-sbt-githubactions/build.sbt b/zio-sbt-githubactions/build.sbt index 938d170c..f959f826 100644 --- a/zio-sbt-githubactions/build.sbt +++ b/zio-sbt-githubactions/build.sbt @@ -1,3 +1,3 @@ -libraryDependencies += "dev.zio" %% "zio" % "2.1.9" +libraryDependencies += "dev.zio" %% "zio" % "2.1.13" libraryDependencies += "dev.zio" %% "zio-json" % "0.7.3" libraryDependencies += "dev.zio" %% "zio-json-yaml" % "0.7.3" diff --git a/zio-sbt-githubactions/src/main/scala/zio/sbt/githubactions/ScalaWorkflow.scala b/zio-sbt-githubactions/src/main/scala/zio/sbt/githubactions/ScalaWorkflow.scala index f895e3cd..a8350785 100644 --- a/zio-sbt-githubactions/src/main/scala/zio/sbt/githubactions/ScalaWorkflow.scala +++ b/zio-sbt-githubactions/src/main/scala/zio/sbt/githubactions/ScalaWorkflow.scala @@ -16,8 +16,9 @@ package zio.sbt.githubactions +import scala.collection.immutable.ListMap + import zio.json._ -import zio.sbt.githubactions.ScalaWorkflow.JavaVersion.JDK11 // The original code of the githubactions package was originally copied from the zio-aws-codegen project: // https://github.com/zio/zio-aws/tree/master/zio-aws-codegen/src/main/scala/zio/aws/codegen/githubactions @@ -29,8 +30,8 @@ object ScalaWorkflow { name = "Checkout current branch", uses = Some(ActionRef("actions/checkout@v2")), `with` = Some( - Map( - "fetch-depth" -> fetchDepth.toJson + ListMap( + "fetch-depth" -> fetchDepth.toJsonAST.right.get ) ) ) @@ -40,11 +41,11 @@ object ScalaWorkflow { name = "Setup Java and Scala", uses = Some(ActionRef("olafurpg/setup-scala@v11")), `with` = Some( - Map( + ListMap( "java-version" -> (javaVersion match { case None => "${{ matrix.java }}" case Some(version) => version.asString - }) + }).toJsonAST.right.get ) ) ) @@ -54,12 +55,12 @@ object ScalaWorkflow { name = "Setup NodeJS", uses = Some(ActionRef("actions/setup-node@v3")), `with` = Some( - Map( + ListMap( "node-version" -> (javaVersion match { case None => "16.x" case Some(version) => version.asString - }), - "registry-url" -> "https://registry.npmjs.org" + }).toJsonAST.right.get, + "registry-url" -> "https://registry.npmjs.org".toJsonAST.right.get ) ) ) @@ -81,14 +82,14 @@ object ScalaWorkflow { name = "Cache SBT", uses = Some(ActionRef("actions/cache@v2")), `with` = Some( - Map( + ListMap( "path" -> Seq( "~/.ivy2/cache", "~/.sbt", "~/.coursier/cache/v1", "~/.cache/coursier/v1" - ).mkString("\n"), - "key" -> s"$osS-sbt-$scalaS-$${{ hashFiles('**/*.sbt') }}-$${{ hashFiles('**/build.properties') }}" + ).mkString("\n").toJsonAST.right.get, + "key" -> s"$osS-sbt-$scalaS-$${{ hashFiles('**/*.sbt') }}-$${{ hashFiles('**/build.properties') }}".toJsonAST.right.get ) ) ) @@ -105,7 +106,7 @@ object ScalaWorkflow { parameters: List[String], heapGb: Int = 6, stackMb: Int = 16, - env: Map[String, String] = Map.empty + env: ListMap[String, String] = ListMap.empty ): Step = SingleStep( name, @@ -138,9 +139,9 @@ object ScalaWorkflow { s"Upload $id targets", uses = Some(ActionRef("actions/upload-artifact@v2")), `with` = Some( - Map( - "name" -> s"target-$id-$osS-$scalaS-$javaS", - "path" -> "targets.tar" + ListMap( + "name" -> s"target-$id-$osS-$scalaS-$javaS".toJsonAST.right.get, + "path" -> "targets.tar".toJsonAST.right.get ) ) ) @@ -164,8 +165,8 @@ object ScalaWorkflow { s"Download stored $id targets", uses = Some(ActionRef("actions/download-artifact@v2")), `with` = Some( - Map( - "name" -> s"target-$id-$osS-$scalaS-$javaS" + ListMap( + "name" -> s"target-$id-$osS-$scalaS-$javaS".toJsonAST.right.get ) ) ), @@ -193,7 +194,7 @@ object ScalaWorkflow { SingleStep( "Load PGP secret", run = Some(".github/import-key.sh"), - env = Some(Map("PGP_SECRET" -> "${{ secrets.PGP_SECRET }}")) + env = Some(ListMap("PGP_SECRET" -> "${{ secrets.PGP_SECRET }}")) ) def turnstyle(): Step = @@ -201,7 +202,7 @@ object ScalaWorkflow { "Turnstyle", uses = Some(ActionRef("softprops/turnstyle@v1")), env = Some( - Map( + ListMap( "GITHUB_TOKEN" -> "${{ secrets.ADMIN_GITHUB_TOKEN }}" ) ) @@ -230,30 +231,39 @@ object ScalaWorkflow { case class ScalaVersion(version: String) - trait JavaVersion { - val asString: String + sealed trait JavaVersion { + def distribution: String + def version: String + def asString: String = s"$distribution:$version" } + object JavaVersion { - case class CorrettoJDK(javaVersion: String) extends JavaVersion { - override val asString: String = s"corretto:$javaVersion" + def apply(distribution: String, version: String): JavaVersion = CustomJDK(distribution, version) + + case class CustomJDK(distribution: String, version: String) extends JavaVersion + + case class CorrettoJDK(version: String) extends JavaVersion { + override def distribution: String = "corretto" } - val JDK11: JavaVersion = CorrettoJDK("11") - val JDK17: JavaVersion = CorrettoJDK("17") - val JDK21: JavaVersion = CorrettoJDK("21") + object CorrettoJDK { + val `11`: JavaVersion = CorrettoJDK("11") + val `17`: JavaVersion = CorrettoJDK("17") + val `21`: JavaVersion = CorrettoJDK("21") + } } - implicit class JobOps(job: JobValue) { + implicit class JobOps(job: Job) { def matrix( scalaVersions: Seq[ScalaVersion], operatingSystems: Seq[OS] = Seq(OS.UbuntuLatest), - javaVersions: Seq[JavaVersion] = Seq(JDK11) - ): JobValue = + javaVersions: Seq[JavaVersion] = Seq(JavaVersion.CorrettoJDK.`11`) + ): Job = job.copy( strategy = Some( Strategy( - matrix = Map( + matrix = ListMap( "os" -> operatingSystems.map(_.asString).toList, "scala" -> scalaVersions.map(_.version).toList, "java" -> javaVersions.map(_.asString).toList @@ -263,5 +273,4 @@ object ScalaWorkflow { runsOn = "${{ matrix.os }}" ) } - } diff --git a/zio-sbt-githubactions/src/main/scala/zio/sbt/githubactions/model.scala b/zio-sbt-githubactions/src/main/scala/zio/sbt/githubactions/model.scala index 96d364be..91738031 100644 --- a/zio-sbt-githubactions/src/main/scala/zio/sbt/githubactions/model.scala +++ b/zio-sbt-githubactions/src/main/scala/zio/sbt/githubactions/model.scala @@ -20,12 +20,20 @@ import scala.collection.immutable.ListMap import scala.util.{Failure, Success, Try} import zio.json._ +import zio.json.ast.Json -sealed trait OS { - val asString: String +abstract class OS(name: String) { + val asString: String = name } object OS { - case object UbuntuLatest extends OS { val asString = "ubuntu-latest" } + + def apply(name: String): OS = Custom(name) + + case class Custom(name: String) extends OS(name) + + case object UbuntuLatest extends OS("ubuntu-latest") + case object Ubuntu2404 extends OS("ubuntu-24.04") + case object Ubuntu2204 extends OS("ubuntu-22.04") } sealed trait Branch @@ -33,7 +41,7 @@ object Branch { case object All extends Branch case class Named(name: String) extends Branch - implicit val codec: JsonCodec[Branch] = JsonCodec.string.transform( + implicit lazy val codec: JsonCodec[Branch] = JsonCodec.string.transform( { case "*" => All case name => Named(name) @@ -47,22 +55,29 @@ object Branch { @jsonMemberNames(SnakeCase) case class Triggers( - workflowDispatch: Option[Triggers.WorkflowDispatch] = None, - release: Option[Triggers.Release] = None, - pullRequest: Option[Triggers.PullRequest] = None, - push: Option[Triggers.Push] = None, - create: Option[Triggers.Create] = None + workflowDispatch: Trigger.WorkflowDispatch = Trigger.WorkflowDispatch(), + release: Option[Trigger.Release] = None, + pullRequest: Option[Trigger.PullRequest] = None, + push: Option[Trigger.Push] = None, + create: Option[Trigger.Create] = None ) object Triggers { + + implicit lazy val codec: JsonCodec[Triggers] = DeriveJsonCodec.gen[Triggers] +} + +sealed trait Trigger + +object Trigger { case class InputValue(description: String, required: Boolean, default: String) object InputValue { - implicit val jsonCodec: JsonCodec[InputValue] = DeriveJsonCodec.gen[InputValue] + implicit lazy val jsonCodec: JsonCodec[InputValue] = DeriveJsonCodec.gen[InputValue] } case class WorkflowDispatch( - inputs: ListMap[String, InputValue] = ListMap.empty - ) + inputs: Option[ListMap[String, InputValue]] = None + ) extends Trigger object WorkflowDispatch { implicit def listMapCodec[K: JsonFieldDecoder: JsonFieldEncoder, V: JsonCodec]: JsonCodec[ListMap[K, V]] = @@ -71,15 +86,15 @@ object Triggers { JsonDecoder.keyValueChunk[K, V].map(c => ListMap(c: _*)) ) - implicit val jsonCodec: JsonCodec[WorkflowDispatch] = DeriveJsonCodec.gen[WorkflowDispatch] + implicit lazy val jsonCodec: JsonCodec[WorkflowDispatch] = DeriveJsonCodec.gen[WorkflowDispatch] } case class Release( types: Seq[ReleaseType] = Seq.empty - ) + ) extends Trigger object Release { - implicit val jsonCodec: JsonCodec[Release] = DeriveJsonCodec.gen[Release] + implicit lazy val jsonCodec: JsonCodec[Release] = DeriveJsonCodec.gen[Release] } sealed trait ReleaseType @@ -88,7 +103,7 @@ object Triggers { case object Published extends ReleaseType case object Prereleased extends ReleaseType - implicit val codec: JsonCodec[ReleaseType] = JsonCodec.string.transformOrFail( + implicit lazy val codec: JsonCodec[ReleaseType] = JsonCodec.string.transformOrFail( { case "created" => Right(Created) case "published" => Right(Published) @@ -109,43 +124,43 @@ object Triggers { branches: Option[Seq[Branch]] = None, branchesIgnore: Option[Seq[Branch]] = None, paths: Option[Seq[String]] = None - ) + ) extends Trigger object PullRequest { - implicit val jsonCodec: JsonCodec[PullRequest] = DeriveJsonCodec.gen[PullRequest] + implicit lazy val jsonCodec: JsonCodec[PullRequest] = DeriveJsonCodec.gen[PullRequest] } case class Push( branches: Option[Seq[Branch]] = None, branchesIgnore: Option[Seq[Branch]] = None - ) + ) extends Trigger object Push { - implicit val jsonCodec: JsonCodec[Push] = DeriveJsonCodec.gen[Push] + implicit lazy val jsonCodec: JsonCodec[Push] = DeriveJsonCodec.gen[Push] } case class Create( branches: Option[Seq[Branch]] = None, branchesIgnore: Option[Seq[Branch]] = None - ) + ) extends Trigger object Create { - implicit val jsonCodec: JsonCodec[Create] = DeriveJsonCodec.gen[Create] + implicit lazy val jsonCodec: JsonCodec[Create] = DeriveJsonCodec.gen[Create] } - - implicit val codec: JsonCodec[Triggers] = DeriveJsonCodec.gen[Triggers] } @jsonMemberNames(KebabCase) -case class Strategy(matrix: Map[String, List[String]], maxParallel: Option[Int] = None, failFast: Boolean = true) +case class Strategy(matrix: ListMap[String, List[String]], maxParallel: Option[Int] = None, failFast: Boolean = true) object Strategy { - implicit val codec: JsonCodec[Strategy] = DeriveJsonCodec.gen[Strategy] + import Workflow.listMapCodec + + implicit lazy val codec: JsonCodec[Strategy] = DeriveJsonCodec.gen[Strategy] } case class ActionRef(ref: String) object ActionRef { - implicit val codec: JsonCodec[ActionRef] = JsonCodec.string.transform(ActionRef(_), _.ref) + implicit lazy val codec: JsonCodec[ActionRef] = JsonCodec.string.transform(ActionRef(_), _.ref) } sealed trait Condition { @@ -176,7 +191,7 @@ object Condition { } object Expression { - implicit val codec: JsonCodec[Expression] = JsonCodec.string.transform(Expression(_), _.asString) + implicit lazy val codec: JsonCodec[Expression] = JsonCodec.string.transform(Expression(_), _.asString) } case class Function(expression: String) extends Condition { @@ -190,10 +205,10 @@ object Condition { } object Function { - implicit val codec: JsonCodec[Function] = JsonCodec.string.transform(Function(_), _.expression) + implicit lazy val codec: JsonCodec[Function] = JsonCodec.string.transform(Function(_), _.expression) } - implicit val codec: JsonCodec[Condition] = JsonCodec.string.transform( + implicit lazy val codec: JsonCodec[Condition] = JsonCodec.string.transform( { case expression if expression.startsWith("${{") => Expression(expression) case expression => Function(expression) @@ -212,9 +227,9 @@ object Step { id: Option[String] = None, uses: Option[ActionRef] = None, `if`: Option[Condition] = None, - `with`: Option[Map[String, String]] = None, + `with`: Option[ListMap[String, Json]] = None, run: Option[String] = None, - env: Option[Map[String, String]] = None + env: Option[ListMap[String, String]] = None ) extends Step { override def when(condition: Condition): Step = copy(`if` = Some(condition)) @@ -223,7 +238,9 @@ object Step { } object SingleStep { - implicit val codec: JsonCodec[SingleStep] = DeriveJsonCodec.gen[SingleStep] + import Workflow.listMapCodec + + implicit lazy val codec: JsonCodec[SingleStep] = DeriveJsonCodec.gen[SingleStep] } case class StepSequence(steps: Seq[Step]) extends Step { @@ -234,17 +251,17 @@ object Step { steps.flatMap(_.flatten) } - implicit val codec: JsonCodec[Step] = DeriveJsonCodec.gen[Step] + implicit lazy val codec: JsonCodec[Step] = DeriveJsonCodec.gen[Step] } case class ImageRef(ref: String) object ImageRef { - implicit val codec: JsonCodec[ImageRef] = JsonCodec.string.transform(ImageRef(_), _.ref) + implicit lazy val codec: JsonCodec[ImageRef] = JsonCodec.string.transform(ImageRef(_), _.ref) } case class ServicePort(inner: Int, outer: Int) object ServicePort { - implicit val codec: JsonCodec[ServicePort] = JsonCodec.string.transformOrFail( + implicit lazy val codec: JsonCodec[ServicePort] = JsonCodec.string.transformOrFail( v => Try(v.split(":", 2).map(_.toInt).toList) match { case Success(inner :: outer :: Nil) => Right(ServicePort(inner.toInt, outer.toInt)) @@ -258,15 +275,15 @@ object ServicePort { case class Service( name: String, image: ImageRef, - env: Map[String, String] = Map.empty, - ports: Seq[ServicePort] = Seq.empty + env: Option[Map[String, String]] = None, + ports: Option[Seq[ServicePort]] = None ) object Service { - implicit val codec: JsonCodec[Service] = DeriveJsonCodec.gen[Service] + implicit lazy val codec: JsonCodec[Service] = DeriveJsonCodec.gen[Service] } @jsonMemberNames(KebabCase) -case class JobValue( +case class Job( name: String, runsOn: String = "ubuntu-latest", timeoutMinutes: Option[Int] = None, @@ -277,22 +294,43 @@ case class JobValue( `if`: Option[Condition] = None, steps: Seq[Step.SingleStep] = Seq.empty ) { - def withStrategy(strategy: Strategy): JobValue = + + def id: String = name.toLowerCase().replace(" ", "-") + + def withStrategy(strategy: Strategy): Job = copy(strategy = Some(strategy)) - def withSteps(steps: Step*): JobValue = steps match { + def withSteps(steps: Step*): Job = steps match { case steps: Step.StepSequence => copy(steps = steps.flatten) case step: Step.SingleStep => copy(steps = step :: Nil) } - def withServices(services: Service*): JobValue = + def withServices(services: Service*): Job = copy(services = Some(services)) + + def withRunsOn(runsOn: String): Job = + copy(runsOn = runsOn) + + def withName(name: String): Job = + copy(name = name) + + def withTimeoutMinutes(timeoutMinutes: Option[Int]): Job = + copy(timeoutMinutes = timeoutMinutes) + + def withContinueOnError(continueOnError: Boolean): Job = + copy(continueOnError = continueOnError) + + def withStrategy(strategy: Option[Strategy]): Job = + copy(strategy = strategy) + + def withNeeds(needs: Option[Seq[String]]): Job = + copy(needs = needs) } -object JobValue { - implicit val codec: JsonCodec[JobValue] = DeriveJsonCodec.gen[JobValue] +object Job { + implicit lazy val codec: JsonCodec[Job] = DeriveJsonCodec.gen[Job] } @jsonMemberNames(KebabCase) @@ -302,36 +340,37 @@ case class Concurrency( ) object Concurrency { - implicit val codec: JsonCodec[Concurrency] = DeriveJsonCodec.gen[Concurrency] + implicit lazy val codec: JsonCodec[Concurrency] = DeriveJsonCodec.gen[Concurrency] } case class Workflow( name: String, - env: ListMap[String, String] = ListMap.empty, + env: Option[ListMap[String, String]] = None, on: Option[Triggers] = None, concurrency: Concurrency = Concurrency( "${{ github.workflow }}-${{ github.ref == format('refs/heads/{0}', github.event.repository.default_branch) && github.run_id || github.ref }}" ), - jobs: ListMap[String, JobValue] = ListMap.empty + jobs: ListMap[String, Job] = ListMap.empty ) { def withOn(on: Triggers): Workflow = copy(on = Some(on)) - def withJobs(jobs: (String, JobValue)*): Workflow = + def withJobs(jobs: (String, Job)*): Workflow = copy(jobs = ListMap(jobs: _*)) - def addJob(job: (String, JobValue)): Workflow = + def addJob(job: (String, Job)): Workflow = copy(jobs = jobs + job) - def addJobs(newJobs: (String, JobValue)*): Workflow = + def addJobs(newJobs: (String, Job)*): Workflow = copy(jobs = jobs ++ newJobs) } object Workflow { + implicit def listMapCodec[K: JsonFieldDecoder: JsonFieldEncoder, V: JsonCodec]: JsonCodec[ListMap[K, V]] = JsonCodec( JsonEncoder.keyValueIterable[K, V, ListMap], JsonDecoder.keyValueChunk[K, V].map(c => ListMap(c: _*)) ) - implicit val codec: JsonCodec[Workflow] = DeriveJsonCodec.gen[Workflow] + implicit lazy val codec: JsonCodec[Workflow] = DeriveJsonCodec.gen[Workflow] } diff --git a/zio-sbt-githubactions/src/main/scala/zio/sbt/githubactions/package.scala b/zio-sbt-githubactions/src/main/scala/zio/sbt/githubactions/package.scala deleted file mode 100644 index 9f1e009c..00000000 --- a/zio-sbt-githubactions/src/main/scala/zio/sbt/githubactions/package.scala +++ /dev/null @@ -1,5 +0,0 @@ -package zio.sbt - -package object githubactions { - type Job = (String, JobValue) -} diff --git a/zio-sbt-website/build.sbt b/zio-sbt-website/build.sbt index f6ebeff3..2bc7157b 100644 --- a/zio-sbt-website/build.sbt +++ b/zio-sbt-website/build.sbt @@ -2,6 +2,6 @@ addSbtPlugin("org.scalameta" % "sbt-mdoc" % "2.6.1") addSbtPlugin("com.github.sbt" % "sbt-unidoc" % "0.5.0") addSbtPlugin("com.thoughtworks.sbt-api-mappings" % "sbt-api-mappings" % "3.0.2") -libraryDependencies += "dev.zio" %% "zio" % "2.1.9" +libraryDependencies += "dev.zio" %% "zio" % "2.1.13" libraryDependencies += "dev.zio" %% "zio-json" % "0.7.3" libraryDependencies += "dev.zio" %% "zio-json-yaml" % "0.7.3" From 223d0f21c8de18a80e23bcd26cd3cf4cbb68c6f3 Mon Sep 17 00:00:00 2001 From: Thijs Broersen Date: Thu, 28 Nov 2024 23:59:25 +0100 Subject: [PATCH 3/5] restore step sequence --- zio-sbt-ci/src/main/scala/zio/sbt/ZioSbtCiPlugin.scala | 4 +--- .../src/main/scala/zio/sbt/githubactions/model.scala | 6 +++--- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/zio-sbt-ci/src/main/scala/zio/sbt/ZioSbtCiPlugin.scala b/zio-sbt-ci/src/main/scala/zio/sbt/ZioSbtCiPlugin.scala index 562fb65e..6968a010 100644 --- a/zio-sbt-ci/src/main/scala/zio/sbt/ZioSbtCiPlugin.scala +++ b/zio-sbt-ci/src/main/scala/zio/sbt/ZioSbtCiPlugin.scala @@ -110,9 +110,7 @@ object ZioSbtCiPlugin extends AutoPlugin { SetupLibuv, SetupJava(javaVersion), CacheDependencies - ) ++ checkAllCodeCompiles.flatMap(_.flatten) ++ checkArtifactBuildProcess.flatMap( - _.flatten - ) ++ checkWebsiteBuildProcess.flatMap(_.flatten) + ) ++ checkAllCodeCompiles ++ checkArtifactBuildProcess ++ checkWebsiteBuildProcess } ) ) diff --git a/zio-sbt-githubactions/src/main/scala/zio/sbt/githubactions/model.scala b/zio-sbt-githubactions/src/main/scala/zio/sbt/githubactions/model.scala index 91738031..3dd349b6 100644 --- a/zio-sbt-githubactions/src/main/scala/zio/sbt/githubactions/model.scala +++ b/zio-sbt-githubactions/src/main/scala/zio/sbt/githubactions/model.scala @@ -250,8 +250,6 @@ object Step { override def flatten: Seq[SingleStep] = steps.flatMap(_.flatten) } - - implicit lazy val codec: JsonCodec[Step] = DeriveJsonCodec.gen[Step] } case class ImageRef(ref: String) @@ -292,7 +290,7 @@ case class Job( needs: Option[Seq[String]] = None, services: Option[Seq[Service]] = None, `if`: Option[Condition] = None, - steps: Seq[Step.SingleStep] = Seq.empty + steps: Seq[Step] = Seq.empty ) { def id: String = name.toLowerCase().replace(" ", "-") @@ -330,6 +328,8 @@ case class Job( } object Job { + implicit lazy val stepsCodec: JsonCodec[Seq[Step]] = + JsonCodec.seq[Step.SingleStep].transform[Seq[Step]](identity, _.flatMap(_.flatten)) implicit lazy val codec: JsonCodec[Job] = DeriveJsonCodec.gen[Job] } From e7dec54f228a55e1136b95235154e5fcf4948c85 Mon Sep 17 00:00:00 2001 From: Thijs Broersen Date: Thu, 12 Dec 2024 16:07:44 +0100 Subject: [PATCH 4/5] add setup-sbt --- .github/workflows/ci.yml | 10 ++++++++++ zio-sbt-ci/src/main/scala/zio/sbt/V.scala | 3 ++- .../src/main/scala/zio/sbt/ZioSbtCiPlugin.scala | 14 +++++++++++++- 3 files changed, 25 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8cf9a0a4..0f898f29 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -36,6 +36,8 @@ jobs: distribution: corretto java-version: '17' check-latest: true + - name: Setup SBT + uses: sbt/setup-sbt@v1 - name: Cache Dependencies uses: coursier/cache-action@v6 - name: Check all code compiles @@ -61,6 +63,8 @@ jobs: distribution: corretto java-version: '17' check-latest: true + - name: Setup SBT + uses: sbt/setup-sbt@v1 - name: Cache Dependencies uses: coursier/cache-action@v6 - name: Check if the site workflow is up to date @@ -87,6 +91,8 @@ jobs: distribution: corretto java-version: ${{ matrix.java }} check-latest: true + - name: Setup SBT + uses: sbt/setup-sbt@v1 - name: Cache Dependencies uses: coursier/cache-action@v6 - name: Git Checkout @@ -113,6 +119,8 @@ jobs: distribution: corretto java-version: '17' check-latest: true + - name: Setup SBT + uses: sbt/setup-sbt@v1 - name: Cache Dependencies uses: coursier/cache-action@v6 - name: Generate Readme @@ -187,6 +195,8 @@ jobs: distribution: corretto java-version: '17' check-latest: true + - name: Setup SBT + uses: sbt/setup-sbt@v1 - name: Cache Dependencies uses: coursier/cache-action@v6 - name: Release diff --git a/zio-sbt-ci/src/main/scala/zio/sbt/V.scala b/zio-sbt-ci/src/main/scala/zio/sbt/V.scala index f71e1f18..770fd1a9 100644 --- a/zio-sbt-ci/src/main/scala/zio/sbt/V.scala +++ b/zio-sbt-ci/src/main/scala/zio/sbt/V.scala @@ -9,6 +9,7 @@ object V { "actions/checkout" -> "v4", "coursier/cache-action" -> "v6", "actions/setup-java" -> "v4", - "actions/setup-node" -> "v4" + "actions/setup-node" -> "v4", + "sbt/setup-sbt" -> "v1" ).map { case (k, v) => (k, s"$k@$v") }.apply(packageName) } diff --git a/zio-sbt-ci/src/main/scala/zio/sbt/ZioSbtCiPlugin.scala b/zio-sbt-ci/src/main/scala/zio/sbt/ZioSbtCiPlugin.scala index 6968a010..82ae8781 100644 --- a/zio-sbt-ci/src/main/scala/zio/sbt/ZioSbtCiPlugin.scala +++ b/zio-sbt-ci/src/main/scala/zio/sbt/ZioSbtCiPlugin.scala @@ -109,6 +109,7 @@ object ZioSbtCiPlugin extends AutoPlugin { checkout, SetupLibuv, SetupJava(javaVersion), + SetupSbt, CacheDependencies ) ++ checkAllCodeCompiles ++ checkArtifactBuildProcess ++ checkWebsiteBuildProcess } @@ -128,7 +129,8 @@ object ZioSbtCiPlugin extends AutoPlugin { Job( name = "Lint", steps = (if (swapSizeGB > 0) Seq(setSwapSpace) else Seq.empty) ++ - Seq(checkout, SetupLibuv, SetupJava(javaVersion), CacheDependencies) ++ checkGithubWorkflow.flatMap( + Seq(checkout, SetupLibuv, SetupJava(javaVersion), SetupSbt, CacheDependencies) ++ + checkGithubWorkflow.flatMap( _.flatten ) ++ Seq(lint) ) @@ -170,6 +172,7 @@ object ZioSbtCiPlugin extends AutoPlugin { (if (swapSizeGB > 0) Seq(setSwapSpace) else Seq.empty) ++ Seq( SetupLibuv, SetupJava("${{ matrix.java }}"), + SetupSbt, CacheDependencies, checkout ) ++ (if (javaPlatformMatrix.values.toSet.isEmpty) { @@ -249,6 +252,7 @@ object ZioSbtCiPlugin extends AutoPlugin { Seq( SetupLibuv, SetupJava("${{ matrix.java }}"), + SetupSbt, CacheDependencies, checkout ) ++ ( @@ -303,6 +307,7 @@ object ZioSbtCiPlugin extends AutoPlugin { Seq( SetupLibuv, SetupJava("${{ matrix.java }}"), + SetupSbt, CacheDependencies, checkout, Step.SingleStep( @@ -352,6 +357,7 @@ object ZioSbtCiPlugin extends AutoPlugin { checkout, SetupLibuv, SetupJava(javaVersion), + SetupSbt, CacheDependencies, generateReadme, Step.SingleStep( @@ -438,6 +444,7 @@ object ZioSbtCiPlugin extends AutoPlugin { checkout, SetupLibuv, SetupJava(javaVersion), + SetupSbt, CacheDependencies, release ) @@ -675,6 +682,11 @@ object ZioSbtCiPlugin extends AutoPlugin { ) ) + val SetupSbt: Step.SingleStep = Step.SingleStep( + name = "Setup SBT", + uses = Some(ActionRef(V("sbt/setup-sbt"))) + ) + lazy val CacheDependencies: Step.SingleStep = Step.SingleStep( name = "Cache Dependencies", uses = Some(ActionRef(V("coursier/cache-action"))) From 28c49c41085e63feb649539c93303604ed8abea2 Mon Sep 17 00:00:00 2001 From: Thijs Broersen Date: Fri, 13 Dec 2024 10:03:31 +0100 Subject: [PATCH 5/5] use zio-json explicitEmptyCollections --- .github/workflows/ci.yml | 1 - project/plugins.sbt | 8 +- zio-sbt-ci/build.sbt | 6 +- .../main/scala/zio/sbt/ZioSbtCiPlugin.scala | 104 ++++++++---------- zio-sbt-ecosystem/build.sbt | 8 +- zio-sbt-githubactions/build.sbt | 6 +- .../zio/sbt/githubactions/ScalaWorkflow.scala | 74 +++++-------- .../scala/zio/sbt/githubactions/model.scala | 44 +++++--- .../scala/zio/sbt/githubactions/package.scala | 8 ++ zio-sbt-website/build.sbt | 6 +- 10 files changed, 132 insertions(+), 133 deletions(-) create mode 100644 zio-sbt-githubactions/src/main/scala/zio/sbt/githubactions/package.scala diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0f898f29..4b8b32e9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -5,7 +5,6 @@ name: CI env: JDK_JAVA_OPTIONS: -XX:+PrintCommandLineFlags 'on': - workflow_dispatch: {} release: types: - published diff --git a/project/plugins.sbt b/project/plugins.sbt index 1586863d..9f1882ac 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -26,6 +26,8 @@ addSbtPlugin("org.portable-scala" % "sbt-platform-deps" % "1.0.2") addSbtPlugin("pl.project13.scala" % "sbt-jmh" % "0.4.7") libraryDependencies += "org.snakeyaml" % "snakeyaml-engine" % "2.8" -libraryDependencies += "dev.zio" %% "zio" % "2.1.9" -libraryDependencies += "dev.zio" %% "zio-json" % "0.7.3" -libraryDependencies += "dev.zio" %% "zio-json-yaml" % "0.7.3" +libraryDependencies += "dev.zio" %% "zio" % "2.1.13" +libraryDependencies += "dev.zio" %% "zio-json" % "0.7.3+19-9339fbba-SNAPSHOT" +libraryDependencies += "dev.zio" %% "zio-json-yaml" % "0.7.3+19-9339fbba-SNAPSHOT" + +resolvers ++= Resolver.sonatypeOssRepos("snapshots") diff --git a/zio-sbt-ci/build.sbt b/zio-sbt-ci/build.sbt index f959f826..aaba83b4 100644 --- a/zio-sbt-ci/build.sbt +++ b/zio-sbt-ci/build.sbt @@ -1,3 +1,5 @@ libraryDependencies += "dev.zio" %% "zio" % "2.1.13" -libraryDependencies += "dev.zio" %% "zio-json" % "0.7.3" -libraryDependencies += "dev.zio" %% "zio-json-yaml" % "0.7.3" +libraryDependencies += "dev.zio" %% "zio-json" % "0.7.3+19-9339fbba-SNAPSHOT" +libraryDependencies += "dev.zio" %% "zio-json-yaml" % "0.7.3+19-9339fbba-SNAPSHOT" + +resolvers ++= Resolver.sonatypeOssRepos("snapshots") diff --git a/zio-sbt-ci/src/main/scala/zio/sbt/ZioSbtCiPlugin.scala b/zio-sbt-ci/src/main/scala/zio/sbt/ZioSbtCiPlugin.scala index 82ae8781..9be4cb1c 100644 --- a/zio-sbt-ci/src/main/scala/zio/sbt/ZioSbtCiPlugin.scala +++ b/zio-sbt-ci/src/main/scala/zio/sbt/ZioSbtCiPlugin.scala @@ -329,7 +329,7 @@ object ZioSbtCiPlugin extends AutoPlugin { Seq( Job( name = "ci", - needs = Some(pullRequestApprovalJobs), + needs = pullRequestApprovalJobs, steps = Seq( SingleStep( name = "Report Successful CI", @@ -372,52 +372,44 @@ object ZioSbtCiPlugin extends AutoPlugin { name = "Generate Token", id = Some("generate-token"), uses = Some(ActionRef(V("zio/generate-github-app-token"))), - `with` = Some( - ListMap( - "app_id" -> "${{ secrets.APP_ID }}".toJsonAST.right.get, - "app_private_key" -> "${{ secrets.APP_PRIVATE_KEY }}".toJsonAST.right.get - ) + `with` = ListMap( + "app_id" -> "${{ secrets.APP_ID }}".toJsonAST.right.get, + "app_private_key" -> "${{ secrets.APP_PRIVATE_KEY }}".toJsonAST.right.get ) ), Step.SingleStep( name = "Create Pull Request", id = Some("cpr"), uses = Some(ActionRef(V("peter-evans/create-pull-request"))), - `with` = Some( - ListMap( - "title" -> "Update README.md".toJsonAST.right.get, - "commit-message" -> "Update README.md".toJsonAST.right.get, - "branch" -> "zio-sbt-website/update-readme".toJsonAST.right.get, - "delete-branch" -> true.toJsonAST.right.get, - "body" -> - """|Autogenerated changes after running the `sbt docs/generateReadme` command of the [zio-sbt-website](https://zio.dev/zio-sbt) plugin. - | - |I will automatically update the README.md file whenever there is new change for README.md, e.g. - | - After each release, I will update the version in the installation section. - | - After any changes to the "docs/index.md" file, I will update the README.md file accordingly.""".stripMargin.toJsonAST.right.get, - "token" -> "${{ steps.generate-token.outputs.token }}".toJsonAST.right.get - ) + `with` = ListMap( + "title" -> "Update README.md".toJsonAST.right.get, + "commit-message" -> "Update README.md".toJsonAST.right.get, + "branch" -> "zio-sbt-website/update-readme".toJsonAST.right.get, + "delete-branch" -> true.toJsonAST.right.get, + "body" -> + """|Autogenerated changes after running the `sbt docs/generateReadme` command of the [zio-sbt-website](https://zio.dev/zio-sbt) plugin. + | + |I will automatically update the README.md file whenever there is new change for README.md, e.g. + | - After each release, I will update the version in the installation section. + | - After any changes to the "docs/index.md" file, I will update the README.md file accordingly.""".stripMargin.toJsonAST.right.get, + "token" -> "${{ steps.generate-token.outputs.token }}".toJsonAST.right.get ) ), Step.SingleStep( name = "Approve PR", `if` = Some(Condition.Expression("steps.cpr.outputs.pull-request-number")), - env = Some( - ListMap( - "GITHUB_TOKEN" -> "${{ secrets.GITHUB_TOKEN }}", - "PR_URL" -> "${{ steps.cpr.outputs.pull-request-url }}" - ) + env = ListMap( + "GITHUB_TOKEN" -> "${{ secrets.GITHUB_TOKEN }}", + "PR_URL" -> "${{ steps.cpr.outputs.pull-request-url }}" ), run = Some("gh pr review \"$PR_URL\" --approve") ), Step.SingleStep( name = "Enable Auto-Merge", `if` = Some(Condition.Expression("steps.cpr.outputs.pull-request-number")), - env = Some( - ListMap( - "GITHUB_TOKEN" -> "${{ secrets.GITHUB_TOKEN }}", - "PR_URL" -> "${{ steps.cpr.outputs.pull-request-url }}" - ) + env = ListMap( + "GITHUB_TOKEN" -> "${{ secrets.GITHUB_TOKEN }}", + "PR_URL" -> "${{ steps.cpr.outputs.pull-request-url }}" ), run = Some("gh pr merge --auto --squash \"$PR_URL\" || gh pr merge --squash \"$PR_URL\"") ) @@ -437,7 +429,7 @@ object ZioSbtCiPlugin extends AutoPlugin { Seq( Job( name = "Release", - needs = Some(jobs), + needs = jobs, `if` = Some(Condition.Expression("github.event_name != 'pull_request'")), steps = (if (swapSizeGB > 0) Seq(setSwapSpace) else Seq.empty) ++ Seq( @@ -462,7 +454,7 @@ object ZioSbtCiPlugin extends AutoPlugin { Seq( Job( name = "Release Docs", - needs = Some(Seq("release")), + needs = Seq("release"), `if` = Some( Condition.Expression("github.event_name == 'release'") && Condition.Expression("github.event.action == 'published'") || Condition.Expression( @@ -481,7 +473,7 @@ object ZioSbtCiPlugin extends AutoPlugin { ), Job( name = "Notify Docs Release", - needs = Some(Seq("release-docs")), + needs = Seq("release-docs"), `if` = Some( Condition.Expression("github.event_name == 'release'") && Condition.Expression("github.event.action == 'published'") @@ -541,12 +533,12 @@ object ZioSbtCiPlugin extends AutoPlugin { val workflow = Workflow( name = workflowName, - env = Some(jvmMap ++ nodeMap), + env = jvmMap ++ nodeMap, on = Some( Triggers( release = Some(Trigger.Release(Seq(Trigger.ReleaseType.Published))), - push = Some(Trigger.Push(branches = Some(enabledBranches.map(Branch.Named)).filter(_.nonEmpty))), - pullRequest = Some(Trigger.PullRequest(branchesIgnore = Some(Seq(Branch.Named("gh-pages"))))) + push = Some(Trigger.Push(branches = enabledBranches.map(Branch.Named))).filter(_.branches.nonEmpty), + pullRequest = Some(Trigger.PullRequest(branchesIgnore = Seq(Branch.Named("gh-pages")))) ) ), jobs = ListMap( @@ -555,7 +547,9 @@ object ZioSbtCiPlugin extends AutoPlugin { ) ) - val yaml: String = workflow.toJsonAST.flatMap(_.toYaml(yamlOptions).left.map(_.getMessage())) match { + val yaml: String = zio.json.ast.Json.decoder + .decodeJson(workflow.toJson) + .flatMap(_.toYaml(yamlOptions).left.map(_.getMessage())) match { case Right(value) => value case Left(error) => sys.error(s"Error generating workflow yaml: $error") } @@ -652,7 +646,7 @@ object ZioSbtCiPlugin extends AutoPlugin { Step.SingleStep( name = "Set Swap Space", uses = Some(ActionRef(V("pierotofy/set-swap-space"))), - `with` = Some(ListMap("swap-size-gb" -> swapSizeGB.toString.toJsonAST.right.get)) + `with` = ListMap("swap-size-gb" -> swapSizeGB.toString.toJsonAST.right.get) ) } @@ -661,7 +655,7 @@ object ZioSbtCiPlugin extends AutoPlugin { Step.SingleStep( name = "Git Checkout", uses = Some(ActionRef(V("actions/checkout"))), - `with` = Some(ListMap("fetch-depth" -> "0".toJsonAST.right.get)) + `with` = ListMap("fetch-depth" -> "0".toJsonAST.right.get) ) } @@ -673,12 +667,10 @@ object ZioSbtCiPlugin extends AutoPlugin { def SetupJava(version: String = "17"): Step.SingleStep = Step.SingleStep( name = "Setup Scala", uses = Some(ActionRef(V("actions/setup-java"))), - `with` = Some( - ListMap( - "distribution" -> "corretto".toJsonAST.right.get, - "java-version" -> version.toJsonAST.right.get, - "check-latest" -> true.toJsonAST.right.get - ) + `with` = ListMap( + "distribution" -> "corretto".toJsonAST.right.get, + "java-version" -> version.toJsonAST.right.get, + "check-latest" -> true.toJsonAST.right.get ) ) @@ -723,13 +715,11 @@ object ZioSbtCiPlugin extends AutoPlugin { Step.SingleStep( name = "Release", run = Some(prefixJobs + "sbt ci-release"), - env = Some( - ListMap( - "PGP_PASSPHRASE" -> "${{ secrets.PGP_PASSPHRASE }}", - "PGP_SECRET" -> "${{ secrets.PGP_SECRET }}", - "SONATYPE_PASSWORD" -> "${{ secrets.SONATYPE_PASSWORD }}", - "SONATYPE_USERNAME" -> "${{ secrets.SONATYPE_USERNAME }}" - ) + env = ListMap( + "PGP_PASSPHRASE" -> "${{ secrets.PGP_PASSPHRASE }}", + "PGP_SECRET" -> "${{ secrets.PGP_SECRET }}", + "SONATYPE_PASSWORD" -> "${{ secrets.SONATYPE_PASSWORD }}", + "SONATYPE_USERNAME" -> "${{ secrets.SONATYPE_USERNAME }}" ) ) } @@ -737,11 +727,9 @@ object ZioSbtCiPlugin extends AutoPlugin { val SetupNodeJs: Step.SingleStep = Step.SingleStep( name = "Setup NodeJs", uses = Some(ActionRef(V("actions/setup-node"))), - `with` = Some( - ListMap( - "node-version" -> "16.x".toJsonAST.right.get, - "registry-url" -> "https://registry.npmjs.org".toJsonAST.right.get - ) + `with` = ListMap( + "node-version" -> "16.x".toJsonAST.right.get, + "registry-url" -> "https://registry.npmjs.org".toJsonAST.right.get ) ) @@ -754,7 +742,7 @@ object ZioSbtCiPlugin extends AutoPlugin { Step.SingleStep( name = "Publish Docs to NPM Registry", run = Some(prefixJobs + s"sbt docs/${docsVersioning.npmCommand}"), - env = Some(ListMap("NODE_AUTH_TOKEN" -> "${{ secrets.NPM_TOKEN }}")) + env = ListMap("NODE_AUTH_TOKEN" -> "${{ secrets.NPM_TOKEN }}") ) } diff --git a/zio-sbt-ecosystem/build.sbt b/zio-sbt-ecosystem/build.sbt index 3cf71721..87193342 100644 --- a/zio-sbt-ecosystem/build.sbt +++ b/zio-sbt-ecosystem/build.sbt @@ -29,6 +29,8 @@ addSbtPlugin("pl.project13.scala" % "sbt-jcstress" % "0.2.0") // Binary Compatibility Plugin libraryDependencies += "dev.zio" %% "zio" % "2.1.13" -libraryDependencies += "dev.zio" %% "zio" % "2.1.9" -libraryDependencies += "dev.zio" %% "zio-json" % "0.7.3" -libraryDependencies += "dev.zio" %% "zio-json-yaml" % "0.7.3" +libraryDependencies += "dev.zio" %% "zio" % "2.1.13" +libraryDependencies += "dev.zio" %% "zio-json" % "0.7.3+19-9339fbba-SNAPSHOT" +libraryDependencies += "dev.zio" %% "zio-json-yaml" % "0.7.3+19-9339fbba-SNAPSHOT" + +resolvers ++= Resolver.sonatypeOssRepos("snapshots") diff --git a/zio-sbt-githubactions/build.sbt b/zio-sbt-githubactions/build.sbt index f959f826..aaba83b4 100644 --- a/zio-sbt-githubactions/build.sbt +++ b/zio-sbt-githubactions/build.sbt @@ -1,3 +1,5 @@ libraryDependencies += "dev.zio" %% "zio" % "2.1.13" -libraryDependencies += "dev.zio" %% "zio-json" % "0.7.3" -libraryDependencies += "dev.zio" %% "zio-json-yaml" % "0.7.3" +libraryDependencies += "dev.zio" %% "zio-json" % "0.7.3+19-9339fbba-SNAPSHOT" +libraryDependencies += "dev.zio" %% "zio-json-yaml" % "0.7.3+19-9339fbba-SNAPSHOT" + +resolvers ++= Resolver.sonatypeOssRepos("snapshots") diff --git a/zio-sbt-githubactions/src/main/scala/zio/sbt/githubactions/ScalaWorkflow.scala b/zio-sbt-githubactions/src/main/scala/zio/sbt/githubactions/ScalaWorkflow.scala index a8350785..f8a99987 100644 --- a/zio-sbt-githubactions/src/main/scala/zio/sbt/githubactions/ScalaWorkflow.scala +++ b/zio-sbt-githubactions/src/main/scala/zio/sbt/githubactions/ScalaWorkflow.scala @@ -29,10 +29,8 @@ object ScalaWorkflow { SingleStep( name = "Checkout current branch", uses = Some(ActionRef("actions/checkout@v2")), - `with` = Some( - ListMap( - "fetch-depth" -> fetchDepth.toJsonAST.right.get - ) + `with` = ListMap( + "fetch-depth" -> fetchDepth.toJsonAST.right.get ) ) @@ -40,13 +38,11 @@ object ScalaWorkflow { SingleStep( name = "Setup Java and Scala", uses = Some(ActionRef("olafurpg/setup-scala@v11")), - `with` = Some( - ListMap( - "java-version" -> (javaVersion match { - case None => "${{ matrix.java }}" - case Some(version) => version.asString - }).toJsonAST.right.get - ) + `with` = ListMap( + "java-version" -> (javaVersion match { + case None => "${{ matrix.java }}" + case Some(version) => version.asString + }).toJsonAST.right.get ) ) @@ -54,14 +50,12 @@ object ScalaWorkflow { SingleStep( name = "Setup NodeJS", uses = Some(ActionRef("actions/setup-node@v3")), - `with` = Some( - ListMap( - "node-version" -> (javaVersion match { - case None => "16.x" - case Some(version) => version.asString - }).toJsonAST.right.get, - "registry-url" -> "https://registry.npmjs.org".toJsonAST.right.get - ) + `with` = ListMap( + "node-version" -> (javaVersion match { + case None => "16.x" + case Some(version) => version.asString + }).toJsonAST.right.get, + "registry-url" -> "https://registry.npmjs.org".toJsonAST.right.get ) ) @@ -81,16 +75,14 @@ object ScalaWorkflow { SingleStep( name = "Cache SBT", uses = Some(ActionRef("actions/cache@v2")), - `with` = Some( - ListMap( - "path" -> Seq( - "~/.ivy2/cache", - "~/.sbt", - "~/.coursier/cache/v1", - "~/.cache/coursier/v1" - ).mkString("\n").toJsonAST.right.get, - "key" -> s"$osS-sbt-$scalaS-$${{ hashFiles('**/*.sbt') }}-$${{ hashFiles('**/build.properties') }}".toJsonAST.right.get - ) + `with` = ListMap( + "path" -> Seq( + "~/.ivy2/cache", + "~/.sbt", + "~/.coursier/cache/v1", + "~/.cache/coursier/v1" + ).mkString("\n").toJsonAST.right.get, + "key" -> s"$osS-sbt-$scalaS-$${{ hashFiles('**/*.sbt') }}-$${{ hashFiles('**/build.properties') }}".toJsonAST.right.get ) ) } @@ -113,7 +105,7 @@ object ScalaWorkflow { run = Some( s"sbt -J-XX:+UseG1GC -J-Xmx${heapGb}g -J-Xms${heapGb}g -J-Xss${stackMb}m ${parameters.mkString(" ")}" ), - env = Some(env).filter(_.nonEmpty) + env = env ) def storeTargets( @@ -138,11 +130,9 @@ object ScalaWorkflow { SingleStep( s"Upload $id targets", uses = Some(ActionRef("actions/upload-artifact@v2")), - `with` = Some( - ListMap( - "name" -> s"target-$id-$osS-$scalaS-$javaS".toJsonAST.right.get, - "path" -> "targets.tar".toJsonAST.right.get - ) + `with` = ListMap( + "name" -> s"target-$id-$osS-$scalaS-$javaS".toJsonAST.right.get, + "path" -> "targets.tar".toJsonAST.right.get ) ) ) @@ -164,10 +154,8 @@ object ScalaWorkflow { SingleStep( s"Download stored $id targets", uses = Some(ActionRef("actions/download-artifact@v2")), - `with` = Some( - ListMap( - "name" -> s"target-$id-$osS-$scalaS-$javaS".toJsonAST.right.get - ) + `with` = ListMap( + "name" -> s"target-$id-$osS-$scalaS-$javaS".toJsonAST.right.get ) ), SingleStep( @@ -194,17 +182,15 @@ object ScalaWorkflow { SingleStep( "Load PGP secret", run = Some(".github/import-key.sh"), - env = Some(ListMap("PGP_SECRET" -> "${{ secrets.PGP_SECRET }}")) + env = ListMap("PGP_SECRET" -> "${{ secrets.PGP_SECRET }}") ) def turnstyle(): Step = SingleStep( "Turnstyle", uses = Some(ActionRef("softprops/turnstyle@v1")), - env = Some( - ListMap( - "GITHUB_TOKEN" -> "${{ secrets.ADMIN_GITHUB_TOKEN }}" - ) + env = ListMap( + "GITHUB_TOKEN" -> "${{ secrets.ADMIN_GITHUB_TOKEN }}" ) ) diff --git a/zio-sbt-githubactions/src/main/scala/zio/sbt/githubactions/model.scala b/zio-sbt-githubactions/src/main/scala/zio/sbt/githubactions/model.scala index 3dd349b6..026836aa 100644 --- a/zio-sbt-githubactions/src/main/scala/zio/sbt/githubactions/model.scala +++ b/zio-sbt-githubactions/src/main/scala/zio/sbt/githubactions/model.scala @@ -76,7 +76,7 @@ object Trigger { } case class WorkflowDispatch( - inputs: Option[ListMap[String, InputValue]] = None + inputs: ListMap[String, InputValue] = ListMap.empty ) extends Trigger object WorkflowDispatch { @@ -120,10 +120,10 @@ object Trigger { @jsonMemberNames(KebabCase) case class PullRequest( - // types: Option[Seq[PullRequestType]] = None, - branches: Option[Seq[Branch]] = None, - branchesIgnore: Option[Seq[Branch]] = None, - paths: Option[Seq[String]] = None + // types: Seq[PullRequestType] = Seq.empty, + branches: Seq[Branch] = Seq.empty, + branchesIgnore: Seq[Branch] = Seq.empty, + paths: Seq[String] = Seq.empty ) extends Trigger object PullRequest { @@ -131,8 +131,8 @@ object Trigger { } case class Push( - branches: Option[Seq[Branch]] = None, - branchesIgnore: Option[Seq[Branch]] = None + branches: Seq[Branch] = Seq.empty, + branchesIgnore: Seq[Branch] = Seq.empty ) extends Trigger object Push { @@ -140,8 +140,8 @@ object Trigger { } case class Create( - branches: Option[Seq[Branch]] = None, - branchesIgnore: Option[Seq[Branch]] = None + branches: Seq[Branch] = Seq.empty, + branchesIgnore: Seq[Branch] = Seq.empty ) extends Trigger object Create { @@ -227,10 +227,14 @@ object Step { id: Option[String] = None, uses: Option[ActionRef] = None, `if`: Option[Condition] = None, - `with`: Option[ListMap[String, Json]] = None, + `with`: ListMap[String, Json] = ListMap.empty, run: Option[String] = None, - env: Option[ListMap[String, String]] = None + env: ListMap[String, String] = ListMap.empty ) extends Step { + + @deprecated("Use `if` instead", "0.4.0-alpha.29") + def condition: Option[Condition] = `if` + override def when(condition: Condition): Step = copy(`if` = Some(condition)) @@ -273,8 +277,8 @@ object ServicePort { case class Service( name: String, image: ImageRef, - env: Option[Map[String, String]] = None, - ports: Option[Seq[ServicePort]] = None + env: Map[String, String] = Map.empty, + ports: Seq[ServicePort] = Seq.empty ) object Service { implicit lazy val codec: JsonCodec[Service] = DeriveJsonCodec.gen[Service] @@ -287,14 +291,17 @@ case class Job( timeoutMinutes: Option[Int] = None, continueOnError: Boolean = false, strategy: Option[Strategy] = None, - needs: Option[Seq[String]] = None, - services: Option[Seq[Service]] = None, + needs: Seq[String] = Seq.empty, + services: Seq[Service] = Seq.empty, `if`: Option[Condition] = None, steps: Seq[Step] = Seq.empty ) { def id: String = name.toLowerCase().replace(" ", "-") + @deprecated("Use `if` instead", "0.4.0-alpha.29") + def condition: Option[Condition] = `if` + def withStrategy(strategy: Strategy): Job = copy(strategy = Some(strategy)) @@ -306,7 +313,7 @@ case class Job( } def withServices(services: Service*): Job = - copy(services = Some(services)) + copy(services = services) def withRunsOn(runsOn: String): Job = copy(runsOn = runsOn) @@ -323,7 +330,7 @@ case class Job( def withStrategy(strategy: Option[Strategy]): Job = copy(strategy = strategy) - def withNeeds(needs: Option[Seq[String]]): Job = + def withNeeds(needs: Seq[String]): Job = copy(needs = needs) } @@ -331,6 +338,7 @@ object Job { implicit lazy val stepsCodec: JsonCodec[Seq[Step]] = JsonCodec.seq[Step.SingleStep].transform[Seq[Step]](identity, _.flatMap(_.flatten)) implicit lazy val codec: JsonCodec[Job] = DeriveJsonCodec.gen[Job] + } @jsonMemberNames(KebabCase) @@ -345,7 +353,7 @@ object Concurrency { case class Workflow( name: String, - env: Option[ListMap[String, String]] = None, + env: ListMap[String, String] = ListMap.empty, on: Option[Triggers] = None, concurrency: Concurrency = Concurrency( "${{ github.workflow }}-${{ github.ref == format('refs/heads/{0}', github.event.repository.default_branch) && github.run_id || github.ref }}" diff --git a/zio-sbt-githubactions/src/main/scala/zio/sbt/githubactions/package.scala b/zio-sbt-githubactions/src/main/scala/zio/sbt/githubactions/package.scala new file mode 100644 index 00000000..112f9c6b --- /dev/null +++ b/zio-sbt-githubactions/src/main/scala/zio/sbt/githubactions/package.scala @@ -0,0 +1,8 @@ +package zio.sbt + +import zio.json.JsonCodecConfiguration + +package object githubactions { + implicit val jsonConfig: JsonCodecConfiguration = + JsonCodecConfiguration.default.copy(explicitEmptyCollections = false) +} diff --git a/zio-sbt-website/build.sbt b/zio-sbt-website/build.sbt index 2bc7157b..a899ecea 100644 --- a/zio-sbt-website/build.sbt +++ b/zio-sbt-website/build.sbt @@ -3,5 +3,7 @@ addSbtPlugin("com.github.sbt" % "sbt-unidoc" % "0.5.0") addSbtPlugin("com.thoughtworks.sbt-api-mappings" % "sbt-api-mappings" % "3.0.2") libraryDependencies += "dev.zio" %% "zio" % "2.1.13" -libraryDependencies += "dev.zio" %% "zio-json" % "0.7.3" -libraryDependencies += "dev.zio" %% "zio-json-yaml" % "0.7.3" +libraryDependencies += "dev.zio" %% "zio-json" % "0.7.3+19-9339fbba-SNAPSHOT" +libraryDependencies += "dev.zio" %% "zio-json-yaml" % "0.7.3+19-9339fbba-SNAPSHOT" + +resolvers ++= Resolver.sonatypeOssRepos("snapshots")