Skip to content

A Gradle plugin for counting lines of code using the locc4j library.

License

Notifications You must be signed in to change notification settings

cthing/gradle-locc

Repository files navigation

C Thing Software gradle-locc

CI Portal

A Gradle plugin for counting lines of code in a project using a fast yet highly accurate algorithm.

Features

  • 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
  • Uses the locc4j library, which is modeled after the tokei line counting tool

Counting Lines of Code

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.

Usage

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 "1.0.1"
}

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:

Test files can be excluded from being counted using the following configuration:

locc {
    includeTestSources = false
}

Counting Additional or Different Files

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')
}

File Extension Mapping

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)
}

Doc Strings

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
}

Reports

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 Schema
CSV
HTML
JSON https://www.cthing.com/schemas/locc-1.json
Text
XML https://www.cthing.com/schemas/locc-1.xsd
YAML https://www.cthing.com/schemas/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
    }
}

Compatibility

The following Gradle and Java versions are supported:

Plugin Version Gradle Version Minimum Java Version
1.0.1+ 8.3+ 17

Building

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

Releasing

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 the ProjectVersion 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 and Compatibility sections in the README.md with the latest artifact release version
  • Commit these changes