gherkin-linter 1.1.1

There is a newer version of this package available.
See the version list below for details.
dotnet tool install --global gherkin-linter --version 1.1.1
                    
This package contains a .NET tool you can call from the shell/command line.
dotnet new tool-manifest
                    
if you are setting up this repo
dotnet tool install --local gherkin-linter --version 1.1.1
                    
This package contains a .NET tool you can call from the shell/command line.
#tool dotnet:?package=gherkin-linter&version=1.1.1
                    
nuke :add-package gherkin-linter --version 1.1.1
                    

Gherkin Linter for C# Projects

NuGet License

A pure C# implementation of a Gherkin linter for SpecFlow and other BDD frameworks, designed to integrate seamlessly with C# projects.

Table of Contents

Quick Start

  1. Install the GherkinLinter as a .NET tool:

    dotnet tool install --global GherkinLinter.Cli
    
  2. Lint your feature files:

    gherkin-linter lint
    
  3. Set up a Git pre-commit hook to automatically lint staged feature files:

    gherkin-linter install
    

Features

  • Lint Gherkin feature files to ensure quality and consistency
  • Built-in rules for common Gherkin issues
  • Custom rule support
  • Git pre-commit hook integration
  • Configurable via JSON
  • No Node.js or JavaScript dependencies
  • Strict mode for CI/CD pipelines
  • Multi-targeting for .NET 6.0, 7.0, and 8.0

Installation

Option 1: Add to Your C# Project

  1. Clone this repository or download the source code
  2. Add the GherkinLinter solution to your project:
    git clone https://github.com/yourusername/GherkinLinter.git
    
  3. Reference the project in your solution

Option 2: Install as .NET Tool

Install from NuGet:

dotnet tool install --global GherkinLinter.Cli

Usage

Command Line Interface

# Lint all feature files
gherkin-linter lint

# Lint only staged feature files
gherkin-linter lint --staged

# Lint a specific feature file
gherkin-linter lint --file path/to/feature.feature

# Use a specific configuration file
gherkin-linter lint --config path/to/config.json

# Use strict mode (returns non-zero exit code when violations are found)
gherkin-linter lint --strict

For project reference usage:

dotnet run --project path/to/GherkinLinter.Cli/GherkinLinter.Cli.csproj lint

Git Pre-commit Hook Setup

# Install the pre-commit hook
gherkin-linter install

This will:

  1. Set up a Git pre-commit hook
  2. Create a default configuration file

Configuration

The linter uses a JSON configuration file named .gherkin-linter.json in your project root:

{
  "include": [
    "Features/**/*.feature",
    "**/*.feature"
  ],
  "exclude": [
    "bin/**/*.feature",
    "obj/**/*.feature"
  ],
  "rules": {
    "scenario-names": {
      "enabled": true
    },
    "no-empty-steps": {
      "enabled": true
    },
    "no-duplicate-scenario-names": {
      "enabled": true
    },
    "max-step-length": {
      "enabled": true,
      "config": {
        "length": 100
      }
    },
    "weak-language": {
      "enabled": true
    }
  },
  "custom_rules": []
}

Built-in Rules

Rule Description Configuration
scenario-names Ensures all scenarios have names None
no-empty-steps Ensures all steps have descriptions None
no-duplicate-scenario-names Checks for duplicated scenario names None
max-step-length Limits step length length: Maximum characters (default: 100)
weak-language Checks for weak language patterns in steps Customizable phrase mappings for Given/When and Then steps

Rule Examples

scenario-names

This rule ensures that all scenarios have a name. Unnamed scenarios make it difficult to understand the purpose of the test.

# ❌ Bad - Unnamed scenario
Scenario:
  Given I am on the homepage
  When I click the login button
  Then I should see the login form

# ✅ Good - Named scenario
Scenario: User can navigate to login form
  Given I am on the homepage
  When I click the login button
  Then I should see the login form
no-empty-steps

This rule checks for steps that have no description.

# ❌ Bad - Empty step
Scenario: User login
  Given I am on the login page
  When 
  Then I should be logged in

# ✅ Good - All steps have descriptions
Scenario: User login
  Given I am on the login page
  When I enter my credentials and click login
  Then I should be logged in
no-duplicate-scenario-names

This rule ensures that all scenarios have unique names within a feature file.

# ❌ Bad - Duplicate scenario names
Scenario: User login
  Given I am on the login page
  When I enter valid credentials
  Then I should be logged in

Scenario: User login
  Given I am on the login page
  When I enter invalid credentials
  Then I should see an error message

# ✅ Good - Unique scenario names
Scenario: User login with valid credentials
  Given I am on the login page
  When I enter valid credentials
  Then I should be logged in

