From 2cc6c2b62ba7ed96175e3778ed6bdf90db45bf65 Mon Sep 17 00:00:00 2001 From: Daniel Ramirez Date: Wed, 26 Apr 2023 01:11:13 -0500 Subject: [PATCH 01/11] Satiate RuboCop --- git-game | 45 +++++++++++++++++++++++---------------------- 1 file changed, 23 insertions(+), 22 deletions(-) diff --git a/git-game b/git-game index 503eb61..70766e6 100755 --- a/git-game +++ b/git-game @@ -1,51 +1,52 @@ #!/usr/bin/ruby +# frozen_string_literal: true longest_streak = streak = 0 # -- Exit gracefully -- -Signal.trap("INT") { +Signal.trap('INT') do puts "\nLongest streak: #{longest_streak}" exit 0 -} +end def print_header - puts "----------------------------------------------------------" - puts " THE GIT GAME " - puts "----------------------------------------------------------" - puts "Welcome! The goal of the git game is to guess committers" + puts '----------------------------------------------------------' + puts ' THE GIT GAME ' + puts '----------------------------------------------------------' + puts 'Welcome! The goal of the git game is to guess committers' puts "based on their commit messages.\n\n" end def print_help - puts "----------------------------------------------------------" - puts " USAGE " - puts "----------------------------------------------------------" - puts "git game [extra git log options]" - puts "EX: git game --after={2014-08-08}" - puts "(This script already uses --no-merges and --pretty." - puts "For more valid options see: http://gitref.org/inspect/)" + puts '----------------------------------------------------------' + puts ' USAGE ' + puts '----------------------------------------------------------' + puts 'git game [extra git log options]' + puts 'EX: git game --after={2014-08-08}' + puts '(This script already uses --no-merges and --pretty.' + puts 'For more valid options see: http://gitref.org/inspect/)' end # -- Usage Text -- -if ARGV.count > 0 && (input = ARGV.shift) == 'help' +if ARGV.count.positive? && (input = ARGV.shift) == 'help' print_header print_help exit 0 end # -- Parse commits -- -COMMIT_DELIMITER = "XXXCOMMITXXX" -FIELD_DELIMITER = "|||" +COMMIT_DELIMITER = 'XXXCOMMITXXX' +FIELD_DELIMITER = '|||' -commit_format = ["%an", "%ar", "%B"].join(FIELD_DELIMITER) +commit_format = ['%an', '%ar', '%B'].join(FIELD_DELIMITER) -raw_commits = `git log --no-merges --pretty="#{COMMIT_DELIMITER}#{commit_format}" #{input if input}`.split("#{COMMIT_DELIMITER}") +raw_commits = `git log --no-merges --pretty="#{COMMIT_DELIMITER}#{commit_format}" #{input}`.split(COMMIT_DELIMITER.to_s) commits = [] raw_commits.each do |c| next if c.strip.empty? fields = c.split(FIELD_DELIMITER) - commits << {:author => fields[0], :date => fields[1], :message => fields[2]} + commits << { author: fields[0], date: fields[1], message: fields[2] } end committers = commits.map { |c| c[:author] }.compact.uniq @@ -61,7 +62,7 @@ committers.each do |committer| puts committer end -puts "Ready? PRESS ENTER TO START PLAYING (Ctrl-C to quit)" +puts 'Ready? PRESS ENTER TO START PLAYING (Ctrl-C to quit)' gets @@ -82,7 +83,7 @@ loop do puts choices = committers.sample(NUM_CHOICE) - if !choices.include?(author) + unless choices.include?(author) choices.pop choices.push author end @@ -103,7 +104,7 @@ loop do if choices[guess.to_i - 1] == author streak += 1 - puts "Got it!" + puts 'Got it!' else streak = 0 puts "Actually, it was #{author}." From d0508d17c418397445fb4077bcf1b49894e986a8 Mon Sep 17 00:00:00 2001 From: Daniel Ramirez Date: Wed, 26 Apr 2023 03:53:18 -0500 Subject: [PATCH 02/11] Refactor and add shortstat --- git-game | 49 +++++++++++++++++++++++++++++++------------------ 1 file changed, 31 insertions(+), 18 deletions(-) diff --git a/git-game b/git-game index 70766e6..4a969de 100755 --- a/git-game +++ b/git-game @@ -28,29 +28,43 @@ def print_help end # -- Usage Text -- -if ARGV.count.positive? && (input = ARGV.shift) == 'help' - print_header - print_help - exit 0 +input = nil +if ARGV.count.positive? + input = ARGV.shift + + case input + when 'help' + print_header + print_help + exit 0 + end end # -- Parse commits -- COMMIT_DELIMITER = 'XXXCOMMITXXX' -FIELD_DELIMITER = '|||' +FIELD_DELIMITER = ',,,' -commit_format = ['%an', '%ar', '%B'].join(FIELD_DELIMITER) +commit_format = ['%aN', '%ar', '%B', ''].join(FIELD_DELIMITER) -raw_commits = `git log --no-merges --pretty="#{COMMIT_DELIMITER}#{commit_format}" #{input}`.split(COMMIT_DELIMITER.to_s) +raw_commits = `git log --no-merges --pretty=#{COMMIT_DELIMITER}#{commit_format} --shortstat #{input}` + .split(COMMIT_DELIMITER) commits = [] -raw_commits.each do |c| - next if c.strip.empty? - - fields = c.split(FIELD_DELIMITER) - commits << { author: fields[0], date: fields[1], message: fields[2] } +committers = [] +raw_commits.each do |com| + next if com.strip.empty? + + fields = com.split(FIELD_DELIMITER) + next if fields.any?(&:empty?) + + committers |= [fields[0]] + commits << { + author: fields[0], + date: fields[1], + message: fields[2], + stat: fields[3] + } end -committers = commits.map { |c| c[:author] }.compact.uniq - # -- Show welcome message -- system('clear') @@ -73,13 +87,12 @@ NUM_CHOICE = 4 loop do commit = commits.shuffle.pop - message = commit[:message] author = commit[:author] - next if message.nil? || message.empty? || author.nil? || author.empty? - puts "(#{commit[:date]})\n" - puts "#{message.strip}\n\n" + puts commit[:message] + puts commit[:stat] + puts puts choices = committers.sample(NUM_CHOICE) From a888d16b0e0e80c2463ced67afd136984ca2d8f3 Mon Sep 17 00:00:00 2001 From: Daniel Ramirez Date: Wed, 26 Apr 2023 12:11:04 -0500 Subject: [PATCH 03/11] Lazy load commit data This version took a big performance hit whenver I added shortstat to it. To counteract that I am only loading in the SHA first and fetching all extra data after the commit has been selected. This simplifies the commit parsing, allows for more flexibility with data retrieved and reduces memory footprint of the game (especially relevant in large repos). --- git-game | 38 ++++++++++---------------------------- 1 file changed, 10 insertions(+), 28 deletions(-) diff --git a/git-game b/git-game index 4a969de..efc0f0e 100755 --- a/git-game +++ b/git-game @@ -40,36 +40,20 @@ if ARGV.count.positive? end end -# -- Parse commits -- -COMMIT_DELIMITER = 'XXXCOMMITXXX' -FIELD_DELIMITER = ',,,' +# -- Fetch Repository Info -- +COMMIT_DELIMITER = "\0" -commit_format = ['%aN', '%ar', '%B', ''].join(FIELD_DELIMITER) - -raw_commits = `git log --no-merges --pretty=#{COMMIT_DELIMITER}#{commit_format} --shortstat #{input}` +commit_shas = `git log --no-merges --pretty=%H -z #{input}` .split(COMMIT_DELIMITER) -commits = [] -committers = [] -raw_commits.each do |com| - next if com.strip.empty? - - fields = com.split(FIELD_DELIMITER) - next if fields.any?(&:empty?) - - committers |= [fields[0]] - commits << { - author: fields[0], - date: fields[1], - message: fields[2], - stat: fields[3] - } -end +committers = `git log --pretty=%aN -z` + .split(COMMIT_DELIMITER) + .uniq # -- Show welcome message -- system('clear') print_header -puts "You're playing in a repo with #{commits.size} commits and #{committers.size}" +puts "You're playing in a repo with #{commit_shas.size} commits and #{committers.size}" puts "distinct committers.\n\n" committers.each do |committer| @@ -86,12 +70,10 @@ system('clear') NUM_CHOICE = 4 loop do - commit = commits.shuffle.pop - author = commit[:author] + sha = commit_shas.shuffle.pop + author = `git show #{sha} --pretty=%aN --no-patch` - puts "(#{commit[:date]})\n" - puts commit[:message] - puts commit[:stat] + puts `git show #{sha} --pretty='(%ar)%n%B' --shortstat` puts puts From e668c899e7108077ed5ad0eb1e8af2023777247f Mon Sep 17 00:00:00 2001 From: Daniel Ramirez Date: Wed, 26 Apr 2023 14:03:44 -0500 Subject: [PATCH 04/11] Fixup committers handling --- git-game | 27 ++++++++++----------------- 1 file changed, 10 insertions(+), 17 deletions(-) diff --git a/git-game b/git-game index efc0f0e..f261756 100755 --- a/git-game +++ b/git-game @@ -41,13 +41,10 @@ if ARGV.count.positive? end # -- Fetch Repository Info -- -COMMIT_DELIMITER = "\0" - commit_shas = `git log --no-merges --pretty=%H -z #{input}` - .split(COMMIT_DELIMITER) -committers = `git log --pretty=%aN -z` - .split(COMMIT_DELIMITER) - .uniq + .split("\0") +committers = `git log --no-merges --pretty=%aN | sort -u` + .split("\n") # -- Show welcome message -- system('clear') @@ -73,18 +70,14 @@ loop do sha = commit_shas.shuffle.pop author = `git show #{sha} --pretty=%aN --no-patch` - puts `git show #{sha} --pretty='(%ar)%n%B' --shortstat` - puts - puts + puts `git show #{sha} --pretty='(%ar)%n%B' --shortstat\n\n` - choices = committers.sample(NUM_CHOICE) - unless choices.include?(author) - choices.pop - choices.push author - end - choices.shuffle! + choices = [author] + choices += committers.reject do |name| + name == author + end.sample(NUM_CHOICE - 1) - choices.each_with_index do |name, index| + choices.shuffle.each_with_index do |name, index| puts "[#{index + 1}] #{name}" end @@ -92,7 +85,7 @@ loop do guess = gets.strip - while guess.empty? || !guess.to_i.between?(1, NUM_CHOICE) + until guess.to_i.between?(1, NUM_CHOICE) print "Who wrote it (current streak: #{streak})? " guess = gets.strip end From c2b3d56cac998a196d6922cee4e64de35cb69a84 Mon Sep 17 00:00:00 2001 From: Daniel Ramirez Date: Sat, 29 Apr 2023 15:48:12 -0500 Subject: [PATCH 05/11] Randomize once And fixup author trailing whitespace --- git-game | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/git-game b/git-game index f261756..abd088c 100755 --- a/git-game +++ b/git-game @@ -43,6 +43,7 @@ end # -- Fetch Repository Info -- commit_shas = `git log --no-merges --pretty=%H -z #{input}` .split("\0") + .shuffle committers = `git log --no-merges --pretty=%aN | sort -u` .split("\n") @@ -67,8 +68,8 @@ system('clear') NUM_CHOICE = 4 loop do - sha = commit_shas.shuffle.pop - author = `git show #{sha} --pretty=%aN --no-patch` + sha = commit_shas.pop + author = `git show #{sha} --pretty=%aN --no-patch`.strip puts `git show #{sha} --pretty='(%ar)%n%B' --shortstat\n\n` From d8b9bf47f9a49c1d82e77e9747f444bf5c956ded Mon Sep 17 00:00:00 2001 From: Daniel Ramirez Date: Sat, 29 Apr 2023 17:29:57 -0500 Subject: [PATCH 06/11] Add win screen And use heredocs in favor of multiple puts/prints And add more options for help command --- git-game | 53 ++++++++++++++++++++++++++++++----------------------- 1 file changed, 30 insertions(+), 23 deletions(-) diff --git a/git-game b/git-game index abd088c..85c5b03 100755 --- a/git-game +++ b/git-game @@ -10,21 +10,26 @@ Signal.trap('INT') do end def print_header - puts '----------------------------------------------------------' - puts ' THE GIT GAME ' - puts '----------------------------------------------------------' - puts 'Welcome! The goal of the git game is to guess committers' - puts "based on their commit messages.\n\n" + puts <<~TXT + ---------------------------------------------------------- + THE GIT GAME + ---------------------------------------------------------- + Welcome! The goal of the git game is to guess committers + based on their commit messages. + + TXT end def print_help - puts '----------------------------------------------------------' - puts ' USAGE ' - puts '----------------------------------------------------------' - puts 'git game [extra git log options]' - puts 'EX: git game --after={2014-08-08}' - puts '(This script already uses --no-merges and --pretty.' - puts 'For more valid options see: http://gitref.org/inspect/)' + puts <<~TXT + ---------------------------------------------------------- + USAGE + ---------------------------------------------------------- + git game [extra git log options] + EX: git game --after={2014-08-08} + (This script already uses --no-merges and --pretty. + For more valid options see: https://git-scm.com/docs/git-log) + TXT end # -- Usage Text -- @@ -33,7 +38,7 @@ if ARGV.count.positive? input = ARGV.shift case input - when 'help' + when 'help', '--help', '-h' print_header print_help exit 0 @@ -59,7 +64,6 @@ committers.each do |committer| end puts 'Ready? PRESS ENTER TO START PLAYING (Ctrl-C to quit)' - gets system('clear') @@ -67,12 +71,11 @@ system('clear') # -- Game loop -- NUM_CHOICE = 4 -loop do - sha = commit_shas.pop - author = `git show #{sha} --pretty=%aN --no-patch`.strip - - puts `git show #{sha} --pretty='(%ar)%n%B' --shortstat\n\n` +commit_shas.each do |sha| + puts `git show #{sha} --pretty='(%ar)%n%B' --shortstat` + puts "\n\n" + author = `git show #{sha} --pretty=%aN --no-patch`.strip choices = [author] choices += committers.reject do |name| name == author @@ -82,10 +85,7 @@ loop do puts "[#{index + 1}] #{name}" end - print "Who wrote it (current streak: #{streak})? " - - guess = gets.strip - + guess = nil until guess.to_i.between?(1, NUM_CHOICE) print "Who wrote it (current streak: #{streak})? " guess = gets.strip @@ -104,3 +104,10 @@ loop do sleep 1 system('clear') end + +puts <<~TXT + Congratulations! There are no more commits in this repo! + + Longest streak: #{longest_streak} +TXT +exit 0 From 138f6002a6c1257664c85219d79ccbb57958f4c2 Mon Sep 17 00:00:00 2001 From: Daniel Ramirez Date: Sat, 29 Apr 2023 17:48:42 -0500 Subject: [PATCH 07/11] Handle unrecognized argument --- git-game | 3 +++ 1 file changed, 3 insertions(+) diff --git a/git-game b/git-game index 85c5b03..4eb5b96 100755 --- a/git-game +++ b/git-game @@ -1,6 +1,8 @@ #!/usr/bin/ruby # frozen_string_literal: true +require 'English' + longest_streak = streak = 0 # -- Exit gracefully -- @@ -49,6 +51,7 @@ end commit_shas = `git log --no-merges --pretty=%H -z #{input}` .split("\0") .shuffle +exit $CHILD_STATUS.exitstatus unless $CHILD_STATUS.success? committers = `git log --no-merges --pretty=%aN | sort -u` .split("\n") From 7a2e2aa56368faadb4617baa5108fb579aa2371e Mon Sep 17 00:00:00 2001 From: Daniel Ramirez Date: Sat, 29 Apr 2023 17:51:50 -0500 Subject: [PATCH 08/11] Update git-log docs link --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index eb62f22..5b17714 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ ## What is it? -In the git game, you guess who made a commit to your team's repo based on their commit message: +In the git game, you guess who made a commit to your team's repo based on their commit message: ![](https://cloud.githubusercontent.com/assets/21294/6428030/ba13a98c-bf60-11e4-92fa-ae25302e9a84.png) @@ -13,7 +13,7 @@ The goal is to get the longest streak! (It's harder than you think...) - [Download the `git-game` executable](https://github.com/jsomers/git-game/releases/tag/1.2) - Put it somewhere on your PATH (like /usr/local/bin) - Then, in any git repository, run `git game` -- (If you'd like, you can select a subset of commits, for example, `git game --after={2014-08-08}`. For more options, see [http://gitref.org/inspect/](http://gitref.org/inspect/).) +- (If you'd like, you can select a subset of commits, for example, `git game --after={2014-08-08}`. For more options, see [Git - git-log documentation](https://git-scm.com/docs/git-log).) ## Requirements From 8dfa61d952f74fa1a432edd5a2a255cedb9de39d Mon Sep 17 00:00:00 2001 From: Daniel Ramirez Date: Sat, 29 Apr 2023 21:01:55 -0500 Subject: [PATCH 09/11] Prompt user before next question Based on feedback that time betweem questions is too short Fix multiple choice shuffling issue that cause indexes to not be lined up --- git-game | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/git-game b/git-game index 4eb5b96..dc03c08 100755 --- a/git-game +++ b/git-game @@ -54,6 +54,7 @@ commit_shas = `git log --no-merges --pretty=%H -z #{input}` exit $CHILD_STATUS.exitstatus unless $CHILD_STATUS.success? committers = `git log --no-merges --pretty=%aN | sort -u` .split("\n") + .map(&:strip) # -- Show welcome message -- system('clear') @@ -83,8 +84,9 @@ commit_shas.each do |sha| choices += committers.reject do |name| name == author end.sample(NUM_CHOICE - 1) + choices.shuffle! - choices.shuffle.each_with_index do |name, index| + choices.each_with_index do |name, index| puts "[#{index + 1}] #{name}" end @@ -104,7 +106,8 @@ commit_shas.each do |sha| longest_streak = [longest_streak, streak].max - sleep 1 + puts "\nEnter to go to next question" + gets system('clear') end From 461efa9f27a197e57195f2c54ab64245611fa639 Mon Sep 17 00:00:00 2001 From: Daniel Ramirez Date: Thu, 4 May 2023 23:12:28 -0500 Subject: [PATCH 10/11] Add option to control commit stats Show commit stats by default, this is normal difficulty. Hide stats when --hard is passed. Slight refactor of command line args so user can pass --hard and other git options. ex: git game --hard --after={2023-01-01} And encourage use of --help and -h flags, but still support git game help. --- git-game | 45 ++++++++++++++++++++++++++++++++------------- 1 file changed, 32 insertions(+), 13 deletions(-) diff --git a/git-game b/git-game index dc03c08..41f9798 100755 --- a/git-game +++ b/git-game @@ -4,6 +4,7 @@ require 'English' longest_streak = streak = 0 +difficulty = :normal # -- Exit gracefully -- Signal.trap('INT') do @@ -27,26 +28,45 @@ def print_help ---------------------------------------------------------- USAGE ---------------------------------------------------------- - git game [extra git log options] + git game [options] + + Flags: + -h, --help Show this help message + --hard Opt into a challenge (git game classic) + + Extra options can be passed directly to git log: + EX: git game --after={2014-08-08} (This script already uses --no-merges and --pretty. For more valid options see: https://git-scm.com/docs/git-log) TXT end -# -- Usage Text -- -input = nil -if ARGV.count.positive? - input = ARGV.shift +def print_commit_preview(sha, difficulty) + details_args = { + normal: "--pretty='(%ar)%n%B' --shortstat", + hard: "--pretty='(%ar)%n%B' --no-patch" + }[difficulty] - case input - when 'help', '--help', '-h' - print_header - print_help - exit 0 - end + puts `git show #{sha} #{details_args}` + puts "\n\n" end +# -- Command line options -- +used_args = [] +if ARGV.include?('help') || + ARGV.include?('--help') || + ARGV.include?('-h') + print_header + print_help + exit 0 +elsif ARGV.include?('--hard') + used_args << '--hard' + difficulty = :hard +end +input = ARGV.reject { |arg| used_args.include?(arg) }.join(' ') +ARGV.clear + # -- Fetch Repository Info -- commit_shas = `git log --no-merges --pretty=%H -z #{input}` .split("\0") @@ -76,8 +96,7 @@ system('clear') NUM_CHOICE = 4 commit_shas.each do |sha| - puts `git show #{sha} --pretty='(%ar)%n%B' --shortstat` - puts "\n\n" + print_commit_preview(sha, difficulty) author = `git show #{sha} --pretty=%aN --no-patch`.strip choices = [author] From 0d4f7f812c61f3cedc8ca53e807d27b1413131ad Mon Sep 17 00:00:00 2001 From: Daniel Ramirez Date: Thu, 4 May 2023 23:28:07 -0500 Subject: [PATCH 11/11] Encourage use of -h for help --help does not work when called with git game. It may be getting picked up by git before git-game has a chance to parse it. I get the message: No manual entry for git-game But it works as expected with git-game --help so I am leaving it in. --- git-game | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/git-game b/git-game index 41f9798..00251d7 100755 --- a/git-game +++ b/git-game @@ -31,8 +31,8 @@ def print_help git game [options] Flags: - -h, --help Show this help message - --hard Opt into a challenge (git game classic) + -h Show this help message + --hard Opt into a challenge (git game classic) Extra options can be passed directly to git log: