This release introduces important breaking changes to the CycloneDX Gradle Plugin configuration and behavior.
These changes bring the plugin in line with Gradle’s direction, ensuring full compatibility with Gradle 9
while improving correctness and concurrency. Each subproject is now evaluated, configured, and resolved
independently, removing prior conflicts with Gradle’s parallel execution model.
Breaking Changes
- A new task
cyclonedxDirectBom
has been added to generate a BOM for a single project. The existingcyclonedxBom
task now acts as an aggregator, combining BOMs from all subprojects into one - Configuration properties that were deprecated in 2.4.0 removed now:
destination
,outputName
, andoutputFormat
,gitVCS
. Removed support forString
input forschemaVersion
andprojectType
- Properties
skipConfigs
,includeConfigs
,includeMetadataResolution
were removed fromcyclonedxBom
task. They moved tocyclonedxDirectBom
and should be configued for each project explicitly - Setters and getters were removed from tasks. Now configuration properties should be accessed directly
- Default output locations changed from
./build/reports/bom.{xml,json}
tobuild/reports/cyclonedx-direct/bom.{xml,json}
forcyclonedxDirectBom
, and tobuild/reports/cyclonedx/bom.{xml,json}
forcyclonedxBom
- Removed clojure based configuration of
organizationalEntity
andlicenseChoice
, they must be configured with direct object assignment - Fully qualified name for tasks changed. Task class
org.cyclonedx.gradle.CycloneDxTask
removed. Addedorg.cyclonedx.gradle.CyclonedxAggregateTask
,org.cyclonedx.gradle.CyclonedxDirectTask
, both extendorg.cyclonedx.gradle.BaseCyclonedxTask
New Featues
- Collect sbom per project, add cyclonedxAggregateBom task by @skhokhlov in #661
Bug Fixes
- Skip repositories without url in distributionManagement by @xvik in #673
- Stop adding self references and dependency constraints as direct dependencies by @tjog in #670
Full Changelog
- refactor: use Logging#getLogger for logs by @skhokhlov in #664
- build(deps): bump actions/checkout from 4.2.2 to 5.0.0 by @dependabot[bot] in #662
- refactor: migrate to jspecify annotations by @skhokhlov in #665
- build(deps): bump com.uber.nullaway:nullaway from 0.12.8 to 0.12.9 by @dependabot[bot] in #666
- build: prepare version 3.0.0-alpha-0 by @skhokhlov in #668
- test: run tests with java 8 and 11 by @skhokhlov in #672
- build(deps): bump actions/setup-java from 4.7.1 to 5.0.0 by @dependabot[bot] in #671
- Skip repositories without url in distributionManagement by @xvik in #673
- refactor: use Gradle's JavaVersion class by @skhokhlov in #674
- Stop adding self references and dependency constraints as direct dependencies by @tjog in #670
- Remove extension by @skhokhlov in #675
- build: prepare version 3.0.0-alpha-1 by @skhokhlov in #676
- chore: migrate issue templates to forms by @skhokhlov in #680
- build(deps): bump gradle/actions from 4.4.2 to 4.4.3 by @dependabot[bot] in #678
- build(deps): bump org.cyclonedx.bom from 2.3.1 to 2.4.0 by @dependabot[bot] in #684
- build(deps): bump com.uber.nullaway:nullaway from 0.12.9 to 0.12.10 by @dependabot[bot] in #685
- build(deps): bump com.gradle.plugin-publish from 1.3.1 to 2.0.0 by @dependabot[bot] in #677
- build: upgrade gradle to 9.1.0 by @skhokhlov in #687
- Java 25 by @skhokhlov in #688
- build(deps): bump org.cyclonedx.bom from 2.4.0 to 2.4.1 by @dependabot[bot] in #693
- build: use jdk 21 as default by @skhokhlov in #695
- fix: register direct bom task once by @skhokhlov in #694
- build(deps): bump org.cyclonedx:cyclonedx-core-java from 10.2.1 to 11.0.0 by @dependabot[bot] in #698
- build(deps): bump gradle/actions from 4.4.3 to 4.4.4 by @dependabot[bot] in #697
- build: prepare version 3.0.0-alpha-2 by @skhokhlov in #699
- build(deps): bump com.diffplug.spotless from 7.2.1 to 8.0.0 by @dependabot[bot] in #696
New Contributors
Full Changelog: cyclonedx-gradle-plugin-2.4.1...cyclonedx-gradle-plugin-3.0.0
CycloneDX Gradle Plugin Migration Guide: 2.4.1 → 3.0.0
This guide covers the breaking changes and migration steps required when upgrading from CycloneDX Gradle Plugin version 2.4.1 to 3.0.0.
Task Behavior and Naming Changes
Version 2.4.1: Single Task Model
# Single task for all scenarios
gradle cyclonedxBom
Version 3.0.0: Dual Task Model
# Generate per-project SBOMs (individual projects)
gradle cyclonedxDirectBom
# Generate aggregated SBOM (multi-project builds)
gradle cyclonedxBom
Task Behavior Changes
Aspect | Version 2.4.1 | Version 3.0.0 |
---|---|---|
Per-project SBOMs | Single task handled both | cyclonedxDirectBom task
|
Multi-project aggregation | Single task handled both | cyclonedxBom task
|
Output location | ./build/reports/bom.{xml,json}
| Direct: build/reports/cyclonedx-direct/bom.{xml,json} Aggregate: build/reports/cyclonedx/bom.{xml,json}
|
Task types | Single task class | CyclonedxDirectTask and CyclonedxAggregateTask
|
Configuration Method Changes
❌ Version 2.4.1: Single task configuration
// OLD - No longer supported
tasks.cyclonedxBom {
setIncludeConfigs(["runtimeClasspath"])
setDestination(file("build/reports"))
setOutputName("bom")
setOutputFormat("json")
}
✅ Version 3.0.0: Project-scoped task configuration
// NEW
tasks.cyclonedxDirectBom {
includeConfigs = ["runtimeClasspath"]
jsonOutput = file("build/reports/sbom/bom.json")
xmlOutput = file("build/reports/sbom/bom.xml")
}
tasks.cyclonedxBom {
jsonOutput = file("build/reports/sbom/bom.json")
xmlOutput = file("build/reports/sbom/bom.xml")
}
Plugin Application Recommendations
Version 2.4.1: Multiple Application Strategies
// Applied to individual projects OR used in init scripts
plugins {
id 'org.cyclonedx.bom' version '2.4.1'
}
Version 3.0.0: Root Project Application
// ROOT PROJECT build.gradle - RECOMMENDED
plugins {
id 'org.cyclonedx.bom' version '3.0.0'
}
cyclonedxBom {
// Configuration applies to both direct and aggregate tasks
}
Output Configuration Changes
Version 2.4.1: Combined Output Properties (deprecated since 2.4.0)
cyclonedxBom {
destination = file("build/reports") // Directory
outputName = "bom" // Base filename
outputFormat = "json" // Format: xml, json, all
}
Version 3.0.0: Explicit File Properties
tasks.cyclonedxBom {
// Explicit file paths for each format
jsonOutput = file("build/reports/sbom/bom.json")
xmlOutput = file("build/reports/sbom/bom.xml")
}
// Or disable specific formats
tasks.withType<CyclonedxDirectTask> {
xmlOutput.unsetConvention() // Generate JSON only
}
Migration Example
// OLD (2.4.1)
cyclonedxBom {
destination = file("build/custom")
outputName = "my-sbom"
outputFormat = "json"
}
// NEW (3.0.0)
tasks.cyclonedxBom {
jsonOutput = file("build/custom/my-sbom.json")
// xmlOutput omitted = only JSON generated
}
Schema Version Configuration Changes
Version 2.4.1: String-Based (deprecated since 2.4.0)
cyclonedxBom {
schemaVersion = "1.6"
}
Version 3.0.0: Enum-Based
import org.cyclonedx.model.schema.SchemaVersion
tasks.cyclonedxBom {
schemaVersion = SchemaVersion.VERSION_16
}
tasks.cyclonedxDirectBom {
schemaVersion = SchemaVersion.VERSION_16
}
Organizational Entity Configuration
Version 2.4.1: Closure-Based Configuration (deprecated since 2.4.0)
cyclonedxBom {
// Closure-based approach
organizationalEntity { oe ->
oe.name = 'Test Company'
oe.url = ['www.test1.com', 'www.test2.com']
oe.addContact(organizationalContact)
}
}
Version 3.0.0: Direct Object Assignment
import org.cyclonedx.model.*
tasks.cyclonedxBom {
// Direct object assignment
organizationalEntity = OrganizationalEntity().apply {
name = "ACME Corporation"
urls = listOf("https://www.acme.com", "https://security.acme.com")
addContact(OrganizationalContact().apply {
name = "Security Team"
email = "security@acme.com"
phone = "+1-555-SECURITY"
})
}
}
License Choice Configuration
Version 2.4.1: Closure-Based Configuration (deprecated since 2.4.0)
cyclonedxBom {
// Closure-based approach
licenseChoice { lc ->
License license = new License()
license.setName("Apache-2.0")
license.setUrl("https://www.apache.org/licenses/LICENSE-2.0.txt")
lc.addLicense(license)
}
}
Version 3.0.0: Direct Object Assignment
import org.cyclonedx.model.*
tasks.cyclonedxBom {
// Direct object assignment
licenseChoice = LicenseChoice().apply {
addLicense(License().apply {
name = "Apache-2.0"
url = "https://www.apache.org/licenses/LICENSE-2.0.txt"
})
}
}
External References Configuration
Version 2.4.1: VCS Git Configuration (deprecated since 2.4.0)
cyclonedxBom {
// VCS-specific configuration
setVCSGit { vcs ->
vcs.url = "https://github.com/example/repo.git"
vcs.comment = "Source repository"
}
}
Version 3.0.0: Generic External References
import org.cyclonedx.model.*
tasks.cyclonedxBom {
// Generic external references
externalReferences = listOf(
ExternalReference().apply {
url = "https://github.com/example/repo.git"
type = ExternalReference.Type.VCS
},
ExternalReference().apply {
url = "https://example.com/docs"
type = ExternalReference.Type.DOCUMENTATION
}
)
}
Multi-Project Setup Changes
# Generate per-project SBOMs for all projects
./gradlew cyclonedxDirectBom
# Generate single aggregated SBOM
./gradlew cyclonedxBom
Breaking Changes Summary
🚨 Critical Breaking Changes
- Task configuration syntax changes
- Output property names changed -
destination
/outputName
/outputFormat
(deprecated since 2.4.0) →jsonOutput
/xmlOutput
- Metadata configuration syntax changed - Closures (deprecated since 2.4.0) → Object assignment
⚠️ Behavioral Changes
- New task structure - Two tasks instead of one
- Different default output locations
- Plugin should be applied to root project for aggregation
Step-by-Step Migration Process
1. Update Plugin Version
plugins {
id("org.cyclonedx.bom") version "3.0.0"
}
2. Update Output Configuration
// OLD
cyclonedxBom {
destination = file("build/reports")
outputName = "sbom"
outputFormat = "json"
}
// NEW
tasks.cyclonedxBom {
jsonOutput = file("build/reports/sbom.json")
xmlOutput.unsetConvention()
}
3. Update Schema Version
import org.cyclonedx.model.schema.SchemaVersion
tasks.cyclonedxBom {
schemaVersion = SchemaVersion.VERSION_16
}
4. Migrate Metadata Configuration
import org.cyclonedx.model.*
tasks.cyclonedxBom {
// Convert closure-based to object assignment
organizationalEntity = OrganizationalEntity().apply {
// configuration
}
licenseChoice = LicenseChoice().apply {
// configuration
}
externalReferences = listOf(
ExternalReference().apply {
// configuration
}
)
}
5. Update Task Execution
# For per-project SBOMs
./gradlew cyclonedxDirectBom
# For aggregated SBOM (multi-project)
./gradlew cyclonedxBom
6. Verify Output Locations
Check that your SBOM files are generated in the expected locations:
- Direct:
build/reports/cyclonedx-direct/
- Aggregated:
build/reports/cyclonedx/
Common Migration Issues and Solutions
Issue: "Task configuration not found"
Problem: Using tasks.cyclonedxBom { }
syntax
Solution: Use cyclonedxBom { }
extension configuration
Issue: "Output files not found"
Problem: Looking in old output location
Solution: Check new default locations or configure explicit paths
Issue: "Schema version error"
Problem: Using string schema version
Solution: Import and use SchemaVersion
enum
Issue: "Multi-project aggregation not working"
Problem: Plugin not applied to root project
Solution: Apply plugin to root project and use cyclonedxBom
task
Testing Your Migration
- Clean build directory:
./gradlew clean
- Test per-project generation:
./gradlew cyclonedxDirectBom --info
- Test aggregation (if applicable):
./gradlew cyclonedxBom --info
- Verify output files exist in expected locations
- Validate SBOM content matches expectations
This migration guide should help you successfully upgrade from CycloneDX Gradle Plugin 2.4.1 to 3.0.0. The new version provides better separation of concerns with dedicated tasks and improved configuration flexibility.