Scenario: User login with invalid credentials
  Given I am on the login page
  When I enter invalid credentials
  Then I should see an error message
max-step-length

This rule limits the length of step descriptions to improve readability.

# ❌ Bad - Step is too long
Scenario: User registration
  Given I am on the registration page
  When I enter my first name, last name, email address, phone number, street address, city, state, zip code, country, preferred contact method, and marketing preferences
  Then I should be registered

# ✅ Good - Steps are concise
Scenario: User registration
  Given I am on the registration page
  When I fill out the registration form with valid data
  And I submit the form
  Then I should be registered
weak-language

This rule identifies steps that use weak or ambiguous language.

# ❌ Bad - Uses weak language
Scenario: User login
  Given I am on the login page
  When I enter my credentials
  Then I should be able to see my dashboard

# ✅ Good - Uses specific language
Scenario: User login
  Given I am on the login page
  When I enter valid credentials and click login
  Then the dashboard is displayed with my account information

Custom Rules

You can create custom rules by implementing the IRuleProvider interface in a new class library project:

using System.Collections.Generic;
using GherkinLinter.Core;

namespace YourNamespace
{
    public class YourCustomRuleProvider : IRuleProvider
    {
        public IEnumerable<RuleViolation> ApplyRule(Feature feature, Dictionary<string, object> config)
        {
            var violations = new List<RuleViolation>();
            
            // Your rule logic here
            // Example: Check if feature name follows a pattern
            if (!feature.Name.StartsWith("JIRA-"))
            {
                violations.Add(new RuleViolation
                {
                    Message = "Feature name must start with JIRA-",
                    Line = feature.Line
                });
            }
            
            return violations;
        }
    }
}

Then reference your class library and add the rule to your configuration:

{
  "rules": {
    "your-custom-rule": {
      "enabled": true,
      "config": {
        "yourSetting": "value"
      }
    }
  },
  "custom_rules": [
    {
      "path": "path/to/your/assembly.dll",
      "config": {
        "additionalSetting": "value"
      }
    }
  ]
}

Integration with MSBuild

To run the linter as part of your build process, add this to your .csproj file:

<Target Name="LintGherkin" BeforeTargets="BeforeBuild">
  <Exec Command="gherkin-linter lint" />
</Target>

Updating Dependencies in Other Projects

If you're using GherkinLinter in other projects (like Tsp.Test), you can use the included PowerShell script to update the dependencies:

# Run from the GherkinLinter project root
.\update-tsp-test.ps1

This script will:

  1. Automatically increment the patch version number (e.g., 1.0.0 → 1.0.1)
  2. Build the GherkinLinter project in Release mode
  3. Copy all necessary files to the Tsp.Test project
  4. Verify the update by checking the version

The script automatically handles version management by incrementing the patch version with each update. If you need to make a major or minor version change (e.g., for breaking changes or new features), you'll need to manually update the version number in src/GherkinLinter.Cli/GherkinLinter.Cli.csproj.

You may need to modify the script if your project paths are different.

Advanced Features

Strict Mode

The strict mode flag (--strict) makes the linter return a non-zero exit code when rule violations are found. This is particularly useful in CI/CD pipelines where you want the build to fail if there are linting errors.

# Normal mode - returns exit code 0 even with violations (for development)
gherkin-linter lint

# Strict mode - returns exit code 1 when violations are found (for CI/CD)
gherkin-linter lint --strict

Multi-targeting

The linter supports multiple .NET versions (6.0, 7.0, and 8.0), allowing you to use it with your preferred .NET runtime. The tool automatically selects the appropriate version based on what's installed on your system.

Troubleshooting

Common Issues

  • Configuration File Not Found: Ensure your .gherkin-linter.json file is in the root of your project.
  • Rules Not Working: Check that the rules are enabled in your configuration file.
  • Git Hook Not Working: Verify that the pre-commit hook is executable and properly installed.

Debugging

For more detailed output, use the verbose flag:

gherkin-linter lint --verbose

Contributing

Contributions are welcome! Here's how you can contribute:

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add some amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

Please ensure your code follows the existing style and includes appropriate tests.

License

MIT

Product Compatible and additional computed target framework versions.
.NET net6.0 is compatible.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 is compatible.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

This package has no dependencies.

Version Downloads Last Updated
1.7.2 160 6/18/2025
1.7.1 231 6/3/2025
1.7.0 167 6/2/2025
1.6.0 161 6/1/2025
1.5.0 216 5/20/2025
1.4.1 151 5/19/2025
1.4.0 147 5/19/2025
1.3.0 144 5/19/2025
1.2.1 146 5/19/2025
1.2.0 148 5/19/2025
1.1.1 154 5/18/2025
1.1.0 150 5/18/2025
1.0.6 148 5/18/2025