diff --git a/.github/typocop/setting.yml b/.github/typocop/setting.yml new file mode 100644 index 00000000..b6bd76fb --- /dev/null +++ b/.github/typocop/setting.yml @@ -0,0 +1,20 @@ +# Configuration for Typocop - a GitHub Action for checking typos in pull requests + +# 'excludes' section allows you to specify files and folders to exclude +# from the typo-checking process. You can list specific files or use glob +# patterns to exclude entire directories. + +excludes: # Folders and files to exclude from typo checks + # Example: Exclude a specific file (e.g., 'exclude.rb' in the 'excludes' folder) + - excludes/exclude.rb + # Example: Exclude all files in the 'test' folder inside the 'excludes' directory + - excludes/test/* + +# 'skips' section defines a list of words, file names, or patterns +# for which Typocop will skip checking for typos. This is useful for common +# terms or abbreviations you don't want to be flagged as typos. + +skips: # Words or patterns to skip typo-checking + - rspec + # Example: Skip checking for the word 'elligible' (common in testing setups) + - elligible diff --git a/.github/workflows/typocop.yml b/.github/workflows/typocop.yml index eb919b5d..eea84d5e 100644 --- a/.github/workflows/typocop.yml +++ b/.github/workflows/typocop.yml @@ -18,3 +18,4 @@ jobs: github_token: ${{ secrets.GITHUB_TOKEN }} pull_request_id: ${{ github.event.pull_request.number }} github_base_ref: ${{ github.base_ref }} + setting: .github/typocop/setting.yml diff --git a/README.md b/README.md index 583c2184..4040eee6 100644 --- a/README.md +++ b/README.md @@ -42,9 +42,29 @@ This GitHub Action automatically checks for typos in the files changed in a pull github_token: ${{ secrets.GITHUB_TOKEN }} pull_request_id: ${{ github.event.pull_request.number }} github_base_ref: ${{ github.base_ref }} + setting: .github/typocop/setting.yml # Optional: Path to your custom settings file ``` - 2. Create a new Pull Request (PR) to trigger the action. + 2. Customize settings (optional): + + By default, Typocop uses predefined settings, but you can create a custom settings file in your repository. For example, create .github/typocop/setting.yml to specify exclusion rules and skip lists. + + Example `.github/typocop/setting.yml`: + + ```yaml + excludes: # Files and directories to exclude + - excludes/exclude.rb + - excludes/test/* + + skips: # Words or patterns to skip during typo detection + - rspec + - eligible + ``` + + - **excludes**: Specifies files or directories to exclude from typo checking. + - **skips**: Specifies words or patterns to skip checking (useful for technical terms or domain-specific language). + + 3. Create a new Pull Request (PR) to trigger the action. 2. **Using Typocop command line** ```bash @@ -71,7 +91,7 @@ We welcome contributions to this project! To contribute: - Hoang Duc Quan ([BlazingRockStorm](https://github.com/BlazingRockStorm)) ## References -- [Crate CI - Typos](https://github.com/crate-ci/typos) +- [Typo Checker](https://github.com/datpmt/typo_checker) - [Pronto Labs](https://github.com/prontolabs/pronto) ## License diff --git a/action.yml b/action.yml index aa3b2837..bcc8f08f 100644 --- a/action.yml +++ b/action.yml @@ -16,21 +16,14 @@ inputs: github_base_ref: description: 'GitHub Base Ref' required: true + setting: + description: 'Path to the custom setting.yml file for Typocop' + required: false + default: '.github/typocop/setting.yml runs: using: 'composite' steps: - - name: Set up Python - uses: actions/setup-python@v3 - with: - python-version: '3.14.0-alpha.1' - - - name: Install typos - run: | - python3 -m pip install --upgrade pip - pip install typos - shell: bash - - name: Setup Ruby uses: ruby/setup-ruby@v1 with: @@ -43,7 +36,7 @@ runs: - name: Run Typocop run: | - typocop execute + typocop execute --config ${{ inputs.setting }} env: GITHUB_TOKEN: ${{ inputs.github_token }} PULL_REQUEST_ID: ${{ inputs.pull_request_id }} diff --git a/excludes/exclude.rb b/excludes/exclude.rb new file mode 100644 index 00000000..d192aa55 --- /dev/null +++ b/excludes/exclude.rb @@ -0,0 +1,9 @@ +def greeting(name) + puts "Hello, #{name}! Welocome to the Ruby typos test." + puts 'languege' # typo + puts 'knowlege' # typo + puts 'knowlege: languege' # typo + puts 'welcom' +end + +greeting('Alice') diff --git a/excludes/include.rb b/excludes/include.rb new file mode 100644 index 00000000..d192aa55 --- /dev/null +++ b/excludes/include.rb @@ -0,0 +1,9 @@ +def greeting(name) + puts "Hello, #{name}! Welocome to the Ruby typos test." + puts 'languege' # typo + puts 'knowlege' # typo + puts 'knowlege: languege' # typo + puts 'welcom' +end + +greeting('Alice') diff --git a/excludes/test/exclude.js b/excludes/test/exclude.js new file mode 100644 index 00000000..b8ee69be --- /dev/null +++ b/excludes/test/exclude.js @@ -0,0 +1,3 @@ +var languege = 'en' // typo +console.log(languege) // typo +console.log('welcom') // typo diff --git a/excludes/test/exclude.py b/excludes/test/exclude.py new file mode 100644 index 00000000..a994b620 --- /dev/null +++ b/excludes/test/exclude.py @@ -0,0 +1,26 @@ +def greet(name): + print(f"Hello, {name}! Welcome to Python programming.") + +def factorial(n): + if n == 0 or n == 1: + return 1 + else: + result = 1 + for i in range(2, n + 1): + result *= i + return result + +numbers = [5, 3, 8, 10] + +for number in numbers: + print(f"Factorial of {number} is: {factorial(number)}") + +user_name = input("Enter your name: ") + +greet(user_name) + +age = int(input("Enter your age: ")) +if age >= 18: + print("You are elligible for an adult privilege.") # typo +else: + print("You are underage, so no adult privileges for you.") diff --git a/lib/typocop.rb b/lib/typocop.rb index ee9d9b07..91870dbf 100644 --- a/lib/typocop.rb +++ b/lib/typocop.rb @@ -9,6 +9,7 @@ require 'typocop/cops' require 'typocop/patch' require 'typocop/repo' +require 'typo_checker' GITHUB_TOKEN = ENV['GITHUB_TOKEN'] || '' PULL_ID = ENV['PULL_REQUEST_ID'] @@ -16,45 +17,19 @@ BASE_BRANCH = GITHUB_BASE_REF.start_with?('origin/') ? GITHUB_BASE_REF : "origin/#{GITHUB_BASE_REF}" module Typocop - def self.execute - typo_outputs = `typos --format brief` - typo_outputs = typo_outputs.split("\n") - - if typo_outputs.empty? - puts 'No typo output.' + def self.execute(settings) + excludes = settings.excludes + skips = settings.skips + typo_checker = TypoChecker::Checker.new(excludes, skips, stdoutput = false) + found_typos = typo_checker.scan_repo('.') + + if found_typos.empty? + puts 'No typos.' else - result = typo_outputs.each_with_object({}) do |output, hash| - path, line, _column, typo_detail = output.split(':') - typo_match = /`(.*?)` -> `(.*?)`/.match(typo_detail) - incorrect_word, correct_word = typo_match ? typo_match.captures : [] - - path = path.start_with?('./') ? path[2..] : path - line = line.to_i - - hash[path] ||= {} - - hash[path][:typos] ||= [] - - existing_entry = hash[path][:typos].find { |typo| typo[:line] == line } - - if existing_entry - existing_entry[:typos] << { incorrect_word: incorrect_word, correct_word: correct_word } - else - hash[path][:typos] << { line: line, typos: [{ incorrect_word: incorrect_word, correct_word: correct_word }] } - end - end - - result = result.map do |path, data| - data[:typos].map do |entry| - { path: path, line: entry[:line], typos: entry[:typos] } - end - end.flatten - - cops = Cops.new(result) - cops_data = cops.cops + cops = Cops.new(found_typos) repo = Repo.new client = Client.new(repo) - client.execute(cops_data) + client.execute(cops.cops) end end end diff --git a/lib/typocop/cli.rb b/lib/typocop/cli.rb index cb553fa7..29d016b8 100644 --- a/lib/typocop/cli.rb +++ b/lib/typocop/cli.rb @@ -1,11 +1,15 @@ require 'thor' +require_relative 'settings' module Typocop class CLI < Thor require 'typocop' + method_option :config, type: :string, default: '.github/typocop/setting.yml', aliases: '-c', desc: 'Load setting.' + desc 'execute', 'Run typocop' def execute - Typocop.execute + settings = Settings.new(options[:config]) + Typocop.execute(settings) end end end diff --git a/lib/typocop/settings.rb b/lib/typocop/settings.rb new file mode 100644 index 00000000..f700c20b --- /dev/null +++ b/lib/typocop/settings.rb @@ -0,0 +1,24 @@ +require 'yaml' + +module Typocop + class Settings + attr_reader :excludes, :skips + + def initialize(setting_path) + @settings = load_settings(setting_path) + @excludes = @settings['excludes'] || [] + @skips = @settings['skips'] || [] + end + + private + + def load_settings(setting_path) + begin + YAML.load_file(setting_path) + rescue StandardError => e + puts "Error loading YAML file: #{e.message}" + return {} + end + end + end +end diff --git a/lib/typocop/version.rb b/lib/typocop/version.rb new file mode 100644 index 00000000..0b4f7685 --- /dev/null +++ b/lib/typocop/version.rb @@ -0,0 +1,5 @@ +# frozen_string_literal: true + +module Typocop + VERSION = '0.1.2' +end diff --git a/typocop.gemspec b/typocop.gemspec index 96ad5512..057df003 100644 --- a/typocop.gemspec +++ b/typocop.gemspec @@ -1,8 +1,10 @@ +require_relative 'lib/typocop/version' + Gem::Specification.new do |s| s.name = 'typocop' - s.version = '0.1.1' + s.version = Typocop::VERSION s.summary = 'Comment on PRs with typos or approvals' - s.description = "Typocop integrates with GitHub Actions to automatically comment on pull requests when typos are detected or when a PR is approved, based on [Crate CI's Typos](https://github.com/crate-ci/typos)." + s.description = 'Typocop integrates with GitHub Actions to automatically comment on pull requests when typos are detected or when a PR is approved).' s.authors = ['datpmt'] s.email = 'datpmt.2k@gmail.com' s.files = Dir['CHANGELOG.md', 'LICENSE', 'README.md', 'lib/**/*', 'bin/*'] @@ -16,6 +18,7 @@ Gem::Specification.new do |s| s.add_dependency 'octokit', '9.2.0' s.add_dependency 'rugged', '~> 1.6.3' s.add_dependency 'thor', '~> 1.3.2' + s.add_dependency 'typo_checker' s.executables = %w[typocop] s.files.each do |file| next unless file.start_with?('bin/')