chutney 3.11.2 → 3.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ec37ccd0377c50adf8968133abf55a2e6ffe76f5e6388d24681cd2c9aa925244
4
- data.tar.gz: 793ca207c66e94d4c48d8f5f752880730e06cc043c8d1ff0b3db972663fb33de
3
+ metadata.gz: 4bb70911d762cb65f7bf9787409241481d5bb6b36544c4d9cb0544ed441ab1f4
4
+ data.tar.gz: 25b3aea992da920ba631c4020dec0f80facac6279687bc7b1855aa65fe511bcb
5
5
  SHA512:
6
- metadata.gz: 16e1f2824bd0183a4d7bf3d383713bdad718abd335f075190fdcdc4a671ac4b272f27f5bf63fe4561fd0a266ee104957d12acd18ca89c3a46783ac2689ce77c3
7
- data.tar.gz: bea0fa1997bf1d06a776dceb8d6d4e0ed31d384cc84a076ffc958077caa0f078fd8f42b7b950047821f7b9f29e8b930b481943bd2b3a05e8967d47fb12f493e4
6
+ metadata.gz: 94edc0b29066f55cc5c1e8badbe9a336ec23415edd92c3ab7a8ef64f7246c59515ec020d6342793ae8cb46bb6e82c51962e08cab7942c718caf93339cd060da2
7
+ data.tar.gz: 4324c6dd20acc5062b6e7022e2d79e86267f3e7c63b5a5924b327d07ffa4abf571e4d99edeabbfb9a0f312f61d46e3c6ccfb36c0b60d6c7697e9bcbce9968730
data/.gitignore CHANGED
@@ -11,6 +11,7 @@ Gemfile.lock
11
11
  # rspec failure tracking
12
12
  .rspec_status
13
13
  .idea/
14
+ .vscode/
14
15
 
15
16
  .DS_Store
16
17
 
data/chutney.gemspec CHANGED
@@ -51,6 +51,7 @@ Gem::Specification.new do |spec|
51
51
  spec.add_dependency 'amatch', '~> 0.4.0'
52
52
  spec.add_dependency 'cuke_modeler', '~> 3.21'
53
53
  spec.add_dependency 'i18n', '>= 1.8.2', '< 1.15.0'
54
+ spec.add_dependency 'fast-mcp', '~> 1.5'
54
55
  spec.add_dependency 'language_server-protocol', '~> 3.17'
55
56
  spec.add_dependency 'pastel', '~> 0.7'
56
57
  spec.add_dependency 'tty-pie', '~> 0.3'
data/exe/chutney-mcp ADDED
@@ -0,0 +1,50 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ # MCP (Model Context Protocol) server for Chutney
5
+ # This executable provides a FastMCP server that exposes Chutney's Gherkin linting
6
+ # capabilities as a tool that can be used by MCP clients
7
+
8
+ require 'chutney'
9
+ require 'fast_mcp'
10
+
11
+ # ChutneyTool provides Gherkin file linting functionality via MCP
12
+ # It wraps Chutney's linting capabilities in a FastMCP tool format
13
+ class ChutneyTool < FastMcp::Tool
14
+ tool_name 'Chutney'
15
+ description 'Lint your Cuxumber Gherkin BDD files and make sure they follow standards and best practice'
16
+
17
+ # Define the required arguments for the tool
18
+ # file_path: Absolute path to the Gherkin feature file to be linted
19
+ arguments do
20
+ required(:file_path).filled(:string).description('An ABSULTE file path to the gherking file to lint')
21
+ end
22
+
23
+ # Main execution method that performs the Gherkin file linting
24
+ # @param file_path [String] Absolute path to the Gherkin file
25
+ # @return [Hash] Analysis report containing linting results
26
+ def call(file_path:)
27
+ # Validate that an absolute path was provided
28
+ raise 'Relative path given, absolute path require' unless File.absolute_path?(file_path)
29
+
30
+ # Verify the file exists before attempting to lint it
31
+ raise 'File not found' unless File.exist?(file_path)
32
+
33
+ # Create a new Chutney linter instance and analyze the file
34
+ linter = Chutney::ChutneyLint.new(file_path)
35
+ report = linter.analyse
36
+
37
+ # Return the analysis report as a hash for MCP consumption
38
+ report.to_h
39
+ end
40
+ end
41
+
42
+ # Initialize and configure the MCP server
43
+ # The server exposes Chutney functionality to MCP clients
44
+ server = FastMcp::Server.new(name: 'chutney', version: Chutney::VERSION)
45
+
46
+ # Register the ChutneyTool with the server
47
+ server.register_tool(ChutneyTool)
48
+
49
+ # Start the MCP server to begin accepting client connections
50
+ server.start
@@ -64,7 +64,7 @@ module Chutney
64
64
  def put_summary
65
65
  pastel = Pastel.new
66
66
  print "#{files.count} features inspected, "
67
- if files_with_issues.count.zero?
67
+ if files_with_issues.none?
68
68
  puts pastel.green('all taste delicious')
69
69
  else
70
70
  puts pastel.red("#{files_with_issues.count} taste nasty")
@@ -37,7 +37,7 @@ module Chutney
37
37
 
38
38
  def put_summary
39
39
  print "#{files.count} features inspected, "
40
- if files_with_issues.count.zero?
40
+ if files_with_issues.none?
41
41
  puts @pastel.green('all taste delicious')
42
42
  else
43
43
  puts @pastel.red("#{files_with_issues.count} taste nasty")
@@ -14,7 +14,7 @@ module Chutney
14
14
  end
15
15
 
16
16
  def files_with_issues
17
- results.filter { |_k, v| v.any? { |r| r[:issues].count.positive? } }
17
+ results.filter { |_k, v| v.any? { |r| r[:issues].any? } }
18
18
  end
19
19
  end
20
20
  end
data/lib/chutney/issue.rb CHANGED
@@ -6,6 +6,7 @@ module Chutney
6
6
  # entity value class for issues
7
7
  class Issue
8
8
  include Term::ANSIColor
9
+
9
10
  attr_reader :name, :references, :description
10
11
 
11
12
  def initialize(name, references, description = nil)
@@ -14,7 +14,7 @@ module Chutney
14
14
  quoted_params = parameters.group_by(&:quotation_mark)
