diff --git a/.github/dependabot.yml b/.github/dependabot.yml
new file mode 100644
index 0000000..355726a
--- /dev/null
+++ b/.github/dependabot.yml
@@ -0,0 +1,20 @@
+version: 2
+updates:
+ - package-ecosystem: "github-actions"
+ directory: "/"
+ schedule:
+ interval: "daily"
+ open-pull-requests-limit: 99
+ assignees:
+ - "biow0lf"
+
+ - package-ecosystem: "bundler"
+ directory: "/"
+ schedule:
+ interval: "daily"
+ open-pull-requests-limit: 99
+ allow:
+ - dependency-type: "direct"
+ - dependency-type: "indirect"
+ assignees:
+ - "biow0lf"
diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml
new file mode 100644
index 0000000..8873fd4
--- /dev/null
+++ b/.github/workflows/codeql.yml
@@ -0,0 +1,78 @@
+# 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"]
+ pull_request:
+ # The branches below must be a subset of the branches above
+ branches: ["main"]
+ schedule:
+ - cron: "0 0 * * 1"
+
+permissions:
+ contents: read
+
+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 [ $supported-codeql-languages ]
+ # Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support
+
+ steps:
+ - name: Harden the runner (Audit all outbound calls)
+ uses: step-security/harden-runner@5ef0c079ce82195b2a36a210272d6b661572d83e # v2.14.2
+ with:
+ egress-policy: audit
+
+ - name: Checkout repository
+ uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
+
+ # Initializes the CodeQL tools for scanning.
+ - name: Initialize CodeQL
+ uses: github/codeql-action/init@9e907b5e64f6b83e7804b09294d44122997950d6 # v4.32.3
+ 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.
+
+ # 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@9e907b5e64f6b83e7804b09294d44122997950d6 # v4.32.3
+
+ # âšī¸ Command-line programs to run using the OS shell.
+ # đ See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
+
+ # If the Autobuild fails above, remove it and uncomment the following three lines.
+ # modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance.
+
+ # - run: |
+ # echo "Run, Build Application using script"
+ # ./location_of_script_within_repo/buildscript.sh
+
+ - name: Perform CodeQL Analysis
+ uses: github/codeql-action/analyze@9e907b5e64f6b83e7804b09294d44122997950d6 # v4.32.3
+ with:
+ category: "/language:${{matrix.language}}"
diff --git a/.github/workflows/dependency-review.yml b/.github/workflows/dependency-review.yml
new file mode 100644
index 0000000..a9dd01b
--- /dev/null
+++ b/.github/workflows/dependency-review.yml
@@ -0,0 +1,27 @@
+# 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
+name: 'Dependency Review'
+on: [pull_request]
+
+permissions:
+ contents: read
+
+jobs:
+ dependency-review:
+ runs-on: ubuntu-latest
+ steps:
+ - name: Harden the runner (Audit all outbound calls)
+ uses: step-security/harden-runner@5ef0c079ce82195b2a36a210272d6b661572d83e # v2.14.2
+ with:
+ egress-policy: audit
+
+ - name: 'Checkout Repository'
+ uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
+ - name: 'Dependency Review'
+ uses: actions/dependency-review-action@68e9887ce6c0bf076e739ad56332b1ee8bc7f88c # v4
diff --git a/.github/workflows/rspec.yml b/.github/workflows/rspec.yml
new file mode 100644
index 0000000..481a993
--- /dev/null
+++ b/.github/workflows/rspec.yml
@@ -0,0 +1,43 @@
+
+name: RSpec
+
+on:
+ push:
+ branches:
+ - main
+ pull_request:
+ branches:
+ - main
+ schedule:
+ - cron: "0 21 * * 6"
+
+permissions:
+ contents: read
+
+jobs:
+ rspec:
+ runs-on: ubuntu-24.04
+ timeout-minutes: 10
+ strategy:
+ fail-fast: false
+ matrix:
+ ruby: ["3.4", "4.0", "head"]
+
+ steps:
+ - name: Harden the runner (Audit all outbound calls)
+ uses: step-security/harden-runner@5ef0c079ce82195b2a36a210272d6b661572d83e # v2.14.2
+ with:
+ egress-policy: audit
+
+ - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
+ - run: rm -f Gemfile.lock
+ - run: rm -f .ruby-version
+ - name: Set up Ruby
+ uses: ruby/setup-ruby@09a7688d3b55cf0e976497ff046b70949eeaccfd # v1.288.0
+ with:
+ ruby-version: ${{ matrix.ruby }}
+ rubygems: latest
+ bundler: latest
+ bundler-cache: true
+
+ - run: bundle exec rspec
diff --git a/.github/workflows/scorecards.yml b/.github/workflows/scorecards.yml
new file mode 100644
index 0000000..0ebf4c5
--- /dev/null
+++ b/.github/workflows/scorecards.yml
@@ -0,0 +1,81 @@
+# This workflow uses actions that are not certified by GitHub. They are provided
+# by a third-party and are governed by separate terms of service, privacy
+# policy, and support documentation.
+
+name: Scorecard supply-chain security
+on:
+ # For Branch-Protection check. Only the default branch is supported. See
+ # https://github.com/ossf/scorecard/blob/main/docs/checks.md#branch-protection
+ branch_protection_rule:
+ # To guarantee Maintained check is occasionally updated. See
+ # https://github.com/ossf/scorecard/blob/main/docs/checks.md#maintained
+ schedule:
+ - cron: '20 7 * * 2'
+ push:
+ branches: ["main"]
+
+# Declare default permissions as read only.
+permissions: read-all
+
+jobs:
+ analysis:
+ name: Scorecard analysis
+ runs-on: ubuntu-latest
+ permissions:
+ # Needed to upload the results to code-scanning dashboard.
+ security-events: write
+ # Needed to publish results and get a badge (see publish_results below).
+ id-token: write
+ contents: read
+ actions: read
+ # To allow GraphQL ListCommits to work
+ issues: read
+ pull-requests: read
+ # To detect SAST tools
+ checks: read
+
+ steps:
+ - name: Harden the runner (Audit all outbound calls)
+ uses: step-security/harden-runner@5ef0c079ce82195b2a36a210272d6b661572d83e # v2.14.2
+ with:
+ egress-policy: audit
+
+ - name: "Checkout code"
+ uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
+ with:
+ persist-credentials: false
+
+ - name: "Run analysis"
+ uses: ossf/scorecard-action@4eaacf0543bb3f2c246792bd56e8cdeffafb205a # v2.4.3
+ with:
+ results_file: results.sarif
+ results_format: sarif
+ # (Optional) "write" PAT token. Uncomment the `repo_token` line below if:
+ # - you want to enable the Branch-Protection check on a *public* repository, or
+ # - you are installing Scorecards on a *private* repository
+ # To create the PAT, follow the steps in https://github.com/ossf/scorecard-action#authentication-with-pat.
+ # repo_token: ${{ secrets.SCORECARD_TOKEN }}
+
+ # Public repositories:
+ # - Publish results to OpenSSF REST API for easy access by consumers
+ # - Allows the repository to include the Scorecard badge.
+ # - See https://github.com/ossf/scorecard-action#publishing-results.
+ # For private repositories:
+ # - `publish_results` will always be set to `false`, regardless
+ # of the value entered here.
+ publish_results: true
+
+ # Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF
+ # format to the repository Actions tab.
+ - name: "Upload artifact"
+ uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
+ with:
+ name: SARIF file
+ path: results.sarif
+ retention-days: 5
+
+ # Upload the results to GitHub's code scanning dashboard.
+ - name: "Upload to code-scanning"
+ uses: github/codeql-action/upload-sarif@9e907b5e64f6b83e7804b09294d44122997950d6 # v4.32.3
+ with:
+ sarif_file: results.sarif
diff --git a/.gitignore b/.gitignore
index f294155..56dd36c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,7 +3,6 @@
.bundle
.config
.yardoc
-Gemfile.lock
InstalledFiles
_yardoc
coverage
@@ -18,3 +17,5 @@ tmp
*.swp
.rspec
vendor/bundle
+.rspec_status
+.idea
diff --git a/.rspec b/.rspec
index b83d9b7..6c6110e 100644
--- a/.rspec
+++ b/.rspec
@@ -1,3 +1,4 @@
---color
--format documentation
+--color
--require spec_helper
+--order random
diff --git a/.rubocop.yml b/.rubocop.yml
new file mode 100644
index 0000000..3eb7161
--- /dev/null
+++ b/.rubocop.yml
@@ -0,0 +1,369 @@
+plugins:
+ - rubocop-performance
+ - rubocop-rake
+ - rubocop-rspec
+ - rubocop-disable_syntax
+
+AllCops:
+ TargetRubyVersion: 3.4
+ NewCops: enable
+
+# We use standard as a linter and formatter instead Rubocop.
+# Also, we are explicitly disable all rubocop rules what
+# already enabled in standard. And standard-performance.
+
+# Standard rules. Style:
+
+# Enforced by standard. Disable.
+Style/StringLiterals:
+ Enabled: false
+
+# Enforced by standard. Disable.
+Style/HashSyntax:
+ Enabled: false
+
+# Enforced by standard. Disable.
+Style/NestedParenthesizedCalls:
+ Enabled: false
+
+# Enforced by standard. Disable.
+Style/RedundantRegexpArgument:
+ Enabled: false
+
+# Enforced by standard. Disable.
+Style/PercentLiteralDelimiters:
+ Enabled: false
+
+# Enforced by standard. Disable.
+Style/RedundantBegin:
+ Enabled: false
+
+# Enforced by standard. Disable.
+Style/SuperWithArgsParentheses:
+ Enabled: false
+
+# Enforced by standard. Disable.
+Style/Encoding:
+ Enabled: false
+
+# Enforced by standard. Disable.
+Style/NumericLiteralPrefix:
+ Enabled: false
+
+# Enforced by standard. Disable.
+Style/RedundantParentheses:
+ Enabled: false
+
+# Enforced by standard. Disable.
+Style/EmptyMethod:
+ Enabled: false
+
+# Enforced by standard. Disable.
+Style/SingleLineMethods:
+ Enabled: false
+
+# Enforced by standard. Disable.
+Style/SafeNavigation:
+ Enabled: false
+
+# Enforced by standard. Disable.
+Style/RescueStandardError:
+ Enabled: false
+
+# Enforced by standard. Disable.
+Style/RedundantSelf:
+ Enabled: false
+
+# Enforced by standard. Disable.
+Style/TernaryParentheses:
+ Enabled: false
+
+# Enforced by standard. Disable.
+Style/RedundantLineContinuation:
+ Enabled: false
+
+# Enforced by standard. Disable.
+Style/SlicingWithRange:
+ Enabled: false
+
+# Enforced by standard. Disable.
+Style/MultilineIfModifier:
+ Enabled: false
+
+# Enforced by standard. Disable.
+Style/RedundantCondition:
+ Enabled: false
+
+# Enforced by standard. Disable.
+Style/RedundantInterpolation:
+ Enabled: false
+
+# Enforced by standard. Disable.
+Style/OrAssignment:
+ Enabled: false
+
+# Enforced by standard. Disable.
+Style/ConditionalAssignment:
+ Enabled: false
+
+# Enforced by standard. Disable.
+Style/ItAssignment:
+ Enabled: false
+
+# Enforced by standard. Disable.
+Style/EachWithObject:
+ Enabled: false
+
+# Enforced by standard. Disable.
+Style/GlobalStdStream:
+ Enabled: false
+
+# Enforced by standard. Disable.
+Style/StringLiteralsInInterpolation:
+ Enabled: false
+
+# Disabled as in standard.
+Style/HashAsLastArrayItem:
+ Enabled: false
+
+# Enforced by standard. Disable.
+Style/Alias:
+ Enabled: false
+
+# Standard rules. Layout:
+
+# Enforced by standard. Disable.
+Layout/HashAlignment:
+ Enabled: false
+
+# Enforced by standard. Disable.
+Layout/FirstArrayElementIndentation:
+ Enabled: false
+
+# Enforced by standard. Disable.
+Layout/SpaceInsideHashLiteralBraces:
+ Enabled: false
+
+# Enforced by standard. Disable.
+Layout/SpaceInsideStringInterpolation:
+ Enabled: false
+
+# Enforced by standard. Disable.
+Layout/DotPosition:
+ Enabled: false
+
+# Enforced by standard. Disable.
+Layout/ExtraSpacing:
+ Enabled: false
+
+# Enforced by standard. Disable.
+Layout/ArgumentAlignment:
+ Enabled: false
+
+# Enforced by standard. Disable.
+Layout/MultilineMethodCallBraceLayout:
+ Enabled: false
+
+# Enforced by standard. Disable.
+Layout/AccessModifierIndentation:
+ Enabled: false
+
+# Enforced by standard. Disable.
+Layout/FirstHashElementIndentation:
+ Enabled: false
+
+# Enforced by standard. Disable.
+Layout/IndentationWidth:
+ Enabled: false
+
+# Enforced by standard. Disable.
+Layout/ElseAlignment:
+ Enabled: false
+
+# Enforced by standard. Disable.
+Layout/EndAlignment:
+ Enabled: false
+
+# Enforced by standard. Disable.
+Layout/MultilineHashBraceLayout:
+ Enabled: false
+
+# Enforced by standard. Disable.
+Layout/EmptyLineBetweenDefs:
+ Enabled: false
+
+# Enforced by standard. Disable.
+Layout/MultilineArrayBraceLayout:
+ Enabled: false
+
+# Enforced by standard. Disable.
+Layout/EmptyLineAfterMagicComment:
+ Enabled: false
+
+# Enforced by standard. Disable.
+Layout/SpaceAroundOperators:
+ Enabled: false
+
+# Enforced by standard. Disable.
+Layout/ArrayAlignment:
+ Enabled: false
+
+# Enforced by standard. Disable.
+Layout/AssignmentIndentation:
+ Enabled: false
+
+# Enforced by standard. Disable.
+Layout/ClosingParenthesisIndentation:
+ Enabled: false
+
+# Enforced by standard. Disable.
+Layout/LineLength:
+ Enabled: false
+
+# Enforced by standard. Disable.
+Layout/MultilineMethodCallIndentation:
+ Enabled: false
+
+# Enforced by standard. Disable.
+Layout/CaseIndentation:
+ Enabled: false
+
+# Standard rules. Lint:
+
+# Enforced by standard. Disable.
+Lint/ImplicitStringConcatenation:
+ Enabled: false
+
+# Enforced by standard. Disable.
+Lint/TripleQuotes:
+ Enabled: false
+
+# Enforced by standard. Disable.
+Lint/IneffectiveAccessModifier:
+ Enabled: false
+
+# Enforced by standard. Disable.
+Lint/SymbolConversion:
+ Enabled: false
+
+# Enforced by rubocop and standard
+Lint/CopDirectiveSyntax:
+ Enabled: true
+
+# Enforced by standard. Disable.
+Lint/DuplicateMethods:
+ Enabled: false
+
+# Enforced by standard. Disable.
+Lint/ConstantDefinitionInBlock:
+ Enabled: false
+
+# Enforced by standard. Disable.
+Lint/UselessTimes:
+ Enabled: false
+
+# Standard-performance rules.
+
+# Enforced by standard-performance. Disable.
+Performance/Detect:
+ Enabled: false
+
+# Enforced by standard-performance. Disable.
+Performance/StringIdentifierArgument:
+ Enabled: false
+
+# Enforced by standard-performance. Disable.
+Performance/RegexpMatch:
+ Enabled: false
+
+# Always enable rubocop Security:
+
+# Enforced by rubocop and standard
+Security/JSONLoad:
+ Enabled: true
+
+# Our rubocop rules
+
+# Bundler rules.
+
+Bundler/OrderedGems:
+ Enabled: false
+
+# Gemspec rules
+
+Gemspec/OrderedDependencies:
+ Enabled: false
+
+# Style rules
+
+# Don't allow %i[foo bar baz]
+Style/SymbolArray:
+ Enabled: true
+ EnforcedStyle: brackets
+
+# Don't allow %w[foo bar baz]
+Style/WordArray:
+ Enabled: true
+ EnforcedStyle: brackets
+
+# Disable warnings like "Missing top-level documentation comment for"
+Style/Documentation:
+ Enabled: false
+
+# Disable as in standard.
+Style/ArgumentsForwarding:
+ Enabled: false
+
+# RSpec rules
+
+# Prefer eq over be.
+RSpec/BeEq:
+ Enabled: false
+
+# Prefer eq over eql.
+RSpec/BeEql:
+ Enabled: false
+
+# We prefer to use `expect` over `allow`.
+RSpec/StubbedMock:
+ Enabled: false
+
+# We prefer multiple before blocks in tests.
+RSpec/ScatteredSetup:
+ Enabled: false
+
+# We use `expect` in before hooks.
+RSpec/ExpectInHook:
+ Enabled: false
+
+# We use item_1, item_2, etc. Disable.
+RSpec/IndexedLet:
+ Enabled: false
+
+# We don't use named subject's
+RSpec/NamedSubject:
+ Enabled: false
+
+# We prefer `receive` over `have_received`
+RSpec/MessageSpies:
+ Enabled: false
+
+# Naming rules:
+
+# Disable anonymous block forwarding.
+Naming/BlockForwarding:
+ Enabled: true
+ EnforcedStyle: explicit
+
+# Enable and exclude specific files.
+Naming/FileName:
+ Enabled: true
+
+# Disabled syntax:
+
+# Disable shorthand hash syntax like: ({ x:, y: })
+# Disable % style literals
+Style/DisableSyntax:
+ DisableSyntax:
+ - shorthand_hash_syntax
+ - percent_literals
diff --git a/.ruby-version b/.ruby-version
new file mode 100644
index 0000000..1454f6e
--- /dev/null
+++ b/.ruby-version
@@ -0,0 +1 @@
+4.0.1
diff --git a/.standard.yml b/.standard.yml
new file mode 100644
index 0000000..65c3e05
--- /dev/null
+++ b/.standard.yml
@@ -0,0 +1 @@
+ruby_version: 3.4
diff --git a/.travis.yml b/.travis.yml
deleted file mode 100644
index bfe7a09..0000000
--- a/.travis.yml
+++ /dev/null
@@ -1,9 +0,0 @@
-language: ruby
-rvm:
- - 2.1
- - 2.2
- - 2.3.0
-sudo: false
-cache: bundler
-script:
- - bundle exec rspec
diff --git a/Gemfile b/Gemfile
index 5ee986f..6ab950e 100644
--- a/Gemfile
+++ b/Gemfile
@@ -1,10 +1,15 @@
-source 'https://rubygems.org'
+# frozen_string_literal: true
+
+source "https://rubygems.org"
-# Specify your gem's dependencies in errbit_github_plugin.gemspec
gemspec
-gem 'errbit_plugin'
-gem 'rspec'
-gem 'guard'
-gem 'guard-rspec'
-gem 'coveralls', :require => false
+gem "rake"
+gem "rspec"
+gem "simplecov", require: false
+gem "standard", "1.54.0", require: false
+gem "rubocop", require: false
+gem "rubocop-disable_syntax", require: false
+gem "rubocop-performance", require: false
+gem "rubocop-rake", require: false
+gem "rubocop-rspec", require: false
diff --git a/Gemfile.lock b/Gemfile.lock
new file mode 100644
index 0000000..cc9d4c7
--- /dev/null
+++ b/Gemfile.lock
@@ -0,0 +1,221 @@
+PATH
+ remote: .
+ specs:
+ errbit_github_plugin (0.4.0)
+ activesupport
+ errbit_plugin
+ faraday-retry
+ octokit
+
+GEM
+ remote: https://rubygems.org/
+ specs:
+ activesupport (8.1.2)
+ base64
+ bigdecimal
+ concurrent-ruby (~> 1.0, >= 1.3.1)
+ connection_pool (>= 2.2.5)
+ drb
+ i18n (>= 1.6, < 2)
+ json
+ logger (>= 1.4.2)
+ minitest (>= 5.1)
+ securerandom (>= 0.3)
+ tzinfo (~> 2.0, >= 2.0.5)
+ uri (>= 0.13.1)
+ addressable (2.8.8)
+ public_suffix (>= 2.0.2, < 8.0)
+ ast (2.4.3)
+ base64 (0.3.0)
+ bigdecimal (4.0.1)
+ concurrent-ruby (1.3.6)
+ connection_pool (3.0.2)
+ diff-lcs (1.6.2)
+ docile (1.4.1)
+ drb (2.2.3)
+ errbit_plugin (0.7.0)
+ faraday (2.14.1)
+ faraday-net_http (>= 2.0, < 3.5)
+ json
+ logger
+ faraday-net_http (3.4.2)
+ net-http (~> 0.5)
+ faraday-retry (2.4.0)
+ faraday (~> 2.0)
+ i18n (1.14.8)
+ concurrent-ruby (~> 1.0)
+ json (2.18.1)
+ language_server-protocol (3.17.0.5)
+ lint_roller (1.1.0)
+ logger (1.7.0)
+ minitest (6.0.1)
+ prism (~> 1.5)
+ net-http (0.9.1)
+ uri (>= 0.11.1)
+ octokit (10.0.0)
+ faraday (>= 1, < 3)
+ sawyer (~> 0.9)
+ parallel (1.27.0)
+ parser (3.3.10.2)
+ ast (~> 2.4.1)
+ racc
+ prism (1.9.0)
+ public_suffix (7.0.2)
+ racc (1.8.1)
+ rainbow (3.1.1)
+ rake (13.3.1)
+ regexp_parser (2.11.3)
+ rspec (3.13.2)
+ rspec-core (~> 3.13.0)
+ rspec-expectations (~> 3.13.0)
+ rspec-mocks (~> 3.13.0)
+ rspec-core (3.13.6)
+ rspec-support (~> 3.13.0)
+ rspec-expectations (3.13.5)
+ diff-lcs (>= 1.2.0, < 2.0)
+ rspec-support (~> 3.13.0)
+ rspec-mocks (3.13.7)
+ diff-lcs (>= 1.2.0, < 2.0)
+ rspec-support (~> 3.13.0)
+ rspec-support (3.13.7)
+ rubocop (1.84.2)
+ json (~> 2.3)
+ language_server-protocol (~> 3.17.0.2)
+ lint_roller (~> 1.1.0)
+ parallel (~> 1.10)
+ parser (>= 3.3.0.2)
+ rainbow (>= 2.2.2, < 4.0)
+ regexp_parser (>= 2.9.3, < 3.0)
+ rubocop-ast (>= 1.49.0, < 2.0)
+ ruby-progressbar (~> 1.7)
+ unicode-display_width (>= 2.4.0, < 4.0)
+ rubocop-ast (1.49.0)
+ parser (>= 3.3.7.2)
+ prism (~> 1.7)
+ rubocop-disable_syntax (0.2.0)
+ lint_roller
+ rubocop (>= 1.72.0)
+ rubocop-performance (1.26.1)
+ lint_roller (~> 1.1)
+ rubocop (>= 1.75.0, < 2.0)
+ rubocop-ast (>= 1.47.1, < 2.0)
+ rubocop-rake (0.7.1)
+ lint_roller (~> 1.1)
+ rubocop (>= 1.72.1)
+ rubocop-rspec (3.9.0)
+ lint_roller (~> 1.1)
+ rubocop (~> 1.81)
+ ruby-progressbar (1.13.0)
+ sawyer (0.9.3)
+ addressable (>= 2.3.5)
+ faraday (>= 0.17.3, < 3)
+ securerandom (0.4.1)
+ simplecov (0.22.0)
+ docile (~> 1.1)
+ simplecov-html (~> 0.11)
+ simplecov_json_formatter (~> 0.1)
+ simplecov-html (0.13.2)
+ simplecov_json_formatter (0.1.4)
+ standard (1.54.0)
+ language_server-protocol (~> 3.17.0.2)
+ lint_roller (~> 1.0)
+ rubocop (~> 1.84.0)
+ standard-custom (~> 1.0.0)
+ standard-performance (~> 1.8)
+ standard-custom (1.0.2)
+ lint_roller (~> 1.0)
+ rubocop (~> 1.50)
+ standard-performance (1.9.0)
+ lint_roller (~> 1.1)
+ rubocop-performance (~> 1.26.0)
+ tzinfo (2.0.6)
+ concurrent-ruby (~> 1.0)
+ unicode-display_width (3.2.0)
+ unicode-emoji (~> 4.1)
+ unicode-emoji (4.2.0)
+ uri (1.1.1)
+
+PLATFORMS
+ aarch64-linux-gnu
+ aarch64-linux-musl
+ arm-linux-gnu
+ arm-linux-musl
+ arm64-darwin
+ ruby
+ x86-linux-gnu
+ x86-linux-musl
+ x86_64-darwin
+ x86_64-linux-gnu
+ x86_64-linux-musl
+
+DEPENDENCIES
+ errbit_github_plugin!
+ rake
+ rspec
+ rubocop
+ rubocop-disable_syntax
+ rubocop-performance
+ rubocop-rake
+ rubocop-rspec
+ simplecov
+ standard (= 1.54.0)
+
+CHECKSUMS
+ activesupport (8.1.2) sha256=88842578ccd0d40f658289b0e8c842acfe9af751afee2e0744a7873f50b6fdae
+ addressable (2.8.8) sha256=7c13b8f9536cf6364c03b9d417c19986019e28f7c00ac8132da4eb0fe393b057
+ ast (2.4.3) sha256=954615157c1d6a382bc27d690d973195e79db7f55e9765ac7c481c60bdb4d383
+ base64 (0.3.0) sha256=27337aeabad6ffae05c265c450490628ef3ebd4b67be58257393227588f5a97b
+ bigdecimal (4.0.1) sha256=8b07d3d065a9f921c80ceaea7c9d4ae596697295b584c296fe599dd0ad01c4a7
+ concurrent-ruby (1.3.6) sha256=6b56837e1e7e5292f9864f34b69c5a2cbc75c0cf5338f1ce9903d10fa762d5ab
+ connection_pool (3.0.2) sha256=33fff5ba71a12d2aa26cb72b1db8bba2a1a01823559fb01d29eb74c286e62e0a
+ diff-lcs (1.6.2) sha256=9ae0d2cba7d4df3075fe8cd8602a8604993efc0dfa934cff568969efb1909962
+ docile (1.4.1) sha256=96159be799bfa73cdb721b840e9802126e4e03dfc26863db73647204c727f21e
+ drb (2.2.3) sha256=0b00d6fdb50995fe4a45dea13663493c841112e4068656854646f418fda13373
+ errbit_github_plugin (0.4.0)
+ errbit_plugin (0.7.0) sha256=2deec87f62dbc953ff86a69b46bb4d339678a9a9439342b85f3dfb909621d94d
+ faraday (2.14.1) sha256=a43cceedc1e39d188f4d2cdd360a8aaa6a11da0c407052e426ba8d3fb42ef61c
+ faraday-net_http (3.4.2) sha256=f147758260d3526939bf57ecf911682f94926a3666502e24c69992765875906c
+ faraday-retry (2.4.0) sha256=7b79c48fb7e56526faf247b12d94a680071ff40c9fda7cf1ec1549439ad11ebe
+ i18n (1.14.8) sha256=285778639134865c5e0f6269e0b818256017e8cde89993fdfcbfb64d088824a5
+ json (2.18.1) sha256=fe112755501b8d0466b5ada6cf50c8c3f41e897fa128ac5d263ec09eedc9f986
+ language_server-protocol (3.17.0.5) sha256=fd1e39a51a28bf3eec959379985a72e296e9f9acfce46f6a79d31ca8760803cc
+ lint_roller (1.1.0) sha256=2c0c845b632a7d172cb849cc90c1bce937a28c5c8ccccb50dfd46a485003cc87
+ logger (1.7.0) sha256=196edec7cc44b66cfb40f9755ce11b392f21f7967696af15d274dde7edff0203
+ minitest (6.0.1) sha256=7854c74f48e2e975969062833adc4013f249a4b212f5e7b9d5c040bf838d54bb
+ net-http (0.9.1) sha256=25ba0b67c63e89df626ed8fac771d0ad24ad151a858af2cc8e6a716ca4336996
+ octokit (10.0.0) sha256=82e99a539b7637b7e905e6d277bb0c1a4bed56735935cc33db6da7eae49a24e8
+ parallel (1.27.0) sha256=4ac151e1806b755fb4e2dc2332cbf0e54f2e24ba821ff2d3dcf86bf6dc4ae130
+ parser (3.3.10.2) sha256=6f60c84aa4bdcedb6d1a2434b738fe8a8136807b6adc8f7f53b97da9bc4e9357
+ prism (1.9.0) sha256=7b530c6a9f92c24300014919c9dcbc055bf4cdf51ec30aed099b06cd6674ef85
+ public_suffix (7.0.2) sha256=9114090c8e4e7135c1fd0e7acfea33afaab38101884320c65aaa0ffb8e26a857
+ racc (1.8.1) sha256=4a7f6929691dbec8b5209a0b373bc2614882b55fc5d2e447a21aaa691303d62f
+ rainbow (3.1.1) sha256=039491aa3a89f42efa1d6dec2fc4e62ede96eb6acd95e52f1ad581182b79bc6a
+ rake (13.3.1) sha256=8c9e89d09f66a26a01264e7e3480ec0607f0c497a861ef16063604b1b08eb19c
+ regexp_parser (2.11.3) sha256=ca13f381a173b7a93450e53459075c9b76a10433caadcb2f1180f2c741fc55a4
+ rspec (3.13.2) sha256=206284a08ad798e61f86d7ca3e376718d52c0bc944626b2349266f239f820587
+ rspec-core (3.13.6) sha256=a8823c6411667b60a8bca135364351dda34cd55e44ff94c4be4633b37d828b2d
+ rspec-expectations (3.13.5) sha256=33a4d3a1d95060aea4c94e9f237030a8f9eae5615e9bd85718fe3a09e4b58836
+ rspec-mocks (3.13.7) sha256=0979034e64b1d7a838aaaddf12bf065ea4dc40ef3d4c39f01f93ae2c66c62b1c
+ rspec-support (3.13.7) sha256=0640e5570872aafefd79867901deeeeb40b0c9875a36b983d85f54fb7381c47c
+ rubocop (1.84.2) sha256=5692cea54168f3dc8cb79a6fe95c5424b7ea893c707ad7a4307b0585e88dbf5f
+ rubocop-ast (1.49.0) sha256=49c3676d3123a0923d333e20c6c2dbaaae2d2287b475273fddee0c61da9f71fd
+ rubocop-disable_syntax (0.2.0) sha256=1e61645773b3fc2f74e995ec65f605f7db59437c274fdfd4f385f60bf86af73e
+ rubocop-performance (1.26.1) sha256=cd19b936ff196df85829d264b522fd4f98b6c89ad271fa52744a8c11b8f71834
+ rubocop-rake (0.7.1) sha256=3797f2b6810c3e9df7376c26d5f44f3475eda59eb1adc38e6f62ecf027cbae4d
+ rubocop-rspec (3.9.0) sha256=8fa70a3619408237d789aeecfb9beef40576acc855173e60939d63332fdb55e2
+ ruby-progressbar (1.13.0) sha256=80fc9c47a9b640d6834e0dc7b3c94c9df37f08cb072b7761e4a71e22cff29b33
+ sawyer (0.9.3) sha256=0d0f19298408047037638639fe62f4794483fb04320269169bd41af2bdcf5e41
+ securerandom (0.4.1) sha256=cc5193d414a4341b6e225f0cb4446aceca8e50d5e1888743fac16987638ea0b1
+ simplecov (0.22.0) sha256=fe2622c7834ff23b98066bb0a854284b2729a569ac659f82621fc22ef36213a5
+ simplecov-html (0.13.2) sha256=bd0b8e54e7c2d7685927e8d6286466359b6f16b18cb0df47b508e8d73c777246
+ simplecov_json_formatter (0.1.4) sha256=529418fbe8de1713ac2b2d612aa3daa56d316975d307244399fa4838c601b428
+ standard (1.54.0) sha256=7a4b08f83d9893083c8f03bc486f0feeb6a84d48233b40829c03ef4767ea0100
+ standard-custom (1.0.2) sha256=424adc84179a074f1a2a309bb9cf7cd6bfdb2b6541f20c6bf9436c0ba22a652b
+ standard-performance (1.9.0) sha256=49483d31be448292951d80e5e67cdcb576c2502103c7b40aec6f1b6e9c88e3f2
+ tzinfo (2.0.6) sha256=8daf828cc77bcf7d63b0e3bdb6caa47e2272dcfaf4fbfe46f8c3a9df087a829b
+ unicode-display_width (3.2.0) sha256=0cdd96b5681a5949cdbc2c55e7b420facae74c4aaf9a9815eee1087cb1853c42
+ unicode-emoji (4.2.0) sha256=519e69150f75652e40bf736106cfbc8f0f73aa3fb6a65afe62fefa7f80b0f80f
+ uri (1.1.1) sha256=379fa58d27ffb1387eaada68c749d1426738bd0f654d812fcc07e7568f5c57c6
+
+BUNDLED WITH
+ 4.0.4
diff --git a/README.md b/README.md
index f62cdde..66ec046 100644
--- a/README.md
+++ b/README.md
@@ -1,29 +1,7 @@
-# ErrbitGithubPlugin
+# Errbit GitHub Plugin
-TODO: Write a gem description
+[](https://github.com/errbit/errbit_github_plugin/actions/workflows/rspec.yml)
+[](https://github.com/standardrb/standard)
-## Installation
-
-Add this line to your application's Gemfile:
-
- gem 'errbit_github_plugin'
-
-And then execute:
-
- $ bundle
-
-Or install it yourself as:
-
- $ gem install errbit_github_plugin
-
-## Usage
-
-TODO: Write usage instructions here
-
-## Contributing
-
-1. Fork it
-2. Create your feature branch (`git checkout -b my-new-feature`)
-3. Commit your changes (`git commit -am 'Add some feature'`)
-4. Push to the branch (`git push origin my-new-feature`)
-5. Create new Pull Request
+This plugin provides GitHub issue tracker integration for Errbit, and it is the
+only plugin included by default in Errbit.
diff --git a/Rakefile b/Rakefile
index 2995527..5263b58 100644
--- a/Rakefile
+++ b/Rakefile
@@ -1 +1,3 @@
+# frozen_string_literal: true
+
require "bundler/gem_tasks"
diff --git a/errbit_github_plugin.gemspec b/errbit_github_plugin.gemspec
index 53d31f5..88083e6 100644
--- a/errbit_github_plugin.gemspec
+++ b/errbit_github_plugin.gemspec
@@ -1,28 +1,37 @@
-# coding: utf-8
-lib = File.expand_path('../lib', __FILE__)
-$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
-require 'errbit_github_plugin/version'
+# frozen_string_literal: true
+
+require_relative "lib/errbit_github_plugin/version"
Gem::Specification.new do |spec|
- spec.name = "errbit_github_plugin"
- spec.version = ErrbitGithubPlugin::VERSION
- spec.authors = ["Stephen Crosby", "Cyril Mougel"]
- spec.email = ["stevecrozz@gmail.com", "cyril.mougel@gmail.com"]
+ spec.name = "errbit_github_plugin"
+ spec.version = ErrbitGithubPlugin::VERSION
+ spec.authors = ["Stephen Crosby"]
+ spec.email = ["stevecrozz@gmail.com"]
+
+ spec.summary = "GitHub integration for Errbit"
+ spec.description = "GitHub integration for Errbit"
+ spec.homepage = "https://github.com/errbit/errbit_github_plugin"
+ spec.license = "MIT"
+ spec.required_ruby_version = ">= 3.4.0"
- spec.description = %q{GitHub integration for Errbit}
- spec.summary = %q{GitHub integration for Errbit}
- spec.homepage = "https://github.com/errbit/errbit_github_plugin"
- spec.license = "MIT"
+ spec.metadata["homepage_uri"] = spec.homepage
+ spec.metadata["source_code_uri"] = spec.homepage
+ spec.metadata["bug_tracker_uri"] = "#{spec.homepage}/issues"
+ spec.metadata["rubygems_mfa_required"] = "true"
- spec.files = `git ls-files`.split($/)
- spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
- spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
+ # Specify which files should be added to the gem when it is released.
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
+ gemspec = File.basename(__FILE__)
+ spec.files = IO.popen(["git", "ls-files", "-z"], chdir: __dir__, err: IO::NULL) do |ls|
+ ls.readlines("\x0", chomp: true).reject do |f|
+ (f == gemspec) ||
+ f.start_with?("bin/", "test/", "spec/", "features/", ".git", ".github", "appveyor", "Gemfile")
+ end
+ end
spec.require_paths = ["lib"]
spec.add_dependency "errbit_plugin"
+ spec.add_dependency "faraday-retry"
spec.add_dependency "octokit"
-
- spec.add_development_dependency "bundler", "~> 1.3"
- spec.add_development_dependency "rake"
- spec.add_development_dependency "activesupport"
+ spec.add_dependency "activesupport"
end
diff --git a/lib/errbit_github_plugin.rb b/lib/errbit_github_plugin.rb
index fcddc1e..57afb5a 100644
--- a/lib/errbit_github_plugin.rb
+++ b/lib/errbit_github_plugin.rb
@@ -1,14 +1,16 @@
+# frozen_string_literal: true
+
require "errbit_github_plugin/version"
-require 'errbit_github_plugin/error'
-require 'errbit_github_plugin/issue_tracker'
+require "errbit_github_plugin/authentication_error"
+require "errbit_github_plugin/issue_tracker"
module ErrbitGithubPlugin
def self.root
- File.expand_path '../..', __FILE__
+ File.expand_path "../..", __FILE__
end
def self.read_static_file(file)
- File.read(File.join(self.root, 'static', file))
+ File.read(File.join(root, "static", file))
end
end
diff --git a/lib/errbit_github_plugin/error.rb b/lib/errbit_github_plugin/authentication_error.rb
similarity index 70%
rename from lib/errbit_github_plugin/error.rb
rename to lib/errbit_github_plugin/authentication_error.rb
index dc8859f..655dbf6 100644
--- a/lib/errbit_github_plugin/error.rb
+++ b/lib/errbit_github_plugin/authentication_error.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module ErrbitGithubPlugin
class AuthenticationError < Exception; end
end
diff --git a/lib/errbit_github_plugin/issue_tracker.rb b/lib/errbit_github_plugin/issue_tracker.rb
index 1329cab..106e1ad 100644
--- a/lib/errbit_github_plugin/issue_tracker.rb
+++ b/lib/errbit_github_plugin/issue_tracker.rb
@@ -1,15 +1,17 @@
-require 'octokit'
+# frozen_string_literal: true
+
+require "active_support/core_ext/object/blank"
+require "octokit"
module ErrbitGithubPlugin
class IssueTracker < ErrbitPlugin::IssueTracker
+ LABEL = "github"
- LABEL = 'github'
-
- NOTE = 'Please configure your github repository in the GITHUB ' <<
- 'REPO field above.
Instead of providing your ' <<
- 'username & password, you can link your Github account to your ' <<
- 'user profile, and allow Errbit to create issues using your ' <<
- 'OAuth token.'
+ NOTE = "Please configure your GitHub repository in the GITHUB " \
+ "REPO field above.
Instead of providing your " \
+ "username & password, you can link your GitHub account to your " \
+ "user profile, and allow Errbit to create issues using your " \
+ "OAuth token."
FIELDS = {
username: {
@@ -35,13 +37,13 @@ def self.fields
def self.icons
@icons ||= {
create: [
- 'image/png', ErrbitGithubPlugin.read_static_file('github_create.png')
+ "image/png", ErrbitGithubPlugin.read_static_file("github_create.png")
],
goto: [
- 'image/png', ErrbitGithubPlugin.read_static_file('github_goto.png'),
+ "image/png", ErrbitGithubPlugin.read_static_file("github_goto.png")
],
inactive: [
- 'image/png', ErrbitGithubPlugin.read_static_file('github_inactive.png'),
+ "image/png", ErrbitGithubPlugin.read_static_file("github_inactive.png")
]
}
end
@@ -56,12 +58,15 @@ def url
def errors
errors = []
- if self.class.fields.detect {|f| options[f[0]].blank? }
- errors << [:base, 'You must specify your GitHub username and password']
+
+ if self.class.fields.detect { |f| options[f[0]].blank? }
+ errors << [:base, "You must specify your GitHub username and password"]
end
+
if repo.blank?
- errors << [:base, 'You must specify your GitHub repository url.']
+ errors << [:base, "You must specify your GitHub repository url."]
end
+
errors
end
@@ -70,17 +75,42 @@ def repo
end
def create_issue(title, body, user: {})
- if user['github_login'] && user['github_oauth_token']
- github_client = Octokit::Client.new(
- login: user['github_login'], access_token: user['github_oauth_token'])
+ github_client = if user["github_login"] && user["github_oauth_token"]
+ Octokit::Client.new(
+ login: user["github_login"], access_token: user["github_oauth_token"]
+ )
else
- github_client = Octokit::Client.new(
- login: options['username'], password: options['password'])
+ Octokit::Client.new(
+ login: options["username"], password: options["password"]
+ )
end
issue = github_client.create_issue(repo, title, body)
issue.html_url
rescue Octokit::Unauthorized
raise ErrbitGithubPlugin::AuthenticationError, "Could not authenticate with GitHub. Please check your username and password."
end
+
+ # @param url [String]
+ # @param user [Hash]
+ # @return [String] The URL of the closed issue
+ def close_issue(url, user: {})
+ github_client = if user["github_login"] && user["github_oauth_token"]
+ Octokit::Client.new(
+ login: user["github_login"], access_token: user["github_oauth_token"]
+ )
+ else
+ Octokit::Client.new(
+ login: options["username"], password: options["password"]
+ )
+ end
+ # It would be better to get the number from issue.number when we create the issue,
+ # however, since we only have the url, get the number from it.
+ # ex: "https://github.com/octocat/Hello-World/issues/1347"
+ issue_number = url.split("/").last
+ issue = github_client.close_issue(repo, issue_number)
+ issue.html_url
+ rescue Octokit::Unauthorized
+ raise ErrbitGithubPlugin::AuthenticationError, "Could not authenticate with GitHub. Please check your username and password."
+ end
end
end
diff --git a/lib/errbit_github_plugin/version.rb b/lib/errbit_github_plugin/version.rb
index 95c2335..839f65d 100644
--- a/lib/errbit_github_plugin/version.rb
+++ b/lib/errbit_github_plugin/version.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module ErrbitGithubPlugin
- VERSION = "0.2.0"
+ VERSION = "0.4.0"
end
diff --git a/spec/errbit_github_plugin/issue_tracker_spec.rb b/spec/errbit_github_plugin/issue_tracker_spec.rb
new file mode 100644
index 0000000..a6a9a88
--- /dev/null
+++ b/spec/errbit_github_plugin/issue_tracker_spec.rb
@@ -0,0 +1,249 @@
+# frozen_string_literal: true
+
+require "spec_helper"
+
+RSpec.describe ErrbitGithubPlugin::IssueTracker do
+ describe ".label" do
+ it { expect(described_class.label).to eq("github") }
+ end
+
+ describe ".note" do
+ it { expect(described_class.note).to start_with("Please configure your GitHub") }
+ end
+
+ describe ".fields" do
+ it do
+ expect(described_class.fields).to eq(
+ {
+ username: {
+ placeholder: "Your username on GitHub"
+ },
+ password: {
+ placeholder: "Password for your account"
+ }
+ }
+ )
+ end
+ end
+
+ describe ".icons" do
+ it "puts create icon onto the icons" do
+ expect(described_class.icons[:create][0]).to eq("image/png")
+
+ expect(described_class.icons[:create][1])
+ .to eq(ErrbitGithubPlugin.read_static_file("github_create.png"))
+ end
+
+ it "puts goto icon onto the icons" do
+ expect(described_class.icons[:goto][0]).to eq("image/png")
+
+ expect(described_class.icons[:goto][1])
+ .to eq(ErrbitGithubPlugin.read_static_file("github_goto.png"))
+ end
+
+ it "puts inactive icon onto the icons" do
+ expect(described_class.icons[:inactive][0]).to eq("image/png")
+
+ expect(described_class.icons[:inactive][1])
+ .to eq(ErrbitGithubPlugin.read_static_file("github_inactive.png"))
+ end
+ end
+
+ let(:tracker) { described_class.new(options) }
+
+ describe "#configured?" do
+ context "with errors" do
+ let(:options) { {invalid_key: ""} }
+
+ it "return false" do
+ expect(tracker.configured?).to eq(false)
+ end
+ end
+
+ context "without errors" do
+ let(:options) do
+ {username: "foo", password: "bar", github_repo: "user/repository"}
+ end
+
+ it "return true" do
+ expect(tracker.configured?).to eq(true)
+ end
+ end
+ end
+
+ describe "#url" do
+ let(:options) { {github_repo: "user/repo"} }
+
+ it "returns issues url" do
+ expect(tracker.url).to eq("https://github.com/user/repo/issues")
+ end
+ end
+
+ describe "#errors" do
+ subject { tracker.errors }
+
+ context "without username" do
+ let(:options) { {username: "", password: "bar", github_repo: "repo"} }
+
+ it { is_expected.not_to be_empty }
+ end
+
+ context "without password" do
+ let(:options) do
+ {username: "", password: "bar", github_repo: "repo"}
+ end
+
+ it { is_expected.not_to be_empty }
+ end
+
+ context "without github_repo" do
+ let(:options) do
+ {username: "foo", password: "bar", github_repo: ""}
+ end
+
+ it { is_expected.not_to be_empty }
+ end
+
+ context "with completed options" do
+ let(:options) do
+ {username: "foo", password: "bar", github_repo: "repo"}
+ end
+
+ it { is_expected.to be_empty }
+ end
+ end
+
+ describe "#repo" do
+ let(:options) { {github_repo: "baz"} }
+
+ it "returns github repo" do
+ expect(tracker.repo).to eq("baz")
+ end
+ end
+
+ describe "#create_issue" do
+ subject { tracker.create_issue("title", "body", user: user) }
+
+ let(:options) do
+ {username: "foo", password: "bar", github_repo: "user/repos"}
+ end
+
+ let(:fake_github_client) do
+ double("Fake GitHub Client").tap do |github_client|
+ expect(github_client).to receive(:create_issue).and_return(fake_issue)
+ end
+ end
+
+ let(:fake_issue) do
+ double("Fake Issue").tap do |issue|
+ expect(issue).to receive(:html_url).and_return("http://github.com/user/repos/issues/878").twice
+ end
+ end
+
+ context "signed in with token" do
+ let(:user) do
+ {
+ "github_login" => "bob",
+ "github_oauth_token" => "valid_token"
+ }
+ end
+
+ it "return issue url" do
+ expect(Octokit::Client).to receive(:new).with(
+ login: user["github_login"], access_token: user["github_oauth_token"]
+ ).and_return(fake_github_client)
+
+ expect(subject).to eq(fake_issue.html_url)
+ end
+ end
+
+ context "signed in with password" do
+ let(:user) { {} }
+
+ it "return issue url" do
+ expect(Octokit::Client).to receive(:new).with(
+ login: options["username"], password: options["password"]
+ ).and_return(fake_github_client)
+
+ expect(subject).to eq(fake_issue.html_url)
+ end
+ end
+
+ context "when unauthentication error" do
+ let(:user) do
+ {"github_login" => "alice", "github_oauth_token" => "invalid_token"}
+ end
+
+ it "raise AuthenticationError" do
+ expect(Octokit::Client).to receive(:new).with(
+ login: user["github_login"], access_token: user["github_oauth_token"]
+ ).and_raise(Octokit::Unauthorized)
+
+ expect { subject }.to raise_error(ErrbitGithubPlugin::AuthenticationError)
+ end
+ end
+ end
+
+ describe "#close_issue" do
+ subject { tracker.close_issue("url", user: user) }
+
+ let(:options) do
+ {username: "foo", password: "bar", github_repo: "user/repository"}
+ end
+
+ let(:fake_github_client) do
+ double("Fake GitHub Client").tap do |github_client|
+ expect(github_client).to receive(:close_issue).and_return(fake_issue)
+ end
+ end
+
+ let(:fake_issue) do
+ double("Fake Issue").tap do |issue|
+ expect(issue).to receive(:html_url).and_return("http://github.com/user/repos/issues/878").twice
+ end
+ end
+
+ context "signed in with token" do
+ let(:user) do
+ {
+ "github_login" => "bob",
+ "github_oauth_token" => "valid_token"
+ }
+ end
+
+ it "return issue url" do
+ expect(Octokit::Client).to receive(:new).with(
+ login: user["github_login"], access_token: user["github_oauth_token"]
+ ).and_return(fake_github_client)
+
+ expect(subject).to eq(fake_issue.html_url)
+ end
+ end
+
+ context "signed in with password" do
+ let(:user) { {} }
+
+ it "return issue url" do
+ expect(Octokit::Client).to receive(:new).with(
+ login: options["username"], password: options["password"]
+ ).and_return(fake_github_client)
+
+ expect(subject).to eq(fake_issue.html_url)
+ end
+ end
+
+ context "when unauthentication error" do
+ let(:user) do
+ {"github_login" => "alice", "github_oauth_token" => "invalid_token"}
+ end
+ #
+ it "raise AuthenticationError" do
+ expect(Octokit::Client).to receive(:new).with(
+ login: user["github_login"], access_token: user["github_oauth_token"]
+ ).and_raise(Octokit::Unauthorized)
+
+ expect { subject }.to raise_error(ErrbitGithubPlugin::AuthenticationError)
+ end
+ end
+ end
+end
diff --git a/spec/issue_tracker_spec.rb b/spec/issue_tracker_spec.rb
deleted file mode 100644
index 22dd275..0000000
--- a/spec/issue_tracker_spec.rb
+++ /dev/null
@@ -1,156 +0,0 @@
-describe ErrbitGithubPlugin::IssueTracker do
- describe '.label' do
- it 'return LABEL' do
- expect(described_class.label).to eq described_class::LABEL
- end
- end
-
- describe '.note' do
- it 'return NOTE' do
- expect(described_class.note).to eq described_class::NOTE
- end
- end
-
- describe '.fields' do
- it 'return FIELDS' do
- expect(described_class.fields).to eq described_class::FIELDS
- end
- end
-
- describe '.icons' do
-
- it 'puts create icon onto the icons' do
- expect(described_class.icons[:create][0]).to eq 'image/png'
- expect(
- described_class.icons[:create][1]
- ).to eq ErrbitGithubPlugin.read_static_file('github_create.png')
- end
-
- it 'puts goto icon onto the icons' do
- expect(described_class.icons[:goto][0]).to eq 'image/png'
- expect(
- described_class.icons[:goto][1]
- ).to eq ErrbitGithubPlugin.read_static_file('github_goto.png')
- end
-
- it 'puts inactive icon onto the icons' do
- expect(described_class.icons[:inactive][0]).to eq 'image/png'
- expect(
- described_class.icons[:inactive][1]
- ).to eq ErrbitGithubPlugin.read_static_file('github_inactive.png')
- end
- end
-
- let(:tracker) { described_class.new(options) }
-
- describe '#configured?' do
- context 'with errors' do
- let(:options) { { invalid_key: '' } }
- it 'return false' do
- expect(tracker.configured?).to eq false
- end
- end
- context 'without errors' do
- let(:options) do
- { username: 'foo', password: 'bar', github_repo: 'user/repos' }
- end
- it 'return true' do
- expect(tracker.configured?).to eq true
- end
- end
- end
-
- describe '#url' do
- let(:options) { { github_repo: 'repo' } }
- it 'returns issues url' do
- expect(tracker.url).to eq 'https://github.com/repo/issues'
- end
- end
-
- describe '#errors' do
- subject { tracker.errors }
- context 'without username' do
- let(:options) { { username: '', password: 'bar', github_repo: 'repo' } }
- it { is_expected.not_to be_empty }
- end
- context 'without password' do
- let(:options) do
- { username: '', password: 'bar', github_repo: 'repo' }
- end
- it { is_expected.not_to be_empty }
- end
- context 'without github_repo' do
- let(:options) do
- { username: 'foo', password: 'bar', github_repo: '' }
- end
- it { is_expected.not_to be_empty }
- end
- context 'with completed options' do
- let(:options) do
- { username: 'foo', password: 'bar', github_repo: 'repo' }
- end
- it { is_expected.to be_empty }
- end
- end
-
- describe '#repo' do
- let(:options) { { github_repo: 'baz' } }
- it 'returns github repo' do
- expect(tracker.repo).to eq 'baz'
- end
- end
-
- describe '#create_issue' do
- subject { tracker.create_issue('title', 'body', user: user) }
- let(:options) do
- { username: 'foo', password: 'bar', github_repo: 'user/repos' }
- end
- let(:fake_github_client) do
- double('Fake GitHub Client').tap do |github_client|
- github_client.stub(:create_issue).and_return(fake_issue)
- end
- end
- let(:fake_issue) do
- double('Fake Issue').tap do |issue|
- issue.stub(:html_url).and_return('http://github.com/user/repos/issues/878')
- end
- end
-
- context 'signed in with token' do
- let(:user) do
- {
- 'github_login' => 'bob',
- 'github_oauth_token' => 'valid_token'
- }
- end
- it 'return issue url' do
- Octokit::Client.stub(:new).with(
- login: user['github_login'], access_token: user['github_oauth_token']
- ).and_return(fake_github_client)
- expect(subject).to eq fake_issue.html_url
- end
- end
-
- context 'signed in with password' do
- let(:user) { {} }
- it 'return issue url' do
- (Octokit::Client).stub(:new).with(
- login: options['username'], password: options['password']
- ).and_return(fake_github_client)
- expect(subject).to eq fake_issue.html_url
- end
- end
-
- context 'when unauthentication error' do
- let(:user) do
- { 'github_login' => 'alice', 'github_oauth_token' => 'invalid_token' }
- end
- it 'raise AuthenticationError' do
- (Octokit::Client).stub(:new).with(
- login: user['github_login'], access_token: user['github_oauth_token']
- ).and_raise(Octokit::Unauthorized)
- expect { subject }.to raise_error
- end
- end
- end
-end
diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb
index badea54..e5b39a9 100644
--- a/spec/spec_helper.rb
+++ b/spec/spec_helper.rb
@@ -1,28 +1,26 @@
-if ENV['COVERAGE']
- require 'simplecov'
- if ENV['CI']
- require 'coveralls'
- Coveralls.wear!
- SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter[
- SimpleCov::Formatter::HTMLFormatter,
- Coveralls::SimpleCov::Formatter
- ]
- end
+# frozen_string_literal: true
+
+require "simplecov"
+
+SimpleCov.start do
+ enable_coverage :branch
+
+ primary_coverage :branch
- SimpleCov.start
+ add_filter "spec/"
end
-require 'errbit_plugin'
-require 'errbit_github_plugin'
-require 'active_support/all'
+require "errbit_plugin"
+require "errbit_github_plugin"
RSpec.configure do |config|
- config.run_all_when_everything_filtered = true
- config.filter_run :focus
-
- # Run specs in random order to surface order dependencies. If you find an
- # order dependency and want to debug it, you can fix the order by providing
- # the seed, which is printed after each run.
- # --seed 1234
- config.order = 'random'
+ # Enable flags like --only-failures and --next-failure
+ config.example_status_persistence_file_path = ".rspec_status"
+
+ # Disable RSpec exposing methods globally on `Module` and `main`
+ config.disable_monkey_patching!
+
+ config.expect_with :rspec do |c|
+ c.syntax = :expect
+ end
end
diff --git a/vendor/assets/images/github_create.png b/vendor/assets/images/github_create.png
deleted file mode 100644
index 8bc8e9d..0000000
Binary files a/vendor/assets/images/github_create.png and /dev/null differ
diff --git a/vendor/assets/images/github_inactive.png b/vendor/assets/images/github_inactive.png
deleted file mode 100644
index 1bcffc7..0000000
Binary files a/vendor/assets/images/github_inactive.png and /dev/null differ