From 943f373e398f0f531fcd2ccdfceeb69ac0583f7b Mon Sep 17 00:00:00 2001 From: "Peter H. Boling" Date: Sat, 7 Jun 2025 13:31:05 +0700 Subject: [PATCH 1/8] =?UTF-8?q?=F0=9F=93=9D=20Add=20CITATION.cff?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CITATION.cff | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 CITATION.cff diff --git a/CITATION.cff b/CITATION.cff new file mode 100644 index 0000000..8b9277a --- /dev/null +++ b/CITATION.cff @@ -0,0 +1,23 @@ +cff-version: 1.2.0 +title: oauth-tty +message: >- + If you use this work and you want to cite it, + then you can use the metadata from this file. +type: software +authors: + - given-names: Peter Hurn + family-names: Boling + email: peter@railsbling.com + affiliation: railsbling.com + orcid: 'https://orcid.org/0009-0008-8519-441X' + - given-names: Aboling0 + email: aboling@railsbling.com + affiliation: railsbling.com +identifiers: + - type: url + value: 'https://github.com/oauth-xx/oauth-tty' + description: oauth-tty +repository-code: 'https://github.com/oauth-xx/oauth-tty' +abstract: >- + oauth-tty +license: See license file \ No newline at end of file From 1aa02210e43b7936971ba0007ae514772d464746 Mon Sep 17 00:00:00 2001 From: "Peter H. Boling" Date: Thu, 11 Sep 2025 02:24:22 -0600 Subject: [PATCH 2/8] =?UTF-8?q?=F0=9F=8E=A8=20Template=20bootstrap=20by=20?= =?UTF-8?q?kettle-dev-setup=20v1.1.16?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - convert all tests to RSpec --- .aiignore | 19 + .devcontainer/devcontainer.json | 26 + .env.local.example | 27 + .envrc | 46 ++ .git-hooks/commit-msg | 48 ++ .git-hooks/commit-subjects-goalie.txt | 8 + .git-hooks/footer-template.erb.txt | 16 + .git-hooks/prepare-commit-msg | 19 + .github/FUNDING.yml | 4 +- .github/dependabot.yml | 13 + .github/workflows/ancient.yml | 81 +++ .github/workflows/auto-assign.yml | 21 + .github/workflows/codeql-analysis.yml | 70 +++ .github/workflows/coverage.yml | 127 +++++ .github/workflows/current.yml | 91 ++++ .github/workflows/dep-heads.yml | 105 ++++ .github/workflows/dependency-review.yml | 20 + .github/workflows/discord-notifier.yml | 39 ++ .github/workflows/heads.yml | 102 ++++ .github/workflows/jruby.yml | 72 +++ .github/workflows/legacy.yml | 76 +++ .github/workflows/locked_deps.yml | 85 +++ .github/workflows/opencollective.yml | 40 ++ .github/workflows/style.yml | 65 +++ .github/workflows/supported.yml | 75 +++ .github/workflows/truffle.yml | 93 ++++ .github/workflows/unlocked_deps.yml | 84 +++ .github/workflows/unsupported.yml | 76 +++ .gitignore | 53 +- .gitlab-ci.yml | 136 +++++ .idea/oauth-tty.iml | 210 +++++--- .idea/vcs.xml | 7 +- .junie/guidelines-rbs.md | 49 ++ .junie/guidelines.md | 139 +++++ .opencollective.yml | 3 + .qlty/qlty.toml | 79 +++ .rspec | 8 +- .rubocop.yml | 27 +- .rubocop_gradual.lock | 47 ++ .rubocop_rspec.yml | 30 ++ .simplecov | 42 +- .tool-versions | 1 + .yard_gfm_support.rb | 22 + .yardopts | 11 + Appraisal.root.gemfile | 12 + Appraisals | 100 ++++ CHANGELOG.md | 42 +- CITATION.cff | 9 +- CODE_OF_CONDUCT.md | 7 +- CONTRIBUTING.md | 146 ++++- FUNDING.md | 77 +++ Gemfile | 67 +-- Gemfile.lock | 478 ++++++++++++----- README.md | 500 ++++++++++++------ RUBOCOP.md | 71 +++ Rakefile | 69 ++- SECURITY.md | 26 +- bin/appraisal | 16 + bin/bundle-audit | 16 + bin/bundler-audit | 16 + bin/code_climate_reek | 16 + bin/erb | 16 + bin/gem_checksums | 16 + bin/htmldiff | 16 + bin/irb | 16 + bin/kettle-changelog | 16 + bin/kettle-commit-msg | 16 + bin/kettle-dev-setup | 16 + bin/kettle-dvcs | 16 + bin/kettle-pre-release | 16 + bin/kettle-readme-backers | 16 + bin/kettle-release | 16 + bin/kramdown | 16 + bin/ldiff | 16 + bin/nokogiri | 16 + bin/oauth | 16 + bin/racc | 16 + bin/rackup | 16 + bin/rake | 16 + bin/rbs | 16 + bin/rdbg | 16 + bin/rdoc | 16 + bin/reek | 16 + bin/restclient | 16 + bin/ri | 16 + bin/rspec | 16 + bin/rubocop | 16 + bin/rubocop-gradual | 16 + bin/ruby-parse | 16 + bin/ruby-rewrite | 16 + bin/standardrb | 16 + bin/thor | 16 + bin/yard | 16 + bin/yard-junk | 16 + bin/yardoc | 16 + bin/yri | 16 + gemfiles/README.md | 21 - gemfiles/audit.gemfile | 7 + gemfiles/coverage.gemfile | 11 + gemfiles/current.gemfile | 7 + gemfiles/dep_heads.gemfile | 7 + gemfiles/head.gemfile | 9 + gemfiles/modular/audit.gemfile | 5 + gemfiles/modular/base64/r2.3/v0.1.gemfile | 2 + gemfiles/modular/base64/r2/v0.2.gemfile | 1 + gemfiles/modular/base64/r3/v0.3.gemfile | 1 + gemfiles/modular/base64/vHEAD.gemfile | 2 + gemfiles/modular/coverage.gemfile | 6 + gemfiles/modular/debug.gemfile | 13 + gemfiles/modular/documentation.gemfile | 11 + gemfiles/modular/erb/r2.3/default.gemfile | 6 + gemfiles/modular/erb/r2.6/v2.2.gemfile | 3 + gemfiles/modular/erb/r2/v3.0.gemfile | 1 + gemfiles/modular/erb/r3.1/v4.0.gemfile | 2 + gemfiles/modular/erb/r3/v5.0.gemfile | 1 + gemfiles/modular/erb/vHEAD.gemfile | 2 + gemfiles/modular/injected.gemfile | 60 +++ gemfiles/modular/mutex_m/r2.4/v0.1.gemfile | 3 + gemfiles/modular/mutex_m/r2/v0.3.gemfile | 2 + gemfiles/modular/mutex_m/r3/v0.3.gemfile | 2 + gemfiles/modular/mutex_m/vHEAD.gemfile | 2 + gemfiles/modular/optional.gemfile | 1 + gemfiles/modular/runtime_heads.gemfile | 8 + gemfiles/modular/stringio/r2.4/v0.0.2.gemfile | 4 + gemfiles/modular/stringio/r2/v3.0.gemfile | 5 + gemfiles/modular/stringio/r3/v3.0.gemfile | 5 + gemfiles/modular/stringio/vHEAD.gemfile | 2 + gemfiles/modular/style.gemfile | 25 + gemfiles/modular/x_std_libs.gemfile | 2 + gemfiles/modular/x_std_libs/r2.3/libs.gemfile | 4 + gemfiles/modular/x_std_libs/r2.4/libs.gemfile | 4 + gemfiles/modular/x_std_libs/r2.6/libs.gemfile | 4 + gemfiles/modular/x_std_libs/r2/libs.gemfile | 4 + gemfiles/modular/x_std_libs/r3.1/libs.gemfile | 4 + gemfiles/modular/x_std_libs/r3/libs.gemfile | 4 + gemfiles/modular/x_std_libs/vHEAD.gemfile | 4 + gemfiles/ruby_2_3.gemfile | 7 + gemfiles/ruby_2_4.gemfile | 7 + gemfiles/ruby_2_5.gemfile | 7 + gemfiles/ruby_2_6.gemfile | 7 + gemfiles/ruby_2_7.gemfile | 7 + gemfiles/ruby_3_0.gemfile | 7 + gemfiles/ruby_3_1.gemfile | 7 + gemfiles/ruby_3_2.gemfile | 7 + gemfiles/ruby_3_3.gemfile | 7 + gemfiles/style.gemfile | 9 + gemfiles/unlocked_deps.gemfile | 15 + lib/oauth/tty.rb | 15 +- lib/oauth/tty/cli.rb | 4 +- lib/oauth/tty/command.rb | 6 +- lib/oauth/tty/commands/authorize_command.rb | 21 +- lib/oauth/tty/commands/query_command.rb | 9 +- lib/oauth/tty/commands/sign_command.rb | 33 +- lib/oauth/tty/commands/version_command.rb | 6 +- oauth-tty.gemspec | 166 +++++- spec/config/debug.rb | 4 + spec/config/rspec/rack_test.rb | 5 + spec/config/rspec/rspec_block_is_expected.rb | 2 + spec/config/rspec/rspec_core.rb | 11 + spec/config/rspec/rspec_pending_for.rb | 6 + spec/config/rspec/version_gem.rb | 1 + spec/config/vcr.rb | 12 + spec/oauth/backwards_compatibility_spec.rb | 8 + spec/oauth/cli_spec.rb | 7 - spec/oauth/tty/cli_spec.rb | 309 +++++++++++ spec/oauth/tty/version_spec.rb | 11 + spec/oauth/tty_spec.rb | 4 + spec/spec_helper.rb | 35 +- test/backwards_compatibility_test.rb | 10 - test/cli_test.rb | 308 ----------- test/test_helper.rb | 61 --- 171 files changed, 5019 insertions(+), 1029 deletions(-) create mode 100644 .aiignore create mode 100644 .devcontainer/devcontainer.json create mode 100644 .env.local.example create mode 100644 .envrc create mode 100644 .git-hooks/commit-msg create mode 100644 .git-hooks/commit-subjects-goalie.txt create mode 100644 .git-hooks/footer-template.erb.txt create mode 100644 .git-hooks/prepare-commit-msg create mode 100644 .github/dependabot.yml create mode 100644 .github/workflows/ancient.yml create mode 100644 .github/workflows/auto-assign.yml create mode 100644 .github/workflows/codeql-analysis.yml create mode 100644 .github/workflows/coverage.yml create mode 100644 .github/workflows/current.yml create mode 100644 .github/workflows/dep-heads.yml create mode 100644 .github/workflows/dependency-review.yml create mode 100644 .github/workflows/discord-notifier.yml create mode 100644 .github/workflows/heads.yml create mode 100644 .github/workflows/jruby.yml create mode 100644 .github/workflows/legacy.yml create mode 100644 .github/workflows/locked_deps.yml create mode 100644 .github/workflows/opencollective.yml create mode 100644 .github/workflows/style.yml create mode 100644 .github/workflows/supported.yml create mode 100644 .github/workflows/truffle.yml create mode 100644 .github/workflows/unlocked_deps.yml create mode 100644 .github/workflows/unsupported.yml create mode 100644 .gitlab-ci.yml create mode 100644 .junie/guidelines-rbs.md create mode 100644 .junie/guidelines.md create mode 100644 .opencollective.yml create mode 100644 .qlty/qlty.toml create mode 100644 .rubocop_gradual.lock create mode 100644 .rubocop_rspec.yml create mode 100644 .tool-versions create mode 100644 .yard_gfm_support.rb create mode 100644 .yardopts create mode 100644 Appraisal.root.gemfile create mode 100644 Appraisals create mode 100644 FUNDING.md create mode 100644 RUBOCOP.md create mode 100644 bin/appraisal create mode 100644 bin/bundle-audit create mode 100644 bin/bundler-audit create mode 100644 bin/code_climate_reek create mode 100644 bin/erb create mode 100644 bin/gem_checksums create mode 100644 bin/htmldiff create mode 100644 bin/irb create mode 100644 bin/kettle-changelog create mode 100644 bin/kettle-commit-msg create mode 100644 bin/kettle-dev-setup create mode 100644 bin/kettle-dvcs create mode 100644 bin/kettle-pre-release create mode 100644 bin/kettle-readme-backers create mode 100644 bin/kettle-release create mode 100644 bin/kramdown create mode 100644 bin/ldiff create mode 100644 bin/nokogiri create mode 100644 bin/oauth create mode 100644 bin/racc create mode 100644 bin/rackup create mode 100644 bin/rake create mode 100644 bin/rbs create mode 100644 bin/rdbg create mode 100644 bin/rdoc create mode 100644 bin/reek create mode 100644 bin/restclient create mode 100644 bin/ri create mode 100644 bin/rspec create mode 100644 bin/rubocop create mode 100644 bin/rubocop-gradual create mode 100644 bin/ruby-parse create mode 100644 bin/ruby-rewrite create mode 100644 bin/standardrb create mode 100644 bin/thor create mode 100644 bin/yard create mode 100644 bin/yard-junk create mode 100644 bin/yardoc create mode 100644 bin/yri delete mode 100644 gemfiles/README.md create mode 100644 gemfiles/audit.gemfile create mode 100644 gemfiles/coverage.gemfile create mode 100644 gemfiles/current.gemfile create mode 100644 gemfiles/dep_heads.gemfile create mode 100644 gemfiles/head.gemfile create mode 100644 gemfiles/modular/audit.gemfile create mode 100644 gemfiles/modular/base64/r2.3/v0.1.gemfile create mode 100644 gemfiles/modular/base64/r2/v0.2.gemfile create mode 100644 gemfiles/modular/base64/r3/v0.3.gemfile create mode 100644 gemfiles/modular/base64/vHEAD.gemfile create mode 100644 gemfiles/modular/coverage.gemfile create mode 100644 gemfiles/modular/debug.gemfile create mode 100644 gemfiles/modular/documentation.gemfile create mode 100644 gemfiles/modular/erb/r2.3/default.gemfile create mode 100644 gemfiles/modular/erb/r2.6/v2.2.gemfile create mode 100644 gemfiles/modular/erb/r2/v3.0.gemfile create mode 100644 gemfiles/modular/erb/r3.1/v4.0.gemfile create mode 100644 gemfiles/modular/erb/r3/v5.0.gemfile create mode 100644 gemfiles/modular/erb/vHEAD.gemfile create mode 100644 gemfiles/modular/injected.gemfile create mode 100644 gemfiles/modular/mutex_m/r2.4/v0.1.gemfile create mode 100644 gemfiles/modular/mutex_m/r2/v0.3.gemfile create mode 100644 gemfiles/modular/mutex_m/r3/v0.3.gemfile create mode 100644 gemfiles/modular/mutex_m/vHEAD.gemfile create mode 100644 gemfiles/modular/optional.gemfile create mode 100644 gemfiles/modular/runtime_heads.gemfile create mode 100644 gemfiles/modular/stringio/r2.4/v0.0.2.gemfile create mode 100644 gemfiles/modular/stringio/r2/v3.0.gemfile create mode 100644 gemfiles/modular/stringio/r3/v3.0.gemfile create mode 100644 gemfiles/modular/stringio/vHEAD.gemfile create mode 100644 gemfiles/modular/style.gemfile create mode 100644 gemfiles/modular/x_std_libs.gemfile create mode 100644 gemfiles/modular/x_std_libs/r2.3/libs.gemfile create mode 100644 gemfiles/modular/x_std_libs/r2.4/libs.gemfile create mode 100644 gemfiles/modular/x_std_libs/r2.6/libs.gemfile create mode 100644 gemfiles/modular/x_std_libs/r2/libs.gemfile create mode 100644 gemfiles/modular/x_std_libs/r3.1/libs.gemfile create mode 100644 gemfiles/modular/x_std_libs/r3/libs.gemfile create mode 100644 gemfiles/modular/x_std_libs/vHEAD.gemfile create mode 100644 gemfiles/ruby_2_3.gemfile create mode 100644 gemfiles/ruby_2_4.gemfile create mode 100644 gemfiles/ruby_2_5.gemfile create mode 100644 gemfiles/ruby_2_6.gemfile create mode 100644 gemfiles/ruby_2_7.gemfile create mode 100644 gemfiles/ruby_3_0.gemfile create mode 100644 gemfiles/ruby_3_1.gemfile create mode 100644 gemfiles/ruby_3_2.gemfile create mode 100644 gemfiles/ruby_3_3.gemfile create mode 100644 gemfiles/style.gemfile create mode 100644 gemfiles/unlocked_deps.gemfile create mode 100644 spec/config/debug.rb create mode 100644 spec/config/rspec/rack_test.rb create mode 100644 spec/config/rspec/rspec_block_is_expected.rb create mode 100644 spec/config/rspec/rspec_core.rb create mode 100644 spec/config/rspec/rspec_pending_for.rb create mode 100644 spec/config/rspec/version_gem.rb create mode 100644 spec/config/vcr.rb create mode 100644 spec/oauth/backwards_compatibility_spec.rb delete mode 100644 spec/oauth/cli_spec.rb create mode 100644 spec/oauth/tty/cli_spec.rb create mode 100644 spec/oauth/tty/version_spec.rb create mode 100644 spec/oauth/tty_spec.rb delete mode 100644 test/backwards_compatibility_test.rb delete mode 100644 test/cli_test.rb delete mode 100644 test/test_helper.rb diff --git a/.aiignore b/.aiignore new file mode 100644 index 0000000..df6bd8b --- /dev/null +++ b/.aiignore @@ -0,0 +1,19 @@ +# An .aiignore file follows the same syntax as a .gitignore file. +# .gitignore documentation: https://git-scm.com/docs/gitignore + +# you can ignore files +.DS_Store +*.log +*.tmp + +# or folders +.devcontainer/ +.qlty/ +.yardoc/ +dist/ +build/ +out/ +coverage/ +docs/ +pkg/ +results/ diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 0000000..c5fee1c --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,26 @@ +// For format details, see https://aka.ms/devcontainer.json. For config options, see the +// README at: https://github.com/devcontainers/templates/tree/main/src/ruby +{ + "name": "Ruby", + // Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile + "image": "mcr.microsoft.com/devcontainers/ruby:1-3-bookworm", + + // Features to add to the dev container. More info: https://containers.dev/features. + // "features": {}, + + // Use 'forwardPorts' to make a list of ports inside the container available locally. + // "forwardPorts": [], + + // Use 'postCreateCommand' to run commands after the container is created. + // "postCreateCommand": "ruby --version", + + // Configure tool-specific properties. + "customizations" : { + "jetbrains" : { + "backend" : "RubyMine" + } + }, + + // Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root. + // "remoteUser": "root" +} diff --git a/.env.local.example b/.env.local.example new file mode 100644 index 0000000..7729745 --- /dev/null +++ b/.env.local.example @@ -0,0 +1,27 @@ +# +# DO NOT EDIT THIS FILE +# +# COPT THIS FILE TO .env.local +# +# That file is ignored by .gitignore. This file is not. +# +export DEBUG=false # do not allow byebug statements (override in .env.local) +export FLOSS_FUNDING_DEBUG=false # extra logging to help diagnose issues (override in .env.local) +export AUTOGEN_FIXTURE_CLEANUP=false # autogenerated gem fixture cleanup after every RSpec run +export GIT_HOOK_FOOTER_APPEND=false +export GIT_HOOK_FOOTER_APPEND_DEBUG=false +export GIT_HOOK_FOOTER_SENTINEL="âšĄī¸ A message from a fellow meat-based-AI" + +# Tokens used by ci:act and CI helpers for reading workflow/pipeline status via APIs +# GitHub (either GITHUB_TOKEN or GH_TOKEN will be used; fine-grained recommended) +# - Scope/permissions: For fine-grained tokens, grant repository access (Read) and Actions: Read +# - For classic tokens, public repos need no scopes; private repos typically require repo +export GITHUB_TOKEN= +# Alternatively: +# export GH_TOKEN= + +# GitLab (either GITLAB_TOKEN or GL_TOKEN will be used) +# - Scope: read_api is sufficient to read pipelines +export GITLAB_TOKEN= +# Alternatively: +# export GL_TOKEN= diff --git a/.envrc b/.envrc new file mode 100644 index 0000000..800bc2d --- /dev/null +++ b/.envrc @@ -0,0 +1,46 @@ +# Run any command in this library's bin/ without the bin/ prefix! +# Prefer exe version over binstub +PATH_add exe +PATH_add bin + +# Only add things to this file that should be shared with the team. + +# **dotenv** (See end of file for .env.local integration) +# .env would override anything in this file, if enabled. +# .env is a DOCKER standard, and if we use it, it would be in deployed, or DOCKER, environments. +# Override and customize anything below in your own .env.local +# If you are using dotenv and not direnv, +# copy the following `export` statements to your own .env file. + +### General Ruby ### +# Turn off Ruby Warnings about deprecated code +# export RUBYOPT="-W0" + +### External Testing Controls +export K_SOUP_COV_DO=true # Means you want code coverage +export K_SOUP_COV_COMMAND_NAME="Test Coverage" +# Available formats are html, xml, rcov, lcov, json, tty +export K_SOUP_COV_FORMATTERS="html,xml,rcov,lcov,json,tty" +export K_SOUP_COV_MIN_BRANCH=80 # Means you want to enforce X% branch coverage +export K_SOUP_COV_MIN_LINE=96 # Means you want to enforce X% line coverage +export K_SOUP_COV_MIN_HARD=true # Means you want the build to fail if the coverage thresholds are not met +export K_SOUP_COV_MULTI_FORMATTERS=true +export K_SOUP_COV_OPEN_BIN= # Means don't try to open coverage results in browser +export MAX_ROWS=1 # Setting for simplecov-console gem for tty output, limits to the worst N rows of bad coverage +export KETTLE_TEST_SILENT=true + +# Internal Debugging Controls +export DEBUG=false # do not allow byebug statements (override in .env.local) +export FLOSS_CFG_FUND_DEBUG=false # extra logging to help diagnose issues (override in .env.local) +export FLOSS_CFG_FUND_LOGFILE=tmp/log/debug.log + +# Concurrently developing the rubocop-lts suite? +export RUBOCOP_LTS_LOCAL=false + +# .env would override anything in this file, if `dotenv` is uncommented below. +# .env is a DOCKER standard, and if we use it, it would be in deployed, or DOCKER, environments, +# and that is why we generally want to leave it commented out. +# dotenv + +# .env.local will override anything in this file. +dotenv_if_exists .env.local diff --git a/.git-hooks/commit-msg b/.git-hooks/commit-msg new file mode 100644 index 0000000..750c5bb --- /dev/null +++ b/.git-hooks/commit-msg @@ -0,0 +1,48 @@ +#!/usr/bin/env ruby +# vim: set syntax=ruby + +# Do not rely on Bundler; allow running outside a Bundler context +begin + require "rubygems" +rescue LoadError + # continue +end + +begin + # External gems + require "gitmoji/regex" + + full_text = File.read(ARGV[0]) + # Is the first character a GitMoji? + gitmoji_index = full_text =~ Gitmoji::Regex::REGEX + if gitmoji_index == 0 + exit 0 + else + denied = < e + warn("gitmoji-regex gem not found: #{e.class}: #{e.message}.\n\tSkipping gitmoji check and allowing commit to proceed.\n\tRecommendation: add 'gitmoji-regex' to your development dependencies to enable this check.") + exit 0 +end diff --git a/.git-hooks/commit-subjects-goalie.txt b/.git-hooks/commit-subjects-goalie.txt new file mode 100644 index 0000000..54b905a --- /dev/null +++ b/.git-hooks/commit-subjects-goalie.txt @@ -0,0 +1,8 @@ +🔖 Prepare release v +đŸ”’ī¸ Checksums for v + +# Lines beginning with # are ignored. +# This file is read by .git-hooks/prepare-commit-msg in each project. +# Each line of this file will be matched against the commit subject using `starts_with?`. +# If any `starts_with?` match the project script bin/prepare-commit-msg will run. +# đŸ”’ī¸ Checksums for v is the standard commit message by stone_checksums. diff --git a/.git-hooks/footer-template.erb.txt b/.git-hooks/footer-template.erb.txt new file mode 100644 index 0000000..d732d69 --- /dev/null +++ b/.git-hooks/footer-template.erb.txt @@ -0,0 +1,16 @@ +âšĄī¸ A message from a fellow meat-based-AI âšĄī¸ +- [â¤ī¸] Finely-crafted open-source tools like <%= @gem_name %> (& many more) are a full-time endeavor. +- [â¤ī¸] Though I adore my work, it lacks financial sustainability. +- [â¤ī¸] Please, help me continue enhancing your tools by becoming a sponsor: + - [💲] https://liberapay.com/pboling/donate + - [💲] https://github.com/sponsors/pboling + +<% if ENV["GIT_HOOK_FOOTER_APPEND_DEBUG"] == "true" %> + @pwd = <%= @pwd %> + @gemspecs = <%= @gemspecs %> + @spec = <%= @spec %> + @gemspec_path = <%= @gemspec_path %> + @gem_name <%= @gem_name %> + @spec_name <%= @spec_name %> + @content <%= @content %> +<% end %> diff --git a/.git-hooks/prepare-commit-msg b/.git-hooks/prepare-commit-msg new file mode 100644 index 0000000..c6a1557 --- /dev/null +++ b/.git-hooks/prepare-commit-msg @@ -0,0 +1,19 @@ +#!/bin/sh + +# Fail on error and unset variables +set -eu + +# Determine project root as the parent directory of this hook script +PROJECT_ROOT="$(CDPATH= cd -- "$(dirname -- "$0")"/.. && pwd)" + +# Run the Ruby hook within the direnv context (if available), +# so ENV from .envrc/.env.local at project root is loaded. +# One of the things .envrc needs to do is add $PROJECT_ROOT/bin/ to the path. +# You should have this line at the top of .envrc +# PATH_add bin +# NOTE: If this project ships exe scripts it should also add that. +if command -v direnv >/dev/null 2>&1; then + exec direnv exec "$PROJECT_ROOT" "kettle-commit-msg" "$@" +else + raise "direnv not found. Local development of this project ($PROJECT_ROOT) with tools from the kettle-dev gem may not work properly. Please run 'brew install direnv'." +fi diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml index 5c0523c..8f98042 100644 --- a/.github/FUNDING.yml +++ b/.github/FUNDING.yml @@ -6,8 +6,8 @@ github: [pboling] # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., issuehunt: pboling # Replace with a single IssueHunt username ko_fi: pboling # Replace with a single Ko-fi username liberapay: pboling # Replace with a single Liberapay username -open_collective: ruby-oauth # Replace with a single Open Collective username +open_collective: ruby-oauth patreon: galtzo # Replace with a single Patreon username polar: pboling thanks_dev: u/gh/pboling -tidelift: rubygems/oauth-tty # Replace with a single Tidelift platform-name/package-name e.g., npm/babel +tidelift: rubygems/oauth-tty diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..956aa5a --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,13 @@ +version: 2 +updates: + - package-ecosystem: bundler + directory: "/" + schedule: + interval: "weekly" + open-pull-requests-limit: 5 + ignore: + - dependency-name: "rubocop-lts" + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "weekly" diff --git a/.github/workflows/ancient.yml b/.github/workflows/ancient.yml new file mode 100644 index 0000000..3cc6e37 --- /dev/null +++ b/.github/workflows/ancient.yml @@ -0,0 +1,81 @@ +name: MRI 2.3, 2.4, 2.5 (EOL) + +permissions: + contents: read + +on: + push: + branches: + - 'main' + - '*-stable' + tags: + - '!*' # Do not execute on tags + pull_request: + branches: + - '*' + # Allow manually triggering the workflow. + workflow_dispatch: + +# Cancels all previous workflow runs for the same branch that have not yet completed. +concurrency: + # The concurrency group contains the workflow name and the branch name. + group: "${{ github.workflow }}-${{ github.ref }}" + cancel-in-progress: true + +jobs: + test: + if: "!contains(github.event.commits[0].message, '[ci skip]') && !contains(github.event.commits[0].message, '[skip ci]')" + name: Specs ${{ matrix.ruby }} ${{ matrix.appraisal }}${{ matrix.name_extra || '' }} + runs-on: ubuntu-22.04 + continue-on-error: ${{ matrix.experimental || endsWith(matrix.ruby, 'head') }} + env: # $BUNDLE_GEMFILE must be set at job level, so it is set for all steps + BUNDLE_GEMFILE: ${{ github.workspace }}/${{ matrix.gemfile }}.gemfile + strategy: + fail-fast: false + matrix: + include: + # Ruby 2.3 + - ruby: "ruby-2.3" + appraisal: "ruby-2-3" + exec_cmd: "rake test" + gemfile: "Appraisal.root" + rubygems: "3.3.27" + bundler: "2.3.27" + + # Ruby 2.4 + - ruby: "ruby-2.4" + appraisal: "ruby-2-4" + exec_cmd: "rake test" + gemfile: "Appraisal.root" + rubygems: "3.3.27" + bundler: "2.3.27" + + # Ruby 2.5 + - ruby: "ruby-2.5" + appraisal: "ruby-2-5" + exec_cmd: "rake test" + gemfile: "Appraisal.root" + rubygems: "3.3.27" + bundler: "2.3.27" + + steps: + - name: Checkout + uses: actions/checkout@v5 + + - name: Setup Ruby & RubyGems + uses: ruby/setup-ruby@v1 + with: + ruby-version: ${{ matrix.ruby }} + rubygems: ${{ matrix.rubygems }} + bundler: ${{ matrix.bundler }} + bundler-cache: false + + # Raw `bundle` will use the BUNDLE_GEMFILE set to matrix.gemfile (i.e. Appraisal.root) + # We need to do this first to get appraisal installed. + # NOTE: This does not use the primary Gemfile at all. + - name: Install Root Appraisal + run: bundle + - name: Appraisal for ${{ matrix.appraisal }} + run: bundle exec appraisal ${{ matrix.appraisal }} bundle + - name: Tests for ${{ matrix.ruby }} via ${{ matrix.exec_cmd }} + run: bundle exec appraisal ${{ matrix.appraisal }} bundle exec ${{ matrix.exec_cmd }} diff --git a/.github/workflows/auto-assign.yml b/.github/workflows/auto-assign.yml new file mode 100644 index 0000000..96975f2 --- /dev/null +++ b/.github/workflows/auto-assign.yml @@ -0,0 +1,21 @@ +name: Auto Assign +on: + issues: + types: [opened] + pull_request: + types: [opened] +jobs: + run: + runs-on: ubuntu-latest + permissions: + issues: write + pull-requests: write + steps: + - name: 'Auto-assign issue' + uses: pozil/auto-assign-issue@v2 + with: + repo-token: ${{ secrets.GITHUB_TOKEN }} + assignees: pboling + abortIfPreviousAssignees: true + allowSelfAssign: true + numOfAssignee: 1 \ No newline at end of file diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml new file mode 100644 index 0000000..45a8ec2 --- /dev/null +++ b/.github/workflows/codeql-analysis.yml @@ -0,0 +1,70 @@ +# For most projects, this workflow file will not need changing; you simply need +# to commit it to your repository. +# +# You may wish to alter this file to override the set of languages analyzed, +# or to provide custom queries or build logic. +# +# ******** NOTE ******** +# We have attempted to detect the languages in your repository. Please check +# the `language` matrix defined below to confirm you have the correct set of +# supported CodeQL languages. +# +name: "CodeQL" + +on: + push: + branches: [ main, '*-stable' ] + pull_request: + # The branches below must be a subset of the branches above + branches: [ main, '*-stable' ] + schedule: + - cron: '35 1 * * 5' + +jobs: + analyze: + name: Analyze + runs-on: ubuntu-latest + permissions: + actions: read + contents: read + security-events: write + + strategy: + fail-fast: false + matrix: + language: [ 'ruby' ] + # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ] + # Learn more about CodeQL language support at https://git.io/codeql-language-support + + steps: + - name: Checkout repository + uses: actions/checkout@v5 + + # Initializes the CodeQL tools for scanning. + - name: Initialize CodeQL + uses: github/codeql-action/init@v3 + with: + languages: ${{ matrix.language }} + # If you wish to specify custom queries, you can do so here or in a config file. + # By default, queries listed here will override any specified in a config file. + # Prefix the list here with "+" to use these queries and those in the config file. + # queries: ./path/to/local/query, your-org/your-repo/queries@main + + # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). + # If this step fails, then you should remove it and run the build manually (see below) + - name: Autobuild + uses: github/codeql-action/autobuild@v3 + + # â„šī¸ Command-line programs to run using the OS shell. + # 📚 https://git.io/JvXDl + + # âœī¸ If the Autobuild fails above, remove it and uncomment the following three lines + # and modify them (or add more) to build your code if your project + # uses a compiled language + + #- run: | + # make bootstrap + # make release + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v3 diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml new file mode 100644 index 0000000..c9d6a2e --- /dev/null +++ b/.github/workflows/coverage.yml @@ -0,0 +1,127 @@ +name: Test Coverage + +permissions: + contents: read + pull-requests: write + id-token: write + +env: + K_SOUP_COV_MIN_BRANCH: 100 + K_SOUP_COV_MIN_LINE: 100 + K_SOUP_COV_MIN_HARD: true + K_SOUP_COV_FORMATTERS: "xml,rcov,lcov,tty" + K_SOUP_COV_DO: true + K_SOUP_COV_MULTI_FORMATTERS: true + K_SOUP_COV_COMMAND_NAME: "Test Coverage" + +on: + push: + branches: + - 'main' + - '*-stable' + tags: + - '!*' # Do not execute on tags + pull_request: + branches: + - '*' + # Allow manually triggering the workflow. + workflow_dispatch: + +# Cancels all previous workflow runs for the same branch that have not yet completed. +concurrency: + # The concurrency group contains the workflow name and the branch name. + group: "${{ github.workflow }}-${{ github.ref }}" + cancel-in-progress: true + +jobs: + coverage: + if: "!contains(github.event.commits[0].message, '[ci skip]') && !contains(github.event.commits[0].message, '[skip ci]')" + name: Code Coverage on ${{ matrix.ruby }}@current + runs-on: ubuntu-latest + continue-on-error: ${{ matrix.experimental || endsWith(matrix.ruby, 'head') }} + env: # $BUNDLE_GEMFILE must be set at job level, so it is set for all steps + BUNDLE_GEMFILE: ${{ github.workspace }}/${{ matrix.gemfile }}.gemfile + strategy: + fail-fast: false + matrix: + include: + # Coverage + - ruby: "ruby" + appraisal: "coverage" + exec_cmd: "rake test" + gemfile: "Appraisal.root" + rubygems: latest + bundler: latest + + steps: + - name: Checkout + uses: actions/checkout@v5 + + - name: Setup Ruby & RubyGems + uses: ruby/setup-ruby@v1 + with: + ruby-version: "${{ matrix.ruby }}" + rubygems: "${{ matrix.rubygems }}" + bundler: "${{ matrix.bundler }}" + bundler-cache: false + + # Raw `bundle` will use the BUNDLE_GEMFILE set to matrix.gemfile (i.e. Appraisal.root) + # We need to do this first to get appraisal installed. + # NOTE: This does not use the primary Gemfile at all. + - name: Install Root Appraisal + run: bundle + - name: Appraisal for ${{ matrix.appraisal }} + run: bundle exec appraisal ${{ matrix.appraisal }} bundle + - name: Tests for ${{ matrix.ruby }}@current via ${{ matrix.exec_cmd }} + run: bundle exec appraisal ${{ matrix.appraisal }} bundle exec ${{ matrix.exec_cmd }} + + # Do SaaS coverage uploads first + - name: Upload coverage to Coveralls + if: ${{ !env.ACT }} + uses: coverallsapp/github-action@master + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + continue-on-error: ${{ matrix.experimental != 'false' }} + + - name: Upload coverage to QLTY + if: ${{ !env.ACT }} + uses: qltysh/qlty-action/coverage@main + with: + token: ${{secrets.QLTY_COVERAGE_TOKEN}} + files: coverage/.resultset.json + continue-on-error: ${{ matrix.experimental != 'false' }} + + # Build will fail here if coverage upload fails + # which will hopefully be noticed for the lack of code coverage comments + - name: Upload coverage to CodeCov + if: ${{ !env.ACT }} + uses: codecov/codecov-action@v5 + with: + use_oidc: true + fail_ci_if_error: false # optional (default = false) + files: coverage/lcov.info,coverage/coverage.xml + verbose: true # optional (default = false) + + # Then PR comments + - name: Code Coverage Summary Report + if: ${{ !env.ACT && github.event_name == 'pull_request' }} + uses: irongut/CodeCoverageSummary@v1.3.0 + with: + filename: ./coverage/coverage.xml + badge: true + fail_below_min: true + format: markdown + hide_branch_rate: false + hide_complexity: true + indicators: true + output: both + thresholds: '100 100' + continue-on-error: ${{ matrix.experimental != 'false' }} + + - name: Add Coverage PR Comment + uses: marocchino/sticky-pull-request-comment@v2 + if: ${{ !env.ACT && github.event_name == 'pull_request' }} + with: + recreate: true + path: code-coverage-results.md + continue-on-error: ${{ matrix.experimental != 'false' }} diff --git a/.github/workflows/current.yml b/.github/workflows/current.yml new file mode 100644 index 0000000..72e44fe --- /dev/null +++ b/.github/workflows/current.yml @@ -0,0 +1,91 @@ +# Targets the evergreen latest release of ruby, truffleruby, and jruby +name: Current + +permissions: + contents: read + +env: + K_SOUP_COV_DO: false + +on: + push: + branches: + - 'main' + - '*-stable' + tags: + - '!*' # Do not execute on tags + pull_request: + branches: + - '*' + # Allow manually triggering the workflow. + workflow_dispatch: + +# Cancels all previous workflow runs for the same branch that have not yet completed. +concurrency: + # The concurrency group contains the workflow name and the branch name. + group: "${{ github.workflow }}-${{ github.ref }}" + cancel-in-progress: true + +jobs: + test: + if: "!contains(github.event.commits[0].message, '[ci skip]') && !contains(github.event.commits[0].message, '[skip ci]')" + name: Specs ${{ matrix.ruby }}@${{ matrix.appraisal }} + runs-on: ubuntu-latest + continue-on-error: ${{ matrix.experimental || endsWith(matrix.ruby, 'head') }} + env: # $BUNDLE_GEMFILE must be set at job level, so it is set for all steps + BUNDLE_GEMFILE: ${{ github.workspace }}/${{ matrix.gemfile }}.gemfile + strategy: + matrix: + include: + # Ruby 3.4 + - ruby: "ruby" + appraisal: "current" + exec_cmd: "rake test" + gemfile: "Appraisal.root" + rubygems: latest + bundler: latest + + # truffleruby-24.1 + # (according to documentation: targets Ruby 3.3 compatibility) + # (according to runtime: targets Ruby 3.2 compatibility) + - ruby: "truffleruby" + appraisal: "current" + exec_cmd: "rake test" + gemfile: "Appraisal.root" + rubygems: default + bundler: default + + # jruby-10.0 (targets Ruby 3.4 compatibility) + - ruby: "jruby" + appraisal: "current" + exec_cmd: "rake test" + gemfile: "Appraisal.root" + rubygems: default + bundler: default + + steps: + - name: Checkout + if: ${{ !(env.ACT && startsWith(matrix.ruby, 'jruby')) }} + uses: actions/checkout@v5 + + - name: Setup Ruby & RubyGems + if: ${{ !(env.ACT && startsWith(matrix.ruby, 'jruby')) }} + uses: ruby/setup-ruby@v1 + with: + ruby-version: ${{ matrix.ruby }} + rubygems: ${{ matrix.rubygems }} + bundler: ${{ matrix.bundler }} + bundler-cache: false + + # Raw `bundle` will use the BUNDLE_GEMFILE set to matrix.gemfile (i.e. Appraisal.root) + # We need to do this first to get appraisal installed. + # NOTE: This does not use the primary Gemfile at all. + - name: Install Root Appraisal + if: ${{ !(env.ACT && startsWith(matrix.ruby, 'jruby')) }} + run: bundle + - name: Appraisal for ${{ matrix.ruby }}@${{ matrix.appraisal }} + if: ${{ !(env.ACT && startsWith(matrix.ruby, 'jruby')) }} + run: bundle exec appraisal ${{ matrix.appraisal }} bundle + - name: Tests for ${{ matrix.ruby }}@${{ matrix.appraisal }} via ${{ matrix.exec_cmd }} + if: ${{ !(env.ACT && startsWith(matrix.ruby, 'jruby')) }} + run: bundle exec appraisal ${{ matrix.appraisal }} bundle exec ${{ matrix.exec_cmd }} diff --git a/.github/workflows/dep-heads.yml b/.github/workflows/dep-heads.yml new file mode 100644 index 0000000..f691568 --- /dev/null +++ b/.github/workflows/dep-heads.yml @@ -0,0 +1,105 @@ +# Targets the evergreen latest release of ruby, truffleruby, and jruby +# and tests against the HEAD of runtime dependencies +name: Runtime Deps @ HEAD + +permissions: + contents: read + +env: + K_SOUP_COV_DO: false + +on: + push: + branches: + - 'main' + - '*-stable' + tags: + - '!*' # Do not execute on tags + pull_request: + branches: + - '*' + # Allow manually triggering the workflow. + workflow_dispatch: + +# Cancels all previous workflow runs for the same branch that have not yet completed. +concurrency: + # The concurrency group contains the workflow name and the branch name. + group: "${{ github.workflow }}-${{ github.ref }}" + cancel-in-progress: true + +jobs: + test: + if: "!contains(github.event.commits[0].message, '[ci skip]') && !contains(github.event.commits[0].message, '[skip ci]')" + name: Specs ${{ matrix.ruby }}@${{ matrix.appraisal }}${{ matrix.name_extra || '' }} + runs-on: ubuntu-latest + continue-on-error: ${{ matrix.experimental || endsWith(matrix.ruby, 'head') }} + env: # $BUNDLE_GEMFILE must be set at job level, so it is set for all steps + BUNDLE_GEMFILE: ${{ github.workspace }}/${{ matrix.gemfile }}.gemfile + strategy: + fail-fast: true + matrix: + include: + # Ruby 3.4 + - ruby: "ruby" + appraisal: "dep-heads" + exec_cmd: "rake test" + gemfile: "Appraisal.root" + rubygems: latest + bundler: latest + + # truffleruby-24.1 + # (according to documentation: targets Ruby 3.3 compatibility) + # (according to runtime: targets Ruby 3.2 compatibility) + - ruby: "truffleruby" + appraisal: "dep-heads" + exec_cmd: "rake test" + gemfile: "Appraisal.root" + rubygems: default + bundler: default + + # jruby-10.0 (targets Ruby 3.4 compatibility) + - ruby: "jruby" + appraisal: "dep-heads" + exec_cmd: "rake test" + gemfile: "Appraisal.root" + rubygems: default + bundler: default + + steps: + - name: Checkout + if: ${{ !(env.ACT && startsWith(matrix.ruby, 'jruby')) }} + uses: actions/checkout@v5 + + - name: Setup Ruby & RubyGems + if: ${{ !(env.ACT && startsWith(matrix.ruby, 'jruby')) }} + uses: ruby/setup-ruby@v1 + with: + ruby-version: ${{ matrix.ruby }} + rubygems: ${{ matrix.rubygems }} + bundler: ${{ matrix.bundler }} + bundler-cache: false + + # Raw `bundle` will use the BUNDLE_GEMFILE set to matrix.gemfile (i.e. Appraisal.root) + # We need to do this first to get appraisal installed. + # NOTE: This does not use the primary Gemfile at all. + - name: "Install Root Appraisal" + if: ${{ !(env.ACT && startsWith(matrix.ruby, 'jruby')) }} + run: bundle + + - name: "[Attempt 1] Appraisal for ${{ matrix.ruby }}@${{ matrix.appraisal }}" + if: ${{ !(env.ACT && startsWith(matrix.ruby, 'jruby')) }} + id: bundleAttempt1 + run: bundle exec appraisal ${{ matrix.appraisal }} bundle + # Continue to the next step on failure + continue-on-error: true + + # Effectively an automatic retry of the previous step. + - name: "[Attempt 2] Appraisal for ${{ matrix.ruby }}@${{ matrix.appraisal }}" + # If bundleAttempt1 failed, try again here; Otherwise skip. + if: ${{ steps.bundleAttempt1.outcome == 'failure' && !(env.ACT && startsWith(matrix.ruby, 'jruby')) }} + id: bundleAttempt2 + run: bundle exec appraisal ${{ matrix.appraisal }} bundle + + - name: Tests for ${{ matrix.ruby }}@${{ matrix.appraisal }} via ${{ matrix.exec_cmd }} + if: ${{ !(env.ACT && startsWith(matrix.ruby, 'jruby')) }} + run: bundle exec appraisal ${{ matrix.appraisal }} bundle exec ${{ matrix.exec_cmd }} diff --git a/.github/workflows/dependency-review.yml b/.github/workflows/dependency-review.yml new file mode 100644 index 0000000..046e9c8 --- /dev/null +++ b/.github/workflows/dependency-review.yml @@ -0,0 +1,20 @@ +# Dependency Review Action +# +# This Action will scan dependency manifest files that change as part of a Pull Request, surfacing known-vulnerable versions of the packages declared or updated in the PR. Once installed, if the workflow run is marked as required, PRs introducing known-vulnerable packages will be blocked from merging. +# +# Source repository: https://github.com/actions/dependency-review-action +# Public documentation: https://docs.github.com/en/code-security/supply-chain-security/understanding-your-software-supply-chain/about-dependency-review#dependency-review-enforcement +name: 'Dependency Review' +on: [pull_request] + +permissions: + contents: read + +jobs: + dependency-review: + runs-on: ubuntu-latest + steps: + - name: 'Checkout Repository' + uses: actions/checkout@v5 + - name: 'Dependency Review' + uses: actions/dependency-review-action@v4 diff --git a/.github/workflows/discord-notifier.yml b/.github/workflows/discord-notifier.yml new file mode 100644 index 0000000..ad98367 --- /dev/null +++ b/.github/workflows/discord-notifier.yml @@ -0,0 +1,39 @@ +name: Discord Notify + +on: + check_run: + types: [completed] + discussion: + types: [ created ] + discussion_comment: + types: [ created ] + fork: + gollum: + issues: + types: [ opened ] + issue_comment: + types: [ created ] + pull_request: + types: [ opened, reopened, closed ] + release: + types: [ published ] + watch: + types: [ started ] + +# A workflow run is made up of one or more jobs that can run sequentially or in parallel +jobs: + # This workflow contains a single job called "build" + notify: + if: false + # The type of runner that the job will run on + runs-on: ubuntu-latest + + # Steps represent a sequence of tasks that will be executed as part of the job + steps: + - name: Actions Status Discord + uses: sarisia/actions-status-discord@v1 + if: always() + with: + webhook: ${{ secrets.DISCORD_WEBHOOK }} + status: ${{ job.status }} + username: GitHub Actions diff --git a/.github/workflows/heads.yml b/.github/workflows/heads.yml new file mode 100644 index 0000000..f8c92d1 --- /dev/null +++ b/.github/workflows/heads.yml @@ -0,0 +1,102 @@ +name: Heads + +permissions: + contents: read + +env: + K_SOUP_COV_DO: false + +on: + push: + branches: + - 'main' + - '*-stable' + tags: + - '!*' # Do not execute on tags + pull_request: + branches: + - '*' + # Allow manually triggering the workflow. + workflow_dispatch: + +# Cancels all previous workflow runs for the same branch that have not yet completed. +concurrency: + # The concurrency group contains the workflow name and the branch name. + group: "${{ github.workflow }}-${{ github.ref }}" + cancel-in-progress: true + +jobs: + test: + if: "!contains(github.event.commits[0].message, '[ci skip]') && !contains(github.event.commits[0].message, '[skip ci]')" + name: Specs ${{ matrix.ruby }}@${{ matrix.appraisal }}${{ matrix.name_extra || '' }} + runs-on: ubuntu-latest + continue-on-error: ${{ matrix.experimental || endsWith(matrix.ruby, 'head') }} + env: # $BUNDLE_GEMFILE must be set at job level, so it is set for all steps + BUNDLE_GEMFILE: ${{ github.workspace }}/${{ matrix.gemfile }}.gemfile + strategy: + fail-fast: true + matrix: + include: + # NOTE: Heads use default rubygems / bundler; their defaults are custom, unreleased, and from the future! + # ruby-head + - ruby: "ruby-head" + appraisal: "head" + exec_cmd: "rake test" + gemfile: "Appraisal.root" + rubygems: default + bundler: default + + # truffleruby-head + - ruby: "truffleruby-head" + appraisal: "head" + exec_cmd: "rake test" + gemfile: "Appraisal.root" + rubygems: default + bundler: default + + # jruby-head + - ruby: "jruby-head" + appraisal: "head" + exec_cmd: "rake test" + gemfile: "Appraisal.root" + rubygems: default + bundler: default + + steps: + - name: Checkout + if: ${{ !(env.ACT && startsWith(matrix.ruby, 'jruby')) }} + uses: actions/checkout@v5 + + - name: Setup Ruby & RubyGems + if: ${{ !(env.ACT && startsWith(matrix.ruby, 'jruby')) }} + uses: ruby/setup-ruby@v1 + with: + ruby-version: ${{ matrix.ruby }} + rubygems: ${{ matrix.rubygems }} + bundler: ${{ matrix.bundler }} + bundler-cache: false + + # Raw `bundle` will use the BUNDLE_GEMFILE set to matrix.gemfile (i.e. Appraisal.root) + # We need to do this first to get appraisal installed. + # NOTE: This does not use the primary Gemfile at all. + - name: "Install Root Appraisal" + if: ${{ !(env.ACT && startsWith(matrix.ruby, 'jruby')) }} + run: bundle + + - name: "[Attempt 1] Appraisal for ${{ matrix.ruby }}@${{ matrix.appraisal }}" + if: ${{ !(env.ACT && startsWith(matrix.ruby, 'jruby')) }} + id: bundleAttempt1 + run: bundle exec appraisal ${{ matrix.appraisal }} bundle + # Continue to the next step on failure + continue-on-error: true + + # Effectively an automatic retry of the previous step. + - name: "[Attempt 2] Appraisal for ${{ matrix.ruby }}@${{ matrix.appraisal }}" + # If bundleAttempt1 failed, try again here; Otherwise skip. + if: ${{ steps.bundleAttempt1.outcome == 'failure' && !(env.ACT && startsWith(matrix.ruby, 'jruby')) }} + id: bundleAttempt2 + run: bundle exec appraisal ${{ matrix.appraisal }} bundle + + - name: Tests for ${{ matrix.ruby }}@${{ matrix.appraisal }} via ${{ matrix.exec_cmd }} + if: ${{ !(env.ACT && startsWith(matrix.ruby, 'jruby')) }} + run: bundle exec appraisal ${{ matrix.appraisal }} bundle exec ${{ matrix.exec_cmd }} diff --git a/.github/workflows/jruby.yml b/.github/workflows/jruby.yml new file mode 100644 index 0000000..26cc8f3 --- /dev/null +++ b/.github/workflows/jruby.yml @@ -0,0 +1,72 @@ +name: JRuby + +permissions: + contents: read + +env: + K_SOUP_COV_DO: false + +on: + push: + branches: + - 'main' + - '*-stable' + tags: + - '!*' # Do not execute on tags + pull_request: + branches: + - '*' + # Allow manually triggering the workflow. + workflow_dispatch: + +# Cancels all previous workflow runs for the same branch that have not yet completed. +concurrency: + # The concurrency group contains the workflow name and the branch name. + group: "${{ github.workflow }}-${{ github.ref }}" + cancel-in-progress: true + +jobs: + test: + if: "!contains(github.event.commits[0].message, '[ci skip]') && !contains(github.event.commits[0].message, '[skip ci]')" + name: Specs ${{ matrix.ruby }} ${{ matrix.appraisal }}${{ matrix.name_extra || '' }} + runs-on: ubuntu-22.04 + continue-on-error: ${{ matrix.experimental || endsWith(matrix.ruby, 'head') }} + env: # $BUNDLE_GEMFILE must be set at job level, so it is set for all steps + BUNDLE_GEMFILE: ${{ github.workspace }}/${{ matrix.gemfile }}.gemfile + strategy: + matrix: + include: + # jruby-9.4 (targets Ruby 3.1 compatibility) + - ruby: "jruby-9.4" + appraisal: "ruby-3-1" + exec_cmd: "rake test" + gemfile: "Appraisal.root" + rubygems: default + bundler: default + + steps: + - name: Checkout + if: ${{ !env.ACT }} + uses: actions/checkout@v5 + + - name: Setup Ruby & RubyGems + if: ${{ !env.ACT }} + uses: ruby/setup-ruby@v1 + with: + ruby-version: ${{ matrix.ruby }} + rubygems: ${{ matrix.rubygems }} + bundler: ${{ matrix.bundler }} + bundler-cache: false + + # Raw `bundle` will use the BUNDLE_GEMFILE set to matrix.gemfile (i.e. Appraisal.root) + # We need to do this first to get appraisal installed. + # NOTE: This does not use the primary Gemfile at all. + - name: Install Root Appraisal + if: ${{ !env.ACT }} + run: bundle + - name: Appraisal for ${{ matrix.appraisal }} + if: ${{ !env.ACT }} + run: bundle exec appraisal ${{ matrix.appraisal }} bundle + - name: Tests for ${{ matrix.ruby }} via ${{ matrix.exec_cmd }} + if: ${{ !env.ACT }} + run: bundle exec appraisal ${{ matrix.appraisal }} bundle exec ${{ matrix.exec_cmd }} diff --git a/.github/workflows/legacy.yml b/.github/workflows/legacy.yml new file mode 100644 index 0000000..7f1fc29 --- /dev/null +++ b/.github/workflows/legacy.yml @@ -0,0 +1,76 @@ +name: MRI 3.0, 3.1 (EOL) + +permissions: + contents: read + +env: + K_SOUP_COV_DO: false + +on: + push: + branches: + - 'main' + - '*-stable' + tags: + - '!*' # Do not execute on tags + pull_request: + branches: + - '*' + # Allow manually triggering the workflow. + workflow_dispatch: + +# Cancels all previous workflow runs for the same branch that have not yet completed. +concurrency: + # The concurrency group contains the workflow name and the branch name. + group: "${{ github.workflow }}-${{ github.ref }}" + cancel-in-progress: true + +jobs: + test: + if: "!contains(github.event.commits[0].message, '[ci skip]') && !contains(github.event.commits[0].message, '[skip ci]')" + name: Specs ${{ matrix.ruby }} ${{ matrix.appraisal }}${{ matrix.name_extra || '' }} + runs-on: ubuntu-22.04 + continue-on-error: ${{ matrix.experimental || endsWith(matrix.ruby, 'head') }} + env: # $BUNDLE_GEMFILE must be set at job level, so it is set for all steps + BUNDLE_GEMFILE: ${{ github.workspace }}/${{ matrix.gemfile }}.gemfile + strategy: + fail-fast: false + matrix: + include: + # Ruby 3.0 + - ruby: "ruby-3.0" + appraisal: "ruby-3-0" + exec_cmd: "rake test" + gemfile: "Appraisal.root" + rubygems: '3.5.23' + bundler: '2.5.23' + + # Ruby 3.1 + - ruby: "ruby-3.1" + appraisal: "ruby-3-1" + exec_cmd: "rake test" + gemfile: "Appraisal.root" + rubygems: latest + bundler: latest + + steps: + - name: Checkout + uses: actions/checkout@v5 + + - name: Setup Ruby & RubyGems + uses: ruby/setup-ruby@v1 + with: + ruby-version: ${{ matrix.ruby }} + rubygems: ${{ matrix.rubygems }} + bundler: ${{ matrix.bundler }} + bundler-cache: false + + # Raw `bundle` will use the BUNDLE_GEMFILE set to matrix.gemfile (i.e. Appraisal.root) + # We need to do this first to get appraisal installed. + # NOTE: This does not use the primary Gemfile at all. + - name: Install Root Appraisal + run: bundle + - name: Appraisal for ${{ matrix.appraisal }} + run: bundle exec appraisal ${{ matrix.appraisal }} bundle + - name: Tests for ${{ matrix.ruby }} via ${{ matrix.exec_cmd }} + run: bundle exec appraisal ${{ matrix.appraisal }} bundle exec ${{ matrix.exec_cmd }} diff --git a/.github/workflows/locked_deps.yml b/.github/workflows/locked_deps.yml new file mode 100644 index 0000000..7d946ad --- /dev/null +++ b/.github/workflows/locked_deps.yml @@ -0,0 +1,85 @@ +--- +# Lock/Unlock Deps Pattern +# +# Two often conflicting goals resolved! +# +# - unlocked_deps.yml +# - All runtime & dev dependencies, but does not have a `gemfiles/*.gemfile.lock` committed +# - Uses an Appraisal2 "unlocked_deps" gemfile, and the current MRI Ruby release +# - Know when new dependency releases will break local dev with unlocked dependencies +# - Broken workflow indicates that new releases of dependencies may not work +# +# - locked_deps.yml +# - All runtime & dev dependencies, and has a `Gemfile.lock` committed +# - Uses the project's main Gemfile, and the current MRI Ruby release +# - Matches what contributors and maintainers use locally for development +# - Broken workflow indicates that a new contributor will have a bad time +# +name: Deps Locked + +permissions: + contents: read + +env: + # Running coverage, but not validating minimum coverage, + # because it would be redundant with the coverage workflow. + # Also we can validate all output formats without breaking CodeCov, + # since we aren't submitting these reports anywhere. + K_SOUP_COV_MIN_BRANCH: 71 + K_SOUP_COV_MIN_LINE: 86 + K_SOUP_COV_MIN_HARD: false + K_SOUP_COV_FORMATTERS: "html,xml,rcov,lcov,json,tty" + K_SOUP_COV_DO: true + K_SOUP_COV_MULTI_FORMATTERS: true + K_SOUP_COV_COMMAND_NAME: "Test Coverage" + +on: + push: + branches: + - 'main' + - '*-stable' + tags: + - '!*' # Do not execute on tags + pull_request: + branches: + - '*' + # Allow manually triggering the workflow. + workflow_dispatch: + +# Cancels all previous workflow runs for the same branch that have not yet completed. +concurrency: + # The concurrency group contains the workflow name and the branch name. + group: "${{ github.workflow }}-${{ github.ref }}" + cancel-in-progress: true + +jobs: + test: + if: "!contains(github.event.commits[0].message, '[ci skip]') && !contains(github.event.commits[0].message, '[skip ci]')" + name: Default rake task w/ main Gemfile.lock ${{ matrix.name_extra || '' }} + runs-on: ubuntu-latest + continue-on-error: ${{ matrix.experimental }} + strategy: + fail-fast: false + matrix: + include: + # Ruby + - ruby: "ruby" + exec_cmd: "rake" + rubygems: latest + bundler: latest + experimental: false + + steps: + - name: Checkout + uses: actions/checkout@v5 + + - name: Setup Ruby & RubyGems + uses: ruby/setup-ruby@v1 + with: + ruby-version: ${{ matrix.ruby }} + rubygems: ${{ matrix.rubygems }} + bundler: ${{ matrix.bundler }} + bundler-cache: true + + - name: Checks the kitchen sink via ${{ matrix.exec_cmd }} + run: bundle exec ${{ matrix.exec_cmd }} diff --git a/.github/workflows/opencollective.yml b/.github/workflows/opencollective.yml new file mode 100644 index 0000000..6122df4 --- /dev/null +++ b/.github/workflows/opencollective.yml @@ -0,0 +1,40 @@ +name: Open Collective Backers + +on: + schedule: + # Run once a week on Sunday at 12:00 AM UTC + - cron: '0 0 * * 0' + workflow_dispatch: + +permissions: + contents: write + +jobs: + update-backers: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v5 + with: + persist-credentials: false + - name: Setup Ruby & RubyGems + uses: ruby/setup-ruby@v1 + with: + ruby-version: ruby + rubygems: default + bundler: default + bundler-cache: true + + - name: README Update + env: + # Keep GITHUB_TOKEN for any tools/scripts expecting it, mapped to the same secret + GITHUB_TOKEN: ${{ secrets.README_UPDATER_TOKEN }} + README_UPDATER_TOKEN: ${{ secrets.README_UPDATER_TOKEN }} + REPO: ${{ github.repository }} + run: | + git config user.name 'autobolt' + git config user.email 'autobots@9thbit.net' + # Use the configured token for authenticated pushes + git remote set-url origin "https://x-access-token:${README_UPDATER_TOKEN}@github.com/${REPO}.git" + bin/kettle-readme-backers + # Push back to the same branch/ref that triggered the workflow (default branch for schedule) + git push origin HEAD diff --git a/.github/workflows/style.yml b/.github/workflows/style.yml new file mode 100644 index 0000000..2fe1e03 --- /dev/null +++ b/.github/workflows/style.yml @@ -0,0 +1,65 @@ +name: Style + +permissions: + contents: read + +on: + push: + branches: + - 'main' + - '*-stable' + tags: + - '!*' # Do not execute on tags + pull_request: + branches: + - '*' + # Allow manually triggering the workflow. + workflow_dispatch: + +# Cancels all previous workflow runs for the same branch that have not yet completed. +concurrency: + # The concurrency group contains the workflow name and the branch name. + group: "${{ github.workflow }}-${{ github.ref }}" + cancel-in-progress: true + +jobs: + rubocop: + if: "!contains(github.event.commits[0].message, '[ci skip]') && !contains(github.event.commits[0].message, '[skip ci]')" + name: Style on ${{ matrix.ruby }}@current + runs-on: ubuntu-latest + continue-on-error: ${{ matrix.experimental || endsWith(matrix.ruby, 'head') }} + env: # $BUNDLE_GEMFILE must be set at job level, so it is set for all steps + BUNDLE_GEMFILE: ${{ github.workspace }}/${{ matrix.gemfile }}.gemfile + strategy: + fail-fast: false + matrix: + include: + # Style + - ruby: "ruby" + appraisal: "style" + exec_cmd: "rake rubocop_gradual:check" + gemfile: "Appraisal.root" + rubygems: latest + bundler: latest + + steps: + - name: Checkout + uses: actions/checkout@v5 + + - name: Setup Ruby & RubyGems + uses: ruby/setup-ruby@v1 + with: + ruby-version: ${{ matrix.ruby }} + rubygems: ${{ matrix.rubygems }} + bundler: ${{ matrix.bundler }} + bundler-cache: false + + # Raw `bundle` will use the BUNDLE_GEMFILE set to matrix.gemfile (i.e. Appraisal.root) + # We need to do this first to get appraisal installed. + # NOTE: This does not use the primary Gemfile at all. + - name: Install Root Appraisal + run: bundle + - name: Appraisal for ${{ matrix.appraisal }} + run: bundle exec appraisal ${{ matrix.appraisal }} bundle + - name: Run ${{ matrix.appraisal }} checks via ${{ matrix.exec_cmd }} + run: bundle exec appraisal ${{ matrix.appraisal }} bundle exec ${{ matrix.exec_cmd }} diff --git a/.github/workflows/supported.yml b/.github/workflows/supported.yml new file mode 100644 index 0000000..887034b --- /dev/null +++ b/.github/workflows/supported.yml @@ -0,0 +1,75 @@ +name: MRI Non-EOL + +permissions: + contents: read + +env: + K_SOUP_COV_DO: false + +on: + push: + branches: + - 'main' + - '*-stable' + tags: + - '!*' # Do not execute on tags + pull_request: + branches: + - '*' + # Allow manually triggering the workflow. + workflow_dispatch: + +# Cancels all previous workflow runs for the same branch that have not yet completed. +concurrency: + # The concurrency group contains the workflow name and the branch name. + group: "${{ github.workflow }}-${{ github.ref }}" + cancel-in-progress: true + +jobs: + test: + if: "!contains(github.event.commits[0].message, '[ci skip]') && !contains(github.event.commits[0].message, '[skip ci]')" + name: Specs ${{ matrix.ruby }} ${{ matrix.appraisal }}${{ matrix.name_extra || '' }} + runs-on: ubuntu-latest + continue-on-error: ${{ matrix.experimental || endsWith(matrix.ruby, 'head') }} + env: # $BUNDLE_GEMFILE must be set at job level, so it is set for all steps + BUNDLE_GEMFILE: ${{ github.workspace }}/${{ matrix.gemfile }}.gemfile + strategy: + matrix: + include: + # Ruby 3.2 + - ruby: "ruby-3.2" + appraisal: "ruby-3-2" + exec_cmd: "rake test" + gemfile: "Appraisal.root" + rubygems: latest + bundler: latest + + # Ruby 3.3 + - ruby: "ruby-3.3" + appraisal: "ruby-3-3" + exec_cmd: "rake test" + gemfile: "Appraisal.root" + rubygems: latest + bundler: latest + + steps: + - name: Checkout + uses: actions/checkout@v5 + + - name: Setup Ruby & RubyGems + uses: ruby/setup-ruby@v1 + with: + ruby-version: ${{ matrix.ruby }} + rubygems: ${{ matrix.rubygems }} + bundler: ${{ matrix.bundler }} + bundler-cache: false + + # Raw `bundle` will use the BUNDLE_GEMFILE set to matrix.gemfile (i.e. Appraisal.root) + # We need to do this first to get appraisal installed. + # NOTE: This does not use the primary Gemfile at all. + - name: Install Root Appraisal + run: bundle + - name: Appraisal for ${{ matrix.ruby }} ${{ matrix.appraisal }} + run: bundle exec appraisal ${{ matrix.appraisal }} bundle + - name: Tests for ${{ matrix.ruby }} ${{ matrix.appraisal }} via ${{ matrix.exec_cmd }} + run: bundle exec appraisal ${{ matrix.appraisal }} bundle exec ${{ matrix.exec_cmd }} diff --git a/.github/workflows/truffle.yml b/.github/workflows/truffle.yml new file mode 100644 index 0000000..db65188 --- /dev/null +++ b/.github/workflows/truffle.yml @@ -0,0 +1,93 @@ +name: Truffle + +permissions: + contents: read + +env: + K_SOUP_COV_DO: false + +on: + push: + branches: + - 'main' + - '*-stable' + tags: + - '!*' # Do not execute on tags + pull_request: + branches: + - '*' + # Allow manually triggering the workflow. + workflow_dispatch: + +# Cancels all previous workflow runs for the same branch that have not yet completed. +concurrency: + # The concurrency group contains the workflow name and the branch name. + group: "${{ github.workflow }}-${{ github.ref }}" + cancel-in-progress: true + +jobs: + test: + if: "!contains(github.event.commits[0].message, '[ci skip]') && !contains(github.event.commits[0].message, '[skip ci]')" + name: Specs ${{ matrix.ruby }} ${{ matrix.appraisal }}${{ matrix.name_extra || '' }} + runs-on: ubuntu-22.04 + continue-on-error: ${{ matrix.experimental || endsWith(matrix.ruby, 'head') }} + env: # $BUNDLE_GEMFILE must be set at job level, so it is set for all steps + BUNDLE_GEMFILE: ${{ github.workspace }}/${{ matrix.gemfile }}.gemfile + strategy: + matrix: + include: + # NOTE: truffleruby does not support upgrading rubygems. + # truffleruby-23.1 (targets Ruby 3.2 compatibility) + - ruby: "truffleruby-23.1" + appraisal: "ruby-3-2" + exec_cmd: "rake test" + gemfile: "Appraisal.root" + rubygems: default + bundler: default + + steps: + - name: Checkout + uses: actions/checkout@v5 + + - name: Setup Ruby & RubyGems + uses: ruby/setup-ruby@v1 + with: + ruby-version: ${{ matrix.ruby }} + rubygems: ${{ matrix.rubygems }} + bundler: ${{ matrix.bundler }} + bundler-cache: false + + # Raw `bundle` will use the BUNDLE_GEMFILE set to matrix.gemfile (i.e. Appraisal.root) + # We need to do this first to get appraisal installed. + # NOTE: This does not use the primary Gemfile at all. + - name: Install Root Appraisal + run: bundle + + - name: "[Attempt 1] Install Root Appraisal" + id: bundleAttempt1 + run: bundle + # Continue to the next step on failure + continue-on-error: true + + # Effectively an automatic retry of the previous step. + - name: "[Attempt 2] Install Root Appraisal" + id: bundleAttempt2 + # If bundleAttempt1 failed, try again here; Otherwise skip. + if: steps.bundleAttempt1.outcome == 'failure' + run: bundle + + - name: "[Attempt 1] Appraisal for ${{ matrix.ruby }}@${{ matrix.appraisal }}" + id: bundleAppraisalAttempt1 + run: bundle exec appraisal ${{ matrix.appraisal }} bundle + # Continue to the next step on failure + continue-on-error: true + + # Effectively an automatic retry of the previous step. + - name: "[Attempt 2] Appraisal for ${{ matrix.ruby }}@${{ matrix.appraisal }}" + id: bundleAppraisalAttempt2 + # If bundleAttempt1 failed, try again here; Otherwise skip. + if: steps.bundleAppraisalAttempt1.outcome == 'failure' + run: bundle exec appraisal ${{ matrix.appraisal }} bundle + + - name: Tests for ${{ matrix.ruby }} via ${{ matrix.exec_cmd }} + run: bundle exec appraisal ${{ matrix.appraisal }} bundle exec ${{ matrix.exec_cmd }} diff --git a/.github/workflows/unlocked_deps.yml b/.github/workflows/unlocked_deps.yml new file mode 100644 index 0000000..7faffa1 --- /dev/null +++ b/.github/workflows/unlocked_deps.yml @@ -0,0 +1,84 @@ +--- +# Lock/Unlock Deps Pattern +# +# Two often conflicting goals resolved! +# +# - unlocked_deps.yml +# - All runtime & dev dependencies, but does not have a `gemfiles/*.gemfile.lock` committed +# - Uses an Appraisal2 "unlocked_deps" gemfile, and the current MRI Ruby release +# - Know when new dependency releases will break local dev with unlocked dependencies +# - Broken workflow indicates that new releases of dependencies may not work +# +# - locked_deps.yml +# - All runtime & dev dependencies, and has a `Gemfile.lock` committed +# - Uses the project's main Gemfile, and the current MRI Ruby release +# - Matches what contributors and maintainers use locally for development +# - Broken workflow indicates that a new contributor will have a bad time +# +name: Deps Unlocked + +permissions: + contents: read + +env: + K_SOUP_COV_DO: false + +on: + push: + branches: + - 'main' + - '*-stable' + tags: + - '!*' # Do not execute on tags + pull_request: + branches: + - '*' + # Allow manually triggering the workflow. + workflow_dispatch: + +# Cancels all previous workflow runs for the same branch that have not yet completed. +concurrency: + # The concurrency group contains the workflow name and the branch name. + group: "${{ github.workflow }}-${{ github.ref }}" + cancel-in-progress: true + +jobs: + test: + if: "!contains(github.event.commits[0].message, '[ci skip]') && !contains(github.event.commits[0].message, '[skip ci]')" + name: Default rake task w/ unlocked deps ${{ matrix.name_extra || '' }} + runs-on: ubuntu-latest + continue-on-error: ${{ matrix.experimental || endsWith(matrix.ruby, 'head') }} + env: # $BUNDLE_GEMFILE must be set at job level, so it is set for all steps + BUNDLE_GEMFILE: ${{ github.workspace }}/${{ matrix.gemfile }}.gemfile + strategy: + matrix: + include: + # Ruby + - ruby: "ruby" + appraisal_name: "unlocked_deps" + exec_cmd: "rake" + gemfile: "Appraisal.root" + rubygems: latest + bundler: latest + + steps: + - name: Checkout + uses: actions/checkout@v5 + + - name: Setup Ruby & RubyGems + uses: ruby/setup-ruby@v1 + with: + ruby-version: ${{ matrix.ruby }} + rubygems: ${{ matrix.rubygems }} + bundler: ${{ matrix.bundler }} + bundler-cache: false + + # Raw `bundle` will use the BUNDLE_GEMFILE set to matrix.gemfile (i.e. Appraisal.root) + # We need to do this first to get appraisal installed. + # NOTE: This does not use the primary Gemfile at all. + - name: Install Root Appraisal + run: bundle + - name: Appraisal for ${{ matrix.ruby }}@${{ matrix.appraisal_name }} + run: bundle exec appraisal ${{ matrix.appraisal_name }} bundle + - name: Run ${{ matrix.exec_cmd }} on ${{ matrix.ruby }}@${{ matrix.appraisal_name }} + run: bundle exec appraisal ${{ matrix.appraisal_name }} bundle exec ${{ matrix.exec_cmd }} diff --git a/.github/workflows/unsupported.yml b/.github/workflows/unsupported.yml new file mode 100644 index 0000000..9833699 --- /dev/null +++ b/.github/workflows/unsupported.yml @@ -0,0 +1,76 @@ +name: MRI 2.6 & 2.7 (EOL) + +permissions: + contents: read + +env: + K_SOUP_COV_DO: false + +on: + push: + branches: + - 'main' + - '*-stable' + tags: + - '!*' # Do not execute on tags + pull_request: + branches: + - '*' + # Allow manually triggering the workflow. + workflow_dispatch: + +# Cancels all previous workflow runs for the same branch that have not yet completed. +concurrency: + # The concurrency group contains the workflow name and the branch name. + group: "${{ github.workflow }}-${{ github.ref }}" + cancel-in-progress: true + +jobs: + test: + if: "!contains(github.event.commits[0].message, '[ci skip]') && !contains(github.event.commits[0].message, '[skip ci]')" + name: Specs ${{ matrix.ruby }} ${{ matrix.appraisal }}${{ matrix.name_extra || '' }} + runs-on: ubuntu-22.04 + continue-on-error: ${{ matrix.experimental || endsWith(matrix.ruby, 'head') }} + env: # $BUNDLE_GEMFILE must be set at job level, so it is set for all steps + BUNDLE_GEMFILE: ${{ github.workspace }}/${{ matrix.gemfile }}.gemfile + strategy: + fail-fast: false + matrix: + include: + # Ruby 2.6 + - ruby: "ruby-2.6" + appraisal: "ruby-2-6" + exec_cmd: "rake test" + gemfile: "Appraisal.root" + rubygems: '3.4.22' + bundler: '2.4.22' + + # Ruby 2.7 + - ruby: "ruby-2.7" + appraisal: "ruby-2-7" + exec_cmd: "rake test" + gemfile: "Appraisal.root" + rubygems: '3.4.22' + bundler: '2.4.22' + + steps: + - name: Checkout + uses: actions/checkout@v5 + + - name: Setup Ruby & RubyGems + uses: ruby/setup-ruby@v1 + with: + ruby-version: ${{ matrix.ruby }} + rubygems: ${{ matrix.rubygems }} + bundler: ${{ matrix.bundler }} + bundler-cache: false + + # Raw `bundle` will use the BUNDLE_GEMFILE set to matrix.gemfile (i.e. Appraisal.root) + # We need to do this first to get appraisal installed. + # NOTE: This does not use the primary Gemfile at all. + - name: Install Root Appraisal + run: bundle + - name: Appraisal for ${{ matrix.appraisal }} + run: bundle exec appraisal ${{ matrix.appraisal }} bundle + - name: Tests for ${{ matrix.ruby }} via ${{ matrix.exec_cmd }} + run: bundle exec appraisal ${{ matrix.appraisal }} bundle exec ${{ matrix.exec_cmd }} diff --git a/.gitignore b/.gitignore index 010e19e..5fb6e27 100644 --- a/.gitignore +++ b/.gitignore @@ -1,14 +1,49 @@ -/.bundle/ -/.yardoc -/_yardoc/ -/coverage/ -/doc/ +# Build Artifacts /pkg/ -/spec/reports/ /tmp/ +*.gem -# rspec failure tracking +# Bundler +/.bundle/ +/gemfiles/*.lock +/gemfiles/.bundle/ +/gemfiles/.bundle/config +/gemfiles/vendor/ +Appraisal.*.gemfile.lock + +# Specs .rspec_status -gemfiles/*.lock +/coverage/ +/spec/reports/ +/results/ +.output.txt + +# Documentation +/.yardoc/ +/_yardoc/ +/rdoc/ +/doc/ + +# Ruby Version Managers (RVM, rbenv, etc) +# Ignored because we currently use .tool-versions +.rvmrc +.ruby-version +.ruby-gemset + +# Benchmarking +/measurement/ + +# Debugger detritus +.byebug_history + +# direnv - brew install direnv +.env.local + +# OS Detritus +.DS_Store + +# Editors +*~ -*.gem \ No newline at end of file +# Sentinels +.floss_funding.*.lock diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml new file mode 100644 index 0000000..3390138 --- /dev/null +++ b/.gitlab-ci.yml @@ -0,0 +1,136 @@ +# You can override the included template(s) by including variable overrides +# SAST customization: https://docs.gitlab.com/ee/user/application_security/sast/#customizing-the-sast-settings +# Secret Detection customization: https://docs.gitlab.com/ee/user/application_security/secret_detection/#customizing-settings +# Dependency Scanning customization: https://docs.gitlab.com/ee/user/application_security/dependency_scanning/#customizing-the-dependency-scanning-settings +# Container Scanning customization: https://docs.gitlab.com/ee/user/application_security/container_scanning/#customizing-the-container-scanning-settings +# Note that environment variables can be set in several places +# See https://docs.gitlab.com/ee/ci/variables/#cicd-variable-precedence +#stages: +# - test +#sast: +# stage: test +#include: +# - template: Security/SAST.gitlab-ci.yml + +default: + image: ruby + +variables: + BUNDLE_INSTALL_FLAGS: "--quiet --jobs=$(nproc) --retry=3" + BUNDLE_FROZEN: "false" # No lockfile! + BUNDLE_GEMFILE: Appraisal.root.gemfile + K_SOUP_COV_DEBUG: true + K_SOUP_COV_DO: true + K_SOUP_COV_HARD: true + K_SOUP_COV_MIN_BRANCH: 100 + K_SOUP_COV_MIN_LINE: 100 + K_SOUP_COV_VERBOSE: true + K_SOUP_COV_FORMATTERS: "tty" + K_SOUP_COV_MULTI_FORMATTERS: true + K_SOUP_COV_COMMAND_NAME: "RSpec Coverage" + +workflow: + rules: + # For merge requests, create a pipeline. + - if: '$CI_MERGE_REQUEST_IID' + # For the ` main ` branch, create a pipeline (this includes on schedules, pushes, merges, etc.). + - if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH' + # For tags, create a pipeline. + - if: '$CI_COMMIT_TAG' + +.test_template-current: &test_definition-current + image: ruby:${RUBY_VERSION} + stage: test + script: + # || true so we don't fail here, because it'll probably work even if the gem update fails + - gem update --silent --system > /dev/null 2>&1 || true + - mkdir -p vendor/bundle + - bundle config set path 'vendor/bundle' + - chmod +t -R vendor/bundle + - chmod o-w -R vendor/bundle + # Setup appraisal2 + - bundle install + # Bundle a specific appraisal + - bundle exec appraisal unlocked_deps bundle install + # Light smoke test + - bundle exec appraisal unlocked_deps bin/rake --tasks + # Run tests, skipping those that won't work in CI + - > + bundle exec appraisal unlocked_deps \ + bin/rspec spec \ + --tag \~ci_skip \ + --format progress \ + --format RspecJunitFormatter + cache: + key: ${CI_JOB_IMAGE} + paths: + - vendor/ruby + +.test_template-legacy: &test_definition-legacy + image: ruby:${RUBY_VERSION} + stage: test + script: + # RUBYGEMS_VERSION because we support EOL Ruby still... + # || true so we don't fail here, because it'll probably work even if the gem update fails + - gem install rubygems-update -v ${RUBYGEMS_VERSION} || true + # Actually updates both RubyGems and Bundler! + - update_rubygems + - mkdir -p vendor/bundle + - bundle config set path 'vendor/bundle' + - chmod +t -R vendor/bundle + - chmod o-w -R vendor/bundle + # Setup appraisal2 + - bundle install + # Bundle a specific appraisal + - bundle exec appraisal ${APPRAISAL} bundle install + # Light smoke test + - bundle exec appraisal ${APPRAISAL} bin/rake --tasks + # Run tests, skipping those that won't work in CI + - > + bundle exec appraisal unlocked_deps \ + bin/rspec spec \ + --tag \~ci_skip \ + --format progress \ + --format RspecJunitFormatter + cache: + key: ${CI_JOB_IMAGE} + paths: + - vendor/ruby + +ruby-current: + variables: + K_SOUP_COV_DO: true + <<: *test_definition-current + parallel: + matrix: + - RUBY_VERSION: ["3.2", "3.3", "3.4"] + +ruby-ruby3_1: + variables: + RUBYGEMS_VERSION: "3.6.9" + APPRAISAL: ruby_3_1 + K_SOUP_COV_DO: false + <<: *test_definition-legacy + parallel: + matrix: + - RUBY_VERSION: ["3.1"] + +ruby-ruby3_0: + variables: + RUBYGEMS_VERSION: "3.5.23" + APPRAISAL: ruby_3_0 + K_SOUP_COV_DO: false + <<: *test_definition-legacy + parallel: + matrix: + - RUBY_VERSION: ["3.0"] + +ruby-ruby2_7: + variables: + RUBYGEMS_VERSION: "3.4.22" + APPRAISAL: ruby_2_7 + K_SOUP_COV_DO: false + <<: *test_definition-legacy + parallel: + matrix: + - RUBY_VERSION: ["2.7"] diff --git a/.idea/oauth-tty.iml b/.idea/oauth-tty.iml index 8682afc..2ac92f7 100644 --- a/.idea/oauth-tty.iml +++ b/.idea/oauth-tty.iml @@ -9,81 +9,143 @@ - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +