A Gradle plugin for counting lines of code in a project using a fast yet highly accurate algorithm.
- Counts code lines, comment lines and blank lines
- Highly accurate without the expense of full parsing
- Supports over 250 computer languages
- Detects embedded languages (e.g. CSS in HTML)
- Accommodates nested comments
- Ability to associate custom file extensions with languages and remove unwanted associations
- Provides a number of report formats (e.g. JSON, XML)
- Uses the locc4j library, which is modeled after the tokei line counting tool
At first glance, counting lines of source code appears to be a relatively straightforward task. One could detect blank lines and assume every other line contains source code. That would count lines containing comments as source code, which is typically a bad assumption. One coulde naively apply regular expressions to detect line comments and block comments. Unfortunately, initial success is short-lived once encountering nested comments and languages that can embed other languages (e.g. CSS in HTML). At that point, it is tempting to employ language specific full lexing and parsing to ensure an accurate count. While this achieves high accuracy it is at a high performance cost spending most of the performance on needless work.
As a compromise between the naive and exhaustive approaches described above, the current state-of-the-art in counting lines of code employs a data-driven selective matching approach. A given computer language is described by a set of characteristics relevant to line counting. These characteristics include the file extension, line and block comment delimiters, and regular expressions to detect important syntax that indicates the need for more detailed parsing. Highly accurate and performant line counting tools such as tokei, scc and the locc4j library used by this plugin use this approach. The plugin is able to detect and count over 250 computer languages, and can accommodate languages embedded within languages.
This plugin counts four types of lines:
- Total lines: All lines in the file.
- Code lines: Lines considered source code. Note that a line of code with a trailing comment is considered a code line.
- Comment lines: Lines consisting solely of comments. Note that a line of code with a trailing comment is not counted as a comment line.
- Blank lines: Lines consisting solely of zero or more whitespace characters.
The plugin is available from the
Gradle Plugin Portal and can be applied to a Gradle
project using the plugins
block:
plugins {
id("org.cthing.locc") version "2.0.0"
}
The plugin creates a task called countCodeLines
which counts all source code in all projects. Specifically, the
files in the following Gradle constructs are counted by default:
- All SourceSets, which includes JVM-based languages (e.g. Java, Kotlin, Groovy)
- The C++ CppApplication, CppLibrary, and CppTestSuite components
- The Swift SwiftApplication, SwiftLibrary, and SwiftXCTestSuite components
Test files can be excluded from being counted using the following configuration:
locc {
includeTestSources = false
}
The countCodeLines
task is an instance of an LoccTask
which is derived from
SourceTask. Therefore, all
properties and methods of that task can be used to add or replace files to be counted. For example, to count
additional files, configure the countCodeLines
task:
tasks.countCodeLines {
source(project.buildFile, new File(project.rootDir, 'dev/checkstyle.xml'))
}
The following example, completely replaces the default set of files counted with those specified:
tasks.countCodeLines {
source = new File(project.rootDir, 'dev/checkstyle.xml')
}
The plugin uses a built-in map of file extensions to computer languages. The complete list of supported languages
and their file extensions is available in the Javadoc for the
Language enum. File extensions
can be added or removed from the mapping. The following example removes the association of the css
file extension
with any language and associates the foo
file extension with the Java programming language:
tasks.countCodeLines {
removeExtension("css")
addExtension("foo", Language.Java)
}
Languages such as Python have a dedicated syntax for embedding documentation in source code. By default, the plugin
will count those lines as comments. To count those lines as code, configure the locc
extension:
locc {
countDocStrings = false
}
The plugin is capable of generating a line count report in a number of formats. Note that different formats provide different amounts of information as described in the following table.
Format | Project Information | Counts Per Language | Counts Per File | Counts Per Language Per File | Example | Schema |
---|---|---|---|---|---|---|
CSV | ✅ | locc.csv | ||||
HTML | ✅ | ✅ | ✅ | locc.html | ||
JSON | ✅ | ✅ | ✅ | ✅ | locc.json | locc‑1.json |
Text | ✅ | ✅ | ✅ | locc.txt | ||
XML | ✅ | ✅ | ✅ | ✅ | locc.xml | locc‑1.xsd |
YAML | ✅ | ✅ | ✅ | ✅ | locc.yaml | locc‑1.json |
The report for each format is generated as build/reports/locc/locc.{csv, html, json, txt, xml, yaml}
. By default,
the plugin will generate a report in the HTML and XML formats. Configure the task reports to control which file
formats are generated. For example, to output all formats:
tasks.countCodeLines {
reports {
xml.required = true
html.required = true
yaml.required = true
json.required = true
csv.required = true
text.required = true
}
}
To output only a JSON format line count report:
tasks.countCodeLines {
reports {
xml.required = false
html.required = false
json.required = true
}
}
The following Gradle and Java versions are supported:
Plugin Version | Gradle Version | Minimum Java Version |
---|---|---|
1.x | 8.3+ | 17 |
2.x | 8.4+ | 17 |
The plugin is compiled for Java 17. If a Java 17 toolchain is not available, one will be downloaded.
Gradle is used to build the plugin:
./gradlew build
The Javadoc for the plugin can be generated by running:
./gradlew javadoc
This project is released on the Gradle Plugin Portal. Perform the following steps to create a release.
- Commit all changes for the release
- In the
build.gradle.kts
file, edit theProjectVersion
object- Set the version for the release. The project follows semantic versioning.
- Set the build type to
BuildType.release
- Commit the changes
- Wait until CI successfully builds the release candidate
- Verify GitHub Actions build is successful
- If there have been changes to the JSON or XML schema, publish them to the C Thing Software website by adding them to the cthing-website project
- In a browser go to the C Thing Software Jenkins CI page
- Run the
gradle-locc-validate
job - Wait until that job successfully completes
- Run the
gradle-locc-release
job to release the plugin to the Gradle Plugin Portal - Wait for the plugin to be reviewed and made available by the Gradle team
- In a browser, go to the project on GitHub
- Generate a release with the tag
<version>
- In the build.gradle.kts file, edit the
ProjectVersion
object- Increment the version patch number
- Set the build type to
BuildType.snapshot
- Update the
CHANGELOG.md
with the changes in the release and prepare for next release changes - Update the
Usage
andCompatibility
sections in theREADME.md
with the latest artifact release version - Commit these changes