Skip to content
Plugin to block compilation when unapproved dependencies are used or code styling does not comply.
Scala Makefile
Branch: master
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
bin Add sonatype publish Jun 11, 2019
project Add plugin to itself and clean up Jun 20, 2019
src Allow to use a URL for the 'safetyConfPath' setting Jul 2, 2019
.bettercodehub.yml Add BetterCodeHub May 31, 2019
.gitignore Add coverage integration with coveralls.io May 31, 2019
.scalafix.conf Add scala styles May 30, 2019
.scalafmt.conf Add scala styles May 30, 2019
.travis.yml Remove the attempt to not run test when only documentation are updated Jun 21, 2019
LICENSE
Makefile
PROJECT_NAME First commit May 29, 2019
PULL_REQUEST_TEMPLATE.md First commit May 29, 2019
README.md Allow to use a URL for the 'safetyConfPath' setting Jul 2, 2019
VERSION Update VERSION Aug 13, 2019
build.sbt Add plugin to itself and clean up Jun 20, 2019
project.sbt
publish.sbt Allow to use a URL for the 'safetyConfPath' setting Jul 2, 2019
safetyPlugin.json First commit May 29, 2019
scalastyle-config.xml First commit May 29, 2019
stryker4s.conf Add stryker step to submit to dashboard Jun 19, 2019
test.sbt Fix stryker failing because of compiler warning (2) Jun 21, 2019

README.md

License: MIT Gitter release-badge maven-central-badge

Build Status BCH compliance Coverage Status Mutation testing badge

sbt_safety_plugin

If you have any question submit an issue.

Table of Contents

Created by gh-md-toc

Setup steps

  1. Make sure you are using SBT 1.2.x.
  2. Add to ./project/safety.sbt in your project:
    addSbtPlugin("com.leobenkel" % "safety_plugin" % safetyPluginVersion)
    
    The latest release is release-badge maven-central-badge
  3. Make sure to have a config file. Take a look at safetyPlugin.json for examples
  4. If you need a fat-jar:
    1. Add to your build.sbt the following lines:
      assemblyOption in assembly := safetyAssemblySettings.value
      enablePlugins(DockerPlugin)
      
  5. Clean up your build.sbt by removing all pre-set settings:
    1. dependencyOverrides
    2. scalacOptions
    3. All settings related to sbt-assembly and sbt-docker
    4. All test options in Test:
      1. javaOptions in Test
      2. testOptions in Test
      3. parallelExecution in Test
      4. fork in Test
  6. Remove all plugins that are already included for you:
    1. sbt-scoverage
    2. sbt-assembly
    3. sbt-docker
    4. sbt-dependency-graph
    5. sbt-scalafix
    6. sbt-scalafmt
    7. scalastyle-sbt-plugin
  7. You can run your project the same as before. There can be compilation issues due to vulnerable dependencies.
  8. Dangerous! If you are not able to fix compiler issues, add: safetySoftOnCompilerWarning := true
  9. Dangerous! If you are not able to fix dependencies issues, add: safetySoft := true
  10. You can now then fix scala style issues:
    1. Run sbt safetyCheckScalaStyle
    2. Run sbt safetyCheckScalaFix
    3. Run sbt safetyCheckScalaFmt
      1. If you are ready to rewrite the broken files:
        1. Create a clean branch
        2. Run sbt safetyCheckScalaFmtRun

safetyPlugin.json

Root level

To override where the config file is read from, update the setting safetyConfPath in your build.sbt. This setting can be a URL starting by http:// or https:// or a local file path. By default it will search for ./safetyPlugin.json.

Root level:

  • dockerImage: To set in which image the fat-jar will be built.
  • sbtVersion: SBTVersion to enforce. If a project is trying to compile with a different version, it will break.
  • scalaVersions: Is an array of authorized scala Version. This is an array and not a value to allow Spark/Play project on different version.
  • scalaCFlags: The list of compile flag to add to the build process. If safetySoftOnCompilerWarning is not true, then -Xfatal-warnings will be added as well to trigger a compilation failure.
  • modules: This is where the bulk of the settings are living.
    • The structure is groupId|com.organization -> artifactName -> description of the constraints

Modules

The modules are the constraint enforced by the plugin related to each dependencies.

The path to each module is groupId|com.organization -> artifactName -> description of the constraints.

