From 2f495f7495b22ee8258efe59f3fb9f8fe0289c78 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alejandro=20Herna=CC=81ndez?= Date: Tue, 22 Nov 2022 08:48:06 +0100 Subject: [PATCH] Initial commit --- .github/CODEOWNERS | 1 + .github/release.yml | 28 +++ .github/workflows/ci.yml | 78 +++++++ .github/workflows/main.yml | 27 +++ .github/workflows/release.yml | 84 ++++++++ .gitignore | 89 ++++++++ LICENSE.md | 201 ++++++++++++++++++ README.md | 36 ++++ build.sbt | 17 ++ docs/LICENSE.md | 201 ++++++++++++++++++ docs/README.md | 34 +++ .../munit/SbtScriptedMUnitPlugin.scala | 119 +++++++++++ .../sbt-scripted-munit/fail/build.sbt | 7 + .../fail/project/build.properties | 1 + .../fail/project/plugins.sbt | 1 + .../src/sbt-test/sbt-scripted-munit/fail/test | 1 + .../sbt-scripted-munit/simple/build.sbt | 19 ++ .../simple/project/build.properties | 1 + .../simple/project/plugins.sbt | 1 + .../sbt-test/sbt-scripted-munit/simple/test | 1 + project/build.properties | 1 + project/plugins.sbt | 15 ++ 22 files changed, 963 insertions(+) create mode 100644 .github/CODEOWNERS create mode 100644 .github/release.yml create mode 100644 .github/workflows/ci.yml create mode 100644 .github/workflows/main.yml create mode 100644 .github/workflows/release.yml create mode 100644 .gitignore create mode 100644 LICENSE.md create mode 100644 README.md create mode 100644 build.sbt create mode 100644 docs/LICENSE.md create mode 100644 docs/README.md create mode 100644 modules/sbt-scripted-munit/src/main/scala/com/alejandrohdezma/sbt/scripted/munit/SbtScriptedMUnitPlugin.scala create mode 100644 modules/sbt-scripted-munit/src/sbt-test/sbt-scripted-munit/fail/build.sbt create mode 100644 modules/sbt-scripted-munit/src/sbt-test/sbt-scripted-munit/fail/project/build.properties create mode 100644 modules/sbt-scripted-munit/src/sbt-test/sbt-scripted-munit/fail/project/plugins.sbt create mode 100644 modules/sbt-scripted-munit/src/sbt-test/sbt-scripted-munit/fail/test create mode 100644 modules/sbt-scripted-munit/src/sbt-test/sbt-scripted-munit/simple/build.sbt create mode 100644 modules/sbt-scripted-munit/src/sbt-test/sbt-scripted-munit/simple/project/build.properties create mode 100644 modules/sbt-scripted-munit/src/sbt-test/sbt-scripted-munit/simple/project/plugins.sbt create mode 100644 modules/sbt-scripted-munit/src/sbt-test/sbt-scripted-munit/simple/test create mode 100644 project/build.properties create mode 100644 project/plugins.sbt diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 0000000..41b8f25 --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1 @@ +* @alejandrohdezma diff --git a/.github/release.yml b/.github/release.yml new file mode 100644 index 0000000..4e3e809 --- /dev/null +++ b/.github/release.yml @@ -0,0 +1,28 @@ +# Don't edit this file! +# It is automatically updated after every release of https://github.com/alejandrohdezma/sbt-ci +# If you want to suggest a change, please open a PR or issue in that repository + +# This file contains the template for the "auto-generated release notes" + +changelog: + exclude: + labels: + - ":chart_with_upwards_trend: dependency-update" + authors: + - alejandrohdezma-steward + categories: + - title: "⚠️ Breaking changes" + labels: + - ":warning: breaking" + - title: "🚀 New features" + labels: + - ":rocket: feature" + - title: "📘 Documentation updates" + labels: + - ":blue_book: documentation" + - title: "🐛 Bug fixes" + labels: + - ":beetle: bug" + - title: Other Changes + labels: + - "*" diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..0fd2a70 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,78 @@ +# Don't edit this file! +# It is automatically updated after every release of https://github.com/alejandrohdezma/sbt-ci +# If you want to suggest a change, please open a PR or issue in that repository + +# Runs `sbt ci-test` on the project on differnt JDKs (this task should be added to the project as a command alias +# containing the necessary steps to compile, check formatters, launch tests...). +# +# An example of this `ci-test` alias can be found in https://github.com/alejandrohdezma/sbt-github/blob/main/build.sbt. +# +# It will also do the following: +# +# - It will automatically label PRs based on head branch. +# - It will automatically enable auto-merge on `Scala Steward` PRs. + +name: CI (PR) + +on: + pull_request: + types: [opened, reopened, labeled, unlabeled, synchronize] + +jobs: + labeler: + if: github.event.pull_request.state == 'OPEN' && github.actor != 'dependabot[bot]' + name: Labeler + runs-on: ubuntu-latest + steps: + - name: Update PR labels + uses: alejandrohdezma/actions/labeler@v1 + if: github.event.pull_request.head.repo.full_name == github.repository + + - name: Check PR labels + uses: alejandrohdezma/actions/label-check@v1 + + ci-steward: + if: | + github.event.pull_request.state == 'OPEN' && github.event.pull_request.head.repo.full_name == github.repository && + github.event.pull_request.user.login == 'alejandrohdezma-steward[bot]' + name: (Scala Steward) Enable auto-merge + runs-on: ubuntu-latest + steps: + - name: Get the GitHub App installation token + uses: alejandrohdezma/actions/github-app-token@v1 + id: github_app + with: + token: ${{ secrets.GH_APP_TOKEN }} + + - name: Enable auto-merge for this PR + run: gh pr merge --auto --merge ${{github.event.pull_request.number}} -R "$GITHUB_REPOSITORY" + env: + GITHUB_TOKEN: ${{ steps.github_app.outputs.token }} + + test: + needs: [ci-steward] + if: | + always() && !contains(needs.*.result, 'failure') && github.event.pull_request.state == 'OPEN' && + github.actor != 'dependabot[bot]' + name: Run "sbt ci-test" on JDK ${{ matrix.jdk }} + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + jdk: + - 11 + - 17 + steps: + - name: Checkout project + uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 # v3.1.0 + with: + ref: ${{ github.head_ref }} + + - uses: actions/setup-java@de1bb2b0c5634f0fc4438d7aa9944e68f9bf86cc # v3.6.0 + with: + distribution: "liberica" + java-version: ${{ matrix.jdk }} + cache: "sbt" + + - name: Run `sbt ci-test` + run: sbt ci-test diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml new file mode 100644 index 0000000..8c7ed20 --- /dev/null +++ b/.github/workflows/main.yml @@ -0,0 +1,27 @@ +# Don't edit this file! +# It is automatically updated after every release of https://github.com/alejandrohdezma/sbt-ci +# If you want to suggest a change, please open a PR or issue in that repository + +# This workflow will update PRs that are out-of-sync with the `main` branch. + +name: CI (main) + +on: + push: + branches: [main] + +jobs: + auto-update-outdated-prs-to-latest-main: + name: Update outdated PRs to latest `main` + runs-on: ubuntu-latest + steps: + - name: Get the GitHub App installation token + uses: alejandrohdezma/actions/github-app-token@v1 + id: github_app + with: + token: ${{ secrets.GH_APP_TOKEN }} + + - name: Update outdated PRs to latest `main` + uses: alejandrohdezma/actions/update-outdated-prs@v1 + with: + github-token: ${{ steps.github_app.outputs.token }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..d42e43e --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,84 @@ +# Don't edit this file! +# It is automatically updated after every release of https://github.com/alejandrohdezma/sbt-ci +# If you want to suggest a change, please open a PR or issue in that repository + +# This workflow performs two tasks: +# +# - Creates a release of the project by running `sbt ci-publish` (this task should be added to the project as a command +# alias containing the necessary steps to do a release). An example of the `ci-publish` alias can be found in +# https://github.com/alejandrohdezma/sbt-github/blob/main/build.sbt. +# +# - Runs `sbt ci-docs` on the project and pushes a commit with the changes (the `ci-docs` task should be added to the +# project as a command alias containing the necessary steps to update documentation: re-generate docs files, +# publish websites, update headers...). An example of the `ci-docs` alias can be found in +# https://github.com/alejandrohdezma/sbt-github/blob/main/build.sbt. +# +# This workflow will launch on pushed tags. Alternatively one can launch it manually using a "workflow dispatch" to +# create a snapshot release (this won't trigger the documentation update). + +name: Release + +on: + push: + tags: [v*] + workflow_dispatch: + +jobs: + release: + name: Release a new version of the artifact + runs-on: ubuntu-latest + steps: + - name: Checkout project + uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 # v3.1.0 + with: + fetch-depth: 0 + + - name: Check latest tag follows semantic versioning + if: github.event_name == 'push' + uses: alejandrohdezma/actions/check-semver-tag@v1 + + - uses: actions/setup-java@de1bb2b0c5634f0fc4438d7aa9944e68f9bf86cc # v3.6.0 + with: + distribution: "liberica" + java-version: "11" + cache: "sbt" + + - name: Run `sbt ci-publish` + run: sbt ci-publish + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + PGP_PASSPHRASE: ${{ secrets.PGP_PASSPHRASE }} + PGP_SECRET: ${{ secrets.PGP_SECRET }} + SONATYPE_PASSWORD: ${{ secrets.SONATYPE_PASSWORD }} + SONATYPE_USERNAME: ${{ secrets.SONATYPE_USERNAME }} + + documentation: + needs: [release] + name: Updates documentation after latest release + if: github.event_name == 'push' + runs-on: ubuntu-latest + steps: + - name: Checkout project + uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 # v3.1.0 + with: + fetch-depth: 0 + ref: main + token: ${{ secrets.ADMIN_GITHUB_TOKEN }} + + - uses: actions/setup-java@de1bb2b0c5634f0fc4438d7aa9944e68f9bf86cc # v3.6.0 + with: + distribution: "liberica" + java-version: "17" + cache: "sbt" + + - name: Run `sbt ci-docs` + run: sbt ci-docs + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GIT_DEPLOY_KEY: ${{ secrets.GIT_DEPLOY_KEY }} + + - name: Commit changes by `sbt ci-docs` + uses: alejandrohdezma/actions/commit-and-push@v1 + with: + message: Run `sbt ci-docs` [skip ci] + branch: main diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c7fe899 --- /dev/null +++ b/.gitignore @@ -0,0 +1,89 @@ +# Don't edit this file! +# It is automatically updated after every release of https://github.com/alejandrohdezma/sbt-ci +# If you want to suggest a change, please open a PR or issue in that repository + +# Default .gitignore for the project. + +### Intellij ### + +.idea +out/ + +### Java ### + +*.class +*.log + +### macOS ### + +.DS_Store + +### SBT ### + +dist/* +target/ +lib_managed/ +src_managed/ +project/boot/ +project/plugins/project/ +.history +.cache +.lib/ + +### Scala ### + +.bloop/ +**/.bloop/ +project/.bloop/ +.bsp +*.metals +.metals/ +**/metals.sbt +project/metals.sbt + +### Vim ### + +# Swap +[._]*.s[a-v][a-z] +[._]*.sw[a-p] +[._]s[a-rt-v][a-z] +[._]ss[a-gi-z] +[._]sw[a-p] + +# Session +Session.vim +Sessionx.vim + +# Temporary +.netrwhist + +# Auto-generated tag files +tags + +# Persistent undo +[._]*.un~ + +# Coc configuration directory +.vim + +### VisualStudioCode ### + +.vscode + +### Docusaurus ### + +.docusaurus +node_modules +website/build + +### sbt-scalafix-defaults ### +# Scalafix configuration file is automatically downloaded by `sbt-scalafix-defaults` +# https://github.com/alejandrohdezma/sbt-scalafix-defaults + +.scalafix.conf + +### sbt-scalafmt-defaults ### +# Scalafmt configuration file is automatically downloaded by `sbt-scalafmt-defaults` +# https://github.com/alejandrohdezma/sbt-scalafmt-defaults + +.scalafmt.conf diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 0000000..1f5cbf7 --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright (C) 2022 Alejandro Hernández + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..b6e8b50 --- /dev/null +++ b/README.md @@ -0,0 +1,36 @@ +SBT plugin to enable using MUnit to test your SBT plugins + +## Usage + +Create a scripted test for your SBT plugin following the +[official guide](https://www.scala-sbt.org/1.x/docs/Testing-sbt-plugins.html). + +Add the following line to the `plugins.sbt` file of your scripted test: + +```sbt +addSbtPlugin("com.alejandrohdezma" % "sbt-scripted-munit" % "0.0.0") +``` + +Add some tests to `build.sbt`: + +```scala +munitSuites += "MySuite" -> new FunSuite { + + test("The most important question") { + assertEquals("The meaning of life, the universe and everything else", "42") + } + +} +``` + +Add this to your `test` file so MUnit suites are executed: + +``` +> munitScripted +``` + +## Contributors to this project + +| alejandrohdezma | +| :--: | +| alejandrohdezma | diff --git a/build.sbt b/build.sbt new file mode 100644 index 0000000..d60a82a --- /dev/null +++ b/build.sbt @@ -0,0 +1,17 @@ +ThisBuild / scalaVersion := _root_.scalafix.sbt.BuildInfo.scala212 +ThisBuild / organization := "com.alejandrohdezma" +ThisBuild / pluginCrossBuild / sbtVersion := "1.2.8" + +addCommandAlias("ci-test", "fix --check; mdoc; scripted") +addCommandAlias("ci-docs", "github; mdoc; headerCreateAll") +addCommandAlias("ci-publish", "github; ci-release") + +lazy val documentation = project + .enablePlugins(MdocPlugin) + .settings(mdocOut := file(".")) + +lazy val `sbt-scripted-munit` = module + .settings(libraryDependencies += "org.scalameta" %% "munit" % "0.7.29") + .enablePlugins(SbtPlugin) + .settings(scriptedBufferLog := false) + .settings(scriptedLaunchOpts += s"-Dplugin.version=${version.value}") diff --git a/docs/LICENSE.md b/docs/LICENSE.md new file mode 100644 index 0000000..76b6d4e --- /dev/null +++ b/docs/LICENSE.md @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright (C) @YEAR_RANGE@ @COPYRIGHT_OWNER@ + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. \ No newline at end of file diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 0000000..89dfc80 --- /dev/null +++ b/docs/README.md @@ -0,0 +1,34 @@ +@DESCRIPTION@ + +## Usage + +Create a scripted test for your SBT plugin following the +[official guide](https://www.scala-sbt.org/1.x/docs/Testing-sbt-plugins.html). + +Add the following line to the `plugins.sbt` file of your scripted test: + +```sbt +addSbtPlugin("@ORGANIZATION@" % "@NAME@" % "@VERSION@") +``` + +Add some tests to `build.sbt`: + +```scala +munitSuites += "MySuite" -> new FunSuite { + + test("The most important question") { + assertEquals("The meaning of life, the universe and everything else", "42") + } + +} +``` + +Add this to your `test` file so MUnit suites are executed: + +``` +> munitScripted +``` + +## Contributors to this project + +@CONTRIBUTORS_TABLE@ diff --git a/modules/sbt-scripted-munit/src/main/scala/com/alejandrohdezma/sbt/scripted/munit/SbtScriptedMUnitPlugin.scala b/modules/sbt-scripted-munit/src/main/scala/com/alejandrohdezma/sbt/scripted/munit/SbtScriptedMUnitPlugin.scala new file mode 100644 index 0000000..ccf471b --- /dev/null +++ b/modules/sbt-scripted-munit/src/main/scala/com/alejandrohdezma/sbt/scripted/munit/SbtScriptedMUnitPlugin.scala @@ -0,0 +1,119 @@ +/* + * Copyright 2022 Alejandro Hernández + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.alejandrohdezma.sbt.scripted.munit + +import java.util.concurrent.atomic.AtomicBoolean + +import scala.Console +import scala.util.control.NoStackTrace + +import sbt.AutoPlugin +import sbt.Keys._ +import sbt.Setting +import sbt.settingKey +import sbt.taskKey +import sbt.testing.Event +import sbt.testing.EventHandler +import sbt.testing.Status +import sbt.testing.TaskDef + +import munit._ + +object SbtScriptedMUnitPlugin extends AutoPlugin { + + case object TestsFailed extends RuntimeException("Some tests failed") with NoStackTrace + + object autoImport { + + type FunSuite = munit.FunSuite + + type Assertions = munit.Assertions + + val Assertions = munit.Assertions + + type FunFixtures = munit.FunFixtures + + type Tag = munit.Tag + + val munitSuites = settingKey[Seq[(String, Suite)]] { + "The list of suites to test as name-suite pairs" + } + + val munitScripted = taskKey[Unit] { + "Executes the suites in `munitSuites`" + } + + } + + import autoImport._ + + override def trigger = allRequirements + + override def projectSettings: Seq[Setting[_]] = Seq( + munitSuites := Nil, + munitScripted := { + val framework = new Framework + + val testsFailed = new AtomicBoolean(false) + + val logger = streams.value.log + + val eventHandler: EventHandler = { + case event if event.isFailure => + testsFailed.set(true) + logger.error(s" ${Console.RED}==> X ${event.name} ${Console.RESET} ${event.failure.getOrElse("")}") + case event if event.isIgnored => + logger.warn(s" ${Console.YELLOW}==> i ${event.name} ${Console.RESET}") + case event => + logger.info(s" ${Console.GREEN}+ ${event.name} ${Console.RESET}") + } + + munitSuites.value.foreach { case (name, suite) => + val runner = framework.runner(Array("+l"), Array.empty, suite.getClass().getClassLoader()) + val taskDef = new TaskDef(suite.getClass().getName(), framework.munitFingerprint, false, Array.empty) + val tasks = runner.tasks(Array(taskDef)) + + logger.info(s"${Console.GREEN}$name:${Console.RESET}") + tasks.foreach(_.execute(eventHandler, Array.empty)) + } + + if (testsFailed.get()) throw TestsFailed // scalafix:ok + } + ) + + implicit private class EventOps(event: Event) { + + val failure: Option[String] = + if (event.throwable().isDefined) Some(event.throwable().get().toString) // scalafix:ok + else None + + val isFailure: Boolean = event.status() match { + case Status.Error | Status.Failure | Status.Canceled | Status.Pending => true + case _ => false + } + + val isIgnored: Boolean = event.status() match { + case Status.Ignored | Status.Skipped => true + case _ => false + } + + val name: String = + event.fullyQualifiedName().replaceAll(""".*\$\$anon\$\d+\.""", "") + + } + +} diff --git a/modules/sbt-scripted-munit/src/sbt-test/sbt-scripted-munit/fail/build.sbt b/modules/sbt-scripted-munit/src/sbt-test/sbt-scripted-munit/fail/build.sbt new file mode 100644 index 0000000..b442675 --- /dev/null +++ b/modules/sbt-scripted-munit/src/sbt-test/sbt-scripted-munit/fail/build.sbt @@ -0,0 +1,7 @@ +munitSuites += "MySuite" -> new FunSuite { + + test("This test fails") { + assertEquals(true, false) + } + +} diff --git a/modules/sbt-scripted-munit/src/sbt-test/sbt-scripted-munit/fail/project/build.properties b/modules/sbt-scripted-munit/src/sbt-test/sbt-scripted-munit/fail/project/build.properties new file mode 100644 index 0000000..8b9a0b0 --- /dev/null +++ b/modules/sbt-scripted-munit/src/sbt-test/sbt-scripted-munit/fail/project/build.properties @@ -0,0 +1 @@ +sbt.version=1.8.0 diff --git a/modules/sbt-scripted-munit/src/sbt-test/sbt-scripted-munit/fail/project/plugins.sbt b/modules/sbt-scripted-munit/src/sbt-test/sbt-scripted-munit/fail/project/plugins.sbt new file mode 100644 index 0000000..8b11d46 --- /dev/null +++ b/modules/sbt-scripted-munit/src/sbt-test/sbt-scripted-munit/fail/project/plugins.sbt @@ -0,0 +1 @@ +addSbtPlugin("com.alejandrohdezma" % "sbt-scripted-munit" % sys.props("plugin.version")) diff --git a/modules/sbt-scripted-munit/src/sbt-test/sbt-scripted-munit/fail/test b/modules/sbt-scripted-munit/src/sbt-test/sbt-scripted-munit/fail/test new file mode 100644 index 0000000..cd717b6 --- /dev/null +++ b/modules/sbt-scripted-munit/src/sbt-test/sbt-scripted-munit/fail/test @@ -0,0 +1 @@ +-> munitScripted \ No newline at end of file diff --git a/modules/sbt-scripted-munit/src/sbt-test/sbt-scripted-munit/simple/build.sbt b/modules/sbt-scripted-munit/src/sbt-test/sbt-scripted-munit/simple/build.sbt new file mode 100644 index 0000000..cf4499c --- /dev/null +++ b/modules/sbt-scripted-munit/src/sbt-test/sbt-scripted-munit/simple/build.sbt @@ -0,0 +1,19 @@ +munitSuites += "MySuite" -> new FunSuite { + + test("This test passes") { + assertEquals(true, true) + } + + test("This test is ignored".ignore) { + assertEquals(true, true) + } + +} + +munitSuites += "MyOtherSuite" -> new FunSuite { + + test("This assertion fails, but the test passes".fail) { + assertEquals(true, false) + } + +} diff --git a/modules/sbt-scripted-munit/src/sbt-test/sbt-scripted-munit/simple/project/build.properties b/modules/sbt-scripted-munit/src/sbt-test/sbt-scripted-munit/simple/project/build.properties new file mode 100644 index 0000000..8b9a0b0 --- /dev/null +++ b/modules/sbt-scripted-munit/src/sbt-test/sbt-scripted-munit/simple/project/build.properties @@ -0,0 +1 @@ +sbt.version=1.8.0 diff --git a/modules/sbt-scripted-munit/src/sbt-test/sbt-scripted-munit/simple/project/plugins.sbt b/modules/sbt-scripted-munit/src/sbt-test/sbt-scripted-munit/simple/project/plugins.sbt new file mode 100644 index 0000000..8b11d46 --- /dev/null +++ b/modules/sbt-scripted-munit/src/sbt-test/sbt-scripted-munit/simple/project/plugins.sbt @@ -0,0 +1 @@ +addSbtPlugin("com.alejandrohdezma" % "sbt-scripted-munit" % sys.props("plugin.version")) diff --git a/modules/sbt-scripted-munit/src/sbt-test/sbt-scripted-munit/simple/test b/modules/sbt-scripted-munit/src/sbt-test/sbt-scripted-munit/simple/test new file mode 100644 index 0000000..7ffd7ce --- /dev/null +++ b/modules/sbt-scripted-munit/src/sbt-test/sbt-scripted-munit/simple/test @@ -0,0 +1 @@ +> munitScripted \ No newline at end of file diff --git a/project/build.properties b/project/build.properties new file mode 100644 index 0000000..40f4d4b --- /dev/null +++ b/project/build.properties @@ -0,0 +1 @@ +sbt.version=1.8.0 \ No newline at end of file diff --git a/project/plugins.sbt b/project/plugins.sbt new file mode 100644 index 0000000..69b551f --- /dev/null +++ b/project/plugins.sbt @@ -0,0 +1,15 @@ +addSbtPlugin("ch.epfl.scala" % "sbt-scalafix" % "0.10.4") +addSbtPlugin("com.alejandrohdezma" % "sbt-ci" % "2.10.1") +addSbtPlugin("com.alejandrohdezma" % "sbt-fix" % "0.7.0") +addSbtPlugin("com.alejandrohdezma" % "sbt-github-mdoc" % "0.11.6") +addSbtPlugin("com.alejandrohdezma" % "sbt-github-header" % "0.11.6") +addSbtPlugin("com.alejandrohdezma" % "sbt-scalafix-defaults" % "0.10.0") +addSbtPlugin("com.alejandrohdezma" % "sbt-scalafmt-defaults" % "0.7.1") +addSbtPlugin("com.alejandrohdezma" % "sbt-modules" % "0.2.0") +addSbtPlugin("com.alejandrohdezma" % "sbt-mdoc-toc" % "0.4.0") +addSbtPlugin("com.eed3si9n" % "sbt-buildinfo" % "0.11.0") +addSbtPlugin("com.github.sbt" % "sbt-ci-release" % "1.5.11") +addSbtPlugin("de.heikoseeberger" % "sbt-header" % "5.8.0") +addSbtPlugin("io.github.davidgregory084" % "sbt-tpolecat" % "0.4.1") +addSbtPlugin("org.scalameta" % "sbt-mdoc" % "2.3.6") +addSbtPlugin("org.scalameta" % "sbt-scalafmt" % "2.4.6")