15
15
  single_quoted = quoted_params[%(')] || []
16
16
  double_quoted = quoted_params[%(")] || []
17
- return unless single_quoted.count.positive? && double_quoted.count.positive?
17
+ return unless single_quoted.any? && double_quoted.any?
18
18
 
19
19
  add_issue(
20
20
  I18n.t('linters.inconsistent_quoting',
@@ -3,6 +3,10 @@
3
3
  module Chutney
4
4
  # Rule to find all the duplicated scenarios
5
5
  class SameScenario < Linter
6
+ def self.reset
7
+ @dictionary = nil
8
+ end
9
+
6
10
  def self.dictionary
7
11
  @dictionary ||= Hash.new { |hash, key| hash[key] = [] }
8
12
  end
@@ -128,9 +128,7 @@ module Chutney
128
128
  off_switch = element.tags
129
129
  .map(&:name)
130
130
  .then { |tags| tags || [] }
131
- .filter { |tag_name| tag_name == "@disable#{linter_name}" }
132
- .count
133
- .positive?
131
+ .any? { |tag_name| tag_name == "@disable#{linter_name}" }
134
132
  off_switch ||= off_switch?(feature) unless element == feature
135
133
  off_switch
136
134
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Chutney
4
- VERSION = '3.11.2'
4
+ VERSION = '3.12.0'
5
5
  end
data/lib/chutney.rb CHANGED
@@ -60,6 +60,7 @@ module Chutney
60
60
  # gherkin linter
61
61
  class ChutneyLint
62
62
  extend Forwardable
63
+
63
64
  attr_accessor :verbose
64
65
  attr_reader :files, :results
65
66
 
@@ -56,7 +56,7 @@ en:
56
56
  missing_action: >-
57
57
  This scenario is missing an action step -- it does not have a 'When'.
58
58
  missing_example_name: >-
59
- You have a scenerio with more than one example table, at least one of which is
59
+ You have a scenario with more than one example table, at least one of which is
60
60
  unnamed or has a duplicate name.
61
61
  You should give your example tables clear and meaningful names when you have more than one.
62
62
  missing_example_table: >-
@@ -116,3 +116,5 @@ sidebar:
116
116
  children:
117
117
  - title: "Language server"
118
118
  url: /docs/language-server/
119
+ - title: "LLM integration"
120
+ url: /docs/mcp/
@@ -0,0 +1,37 @@
1
+ ---
2
+ title: "Chutney MCP Server"
3
+ layout: single
4
+ permalink: /docs/mcp/
5
+ ---
6
+
7
+ {: .notice}
8
+ Since v3.12.0
9
+
10
+ Chutney now ships with a Model Context Protocol (MCP) server for easy integration with AI LLMs, afterall if they're helping author gherkin, it should be tasty.
11
+
12
+ The command to start the MCP is
13
+
14
+ ```bash
15
+ chutney-mcp
16
+ ```
17
+
18
+ The MCP is STDIO based server.
19
+
20
+ ### VS Code integration example
21
+
22
+ To set it up for a particular repository, create a file called `.vscode/mcp.json` in the root of your project. Add this block (or modify the `servers` section if you already have this file) to look like:
23
+
24
+ ```json
25
+ {
26
+ "servers": {
27
+ "chutney": {
28
+ "type": "stdio",
29
+ "command": "chutney-mcp",
30
+ "args": []
31
+ }
32
+ },
33
+ "inputs": []
34
+ }
35
+ ```
36
+
37
+ Then, in your copilot chat, click on tools and make sure the MCP is enabled, then click on the discover tools button and copilot will be able to use chutney.
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: chutney
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.11.2
4
+ version: 3.12.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nigel Brookes-Thomas
@@ -60,6 +60,20 @@ dependencies:
60
60
  - - "<"
61
61
  - !ruby/object:Gem::Version
62
62
  version: 1.15.0
63
+ - !ruby/object:Gem::Dependency
64
+ name: fast-mcp
65
+ requirement: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - "~>"
68
+ - !ruby/object:Gem::Version
69
+ version: '1.5'
70
+ type: :runtime
71
+ prerelease: false
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ requirements:
74
+ - - "~>"
75
+ - !ruby/object:Gem::Version
76
+ version: '1.5'
63
77
  - !ruby/object:Gem::Dependency
64
78
  name: language_server-protocol
65
79
  requirement: !ruby/object:Gem::Requirement
@@ -111,6 +125,7 @@ email:
111
125
  executables:
112
126
  - chutney
113
127
  - chutney-lsp
128
+ - chutney-mcp
114
129
  extensions: []
115
130
  extra_rdoc_files: []
116
131
  files:
@@ -142,6 +157,7 @@ files:
142
157
  - examples/emoji.feature
143
158
  - exe/chutney
144
159
  - exe/chutney-lsp
160
+ - exe/chutney-mcp
145
161
  - img/chutney.svg
146
162
  - img/formatters.png
147
163
  - img/happy_chutney.png
@@ -215,6 +231,7 @@ files:
215
231
  - usechutney.com/docs/disabling-rules/index.md
216
232
  - usechutney.com/docs/installing/index.md
217
233
  - usechutney.com/docs/language-server/index.md
234
+ - usechutney.com/docs/mcp/index.md
218
235
  - usechutney.com/docs/rules/avoid-colons-at-start-of-names/index.md
219
236
  - usechutney.com/docs/rules/avoid-comma-in-tags/index.md
220
237
  - usechutney.com/docs/rules/avoid-full-stops/index.md