Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
104 changes: 104 additions & 0 deletions zBuilder/ReasonToBuildDocumentation/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
# Reason To Build Documentation

## Overview
The ReasonToBuildDocumentation custom Groovy task analyzes and documents the reason why each file was built during a zBuilder build. It distinguishes between files that were built because they were changed versus files that were built due to dependencies (impacted files). This information is captured in the DBB Build Report as metadata records and can be used for analysis, reporting, and testing decisions.

## Contents
| Folder/File | Description |
| --- | --- |
| [groovy/documentReasonToBuild.groovy](groovy/documentReasonToBuild.groovy) | Groovy script that implements the logic for analyzing and documenting build reasons. |

## Installation Instructions

### Copy Files

- Clone this [DBB Community Repository](https://github.com/IBM/dbb) to your workstation.
- Copy the `documentReasonToBuild.groovy` script to the `$DBB_BUILD/groovy` directory.

> **Note:** The Groovy script must reside in the `$DBB_BUILD/groovy` subdirectory to be automatically discovered by the task configuration.

### Integrate with dbb-build.yaml

Add the `ReasonToBuildDocumentation` task to your `dbb-build.yaml` configuration. The task should be placed in the `impact` lifecycle after the build list has been determined but before the actual language builds occur.

Example `dbb-build.yaml` configuration:
```yaml
lifecycles:
- lifecycle: impact
tasks:
- Start
- ScannerInit
- MetadataInit
- ImpactAnalysis
- ReasonToBuildDocumentation # Document build reasons
- Languages # Defined in Languages.yaml
- Finish

tasks:
- task: ReasonToBuildDocumentation
type: task
script: groovy/documentReasonToBuild.groovy
```

## How It Works

The `documentReasonToBuild.groovy` script performs the following:

1. **Retrieves Build Context**: Reads the `CHANGED_FILES` and `BUILD_LIST` context variables populated by the `ImpactAnalysis` task.
2. **Categorizes Files**:
- **Changed Files**: Files that were modified and are on the `CHANGED_FILES` list.
- **Impacted Files**: Files that are on the `BUILD_LIST` but not on the `CHANGED_FILES` list (built due to dependencies).
3. **Generates Metadata Records**: Creates a `PropertiesRecord` for each file in the build list with two properties:
- `file`: The file path
- `reasonForBuilding`: Either "changed" or "impacted"
4. **Provides Reporting**: In verbose mode, displays detailed statistics including:
- List of changed files
- List of impacted files
- Summary statistics (total changed, total built, impacted count)

## Output

### Build Report Records
For each file in the build list, a `PropertiesRecord` is added to the DBB Build Report with the following structure:
```
PropertiesRecord:
- file: "MortgageApplication/cobol/epscmort.cbl"
- reasonForBuilding: "changed"
```

### Console Output (Verbose Mode)
When running in verbose mode (`--verbose` flag), the task provides detailed output:
```
> Document reason for building
=== Build Analysis Report ===
==================================================
> Changed Files: 2
--------------------------------------------------
MortgageApplication/cobol/epscmort.cbl
MortgageApplication/cobol/epsmlist.cbl
> Impacted Files (built due to dependencies): 1
--------------------------------------------------
MortgageApplication/cobol/epsmpmt.cbl
=== Summary ===
--------------------------------------------------
Total Changed Files: 2
Total Files Built: 3
Impacted Files: 1
Changed & Built: 2
==================================================
```

## Task Dependencies

This task consumes the following context variables which are populated by the `ImpactAnalysis` task:
- `CHANGED_FILES`: Set of files that were modified
- `BUILD_LIST`: Set of files that need to be built

Therefore, it must run after the `ImpactAnalysis` task executes.

## Additional Notes

- The task is compatible with DBB's build report system and integrates seamlessly into the `impact` lifecycle.
- Metadata records generated by this task can be consumed by downstream processes such as packaging scripts and deployment tools.
- The task has no impact on the actual build process; it only adds documentation to the build report.
- In non-verbose mode, only summary counts are displayed to minimize console output.
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
@groovy.transform.BaseScript com.ibm.dbb.groovy.TaskScript baseScript
import com.ibm.dbb.metadata.MetadataStoreFactory
import com.ibm.dbb.task.TaskConstants
import com.ibm.dbb.build.*
import com.ibm.dbb.build.report.*
import com.ibm.dbb.build.html.*
import com.ibm.dbb.build.report.records.*

/**
* Document Reason to Build
*
* Analyzes and reports on files that were changed vs files that were built due to dependencies.
* Generates metadata records for each file with its build reason.
*/

// Retrieve changed files and the build list
Set changedFiles = context.getSetStringVariable(TaskConstants.CHANGED_FILES) ?: [] as Set
Set buildFiles = context.getSetStringVariable(TaskConstants.BUILD_LIST) ?: [] as Set
boolean verbose = context.getBooleanVariable(TaskConstants.IS_VERBOSE_MODE)

if (verbose) println "> Document reason for building"

// Compare the two lists and generate report
if (verbose) {
println "=== Build Analysis Report ==="
println "=" * 50
}

// Files that are on the CHANGED_FILES list
println "> Changed Files: ${changedFiles.size()}"
changedFiles.each { file ->
generateMetadataRecord(file, "changed")
}
if (verbose) printFileList(changedFiles)

// b) Files that are on the BUILD_LIST but not on the CHANGED_FILES list (impacted files)
Set impactedFiles = buildFiles - changedFiles
println "> Impacted Files (built due to dependencies): ${impactedFiles.size()}"
impactedFiles.each { file ->
generateMetadataRecord(file, "impacted")
}
if (verbose) printFileList(impactedFiles)

// Summary statistics
if (verbose) {
println "=== Summary ==="
println "-" * 50
println "Total Changed Files: ${changedFiles.size()}"
println "Total Files Built: ${buildFiles.size()}"
println "Impacted Files: ${impactedFiles.size()}"
println "Changed & Built: ${(changedFiles.intersect(buildFiles)).size()}"
println "=" * 50
}

return 0

/**
* Generate a metadata record for a file with its build reason
* @param file The file path
* @param reason The reason for building (changed or impacted)
*/
def generateMetadataRecord(String file, String reason) {
PropertiesRecord filePropertiesMetadataRecord = new PropertiesRecord()
filePropertiesMetadataRecord.addProperty("file", file)
filePropertiesMetadataRecord.addProperty("reasonForBuilding", reason)
BuildReportFactory.getBuildReport().addRecord(filePropertiesMetadataRecord)
}

/**
* Print file list in verbose mode
* @param files Set of files to print
*/
def printFileList(Set files) {
println "-" * 50
if (files.isEmpty()) {
println " No files in this category"
} else {
files.each { file ->
println " ${file}"
}
}
}