A module can accept those keys:

  • version: Either None or a version number. If the library is added with a different version number, the compilation will fail
  • exactName: Default is True if absent. If false, the artifactName can just be a start. It is used for instance where you want to enforce a version for a library and related ones. circe or spark- can be good examples.
  • excludeName: Default empty. It is used to exclude libraries that would be catch by the name + exactName:false. It is used for instance in Play project where you would enforce something for all libraries starting by play- except a few that are behind on version numbers.
  • needDoublePercent: By default is false. If true, the conversion to sbt.ModuleID will be with %% instead of %. The same way it would be in the build.sbt.
  • shouldDownload: Is true by default and is only used for sbt safetyGetAllDependencies.
  • overrideIsEnough: Default is true. This is related to dependenciesToRemove.
    • If overrideIsEnough is true, the library will be added to dependencyOverrides.
    • If overrideIsEnough is false, the library will be converted to an exclusion rule.
  • forbidden: Default is null. If this is set, and the library is added, the message will be displayed as a build failure. For instance you can use it to forbid one MySQL library and advise to use a different one.
  • shouldBeProvided: Default is false. If true, the compilation will fail if the library is not set to Provided in build.sbt. It is used for Spark.
  • dependenciesToRemove: This is a list of groupID | artifactName libraries to remove from this library. This is when overrideIsEnough come into play.

How to make sure library A is always version x.y and Provided ?

"modules": {
    "groupID.A": {
        "artifactName-A": {
            "version": "x.y",
            "shouldBeProvided": true
        }
    }
}

How to remove a dependency D completely from a library A ?

"modules": {
    "groupID.D": {
        "artifactName-D": {
            "version": "None",
            "overrideIsEnough": false
        }
    },
    "groupID.A": {
        "artifactName-A": {
            "dependenciesToRemove": [ 
                "groupID.D | artifactName-D"
            ],
            "version": "vA.A"
        }
    }
}

The dependenciesToRemove in A, will search for D. Since overrideIsEnough is false in D, the plugin will remove D from A using an ExclusionRule. Then, the plugin gather all the library which have been removed, and add them back with the appropriate version. In this case the version of D is None, so it will not be added back.

Is there an easy way to build the dependenciesToRemove tree ?

Yes there is !

First assemble your json:

"modules": {
   "groupID.D": {
       "artifactName-D": {
           "version": "None",
           "overrideIsEnough": false
       }
   },
   "groupID.A": {
       "artifactName-A": {
           "version": "vA.A"
       }
   },
   "groupID.B": {
       "artifactName-B": {
           "version": "vB.B"
       }
   }
}

Then run sbt safetyDebugAllModules.

This will:

  1. Remove all the dependencies from your build.sbt
  2. List all the known libraries from your config file
  3. Add one library at a time, compile and get the fetched dependencies
  4. Compare the fetch dependencies with the known dependencies from your config file
  5. When all the libraries have been reviewed, the plugin will display a new json payload that you can just copy paste with all the dependenciesToRemove set to the knowledge you have in your json.

Features

Scala Style

The sbt plugin includes ScalaFix, ScalaStyle and ScalaFmt.

  1. Check that you have .scalafix.conf, .scalafmt.conf and scalastyle-config.xml in your project
    • Feel free to copy the one present in this repo to follow the same style guides
  2. Run sbt safetyCheckScalaCheckAll to check that everything is correct.
    • You can run each system independently with:
      • sbt safetyCheckScalaStyle
      • sbt safetyCheckScalaFix
      • sbt safetyCheckScalaFmt
  3. To apply the fix for ScalaFmt, you can run sbt safetyCheckScalaFmtRun

For fat-jar assembly build

You need to add

assemblyOption in assembly := safetyAssemblySettings.value
enablePlugins(DockerPlugin)

to your build.sbt file.

You can now call sbt docker to create the fat-jar. It will be located at ./target/docker/0/*.jar.

To change in which docker image the build is ran, you can change dockerImage in safetyPlugin.json.

!!!Dangerous!!! Allow compilation even with vulnerability

Vulnerability by-pass

By default, you won't be able to compile if you have errors in your build.

If you need time to fix several issues, you can add:

safetySoft := true

to your build.sbt file while you are fixing them.

Compilation warning by pass

If you also want to allow compiler warning, you will need to add:

safetySoftOnCompilerWarning := true

to your build.sbt file while you are fixing them

Debug

To print more or less logs for this plugin, you can set safetyLogLevel.

For Debug:

safetyLogLevel := Level.Debug

For Error only:

safetyLogLevel := Level.Error

Publishing

  • Update version number in VERSION file.
  • Deploy the updated plugin locally: make publishLocal
  • Update version number in ./project/safety.sbt.
  • Run the plugin on itself with make publishLocal
  • Publish: make publish

Authors

Leo Benkel

  • leobenkel-github-badge
  • leobenkel-linkedin-badge
  • leobenkel-personal-badge
You can’t perform that action at this time.