diff --git a/.env b/.env index ffa011e..1a5b05a 100644 --- a/.env +++ b/.env @@ -1 +1 @@ -REDIS_URL=redis://:supersecret@127.0.0.1:6379/10 +REDIS_URL=redis://:supersecret@redis:6379/10 diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 0000000..d11ce9e --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,33 @@ +--- +name: Bug report +about: Create a report to help us improve +title: '' +labels: '' +assignees: '' + +--- + +**Describe the bug** +A clear and concise description of what the bug is. + +**To Reproduce** +Steps to reproduce the behavior: +1. Provide configs +2. Run command +3. See error + +**Expected behavior** +A clear and concise description of what you expected to happen. + +**Screenshots** +If applicable, add screenshots to help explain your problem. + +**Context (please complete the following information):** + - Gem version + - Ruby version + - Rails version + - Gruf version + - Faraday version + +**Additional context** +Add any other context about the problem here. diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000..faf014b --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,24 @@ +# Context + + +- + +## Related tickets + +- + +# What's inside + + +- [x] A + +# Checklist: + +- [ ] I have added tests +- [ ] I have made corresponding changes to the documentation diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 712776d..27afc10 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -4,38 +4,47 @@ on: push: branches: [main] pull_request: - branches: [main] + branches: [ '**' ] jobs: - build: + lint: + runs-on: ubuntu-latest + env: + RUBY_VERSION: "3.3" + name: Rubocop + steps: + - name: Checkout code + uses: actions/checkout@v3 + - name: Setup Ruby w/ same version as image + uses: ruby/setup-ruby@v1 + with: + ruby-version: "3.3" + - name: Install dependencies + run: | + gem install dip + dip bundle install + - name: Run linter + run: dip rubocop + + test: runs-on: ubuntu-latest strategy: + fail-fast: false matrix: - ruby: ["2.5", "2.6", "2.7", "3.0"] - services: - redis: - image: bitnami/redis:6.2 - ports: - - 6379:6379 - env: - REDIS_PASSWORD: supersecret - options: >- - --health-cmd "redis-cli -p 6379 -a 'supersecret' ping" - --health-interval 1s - --health-timeout 3s - --health-retries 10 + ruby: [ '2.7', '3.0', '3.1', '3.2', '3.3' ] + env: + RUBY_VERSION: ${{ matrix.ruby }} + name: Ruby ${{ matrix.ruby }} steps: - - uses: actions/checkout@v3 - - name: Set up Ruby + - name: Checkout code + uses: actions/checkout@v3 + - name: Setup Ruby w/ same version as image uses: ruby/setup-ruby@v1 with: - bundler-cache: true ruby-version: ${{ matrix.ruby }} - - name: Run all tests - run: bundle exec rspec - env: - REDIS_URL: redis://:supersecret@redis:${{ job.services.redis.ports[6379] }}/0 - # FIXME! - SKIP_REDIS_SPECS: true - - name: Run rubocop - run: bundle exec rubocop + - name: Install dependencies + run: | + gem install dip + dip provision + - name: Run tests + run: dip appraisal rspec --format RspecJunitFormatter --out test-results/rspec_${{ matrix.ruby }}.xml --format documentation diff --git a/.gitignore b/.gitignore index 300cf9e..0a349d9 100644 --- a/.gitignore +++ b/.gitignore @@ -3,8 +3,15 @@ /_yardoc/ /coverage/ /doc/ +/log/ /pkg/ /spec/reports/ /tmp/ /.idea *.gem +/test-results/ +.rspec_status +/Gemfile.lock +/gemfiles/*gemfile* +/spec/internal/log/*.log +test.log diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml new file mode 100644 index 0000000..82c4ca0 --- /dev/null +++ b/.gitlab-ci.yml @@ -0,0 +1,37 @@ +include: + - project: "nstmrt/rubygems/templates" + ref: master + file: "build-rubygems.yml" + +lint: + stage: test + image: ${BUILD_CONF_HARBOR_REGISTRY}/dhub/library/ruby:3.3 + tags: + - paas-tests + script: + - bundle install + - bundle exec rubocop + +tests: + stage: test + image: ${BUILD_CONF_HARBOR_REGISTRY}/dhub/library/ruby:$RUBY_VERSION + tags: + - paas-tests + services: + - name: ${BUILD_CONF_HARBOR_REGISTRY}/dhub/bitnami/redis:6.2 + alias: redis + variables: + REDIS_PASSWORD: supersecret + parallel: + matrix: + - RUBY_VERSION: ['2.7', '3.0', '3.1', '3.2', '3.3', '3.4'] + before_script: + - gem sources --remove https://rubygems.org/ + - gem sources --add ${RUBYGEMS_PUBLIC_SOURCE} + - gem install bundler -v 2.3.26 + - bin/setup + script: + - bundle exec appraisal rspec --format RspecJunitFormatter --out test-results/rspec_$RUBY_VERSION.xml --format documentation + artifacts: + reports: + junit: test-results/rspec*.xml diff --git a/.rspec b/.rspec index c99d2e7..a4a94f7 100644 --- a/.rspec +++ b/.rspec @@ -1 +1,2 @@ --require spec_helper +--require rails_helper diff --git a/.rubocop.yml b/.rubocop.yml index 1d33654..0e88419 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -1,5 +1,5 @@ AllCops: - TargetRubyVersion: 2.5 + TargetRubyVersion: 2.7 Style/Documentation: Enabled: false diff --git a/Appraisals b/Appraisals new file mode 100644 index 0000000..cd00e53 --- /dev/null +++ b/Appraisals @@ -0,0 +1,24 @@ +# frozen_string_literal: true + +# See compatibility table at https://www.fastruby.io/blog/ruby/rails/versions/compatibility-table.html + +versions_map = { + '6.0' => %w[2.7], + '6.1' => %w[2.7 3.0], + '7.0' => %w[3.1], + '7.1' => %w[3.2], + '7.2' => %w[3.3 3.4], + '8.0' => %w[3.4] +} + +current_ruby_version = RUBY_VERSION.split('.').first(2).join('.') + +versions_map.each do |rails_version, ruby_versions| + ruby_versions.each do |ruby_version| + next if ruby_version != current_ruby_version + + appraise "rails-#{rails_version}" do + gem 'rails', "~> #{rails_version}.0" + end + end +end diff --git a/CHANGELOG.md b/CHANGELOG.md index 76532f7..3ffd4ba 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,16 @@ # CHANGELOG.md +## 1.0.0 (2024-12-28) + +Features: + +- Drop ruby 2.5/2.6 support +- Add appraisals + +Fix: + +- Fix ruby-kafka health-check bug for some ActiveSupport versions + ## 0.5.0 (2023-08-16) Features: diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..fde5b13 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,14 @@ +ARG RUBY_VERSION + +FROM ruby:$RUBY_VERSION + +ARG BUNDLER_VERSION +ARG RUBYGEMS_VERSION + +ENV BUNDLE_JOBS=4 \ + BUNDLE_RETRY=3 + +RUN gem update --system "${RUBYGEMS_VERSION}" \ + && rm /usr/local/lib/ruby/gems/*/specifications/default/bundler*.gemspec \ + && gem install --default bundler:${BUNDLER_VERSION} \ + && gem install bundler -v ${BUNDLER_VERSION} diff --git a/Gemfile b/Gemfile index 06aae5a..8c19a91 100644 --- a/Gemfile +++ b/Gemfile @@ -1,14 +1,11 @@ # frozen_string_literal: true -source 'https://rubygems.org' +source ENV.fetch('RUBYGEMS_PUBLIC_SOURCE', 'https://rubygems.org/') # Specify your gem's dependencies in http_health_check.gemspec gemspec -gem 'rake', '~> 13.0' - group :test do - gem 'rspec_junit_formatter' gem 'simplecov', require: false gem 'simplecov-cobertura', require: false end diff --git a/Gemfile.lock b/Gemfile.lock deleted file mode 100644 index 2559e1b..0000000 --- a/Gemfile.lock +++ /dev/null @@ -1,99 +0,0 @@ -PATH - remote: . - specs: - http_health_check (0.4.1) - rack (~> 2.0) - webrick - -GEM - remote: https://rubygems.org/ - specs: - activesupport (5.2.8.1) - concurrent-ruby (~> 1.0, >= 1.0.2) - i18n (>= 0.7, < 2) - minitest (~> 5.1) - tzinfo (~> 1.1) - ast (2.4.2) - concurrent-ruby (1.1.10) - connection_pool (2.4.1) - diff-lcs (1.5.0) - docile (1.4.0) - dotenv (2.7.6) - i18n (1.12.0) - concurrent-ruby (~> 1.0) - minitest (5.15.0) - parallel (1.22.1) - parser (3.1.2.0) - ast (~> 2.4.1) - rack (2.2.4) - rainbow (3.1.1) - rake (13.0.6) - redis (4.2.5) - redis-client (0.15.0) - connection_pool - regexp_parser (2.5.0) - rexml (3.2.5) - rspec (3.11.0) - rspec-core (~> 3.11.0) - rspec-expectations (~> 3.11.0) - rspec-mocks (~> 3.11.0) - rspec-core (3.11.0) - rspec-support (~> 3.11.0) - rspec-expectations (3.11.0) - diff-lcs (>= 1.2.0, < 2.0) - rspec-support (~> 3.11.0) - rspec-mocks (3.11.1) - diff-lcs (>= 1.2.0, < 2.0) - rspec-support (~> 3.11.0) - rspec-support (3.11.0) - rspec_junit_formatter (0.5.1) - rspec-core (>= 2, < 4, != 2.12.0) - rubocop (0.93.1) - parallel (~> 1.10) - parser (>= 2.7.1.5) - rainbow (>= 2.2.2, < 4.0) - regexp_parser (>= 1.8) - rexml - rubocop-ast (>= 0.6.0) - ruby-progressbar (~> 1.7) - unicode-display_width (>= 1.4.0, < 2.0) - rubocop-ast (1.17.0) - parser (>= 3.1.1.0) - ruby-progressbar (1.11.0) - simplecov (0.21.2) - docile (~> 1.1) - simplecov-html (~> 0.11) - simplecov_json_formatter (~> 0.1) - simplecov-cobertura (2.1.0) - rexml - simplecov (~> 0.19) - simplecov-html (0.12.3) - simplecov_json_formatter (0.1.4) - thor (1.1.0) - thread_safe (0.3.6) - tzinfo (1.2.9) - thread_safe (~> 0.1) - unicode-display_width (1.8.0) - webrick (1.7.0) - -PLATFORMS - ruby - x86_64-darwin-21 - x86_64-linux - -DEPENDENCIES - activesupport (~> 5.0) - dotenv (~> 2.7.6) - http_health_check! - rake (~> 13.0) - redis (~> 4.2.5) - redis-client (~> 0.15.0) - rspec (~> 3.2) - rspec_junit_formatter - rubocop (~> 0.81) - simplecov - simplecov-cobertura - thor (>= 0.20) - -BUNDLED WITH - 2.3.15 diff --git a/bin/setup b/bin/setup index dce67d8..af70fb4 100755 --- a/bin/setup +++ b/bin/setup @@ -4,5 +4,6 @@ IFS=$'\n\t' set -vx bundle install +bundle exec appraisal install # Do any other automated setup that you need to do here diff --git a/bin/test b/bin/test new file mode 100755 index 0000000..e871bda --- /dev/null +++ b/bin/test @@ -0,0 +1,6 @@ +#!/bin/bash + +set -euxo pipefail + +bundle exec rubocop +bundle exec appraisal rspec diff --git a/dip.yml b/dip.yml new file mode 100644 index 0000000..264a272 --- /dev/null +++ b/dip.yml @@ -0,0 +1,68 @@ +version: '7' + +environment: + RUBY_VERSION: '3.3' + +compose: + files: + - docker-compose.yml + +interaction: + bash: + description: Open the Bash shell in app's container + service: ruby + command: /bin/bash + + bundle: + description: Run Bundler commands + service: ruby + command: bundle + + rails: + description: Run RoR commands + service: ruby + command: bundle exec rails + + appraisal: + description: Run Appraisal commands + service: ruby + command: bundle exec appraisal + + rspec: + description: Run Rspec commands + service: ruby + command: bundle exec rspec + subcommands: + all: + command: bundle exec appraisal rspec + rails-6.0: + command: bundle exec appraisal rails-6.0 rspec + rails-6.1: + command: bundle exec appraisal rails-6.1 rspec + rails-7.0: + command: bundle exec appraisal rails-7.0 rspec + rails-7.1: + command: bundle exec appraisal rails-7.1 rspec + rails-7.2: + command: bundle exec appraisal rails-7.2 rspec + + rubocop: + description: Run Ruby linter + service: ruby + command: bundle exec rubocop + + setup: + description: Install deps + service: ruby + command: bin/setup + + test: + description: Run linters, run all tests + service: ruby + command: bin/test + +provision: + - dip compose down --volumes + - rm -f Gemfile.lock + - rm -f gemfiles/*gemfile* + - dip setup diff --git a/docker-compose.yml b/docker-compose.yml index 20ed60e..9f64518 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,13 +1,40 @@ -version: '3.5' services: + ruby: + build: + context: . + dockerfile: Dockerfile + args: + RUBY_VERSION: ${RUBY_VERSION:-3.3} + BUNDLER_VERSION: 2.4.22 + RUBYGEMS_VERSION: 3.4.22 + image: http_health_check-dev:0.1.0-ruby_${RUBY_VERSION:-3.3} + environment: + HISTFILE: /app/tmp/.bash_history + BUNDLE_PATH: /usr/local/bundle + BUNDLE_CONFIG: /app/.bundle/config + REDIS_URL: redis://:supersecret@redis:6379/10 + command: bash + working_dir: /app + depends_on: + redis: + condition: service_healthy + volumes: + - .:/app:cached + - ${SBMT_RUBYGEMS_PATH:-..}:/app/vendor/gems:cached + - bundler_data:/usr/local/bundle + redis: image: bitnami/redis:6.2 environment: REDIS_PASSWORD: supersecret volumes: - redis:/data + healthcheck: + test: redis-cli -a supersecret ping + interval: 10s ports: - - '6379:6379' + - '6379' volumes: - redis: {} + bundler_data: + redis: diff --git a/http_health_check.gemspec b/http_health_check.gemspec index 0413fda..3750c71 100644 --- a/http_health_check.gemspec +++ b/http_health_check.gemspec @@ -6,35 +6,42 @@ Gem::Specification.new do |spec| spec.name = 'http_health_check' spec.version = HttpHealthCheck::VERSION spec.licenses = ['MIT'] - spec.authors = ['SberMarket team'] - spec.email = ['pochi.73@gmail.com'] + spec.authors = ['Kuper Ruby Platform Team'] spec.summary = 'Simple and extensible HTTP health checks server.' spec.description = spec.summary - spec.homepage = 'https://github.com/SberMarket-Tech/http_health_check' - spec.required_ruby_version = Gem::Requirement.new('>= 2.5.0') + spec.homepage = 'https://github.com/Kuper-Tech/http_health_check' + spec.required_ruby_version = Gem::Requirement.new('>= 2.7.0') - spec.metadata['allowed_push_host'] = 'https://rubygems.org/' + spec.metadata['allowed_push_host'] = ENV.fetch('NEXUS_URL', 'https://rubygems.org') spec.metadata['homepage_uri'] = spec.homepage - spec.metadata['source_code_uri'] = 'https://github.com/SberMarket-Tech/http_health_check' - spec.metadata['changelog_uri'] = 'https://github.com/SberMarket-Tech/http_health_check/blob/main/CHANGELOG.md' + spec.metadata['source_code_uri'] = spec.homepage + spec.metadata['changelog_uri'] = "#{spec.homepage}/blob/main/CHANGELOG.md" - spec.files = Dir.chdir(File.expand_path(__dir__)) do - `git ls-files -z`.split("\x0").reject { |f| f.match(%r{\A(?:test|spec|features)/}) } + spec.files = Dir.chdir(__dir__) do + `git ls-files -z`.split("\x0").reject do |f| + (f == __FILE__) || f.match(%r{\A(?:(?:bin|test|spec|features)/|\.(?:git|travis|circleci)|appveyor)}) + end end - spec.bindir = 'exe' - spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) } + spec.bindir = 'exe' + spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) } spec.require_paths = ['lib'] spec.add_dependency 'rack', '~> 2.0' spec.add_dependency 'webrick' - spec.add_development_dependency 'activesupport', '~> 5.0' + spec.add_development_dependency 'activesupport', '>= 6.0' + spec.add_development_dependency 'appraisal', '>= 2.4' + spec.add_development_dependency 'bundler', '>= 2.3' + spec.add_development_dependency 'combustion', '>= 1.3' spec.add_development_dependency 'dotenv', '~> 2.7.6' - spec.add_development_dependency 'redis', '~> 4.2.5' - spec.add_development_dependency 'redis-client', '~> 0.15.0' - spec.add_development_dependency 'rspec', '~> 3.2' + spec.add_development_dependency 'rake', '>= 13.0' + spec.add_development_dependency 'redis' + spec.add_development_dependency 'redis-client' + spec.add_development_dependency 'rspec', '>= 3.0' + spec.add_development_dependency 'rspec_junit_formatter' + spec.add_development_dependency 'rspec-rails' spec.add_development_dependency 'rubocop', '~> 0.81' spec.add_development_dependency 'thor', '>= 0.20' end diff --git a/lib/http_health_check/probes/ruby_kafka.rb b/lib/http_health_check/probes/ruby_kafka.rb index bb83813..7c6a54a 100644 --- a/lib/http_health_check/probes/ruby_kafka.rb +++ b/lib/http_health_check/probes/ruby_kafka.rb @@ -19,7 +19,7 @@ def initialize(opts = {}) end def probe(_env) - now = @timer.now + now = @timer.now.to_i failed_heartbeats = select_failed_heartbeats(now) return probe_ok groups: meta_from_heartbeats(@heartbeats, now) if failed_heartbeats.empty? @@ -59,9 +59,22 @@ def setup_subscriptions group = event.payload[:group_id] @heartbeats[group] ||= {} - @heartbeats[group][event.transaction_id] = Heartbeat.new(event.time, group, event.payload[:topic_partitions]) + @heartbeats[group][event.transaction_id] = Heartbeat.new( + event_time(event), group, event.payload[:topic_partitions] + ) end end + + def event_time(event) + # event.time in millis in ActiveSupport >= 7.0 && ActiveSupport< 7.1.4 + # see ActiveSupport::Notifications::Event.initialize + active_support_version = ActiveSupport.gem_version + if active_support_version >= Gem::Version.new('7.0.0') && active_support_version < Gem::Version.new('7.1.4') + return (event.time.to_i / 1000) + end + + event.time.to_i + end end end end diff --git a/lib/http_health_check/version.rb b/lib/http_health_check/version.rb index 3832785..52b7c1b 100644 --- a/lib/http_health_check/version.rb +++ b/lib/http_health_check/version.rb @@ -1,5 +1,5 @@ # frozen_string_literal: true module HttpHealthCheck - VERSION = '0.5.0' + VERSION = '1.0.0' end diff --git a/spec/http_health_check/http_health_check_spec.rb b/spec/http_health_check/http_health_check_spec.rb index a34c754..8b8cefa 100644 --- a/spec/http_health_check/http_health_check_spec.rb +++ b/spec/http_health_check/http_health_check_spec.rb @@ -49,7 +49,7 @@ def start_server(opts = {}) end context 'with custom configuration' do - class MyCustomProbe # rubocop:disable Lint/ConstantDefinitionInBlock + class MyCustomProbe include HttpHealthCheck::Probe def probe(env) diff --git a/spec/http_health_check/utils/karafka_spec.rb b/spec/http_health_check/utils/karafka_spec.rb index e0ed6b6..cd976d1 100644 --- a/spec/http_health_check/utils/karafka_spec.rb +++ b/spec/http_health_check/utils/karafka_spec.rb @@ -1,5 +1,7 @@ # frozen_string_literal: true +require 'ostruct' + require_relative '../../../lib/http_health_check/utils/karafka' describe HttpHealthCheck::Utils::Karafka do diff --git a/spec/rails_helper.rb b/spec/rails_helper.rb new file mode 100644 index 0000000..30f10b5 --- /dev/null +++ b/spec/rails_helper.rb @@ -0,0 +1,26 @@ +# frozen_string_literal: true + +# Engine root is used by rails_configuration to correctly +# load fixtures and support files +require 'pathname' +ENGINE_ROOT = Pathname.new(File.expand_path('..', __dir__)) + +require 'combustion' + +begin + Combustion.initialize! :action_controller do + config.log_level = :fatal if ENV['LOG'].to_s.empty? + config.i18n.available_locales = %i[ru en] + config.i18n.default_locale = :ru + end +rescue StandardError => e + # Fail fast if application couldn't be loaded + warn "💥 Failed to load the app: #{e.message}\n#{e.backtrace.join("\n")}" + exit(1) +end + +require 'rspec/rails' + +# Add additional requires below this line. Rails is not loaded until this point! + +Dir["#{__dir__}/support/**/*.rb"].sort.each { |f| require f } diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index a83c0e5..afe806b 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -16,6 +16,10 @@ # # See https://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration +ENV['RAILS_ENV'] = 'test' + +require 'bundler/setup' + require 'dotenv/load' require 'http_health_check'