Skip to content

Commit 5ac2998

Browse files
authored
Merge pull request #30 from siculo/projects/v0.2.0
Projects/v0.2.0 (to keep master in sync with all v0.2.0 changes)
2 parents a7c1878 + eeb08ad commit 5ac2998

File tree

18 files changed

+766
-70
lines changed

18 files changed

+766
-70
lines changed

README.md

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,33 @@
55
The aim of this project is to:
66

77
- extract a valid [CycloneDx](https://cyclonedx.org/) bom file from sbt projects
8-
- ensure that the bom file is processable with Software Composition Analysis tools (like Dependency Track)
8+
- ensure that the bom file is processable with Software Composition Analysis tools (like Dependency Track)
99

10-
## how to test the plugin
10+
## usage
1111

12-
see: ["exists" test project README.md](src/sbt-test/sbt-bom/exists/README.md)
12+
## testing
13+
14+
There are two types of test: unit test done with scalatest and scripted test
15+
16+
### unit test
17+
18+
Unit tests are written using scalatest syntax. Only pure logic classes are tested using these tests.
19+
20+
To run unit tests use the `test` command to run all tests, or `testOnly ...` command specifying the list of test to be
21+
executed.
22+
23+
### scripted tests
24+
25+
[Scripted](https://www.scala-sbt.org/1.x/docs/Testing-sbt-plugins.html) is a tool that allow you to test sbt plugins.
26+
For each test it is necessary to create a specially crafted project. These projects are inside src/sbt-test directory.
27+
28+
Scripted tests are run using `scripted` comand.
1329

1430
## changelog
1531

16-
### v0.0.1
32+
### v0.2.0
33+
- The cyclonedx-core-java library has been integrated and is used to generate the BOM
34+
- Removed all old model classes used so far
35+
36+
### v0.1.0
1737
- First release

build.sbt

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,18 @@
1+
ThisBuild / organization := "sbtBom"
2+
ThisBuild / organizationName := "SBT BOM"
3+
ThisBuild / version := "0.2.0-SNAPSHOT"
4+
ThisBuild / scalaVersion := "2.12.8"
5+
ThisBuild / homepage := Some(url("https://github.com/siculo/sbt-bom"))
6+
17
lazy val root = (project in file("."))
28
.enablePlugins(ScriptedPlugin)
39
.settings(
410
name := "sbt-bom",
5-
organization := "sbtBom",
6-
organizationName := "SBT BOM",
7-
version := "0.2.0-SNAPSHOT",
811
sbtPlugin := true,
9-
scalaVersion := "2.12.8",
1012
libraryDependencies ++= Dependencies.library,
11-
scriptedLaunchOpts += ("-Dplugin.version=" + version.value),
13+
scriptedLaunchOpts := {
14+
scriptedLaunchOpts.value ++ Seq("-Xmx1024M", "-Dplugin.version=" + version.value)
15+
},
1216
scriptedBufferLog := false,
1317
dependencyOverrides += "org.typelevel" %% "jawn-parser" % "0.14.1"
1418
)

src/main/scala/sbtBom/BomExtractor.scala

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package sbtBom
22

33
import com.github.packageurl.PackageURL
4-
import org.cyclonedx.CycloneDxSchema
54
import org.cyclonedx.model.{Bom, Component, License, LicenseChoice}
65
import sbt.librarymanagement.ModuleReport
76
import sbt.{Logger, UpdateReport, _}
@@ -11,9 +10,8 @@ import java.util.UUID
1110
import scala.collection.JavaConverters._
1211

1312

14-
class BomExtractor(schemaVersion: CycloneDxSchema.Version, report: UpdateReport, log: Logger) {
13+
class BomExtractor(settings: BomExtractorParams, report: UpdateReport, log: Logger) {
1514
private val serialNumber: String = "urn:uuid:" + UUID.randomUUID.toString
16-
private val configuration: Configuration = Compile
1715

1816
def bom: Bom = {
1917
val bom = new Bom
@@ -23,8 +21,17 @@ class BomExtractor(schemaVersion: CycloneDxSchema.Version, report: UpdateReport,
2321
}
2422

2523
private def components: Seq[Component] = {
24+
val configurations = Seq(Compile, Provided, Runtime, Test, IntegrationTest)
25+
configurations.foldLeft(Seq[Component]()) {
26+
case (collected, configuration) =>
27+
collected ++ componentsForConfiguration(configuration)
28+
}
29+
}
30+
31+
private def componentsForConfiguration(configuration: Configuration): Seq[Component] = {
2632
(report.configuration(configuration) map {
2733
configurationReport =>
34+
log.info(s"Configuration name = ${configurationReport.configuration.name}, modules: ${configurationReport.modules.size}")
2835
configurationReport.modules.map {
2936
module =>
3037
new ComponentExtractor(module).component
@@ -50,7 +57,7 @@ class BomExtractor(schemaVersion: CycloneDxSchema.Version, report: UpdateReport,
5057
component.setScope(Component.Scope.REQUIRED)
5158
licenseChoice.foreach(component.setLicenseChoice)
5259

53-
logComponent(component)
60+
// logComponent(component)
5461

5562
component
5663
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package sbtBom
2+
3+
import org.cyclonedx.CycloneDxSchema
4+
import sbt.Configuration
5+
6+
case class BomExtractorParams(schemaVersion: CycloneDxSchema.Version,
7+
configuration: Configuration)

src/main/scala/sbtBom/BomSbtKeys.scala

Lines changed: 0 additions & 14 deletions
This file was deleted.
Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,30 @@
11
package sbtBom
22

3+
import sbt.Keys.target
34
import sbt._
45

56
/**
67
* plugin object
78
*/
89
object BomSbtPlugin extends AutoPlugin {
910

11+
override def requires: Plugins = empty
12+
1013
override def trigger: PluginTrigger = allRequirements
1114

12-
object autoImport extends BomSbtKeys
15+
object autoImport {
16+
lazy val targetBomFile: SettingKey[sbt.File] = settingKey[File]("target file to store the generated bom")
17+
lazy val makeBom: TaskKey[sbt.File] = taskKey[sbt.File]("Generates bom file which includes all project dependencies")
18+
lazy val listBom: TaskKey[String] = taskKey[String]("Returns a bom which includes all project dependencies")
19+
lazy val supportedConfigurations: Seq[Configuration] = Seq(Compile, Runtime, Test)
20+
}
1321

14-
override lazy val projectSettings: Seq[Setting[_]] = BomSbtSettings.projectSettings
22+
import autoImport._
1523

24+
override lazy val projectSettings: Seq[Setting[_]] =
25+
Seq(
26+
targetBomFile := target.value / "bom.xml",
27+
makeBom := Def.taskDyn(BomSbtSettings.makeBomTask(Classpaths.updateTask.value)).value,
28+
listBom := Def.taskDyn(BomSbtSettings.listBomTask(Classpaths.updateTask.value)).value,
29+
)
1630
}

src/main/scala/sbtBom/BomSbtSettings.scala

Lines changed: 14 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4,32 +4,24 @@ import org.apache.commons.io.FileUtils
44
import org.cyclonedx.model.Bom
55
import org.cyclonedx.{BomGeneratorFactory, CycloneDxSchema}
66
import sbt.Keys.{sLog, target}
7-
import sbt.{Def, File, Setting, _}
7+
import sbt.{Compile, Def, File, Setting, _}
88
import sbtBom.BomSbtPlugin.autoImport._
99

1010
import java.nio.charset.Charset
1111

1212
object BomSbtSettings {
1313
val schemaVersion: CycloneDxSchema.Version = CycloneDxSchema.Version.VERSION_10
1414

15-
def projectSettings: Seq[Setting[_]] = {
16-
// val configs = Seq(Compile, Test, IntegrationTest, Runtime, Provided, Optional)
17-
Seq(
18-
targetBomFile := target.value / "bom.xml",
19-
makeBom := Def.taskDyn(makeBomTask(Classpaths.updateTask.value)).value,
20-
listBom := Def.taskDyn(listBomTask(Classpaths.updateTask.value)).value,
21-
)
22-
}
23-
24-
private def makeBomTask(report: UpdateReport): Def.Initialize[Task[sbt.File]] = Def.task[File] {
15+
def makeBomTask(report: UpdateReport): Def.Initialize[Task[sbt.File]] = Def.task[File] {
2516
val log: Logger = sLog.value
2617
val bomFile = targetBomFile.value
2718

2819
log.info(s"Creating bom file ${bomFile.getAbsolutePath}")
2920

30-
val bom: Bom = new BomExtractor(schemaVersion, report, log).bom
21+
val params = extractorParams
22+
val bom: Bom = new BomExtractor(params, report, log).bom
3123
val bomText: String = getXmlText(bom, schemaVersion)
32-
logBomInfo(log, bom)
24+
logBomInfo(log, params, bom)
3325

3426
FileUtils.write(bomFile, bomText, Charset.forName("UTF-8"), false)
3527

@@ -38,24 +30,29 @@ object BomSbtSettings {
3830
bomFile
3931
}
4032

41-
private def listBomTask(report: UpdateReport): Def.Initialize[Task[String]] =
33+
def listBomTask(report: UpdateReport): Def.Initialize[Task[String]] =
4234
Def.task[String] {
4335
val log: Logger = sLog.value
4436

4537
log.info("Creating bom")
4638

47-
val bom: Bom = new BomExtractor(schemaVersion, report, log).bom
39+
val params = extractorParams
40+
val bom: Bom = new BomExtractor(params, report, log).bom
4841
val bomText: String = getXmlText(bom, schemaVersion)
49-
logBomInfo(log, bom)
42+
logBomInfo(log, params, bom)
5043

5144
log.info("Bom created")
5245

5346
bomText
5447
}
5548

56-
private def logBomInfo(log: Logger, bom: Bom): Unit = {
49+
private def extractorParams: BomExtractorParams =
50+
BomExtractorParams(schemaVersion, Compile)
51+
52+
private def logBomInfo(log: Logger, params: BomExtractorParams, bom: Bom): Unit = {
5753
log.info(s"Schema version: ${schemaVersion.getVersionString}")
5854
log.info(s"Serial number : ${bom.getSerialNumber}")
55+
log.info(s"Scope : ${params.configuration.id}")
5956
}
6057

6158
private def getXmlText(bom: Bom, schemaVersion: CycloneDxSchema.Version) = {
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{"name":"sbt","version":"1.5.2","bspVersion":"2.0.0-M5","languages":["scala"],"argv":["/home/fabrizio/Applications/java/jdk1.8.0_211/jre/bin/java","-Xms100m","-Xmx100m","-classpath","/home/fabrizio/Applications/sbt/sbt-1.5.2/bin/sbt-launch.jar","xsbt.boot.Boot","-bsp","--sbt-launch-jar=/home/fabrizio/Applications/sbt/sbt-1.5.2/bin/sbt-launch.jar"]}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import scala.xml.XML
2+
3+
4+
lazy val root = (project in file("."))
5+
.settings(
6+
name := "dependencies",
7+
version := "0.1",
8+
libraryDependencies ++= Dependencies.library,
9+
scalaVersion := "2.12.8",
10+
check := checkTask.value
11+
)
12+
13+
lazy val check = taskKey[Unit]("check")
14+
lazy val checkTask = Def.task {
15+
val context = thisProject.value
16+
val expected = XML.loadFile(file(s"${context.base}/etc/bom.xml"))
17+
val actual = XML.loadFile(file(s"${context.base}/target/bom.xml"))
18+
require(expected \ "components" == actual \ "components", s"${context.id} is failed.")
19+
}

0 commit comments

Comments
 (0)