diff --git a/.github/workflows/check_misc.yml b/.github/workflows/check_misc.yml index fb00fd5c0c..58e362478d 100644 --- a/.github/workflows/check_misc.yml +++ b/.github/workflows/check_misc.yml @@ -28,15 +28,20 @@ jobs: # Skip overwriting MATZBOT_GITHUB_TOKEN checkout: '' # false (ref: https://github.com/actions/runner/issues/2238) + # Run this step first to make sure auto-style commits are pushed + - name: ${{ (github.repository == 'ruby/ruby' && github.ref == 'refs/heads/master') && 'Auto-correct' || 'Check for' }} code styles + run: | + set -x + ruby tool/auto-style.rb "$GITHUB_OLD_SHA" "$GITHUB_NEW_SHA" "$PUSH_REF" + env: + GITHUB_OLD_SHA: ${{ startsWith(github.event_name, 'pull') && github.event.pull_request.base.sha || github.before }} + GITHUB_NEW_SHA: ${{ startsWith(github.event_name, 'pull') && github.event.pull_request.merge_commit_sha || github.sha }} + PUSH_REF: ${{ (github.repository == 'ruby/ruby' && github.ref == 'refs/heads/master') && github.ref || '' }} + - name: Check if C-sources are US-ASCII run: | grep -r -n --include='*.[chyS]' --include='*.asm' $'[^\t-~]' -- . && exit 1 || : -# - name: Check for trailing spaces -# run: | -# git grep -I -n $'[\t ]$' -- '*.rb' '*.[chy]' '*.rs' '*.yml' && exit 1 || : -# git grep -n $'^[\t ][\t ]*$' -- '*.md' && exit 1 || : - - name: Check for bash specific substitution in configure.ac run: | git grep -n '\${[A-Za-z_0-9]*/' -- configure.ac && exit 1 || : diff --git a/tool/auto-style.rb b/tool/auto-style.rb index 8dc7e1bdee..3b435a6232 100644 --- a/tool/auto-style.rb +++ b/tool/auto-style.rb @@ -1,6 +1,6 @@ #!/usr/bin/env ruby # Usage: -# auto-style.rb [repo_path] [args...] +# auto-style.rb [oldrev] [newrev] [pushref] require 'shellwords' require 'tmpdir' @@ -9,10 +9,15 @@ ENV['LC_ALL'] = 'C' class Git attr_reader :depth - def initialize(oldrev, newrev, branch) + def initialize(oldrev, newrev, branch = nil) @oldrev = oldrev @newrev = newrev @branch = branch + + # GitHub may not fetch github.event.pull_request.base.sha at checkout + git('fetch', '--depth=1', 'origin', @oldrev) + git('fetch', '--depth=100', 'origin', @newrev) + with_clean_env do @revs = {} IO.popen(['git', 'log', '--format=%H %s', "#{@oldrev}..#{@newrev}"]) do |f| @@ -34,7 +39,7 @@ class Git end # [0, 1, 4, ...] - def updated_lines(file) + def updated_lines(file) # NOTE: This doesn't work well on pull requests, so not used anymore lines = [] revs = @revs.map {|rev, subj| rev unless subj.start_with?("Revert ")}.compact revs_pattern = /\A(?:#{revs.join('|')}) / @@ -49,13 +54,21 @@ class Git def commit(log, *files) git('add', *files) git('commit', '-m', log) + end + + def push git('push', 'origin', @branch) end + def diff + git('--no-pager', 'diff') + end + private def git(*args) cmd = ['git', *args].shelljoin + puts "+ #{cmd}" unless with_clean_env { system(cmd) } abort "Failed to run: #{cmd}" end @@ -160,80 +173,79 @@ IGNORED_FILES = [ %r{\Asample/trick[^/]*/}, ] -repo_path, *rest = ARGV -rest.each_slice(3).map do |oldrev, newrev, refname| - branch = IO.popen({ 'GIT_DIR' => repo_path }, ['git', 'rev-parse', '--symbolic', '--abbrev-ref', refname], &:read).strip - next if branch != 'master' # Stable branches are on svn, and for consistency we should not make a git-specific commit. - vcs = Git.new(oldrev, newrev, branch) +oldrev, newrev, pushref = ARGV +unless dry_run = pushref.empty? + branch = IO.popen(['git', 'rev-parse', '--symbolic', '--abbrev-ref', pushref], &:read).strip +end +git = Git.new(oldrev, newrev, branch) - Dir.mktmpdir do |workdir| - depth = vcs.depth + 1 - system "git clone --depth=#{depth} --branch=#{branch} file:///#{repo_path} #{workdir}" - Dir.chdir(workdir) +paths = git.updated_paths +paths.select! {|l| + /^\d/ !~ l and /\.bat\z/ !~ l and + (/\A(?:config|[Mm]akefile|GNUmakefile|README)/ =~ File.basename(l) or + /\A\z|\.(?:[chsy]|\d+|e?rb|tmpl|bas[eh]|z?sh|in|ma?k|def|src|trans|rdoc|ja|en|el|sed|awk|p[ly]|scm|mspec|html|)\z/ =~ File.extname(l)) +} +files = paths.select {|n| File.file?(n) } +files.reject! do |f| + IGNORED_FILES.any? { |re| f.match(re) } +end +if files.empty? + puts "No files are a auto-style target:\n#{paths.join("\n")}" + exit +end - paths = vcs.updated_paths - paths.select! {|l| - /^\d/ !~ l and /\.bat\z/ !~ l and - (/\A(?:config|[Mm]akefile|GNUmakefile|README)/ =~ File.basename(l) or - /\A\z|\.(?:[chsy]|\d+|e?rb|tmpl|bas[eh]|z?sh|in|ma?k|def|src|trans|rdoc|ja|en|el|sed|awk|p[ly]|scm|mspec|html|)\z/ =~ File.extname(l)) - } - files = paths.select {|n| File.file?(n) } - files.reject! do |f| - IGNORED_FILES.any? { |re| f.match(re) } +trailing = eofnewline = expandtab = false + +edited_files = files.select do |f| + src = File.binread(f) rescue next + eofnewline = eofnewline0 = true if src.sub!(/(?