From f822267548cf3bc276887f1a672d3109bf1cbb4b Mon Sep 17 00:00:00 2001 From: Chris Davis Date: Tue, 13 Aug 2024 22:15:53 -0400 Subject: [PATCH 1/3] updated ownership --- zephyr_ruby.gemspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zephyr_ruby.gemspec b/zephyr_ruby.gemspec index b1c4882..c9767f2 100644 --- a/zephyr_ruby.gemspec +++ b/zephyr_ruby.gemspec @@ -10,7 +10,7 @@ Gem::Specification.new do |spec| spec.summary = 'Zephyr REST API Client for Ruby' spec.description = "Allows users to use Zephyr's REST API" spec.license = 'MIT' - spec.required_ruby_version = '>= 3.0' + spec.required_ruby_version = '>= 3' spec.homepage = 'https://github.com/cdavis-personal/zephyr_ruby' spec.files = Dir.chdir(__dir__) do From 52e84c8a67e3d1d22dc9611db2075ae84b5505a2 Mon Sep 17 00:00:00 2001 From: Chris Davis Date: Tue, 13 Aug 2024 22:16:12 -0400 Subject: [PATCH 2/3] updated supported for sending files to the automations endpoint --- zephyr_ruby.gemspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zephyr_ruby.gemspec b/zephyr_ruby.gemspec index c9767f2..b1c4882 100644 --- a/zephyr_ruby.gemspec +++ b/zephyr_ruby.gemspec @@ -10,7 +10,7 @@ Gem::Specification.new do |spec| spec.summary = 'Zephyr REST API Client for Ruby' spec.description = "Allows users to use Zephyr's REST API" spec.license = 'MIT' - spec.required_ruby_version = '>= 3' + spec.required_ruby_version = '>= 3.0' spec.homepage = 'https://github.com/cdavis-personal/zephyr_ruby' spec.files = Dir.chdir(__dir__) do From ff7d7c91b67c2c749534b2be7bdbb6c2c187746e Mon Sep 17 00:00:00 2001 From: cdaviis Date: Wed, 20 Aug 2025 02:52:39 -0400 Subject: [PATCH 3/3] feat: add CLI interface and update test cycle resource methods --- .github/CODEOWNERS | 2 +- .github/PULL_REQUEST_TEMPLATE.md | 2 +- .github/workflows/gem-push.yml | 4 +- CHANGELOG.md | 22 ++ exe/zephyr | 7 + lib/zephyr_ruby.rb | 8 + lib/zephyr_ruby/cli.rb | 43 ++++ lib/zephyr_ruby/cli/helpers/cli_helpers.rb | 77 ++++++ lib/zephyr_ruby/cli/test_cycles.rb | 260 +++++++++++++++++++++ lib/zephyr_ruby/cli/test_plans.rb | 26 +++ lib/zephyr_ruby/resource/test_cycles.rb | 49 +++- lib/zephyr_ruby/version.rb | 2 +- test_api.rb | 91 ++++++++ test_backward_compatibility.rb | 126 ++++++++++ zephyr_ruby-0.5.0.gem | Bin 19968 -> 0 bytes zephyr_ruby-0.6.0.gem | Bin 0 -> 9216 bytes zephyr_ruby.gemspec | 10 +- 17 files changed, 709 insertions(+), 20 deletions(-) create mode 100755 exe/zephyr create mode 100644 lib/zephyr_ruby/cli.rb create mode 100644 lib/zephyr_ruby/cli/helpers/cli_helpers.rb create mode 100644 lib/zephyr_ruby/cli/test_cycles.rb create mode 100644 lib/zephyr_ruby/cli/test_plans.rb create mode 100755 test_api.rb create mode 100644 test_backward_compatibility.rb delete mode 100644 zephyr_ruby-0.5.0.gem create mode 100644 zephyr_ruby-0.6.0.gem diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 3bc29da..82e1780 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -5,4 +5,4 @@ # the repo. Unless a later match takes precedence, # @global-owner1 and @global-owner2 will be requested for # review when someone opens a pull request. -* @cdavis-personal +* @cdaviis @tpospisil diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 43e9e66..e181f57 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -5,4 +5,4 @@ Describe the change(s). Describe the reason for the change(s). ## Testing -Describe how to test your change(s). \ No newline at end of file +Describe how to test your change(s). diff --git a/.github/workflows/gem-push.yml b/.github/workflows/gem-push.yml index a9d9bdd..4e755a4 100644 --- a/.github/workflows/gem-push.yml +++ b/.github/workflows/gem-push.yml @@ -2,9 +2,9 @@ name: Ruby Gem on: push: - branches: [ "main" ] + # branches: [ "main" ] pull_request: - branches: [ "main" ] + # branches: [ "main" ] jobs: build: diff --git a/CHANGELOG.md b/CHANGELOG.md index f177e6a..7a665b1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,27 @@ ## [Unreleased] +## [0.6.0] - 2025-08-20 + +### Changed +- Updated Test Cycles resource to support `testCycleIdOrKey` parameter for all relevant methods +- Renamed resource methods for consistency with the API (e.g., `create_test_cycle` instead of `create_testcycle`) +- Updated CLI implementation to handle both ID and key parameters +- Changed payload generators to use `projectKey` instead of `projectId` to match API requirements +- Improved CLI parameter handling using Thor options hash +- Added better handling for boolean parameters in automation payloads + +### Added +- Added aliases for backward compatibility with old method names +- Added better parameter descriptions in CLI commands +- Added support for `autoCloseCycle` parameter in automation payloads + +### Backward Compatibility +- Maintained full backward compatibility with existing code +- CLI commands support both positional arguments and options hash +- Payload generators accept both `project_id` (numeric) and `project_key` (string) +- Resource methods maintain aliases for old method names +- API client automatically handles both numeric IDs and string keys + ## [0.1.0] - 2022-11-24 - Initial release diff --git a/exe/zephyr b/exe/zephyr new file mode 100755 index 0000000..362ef35 --- /dev/null +++ b/exe/zephyr @@ -0,0 +1,7 @@ +#!/usr/bin/env ruby +# frozen_string_literal: true + +require 'zephyr_ruby' +require 'zephyr_ruby/cli' + +ZephyrRuby::CLI::Main.start(ARGV) diff --git a/lib/zephyr_ruby.rb b/lib/zephyr_ruby.rb index 4d6ad5c..3830abc 100644 --- a/lib/zephyr_ruby.rb +++ b/lib/zephyr_ruby.rb @@ -5,4 +5,12 @@ module ZephyrRuby class Error < StandardError; end + + # Load CLI functionality if Thor is available + begin + require 'thor' + require_relative 'zephyr_ruby/cli' + rescue LoadError + # CLI functionality not available + end end diff --git a/lib/zephyr_ruby/cli.rb b/lib/zephyr_ruby/cli.rb new file mode 100644 index 0000000..891440d --- /dev/null +++ b/lib/zephyr_ruby/cli.rb @@ -0,0 +1,43 @@ +# frozen_string_literal: true + +require 'thor' +require 'nokogiri' +require_relative 'cli/helpers/cli_helpers' +require_relative 'cli/test_cycles' +require_relative 'cli/test_plans' + +module ZephyrRuby + module CLI + # Main CLI class for zephyr_ruby + class Main < Thor + class_option :api_key, type: :string, desc: 'Zephyr API Key (can also be set via ZEPHYR_API_KEY env var)' + + def initialize(*args) + super + # Only check for API key if we're not showing help + return if ARGV.include?('help') || ARGV.include?('--help') || ARGV.empty? + + api_key = options[:api_key] || ENV['ZEPHYR_API_KEY'] + unless api_key + puts "Error: API key is required. Set it with --api-key option or ZEPHYR_API_KEY env var" + exit(1) + end + + @zephyr_client = ZephyrRuby::Client.new(api_key) + end + + desc "test_cycles", "Test cycles commands" + subcommand "test_cycles", TestCycles + + desc "test_plans", "Test plans commands" + subcommand "test_plans", TestPlans + + # Make the client accessible to subcommands + no_commands do + def zephyr_client + @zephyr_client + end + end + end + end +end diff --git a/lib/zephyr_ruby/cli/helpers/cli_helpers.rb b/lib/zephyr_ruby/cli/helpers/cli_helpers.rb new file mode 100644 index 0000000..37a079e --- /dev/null +++ b/lib/zephyr_ruby/cli/helpers/cli_helpers.rb @@ -0,0 +1,77 @@ +# frozen_string_literal: true + +module ZephyrRuby + module CLI + # Helpers module to share common methods among the CLI classes + module Helpers + def generate_automations_payload(project_identifier, file, auto_close_cycle, name, description, auto_create_test_cases) + # Convert to boolean if it's not already + auto_create_test_cases = auto_create_test_cases.to_s.downcase == 'true' unless [true, false].include?(auto_create_test_cases) + + payload = { + file: file, + autoCreateTestCases: auto_create_test_cases, + testCycle: { + name: name, + description: description || "" + } + } + + # Handle different formats of project identifier for backward compatibility + if project_identifier.is_a?(Integer) || project_identifier.to_s.match?(/^\d+$/) + # Old style: numeric project_id - convert to string for new API + payload[:projectKey] = project_identifier.to_s + # Also include projectId for backward compatibility with any custom integrations + payload[:projectId] = project_identifier.to_i + else + # New style: string project_key + payload[:projectKey] = project_identifier + end + + # Add autoCloseCycle if provided + if auto_close_cycle + auto_close_cycle = auto_close_cycle.to_s.downcase == 'true' unless [true, false].include?(auto_close_cycle) + payload[:autoCloseCycle] = auto_close_cycle + end + + payload + end + + def generate_test_cycle_payload(name, description, start_date, end_date, project_identifier) + payload = { + name: name, + description: description, + plannedStartDate: start_date, + plannedEndDate: end_date + } + + # Handle different formats of project identifier for backward compatibility + if project_identifier.is_a?(Hash) + # New style: {key: value} format from refactored code + payload.merge!(project_identifier) + elsif project_identifier.is_a?(Integer) || project_identifier.to_s.match?(/^\d+$/) + # Old style: numeric project_id + payload[:projectId] = project_identifier.to_i + else + # New style: string project_key + payload[:projectKey] = project_identifier + end + + payload + end + + def generate_test_plan_payload(project_key, name, objective, folder_id, status_name, owner_id, labels, custom_fields = {}) + { + projectKey: project_key, + name: name, + objective: objective, + folderId: folder_id, + statusName: status_name, + ownerId: owner_id, + labels: labels, + customFields: custom_fields + } + end + end + end +end diff --git a/lib/zephyr_ruby/cli/test_cycles.rb b/lib/zephyr_ruby/cli/test_cycles.rb new file mode 100644 index 0000000..fb0ba82 --- /dev/null +++ b/lib/zephyr_ruby/cli/test_cycles.rb @@ -0,0 +1,260 @@ +# frozen_string_literal: true + +require 'thor' + +module ZephyrRuby + module CLI + # Subcommand for creating and updating test cycles as well as uploading results in junit and cucumber format + class TestCycles < Thor + include Helpers + + desc "upload_junit_results", "Upload test results in junit format" + method_option :project_key, type: :string, desc: "Project key (e.g. PROJ)" + method_option :project_id, type: :numeric, desc: "Project ID (numeric, deprecated but supported for backward compatibility)" + method_option :file, type: :string, desc: "Path to JUnit XML results file" + method_option :name, type: :string, desc: "Test cycle name" + method_option :description, type: :string, desc: "Test cycle description" + method_option :auto_create_test_cases, type: :boolean, desc: "Auto-create test cases if they don't exist" + method_option :auto_close_cycle, type: :boolean, desc: "Auto-close the test cycle after uploading" + def upload_junit_results(*args) + # Support both positional args and options hash for backward compatibility + if args.length >= 5 + # Old style: positional arguments + project_id_or_key, file, auto_close_cycle, name, description, auto_create_test_cases = args + + # Convert project_id to project_key if needed for API + project_key = project_id_or_key.is_a?(Integer) || project_id_or_key.to_s.match?(/^\d+$/) ? + project_id_or_key.to_s : project_id_or_key + else + # New style: options hash + # Priority: project_id (for backward compatibility) > project_key + project_key = options[:project_id] ? options[:project_id].to_s : options[:project_key] + raise "Either project_key or project_id must be provided" unless project_key + + file = options[:file] + raise "file is required" unless file + + name = options[:name] + raise "name is required" unless name + + description = options[:description] + auto_close_cycle = options[:auto_close_cycle] + auto_create_test_cases = options[:auto_create_test_cases] + end + + payload = generate_automations_payload( + project_key, + file, + auto_close_cycle, + name, + description, + auto_create_test_cases + ) + + parent_command.zephyr_client.create_automation_junit(payload) + end + + desc "upload_cucumber_results", "Upload test results in cucumber format" + method_option :project_key, type: :string, desc: "Project key (e.g. PROJ)" + method_option :project_id, type: :numeric, desc: "Project ID (numeric, deprecated but supported for backward compatibility)" + method_option :file, type: :string, desc: "Path to Cucumber JSON results file" + method_option :name, type: :string, desc: "Test cycle name" + method_option :description, type: :string, desc: "Test cycle description" + method_option :auto_create_test_cases, type: :boolean, desc: "Auto-create test cases if they don't exist" + method_option :auto_close_cycle, type: :boolean, desc: "Auto-close the test cycle after uploading" + def upload_cucumber_results(*args) + # Support both positional args and options hash for backward compatibility + if args.length >= 5 + # Old style: positional arguments + project_id_or_key, file, auto_close_cycle, name, description, auto_create_test_cases = args + + # Convert project_id to project_key if needed for API + project_key = project_id_or_key.is_a?(Integer) || project_id_or_key.to_s.match?(/^\d+$/) ? + project_id_or_key.to_s : project_id_or_key + else + # New style: options hash + # Priority: project_id (for backward compatibility) > project_key + project_key = options[:project_id] ? options[:project_id].to_s : options[:project_key] + raise "Either project_key or project_id must be provided" unless project_key + + file = options[:file] + raise "file is required" unless file + + name = options[:name] + raise "name is required" unless name + + description = options[:description] + auto_close_cycle = options[:auto_close_cycle] + auto_create_test_cases = options[:auto_create_test_cases] + end + + payload = generate_automations_payload( + project_key, + file, + auto_close_cycle, + name, + description, + auto_create_test_cases + ) + + parent_command.zephyr_client.create_automation_cucumber(payload) + end + + desc "create", "Create test cycle" + method_option :project_key, type: :string, desc: "Project key (e.g. PROJ)" + method_option :project_id, type: :numeric, desc: "Project ID (numeric, deprecated but supported for backward compatibility)" + method_option :name, type: :string, desc: "Test cycle name" + method_option :description, type: :string, desc: "Test cycle description" + method_option :start_date, type: :string, desc: "Planned start date (YYYY-MM-DD)" + method_option :end_date, type: :string, desc: "Planned end date (YYYY-MM-DD)" + def create(*args) + # Support both positional args and options hash for backward compatibility + if args.length >= 5 + # Old style: positional arguments + name, description, start_date, end_date, project_id_or_key = args + + # Convert project_id to project_key if needed + project_identifier = project_id_or_key.is_a?(Integer) || project_id_or_key.to_s.match?(/^\d+$/) ? + { projectId: project_id_or_key.to_i } : + { projectKey: project_id_or_key } + + payload = generate_test_cycle_payload(name, description, start_date, end_date, project_identifier.keys.first.to_s.sub('project', '') => project_identifier.values.first) + else + # New style: options hash + project_identifier = if options[:project_id] + { projectId: options[:project_id].to_i } + elsif options[:project_key] + { projectKey: options[:project_key] } + else + raise "Either project_key or project_id must be provided" + end + + payload = generate_test_cycle_payload( + options[:name], + options[:description], + options[:start_date], + options[:end_date], + project_identifier.keys.first.to_s.sub('project', '') => project_identifier.values.first + ) + end + + parent_command.zephyr_client.create_test_cycle(payload) + end + + desc "update", "Update test cycle" + method_option :test_cycle_id_or_key, type: :string, desc: "Test cycle ID or key (format: PROJECT-R123)" + method_option :name, type: :string, desc: "Test cycle name" + method_option :description, type: :string, desc: "Test cycle description" + method_option :start_date, type: :string, desc: "Planned start date (YYYY-MM-DD)" + method_option :end_date, type: :string, desc: "Planned end date (YYYY-MM-DD)" + method_option :project_key, type: :string, desc: "Project key (e.g. PROJ)" + method_option :project_id, type: :numeric, desc: "Project ID (numeric, deprecated but supported for backward compatibility)" + def update(*args) + # Support both positional args and options hash for backward compatibility + if args.length >= 6 + # Old style: positional arguments + test_cycle_id_or_key, name, description, start_date, end_date, project_id_or_key = args + + # Convert project_id to project_key if needed + project_identifier = project_id_or_key.is_a?(Integer) || project_id_or_key.to_s.match?(/^\d+$/) ? + { projectId: project_id_or_key.to_i } : + { projectKey: project_id_or_key } + + payload = generate_test_cycle_payload(name, description, start_date, end_date, project_identifier.keys.first.to_s.sub('project', '') => project_identifier.values.first) + else + # New style: options hash + raise "test_cycle_id_or_key is required" unless options[:test_cycle_id_or_key] + + project_identifier = if options[:project_id] + { projectId: options[:project_id].to_i } + elsif options[:project_key] + { projectKey: options[:project_key] } + else + raise "Either project_key or project_id must be provided" + end + + payload = generate_test_cycle_payload( + options[:name], + options[:description], + options[:start_date], + options[:end_date], + project_identifier.keys.first.to_s.sub('project', '') => project_identifier.values.first + ) + + test_cycle_id_or_key = options[:test_cycle_id_or_key] + end + + parent_command.zephyr_client.update_test_cycle(test_cycle_id_or_key, payload) + end + + desc "get", "Get test cycle details" + method_option :test_cycle_id_or_key, type: :string, desc: "Test cycle ID or key (format: PROJECT-R123)" + def get(*args) + # Support both positional args and options hash for backward compatibility + test_cycle_id_or_key = if args.length > 0 + # Old style: positional argument + args.first + else + # New style: options hash + raise "test_cycle_id_or_key is required" unless options[:test_cycle_id_or_key] + options[:test_cycle_id_or_key] + end + + parent_command.zephyr_client.get_test_cycle(test_cycle_id_or_key) + end + + desc "list", "List test cycles" + method_option :project_key, type: :string, required: false, desc: "Filter by project key" + method_option :project_id, type: :numeric, required: false, desc: "Filter by project ID (numeric, deprecated but supported for backward compatibility)" + method_option :max_results, type: :numeric, required: false, desc: "Maximum number of results to return" + def list(*args) + params = {} + + # Support both positional args and options hash for backward compatibility + if args.length > 0 + # Old style: positional arguments - project_id or project_key + project_id_or_key = args.first + + if project_id_or_key + if project_id_or_key.is_a?(Integer) || project_id_or_key.to_s.match?(/^\d+$/) + params[:projectId] = project_id_or_key.to_i + else + params[:projectKey] = project_id_or_key + end + end + + # Second arg could be max_results + params[:maxResults] = args[1].to_i if args.length > 1 && args[1] + else + # New style: options hash + # Priority: project_id (for backward compatibility) > project_key + if options[:project_id] + params[:projectId] = options[:project_id] + elsif options[:project_key] + params[:projectKey] = options[:project_key] + end + + params[:maxResults] = options[:max_results] if options[:max_results] + end + + parent_command.zephyr_client.list_test_cycles(params) + end + + desc "get_links", "Get test cycle links" + method_option :test_cycle_id_or_key, type: :string, desc: "Test cycle ID or key (format: PROJECT-R123)" + def get_links(*args) + # Support both positional args and options hash for backward compatibility + test_cycle_id_or_key = if args.length > 0 + # Old style: positional argument + args.first + else + # New style: options hash + raise "test_cycle_id_or_key is required" unless options[:test_cycle_id_or_key] + options[:test_cycle_id_or_key] + end + + parent_command.zephyr_client.get_test_cycle_links(test_cycle_id_or_key) + end + end + end +end diff --git a/lib/zephyr_ruby/cli/test_plans.rb b/lib/zephyr_ruby/cli/test_plans.rb new file mode 100644 index 0000000..dd17bc7 --- /dev/null +++ b/lib/zephyr_ruby/cli/test_plans.rb @@ -0,0 +1,26 @@ +# frozen_string_literal: true + +require 'thor' + +module ZephyrRuby + module CLI + # Subcommand for creating and updating test plans + class TestPlans < Thor + include Helpers + + desc "create", "Create test plan" + method_option :name, type: :string, required: true + method_option :project_id, type: :numeric, required: true + method_option :description, type: :string + method_option :objective, type: :string + method_option :folder_id, type: :string + method_option :status_name, type: :string + method_option :owner_id, type: :string + method_option :labels, type: :string + def create_test_plan(name, project_id, description, objective, folder_id, status_name, owner_id, labels) + testplan_payload = generate_test_plan_payload(project_id, name, objective, folder_id, status_name, owner_id, labels) + parent_command.zephyr_client.create_testplan(testplan_payload) + end + end + end +end diff --git a/lib/zephyr_ruby/resource/test_cycles.rb b/lib/zephyr_ruby/resource/test_cycles.rb index 516c5f9..dcbb03c 100644 --- a/lib/zephyr_ruby/resource/test_cycles.rb +++ b/lib/zephyr_ruby/resource/test_cycles.rb @@ -5,33 +5,58 @@ class Client module Resource # Operations related to Test Cycles module TestCycles - def create_testcycle(body) + # Create a new test cycle + def create_test_cycle(body) post '/testcycles', body end - def get_testcycle(testcycle_id) - get "/testcycles/#{testcycle_id}" + # Get a test cycle by ID or key + # @param test_cycle_id_or_key [String, Integer] The ID or key of the test cycle + def get_test_cycle(test_cycle_id_or_key) + get "/testcycles/#{test_cycle_id_or_key}" end - def update_testcycle(testcycle_id, params = {}) - put "/testcycles/#{testcycle_id}", params + # Update an existing test cycle + # @param test_cycle_id_or_key [String, Integer] The ID or key of the test cycle + # @param params [Hash] The parameters to update + def update_test_cycle(test_cycle_id_or_key, params = {}) + put "/testcycles/#{test_cycle_id_or_key}", params end - def list_testcycles(params = {}) + # List all test cycles with optional filtering + # @param params [Hash] Optional parameters for filtering + def list_test_cycles(params = {}) get '/testcycles', params end - def get_testcycle_links(testcycle_id) - get "/testcycles/#{testcycle_id}/links" + # Get links for a test cycle + # @param test_cycle_id_or_key [String, Integer] The ID or key of the test cycle + def get_test_cycle_links(test_cycle_id_or_key) + get "/testcycles/#{test_cycle_id_or_key}/links" end - def create_testcycle_issue_link(testcycle_id, body) - post "/testcycles/#{testcycle_id}/links/issues", body + # Create a link between a test cycle and a Jira issue + # @param test_cycle_id_or_key [String, Integer] The ID or key of the test cycle + # @param body [Hash] The issue link details + def create_test_cycle_issue_link(test_cycle_id_or_key, body) + post "/testcycles/#{test_cycle_id_or_key}/links/issues", body end - def create_testcycle_web_link(testcycle_id, body) - post "/testcycles/#{testcycle_id}/links/weblinks", body + # Create a link between a test cycle and a generic URL + # @param test_cycle_id_or_key [String, Integer] The ID or key of the test cycle + # @param body [Hash] The web link details + def create_test_cycle_web_link(test_cycle_id_or_key, body) + post "/testcycles/#{test_cycle_id_or_key}/links/weblinks", body end + + # Maintain backward compatibility with old method names + alias create_testcycle create_test_cycle + alias get_testcycle get_test_cycle + alias update_testcycle update_test_cycle + alias list_testcycles list_test_cycles + alias get_testcycle_links get_test_cycle_links + alias create_testcycle_issue_link create_test_cycle_issue_link + alias create_testcycle_web_link create_test_cycle_web_link end end end diff --git a/lib/zephyr_ruby/version.rb b/lib/zephyr_ruby/version.rb index d01f517..c639141 100644 --- a/lib/zephyr_ruby/version.rb +++ b/lib/zephyr_ruby/version.rb @@ -1,5 +1,5 @@ # frozen_string_literal: true module ZephyrRuby - VERSION = '0.5.0' + VERSION = '0.6.0' end diff --git a/test_api.rb b/test_api.rb new file mode 100755 index 0000000..a82823a --- /dev/null +++ b/test_api.rb @@ -0,0 +1,91 @@ +#!/usr/bin/env ruby +# frozen_string_literal: true + +require 'bundler/setup' +require 'zephyr_ruby' +require 'json' + +# This script tests the updated Zephyr Ruby gem functionality +# Replace these values with your actual API credentials and project information +API_KEY = ENV['ZEPHYR_API_KEY'] || 'your_api_key_here' +PROJECT_KEY = 'TEST' # Replace with your project key + +# Initialize the client +client = ZephyrRuby::Client.new(api_key: API_KEY) + +# Test 1: Create a test cycle with project key +puts "=== Test 1: Creating a test cycle ===" +test_cycle_payload = { + name: "Test Cycle #{Time.now.to_i}", + description: "Test cycle created by API test script", + plannedStartDate: Date.today.to_s, + plannedEndDate: (Date.today + 7).to_s, + projectKey: PROJECT_KEY +} + +begin + response = client.create_test_cycle(test_cycle_payload) + puts "Success! Test cycle created:" + puts JSON.pretty_generate(response) + test_cycle_key = response['key'] + puts "Test cycle key: #{test_cycle_key}" +rescue => e + puts "Error creating test cycle: #{e.message}" +end + +# Test 2: Get test cycle by key +if defined?(test_cycle_key) + puts "\n=== Test 2: Getting test cycle by key ===" + begin + response = client.get_test_cycle(test_cycle_key) + puts "Success! Test cycle retrieved:" + puts JSON.pretty_generate(response) + rescue => e + puts "Error getting test cycle: #{e.message}" + end +end + +# Test 3: Update test cycle by key +if defined?(test_cycle_key) + puts "\n=== Test 3: Updating test cycle by key ===" + update_payload = { + name: "Updated Test Cycle #{Time.now.to_i}", + description: "Updated test cycle description", + plannedStartDate: Date.today.to_s, + plannedEndDate: (Date.today + 14).to_s, + projectKey: PROJECT_KEY + } + + begin + response = client.update_test_cycle(test_cycle_key, update_payload) + puts "Success! Test cycle updated:" + puts JSON.pretty_generate(response) + rescue => e + puts "Error updating test cycle: #{e.message}" + end +end + +# Test 4: List test cycles +puts "\n=== Test 4: Listing test cycles ===" +begin + params = { projectKey: PROJECT_KEY, maxResults: 5 } + response = client.list_test_cycles(params) + puts "Success! Test cycles listed:" + puts JSON.pretty_generate(response) +rescue => e + puts "Error listing test cycles: #{e.message}" +end + +# Test 5: Get test cycle links +if defined?(test_cycle_key) + puts "\n=== Test 5: Getting test cycle links ===" + begin + response = client.get_test_cycle_links(test_cycle_key) + puts "Success! Test cycle links retrieved:" + puts JSON.pretty_generate(response) + rescue => e + puts "Error getting test cycle links: #{e.message}" + end +end + +puts "\nAll tests completed!" diff --git a/test_backward_compatibility.rb b/test_backward_compatibility.rb new file mode 100644 index 0000000..a4cf7c2 --- /dev/null +++ b/test_backward_compatibility.rb @@ -0,0 +1,126 @@ +#!/usr/bin/env ruby +# frozen_string_literal: true + +require 'bundler/setup' +require 'zephyr_ruby' +require 'json' + +# This script tests backward compatibility of the Zephyr Ruby gem +# Replace these values with your actual API credentials and project information +API_KEY = ENV['ZEPHYR_API_KEY'] || 'your_api_key_here' +PROJECT_ID = 12345 # Replace with a numeric project ID +PROJECT_KEY = 'TEST' # Replace with your project key +TEST_CYCLE_ID = 67890 # Replace with a numeric test cycle ID +TEST_CYCLE_KEY = 'TEST-R123' # Replace with a test cycle key + +# Initialize the client +client = ZephyrRuby::Client.new(api_key: API_KEY) + +puts "=== Testing Backward Compatibility ===" + +# Test 1: Using old method names (aliases) +puts "\n=== Test 1: Using old method names (aliases) ===" +begin + puts "Calling create_testcycle (old name)..." + test_cycle_payload = { + name: "Test Cycle Old Method #{Time.now.to_i}", + description: "Testing backward compatibility with old method names", + plannedStartDate: Date.today.to_s, + plannedEndDate: (Date.today + 7).to_s, + projectKey: PROJECT_KEY + } + response = client.create_testcycle(test_cycle_payload) + puts "Success! Test cycle created with old method name." + puts "Response contains key: #{response['key'] ? 'Yes' : 'No'}" +rescue => e + puts "Error using old method name: #{e.message}" +end + +# Test 2: Using numeric project_id instead of project_key +puts "\n=== Test 2: Using numeric project_id instead of project_key ===" +begin + puts "Creating test cycle with numeric project_id..." + test_cycle_payload = { + name: "Test Cycle Project ID #{Time.now.to_i}", + description: "Testing backward compatibility with numeric project ID", + plannedStartDate: Date.today.to_s, + plannedEndDate: (Date.today + 7).to_s, + projectId: PROJECT_ID + } + response = client.create_test_cycle(test_cycle_payload) + puts "Success! Test cycle created with numeric project ID." + puts "Response contains key: #{response['key'] ? 'Yes' : 'No'}" +rescue => e + puts "Error using numeric project ID: #{e.message}" +end + +# Test 3: Using numeric test_cycle_id instead of test_cycle_key +puts "\n=== Test 3: Using numeric test_cycle_id instead of test_cycle_key ===" +begin + puts "Getting test cycle with numeric ID..." + response = client.get_test_cycle(TEST_CYCLE_ID) + puts "Success! Got test cycle with numeric ID." + puts "Response contains name: #{response['name'] ? 'Yes' : 'No'}" +rescue => e + puts "Error using numeric test cycle ID: #{e.message}" +end + +# Test 4: Using string test_cycle_key +puts "\n=== Test 4: Using string test_cycle_key ===" +begin + puts "Getting test cycle with string key..." + response = client.get_test_cycle(TEST_CYCLE_KEY) + puts "Success! Got test cycle with string key." + puts "Response contains name: #{response['name'] ? 'Yes' : 'No'}" +rescue => e + puts "Error using string test cycle key: #{e.message}" +end + +# Test 5: CLI with positional arguments (using CLI class directly for testing) +puts "\n=== Test 5: CLI with positional arguments ===" +begin + require 'zephyr_ruby/cli/test_cycles' + + # Mock parent command with zephyr_client + class MockParent + attr_reader :zephyr_client + + def initialize(client) + @zephyr_client = client + end + end + + # Create a CLI instance with our client + cli = ZephyrRuby::CLI::TestCycles.new + cli.define_singleton_method(:parent_command) { MockParent.new(client) } + + # Test create with positional arguments + puts "Testing CLI create with positional arguments..." + name = "CLI Test Cycle #{Time.now.to_i}" + description = "Testing CLI backward compatibility" + start_date = Date.today.to_s + end_date = (Date.today + 7).to_s + + # Call with positional arguments (old style) + result = cli.create(name, description, start_date, end_date, PROJECT_ID) + puts "Success! CLI create with positional arguments works." + puts "Response contains key: #{result['key'] ? 'Yes' : 'No'}" + + # Test get with positional arguments + puts "Testing CLI get with positional arguments..." + test_cycle_id = result['id'] + result = cli.get(test_cycle_id) + puts "Success! CLI get with positional arguments works." + puts "Response contains name: #{result['name'] ? 'Yes' : 'No'}" + + # Test list with positional arguments + puts "Testing CLI list with positional arguments..." + result = cli.list(PROJECT_KEY, 10) + puts "Success! CLI list with positional arguments works." + puts "Response contains test cycles: #{result['values'] && !result['values'].empty? ? 'Yes' : 'No'}" +rescue => e + puts "Error testing CLI with positional arguments: #{e.message}" + puts e.backtrace.join("\n") +end + +puts "\nAll backward compatibility tests completed!" diff --git a/zephyr_ruby-0.5.0.gem b/zephyr_ruby-0.5.0.gem deleted file mode 100644 index 45318353dab9d94ad098ac28d093ee1366646866..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 19968 zcmeFYQ;;uA5a_qIZQHhOp0#b;-aYHxv$k#9wr$(yKVOoE+`2D$x=9|=FFjLTGu2(w z^Q)EvBU2++BL)j^p#N3E^q;V?u>t+>`ak)fH8UF%8xS)a2RkPdGYdP*e|Bb8 zHdam`BBuXU4*iewy1BR-IsfO9hozaB?f+=_pW6R-_Wv`s|0}rvY54zFyM)nDKuYM{ z<{+Re>N^fgOh^H521cKYWyKrXU{S-x)>Wg$cKP;)Mo{9lE_U5K?)5nhf%^_;htDns z6^4t=&4?XOjAviHu)%@7%qPW{7ZdD`n1rGPW0>HM%;?$N1?b9j5$V67Bvo=MCKK>j z(UcFMdHz;$P$jfVXua^HDpIGVo5##AB$^j2cD8aL-s#vz7sy@6t>!kMd$LAE6sQF% zM#eC0LR?sB_c73D?=QI08KOC_ML)twJ&3OmY*EGl#G(_?Iw=_Nax^r|eTUAv+XWQm zg3;IlRddZrYwrRngh_tWOHaR;eR{54br+Ctw_iM0KIJ6Ek18*9{j1xsyG|QwNWx!f z7#QI_)yql{`Dpoy>~Uc1Fkn!W^cM_S*sH(fI^o^cLmqG+EiWYc9J^me0Kkj{aUH|% zoaKAm0|y4~b~I!+0MBbTAPoFBCcMnB13B!ex*+*8qNGF|&aKnGK*QhGjUGRqf#Kr* z2|6en8XFalrrXt)#EESg72F=bT>CkSjgGnEbm9*k^9-)J7NwXt`jl}LC8swgGi3)Z#LEQ-NF*sQ;J$`itOHyCX-H9@N2 z)Q-ht08PS@6t5PjMo8~W4|kg9l&NXc5P^WciPB-wuA#=yFtL{~VY?|T69b!{5QnfzU!V3ejtf!$f;*;RMVeBlmkpBm z8glG8Tf6M+s_3{9RD-_SvlGNfByeJkpce~|F8L>`Tp4KNf||9pew`u^V<_~7g?pNfC?EfowhW; zwh>c_vL%)gkAez=qSk4g$|Wc15;M)Yo7PI%mfqWBmt`KIXN~g|*^lTB!tPnxQz>;M~!m5UFLIQn)4isW> zY{y%Kh_wL?St)pZM>J%`!Z8MkIK*`$qJpK8m|7ivz(NZPCq_0l1h&^l8u)w>bey1` zD5s?^U(r2ferE zfau?l8D%L-szE6DVPGg&QZ6`9ap8SqL%2x{7?6U*Rw`Ah^bwR0;B5g!L?n71ZK0Zl zZK-5%SVOx0O%5g1^bXQ>WFRn556yW))^d0>BM9;I!F)?5IAHhSO--J{7{~H$E?pqd z=I1CMP;+77>U_FvLkv!7qT~HjGc8-azj9iuH`4~56*N=SM`w zI7ARz0hJ9F4(4@8kc2E1jP)T@tB^1fRyj7Mp-R3I(;}X&b)+mj*8mn7RaQvDi&BiB!_6`rnV?D78Jx7 z;#uvyp*q~Wlf;cUoCF6SDk~Kj0tg+#?d~FdJwM#Itu3?Aaxkk?DHl$5pcYHmR_4KH zy(=z4Q#ieIf58!CJOr?q-9kT<e??oP5yfWT{S&OByeZv zJoq-qdUf^XA$>DB7y@LL5GEzuKCEbXKT@0*K9}wUxCcEztD| zaO36VWkd@Q1B^AyCC@gHMm~JCBiuXCs`@`=wUGvpiF1&iwZRuey0QW<5m_x|X~^p0 z0-8D?wn-Ww{-i`THBCcsI2i>s39VREI>sW3qVmA8MWAxaAV)*k9?&al>itZ|Z_~g4 zXP!x%%XXu2tMV&LU_$O7W$O#NqD$)kQaRYHIl09N)mc+kG!`{9O94m}R1vISRYNmB zILrDTlNKa!U*O7`mJStcigvslq&e_J8DRX;zQ+I9ce<#Okf@>h4x0opxCe-I+gt^F zi;!Hs^z~8y3PvK%Ii2wOKGwwmQGg+g`G_D{KA`TV9|b#iTX3-IJhCI<;`VPG7zOnQ zFsFfm762^+TU$p1XCv)0CAxh()G_fr!CQ^8?Tg0u^PLPC?V7=pQO3>*%k z0DjTZj{2XyqB{Ob#fpvvU+k#kGTfUI&8_cFH2D@xtI4 z4dV#wFVHP@EUv*u9EKPLR}y(*DkykQkC4O;5+1;R}01UUjV#=}Kh+=Li|4F)FR3nT)=L_5I5+y`+3BEe68 z83ef?(uhQ@-{xu%CIO=Q&KyeYF9s2@w1yTHO6%+N+$$y90)xOIow|uBGlN5@s2J@&(hKmb`{#if;p0tMyG34(6^j6Gx?*stWdl8+ z?~7l;z0L1D12NB@-#5i_06lMnIN=N^RVp$>aH~jDpd({o0Y}98AhWTddHQd~OZR@j zZSas>FH;Fs5wbf`Ky5t)DlFr2^Y*V6o4@XK0~w(aO3~UdJb@s2I#WhqyAtXWA5t| z0S3QCu6_Y|6#%Mp5vpm>h7qEg2Wgtj6G=yZ|rX^ zDNy5RSQIEziaQf46^?DJU{d&KS>x2i&tWROXGtaK=o)`2EZw}&wU;@zMPgUy5k zG5z_pL%t=W^}Iv=IgkiFxc>jT-$v}2~ zH4<(*axdCMcpof;Y!(nGN2B<_01B-IClJ*wc&&SW=%t_<^ z0XX~E8c5nl!+~`v!zn}bykR}}n{fdoU8^l(uN!JVdoYPyqPbF&S{pC~M?1(NO5KR< zl4XM*G72U!!z;o)B3B7W=UKO0IJlCHtPoEQ#^tghv@}x@9g}S!L(9?T^2 zD>_)ShY+xp)+Q?k!Gk$AQuehU~BoIqfuEx}fNeN8>?f%N4@!m@u z1_L+nL}H7`X$)@IQMKLt14DmJ^cP_N-Dhj{+l{whb`}7(HVPnVmjqco0s#EK0Xaf; zT2ku4?7AO#776{Qtx(_e{cuKjefV7ymNZ2Jt(M!TKylgNXrP)TWH@hY7)|w%Mi615 z%u2d51T9DjPN4bGJz6L5Y1L>#!EP<$L)<`XUf; z`;Q?Eb@fd@&~4x&AK+%1K;Ll!)n5mIvR{DCNe+MwePhi30*x)T3fTj)uJ5@7Pr${5BmxCF z2R~$29Xuho!+4Qj$Z>V`91BQ3!iwHm-t-lZe$`$B+%|p%U4aC*0O%;lnl=FN(2vy{ zK;P1DfEt4V#eFO9i0`E77K25jTemX>UrLWDz)m;Wx))ysw6n49rU{n>X3He*opA9Z~VRsvS% z0)BK}2m=VfyPf+@u>)p=Q&w_u8Dl)P*alZf?j@5oG0B!;F5g=S4T2zbKUlJ9=U7;d z;z`5UzwcY(1t$^XzvE|MdaD2dQKx`P0KgicA*ST12LR-J0^nx=+83A{W%suc=x-MC z&Asis)8kFWF40T?n~gWYbwFLV&rf`8|J-YUXIS4R;NV1O4ge_m>^m(#XZh5)sdBzX zH~MzU?76IeoxAdnehCxD8@p4(>dpUnA{k=oDB;|rW2;62k6EJ`Csf15$R+xv2ywW5 zJ{mLpGO@q<;=XzX_`C)jIKJi~f&97xBn@wV5$p2jKi>krZEgUSs(`9$0A`KB`fnJo zVAFT>+}`)5{~QU|)!~(g?K6mU_lz#cSDSeH-U^_^BIVcn=j`YN^IHZW9=iGh*sA~- z@C`P_beFoN{4zox#=iu7EOZ*gePJ;5V!qTAzCEQoBrgBAfOZoo-2JI^qCXnrB|4$}*rp^<$!AtnRztnK5nG*Qd=egU+x_L-aRT^qnFi&ok_<>8nSX z-WK9_p@BZx8av=JH7!w{gJ=!zHH+k4br#l#&2rR$FSbi=fWZ2Z(j6qfl?kzryi_9E zpdk3S#SE|^L#O<;^I|akHH1?CckVs<+RGY}m;tqS{@6r^c6|*YIUamD`fscsUeNb_nV4%TtNQ#s86)%xM-S<|jGP0HegqHNlfKX(uGM^EEdMDW_>QwPSPFBH zA4i0{Vsty!fd8S1|2abctQ2kS>t*Z1NWrQ()(IGNu0Gc5<9NSg0w6;C9xdNR$K~TA zmkR2I2vQ+T_3RHg8GRe5Ca@#V@0C$pb$kH!z6k@=e;EY<)Wej|D<6uxFF$z!F5hjB zZfORg{#99hEa6;6-^$%>_aiNRmu3&ksk^>wsYg}}n=|75c>+kCkD-%_q~j$F00}jW zz37osaB&;Rd6#I9SuKR~kT_3#dT^C*{8STm5`*2w&Q&l3Vn;#x;=r8Pl5 zJwM|<;oJ@PVXj;KLI9Jojfj)+mJ;x*{)36s-(&FgrTBgI33xjfL<40GF(lf?Pzbz5!C>^J|;~ovC91Q;&#-)v$@*Nl2k{6U-Jvi}UB0FQ@o~OU~mo{^` zHdWv^@|`S(vEUd>ZFBRkN^(o02%IVz<4+9C{+!tb7L3Q8XUoEmv&^xoba7XfAwJD# z?a99n)hFebO%uZjXwEIEc#XTnoRe0oWfSnXOqaU-x9`XCzSyDSVAjeB<`4@X#X(qp z2_?JhAbhYnmz^}US(YGL=C0=0x@5~nVGHm|KnUA2S211fcVtJ-+fI?XIBbkqD;wPf zyM>xP_4;}J8vyw+udu1VfvHgB9DP5A{&%CjdHK(^qx0d+jTuVAUlXJ$ zpEnVz42Rug&QuB+6Q&?xSJizv;6Gmi5iDmVr2cYWQ`mzI(X8}Uv?QH<{))rCK>k=BUv;QpC+p3IxfyKbZTW5W8RkglS7A;F=& z!DQrLF`)3^BPUVv$EV~@-DH!#KhnP~v1#GL8xTY*6Y$1}?wLsvCs@RJFPvM?3VGZY zL*es??HR{{_$qE3?|Z#UdzR|s@AtVSPw0KbU-volzJV;Hx3P6FGj zI#Lb#hPKR8zV=*B9`)z$<;DiIqV6@QWn(+3asz`i%(feQweL&)IoChw@u36^chq3j^kBG;ot%NRc^q+;FfKxa$l2JFoE?(DVD{u>}}V zHHD}YP2$_IB^2)3ZLAs{%G}VuT;5&Wsm|AqmTre+jaRZ<&G5`uY8>Kq`l6pHdz6Ip z7`3EPWHNxCrx_Dyh>u>MG2{AjC7>s_6uj0Z*0$1MM(208e01K={XR96O|RHXr(cO- zi6s6=3IANwH!a z*R&!dlipC8Q;fOOL2G`=V%}D{ChJ*5dqBY$Vxd=OC*S}Fw9`>tR_5_X=gU$wr~v_s z9)n~|7dACWuXFXQ8Fb~{L36eoXL=P$?i!OlHl0&Utgyx z2@$P?oMAqs)Rr6H0#3q~`n4*Zxz-f}UtsB$l@)%Y1mXMztW$^2d!@;yqeaxpHB-Sv zZzSodgx(27v-&;>^(`3WCx{Z}`a94ZSWdFzZQ?6R3+Z;|+IW@cYth-|nlx8Gg35H+ zyi#t@^K|)fp#}L}n=#O$Qikk!zs8#LdD`(Apqhik8V6cGKNp-v9W2(-h> z0g|yQqQ!0EG_&@w&{?0afAv$e5G-IPQ|^MT0z%3pgJitKzJVa}=9C7H;S4WM+U?XL zYV#J97h;mFlzoOnS>KI?)*>XQ!i(NfQ9uDK9}(^X*=C5}qFDCe{OcM!5^0%_hnfCM z6Ht@B#LehQQH9i-GPvoFsPqI(T;hoFPJIs$5QVXkW|$OG;9U0Nc9bo9vX@J!o1)6f zGV+lW4Llxi!2kg-M6L{c@wtPkg5g8*mlgCE@r7dWX57UqpG(Ab>5$4Fx(GfF%M;iS z0x~CVUQGoYoXe?B@_?@^jwqjJbMsPAN7&&Dg5dkoBevuZ80VM=pU0}&R3*FOpiJr~ zbIT815?+bw8BefI;wEGiLzXSN5QaB;qtr6eY;>Uq^J2WX!1N3R?4;vHAAB1Obht{S zNkgMFQVdDny+l>~P)dj=>J8K&%a95CQvCOKFyE+e<{5YS!wMr=_;&6K0+~i7L>lYP zAQQ$}Ri56YORw?fqeV~y>fSk0f%Wjp!Whi;B}(iD%__uoQQjgQDCV@Msok!;m%lA9 zMDlmgQeIq+m#0@bSp)*g^qxB_={Buh>EA+`GYWa8?w`A%5w_-Rk&Vp08AER~2R?21b0qq44h7$O0LeHNp`H7i5J`Al5KX~fi7}py|e7p zGNiNHIBMyd)pjqk4#c@+G?SlA}ve>I(D~ZU1*36iwaxg9cH3&}fkbaYQlB z!C!Rcvj9qrRa;ZF1y28*J+=I>{;uS%4nc=U=Cg%*$bEZLRI?_OdF1mo@|}2u(HwQi z%Y&veU|dQE*Q8eV*4=I?cjR_}vPaQ@2=?*3xY`{?=C}3NV+@ayow74^PirWja?qb9 z6fdWu(&MZn^QG44wdZb<$JFET&IBxYXy+O%0=I1*E?6MJZgrgKbaSd5-_Y~IIosn>7=K9dc1)T*N7r(A?e%yp<_ z9JG=jw0Mc3`G$m;?Tu~y#_7s@T^<~yEqxBSj)_byd6gTV?eVUx39Fftf7|Mw?<96W zA~DC!}5v;n06s7^8h(0R8SHRA$ZGL zf4nP_%$Fkm?m84*lOy$Oj zV-T<}NjLpoTMBYT&XXf?;Z%wH_37q9+&avI6m1s}A8Yv%VD6nKmG&VAovrWLmIf<) z^H)xBW}uqp@OL9NMsz9V3+(R7#WkhCJZ9HO=kv)Ow-VgM;(N>i$;N);$nVpu)O}pN zAz5{RH^z#uSr=MxdnTYaC-l9%BqL%Ae0FDXu?21xjlgF{WTZ^djy!7bfL(TFZA|qj zmyjtyH-FM+w^Fsdwu6(ApLWL?f%jw6&jVX}$dC2*$$`=SGIWT(GqwzSgK?6|-TaTO z`(X>&c>^a{W94Q@cvs$u3K2&p%}oP_1EMnE8kYpEmXl{2o_#fQ}QvAy?*8 zT{u6rG>pPEB)<~_nXw-mo}5<%e{}c{vc>$tft>YTT<^vY+L%;D4v0efMiJCv*N>Pv zN%T1ki8&&5KBd0W3)g**RU?_Fi{BW>tj3~l9Iy1sI`%2QJ_;H~s=;gJwsx*0&LoZc z;lkFQ90qb;zA<(#gHsZ6@v1Z?((eI-IjxNrI`(1qB_z*`W9jB9{y`mC{}0m`hD*!t z%~q^ucCox?W$hw3-gCPlxuBwO(a~)&8KNMDWLr@N^I?)(=ttRXS2Bw^uB^#$(&3!I zHgfH>Z@BiqHMa=Vlrpc?4SC^=Y&MTg)e;UcK|=J+VjubRYOR942cfc#9Ld$?B>@+< zfR~Q{4%S&J3Sv*7t3giJrs-YRW9xKvqjr?LI^+ui)%4Uv2hU^(ph@y5w#bYPzGOsF9 zu-eW+I!7cdOp*Jz4d5gyC0oIh5@u(rvd#zd@9WU)&g)jz^e~`Zk{}}%c|-BEsF%mO zjxX#R;s5?cT(|2Q@wrt^l|^e<)%(xREngMmw-v1lA!|Y{s7RvSbmT~F8Mr0i?WD|n zLy+fiAja1DNX%MpA^mfdfyg<@#xvv_$-KC;VQ*122lF{{(MPppNcucI-7w9Az@m32 zB5*GtxRPLrCf{3il=>(h+pPkQ(!tt28QYz`ProD?)x`mtX5W5WIZ)cPb6@Bt8!O>l zQ0Te*&8K{Z5K(pKP)al8^gGnKC}LSXLl6$JjpPoQb82wo8JEzN30S2{J0T&}S;zA_ zM1W7^F`glt>|fB12@L4WisawtE(|+jV@MzfZ{-5p87i z^4?h4Y|6dq$qqW7J16!SX>;+)`>V*_0h9J#TUG87&$lPv@$l1RzH#I*gqm6Bzj|F7 z>RFZP9K#+C8{9a$C6BMCA_?L>#hJ^zsf|VIS(*Ho!LSVF*&3)xnQlZMBpI^L4R}3q z;O71ZDc25-?a{$tKFg%XW~qTaG=1!eEX4kkb%I%LuHp8m%sx?ZZ=65+l@V=^00Gxr7!EYbBeFgYY$ft*4T)!_>-6>xN_F3em0s2dQWn zRiTKytoXQ|p*tRt8w$spbMmf|0`nQL`dt`05{|>m*x(fQ=>~l@Rn>LpQnEoVZ@(w; zT#-Eg*D;c1)*vvoS9M#?DV=ZaL3-|rUiEs-hRo;Jy8ck?!#p!K@S0Q${ale%5yK14 zwS}ihRL6PS(2m6?_Q8C1NR)}B)iLdzr;!Z8^hwSPxwGY`dtA-*(`p-k;?H``O4HEN z`ZG2i#8bI~5suBmodU{&{W>RmKC+<8ANSwH=|GE|>CsM5<>Ud?378u%YE9Fn<1^EM zi+W(&C#9aRh+mz&2A!+=LHgoEMjZv^kCJmjCO<^!Iu-|c9G9o;muIf|g1)h{^#WTr z{{c4I27%qn$}`>yFXLJXVJkt6-3F7MkHYyAUWnrvA57rNJr}GPW|$Q2(7RQZ;Qi0q(j^r#40_Jqp5>yR1fUQ zgrD0Mt7{br&B0M^PmtH+i=`MB%^*cDH@&Y(*yn95Qq>Eq9+pE`A$4DiC(`1E+fjOJKKVIClVo40N z#(U&3zmB~tGwB&Z!}8YKEQd5s&M6K2jm%l6gTSG~0v?0vUos$rcv^`f5ExwN#uvP4 zF~K`s%Fw%x4L}csmEZu6WG`?4!Ov;+Ill9!%pOxz!5VG2~B58wg?z_&VJr;TEpqLl7XT&*Z zY%zs;1m;JnRBV^BmcI0+# zJ}TTRNZ!XY3A(9xLtK>XiuO4)t!t$IUsy{RV;OHw3V*mcz{Pj-=8L5|I+Ee_o2h$$E^ZL=~u z1+b_{V`UDku1shcTh#5AZm;k2d$KK(zPXd@A*P;I{<%!K8ZwP5_ZjMu!c=VBqF>Rd zC$vwBEN0E^o=oZFzvCau!FG?h%A%^B{_H)iaB0I2;9)zozt{@LZ^9|NgSPbRNb3{X zAKFPNzA3rD0JXJz|3gB~V3c(*sL+eL#wSuGD!k0S-!XjG_!a)ed z76oKkpJU=yfAZ&}&Tj2^?($xTIlH#|826Gcv9EYgJ8%Ab9_WmT-K2|tTbkPFP+Ye= z+rzwac5#>6$>$n0cf9YJdUAeESh`tprn#g@DH3p7>k`n5Efb`o2)kYPVm>KP8}DHX zcv13s@azD6(Dvu{_>z(AuYow#7uEkb_Ey}(ougPaz(Hdg#gdPYFhgBg9o=ck#fB;< z?jKb82||7FKWf*<9zA-tx~`Eqc93Q)78MlYc#d z^jcfvx=GB)jz4c@jSys!iv7Ewx}HC%301o+9}3`Jian^oRAoRbsdpiNLBNf9kk(lV_%jQ_eykfo z(y{*Hc1-HYS@h;I6{)_ciI;E<42?@ZvfeVsyfZCB#yu3VyvB+ANl403Ea4 zLir_Bx|Fk8`pKKj^RnX= z^KM*B+6ALEv|&cWZaTg5(>-(f6MSL3Jci3w?C0{LxVx-u%%^DVHmxl(ED4Qp%0-oq zeK4*pwnttf-o~3;)EWcKmE{k1Ycx1QXORAFE1_M)1RVA5q-(?Kr%W`ti+Oym zK-mH>pgT_K!OYh1JQ6kvB_1btw5aaH7l&s-X4Q39Nv-?o^W}1`AtID^BfBlDmBp=( z+GgiSol?nHVZc~Zl68H?yPr*;c8bPg{_VJ`{CK{Xze}EMOc4g!U!kKpzT{g7e_D)- z8}L*X{>c1v_*ulyx%o*!1LhoWdLMu@ixA+I7_r_Z)xJi|Lc%^^Wcpld@;3_;9Pfo= z;e^aujcBClF&%i?ha-?PmJJNtl&*3iwIM)N1T% zl9w-|$e{~9WiN1;RRtR>`Rmr&WryB*jR63sG1v;%8eiW1e6uwLmoh z*S~c8_Ao*u4{AY@JrQK&{+dY&sD-uts8pdxo;X7tNzE!W_~6NT=QW#qW;7w1l}=F&_KW*CIiz$Zn&WCbp@*sTH5*jq4`27$%E7ch>GSbWTDDeit-F3F zrz!ce&di3GT7y-GMpH`!E*0eFg)U$EX4Tu`O;wpY{{%3uppWu~)nct?Jo`guDfN#6 z`sP0$jl((%$M@?=*1E^-ul(~+;H{C}i=I{JiP9X@KYzl}eLz)rXdNPCAt)gis|1xa zdTXYuOA&C=X}LYa^D21r*Jt%dgx{WAX0K~W!-GJ>B_O1IHpH3)^0-p&=D;4xB29Pe zS8StBMq}4grM9}4v5w5S?6j|>p^}eYAo@IVRK670sdtZZt=)2$P&seBcD9h#^aD%) z+p;F;DwQ=ZwH^B%jSnhyu6L#{_Mgq(43XS&DXhj>#n(+XJ!^Chz> z2~vyL{`6%8cAhc5sj6?S(kEr9Gs)WLZHyc@of_W_XWycQMnj&L9;3}Ob>R@S*9K+V zq(K5X(KJwv>bMB`Uudf+SU40XF{#v*|J6gQW1+5V%{I#(Pj1<~VkdckIKO;v`4nE2yU>cfX}qzFC`6S7MFf9(y?!49(NuyE%JTt3BHxfX_OOmp)2UN)dlrus#y zk_DSb{2dtBN?1zth)0x;3!p1-tNJ(Y!uD{t#@P8j@gkOYYFA;wAu|Ux$c7%rCSTsE zkebl3874-+k`*Eohi%SLtiNr92kGN79jl)0fVu?T#q)C;wWJ(wRFFcL6Pl+$l1Vgt z|1H^uT_{@BuK2~*t6vYi>n+xCc$)KlYx&ghEbEFd>E^my(rfB_{AWdQzW7c}pV2k{ zJ*jEG8WV&?-v7j~-ST3CmvPTUspH{oK~y(a9-8D8qqT}u?JqUv7)JO=9P zs-Vbjn)Oc^TSQF1sJajKxbybqpk(UsFUc^xJ*R0hnQU4I9E7f}vl?`l-Q97V=n5Wq zcc=--=VzO%iEA%;%R4>f z>~!>=73lqbyEv6hySo2&#v8v9(#@IC%T+s668W+11nmeaMO7SK%-Txx3$(DF)%V$M zDVfE15BWvx{8!)3A{SF}S*a@{eoy70(bHJJ&EkGS(8i3htjp|rhwv7HVKFs{=tUlS zrW9KqL2N#%BaNMHQR>U24<*yxKR$oPwVb{g2wg7fR02Dl#Y5#-aq5m%hE^lW*$(sFRQv7Clhoo|=7 z@NZ%fN%g@(a$e^Ba_ONw;t;&}rDY@*u2<0<4M!bp!6KwI&*H-Wl*T{m)x`q8ET`ei zfr;UGxH2i_EXY)x=cw|QwC^Hi(yOlMJCQu3mBloq4IzlAb9NYX=LmR4Fqd_-W7Hj- zn?9HnDIT?3l3IJ^bOA7S%rzH9jSpowl`Dt}y?iCz1p=mxC;1Y9m&pjbl+~RB=#qjk z;#&mwVjLAxxFm%Vao%YAqA|j~zWK+`j;Oh-weXT+9CFHZV>_~!M>_(|oorqTS{sk2 z;^wt?{AZn$W;p!A<9n@M=YvdG+q0ArW2!0FY~x_+rY?cuR$CywT2Se`J9Eh38aY^SSV;Z1Zw00Wy>Pf zg7hXsR>3FYWAAW5@|6U#mGUHsT3AieAiwUdxdEUriIy9NNS#&Ux~I-8-`s!}KV8J>@bG36LY||#EOUfNBpCvSHE=N8B?z(sO*c*g5 zmX5-IR37BREWznMax9H@5=$@gFGN0PyuL^({^h0XVrPrySy{8*LHBm3-KLK)Z)D1o zBqw7=?@o2a$Q<|L%RV$?cRk!I}GMF8({( zzsptj-z4j2_Gy^Ct761g)UhQmJir!ITh2`9!r9-MYwL zL{#rP?3qlimz*Eu$?rP47!eT=^FR6ek?xgLQeNva&D(YgFunf8veI^ZyVhID{!Jun zFy5U#u$ZYUr{5Gv)jMeiSs`PE-ZQdXQ*T|+ZMYUXedV%aW6`?OkGJF+_tWGFo|( zY)ts%#vOOEJHeOClC+Y8RRF;ww1k?Q*_L+X9l8tawAEEK2|S00k=Wro>#a6CQ!w_^ z-n=9^kSQ_QY$(F(-02$+b{eh~k$t;OtI9lOHmFT zd`7A_pw4N-j)sTmv9zh^U)B>!tEZ+be#bkS-z86x zqH0c6QS94T8mZ!+y>(aEMd&e!x$A)BFRWH_u5}yBm6vqdy}CLBl>?mKYYn3O zA$*M-sc7uyEa+oH8o~qE?GnFwP5P1OixmdGgFzrOoWn|V^=lW86&o#PZf$WamH_XN zyYZYUFXgaLR&k|%bNGE#_BM@%6>kyF;*}G%11$f3gQ7kMB^G;X`DSE^(}`cLg4eF5 zOo=dU8nZPA|Ip#rMUkk}ps@Vp@9L}Mt?`5-jHz)};)UO4cuw}jK#_{COCv{{&gO*t zRC&}ZA!V=ZLuhG|1D$86A<3wPzf4D}q$A&3?MMR)1qPW7V%k#cg`B&8+27iK`J&#t zZFf8|L>VS!>4*gixt@X#uiF!6h!bE4eGGK4qqq5Z|IX>5cNl*8gdduMYW>XzjsO0>~Ny(>1JtX_vZku5}AH0Zu2 z!M$2nv|49i9X~~F$x8S!-hjaAX@ap5Fd~UEUq(H%RkHu}^a`FV^U&5W80Y3L6?YOm z4sotnJ#zAfW35tpAd-PmM{^ReHw2}mH*fAEIpY}BPVm=6*+~odB7luHR>+SvO32zb z?U@W4sJt*I$WdLZIXj6zfoX5H zl!v3US=Mr69iH1ZCyLI=ZJ*~1i#DxI+lLU&INHMu5_Rb-NKcB z7V6ue`4!=@#06i~l;5UJdku?v$EqDLPu}J7yZs`dMc=14AgD(Z4&^2*(oeH8axo<0 zTAIp_6t=RTAbx5XR7d{U^BGk6=j#C=R{y)Q*EI!PtX;o}*XbM!pPL;4N1 zUa*$`#*;{XltFp?U0b3w%2AEMi+29YX@EuRSJcl>>YaDz0*GM9WkM-?;9p}JqR`kY zx%M7$?E^ew9~`Hi$CnXuVY>M?V~`ZABO6ydG;_@)8{ZY}GRH$yJuCPP>4Y};x8*qK zHO^P_=jNu<(k+S3hGbY;ejP_pF)ZCe3n*$p5{Lw&W(Py=$m;7goY~l&wa{jraoSF{ zdHO=}GGuxyA4|DL70sg2tamc7?drdoF%4jo|;C8(f{i%cLoamQI-!f4$lXxDMzl~SHUl=2?s2eVk ztT!HGh?Cv`YugEdN{A7xulnm#nClU~bfVVT64pf8JXYVkaLQV0`tG+BQ^0%Pg7(vV zgOq`}hc-7>Z*vN&Jh6^5gH#s8tNT+ICJFD}r$n-(8^E^K5!u zFC$fUOd(4nhyl#n2Dv9nU~g~igV@O8t0>A=p=vBa#}2ndTk;EKJoAQ=ILD`l`?aBi zeUMkOY}B1V)-_teB<~YwE=Xc^Ne_LettyD}Q5Cs5(DMC{g`7;x1Zs2QQP$0$X-u@) zH~TFQS%f25W&X-`L|GA`z!7_*a<;%2)ZrS!Ur>hcc#1;1|9+3gA=$hexWL>~p7nWw zhk34L15k&5$o4-!`ubkJ3E7lHax^oSeIyF!=hMGOF!bBQMxZv%#wvV2;}kG- zd#xFOZ$<7hcuP`RIJ2zK`24Nsz`~h}@I3XS^T*6fuNJ*8<-J_V<}Lc>39m(O9%UX$ zoJ~fcu5`C+Q}G4N0`lv*K1_$di+QBTT+f=8W*%yr>O`lM|F`L^uhHz6T)a8y-uGC^ z2bVWZ+3}#jth)KI}>QYU1D2y(;AH_19m2{Clf?>R*M;eEZ*TpXUGn^!WSn;2R=g$`A5HPg$yD zw%$x`zjaCQ$TH0z0xNYy-(BQMPPtoAIe*Re|G%Cr^l$!d#gM-F8gS_-!=ZHcguBwq z%}(oaZkiTo5O+9hb^oJy|HvQnpUZUTB?feGZ9lQ;Xovi--fYP(Cx6-K&5#i%8tAut*Oqai@o5C8xv&6bG( diff --git a/zephyr_ruby-0.6.0.gem b/zephyr_ruby-0.6.0.gem new file mode 100644 index 0000000000000000000000000000000000000000..0e7f8503a56698fd7acaaad698be8723fd689fef GIT binary patch literal 9216 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 literal 0 HcmV?d00001 diff --git a/zephyr_ruby.gemspec b/zephyr_ruby.gemspec index b1c4882..96d1646 100644 --- a/zephyr_ruby.gemspec +++ b/zephyr_ruby.gemspec @@ -7,15 +7,17 @@ Gem::Specification.new do |spec| spec.version = ZephyrRuby::VERSION spec.authors = ['Chris Davis'] - spec.summary = 'Zephyr REST API Client for Ruby' - spec.description = "Allows users to use Zephyr's REST API" + spec.summary = 'Zephyr REST API Client and CLI for Ruby' + spec.description = "Allows users to use Zephyr's REST API and provides a command-line interface" spec.license = 'MIT' spec.required_ruby_version = '>= 3.0' spec.homepage = 'https://github.com/cdavis-personal/zephyr_ruby' 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)}) + (f == __FILE__) || + f.match(%r{\A(?:(?:bin|test|spec|features)/|\.(?:git|travis|circleci)|appveyor)}) || + f.end_with?(".gem") end end spec.bindir = 'exe' @@ -25,4 +27,6 @@ Gem::Specification.new do |spec| spec.add_dependency 'faraday', '~> 1.7', '>= 1.7.0' spec.add_dependency 'json', '~> 2.3', '>= 2.3.0' spec.add_dependency 'rspec', '~> 3.7', '>= 3.7.0' + spec.add_dependency 'thor', '~> 1.0' + spec.add_dependency 'nokogiri', '~> 1.12' end