jira-ruby-1.4.3/0000755000004100000410000000000013167661427013470 5ustar www-datawww-datajira-ruby-1.4.3/Rakefile0000644000004100000410000000136013167661427015135 0ustar www-datawww-datarequire 'bundler/gem_tasks' require 'rubygems' require 'rspec/core/rake_task' require 'rdoc/task' Dir.glob('lib/tasks/*.rake').each { |r| import r } task :default => [:test] task :test => [:prepare, :spec] desc 'Prepare and run rspec tests' task :prepare do rsa_key = File.expand_path('rsakey.pem') unless File.exists?(rsa_key) raise 'rsakey.pem does not exist, tests will fail. Run `rake jira:generate_public_cert` first' end end desc 'Run RSpec tests' #RSpec::Core::RakeTask.new(:spec) RSpec::Core::RakeTask.new(:spec) do |task| task.rspec_opts = ['--color', '--format', 'doc'] end Rake::RDocTask.new(:doc) do |rd| rd.main = 'README.rdoc' rd.rdoc_dir = 'doc' rd.rdoc_files.include('README.rdoc', 'lib/**/*.rb') end jira-ruby-1.4.3/Gemfile0000644000004100000410000000024413167661427014763 0ustar www-datawww-datasource "http://rubygems.org" group :development do gem 'wdm', '>= 0.1.0' if Gem.win_platform? end # Specify your gem's dependencies in jira_api.gemspec gemspec jira-ruby-1.4.3/example.rb0000644000004100000410000001517113167661427015455 0ustar www-datawww-datarequire 'pp' require './lib/jira-ruby' CONSUMER_KEY = 'test' SITE = 'https://test.jira.com' options = { :private_key_file => "rsakey.pem", :context_path => '', :consumer_key => CONSUMER_KEY, :site => SITE } client = JIRA::Client.new(options) if ARGV.length == 0 # If not passed any command line arguments, open a browser and prompt the # user for the OAuth verifier. request_token = client.request_token puts "Opening #{request_token.authorize_url}" system "open #{request_token.authorize_url}" puts "Enter the oauth_verifier: " oauth_verifier = gets.strip access_token = client.init_access_token(:oauth_verifier => oauth_verifier) puts "Access token: #{access_token.token} secret: #{access_token.secret}" elsif ARGV.length == 2 # Otherwise assume the arguments are a previous access token and secret. access_token = client.set_access_token(ARGV[0], ARGV[1]) else # Script must be passed 0 or 2 arguments raise "Usage: #{$0} [ token secret ]" end # Show all projects projects = client.Project.all projects.each do |project| puts "Project -> key: #{project.key}, name: #{project.name}" end issue = client.Issue.find('SAMPLEPROJECT-1') pp issue # # Handling fields by name, rather than by id # # ------------------------------------------ # Cache the Field list from the server client.Field.map_fields # This allows use of friendlier names for custom fields # Say that 'Special Field' is customfield_12345 # It becomes mapped to Special_Field which is usable as a method call # # Say that there is a second 'Special Field' is customfield_54321 # Names are deduplicated so the second 'Special Field' becomes Special_Field_54321 # # Names are massaged to get rid of special characters, and spaces # So 'Special & @ Field' becomes Special_____Field - not perfect, but usable old_way = issue.customfield_12345 new_way = issue.Special_Field (old_way == new_way) && puts 'much easier' # # You can also specify fields to be returned in the response # This is especially useful in regards to shortening JQL query response times if performance becomes an issue client.Issue.jql(a_normal_jql_search, fields:[:description, :summary, :Special_field, :created]) # Or you could always do it the old way - if you can remember the custom field numbers... client.Issue.jql(a_normal_jql_search, fields:[:description, :summary, :customfield_1234, :created]) # You can also specify the maximum number of results to be returned in the response, i.e. 500 client.Issue.jql(a_normal_jql_search, max_results: 500) # # Find a specific project by key # # ------------------------------ # project = client.Project.find('SAMPLEPROJECT') # pp project # project.issues.each do |issue| # puts "#{issue.id} - #{issue.fields['summary']}" # end # # # List all Issues # # --------------- # client.Issue.all.each do |issue| # puts "#{issue.id} - #{issue.fields['summary']}" # end # # # List issues by JQL query # # ------------------------ # client.Issue.jql('PROJECT = "SAMPLEPROJECT"', [comments, summary]).each do |issue| # puts "#{issue.id} - #{issue.fields['summary']}" # end # # # Delete an issue # # --------------- # issue = client.Issue.find('SAMPLEPROJECT-2') # if issue.delete # puts "Delete of issue SAMPLEPROJECT-2 sucessful" # else # puts "Delete of issue SAMPLEPROJECT-2 failed" # end # # # Create an issue # # --------------- # issue = client.Issue.build # issue.save({"fields"=>{"summary"=>"blarg from in example.rb","project"=>{"id"=>"10001"},"issuetype"=>{"id"=>"3"}}}) # issue.fetch # pp issue # # # Update an issue # # --------------- # issue = client.Issue.find("10002") # issue.save({"fields"=>{"summary"=>"EVEN MOOOOOOARRR NINJAAAA!"}}) # pp issue # # # Transition an issue # # ------------------- # issue_transition = issue.transitions.build # issue_transition.save!('transition' => {'id' => transition_id}) # # # Change assignee # # ------------------- # issue.save({'fields' => {'assignee' => {'name' => person_name}}}) # # # Find a user # # ----------- # user = client.User.find('admin') # pp user # # # Get all issue watchers # # ---------------------- # issue = client.Issue.find("10002") # watchers = issue.watchers.all # watchers = client.Watcher.all(:issue => issue) # # Get all issue types # # ------------------- # issuetypes = client.Issuetype.all # pp issuetypes # # # Get a single issue type # # ----------------------- # issuetype = client.Issuetype.find('5') # pp issuetype # # # Get all comments for an issue # # ----------------------------- # issue.comments.each do |comment| # pp comment # end # # # Build and Save a comment # # ------------------------ # comment = issue.comments.build # comment.save!(:body => "New comment from example script") # # # Delete a comment from the collection # # ------------------------------------ # issue.comments.last.delete # # # Update an existing comment # # -------------------------- # issue.comments.first.save({"body" => "an updated comment frome example.rb"}) # List all available link types # ------------------------------ pp client.Issuelinktype.all # List issue's links # ------------------------- issue = client.Issue.find("10002") pp issue.issuelinks # Link two issues (on the same Jira instance) # -------------------------------------------- link = client.Issuelink.build link.save( { :type => {:name => 'Relates'}, :inwardIssue => {:key => 'AL-1'}, :outwardIssue => {:key => 'AL-2'} } ) # List issue's remote links # ------------------------- pp issue.remotelink.all # Link two remote issues (on the different Jira instance) # In order to add remote links, you have to add # Application Links between two Jira instances first. # More information: # https://developer.atlassian.com/jiradev/jira-platform/guides/other/guide-jira-remote-issue-links/fields-in-remote-issue-links # http://stackoverflow.com/questions/29850252/jira-api-issuelink-connect-two-different-instances # ------------------------------------------------------- client_1 = JIRA::Client.new(options) client_2 = JIRA::Client.new(options) # you have to search for your app id here, instead of getting the first client_2_app_link = client_2.ApplicationLink.manifest issue_1 = client_1.Issue.find('BB-2') issue_2 = client_2.Issue.find('AA-1') remote_link = issue_2.remotelink.build remote_link.save( { :globalId => "appId=#{client_2_app_link.id}&issueId=#{issue_1.id}", :application => { :type => 'com.atlassian.jira', :name => client_2_app_link['name'] }, :relationship => 'relates to', :object => { :url => client_1.options[:site] + client_1.options[:context_path] + "/browse/#{issue_1.key}", :title => issue_1.key, } } ) jira-ruby-1.4.3/http-basic-example.rb0000644000004100000410000000545613167661427017516 0ustar www-datawww-datarequire 'rubygems' require 'pp' require 'jira-ruby' if ARGV.length == 0 # If not passed any command line arguments, prompt the # user for the username and password. puts "Enter the username: " username = gets.strip puts "Enter the password: " password = gets.strip elsif ARGV.length == 2 username, password = ARGV[0], ARGV[1] else # Script must be passed 0 or 2 arguments raise "Usage: #{$0} [ username password ]" end options = { :username => username, :password => password, :site => 'http://localhost:8080/', :context_path => '', :auth_type => :basic, :use_ssl => false } client = JIRA::Client.new(options) # Show all projects projects = client.Project.all projects.each do |project| puts "Project -> key: #{project.key}, name: #{project.name}" end # # Find a specific project by key # # ------------------------------ # project = client.Project.find('SAMPLEPROJECT') # pp project # project.issues.each do |issue| # puts "#{issue.id} - #{issue.fields['summary']}" # end # # # List all Issues # # --------------- # client.Issue.all.each do |issue| # puts "#{issue.id} - #{issue.fields['summary']}" # end # # # List issues by JQL query # # ------------------------ # client.Issue.jql('PROJECT = "SAMPLEPROJECT"', {fields: %w(summary status)}).each do |issue| # puts "#{issue.id} - #{issue.fields['summary']}" # end # # # Delete an issue # # --------------- # issue = client.Issue.find('SAMPLEPROJECT-2') # if issue.delete # puts "Delete of issue SAMPLEPROJECT-2 sucessful" # else # puts "Delete of issue SAMPLEPROJECT-2 failed" # end # # # Create an issue # # --------------- # issue = client.Issue.build # issue.save({"fields"=>{"summary"=>"blarg from in example.rb","project"=>{"id"=>"10001"},"issuetype"=>{"id"=>"3"}}}) # issue.fetch # pp issue # # # Update an issue # # --------------- # issue = client.Issue.find("10002") # issue.save({"fields"=>{"summary"=>"EVEN MOOOOOOARRR NINJAAAA!"}}) # pp issue # # # Find a user # # ----------- # user = client.User.find('admin') # pp user # # # Get all issue types # # ------------------- # issuetypes = client.Issuetype.all # pp issuetypes # # # Get a single issue type # # ----------------------- # issuetype = client.Issuetype.find('5') # pp issuetype # # # Get all comments for an issue # # ----------------------------- # issue.comments.each do |comment| # pp comment # end # # # Build and Save a comment # # ------------------------ # comment = issue.comments.build # comment.save!(:body => "New comment from example script") # # # Delete a comment from the collection # # ------------------------------------ # issue.comments.last.delete # # # Update an existing comment # # -------------------------- # issue.comments.first.save({"body" => "an updated comment frome example.rb"}) jira-ruby-1.4.3/.ruby-version0000644000004100000410000000000613167661427016131 0ustar www-datawww-data2.3.3 jira-ruby-1.4.3/spec/0000755000004100000410000000000013167661427014422 5ustar www-datawww-datajira-ruby-1.4.3/spec/spec_helper.rb0000644000004100000410000000113713167661427017242 0ustar www-datawww-data$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib')) require 'rubygems' require 'bundler/setup' require 'webmock/rspec' Dir["./spec/support/**/*.rb"].each {|f| require f} require 'jira-ruby' RSpec.configure do |config| config.extend ClientsHelper end def get_mock_response(file, value_if_file_not_found = false) begin file.sub!('?', '_') # we have to replace this character on Windows machine File.read(File.join(File.dirname(__FILE__), 'mock_responses/', file)) rescue Errno::ENOENT => e raise e if value_if_file_not_found == false value_if_file_not_found end end jira-ruby-1.4.3/spec/integration/0000755000004100000410000000000013167661427016745 5ustar www-datawww-datajira-ruby-1.4.3/spec/integration/attachment_spec.rb0000644000004100000410000000150313167661427022433 0ustar www-datawww-datarequire 'spec_helper' describe JIRA::Resource::Attachment do with_each_client do |site_url, client| let(:client) { client } let(:site_url) { site_url } let(:key) { "10000" } let(:target) { JIRA::Resource::Attachment.new(client, :attrs => {'id' => '99999'}, :issue_id => '10002') } let(:expected_attributes) do { 'self' => "http://localhost:2990/jira/rest/api/2/attachment/10000", 'size' => 15360, 'filename' => "ballmer.png" } end let(:belongs_to) { JIRA::Resource::Issue.new(client, :attrs => { 'id' => '10002', 'fields' => { 'attachment' => {'attachments' => []} } }) } it_should_behave_like "a resource with a singular GET endpoint" it_should_behave_like "a resource with a DELETE endpoint" end end jira-ruby-1.4.3/spec/integration/transition_spec.rb0000644000004100000410000000237213167661427022502 0ustar www-datawww-datarequire 'spec_helper' describe JIRA::Resource::Transition do with_each_client do |site_url, client| let(:client) { client } let(:site_url) { site_url } let(:key) { '10000' } let(:target) { JIRA::Resource::Transition.new(client, :attrs => {'id' => '99999'}, :issue_id => '10014') } let(:belongs_to) { JIRA::Resource::Issue.new(client, :attrs => { 'id' => '10002', 'self' => "#{site_url}/jira/rest/api/2/issue/10002", 'fields' => { 'comment' => {'comments' => []} } }) } let(:expected_attributes) do { 'self' => "#{site_url}/jira/rest/api/2/issue/10002/transition/10000", 'id' => key } end let(:attributes_for_post) { { 'transition' => { 'id' => '42' } } } it_should_behave_like "a resource" describe "POST endpoint" do it "saves a new resource" do stub_request(:post, /#{described_class.collection_path(client, prefix)}$/) .with(:body => attributes_for_post.to_json) .to_return(:status => 200, :body => get_mock_from_path(:post)) subject = build_receiver.build expect(subject.save(attributes_for_post)).to be_truthy end end end end jira-ruby-1.4.3/spec/integration/priority_spec.rb0000644000004100000410000000112413167661427022163 0ustar www-datawww-datarequire 'spec_helper' describe JIRA::Resource::Priority do with_each_client do |site_url, client| let(:client) { client } let(:site_url) { site_url } let(:key) { "1" } let(:expected_attributes) do { 'self' => "http://localhost:2990/jira/rest/api/2/priority/1", 'id' => key, 'name' => 'Blocker' } end let(:expected_collection_length) { 5 } it_should_behave_like "a resource" it_should_behave_like "a resource with a collection GET endpoint" it_should_behave_like "a resource with a singular GET endpoint" end end jira-ruby-1.4.3/spec/integration/watcher_spec.rb0000644000004100000410000000307313167661427021744 0ustar www-datawww-datarequire 'spec_helper' describe JIRA::Resource::Watcher do with_each_client do |site_url, client| let(:client) { client } let(:site_url) { site_url } let(:target) { JIRA::Resource::Watcher.new(client, :attrs => {'id' => '99999'}, :issue_id => '10002') } let(:belongs_to) { JIRA::Resource::Issue.new(client, :attrs => { 'id' => '10002', 'fields' => { 'comment' => {'comments' => []} } }) } let(:expected_attributes) do { "self" => "http://localhost:2990/jira/rest/api/2/issue/10002/watchers", "isWatching": false, "watchCount": 1, "watchers": [ { "self": "http://www.example.com/jira/rest/api/2/user?username=admin", "name": "admin", "displayName": "admin", "active": false } ] } end describe "watchers" do it "should returns all the watchers" do stub_request(:get, site_url + "/jira/rest/api/2/issue/10002"). to_return(:status => 200, :body => get_mock_response('issue/10002.json')) stub_request(:get, site_url + "/jira/rest/api/2/issue/10002/watchers"). to_return(:status => 200, :body => get_mock_response('issue/10002/watchers.json')) issue = client.Issue.find("10002") watchers = client.Watcher.all(options = {:issue => issue}) expect(watchers.length).to eq(1) end end it_should_behave_like "a resource" end end jira-ruby-1.4.3/spec/integration/version_spec.rb0000644000004100000410000000213413167661427021771 0ustar www-datawww-datarequire 'spec_helper' describe JIRA::Resource::Version do with_each_client do |site_url, client| let(:client) { client } let(:site_url) { site_url } let(:key) { "10000" } let(:expected_attributes) do { 'self' => "http://localhost:2990/jira/rest/api/2/version/10000", 'id' => key, 'description' => "Initial version" } end let(:attributes_for_post) { {"name" => "2.0", "project" => "SAMPLEPROJECT" } } let(:expected_attributes_from_post) { { "id" => "10001", "name" => "2.0" } } let(:attributes_for_put) { {"name" => "2.0.0" } } let(:expected_attributes_from_put) { { "id" => "10000", "name" => "2.0.0" } } it_should_behave_like "a resource" it_should_behave_like "a resource with a singular GET endpoint" it_should_behave_like "a resource with a DELETE endpoint" it_should_behave_like "a resource with a POST endpoint" it_should_behave_like "a resource with a PUT endpoint" it_should_behave_like "a resource with a PUT endpoint that rejects invalid fields" end end jira-ruby-1.4.3/spec/integration/webhook.rb0000644000004100000410000000200513167661427020725 0ustar www-datawww-datarequire 'spec_helper' describe JIRA::Resource::Webhook do with_each_client do |site_url, client| let(:client) { client } let(:site_url) { site_url } let(:key) { "2" } let(:expected_attributes) do {"name"=>"from API", "url"=>"http://localhost:3000/webhooks/1", "excludeBody"=>false, "filters"=>{"issue-related-events-section"=>""}, "events"=>[], "enabled"=>true, "self"=>"http://localhost:2990/jira/rest/webhooks/1.0/webhook/2", "lastUpdatedUser"=>"admin", "lastUpdatedDisplayName"=>"admin", "lastUpdated"=>1453306520188} end let(:expected_collection_length) { 1 } it_should_behave_like "a resource" it_should_behave_like "a resource with a collection GET endpoint" it_should_behave_like "a resource with a singular GET endpoint" it "returns a collection of components" do stub_request(:get, site_url + described_class.singular_path(client, key)). to_return(:status => 200, :body => get_mock_response('webhook/webhook.json')) end end end jira-ruby-1.4.3/spec/integration/issuetype_spec.rb0000644000004100000410000000112613167661427022336 0ustar www-datawww-datarequire 'spec_helper' describe JIRA::Resource::Issuetype do with_each_client do |site_url, client| let(:client) { client } let(:site_url) { site_url } let(:key) { "5" } let(:expected_attributes) do { 'self' => "http://localhost:2990/jira/rest/api/2/issuetype/5", 'id' => key, 'name' => 'Sub-task' } end let(:expected_collection_length) { 5 } it_should_behave_like "a resource" it_should_behave_like "a resource with a collection GET endpoint" it_should_behave_like "a resource with a singular GET endpoint" end end jira-ruby-1.4.3/spec/integration/field_spec.rb0000644000004100000410000000144113167661427021367 0ustar www-datawww-datarequire 'spec_helper' describe JIRA::Resource::Field do with_each_client do |site_url, client| let(:client) { client } let(:site_url) { site_url } let(:key) { "1" } let(:expected_attributes) do { "id"=>key, "name"=>"Description", "custom"=>false, "orderable"=>true, "navigable"=>true, "searchable"=>true, "clauseNames"=>["description"], "schema"=> { "type"=>"string", "system"=>"description" } } end let(:expected_collection_length) { 2 } it_should_behave_like "a resource" it_should_behave_like "a resource with a collection GET endpoint" it_should_behave_like "a resource with a singular GET endpoint" end end jira-ruby-1.4.3/spec/integration/user_spec.rb0000644000004100000410000000100013167661427021251 0ustar www-datawww-datarequire 'spec_helper' describe JIRA::Resource::User do with_each_client do |site_url, client| let(:client) { client } let(:site_url) { site_url } let(:key) { "admin" } let(:expected_attributes) do { 'self' => "http://localhost:2990/jira/rest/api/2/user?username=admin", 'name' => key, 'emailAddress' => 'admin@example.com' } end it_should_behave_like "a resource" it_should_behave_like "a resource with a singular GET endpoint" end end jira-ruby-1.4.3/spec/integration/comment_spec.rb0000644000004100000410000000265213167661427021753 0ustar www-datawww-datarequire 'spec_helper' describe JIRA::Resource::Comment do with_each_client do |site_url, client| let(:client) { client } let(:site_url) { site_url } let(:key) { "10000" } let(:target) { JIRA::Resource::Comment.new(client, :attrs => {'id' => '99999'}, :issue_id => '54321') } let(:expected_collection_length) { 2 } let(:belongs_to) { JIRA::Resource::Issue.new(client, :attrs => { 'id' => '10002', 'fields' => { 'comment' => {'comments' => []} } }) } let(:expected_attributes) do { 'self' => "http://localhost:2990/jira/rest/api/2/issue/10002/comment/10000", 'id' => key, 'body' => "This is a comment. Creative." } end let(:attributes_for_post) { { "body" => "new comment" } } let(:expected_attributes_from_post) { { "id" => "10001", "body" => "new comment"} } let(:attributes_for_put) { {"body" => "new body"} } let(:expected_attributes_from_put) { { "id" => "10000", "body" => "new body" } } it_should_behave_like "a resource" it_should_behave_like "a resource with a collection GET endpoint" it_should_behave_like "a resource with a singular GET endpoint" it_should_behave_like "a resource with a DELETE endpoint" it_should_behave_like "a resource with a POST endpoint" it_should_behave_like "a resource with a PUT endpoint" end end jira-ruby-1.4.3/spec/integration/project_spec.rb0000644000004100000410000000317413167661427021757 0ustar www-datawww-datarequire 'spec_helper' describe JIRA::Resource::Project do with_each_client do |site_url, client| let(:client) { client } let(:site_url) { site_url } let(:key) { "SAMPLEPROJECT" } let(:expected_attributes) do { 'self' => "http://localhost:2990/jira/rest/api/2/project/SAMPLEPROJECT", 'key' => key, 'name' => "Sample Project for Developing RoR RESTful API" } end let(:expected_collection_length) { 1 } it_should_behave_like "a resource" it_should_behave_like "a resource with a collection GET endpoint" it_should_behave_like "a resource with a singular GET endpoint" describe "issues" do it "returns all the issues" do stub_request(:get, site_url + "/jira/rest/api/2/search?jql=project=\"SAMPLEPROJECT\""). to_return(:status => 200, :body => get_mock_response('project/SAMPLEPROJECT.issues.json')) subject = client.Project.build('key' => key) issues = subject.issues expect(issues.length).to eq(11) issues.each do |issue| expect(issue.class).to eq(JIRA::Resource::Issue) expect(issue.expanded?).to be_falsey end end end it "returns a collection of components" do stub_request(:get, site_url + described_class.singular_path(client, key)). to_return(:status => 200, :body => get_mock_response('project/SAMPLEPROJECT.json')) subject = client.Project.find(key) expect(subject.components.length).to eq(2) subject.components.each do |component| expect(component.class).to eq(JIRA::Resource::Component) end end end end jira-ruby-1.4.3/spec/integration/issue_spec.rb0000644000004100000410000000602313167661427021435 0ustar www-datawww-datarequire 'spec_helper' describe JIRA::Resource::Issue do with_each_client do |site_url, client| let(:client) { client } let(:site_url) { site_url } let(:key) { "10002" } let(:expected_attributes) do { 'self' => "http://localhost:2990/jira/rest/api/2/issue/10002", 'key' => "SAMPLEPROJECT-1", 'expand' => "renderedFields,names,schema,transitions,editmeta,changelog" } end let(:attributes_for_post) { { 'foo' => 'bar' } } let(:expected_attributes_from_post) { { "id" => "10005", "key" => "SAMPLEPROJECT-4" } } let(:attributes_for_put) { { 'foo' => 'bar' } } let(:expected_attributes_from_put) { { 'foo' => 'bar' } } let(:expected_collection_length) { 11 } it_should_behave_like "a resource" it_should_behave_like "a resource with a singular GET endpoint" describe "GET all issues" do # JIRA::Resource::Issue.all uses the search endpoint let(:client) { client } let(:site_url) { site_url } let(:expected_attributes) { { "id"=>"10014", "self"=>"http://localhost:2990/jira/rest/api/2/issue/10014", "key"=>"SAMPLEPROJECT-13" } } before(:each) do stub_request(:get, site_url + "/jira/rest/api/2/search?expand=transitions.fields"). to_return(:status => 200, :body => get_mock_response('issue.json')) end it_should_behave_like "a resource with a collection GET endpoint" end it_should_behave_like "a resource with a DELETE endpoint" it_should_behave_like "a resource with a POST endpoint" it_should_behave_like "a resource with a PUT endpoint" it_should_behave_like "a resource with a PUT endpoint that rejects invalid fields" describe "errors" do before(:each) do stub_request(:get, site_url + "/jira/rest/api/2/issue/10002"). to_return(:status => 200, :body => get_mock_response('issue/10002.json')) stub_request(:put, site_url + "/jira/rest/api/2/issue/10002"). with(:body => '{"missing":"fields and update"}'). to_return(:status => 400, :body => get_mock_response('issue/10002.put.missing_field_update.json')) end it "fails to save when fields and update are missing" do subject = client.Issue.build('id' => '10002') subject.fetch expect(subject.save('missing' => 'fields and update')).to be_falsey end end describe "GET jql issues" do # JIRA::Resource::Issue.jql uses the search endpoint jql_query_string = "PROJECT = 'SAMPLEPROJECT'" let(:client) { client } let(:site_url) { site_url } let(:jql_query_string) { jql_query_string } let(:expected_attributes) { { "id"=>"10014", "self"=>"http://localhost:2990/jira/rest/api/2/issue/10014", "key"=>"SAMPLEPROJECT-13" } } it_should_behave_like "a resource with JQL inputs and a collection GET endpoint" end end end jira-ruby-1.4.3/spec/integration/resolution_spec.rb0000644000004100000410000000140213167661427022504 0ustar www-datawww-datarequire 'spec_helper' describe JIRA::Resource::Resolution do with_each_client do |site_url, client| let(:client) { client } let(:site_url) { site_url } let(:key) { "1" } let(:expected_attributes) do { 'self' => "http://www.example.com/jira/rest/api/2/resolution/1", 'id' => key, 'name' => 'Fixed', 'description' => 'A fix for this issue is checked into the tree and tested.', 'iconUrl' => 'http://www.example.com/jira/images/icons/status_resolved.gif' } end let(:expected_collection_length) { 2 } it_should_behave_like "a resource" it_should_behave_like "a resource with a collection GET endpoint" it_should_behave_like "a resource with a singular GET endpoint" end endjira-ruby-1.4.3/spec/integration/issuelinktype_spec.rb0000644000004100000410000000124113167661427023212 0ustar www-datawww-datarequire 'spec_helper' describe JIRA::Resource::Issuelinktype do with_each_client do |site_url, client| let(:client) { client } let(:site_url) { site_url } let(:key) { "10000" } let(:expected_attributes) do { 'id' => key, "self"=>"http://localhost:2990/jira/rest/api/2/issueLinkType/10000", "name"=>"Blocks", "inward"=>"is blocked by", "outward"=>"blocks" } end let(:expected_collection_length) { 3 } it_should_behave_like "a resource" it_should_behave_like "a resource with a collection GET endpoint" it_should_behave_like "a resource with a singular GET endpoint" end end jira-ruby-1.4.3/spec/integration/rapidview_spec.rb0000644000004100000410000000342313167661427022300 0ustar www-datawww-datarequire 'spec_helper' describe JIRA::Resource::RapidView do with_each_client do |site_url, client| let(:client) { client } let(:site_url) { site_url } let(:key) { '1' } let(:expected_collection_length) { 1 } let(:expected_attributes) { { 'id' => 1, 'name' => 'SAMPLEPROJECT', 'canEdit' => true, 'sprintSupportEnabled' => true } } it_should_behave_like 'a resource' # TODO@Anton: Add json file # it_should_behave_like 'a resource with a singular GET endpoint' describe 'GET all rapidviews' do let(:client) { client } let(:site_url) { site_url } before(:each) do stub_request(:get, site_url + '/jira/rest/greenhopper/1.0/rapidview'). to_return(:status => 200, :body => get_mock_response('rapidview.json')) end it_should_behave_like 'a resource with a collection GET endpoint' end describe 'issues' do it 'should return all the issues' do stub_request( :get, site_url + '/jira/rest/greenhopper/1.0/xboard/plan/backlog/data?rapidViewId=1' ).to_return( :status => 200, :body => get_mock_response('rapidview/SAMPLEPROJECT.issues.json') ) stub_request( :get, site_url + '/jira/rest/api/2/search?jql=id IN(10000, 10001)' ).to_return( :status => 200, :body => get_mock_response('rapidview/SAMPLEPROJECT.issues.full.json') ) subject = client.RapidView.build('id' => 1) issues = subject.issues expect(issues.length).to eq(2) issues.each do |issue| expect(issue.class).to eq(JIRA::Resource::Issue) expect(issue.expanded?).to be_falsey end end end end end jira-ruby-1.4.3/spec/integration/status_spec.rb0000644000004100000410000000111513167661427021625 0ustar www-datawww-datarequire 'spec_helper' describe JIRA::Resource::Status do with_each_client do |site_url, client| let(:client) { client } let(:site_url) { site_url } let(:key) { "1" } let(:expected_attributes) do { 'self' => "http://localhost:2990/jira/rest/api/2/status/1", 'id' => key, 'name' => 'Open' } end let(:expected_collection_length) { 5 } it_should_behave_like "a resource" it_should_behave_like "a resource with a collection GET endpoint" it_should_behave_like "a resource with a singular GET endpoint" end end jira-ruby-1.4.3/spec/integration/component_spec.rb0000644000004100000410000000220713167661427022307 0ustar www-datawww-datarequire 'spec_helper' describe JIRA::Resource::Component do with_each_client do |site_url, client| let(:client) { client } let(:site_url) { site_url } let(:key) { "10000" } let(:expected_attributes) do { 'self' => "http://localhost:2990/jira/rest/api/2/component/10000", 'id' => key, 'name' => "Cheesecake" } end let(:attributes_for_post) { {"name" => "Test component", "project" => "SAMPLEPROJECT" } } let(:expected_attributes_from_post) { { "id" => "10001", "name" => "Test component" } } let(:attributes_for_put) { {"name" => "Jammy", "project" => "SAMPLEPROJECT" } } let(:expected_attributes_from_put) { { "id" => "10000", "name" => "Jammy" } } it_should_behave_like "a resource" it_should_behave_like "a resource with a singular GET endpoint" it_should_behave_like "a resource with a DELETE endpoint" it_should_behave_like "a resource with a POST endpoint" it_should_behave_like "a resource with a PUT endpoint" it_should_behave_like "a resource with a PUT endpoint that rejects invalid fields" end end jira-ruby-1.4.3/spec/integration/worklog_spec.rb0000644000004100000410000000261413167661427021773 0ustar www-datawww-datarequire 'spec_helper' describe JIRA::Resource::Worklog do with_each_client do |site_url, client| let(:client) { client } let(:site_url) { site_url } let(:key) { "10000" } let(:target) { JIRA::Resource::Worklog.new(client, :attrs => {'id' => '99999'}, :issue_id => '54321') } let(:expected_collection_length) { 3 } let(:belongs_to) { JIRA::Resource::Issue.new(client, :attrs => { 'id' => '10002', 'fields' => { 'comment' => {'comments' => []} } }) } let(:expected_attributes) do { 'self' => "http://localhost:2990/jira/rest/api/2/issue/10002/worklog/10000", 'id' => key, 'comment' => "Some epic work." } end let(:attributes_for_post) { {"timeSpent" => "2d"} } let(:expected_attributes_from_post) { { "id" => "10001", "timeSpent" => "2d"} } let(:attributes_for_put) { {"timeSpent" => "2d"} } let(:expected_attributes_from_put) { { "id" => "10001", "timeSpent" => "4d"} } it_should_behave_like "a resource" it_should_behave_like "a resource with a collection GET endpoint" it_should_behave_like "a resource with a singular GET endpoint" it_should_behave_like "a resource with a DELETE endpoint" it_should_behave_like "a resource with a POST endpoint" it_should_behave_like "a resource with a PUT endpoint" end end jira-ruby-1.4.3/spec/mock_responses/0000755000004100000410000000000013167661427017454 5ustar www-datawww-datajira-ruby-1.4.3/spec/mock_responses/user_username=admin.json0000644000004100000410000000074213167661427024335 0ustar www-datawww-data{ "self": "http://localhost:2990/jira/rest/api/2/user?username=admin", "name": "admin", "emailAddress": "admin@example.com", "avatarUrls": { "16x16": "http://localhost:2990/jira/secure/useravatar?size=small&avatarId=10122", "48x48": "http://localhost:2990/jira/secure/useravatar?avatarId=10122" }, "displayName": "admin", "active": true, "timeZone": "Pacific/Auckland", "groups": { "size": 3, "items": [] }, "expand": "groups" }jira-ruby-1.4.3/spec/mock_responses/status.json0000644000004100000410000000277613167661427021706 0ustar www-datawww-data[ { "self": "http://localhost:2990/jira/rest/api/2/status/1", "description": "The issue is open and ready for the assignee to start work on it.", "iconUrl": "http://localhost:2990/jira/images/icons/status_open.gif", "name": "Open", "id": "1" }, { "self": "http://localhost:2990/jira/rest/api/2/status/3", "description": "This issue is being actively worked on at the moment by the assignee.", "iconUrl": "http://localhost:2990/jira/images/icons/status_inprogress.gif", "name": "In Progress", "id": "3" }, { "self": "http://localhost:2990/jira/rest/api/2/status/4", "description": "This issue was once resolved, but the resolution was deemed incorrect. From here issues are either marked assigned or resolved.", "iconUrl": "http://localhost:2990/jira/images/icons/status_reopened.gif", "name": "Reopened", "id": "4" }, { "self": "http://localhost:2990/jira/rest/api/2/status/5", "description": "A resolution has been taken, and it is awaiting verification by reporter. From here issues are either reopened, or are closed.", "iconUrl": "http://localhost:2990/jira/images/icons/status_resolved.gif", "name": "Resolved", "id": "5" }, { "self": "http://localhost:2990/jira/rest/api/2/status/6", "description": "The issue is considered finished, the resolution is correct. Issues which are closed can be reopened.", "iconUrl": "http://localhost:2990/jira/images/icons/status_closed.gif", "name": "Closed", "id": "6" } ] jira-ruby-1.4.3/spec/mock_responses/issue/0000755000004100000410000000000013167661427020604 5ustar www-datawww-datajira-ruby-1.4.3/spec/mock_responses/issue/10002/0000755000004100000410000000000013167661427021246 5ustar www-datawww-datajira-ruby-1.4.3/spec/mock_responses/issue/10002/transitions.json0000644000004100000410000000270013167661427024515 0ustar www-datawww-data{ "expand": "transitions", "transitions": [ { "id": "41", "name": "Review", "to": { "self": "http://localhost:2990/rest/api/2/status/10006", "description": "", "iconUrl": "http://localhost:2990/images/icons/statuses/generic.png", "name": "Reviewable", "id": "10006" } }, { "id": "101", "name": "Stop Progress", "to": { "self": "http://localhost:2990/rest/api/2/status/10017", "description": "Mapping for Accepted in Pivotal Tracker", "iconUrl": "http://localhost:2990/images/icons/statuses/closed.png", "name": "Accepted", "id": "10017" } }, { "id": "21", "name": "Remove from Backlog", "to": { "self": "http://localhost:2990/rest/api/2/status/1", "description": "The issue is open and ready for the assignee to start work on it.", "iconUrl": "http://localhost:2990/images/icons/statuses/open.png", "name": "Open", "id": "1" } }, { "id": "71", "name": "Resolve", "to": { "self": "http://localhost:2990/rest/api/2/status/5", "description": "A resolution has been taken, and it is awaiting verification by reporter. From here issues are either reopened, or are closed.", "iconUrl": "http://localhost:2990/images/icons/statuses/resolved.png", "name": "Resolved", "id": "5" } } ] } jira-ruby-1.4.3/spec/mock_responses/issue/10002/comment/0000755000004100000410000000000013167661427022710 5ustar www-datawww-datajira-ruby-1.4.3/spec/mock_responses/issue/10002/comment/10000.json0000644000004100000410000000177713167661427024257 0ustar www-datawww-data{ "self": "http://localhost:2990/jira/rest/api/2/issue/10002/comment/10000", "id": "10000", "author": { "self": "http://localhost:2990/jira/rest/api/2/user?username=admin", "name": "admin", "emailAddress": "admin@example.com", "avatarUrls": { "16x16": "http://localhost:2990/jira/secure/useravatar?size=small&avatarId=10122", "48x48": "http://localhost:2990/jira/secure/useravatar?avatarId=10122" }, "displayName": "admin", "active": true }, "body": "This is a comment. Creative.", "updateAuthor": { "self": "http://localhost:2990/jira/rest/api/2/user?username=admin", "name": "admin", "emailAddress": "admin@example.com", "avatarUrls": { "16x16": "http://localhost:2990/jira/secure/useravatar?size=small&avatarId=10122", "48x48": "http://localhost:2990/jira/secure/useravatar?avatarId=10122" }, "displayName": "admin", "active": true }, "created": "2012-01-11T10:02:14.430+1300", "updated": "2012-01-11T10:02:14.430+1300" } jira-ruby-1.4.3/spec/mock_responses/issue/10002/comment/10000.put.json0000644000004100000410000000175313167661427025060 0ustar www-datawww-data{ "self": "http://localhost:2990/jira/rest/api/2/issue/10002/comment/10000", "id": "10000", "author": { "self": "http://localhost:2990/jira/rest/api/2/user?username=admin", "name": "admin", "emailAddress": "admin@example.com", "avatarUrls": { "16x16": "http://localhost:2990/jira/secure/useravatar?size=small&avatarId=10122", "48x48": "http://localhost:2990/jira/secure/useravatar?avatarId=10122" }, "displayName": "admin", "active": true }, "body": "new body", "updateAuthor": { "self": "http://localhost:2990/jira/rest/api/2/user?username=admin", "name": "admin", "emailAddress": "admin@example.com", "avatarUrls": { "16x16": "http://localhost:2990/jira/secure/useravatar?size=small&avatarId=10122", "48x48": "http://localhost:2990/jira/secure/useravatar?avatarId=10122" }, "displayName": "admin", "active": true }, "created": "2012-01-11T10:02:14.430+1300", "updated": "2012-01-12T14:37:41.933+1300" } jira-ruby-1.4.3/spec/mock_responses/issue/10002/worklog.json0000644000004100000410000000704013167661427023626 0ustar www-datawww-data{ "startAt": 0, "maxResults": 3, "total": 3, "worklogs": [ { "self": "http://localhost:2990/jira/rest/api/2/issue/10002/worklog/10000", "author": { "self": "http://localhost:2990/jira/rest/api/2/user?username=admin", "name": "admin", "emailAddress": "admin@example.com", "avatarUrls": { "16x16": "http://localhost:2990/jira/secure/useravatar?size=small&avatarId=10122", "48x48": "http://localhost:2990/jira/secure/useravatar?avatarId=10122" }, "displayName": "admin", "active": true }, "updateAuthor": { "self": "http://localhost:2990/jira/rest/api/2/user?username=admin", "name": "admin", "emailAddress": "admin@example.com", "avatarUrls": { "16x16": "http://localhost:2990/jira/secure/useravatar?size=small&avatarId=10122", "48x48": "http://localhost:2990/jira/secure/useravatar?avatarId=10122" }, "displayName": "admin", "active": true }, "comment": "Some epic work.", "created": "2012-01-11T13:33:25.604+1300", "updated": "2012-01-11T13:33:25.604+1300", "started": "2012-01-11T13:33:00.000+1300", "timeSpent": "18w 2d", "id": "10000" }, { "self": "http://localhost:2990/jira/rest/api/2/issue/10002/worklog/10001", "author": { "self": "http://localhost:2990/jira/rest/api/2/user?username=admin", "name": "admin", "emailAddress": "admin@example.com", "avatarUrls": { "16x16": "http://localhost:2990/jira/secure/useravatar?size=small&avatarId=10122", "48x48": "http://localhost:2990/jira/secure/useravatar?avatarId=10122" }, "displayName": "admin", "active": true }, "updateAuthor": { "self": "http://localhost:2990/jira/rest/api/2/user?username=admin", "name": "admin", "emailAddress": "admin@example.com", "avatarUrls": { "16x16": "http://localhost:2990/jira/secure/useravatar?size=small&avatarId=10122", "48x48": "http://localhost:2990/jira/secure/useravatar?avatarId=10122" }, "displayName": "admin", "active": true }, "created": "2012-01-12T16:08:58.529+1300", "updated": "2012-01-12T16:11:22.266+1300", "started": "2012-01-12T16:08:58.529+1300", "timeSpent": "4d", "id": "10001" }, { "self": "http://localhost:2990/jira/rest/api/2/issue/10002/worklog/10002", "author": { "self": "http://localhost:2990/jira/rest/api/2/user?username=admin", "name": "admin", "emailAddress": "admin@example.com", "avatarUrls": { "16x16": "http://localhost:2990/jira/secure/useravatar?size=small&avatarId=10122", "48x48": "http://localhost:2990/jira/secure/useravatar?avatarId=10122" }, "displayName": "admin", "active": true }, "updateAuthor": { "self": "http://localhost:2990/jira/rest/api/2/user?username=admin", "name": "admin", "emailAddress": "admin@example.com", "avatarUrls": { "16x16": "http://localhost:2990/jira/secure/useravatar?size=small&avatarId=10122", "48x48": "http://localhost:2990/jira/secure/useravatar?avatarId=10122" }, "displayName": "admin", "active": true }, "created": "2012-01-12T16:20:39.542+1300", "updated": "2012-01-12T16:20:39.542+1300", "started": "2012-01-12T16:20:39.541+1300", "timeSpent": "3d", "id": "10002" } ] } jira-ruby-1.4.3/spec/mock_responses/issue/10002/transitions.post.json0000644000004100000410000000000113167661427025471 0ustar www-datawww-data jira-ruby-1.4.3/spec/mock_responses/issue/10002/attachments/0000755000004100000410000000000013167661427023561 5ustar www-datawww-datajira-ruby-1.4.3/spec/mock_responses/issue/10002/attachments/10000.json0000644000004100000410000000132613167661427025116 0ustar www-datawww-data{ "self": "http://localhost:2990/jira/rest/api/2/attachment/10000", "filename": "ballmer.png", "author": { "self": "http://localhost:2990/jira/rest/api/2/user?username=admin", "name": "admin", "avatarUrls": { "16x16": "http://localhost:2990/jira/secure/useravatar?size=small&avatarId=10122", "48x48": "http://localhost:2990/jira/secure/useravatar?avatarId=10122" }, "displayName": "admin", "active": true }, "created": "2012-01-11T10:54:50.875+1300", "size": 15360, "mimeType": "image/png", "properties": {}, "content": "http://localhost:2990/jira/secure/attachment/10000/ballmer.png", "thumbnail": "http://localhost:2990/jira/secure/thumbnail/10000/_thumb_10000.png" } jira-ruby-1.4.3/spec/mock_responses/issue/10002/worklog/0000755000004100000410000000000013167661427022732 5ustar www-datawww-datajira-ruby-1.4.3/spec/mock_responses/issue/10002/worklog/10000.json0000644000004100000410000000207313167661427024267 0ustar www-datawww-data{ "self": "http://localhost:2990/jira/rest/api/2/issue/10002/worklog/10000", "author": { "self": "http://localhost:2990/jira/rest/api/2/user?username=admin", "name": "admin", "emailAddress": "admin@example.com", "avatarUrls": { "16x16": "http://localhost:2990/jira/secure/useravatar?size=small&avatarId=10122", "48x48": "http://localhost:2990/jira/secure/useravatar?avatarId=10122" }, "displayName": "admin", "active": true }, "updateAuthor": { "self": "http://localhost:2990/jira/rest/api/2/user?username=admin", "name": "admin", "emailAddress": "admin@example.com", "avatarUrls": { "16x16": "http://localhost:2990/jira/secure/useravatar?size=small&avatarId=10122", "48x48": "http://localhost:2990/jira/secure/useravatar?avatarId=10122" }, "displayName": "admin", "active": true }, "comment": "Some epic work.", "created": "2012-01-11T13:33:25.604+1300", "updated": "2012-01-11T13:33:25.604+1300", "started": "2012-01-11T13:33:00.000+1300", "timeSpent": "18w 2d", "id": "10000" } jira-ruby-1.4.3/spec/mock_responses/issue/10002/worklog/10000.put.json0000644000004100000410000000202713167661427025075 0ustar www-datawww-data{ "self": "http://localhost:2990/jira/rest/api/2/issue/10002/worklog/10001", "author": { "self": "http://localhost:2990/jira/rest/api/2/user?username=admin", "name": "admin", "emailAddress": "admin@example.com", "avatarUrls": { "16x16": "http://localhost:2990/jira/secure/useravatar?size=small&avatarId=10122", "48x48": "http://localhost:2990/jira/secure/useravatar?avatarId=10122" }, "displayName": "admin", "active": true }, "updateAuthor": { "self": "http://localhost:2990/jira/rest/api/2/user?username=admin", "name": "admin", "emailAddress": "admin@example.com", "avatarUrls": { "16x16": "http://localhost:2990/jira/secure/useravatar?size=small&avatarId=10122", "48x48": "http://localhost:2990/jira/secure/useravatar?avatarId=10122" }, "displayName": "admin", "active": true }, "created": "2012-01-12T16:08:58.529+1300", "updated": "2012-01-12T16:11:22.266+1300", "started": "2012-01-12T16:08:58.529+1300", "timeSpent": "4d", "id": "10001" } jira-ruby-1.4.3/spec/mock_responses/issue/10002/comment.post.json0000644000004100000410000000175613167661427024600 0ustar www-datawww-data{ "self": "http://localhost:2990/jira/rest/api/2/issue/10002/comment/10001", "id": "10001", "author": { "self": "http://localhost:2990/jira/rest/api/2/user?username=admin", "name": "admin", "emailAddress": "admin@example.com", "avatarUrls": { "16x16": "http://localhost:2990/jira/secure/useravatar?size=small&avatarId=10122", "48x48": "http://localhost:2990/jira/secure/useravatar?avatarId=10122" }, "displayName": "admin", "active": true }, "body": "new comment", "updateAuthor": { "self": "http://localhost:2990/jira/rest/api/2/user?username=admin", "name": "admin", "emailAddress": "admin@example.com", "avatarUrls": { "16x16": "http://localhost:2990/jira/secure/useravatar?size=small&avatarId=10122", "48x48": "http://localhost:2990/jira/secure/useravatar?avatarId=10122" }, "displayName": "admin", "active": true }, "created": "2012-01-12T14:29:59.209+1300", "updated": "2012-01-12T14:29:59.209+1300" } jira-ruby-1.4.3/spec/mock_responses/issue/10002/watchers.json0000644000004100000410000000052613167661427023764 0ustar www-datawww-data{ "self": "http://localhost:2990/jira/rest/api/2/issue/10002/watchers", "isWatching": false, "watchCount": 1, "watchers": [ { "self": "http://www.example.com/jira/rest/api/2/user?username=admin", "name": "admin", "displayName": "admin", "active": false } ] }jira-ruby-1.4.3/spec/mock_responses/issue/10002/comment.json0000644000004100000410000000443713167661427023613 0ustar www-datawww-data{ "startAt": 0, "maxResults": 2, "total": 2, "comments": [ { "self": "http://localhost:2990/jira/rest/api/2/issue/10002/comment/10000", "id": "10000", "author": { "self": "http://localhost:2990/jira/rest/api/2/user?username=admin", "name": "admin", "emailAddress": "admin@example.com", "avatarUrls": { "16x16": "http://localhost:2990/jira/secure/useravatar?size=small&avatarId=10122", "48x48": "http://localhost:2990/jira/secure/useravatar?avatarId=10122" }, "displayName": "admin", "active": true }, "body": "This is a comment. Creative.", "updateAuthor": { "self": "http://localhost:2990/jira/rest/api/2/user?username=admin", "name": "admin", "emailAddress": "admin@example.com", "avatarUrls": { "16x16": "http://localhost:2990/jira/secure/useravatar?size=small&avatarId=10122", "48x48": "http://localhost:2990/jira/secure/useravatar?avatarId=10122" }, "displayName": "admin", "active": true }, "created": "2012-01-11T10:02:14.430+1300", "updated": "2012-01-12T15:15:13.074+1300" }, { "self": "http://localhost:2990/jira/rest/api/2/issue/10002/comment/10001", "id": "10001", "author": { "self": "http://localhost:2990/jira/rest/api/2/user?username=admin", "name": "admin", "emailAddress": "admin@example.com", "avatarUrls": { "16x16": "http://localhost:2990/jira/secure/useravatar?size=small&avatarId=10122", "48x48": "http://localhost:2990/jira/secure/useravatar?avatarId=10122" }, "displayName": "admin", "active": true }, "body": "new comment", "updateAuthor": { "self": "http://localhost:2990/jira/rest/api/2/user?username=admin", "name": "admin", "emailAddress": "admin@example.com", "avatarUrls": { "16x16": "http://localhost:2990/jira/secure/useravatar?size=small&avatarId=10122", "48x48": "http://localhost:2990/jira/secure/useravatar?avatarId=10122" }, "displayName": "admin", "active": true }, "created": "2012-01-12T14:29:59.209+1300", "updated": "2012-01-12T14:29:59.209+1300" } ] } jira-ruby-1.4.3/spec/mock_responses/issue/10002/worklog.post.json0000644000004100000410000000202713167661427024612 0ustar www-datawww-data{ "self": "http://localhost:2990/jira/rest/api/2/issue/10002/worklog/10001", "author": { "self": "http://localhost:2990/jira/rest/api/2/user?username=admin", "name": "admin", "emailAddress": "admin@example.com", "avatarUrls": { "16x16": "http://localhost:2990/jira/secure/useravatar?size=small&avatarId=10122", "48x48": "http://localhost:2990/jira/secure/useravatar?avatarId=10122" }, "displayName": "admin", "active": true }, "updateAuthor": { "self": "http://localhost:2990/jira/rest/api/2/user?username=admin", "name": "admin", "emailAddress": "admin@example.com", "avatarUrls": { "16x16": "http://localhost:2990/jira/secure/useravatar?size=small&avatarId=10122", "48x48": "http://localhost:2990/jira/secure/useravatar?avatarId=10122" }, "displayName": "admin", "active": true }, "created": "2012-01-12T16:08:58.529+1300", "updated": "2012-01-12T16:08:58.529+1300", "started": "2012-01-12T16:08:58.529+1300", "timeSpent": "2d", "id": "10001" } jira-ruby-1.4.3/spec/mock_responses/issue/10002.invalid.put.json0000644000004100000410000000015713167661427024400 0ustar www-datawww-data{ "errorMessages": [], "errors": { "invalid": "Field 'invalid' is not valid for this operation." } } jira-ruby-1.4.3/spec/mock_responses/issue/10002.put.missing_field_update.json0000644000004100000410000000013013167661427027117 0ustar www-datawww-data{ "errorMessages": [ "one of 'fields' or 'update' required" ], "errors": {} } jira-ruby-1.4.3/spec/mock_responses/issue/10002.json0000644000004100000410000000743713167661427022154 0ustar www-datawww-data{ "expand": "renderedFields,names,schema,transitions,editmeta,changelog", "id": "10002", "self": "http://localhost:2990/jira/rest/api/2/issue/10002", "key": "SAMPLEPROJECT-1", "fields": { "summary": "Sample Issue", "progress": { "progress": 0, "total": 0 }, "timetracking": {}, "issuetype": { "self": "http://localhost:2990/jira/rest/api/2/issuetype/3", "id": "3", "description": "A task that needs to be done.", "iconUrl": "http://localhost:2990/jira/images/icons/task.gif", "name": "Task", "subtask": false }, "votes": { "self": "http://localhost:2990/jira/rest/api/2/issue/SAMPLEPROJECT-1/votes", "votes": 0, "hasVoted": false }, "resolution": null, "fixVersions": [], "resolutiondate": null, "timespent": null, "reporter": { "self": "http://localhost:2990/jira/rest/api/2/user?username=admin", "name": "admin", "emailAddress": "admin@example.com", "avatarUrls": { "16x16": "http://localhost:2990/jira/secure/useravatar?size=small&avatarId=10122", "48x48": "http://localhost:2990/jira/secure/useravatar?avatarId=10122" }, "displayName": "admin", "active": true }, "aggregatetimeoriginalestimate": null, "updated": "2011-12-14T10:26:06.030+1300", "created": "2011-12-14T10:26:06.030+1300", "description": null, "priority": { "self": "http://localhost:2990/jira/rest/api/2/priority/3", "iconUrl": "http://localhost:2990/jira/images/icons/priority_major.gif", "name": "Major", "id": "3" }, "duedate": "2011-12-14", "issuelinks": [], "watches": { "self": "http://localhost:2990/jira/rest/api/2/issue/SAMPLEPROJECT-1/watchers", "watchCount": 0, "isWatching": false }, "worklog": { "startAt": 0, "maxResults": 0, "total": 0, "worklogs": [] }, "subtasks": [], "status": { "self": "http://localhost:2990/jira/rest/api/2/status/1", "description": "The issue is open and ready for the assignee to start work on it.", "iconUrl": "http://localhost:2990/jira/images/icons/status_open.gif", "name": "Open", "id": "1" }, "labels": [], "workratio": -1, "assignee": { "self": "http://localhost:2990/jira/rest/api/2/user?username=admin", "name": "admin", "emailAddress": "admin@example.com", "avatarUrls": { "16x16": "http://localhost:2990/jira/secure/useravatar?size=small&avatarId=10122", "48x48": "http://localhost:2990/jira/secure/useravatar?avatarId=10122" }, "displayName": "admin", "active": true }, "attachment": [], "aggregatetimeestimate": null, "project": { "self": "http://localhost:2990/jira/rest/api/2/project/SAMPLEPROJECT", "id": "10001", "key": "SAMPLEPROJECT", "name": "Sample Project for Developing RoR RESTful API", "avatarUrls": { "16x16": "http://localhost:2990/jira/secure/projectavatar?size=small&pid=10001&avatarId=10011", "48x48": "http://localhost:2990/jira/secure/projectavatar?pid=10001&avatarId=10011" } }, "versions": [], "environment": null, "timeestimate": null, "aggregateprogress": { "progress": 0, "total": 0 }, "components": [ { "self": "http://localhost:2990/jira/rest/api/2/component/10001", "id": "10001", "name": "Jamflam" }, { "self": "http://localhost:2990/jira/rest/api/2/component/10000", "id": "10000", "name": "Jammy", "description": "Description!" } ], "comment": { "startAt": 0, "maxResults": 0, "total": 0, "comments": [] }, "timeoriginalestimate": null, "aggregatetimespent": null } } jira-ruby-1.4.3/spec/mock_responses/component/0000755000004100000410000000000013167661427021456 5ustar www-datawww-datajira-ruby-1.4.3/spec/mock_responses/component/10000.json0000644000004100000410000000244613167661427023017 0ustar www-datawww-data{ "self": "http://localhost:2990/jira/rest/api/2/component/10000", "id": "10000", "name": "Cheesecake", "description": "Description!", "lead": { "self": "http://localhost:2990/jira/rest/api/2/user?username=admin", "name": "admin", "avatarUrls": { "16x16": "http://localhost:2990/jira/secure/useravatar?size=small&avatarId=10122", "48x48": "http://localhost:2990/jira/secure/useravatar?avatarId=10122" }, "displayName": "admin", "active": true }, "assigneeType": "PROJECT_DEFAULT", "assignee": { "self": "http://localhost:2990/jira/rest/api/2/user?username=admin", "name": "admin", "avatarUrls": { "16x16": "http://localhost:2990/jira/secure/useravatar?size=small&avatarId=10122", "48x48": "http://localhost:2990/jira/secure/useravatar?avatarId=10122" }, "displayName": "admin", "active": true }, "realAssigneeType": "PROJECT_DEFAULT", "realAssignee": { "self": "http://localhost:2990/jira/rest/api/2/user?username=admin", "name": "admin", "avatarUrls": { "16x16": "http://localhost:2990/jira/secure/useravatar?size=small&avatarId=10122", "48x48": "http://localhost:2990/jira/secure/useravatar?avatarId=10122" }, "displayName": "admin", "active": true }, "isAssigneeTypeValid": true } jira-ruby-1.4.3/spec/mock_responses/component/10000.put.json0000644000004100000410000000244113167661427023621 0ustar www-datawww-data{ "self": "http://localhost:2990/jira/rest/api/2/component/10000", "id": "10000", "name": "Jammy", "description": "Description!", "lead": { "self": "http://localhost:2990/jira/rest/api/2/user?username=admin", "name": "admin", "avatarUrls": { "16x16": "http://localhost:2990/jira/secure/useravatar?size=small&avatarId=10122", "48x48": "http://localhost:2990/jira/secure/useravatar?avatarId=10122" }, "displayName": "admin", "active": true }, "assigneeType": "PROJECT_DEFAULT", "assignee": { "self": "http://localhost:2990/jira/rest/api/2/user?username=admin", "name": "admin", "avatarUrls": { "16x16": "http://localhost:2990/jira/secure/useravatar?size=small&avatarId=10122", "48x48": "http://localhost:2990/jira/secure/useravatar?avatarId=10122" }, "displayName": "admin", "active": true }, "realAssigneeType": "PROJECT_DEFAULT", "realAssignee": { "self": "http://localhost:2990/jira/rest/api/2/user?username=admin", "name": "admin", "avatarUrls": { "16x16": "http://localhost:2990/jira/secure/useravatar?size=small&avatarId=10122", "48x48": "http://localhost:2990/jira/secure/useravatar?avatarId=10122" }, "displayName": "admin", "active": true }, "isAssigneeTypeValid": true } jira-ruby-1.4.3/spec/mock_responses/component/10000.invalid.put.json0000644000004100000410000000037013167661427025245 0ustar www-datawww-data{ "errorMessages": [ "Unrecognized field \"invalid\" (Class com.atlassian.jira.rest.v2.issue.component.ComponentBean), not marked as ignorable\n at [Source: org.apache.catalina.connector.CoyoteInputStream@70faf7c7; line: 1, column: 2]" ] } jira-ruby-1.4.3/spec/mock_responses/resolution.json0000644000004100000410000000076013167661427022555 0ustar www-datawww-data[ { "self": "http://www.example.com/jira/rest/api/2/resolution/1", "description": "A fix for this issue is checked into the tree and tested.", "iconUrl": "http://www.example.com/jira/images/icons/status_resolved.gif", "name": "Fixed", "id": "1" }, { "self": "http://www.example.com/jira/rest/api/2/resolution/3", "description": "This is what it is supposed to do.", "name": "Works as designed", "id": "3" } ]jira-ruby-1.4.3/spec/mock_responses/version.post.json0000644000004100000410000000022013167661427023012 0ustar www-datawww-data{ "self": "http://localhost:2990/jira/rest/api/2/version/10001", "id": "10001", "name": "2.0", "archived": false, "released": false } jira-ruby-1.4.3/spec/mock_responses/field.json0000644000004100000410000000120613167661427021431 0ustar www-datawww-data[ { "id": "1", "name": "Description", "custom": false, "orderable": true, "navigable": true, "searchable": true, "clauseNames": [ "description" ], "schema": { "type": "string", "system": "description" } }, { "id": "2", "name": "Summary", "custom": false, "orderable": true, "navigable": true, "searchable": true, "clauseNames": [ "summary" ], "schema": { "type": "string", "system": "summary" } } ]jira-ruby-1.4.3/spec/mock_responses/priority.json0000644000004100000410000000267513167661427022242 0ustar www-datawww-data[ { "self": "http://localhost:2990/jira/rest/api/2/priority/1", "statusColor": "#cc0000", "description": "Blocks development and/or testing work, production could not run.", "iconUrl": "http://localhost:2990/jira/images/icons/priority_blocker.gif", "name": "Blocker", "id": "1" }, { "self": "http://localhost:2990/jira/rest/api/2/priority/2", "statusColor": "#ff0000", "description": "Crashes, loss of data, severe memory leak.", "iconUrl": "http://localhost:2990/jira/images/icons/priority_critical.gif", "name": "Critical", "id": "2" }, { "self": "http://localhost:2990/jira/rest/api/2/priority/3", "statusColor": "#009900", "description": "Major loss of function.", "iconUrl": "http://localhost:2990/jira/images/icons/priority_major.gif", "name": "Major", "id": "3" }, { "self": "http://localhost:2990/jira/rest/api/2/priority/4", "statusColor": "#006600", "description": "Minor loss of function, or other problem where easy workaround is present.", "iconUrl": "http://localhost:2990/jira/images/icons/priority_minor.gif", "name": "Minor", "id": "4" }, { "self": "http://localhost:2990/jira/rest/api/2/priority/5", "statusColor": "#003300", "description": "Cosmetic problem like misspelled words or misaligned text", "iconUrl": "http://localhost:2990/jira/images/icons/priority_trivial.gif", "name": "Trivial", "id": "5" } ] jira-ruby-1.4.3/spec/mock_responses/webhook/0000755000004100000410000000000013167661427021112 5ustar www-datawww-datajira-ruby-1.4.3/spec/mock_responses/webhook/webhook.json0000644000004100000410000000052613167661427023446 0ustar www-datawww-data{"name":"from API", "url":"http://localhost:3000/webhooks/1", "excludeBody":false, "filters":{"issue-related-events-section":""}, "events":[], "enabled":true, "self":"http://localhost:2990/jira/rest/webhooks/1.0/webhook/2", "lastUpdatedUser":"admin", "lastUpdatedDisplayName":"admin", "lastUpdated":1453306520188 }jira-ruby-1.4.3/spec/mock_responses/issuetype.json0000644000004100000410000000254413167661427022406 0ustar www-datawww-data[ { "self": "http://localhost:2990/jira/rest/api/2/issuetype/5", "id": "5", "description": "The sub-task of the issue", "iconUrl": "http://localhost:2990/jira/images/icons/issue_subtask.gif", "name": "Sub-task", "subtask": true }, { "self": "http://localhost:2990/jira/rest/api/2/issuetype/4", "id": "4", "description": "An improvement or enhancement to an existing feature or task.", "iconUrl": "http://localhost:2990/jira/images/icons/improvement.gif", "name": "Improvement", "subtask": false }, { "self": "http://localhost:2990/jira/rest/api/2/issuetype/3", "id": "3", "description": "A task that needs to be done.", "iconUrl": "http://localhost:2990/jira/images/icons/task.gif", "name": "Task", "subtask": false }, { "self": "http://localhost:2990/jira/rest/api/2/issuetype/1", "id": "1", "description": "A problem which impairs or prevents the functions of the product.", "iconUrl": "http://localhost:2990/jira/images/icons/bug.gif", "name": "Bug", "subtask": false }, { "self": "http://localhost:2990/jira/rest/api/2/issuetype/2", "id": "2", "description": "A new feature of the product, which has yet to be developed.", "iconUrl": "http://localhost:2990/jira/images/icons/newfeature.gif", "name": "New Feature", "subtask": false } ] jira-ruby-1.4.3/spec/mock_responses/component.post.json0000644000004100000410000000165213167661427023341 0ustar www-datawww-data{ "self": "http://localhost:2990/jira/rest/api/2/component/10001", "id": "10001", "name": "Test component", "assigneeType": "PROJECT_DEFAULT", "assignee": { "self": "http://localhost:2990/jira/rest/api/2/user?username=admin", "name": "admin", "avatarUrls": { "16x16": "http://localhost:2990/jira/secure/useravatar?size=small&avatarId=10122", "48x48": "http://localhost:2990/jira/secure/useravatar?avatarId=10122" }, "displayName": "admin", "active": true }, "realAssigneeType": "PROJECT_DEFAULT", "realAssignee": { "self": "http://localhost:2990/jira/rest/api/2/user?username=admin", "name": "admin", "avatarUrls": { "16x16": "http://localhost:2990/jira/secure/useravatar?size=small&avatarId=10122", "48x48": "http://localhost:2990/jira/secure/useravatar?avatarId=10122" }, "displayName": "admin", "active": true }, "isAssigneeTypeValid": true } jira-ruby-1.4.3/spec/mock_responses/status/0000755000004100000410000000000013167661427020777 5ustar www-datawww-datajira-ruby-1.4.3/spec/mock_responses/status/1.json0000644000004100000410000000037413167661427022036 0ustar www-datawww-data{ "self": "http://localhost:2990/jira/rest/api/2/status/1", "description": "The issue is open and ready for the assignee to start work on it.", "iconUrl": "http://localhost:2990/jira/images/icons/status_open.gif", "name": "Open", "id": "1" } jira-ruby-1.4.3/spec/mock_responses/issueLinkType.json0000644000004100000410000000114613167661427023161 0ustar www-datawww-data{ "issueLinkTypes": [ { "id": "10000", "name": "Blocks", "inward": "is blocked by", "outward": "blocks", "self": "http://localhost:2990/jira/rest/api/2/issueLinkType/10000" }, { "id": "10400", "name": "Cloners", "inward": "is cloned by", "outward": "clones", "self": "http://localhost:2990/jira/rest/api/2/issueLinkType/10400" }, { "id": "10401", "name": "Duplicate", "inward": "is duplicated by", "outward": "duplicates", "self": "http://localhost:2990/jira/rest/api/2/issueLinkType/10401" } ] }jira-ruby-1.4.3/spec/mock_responses/issue.json0000644000004100000410000011725713167661427021514 0ustar www-datawww-data{ "expand": "schema,names", "startAt": 0, "maxResults": 50, "total": 11, "issues": [ { "expand": "editmeta,renderedFields,transitions,changelog", "id": "10014", "self": "http://localhost:2990/jira/rest/api/2/issue/10014", "key": "SAMPLEPROJECT-13", "fields": { "summary": "blarg from in example.rb", "progress": { "progress": 0, "total": 0 }, "issuetype": { "self": "http://localhost:2990/jira/rest/api/2/issuetype/3", "id": "3", "description": "A task that needs to be done.", "iconUrl": "http://localhost:2990/jira/images/icons/task.gif", "name": "Task", "subtask": false }, "votes": { "self": "http://localhost:2990/jira/rest/api/2/issue/SAMPLEPROJECT-13/votes", "votes": 0, "hasVoted": false }, "resolution": null, "fixVersions": [], "resolutiondate": null, "timespent": null, "reporter": { "self": "http://localhost:2990/jira/rest/api/2/user?username=admin", "name": "admin", "emailAddress": "admin@example.com", "avatarUrls": { "16x16": "http://localhost:2990/jira/secure/useravatar?size=small&avatarId=10122", "48x48": "http://localhost:2990/jira/secure/useravatar?avatarId=10122" }, "displayName": "admin", "active": true }, "aggregatetimeoriginalestimate": null, "updated": "2011-12-15T15:35:06.000+1300", "created": "2011-12-15T15:35:06.000+1300", "description": null, "priority": { "self": "http://localhost:2990/jira/rest/api/2/priority/3", "iconUrl": "http://localhost:2990/jira/images/icons/priority_major.gif", "name": "Major", "id": "3" }, "duedate": null, "issuelinks": [], "watches": { "self": "http://localhost:2990/jira/rest/api/2/issue/SAMPLEPROJECT-13/watchers", "watchCount": 0, "isWatching": false }, "subtasks": [], "status": { "self": "http://localhost:2990/jira/rest/api/2/status/1", "description": "The issue is open and ready for the assignee to start work on it.", "iconUrl": "http://localhost:2990/jira/images/icons/status_open.gif", "name": "Open", "id": "1" }, "labels": [], "assignee": { "self": "http://localhost:2990/jira/rest/api/2/user?username=admin", "name": "admin", "emailAddress": "admin@example.com", "avatarUrls": { "16x16": "http://localhost:2990/jira/secure/useravatar?size=small&avatarId=10122", "48x48": "http://localhost:2990/jira/secure/useravatar?avatarId=10122" }, "displayName": "admin", "active": true }, "workratio": -1, "aggregatetimeestimate": null, "project": { "self": "http://localhost:2990/jira/rest/api/2/project/SAMPLEPROJECT", "id": "10001", "key": "SAMPLEPROJECT", "name": "Sample Project for Developing RoR RESTful API", "avatarUrls": { "16x16": "http://localhost:2990/jira/secure/projectavatar?size=small&pid=10001&avatarId=10011", "48x48": "http://localhost:2990/jira/secure/projectavatar?pid=10001&avatarId=10011" } }, "versions": [], "environment": null, "timeestimate": null, "aggregateprogress": { "progress": 0, "total": 0 }, "components": [], "timeoriginalestimate": null, "aggregatetimespent": null } }, { "expand": "editmeta,renderedFields,transitions,changelog", "id": "10013", "self": "http://localhost:2990/jira/rest/api/2/issue/10013", "key": "SAMPLEPROJECT-12", "fields": { "summary": "blarg from in example.rb", "progress": { "progress": 0, "total": 0 }, "issuetype": { "self": "http://localhost:2990/jira/rest/api/2/issuetype/3", "id": "3", "description": "A task that needs to be done.", "iconUrl": "http://localhost:2990/jira/images/icons/task.gif", "name": "Task", "subtask": false }, "votes": { "self": "http://localhost:2990/jira/rest/api/2/issue/SAMPLEPROJECT-12/votes", "votes": 0, "hasVoted": false }, "resolution": null, "fixVersions": [], "resolutiondate": null, "timespent": null, "reporter": { "self": "http://localhost:2990/jira/rest/api/2/user?username=admin", "name": "admin", "emailAddress": "admin@example.com", "avatarUrls": { "16x16": "http://localhost:2990/jira/secure/useravatar?size=small&avatarId=10122", "48x48": "http://localhost:2990/jira/secure/useravatar?avatarId=10122" }, "displayName": "admin", "active": true }, "aggregatetimeoriginalestimate": null, "updated": "2011-12-15T15:34:58.000+1300", "created": "2011-12-15T15:34:58.000+1300", "description": null, "priority": { "self": "http://localhost:2990/jira/rest/api/2/priority/3", "iconUrl": "http://localhost:2990/jira/images/icons/priority_major.gif", "name": "Major", "id": "3" }, "duedate": null, "issuelinks": [], "watches": { "self": "http://localhost:2990/jira/rest/api/2/issue/SAMPLEPROJECT-12/watchers", "watchCount": 0, "isWatching": false }, "subtasks": [], "status": { "self": "http://localhost:2990/jira/rest/api/2/status/1", "description": "The issue is open and ready for the assignee to start work on it.", "iconUrl": "http://localhost:2990/jira/images/icons/status_open.gif", "name": "Open", "id": "1" }, "labels": [], "assignee": { "self": "http://localhost:2990/jira/rest/api/2/user?username=admin", "name": "admin", "emailAddress": "admin@example.com", "avatarUrls": { "16x16": "http://localhost:2990/jira/secure/useravatar?size=small&avatarId=10122", "48x48": "http://localhost:2990/jira/secure/useravatar?avatarId=10122" }, "displayName": "admin", "active": true }, "workratio": -1, "aggregatetimeestimate": null, "project": { "self": "http://localhost:2990/jira/rest/api/2/project/SAMPLEPROJECT", "id": "10001", "key": "SAMPLEPROJECT", "name": "Sample Project for Developing RoR RESTful API", "avatarUrls": { "16x16": "http://localhost:2990/jira/secure/projectavatar?size=small&pid=10001&avatarId=10011", "48x48": "http://localhost:2990/jira/secure/projectavatar?pid=10001&avatarId=10011" } }, "versions": [], "environment": null, "timeestimate": null, "aggregateprogress": { "progress": 0, "total": 0 }, "components": [], "timeoriginalestimate": null, "aggregatetimespent": null } }, { "expand": "editmeta,renderedFields,transitions,changelog", "id": "10012", "self": "http://localhost:2990/jira/rest/api/2/issue/10012", "key": "SAMPLEPROJECT-11", "fields": { "summary": "blarg from in example.rb", "progress": { "progress": 0, "total": 0 }, "issuetype": { "self": "http://localhost:2990/jira/rest/api/2/issuetype/3", "id": "3", "description": "A task that needs to be done.", "iconUrl": "http://localhost:2990/jira/images/icons/task.gif", "name": "Task", "subtask": false }, "votes": { "self": "http://localhost:2990/jira/rest/api/2/issue/SAMPLEPROJECT-11/votes", "votes": 0, "hasVoted": false }, "resolution": null, "fixVersions": [], "resolutiondate": null, "timespent": null, "reporter": { "self": "http://localhost:2990/jira/rest/api/2/user?username=admin", "name": "admin", "emailAddress": "admin@example.com", "avatarUrls": { "16x16": "http://localhost:2990/jira/secure/useravatar?size=small&avatarId=10122", "48x48": "http://localhost:2990/jira/secure/useravatar?avatarId=10122" }, "displayName": "admin", "active": true }, "aggregatetimeoriginalestimate": null, "updated": "2011-12-15T15:34:48.000+1300", "created": "2011-12-15T15:34:48.000+1300", "description": null, "priority": { "self": "http://localhost:2990/jira/rest/api/2/priority/3", "iconUrl": "http://localhost:2990/jira/images/icons/priority_major.gif", "name": "Major", "id": "3" }, "duedate": null, "issuelinks": [], "watches": { "self": "http://localhost:2990/jira/rest/api/2/issue/SAMPLEPROJECT-11/watchers", "watchCount": 0, "isWatching": false }, "subtasks": [], "status": { "self": "http://localhost:2990/jira/rest/api/2/status/1", "description": "The issue is open and ready for the assignee to start work on it.", "iconUrl": "http://localhost:2990/jira/images/icons/status_open.gif", "name": "Open", "id": "1" }, "labels": [], "assignee": { "self": "http://localhost:2990/jira/rest/api/2/user?username=admin", "name": "admin", "emailAddress": "admin@example.com", "avatarUrls": { "16x16": "http://localhost:2990/jira/secure/useravatar?size=small&avatarId=10122", "48x48": "http://localhost:2990/jira/secure/useravatar?avatarId=10122" }, "displayName": "admin", "active": true }, "workratio": -1, "aggregatetimeestimate": null, "project": { "self": "http://localhost:2990/jira/rest/api/2/project/SAMPLEPROJECT", "id": "10001", "key": "SAMPLEPROJECT", "name": "Sample Project for Developing RoR RESTful API", "avatarUrls": { "16x16": "http://localhost:2990/jira/secure/projectavatar?size=small&pid=10001&avatarId=10011", "48x48": "http://localhost:2990/jira/secure/projectavatar?pid=10001&avatarId=10011" } }, "versions": [], "environment": null, "timeestimate": null, "aggregateprogress": { "progress": 0, "total": 0 }, "components": [], "timeoriginalestimate": null, "aggregatetimespent": null } }, { "expand": "editmeta,renderedFields,transitions,changelog", "id": "10011", "self": "http://localhost:2990/jira/rest/api/2/issue/10011", "key": "SAMPLEPROJECT-10", "fields": { "summary": "blarg from in example.rb", "progress": { "progress": 0, "total": 0 }, "issuetype": { "self": "http://localhost:2990/jira/rest/api/2/issuetype/3", "id": "3", "description": "A task that needs to be done.", "iconUrl": "http://localhost:2990/jira/images/icons/task.gif", "name": "Task", "subtask": false }, "votes": { "self": "http://localhost:2990/jira/rest/api/2/issue/SAMPLEPROJECT-10/votes", "votes": 0, "hasVoted": false }, "resolution": null, "fixVersions": [], "resolutiondate": null, "timespent": null, "reporter": { "self": "http://localhost:2990/jira/rest/api/2/user?username=admin", "name": "admin", "emailAddress": "admin@example.com", "avatarUrls": { "16x16": "http://localhost:2990/jira/secure/useravatar?size=small&avatarId=10122", "48x48": "http://localhost:2990/jira/secure/useravatar?avatarId=10122" }, "displayName": "admin", "active": true }, "aggregatetimeoriginalestimate": null, "updated": "2011-12-15T15:11:57.000+1300", "created": "2011-12-15T15:11:57.000+1300", "description": null, "priority": { "self": "http://localhost:2990/jira/rest/api/2/priority/3", "iconUrl": "http://localhost:2990/jira/images/icons/priority_major.gif", "name": "Major", "id": "3" }, "duedate": null, "issuelinks": [], "watches": { "self": "http://localhost:2990/jira/rest/api/2/issue/SAMPLEPROJECT-10/watchers", "watchCount": 0, "isWatching": false }, "subtasks": [], "status": { "self": "http://localhost:2990/jira/rest/api/2/status/1", "description": "The issue is open and ready for the assignee to start work on it.", "iconUrl": "http://localhost:2990/jira/images/icons/status_open.gif", "name": "Open", "id": "1" }, "labels": [], "assignee": { "self": "http://localhost:2990/jira/rest/api/2/user?username=admin", "name": "admin", "emailAddress": "admin@example.com", "avatarUrls": { "16x16": "http://localhost:2990/jira/secure/useravatar?size=small&avatarId=10122", "48x48": "http://localhost:2990/jira/secure/useravatar?avatarId=10122" }, "displayName": "admin", "active": true }, "workratio": -1, "aggregatetimeestimate": null, "project": { "self": "http://localhost:2990/jira/rest/api/2/project/SAMPLEPROJECT", "id": "10001", "key": "SAMPLEPROJECT", "name": "Sample Project for Developing RoR RESTful API", "avatarUrls": { "16x16": "http://localhost:2990/jira/secure/projectavatar?size=small&pid=10001&avatarId=10011", "48x48": "http://localhost:2990/jira/secure/projectavatar?pid=10001&avatarId=10011" } }, "versions": [], "environment": null, "timeestimate": null, "aggregateprogress": { "progress": 0, "total": 0 }, "components": [], "timeoriginalestimate": null, "aggregatetimespent": null } }, { "expand": "editmeta,renderedFields,transitions,changelog", "id": "10010", "self": "http://localhost:2990/jira/rest/api/2/issue/10010", "key": "SAMPLEPROJECT-9", "fields": { "summary": "blarg from in example.rb", "progress": { "progress": 0, "total": 0 }, "issuetype": { "self": "http://localhost:2990/jira/rest/api/2/issuetype/3", "id": "3", "description": "A task that needs to be done.", "iconUrl": "http://localhost:2990/jira/images/icons/task.gif", "name": "Task", "subtask": false }, "votes": { "self": "http://localhost:2990/jira/rest/api/2/issue/SAMPLEPROJECT-9/votes", "votes": 0, "hasVoted": false }, "resolution": null, "fixVersions": [], "resolutiondate": null, "timespent": null, "reporter": { "self": "http://localhost:2990/jira/rest/api/2/user?username=admin", "name": "admin", "emailAddress": "admin@example.com", "avatarUrls": { "16x16": "http://localhost:2990/jira/secure/useravatar?size=small&avatarId=10122", "48x48": "http://localhost:2990/jira/secure/useravatar?avatarId=10122" }, "displayName": "admin", "active": true }, "aggregatetimeoriginalestimate": null, "updated": "2011-12-15T15:11:45.000+1300", "created": "2011-12-15T15:11:45.000+1300", "description": null, "priority": { "self": "http://localhost:2990/jira/rest/api/2/priority/3", "iconUrl": "http://localhost:2990/jira/images/icons/priority_major.gif", "name": "Major", "id": "3" }, "duedate": null, "issuelinks": [], "watches": { "self": "http://localhost:2990/jira/rest/api/2/issue/SAMPLEPROJECT-9/watchers", "watchCount": 0, "isWatching": false }, "subtasks": [], "status": { "self": "http://localhost:2990/jira/rest/api/2/status/1", "description": "The issue is open and ready for the assignee to start work on it.", "iconUrl": "http://localhost:2990/jira/images/icons/status_open.gif", "name": "Open", "id": "1" }, "labels": [], "assignee": { "self": "http://localhost:2990/jira/rest/api/2/user?username=admin", "name": "admin", "emailAddress": "admin@example.com", "avatarUrls": { "16x16": "http://localhost:2990/jira/secure/useravatar?size=small&avatarId=10122", "48x48": "http://localhost:2990/jira/secure/useravatar?avatarId=10122" }, "displayName": "admin", "active": true }, "workratio": -1, "aggregatetimeestimate": null, "project": { "self": "http://localhost:2990/jira/rest/api/2/project/SAMPLEPROJECT", "id": "10001", "key": "SAMPLEPROJECT", "name": "Sample Project for Developing RoR RESTful API", "avatarUrls": { "16x16": "http://localhost:2990/jira/secure/projectavatar?size=small&pid=10001&avatarId=10011", "48x48": "http://localhost:2990/jira/secure/projectavatar?pid=10001&avatarId=10011" } }, "versions": [], "environment": null, "timeestimate": null, "aggregateprogress": { "progress": 0, "total": 0 }, "components": [], "timeoriginalestimate": null, "aggregatetimespent": null } }, { "expand": "editmeta,renderedFields,transitions,changelog", "id": "10009", "self": "http://localhost:2990/jira/rest/api/2/issue/10009", "key": "SAMPLEPROJECT-8", "fields": { "summary": "blarg from in example.rb", "progress": { "progress": 0, "total": 0 }, "issuetype": { "self": "http://localhost:2990/jira/rest/api/2/issuetype/3", "id": "3", "description": "A task that needs to be done.", "iconUrl": "http://localhost:2990/jira/images/icons/task.gif", "name": "Task", "subtask": false }, "votes": { "self": "http://localhost:2990/jira/rest/api/2/issue/SAMPLEPROJECT-8/votes", "votes": 0, "hasVoted": false }, "resolution": null, "fixVersions": [], "resolutiondate": null, "timespent": null, "reporter": { "self": "http://localhost:2990/jira/rest/api/2/user?username=admin", "name": "admin", "emailAddress": "admin@example.com", "avatarUrls": { "16x16": "http://localhost:2990/jira/secure/useravatar?size=small&avatarId=10122", "48x48": "http://localhost:2990/jira/secure/useravatar?avatarId=10122" }, "displayName": "admin", "active": true }, "aggregatetimeoriginalestimate": null, "updated": "2011-12-15T14:19:49.000+1300", "created": "2011-12-15T14:19:49.000+1300", "description": null, "priority": { "self": "http://localhost:2990/jira/rest/api/2/priority/3", "iconUrl": "http://localhost:2990/jira/images/icons/priority_major.gif", "name": "Major", "id": "3" }, "duedate": null, "issuelinks": [], "watches": { "self": "http://localhost:2990/jira/rest/api/2/issue/SAMPLEPROJECT-8/watchers", "watchCount": 0, "isWatching": false }, "subtasks": [], "status": { "self": "http://localhost:2990/jira/rest/api/2/status/1", "description": "The issue is open and ready for the assignee to start work on it.", "iconUrl": "http://localhost:2990/jira/images/icons/status_open.gif", "name": "Open", "id": "1" }, "labels": [], "assignee": { "self": "http://localhost:2990/jira/rest/api/2/user?username=admin", "name": "admin", "emailAddress": "admin@example.com", "avatarUrls": { "16x16": "http://localhost:2990/jira/secure/useravatar?size=small&avatarId=10122", "48x48": "http://localhost:2990/jira/secure/useravatar?avatarId=10122" }, "displayName": "admin", "active": true }, "workratio": -1, "aggregatetimeestimate": null, "project": { "self": "http://localhost:2990/jira/rest/api/2/project/SAMPLEPROJECT", "id": "10001", "key": "SAMPLEPROJECT", "name": "Sample Project for Developing RoR RESTful API", "avatarUrls": { "16x16": "http://localhost:2990/jira/secure/projectavatar?size=small&pid=10001&avatarId=10011", "48x48": "http://localhost:2990/jira/secure/projectavatar?pid=10001&avatarId=10011" } }, "versions": [], "environment": null, "timeestimate": null, "aggregateprogress": { "progress": 0, "total": 0 }, "components": [], "timeoriginalestimate": null, "aggregatetimespent": null } }, { "expand": "editmeta,renderedFields,transitions,changelog", "id": "10008", "self": "http://localhost:2990/jira/rest/api/2/issue/10008", "key": "SAMPLEPROJECT-7", "fields": { "summary": "blarg from in example.rb", "progress": { "progress": 0, "total": 0 }, "issuetype": { "self": "http://localhost:2990/jira/rest/api/2/issuetype/3", "id": "3", "description": "A task that needs to be done.", "iconUrl": "http://localhost:2990/jira/images/icons/task.gif", "name": "Task", "subtask": false }, "votes": { "self": "http://localhost:2990/jira/rest/api/2/issue/SAMPLEPROJECT-7/votes", "votes": 0, "hasVoted": false }, "resolution": null, "fixVersions": [], "resolutiondate": null, "timespent": null, "reporter": { "self": "http://localhost:2990/jira/rest/api/2/user?username=admin", "name": "admin", "emailAddress": "admin@example.com", "avatarUrls": { "16x16": "http://localhost:2990/jira/secure/useravatar?size=small&avatarId=10122", "48x48": "http://localhost:2990/jira/secure/useravatar?avatarId=10122" }, "displayName": "admin", "active": true }, "aggregatetimeoriginalestimate": null, "updated": "2011-12-14T14:50:38.000+1300", "created": "2011-12-14T14:50:38.000+1300", "description": null, "priority": { "self": "http://localhost:2990/jira/rest/api/2/priority/3", "iconUrl": "http://localhost:2990/jira/images/icons/priority_major.gif", "name": "Major", "id": "3" }, "duedate": null, "issuelinks": [], "watches": { "self": "http://localhost:2990/jira/rest/api/2/issue/SAMPLEPROJECT-7/watchers", "watchCount": 0, "isWatching": false }, "subtasks": [], "status": { "self": "http://localhost:2990/jira/rest/api/2/status/1", "description": "The issue is open and ready for the assignee to start work on it.", "iconUrl": "http://localhost:2990/jira/images/icons/status_open.gif", "name": "Open", "id": "1" }, "labels": [], "assignee": { "self": "http://localhost:2990/jira/rest/api/2/user?username=admin", "name": "admin", "emailAddress": "admin@example.com", "avatarUrls": { "16x16": "http://localhost:2990/jira/secure/useravatar?size=small&avatarId=10122", "48x48": "http://localhost:2990/jira/secure/useravatar?avatarId=10122" }, "displayName": "admin", "active": true }, "workratio": -1, "aggregatetimeestimate": null, "project": { "self": "http://localhost:2990/jira/rest/api/2/project/SAMPLEPROJECT", "id": "10001", "key": "SAMPLEPROJECT", "name": "Sample Project for Developing RoR RESTful API", "avatarUrls": { "16x16": "http://localhost:2990/jira/secure/projectavatar?size=small&pid=10001&avatarId=10011", "48x48": "http://localhost:2990/jira/secure/projectavatar?pid=10001&avatarId=10011" } }, "versions": [], "environment": null, "timeestimate": null, "aggregateprogress": { "progress": 0, "total": 0 }, "components": [], "timeoriginalestimate": null, "aggregatetimespent": null } }, { "expand": "editmeta,renderedFields,transitions,changelog", "id": "10007", "self": "http://localhost:2990/jira/rest/api/2/issue/10007", "key": "SAMPLEPROJECT-6", "fields": { "summary": "blarg from in example.rb", "progress": { "progress": 0, "total": 0 }, "issuetype": { "self": "http://localhost:2990/jira/rest/api/2/issuetype/3", "id": "3", "description": "A task that needs to be done.", "iconUrl": "http://localhost:2990/jira/images/icons/task.gif", "name": "Task", "subtask": false }, "votes": { "self": "http://localhost:2990/jira/rest/api/2/issue/SAMPLEPROJECT-6/votes", "votes": 0, "hasVoted": false }, "resolution": null, "fixVersions": [], "resolutiondate": null, "timespent": null, "reporter": { "self": "http://localhost:2990/jira/rest/api/2/user?username=admin", "name": "admin", "emailAddress": "admin@example.com", "avatarUrls": { "16x16": "http://localhost:2990/jira/secure/useravatar?size=small&avatarId=10122", "48x48": "http://localhost:2990/jira/secure/useravatar?avatarId=10122" }, "displayName": "admin", "active": true }, "aggregatetimeoriginalestimate": null, "updated": "2011-12-14T14:49:35.000+1300", "created": "2011-12-14T14:49:35.000+1300", "description": null, "priority": { "self": "http://localhost:2990/jira/rest/api/2/priority/3", "iconUrl": "http://localhost:2990/jira/images/icons/priority_major.gif", "name": "Major", "id": "3" }, "duedate": null, "issuelinks": [], "watches": { "self": "http://localhost:2990/jira/rest/api/2/issue/SAMPLEPROJECT-6/watchers", "watchCount": 0, "isWatching": false }, "subtasks": [], "status": { "self": "http://localhost:2990/jira/rest/api/2/status/1", "description": "The issue is open and ready for the assignee to start work on it.", "iconUrl": "http://localhost:2990/jira/images/icons/status_open.gif", "name": "Open", "id": "1" }, "labels": [], "assignee": { "self": "http://localhost:2990/jira/rest/api/2/user?username=admin", "name": "admin", "emailAddress": "admin@example.com", "avatarUrls": { "16x16": "http://localhost:2990/jira/secure/useravatar?size=small&avatarId=10122", "48x48": "http://localhost:2990/jira/secure/useravatar?avatarId=10122" }, "displayName": "admin", "active": true }, "workratio": -1, "aggregatetimeestimate": null, "project": { "self": "http://localhost:2990/jira/rest/api/2/project/SAMPLEPROJECT", "id": "10001", "key": "SAMPLEPROJECT", "name": "Sample Project for Developing RoR RESTful API", "avatarUrls": { "16x16": "http://localhost:2990/jira/secure/projectavatar?size=small&pid=10001&avatarId=10011", "48x48": "http://localhost:2990/jira/secure/projectavatar?pid=10001&avatarId=10011" } }, "versions": [], "environment": null, "timeestimate": null, "aggregateprogress": { "progress": 0, "total": 0 }, "components": [], "timeoriginalestimate": null, "aggregatetimespent": null } }, { "expand": "editmeta,renderedFields,transitions,changelog", "id": "10006", "self": "http://localhost:2990/jira/rest/api/2/issue/10006", "key": "SAMPLEPROJECT-5", "fields": { "summary": "blah", "progress": { "progress": 0, "total": 0 }, "issuetype": { "self": "http://localhost:2990/jira/rest/api/2/issuetype/3", "id": "3", "description": "A task that needs to be done.", "iconUrl": "http://localhost:2990/jira/images/icons/task.gif", "name": "Task", "subtask": false }, "votes": { "self": "http://localhost:2990/jira/rest/api/2/issue/SAMPLEPROJECT-5/votes", "votes": 0, "hasVoted": false }, "resolution": null, "fixVersions": [], "resolutiondate": null, "timespent": null, "reporter": { "self": "http://localhost:2990/jira/rest/api/2/user?username=admin", "name": "admin", "emailAddress": "admin@example.com", "avatarUrls": { "16x16": "http://localhost:2990/jira/secure/useravatar?size=small&avatarId=10122", "48x48": "http://localhost:2990/jira/secure/useravatar?avatarId=10122" }, "displayName": "admin", "active": true }, "aggregatetimeoriginalestimate": null, "updated": "2011-12-14T14:46:58.000+1300", "created": "2011-12-14T14:46:58.000+1300", "description": null, "priority": { "self": "http://localhost:2990/jira/rest/api/2/priority/3", "iconUrl": "http://localhost:2990/jira/images/icons/priority_major.gif", "name": "Major", "id": "3" }, "duedate": null, "issuelinks": [], "watches": { "self": "http://localhost:2990/jira/rest/api/2/issue/SAMPLEPROJECT-5/watchers", "watchCount": 0, "isWatching": false }, "subtasks": [], "status": { "self": "http://localhost:2990/jira/rest/api/2/status/1", "description": "The issue is open and ready for the assignee to start work on it.", "iconUrl": "http://localhost:2990/jira/images/icons/status_open.gif", "name": "Open", "id": "1" }, "labels": [], "assignee": { "self": "http://localhost:2990/jira/rest/api/2/user?username=admin", "name": "admin", "emailAddress": "admin@example.com", "avatarUrls": { "16x16": "http://localhost:2990/jira/secure/useravatar?size=small&avatarId=10122", "48x48": "http://localhost:2990/jira/secure/useravatar?avatarId=10122" }, "displayName": "admin", "active": true }, "workratio": -1, "aggregatetimeestimate": null, "project": { "self": "http://localhost:2990/jira/rest/api/2/project/SAMPLEPROJECT", "id": "10001", "key": "SAMPLEPROJECT", "name": "Sample Project for Developing RoR RESTful API", "avatarUrls": { "16x16": "http://localhost:2990/jira/secure/projectavatar?size=small&pid=10001&avatarId=10011", "48x48": "http://localhost:2990/jira/secure/projectavatar?pid=10001&avatarId=10011" } }, "versions": [], "environment": null, "timeestimate": null, "aggregateprogress": { "progress": 0, "total": 0 }, "components": [], "timeoriginalestimate": null, "aggregatetimespent": null } }, { "expand": "editmeta,renderedFields,transitions,changelog", "id": "10005", "self": "http://localhost:2990/jira/rest/api/2/issue/10005", "key": "SAMPLEPROJECT-4", "fields": { "summary": "blah", "progress": { "progress": 0, "total": 0 }, "issuetype": { "self": "http://localhost:2990/jira/rest/api/2/issuetype/3", "id": "3", "description": "A task that needs to be done.", "iconUrl": "http://localhost:2990/jira/images/icons/task.gif", "name": "Task", "subtask": false }, "votes": { "self": "http://localhost:2990/jira/rest/api/2/issue/SAMPLEPROJECT-4/votes", "votes": 0, "hasVoted": false }, "resolution": null, "fixVersions": [], "resolutiondate": null, "timespent": null, "reporter": { "self": "http://localhost:2990/jira/rest/api/2/user?username=admin", "name": "admin", "emailAddress": "admin@example.com", "avatarUrls": { "16x16": "http://localhost:2990/jira/secure/useravatar?size=small&avatarId=10122", "48x48": "http://localhost:2990/jira/secure/useravatar?avatarId=10122" }, "displayName": "admin", "active": true }, "aggregatetimeoriginalestimate": null, "updated": "2011-12-14T12:11:48.000+1300", "created": "2011-12-14T12:11:48.000+1300", "description": null, "priority": { "self": "http://localhost:2990/jira/rest/api/2/priority/3", "iconUrl": "http://localhost:2990/jira/images/icons/priority_major.gif", "name": "Major", "id": "3" }, "duedate": null, "issuelinks": [], "watches": { "self": "http://localhost:2990/jira/rest/api/2/issue/SAMPLEPROJECT-4/watchers", "watchCount": 0, "isWatching": false }, "subtasks": [], "status": { "self": "http://localhost:2990/jira/rest/api/2/status/1", "description": "The issue is open and ready for the assignee to start work on it.", "iconUrl": "http://localhost:2990/jira/images/icons/status_open.gif", "name": "Open", "id": "1" }, "labels": [], "assignee": { "self": "http://localhost:2990/jira/rest/api/2/user?username=admin", "name": "admin", "emailAddress": "admin@example.com", "avatarUrls": { "16x16": "http://localhost:2990/jira/secure/useravatar?size=small&avatarId=10122", "48x48": "http://localhost:2990/jira/secure/useravatar?avatarId=10122" }, "displayName": "admin", "active": true }, "workratio": -1, "aggregatetimeestimate": null, "project": { "self": "http://localhost:2990/jira/rest/api/2/project/SAMPLEPROJECT", "id": "10001", "key": "SAMPLEPROJECT", "name": "Sample Project for Developing RoR RESTful API", "avatarUrls": { "16x16": "http://localhost:2990/jira/secure/projectavatar?size=small&pid=10001&avatarId=10011", "48x48": "http://localhost:2990/jira/secure/projectavatar?pid=10001&avatarId=10011" } }, "versions": [], "environment": null, "timeestimate": null, "aggregateprogress": { "progress": 0, "total": 0 }, "components": [], "timeoriginalestimate": null, "aggregatetimespent": null } }, { "expand": "editmeta,renderedFields,transitions,changelog", "id": "10002", "self": "http://localhost:2990/jira/rest/api/2/issue/10002", "key": "SAMPLEPROJECT-1", "fields": { "summary": "MOOOOOOARRR NINJAAAA!", "progress": { "progress": 0, "total": 0 }, "issuetype": { "self": "http://localhost:2990/jira/rest/api/2/issuetype/3", "id": "3", "description": "A task that needs to be done.", "iconUrl": "http://localhost:2990/jira/images/icons/task.gif", "name": "Task", "subtask": false }, "votes": { "self": "http://localhost:2990/jira/rest/api/2/issue/SAMPLEPROJECT-1/votes", "votes": 0, "hasVoted": false }, "resolution": null, "fixVersions": [], "resolutiondate": null, "timespent": null, "reporter": { "self": "http://localhost:2990/jira/rest/api/2/user?username=admin", "name": "admin", "emailAddress": "admin@example.com", "avatarUrls": { "16x16": "http://localhost:2990/jira/secure/useravatar?size=small&avatarId=10122", "48x48": "http://localhost:2990/jira/secure/useravatar?avatarId=10122" }, "displayName": "admin", "active": true }, "aggregatetimeoriginalestimate": null, "updated": "2011-12-15T15:37:33.000+1300", "created": "2011-12-14T10:26:06.000+1300", "description": null, "priority": { "self": "http://localhost:2990/jira/rest/api/2/priority/3", "iconUrl": "http://localhost:2990/jira/images/icons/priority_major.gif", "name": "Major", "id": "3" }, "duedate": "2011-12-14", "issuelinks": [], "watches": { "self": "http://localhost:2990/jira/rest/api/2/issue/SAMPLEPROJECT-1/watchers", "watchCount": 0, "isWatching": false }, "subtasks": [], "status": { "self": "http://localhost:2990/jira/rest/api/2/status/1", "description": "The issue is open and ready for the assignee to start work on it.", "iconUrl": "http://localhost:2990/jira/images/icons/status_open.gif", "name": "Open", "id": "1" }, "labels": [], "assignee": { "self": "http://localhost:2990/jira/rest/api/2/user?username=admin", "name": "admin", "emailAddress": "admin@example.com", "avatarUrls": { "16x16": "http://localhost:2990/jira/secure/useravatar?size=small&avatarId=10122", "48x48": "http://localhost:2990/jira/secure/useravatar?avatarId=10122" }, "displayName": "admin", "active": true }, "workratio": -1, "aggregatetimeestimate": null, "project": { "self": "http://localhost:2990/jira/rest/api/2/project/SAMPLEPROJECT", "id": "10001", "key": "SAMPLEPROJECT", "name": "Sample Project for Developing RoR RESTful API", "avatarUrls": { "16x16": "http://localhost:2990/jira/secure/projectavatar?size=small&pid=10001&avatarId=10011", "48x48": "http://localhost:2990/jira/secure/projectavatar?pid=10001&avatarId=10011" } }, "versions": [], "environment": null, "timeestimate": null, "aggregateprogress": { "progress": 0, "total": 0 }, "components": [], "timeoriginalestimate": null, "aggregatetimespent": null } } ] } jira-ruby-1.4.3/spec/mock_responses/issueLinkType/0000755000004100000410000000000013167661427022264 5ustar www-datawww-datajira-ruby-1.4.3/spec/mock_responses/issueLinkType/10000.json0000644000004100000410000000024213167661427023615 0ustar www-datawww-data{ "id": "10000", "self": "http://localhost:2990/jira/rest/api/2/issueLinkType/10000", "name": "Blocks", "inward": "is blocked by", "outward": "blocks" }jira-ruby-1.4.3/spec/mock_responses/project.json0000644000004100000410000000063513167661427022021 0ustar www-datawww-data[ { "self": "http://localhost:2990/jira/rest/api/2/project/SAMPLEPROJECT", "id": "10001", "key": "SAMPLEPROJECT", "name": "Sample Project for Developing RoR RESTful API", "avatarUrls": { "16x16": "http://localhost:2990/jira/secure/projectavatar?size=small&pid=10001&avatarId=10011", "48x48": "http://localhost:2990/jira/secure/projectavatar?pid=10001&avatarId=10011" } } ] jira-ruby-1.4.3/spec/mock_responses/priority/0000755000004100000410000000000013167661427021335 5ustar www-datawww-datajira-ruby-1.4.3/spec/mock_responses/priority/1.json0000644000004100000410000000044213167661427022370 0ustar www-datawww-data{ "self": "http://localhost:2990/jira/rest/api/2/priority/1", "statusColor": "#cc0000", "description": "Blocks development and/or testing work, production could not run.", "iconUrl": "http://localhost:2990/jira/images/icons/priority_blocker.gif", "name": "Blocker", "id": "1" } jira-ruby-1.4.3/spec/mock_responses/rapidview.json0000644000004100000410000000021613167661427022340 0ustar www-datawww-data{ "views": [ { "id": 1, "name": "SAMPLEPROJECT", "canEdit": true, "sprintSupportEnabled": true } ] }jira-ruby-1.4.3/spec/mock_responses/rapidview/0000755000004100000410000000000013167661427021446 5ustar www-datawww-datajira-ruby-1.4.3/spec/mock_responses/rapidview/SAMPLEPROJECT.issues.json0000644000004100000410000000605413167661427025670 0ustar www-datawww-data{ "sprintMarkersMigrated": true, "issues": [ { "id": 10000, "key": "SAM-1", "hidden": false, "typeName": "Story", "typeId": "10001", "summary": "Test issue 1", "typeUrl": "http://localhost:2990/jira/images/icons/ico_story.png", "priorityUrl": "http://localhost:2990/jira/images/icons/priorities/major.png", "priorityName": "Major", "done": false, "assignee": "admin", "assigneeName": "admin", "hasCustomUserAvatar": false, "autoUserAvatar": { "letter": "a", "color": "#f691b2" }, "color": "#cc0000", "estimateStatistic": { "statFieldId": "customfield_10002", "statFieldValue": {} }, "statusId": "1", "statusName": "Open", "statusUrl": "http://localhost:2990/jira/images/icons/statuses/open.png", "status": { "id": "1", "name": "Open", "description": "The issue is open and ready for the assignee to start work on it.", "iconUrl": "http://localhost:2990/jira/images/icons/statuses/open.png", "statusCategory": { "id": "2", "key": "new", "colorName": "blue-gray" } }, "fixVersions": [], "projectId": 10000, "linkedPagesCount": 0 }, { "id": 10001, "key": "SAM-2", "hidden": false, "typeName": "Story", "typeId": "10001", "summary": "Test issue 2", "typeUrl": "http://localhost:2990/jira/images/icons/ico_story.png", "priorityUrl": "http://localhost:2990/jira/images/icons/priorities/major.png", "priorityName": "Major", "done": false, "assignee": "admin", "assigneeName": "admin", "hasCustomUserAvatar": false, "autoUserAvatar": { "letter": "a", "color": "#f691b2" }, "color": "#cc0000", "estimateStatistic": { "statFieldId": "customfield_10002", "statFieldValue": {} }, "statusId": "1", "statusName": "Open", "statusUrl": "http://localhost:2990/jira/images/icons/statuses/open.png", "status": { "id": "1", "name": "Open", "description": "The issue is open and ready for the assignee to start work on it.", "iconUrl": "http://localhost:2990/jira/images/icons/statuses/open.png", "statusCategory": { "id": "2", "key": "new", "colorName": "blue-gray" } }, "fixVersions": [], "projectId": 10000, "linkedPagesCount": 0 } ], "rankCustomFieldId": 10009, "sprints": [], "supportsPages": false, "projects": [ { "id": 10000, "key": "SAM", "name": "SAMPLEPROJECT" } ], "epicData": { "epics": [], "canEditEpics": false, "supportsPages": false }, "canManageSprints": true, "maxIssuesExceeded": false, "queryResultLimit": 2147483647, "versionData": { "versionsPerProject": { "10000": [] }, "canCreateVersion": true } }jira-ruby-1.4.3/spec/mock_responses/rapidview/SAMPLEPROJECT.issues.full.json0000644000004100000410000003207213167661427026630 0ustar www-datawww-data{ "expand": "schema,names", "startAt": 0, "maxResults": 50, "total": 2, "issues": [ { "expand": "editmeta,renderedFields,transitions,changelog,operations", "id": "10001", "self": "http://localhost:2990/jira/rest/api/2/issue/10001", "key": "SAM-2", "fields": { "summary": "Test issue 2", "progress": { "progress": 0, "total": 0 }, "issuetype": { "self": "http://localhost:2990/jira/rest/api/2/issuetype/10001", "id": "10001", "description": "", "iconUrl": "http://localhost:2990/jira/images/icons/ico_story.png", "name": "Story", "subtask": false }, "votes": { "self": "http://localhost:2990/jira/rest/api/2/issue/SAM-2/votes", "votes": 0, "hasVoted": false }, "resolution": null, "fixVersions": [], "resolutiondate": null, "timespent": null, "creator": { "self": "http://localhost:2990/jira/rest/api/2/user?username=admin", "name": "admin", "emailAddress": "admin@example.com", "avatarUrls": { "16x16": "http://localhost:2990/jira/secure/useravatar?size=xsmall&avatarId=10122", "24x24": "http://localhost:2990/jira/secure/useravatar?size=small&avatarId=10122", "32x32": "http://localhost:2990/jira/secure/useravatar?size=medium&avatarId=10122", "48x48": "http://localhost:2990/jira/secure/useravatar?avatarId=10122" }, "displayName": "admin", "active": true }, "reporter": { "self": "http://localhost:2990/jira/rest/api/2/user?username=admin", "name": "admin", "emailAddress": "admin@example.com", "avatarUrls": { "16x16": "http://localhost:2990/jira/secure/useravatar?size=xsmall&avatarId=10122", "24x24": "http://localhost:2990/jira/secure/useravatar?size=small&avatarId=10122", "32x32": "http://localhost:2990/jira/secure/useravatar?size=medium&avatarId=10122", "48x48": "http://localhost:2990/jira/secure/useravatar?avatarId=10122" }, "displayName": "admin", "active": true }, "aggregatetimeoriginalestimate": null, "created": "2014-07-18T23:30:43.000+0700", "updated": "2014-07-18T23:30:44.000+0700", "description": null, "priority": { "self": "http://localhost:2990/jira/rest/api/2/priority/3", "iconUrl": "http://localhost:2990/jira/images/icons/priorities/major.png", "name": "Major", "id": "3" }, "duedate": null, "customfield_10001": null, "customfield_10002": null, "customfield_10003": null, "issuelinks": [], "customfield_10004": null, "watches": { "self": "http://localhost:2990/jira/rest/api/2/issue/SAM-2/watchers", "watchCount": 1, "isWatching": true }, "customfield_10000": null, "subtasks": [], "customfield_10009": "0|100004:", "status": { "self": "http://localhost:2990/jira/rest/api/2/status/1", "description": "The issue is open and ready for the assignee to start work on it.", "iconUrl": "http://localhost:2990/jira/images/icons/statuses/open.png", "name": "Open", "id": "1", "statusCategory": { "self": "http://localhost:2990/jira/rest/api/2/statuscategory/2", "id": 2, "key": "new", "colorName": "blue-gray", "name": "New" } }, "labels": [], "customfield_10005": null, "workratio": -1, "assignee": { "self": "http://localhost:2990/jira/rest/api/2/user?username=admin", "name": "admin", "emailAddress": "admin@example.com", "avatarUrls": { "16x16": "http://localhost:2990/jira/secure/useravatar?size=xsmall&avatarId=10122", "24x24": "http://localhost:2990/jira/secure/useravatar?size=small&avatarId=10122", "32x32": "http://localhost:2990/jira/secure/useravatar?size=medium&avatarId=10122", "48x48": "http://localhost:2990/jira/secure/useravatar?avatarId=10122" }, "displayName": "admin", "active": true }, "aggregatetimeestimate": null, "project": { "self": "http://localhost:2990/jira/rest/api/2/project/10000", "id": "10000", "key": "SAM", "name": "SAMPLEPROJECT", "avatarUrls": { "16x16": "http://localhost:2990/jira/secure/projectavatar?size=xsmall&pid=10000&avatarId=10011", "24x24": "http://localhost:2990/jira/secure/projectavatar?size=small&pid=10000&avatarId=10011", "32x32": "http://localhost:2990/jira/secure/projectavatar?size=medium&pid=10000&avatarId=10011", "48x48": "http://localhost:2990/jira/secure/projectavatar?pid=10000&avatarId=10011" } }, "versions": [], "environment": null, "timeestimate": null, "aggregateprogress": { "progress": 0, "total": 0 }, "lastViewed": "2014-07-18T23:30:43.561+0700", "components": [], "timeoriginalestimate": null, "aggregatetimespent": null } }, { "expand": "editmeta,renderedFields,transitions,changelog,operations", "id": "10000", "self": "http://localhost:2990/jira/rest/api/2/issue/10000", "key": "SAM-1", "fields": { "summary": "Test issue 1", "progress": { "progress": 0, "total": 0 }, "issuetype": { "self": "http://localhost:2990/jira/rest/api/2/issuetype/10001", "id": "10001", "description": "", "iconUrl": "http://localhost:2990/jira/images/icons/ico_story.png", "name": "Story", "subtask": false }, "votes": { "self": "http://localhost:2990/jira/rest/api/2/issue/SAM-1/votes", "votes": 0, "hasVoted": false }, "resolution": null, "fixVersions": [], "resolutiondate": null, "timespent": null, "creator": { "self": "http://localhost:2990/jira/rest/api/2/user?username=admin", "name": "admin", "emailAddress": "admin@example.com", "avatarUrls": { "16x16": "http://localhost:2990/jira/secure/useravatar?size=xsmall&avatarId=10122", "24x24": "http://localhost:2990/jira/secure/useravatar?size=small&avatarId=10122", "32x32": "http://localhost:2990/jira/secure/useravatar?size=medium&avatarId=10122", "48x48": "http://localhost:2990/jira/secure/useravatar?avatarId=10122" }, "displayName": "admin", "active": true }, "reporter": { "self": "http://localhost:2990/jira/rest/api/2/user?username=admin", "name": "admin", "emailAddress": "admin@example.com", "avatarUrls": { "16x16": "http://localhost:2990/jira/secure/useravatar?size=xsmall&avatarId=10122", "24x24": "http://localhost:2990/jira/secure/useravatar?size=small&avatarId=10122", "32x32": "http://localhost:2990/jira/secure/useravatar?size=medium&avatarId=10122", "48x48": "http://localhost:2990/jira/secure/useravatar?avatarId=10122" }, "displayName": "admin", "active": true }, "aggregatetimeoriginalestimate": null, "created": "2014-07-18T23:30:26.000+0700", "updated": "2014-07-18T23:30:26.000+0700", "description": null, "priority": { "self": "http://localhost:2990/jira/rest/api/2/priority/3", "iconUrl": "http://localhost:2990/jira/images/icons/priorities/major.png", "name": "Major", "id": "3" }, "duedate": null, "customfield_10001": null, "customfield_10002": null, "customfield_10003": null, "issuelinks": [], "customfield_10004": null, "watches": { "self": "http://localhost:2990/jira/rest/api/2/issue/SAM-1/watchers", "watchCount": 1, "isWatching": true }, "customfield_10000": null, "subtasks": [], "customfield_10009": "0|100000:", "status": { "self": "http://localhost:2990/jira/rest/api/2/status/1", "description": "The issue is open and ready for the assignee to start work on it.", "iconUrl": "http://localhost:2990/jira/images/icons/statuses/open.png", "name": "Open", "id": "1", "statusCategory": { "self": "http://localhost:2990/jira/rest/api/2/statuscategory/2", "id": 2, "key": "new", "colorName": "blue-gray", "name": "New" } }, "labels": [], "customfield_10005": null, "workratio": -1, "assignee": { "self": "http://localhost:2990/jira/rest/api/2/user?username=admin", "name": "admin", "emailAddress": "admin@example.com", "avatarUrls": { "16x16": "http://localhost:2990/jira/secure/useravatar?size=xsmall&avatarId=10122", "24x24": "http://localhost:2990/jira/secure/useravatar?size=small&avatarId=10122", "32x32": "http://localhost:2990/jira/secure/useravatar?size=medium&avatarId=10122", "48x48": "http://localhost:2990/jira/secure/useravatar?avatarId=10122" }, "displayName": "admin", "active": true }, "aggregatetimeestimate": null, "project": { "self": "http://localhost:2990/jira/rest/api/2/project/10000", "id": "10000", "key": "SAM", "name": "SAMPLEPROJECT", "avatarUrls": { "16x16": "http://localhost:2990/jira/secure/projectavatar?size=xsmall&pid=10000&avatarId=10011", "24x24": "http://localhost:2990/jira/secure/projectavatar?size=small&pid=10000&avatarId=10011", "32x32": "http://localhost:2990/jira/secure/projectavatar?size=medium&pid=10000&avatarId=10011", "48x48": "http://localhost:2990/jira/secure/projectavatar?pid=10000&avatarId=10011" } }, "versions": [], "environment": null, "timeestimate": null, "aggregateprogress": { "progress": 0, "total": 0 }, "lastViewed": "2014-07-18T23:30:28.576+0700", "components": [], "timeoriginalestimate": null, "aggregatetimespent": null } } ] }jira-ruby-1.4.3/spec/mock_responses/rapidview/SAMPLEPROJECT.json0000644000004100000410000000013313167661427024346 0ustar www-datawww-data{ "id": 1, "name": "SAMPLEPROJECT", "canEdit": true, "sprintSupportEnabled": true }jira-ruby-1.4.3/spec/mock_responses/webhook.json0000644000004100000410000000052713167661427022011 0ustar www-datawww-data[{"name":"from API", "url":"http://localhost:3000/webhooks/1", "excludeBody":false, "filters":{"issue-related-events-section":""}, "events":[], "enabled":true, "self":"http://localhost:2990/jira/rest/webhooks/1.0/webhook/2", "lastUpdatedUser":"admin", "lastUpdatedDisplayName":"admin", "lastUpdated":1453306520188} ]jira-ruby-1.4.3/spec/mock_responses/issuetype/0000755000004100000410000000000013167661427021506 5ustar www-datawww-datajira-ruby-1.4.3/spec/mock_responses/issuetype/5.json0000644000004100000410000000036013167661427022544 0ustar www-datawww-data{ "self": "http://localhost:2990/jira/rest/api/2/issuetype/5", "id": "5", "description": "The sub-task of the issue", "iconUrl": "http://localhost:2990/jira/images/icons/issue_subtask.gif", "name": "Sub-task", "subtask": true } jira-ruby-1.4.3/spec/mock_responses/sprint/0000755000004100000410000000000013167661427020773 5ustar www-datawww-datajira-ruby-1.4.3/spec/mock_responses/sprint/1_issues.json0000644000004100000410000001045713167661427023430 0ustar www-datawww-data{ "expand": "schema,names", "startAt": 0, "maxResults": 50, "total": 1, "issues": [ { "expand": "", "id": "10001", "self": "http://www.example.com/jira/rest/agile/1.0/board/92/issue/10001", "key": "HSP-1", "fields": { "flagged": true, "sprint": { "id": 37, "self": "http://www.example.com/jira/rest/agile/1.0/sprint/13", "state": "future", "name": "sprint 2" }, "closedSprints": [ { "id": 37, "self": "http://www.example.com/jira/rest/agile/1.0/sprint/23", "state": "closed", "name": "sprint 1", "startDate": "2015-04-11T15:22:00.000+10:00", "endDate": "2015-04-20T01:22:00.000+10:00", "completeDate": "2015-04-20T11:04:00.000+10:00" } ], "description": "example bug report", "project": { "self": "http://www.example.com/jira/rest/api/2/project/EX", "id": "10000", "key": "EX", "name": "Example", "avatarUrls": { "48x48": "http://www.example.com/jira/secure/projectavatar?size=large&pid=10000", "24x24": "http://www.example.com/jira/secure/projectavatar?size=small&pid=10000", "16x16": "http://www.example.com/jira/secure/projectavatar?size=xsmall&pid=10000", "32x32": "http://www.example.com/jira/secure/projectavatar?size=medium&pid=10000" }, "projectCategory": { "self": "http://www.example.com/jira/rest/api/2/projectCategory/10000", "id": "10000", "name": "FIRST", "description": "First Project Category" } }, "comment": [ { "self": "http://www.example.com/jira/rest/api/2/issue/10010/comment/10000", "id": "10000", "author": { "self": "http://www.example.com/jira/rest/api/2/user?username=fred", "name": "fred", "displayName": "Fred F. User", "active": false }, "body": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque eget venenatis elit. Duis eu justo eget augue iaculis fermentum. Sed semper quam laoreet nisi egestas at posuere augue semper.", "updateAuthor": { "self": "http://www.example.com/jira/rest/api/2/user?username=fred", "name": "fred", "displayName": "Fred F. User", "active": false }, "created": "2016-06-22T11:49:57.797+0200", "updated": "2016-06-22T11:49:57.800+0200", "visibility": { "type": "role", "value": "Administrators" } } ], "epic": { "id": 37, "self": "http://www.example.com/jira/rest/agile/1.0/epic/23", "name": "epic 1", "summary": "epic 1 summary", "color": { "key": "color_4" }, "done": true }, "worklog": [ { "self": "http://www.example.com/jira/rest/api/2/issue/10010/worklog/10000", "author": { "self": "http://www.example.com/jira/rest/api/2/user?username=fred", "name": "fred", "displayName": "Fred F. User", "active": false }, "updateAuthor": { "self": "http://www.example.com/jira/rest/api/2/user?username=fred", "name": "fred", "displayName": "Fred F. User", "active": false }, "comment": "I did some work here.", "updated": "2016-06-22T11:49:57.804+0200", "visibility": { "type": "group", "value": "jira-developers" }, "started": "2016-06-22T11:49:57.804+0200", "timeSpent": "3h 20m", "timeSpentSeconds": 12000, "id": "100028", "issueId": "10002" } ], "updated": 1, "timetracking": { "originalEstimate": "10m", "remainingEstimate": "3m", "timeSpent": "6m", "originalEstimateSeconds": 600, "remainingEstimateSeconds": 200, "timeSpentSeconds": 400 } } } ] }jira-ruby-1.4.3/spec/mock_responses/board/0000755000004100000410000000000013167661427020543 5ustar www-datawww-datajira-ruby-1.4.3/spec/mock_responses/board/1.json0000644000004100000410000000152113167661427021575 0ustar www-datawww-data{ "maxResults": 50, "startAt": 0, "isLast": true, "values": [ { "id": 1, "self": "https://test.com/jira/rest/agile/1.0/sprint/1", "state": "closed", "name": "Test Sprint 1", "startDate": "2016-05-03T01:45:17.624-04:00", "endDate": "2016-05-06T13:30:00.000-04:00", "completeDate": "2016-05-08T04:05:31.959-04:00", "originBoardId": 1 }, { "id": 2, "self": "https://test.com/jira/rest/agile/1.0/sprint/2", "state": "active", "name": "Test Sprint 2", "startDate": "2016-12-12T04:42:46.184-05:00", "endDate": "2017-01-02T13:56:00.000-05:00", "originBoardId": 1 }, { "id": 3, "self": "https://test.com/jira/rest/agile/1.0/sprint/2", "state": "future", "name": "Test Sprint 2", "originBoardId": 1 } ] }jira-ruby-1.4.3/spec/mock_responses/board/1_issues.json0000644000004100000410000000375013167661427023176 0ustar www-datawww-data{ "expand": "schema,names", "startAt": 0, "maxResults": 1000, "total": 9, "issues": [ { "expand": "operations,versionedRepresentations,editmeta,changelog,renderedFields", "id": "10546", "self": "https://jira.example.com/rest/agile/1.0/issue/10546", "key": "SBT-1" }, { "expand": "operations,versionedRepresentations,editmeta,changelog,renderedFields", "id": "10547", "self": "https://jira.example.com/rest/agile/1.0/issue/10547", "key": "SBT-2" }, { "expand": "operations,versionedRepresentations,editmeta,changelog,renderedFields", "id": "10556", "self": "https://jira.example.com/rest/agile/1.0/issue/10556", "key": "SBT-11" }, { "expand": "operations,versionedRepresentations,editmeta,changelog,renderedFields", "id": "10557", "self": "https://jira.example.com/rest/agile/1.0/issue/10557", "key": "SBT-12" }, { "expand": "operations,versionedRepresentations,editmeta,changelog,renderedFields", "id": "10558", "self": "https://jira.example.com/rest/agile/1.0/issue/10558", "key": "SBT-13" }, { "expand": "operations,versionedRepresentations,editmeta,changelog,renderedFields", "id": "10559", "self": "https://jira.example.com/rest/agile/1.0/issue/10559", "key": "SBT-14" }, { "expand": "operations,versionedRepresentations,editmeta,changelog,renderedFields", "id": "10600", "self": "https://jira.example.com/rest/agile/1.0/issue/10600", "key": "SBT-16" }, { "expand": "operations,versionedRepresentations,editmeta,changelog,renderedFields", "id": "10601", "self": "https://jira.example.com/rest/agile/1.0/issue/10601", "key": "SBT-17" }, { "expand": "operations,versionedRepresentations,editmeta,changelog,renderedFields", "id": "10604", "self": "https://jira.example.com/rest/agile/1.0/issue/10604", "key": "SBT-19" } ] }jira-ruby-1.4.3/spec/mock_responses/project/0000755000004100000410000000000013167661427021122 5ustar www-datawww-datajira-ruby-1.4.3/spec/mock_responses/project/SAMPLEPROJECT.issues.json0000644000004100000410000011725713167661427025354 0ustar www-datawww-data{ "expand": "schema,names", "startAt": 0, "maxResults": 50, "total": 11, "issues": [ { "expand": "editmeta,renderedFields,transitions,changelog", "id": "10014", "self": "http://localhost:2990/jira/rest/api/2/issue/10014", "key": "SAMPLEPROJECT-13", "fields": { "summary": "blarg from in example.rb", "progress": { "progress": 0, "total": 0 }, "issuetype": { "self": "http://localhost:2990/jira/rest/api/2/issuetype/3", "id": "3", "description": "A task that needs to be done.", "iconUrl": "http://localhost:2990/jira/images/icons/task.gif", "name": "Task", "subtask": false }, "votes": { "self": "http://localhost:2990/jira/rest/api/2/issue/SAMPLEPROJECT-13/votes", "votes": 0, "hasVoted": false }, "resolution": null, "fixVersions": [], "resolutiondate": null, "timespent": null, "reporter": { "self": "http://localhost:2990/jira/rest/api/2/user?username=admin", "name": "admin", "emailAddress": "admin@example.com", "avatarUrls": { "16x16": "http://localhost:2990/jira/secure/useravatar?size=small&avatarId=10122", "48x48": "http://localhost:2990/jira/secure/useravatar?avatarId=10122" }, "displayName": "admin", "active": true }, "aggregatetimeoriginalestimate": null, "updated": "2011-12-15T15:35:06.000+1300", "created": "2011-12-15T15:35:06.000+1300", "description": null, "priority": { "self": "http://localhost:2990/jira/rest/api/2/priority/3", "iconUrl": "http://localhost:2990/jira/images/icons/priority_major.gif", "name": "Major", "id": "3" }, "duedate": null, "issuelinks": [], "watches": { "self": "http://localhost:2990/jira/rest/api/2/issue/SAMPLEPROJECT-13/watchers", "watchCount": 0, "isWatching": false }, "subtasks": [], "status": { "self": "http://localhost:2990/jira/rest/api/2/status/1", "description": "The issue is open and ready for the assignee to start work on it.", "iconUrl": "http://localhost:2990/jira/images/icons/status_open.gif", "name": "Open", "id": "1" }, "labels": [], "assignee": { "self": "http://localhost:2990/jira/rest/api/2/user?username=admin", "name": "admin", "emailAddress": "admin@example.com", "avatarUrls": { "16x16": "http://localhost:2990/jira/secure/useravatar?size=small&avatarId=10122", "48x48": "http://localhost:2990/jira/secure/useravatar?avatarId=10122" }, "displayName": "admin", "active": true }, "workratio": -1, "aggregatetimeestimate": null, "project": { "self": "http://localhost:2990/jira/rest/api/2/project/SAMPLEPROJECT", "id": "10001", "key": "SAMPLEPROJECT", "name": "Sample Project for Developing RoR RESTful API", "avatarUrls": { "16x16": "http://localhost:2990/jira/secure/projectavatar?size=small&pid=10001&avatarId=10011", "48x48": "http://localhost:2990/jira/secure/projectavatar?pid=10001&avatarId=10011" } }, "versions": [], "environment": null, "timeestimate": null, "aggregateprogress": { "progress": 0, "total": 0 }, "components": [], "timeoriginalestimate": null, "aggregatetimespent": null } }, { "expand": "editmeta,renderedFields,transitions,changelog", "id": "10013", "self": "http://localhost:2990/jira/rest/api/2/issue/10013", "key": "SAMPLEPROJECT-12", "fields": { "summary": "blarg from in example.rb", "progress": { "progress": 0, "total": 0 }, "issuetype": { "self": "http://localhost:2990/jira/rest/api/2/issuetype/3", "id": "3", "description": "A task that needs to be done.", "iconUrl": "http://localhost:2990/jira/images/icons/task.gif", "name": "Task", "subtask": false }, "votes": { "self": "http://localhost:2990/jira/rest/api/2/issue/SAMPLEPROJECT-12/votes", "votes": 0, "hasVoted": false }, "resolution": null, "fixVersions": [], "resolutiondate": null, "timespent": null, "reporter": { "self": "http://localhost:2990/jira/rest/api/2/user?username=admin", "name": "admin", "emailAddress": "admin@example.com", "avatarUrls": { "16x16": "http://localhost:2990/jira/secure/useravatar?size=small&avatarId=10122", "48x48": "http://localhost:2990/jira/secure/useravatar?avatarId=10122" }, "displayName": "admin", "active": true }, "aggregatetimeoriginalestimate": null, "updated": "2011-12-15T15:34:58.000+1300", "created": "2011-12-15T15:34:58.000+1300", "description": null, "priority": { "self": "http://localhost:2990/jira/rest/api/2/priority/3", "iconUrl": "http://localhost:2990/jira/images/icons/priority_major.gif", "name": "Major", "id": "3" }, "duedate": null, "issuelinks": [], "watches": { "self": "http://localhost:2990/jira/rest/api/2/issue/SAMPLEPROJECT-12/watchers", "watchCount": 0, "isWatching": false }, "subtasks": [], "status": { "self": "http://localhost:2990/jira/rest/api/2/status/1", "description": "The issue is open and ready for the assignee to start work on it.", "iconUrl": "http://localhost:2990/jira/images/icons/status_open.gif", "name": "Open", "id": "1" }, "labels": [], "assignee": { "self": "http://localhost:2990/jira/rest/api/2/user?username=admin", "name": "admin", "emailAddress": "admin@example.com", "avatarUrls": { "16x16": "http://localhost:2990/jira/secure/useravatar?size=small&avatarId=10122", "48x48": "http://localhost:2990/jira/secure/useravatar?avatarId=10122" }, "displayName": "admin", "active": true }, "workratio": -1, "aggregatetimeestimate": null, "project": { "self": "http://localhost:2990/jira/rest/api/2/project/SAMPLEPROJECT", "id": "10001", "key": "SAMPLEPROJECT", "name": "Sample Project for Developing RoR RESTful API", "avatarUrls": { "16x16": "http://localhost:2990/jira/secure/projectavatar?size=small&pid=10001&avatarId=10011", "48x48": "http://localhost:2990/jira/secure/projectavatar?pid=10001&avatarId=10011" } }, "versions": [], "environment": null, "timeestimate": null, "aggregateprogress": { "progress": 0, "total": 0 }, "components": [], "timeoriginalestimate": null, "aggregatetimespent": null } }, { "expand": "editmeta,renderedFields,transitions,changelog", "id": "10012", "self": "http://localhost:2990/jira/rest/api/2/issue/10012", "key": "SAMPLEPROJECT-11", "fields": { "summary": "blarg from in example.rb", "progress": { "progress": 0, "total": 0 }, "issuetype": { "self": "http://localhost:2990/jira/rest/api/2/issuetype/3", "id": "3", "description": "A task that needs to be done.", "iconUrl": "http://localhost:2990/jira/images/icons/task.gif", "name": "Task", "subtask": false }, "votes": { "self": "http://localhost:2990/jira/rest/api/2/issue/SAMPLEPROJECT-11/votes", "votes": 0, "hasVoted": false }, "resolution": null, "fixVersions": [], "resolutiondate": null, "timespent": null, "reporter": { "self": "http://localhost:2990/jira/rest/api/2/user?username=admin", "name": "admin", "emailAddress": "admin@example.com", "avatarUrls": { "16x16": "http://localhost:2990/jira/secure/useravatar?size=small&avatarId=10122", "48x48": "http://localhost:2990/jira/secure/useravatar?avatarId=10122" }, "displayName": "admin", "active": true }, "aggregatetimeoriginalestimate": null, "updated": "2011-12-15T15:34:48.000+1300", "created": "2011-12-15T15:34:48.000+1300", "description": null, "priority": { "self": "http://localhost:2990/jira/rest/api/2/priority/3", "iconUrl": "http://localhost:2990/jira/images/icons/priority_major.gif", "name": "Major", "id": "3" }, "duedate": null, "issuelinks": [], "watches": { "self": "http://localhost:2990/jira/rest/api/2/issue/SAMPLEPROJECT-11/watchers", "watchCount": 0, "isWatching": false }, "subtasks": [], "status": { "self": "http://localhost:2990/jira/rest/api/2/status/1", "description": "The issue is open and ready for the assignee to start work on it.", "iconUrl": "http://localhost:2990/jira/images/icons/status_open.gif", "name": "Open", "id": "1" }, "labels": [], "assignee": { "self": "http://localhost:2990/jira/rest/api/2/user?username=admin", "name": "admin", "emailAddress": "admin@example.com", "avatarUrls": { "16x16": "http://localhost:2990/jira/secure/useravatar?size=small&avatarId=10122", "48x48": "http://localhost:2990/jira/secure/useravatar?avatarId=10122" }, "displayName": "admin", "active": true }, "workratio": -1, "aggregatetimeestimate": null, "project": { "self": "http://localhost:2990/jira/rest/api/2/project/SAMPLEPROJECT", "id": "10001", "key": "SAMPLEPROJECT", "name": "Sample Project for Developing RoR RESTful API", "avatarUrls": { "16x16": "http://localhost:2990/jira/secure/projectavatar?size=small&pid=10001&avatarId=10011", "48x48": "http://localhost:2990/jira/secure/projectavatar?pid=10001&avatarId=10011" } }, "versions": [], "environment": null, "timeestimate": null, "aggregateprogress": { "progress": 0, "total": 0 }, "components": [], "timeoriginalestimate": null, "aggregatetimespent": null } }, { "expand": "editmeta,renderedFields,transitions,changelog", "id": "10011", "self": "http://localhost:2990/jira/rest/api/2/issue/10011", "key": "SAMPLEPROJECT-10", "fields": { "summary": "blarg from in example.rb", "progress": { "progress": 0, "total": 0 }, "issuetype": { "self": "http://localhost:2990/jira/rest/api/2/issuetype/3", "id": "3", "description": "A task that needs to be done.", "iconUrl": "http://localhost:2990/jira/images/icons/task.gif", "name": "Task", "subtask": false }, "votes": { "self": "http://localhost:2990/jira/rest/api/2/issue/SAMPLEPROJECT-10/votes", "votes": 0, "hasVoted": false }, "resolution": null, "fixVersions": [], "resolutiondate": null, "timespent": null, "reporter": { "self": "http://localhost:2990/jira/rest/api/2/user?username=admin", "name": "admin", "emailAddress": "admin@example.com", "avatarUrls": { "16x16": "http://localhost:2990/jira/secure/useravatar?size=small&avatarId=10122", "48x48": "http://localhost:2990/jira/secure/useravatar?avatarId=10122" }, "displayName": "admin", "active": true }, "aggregatetimeoriginalestimate": null, "updated": "2011-12-15T15:11:57.000+1300", "created": "2011-12-15T15:11:57.000+1300", "description": null, "priority": { "self": "http://localhost:2990/jira/rest/api/2/priority/3", "iconUrl": "http://localhost:2990/jira/images/icons/priority_major.gif", "name": "Major", "id": "3" }, "duedate": null, "issuelinks": [], "watches": { "self": "http://localhost:2990/jira/rest/api/2/issue/SAMPLEPROJECT-10/watchers", "watchCount": 0, "isWatching": false }, "subtasks": [], "status": { "self": "http://localhost:2990/jira/rest/api/2/status/1", "description": "The issue is open and ready for the assignee to start work on it.", "iconUrl": "http://localhost:2990/jira/images/icons/status_open.gif", "name": "Open", "id": "1" }, "labels": [], "assignee": { "self": "http://localhost:2990/jira/rest/api/2/user?username=admin", "name": "admin", "emailAddress": "admin@example.com", "avatarUrls": { "16x16": "http://localhost:2990/jira/secure/useravatar?size=small&avatarId=10122", "48x48": "http://localhost:2990/jira/secure/useravatar?avatarId=10122" }, "displayName": "admin", "active": true }, "workratio": -1, "aggregatetimeestimate": null, "project": { "self": "http://localhost:2990/jira/rest/api/2/project/SAMPLEPROJECT", "id": "10001", "key": "SAMPLEPROJECT", "name": "Sample Project for Developing RoR RESTful API", "avatarUrls": { "16x16": "http://localhost:2990/jira/secure/projectavatar?size=small&pid=10001&avatarId=10011", "48x48": "http://localhost:2990/jira/secure/projectavatar?pid=10001&avatarId=10011" } }, "versions": [], "environment": null, "timeestimate": null, "aggregateprogress": { "progress": 0, "total": 0 }, "components": [], "timeoriginalestimate": null, "aggregatetimespent": null } }, { "expand": "editmeta,renderedFields,transitions,changelog", "id": "10010", "self": "http://localhost:2990/jira/rest/api/2/issue/10010", "key": "SAMPLEPROJECT-9", "fields": { "summary": "blarg from in example.rb", "progress": { "progress": 0, "total": 0 }, "issuetype": { "self": "http://localhost:2990/jira/rest/api/2/issuetype/3", "id": "3", "description": "A task that needs to be done.", "iconUrl": "http://localhost:2990/jira/images/icons/task.gif", "name": "Task", "subtask": false }, "votes": { "self": "http://localhost:2990/jira/rest/api/2/issue/SAMPLEPROJECT-9/votes", "votes": 0, "hasVoted": false }, "resolution": null, "fixVersions": [], "resolutiondate": null, "timespent": null, "reporter": { "self": "http://localhost:2990/jira/rest/api/2/user?username=admin", "name": "admin", "emailAddress": "admin@example.com", "avatarUrls": { "16x16": "http://localhost:2990/jira/secure/useravatar?size=small&avatarId=10122", "48x48": "http://localhost:2990/jira/secure/useravatar?avatarId=10122" }, "displayName": "admin", "active": true }, "aggregatetimeoriginalestimate": null, "updated": "2011-12-15T15:11:45.000+1300", "created": "2011-12-15T15:11:45.000+1300", "description": null, "priority": { "self": "http://localhost:2990/jira/rest/api/2/priority/3", "iconUrl": "http://localhost:2990/jira/images/icons/priority_major.gif", "name": "Major", "id": "3" }, "duedate": null, "issuelinks": [], "watches": { "self": "http://localhost:2990/jira/rest/api/2/issue/SAMPLEPROJECT-9/watchers", "watchCount": 0, "isWatching": false }, "subtasks": [], "status": { "self": "http://localhost:2990/jira/rest/api/2/status/1", "description": "The issue is open and ready for the assignee to start work on it.", "iconUrl": "http://localhost:2990/jira/images/icons/status_open.gif", "name": "Open", "id": "1" }, "labels": [], "assignee": { "self": "http://localhost:2990/jira/rest/api/2/user?username=admin", "name": "admin", "emailAddress": "admin@example.com", "avatarUrls": { "16x16": "http://localhost:2990/jira/secure/useravatar?size=small&avatarId=10122", "48x48": "http://localhost:2990/jira/secure/useravatar?avatarId=10122" }, "displayName": "admin", "active": true }, "workratio": -1, "aggregatetimeestimate": null, "project": { "self": "http://localhost:2990/jira/rest/api/2/project/SAMPLEPROJECT", "id": "10001", "key": "SAMPLEPROJECT", "name": "Sample Project for Developing RoR RESTful API", "avatarUrls": { "16x16": "http://localhost:2990/jira/secure/projectavatar?size=small&pid=10001&avatarId=10011", "48x48": "http://localhost:2990/jira/secure/projectavatar?pid=10001&avatarId=10011" } }, "versions": [], "environment": null, "timeestimate": null, "aggregateprogress": { "progress": 0, "total": 0 }, "components": [], "timeoriginalestimate": null, "aggregatetimespent": null } }, { "expand": "editmeta,renderedFields,transitions,changelog", "id": "10009", "self": "http://localhost:2990/jira/rest/api/2/issue/10009", "key": "SAMPLEPROJECT-8", "fields": { "summary": "blarg from in example.rb", "progress": { "progress": 0, "total": 0 }, "issuetype": { "self": "http://localhost:2990/jira/rest/api/2/issuetype/3", "id": "3", "description": "A task that needs to be done.", "iconUrl": "http://localhost:2990/jira/images/icons/task.gif", "name": "Task", "subtask": false }, "votes": { "self": "http://localhost:2990/jira/rest/api/2/issue/SAMPLEPROJECT-8/votes", "votes": 0, "hasVoted": false }, "resolution": null, "fixVersions": [], "resolutiondate": null, "timespent": null, "reporter": { "self": "http://localhost:2990/jira/rest/api/2/user?username=admin", "name": "admin", "emailAddress": "admin@example.com", "avatarUrls": { "16x16": "http://localhost:2990/jira/secure/useravatar?size=small&avatarId=10122", "48x48": "http://localhost:2990/jira/secure/useravatar?avatarId=10122" }, "displayName": "admin", "active": true }, "aggregatetimeoriginalestimate": null, "updated": "2011-12-15T14:19:49.000+1300", "created": "2011-12-15T14:19:49.000+1300", "description": null, "priority": { "self": "http://localhost:2990/jira/rest/api/2/priority/3", "iconUrl": "http://localhost:2990/jira/images/icons/priority_major.gif", "name": "Major", "id": "3" }, "duedate": null, "issuelinks": [], "watches": { "self": "http://localhost:2990/jira/rest/api/2/issue/SAMPLEPROJECT-8/watchers", "watchCount": 0, "isWatching": false }, "subtasks": [], "status": { "self": "http://localhost:2990/jira/rest/api/2/status/1", "description": "The issue is open and ready for the assignee to start work on it.", "iconUrl": "http://localhost:2990/jira/images/icons/status_open.gif", "name": "Open", "id": "1" }, "labels": [], "assignee": { "self": "http://localhost:2990/jira/rest/api/2/user?username=admin", "name": "admin", "emailAddress": "admin@example.com", "avatarUrls": { "16x16": "http://localhost:2990/jira/secure/useravatar?size=small&avatarId=10122", "48x48": "http://localhost:2990/jira/secure/useravatar?avatarId=10122" }, "displayName": "admin", "active": true }, "workratio": -1, "aggregatetimeestimate": null, "project": { "self": "http://localhost:2990/jira/rest/api/2/project/SAMPLEPROJECT", "id": "10001", "key": "SAMPLEPROJECT", "name": "Sample Project for Developing RoR RESTful API", "avatarUrls": { "16x16": "http://localhost:2990/jira/secure/projectavatar?size=small&pid=10001&avatarId=10011", "48x48": "http://localhost:2990/jira/secure/projectavatar?pid=10001&avatarId=10011" } }, "versions": [], "environment": null, "timeestimate": null, "aggregateprogress": { "progress": 0, "total": 0 }, "components": [], "timeoriginalestimate": null, "aggregatetimespent": null } }, { "expand": "editmeta,renderedFields,transitions,changelog", "id": "10008", "self": "http://localhost:2990/jira/rest/api/2/issue/10008", "key": "SAMPLEPROJECT-7", "fields": { "summary": "blarg from in example.rb", "progress": { "progress": 0, "total": 0 }, "issuetype": { "self": "http://localhost:2990/jira/rest/api/2/issuetype/3", "id": "3", "description": "A task that needs to be done.", "iconUrl": "http://localhost:2990/jira/images/icons/task.gif", "name": "Task", "subtask": false }, "votes": { "self": "http://localhost:2990/jira/rest/api/2/issue/SAMPLEPROJECT-7/votes", "votes": 0, "hasVoted": false }, "resolution": null, "fixVersions": [], "resolutiondate": null, "timespent": null, "reporter": { "self": "http://localhost:2990/jira/rest/api/2/user?username=admin", "name": "admin", "emailAddress": "admin@example.com", "avatarUrls": { "16x16": "http://localhost:2990/jira/secure/useravatar?size=small&avatarId=10122", "48x48": "http://localhost:2990/jira/secure/useravatar?avatarId=10122" }, "displayName": "admin", "active": true }, "aggregatetimeoriginalestimate": null, "updated": "2011-12-14T14:50:38.000+1300", "created": "2011-12-14T14:50:38.000+1300", "description": null, "priority": { "self": "http://localhost:2990/jira/rest/api/2/priority/3", "iconUrl": "http://localhost:2990/jira/images/icons/priority_major.gif", "name": "Major", "id": "3" }, "duedate": null, "issuelinks": [], "watches": { "self": "http://localhost:2990/jira/rest/api/2/issue/SAMPLEPROJECT-7/watchers", "watchCount": 0, "isWatching": false }, "subtasks": [], "status": { "self": "http://localhost:2990/jira/rest/api/2/status/1", "description": "The issue is open and ready for the assignee to start work on it.", "iconUrl": "http://localhost:2990/jira/images/icons/status_open.gif", "name": "Open", "id": "1" }, "labels": [], "assignee": { "self": "http://localhost:2990/jira/rest/api/2/user?username=admin", "name": "admin", "emailAddress": "admin@example.com", "avatarUrls": { "16x16": "http://localhost:2990/jira/secure/useravatar?size=small&avatarId=10122", "48x48": "http://localhost:2990/jira/secure/useravatar?avatarId=10122" }, "displayName": "admin", "active": true }, "workratio": -1, "aggregatetimeestimate": null, "project": { "self": "http://localhost:2990/jira/rest/api/2/project/SAMPLEPROJECT", "id": "10001", "key": "SAMPLEPROJECT", "name": "Sample Project for Developing RoR RESTful API", "avatarUrls": { "16x16": "http://localhost:2990/jira/secure/projectavatar?size=small&pid=10001&avatarId=10011", "48x48": "http://localhost:2990/jira/secure/projectavatar?pid=10001&avatarId=10011" } }, "versions": [], "environment": null, "timeestimate": null, "aggregateprogress": { "progress": 0, "total": 0 }, "components": [], "timeoriginalestimate": null, "aggregatetimespent": null } }, { "expand": "editmeta,renderedFields,transitions,changelog", "id": "10007", "self": "http://localhost:2990/jira/rest/api/2/issue/10007", "key": "SAMPLEPROJECT-6", "fields": { "summary": "blarg from in example.rb", "progress": { "progress": 0, "total": 0 }, "issuetype": { "self": "http://localhost:2990/jira/rest/api/2/issuetype/3", "id": "3", "description": "A task that needs to be done.", "iconUrl": "http://localhost:2990/jira/images/icons/task.gif", "name": "Task", "subtask": false }, "votes": { "self": "http://localhost:2990/jira/rest/api/2/issue/SAMPLEPROJECT-6/votes", "votes": 0, "hasVoted": false }, "resolution": null, "fixVersions": [], "resolutiondate": null, "timespent": null, "reporter": { "self": "http://localhost:2990/jira/rest/api/2/user?username=admin", "name": "admin", "emailAddress": "admin@example.com", "avatarUrls": { "16x16": "http://localhost:2990/jira/secure/useravatar?size=small&avatarId=10122", "48x48": "http://localhost:2990/jira/secure/useravatar?avatarId=10122" }, "displayName": "admin", "active": true }, "aggregatetimeoriginalestimate": null, "updated": "2011-12-14T14:49:35.000+1300", "created": "2011-12-14T14:49:35.000+1300", "description": null, "priority": { "self": "http://localhost:2990/jira/rest/api/2/priority/3", "iconUrl": "http://localhost:2990/jira/images/icons/priority_major.gif", "name": "Major", "id": "3" }, "duedate": null, "issuelinks": [], "watches": { "self": "http://localhost:2990/jira/rest/api/2/issue/SAMPLEPROJECT-6/watchers", "watchCount": 0, "isWatching": false }, "subtasks": [], "status": { "self": "http://localhost:2990/jira/rest/api/2/status/1", "description": "The issue is open and ready for the assignee to start work on it.", "iconUrl": "http://localhost:2990/jira/images/icons/status_open.gif", "name": "Open", "id": "1" }, "labels": [], "assignee": { "self": "http://localhost:2990/jira/rest/api/2/user?username=admin", "name": "admin", "emailAddress": "admin@example.com", "avatarUrls": { "16x16": "http://localhost:2990/jira/secure/useravatar?size=small&avatarId=10122", "48x48": "http://localhost:2990/jira/secure/useravatar?avatarId=10122" }, "displayName": "admin", "active": true }, "workratio": -1, "aggregatetimeestimate": null, "project": { "self": "http://localhost:2990/jira/rest/api/2/project/SAMPLEPROJECT", "id": "10001", "key": "SAMPLEPROJECT", "name": "Sample Project for Developing RoR RESTful API", "avatarUrls": { "16x16": "http://localhost:2990/jira/secure/projectavatar?size=small&pid=10001&avatarId=10011", "48x48": "http://localhost:2990/jira/secure/projectavatar?pid=10001&avatarId=10011" } }, "versions": [], "environment": null, "timeestimate": null, "aggregateprogress": { "progress": 0, "total": 0 }, "components": [], "timeoriginalestimate": null, "aggregatetimespent": null } }, { "expand": "editmeta,renderedFields,transitions,changelog", "id": "10006", "self": "http://localhost:2990/jira/rest/api/2/issue/10006", "key": "SAMPLEPROJECT-5", "fields": { "summary": "blah", "progress": { "progress": 0, "total": 0 }, "issuetype": { "self": "http://localhost:2990/jira/rest/api/2/issuetype/3", "id": "3", "description": "A task that needs to be done.", "iconUrl": "http://localhost:2990/jira/images/icons/task.gif", "name": "Task", "subtask": false }, "votes": { "self": "http://localhost:2990/jira/rest/api/2/issue/SAMPLEPROJECT-5/votes", "votes": 0, "hasVoted": false }, "resolution": null, "fixVersions": [], "resolutiondate": null, "timespent": null, "reporter": { "self": "http://localhost:2990/jira/rest/api/2/user?username=admin", "name": "admin", "emailAddress": "admin@example.com", "avatarUrls": { "16x16": "http://localhost:2990/jira/secure/useravatar?size=small&avatarId=10122", "48x48": "http://localhost:2990/jira/secure/useravatar?avatarId=10122" }, "displayName": "admin", "active": true }, "aggregatetimeoriginalestimate": null, "updated": "2011-12-14T14:46:58.000+1300", "created": "2011-12-14T14:46:58.000+1300", "description": null, "priority": { "self": "http://localhost:2990/jira/rest/api/2/priority/3", "iconUrl": "http://localhost:2990/jira/images/icons/priority_major.gif", "name": "Major", "id": "3" }, "duedate": null, "issuelinks": [], "watches": { "self": "http://localhost:2990/jira/rest/api/2/issue/SAMPLEPROJECT-5/watchers", "watchCount": 0, "isWatching": false }, "subtasks": [], "status": { "self": "http://localhost:2990/jira/rest/api/2/status/1", "description": "The issue is open and ready for the assignee to start work on it.", "iconUrl": "http://localhost:2990/jira/images/icons/status_open.gif", "name": "Open", "id": "1" }, "labels": [], "assignee": { "self": "http://localhost:2990/jira/rest/api/2/user?username=admin", "name": "admin", "emailAddress": "admin@example.com", "avatarUrls": { "16x16": "http://localhost:2990/jira/secure/useravatar?size=small&avatarId=10122", "48x48": "http://localhost:2990/jira/secure/useravatar?avatarId=10122" }, "displayName": "admin", "active": true }, "workratio": -1, "aggregatetimeestimate": null, "project": { "self": "http://localhost:2990/jira/rest/api/2/project/SAMPLEPROJECT", "id": "10001", "key": "SAMPLEPROJECT", "name": "Sample Project for Developing RoR RESTful API", "avatarUrls": { "16x16": "http://localhost:2990/jira/secure/projectavatar?size=small&pid=10001&avatarId=10011", "48x48": "http://localhost:2990/jira/secure/projectavatar?pid=10001&avatarId=10011" } }, "versions": [], "environment": null, "timeestimate": null, "aggregateprogress": { "progress": 0, "total": 0 }, "components": [], "timeoriginalestimate": null, "aggregatetimespent": null } }, { "expand": "editmeta,renderedFields,transitions,changelog", "id": "10005", "self": "http://localhost:2990/jira/rest/api/2/issue/10005", "key": "SAMPLEPROJECT-4", "fields": { "summary": "blah", "progress": { "progress": 0, "total": 0 }, "issuetype": { "self": "http://localhost:2990/jira/rest/api/2/issuetype/3", "id": "3", "description": "A task that needs to be done.", "iconUrl": "http://localhost:2990/jira/images/icons/task.gif", "name": "Task", "subtask": false }, "votes": { "self": "http://localhost:2990/jira/rest/api/2/issue/SAMPLEPROJECT-4/votes", "votes": 0, "hasVoted": false }, "resolution": null, "fixVersions": [], "resolutiondate": null, "timespent": null, "reporter": { "self": "http://localhost:2990/jira/rest/api/2/user?username=admin", "name": "admin", "emailAddress": "admin@example.com", "avatarUrls": { "16x16": "http://localhost:2990/jira/secure/useravatar?size=small&avatarId=10122", "48x48": "http://localhost:2990/jira/secure/useravatar?avatarId=10122" }, "displayName": "admin", "active": true }, "aggregatetimeoriginalestimate": null, "updated": "2011-12-14T12:11:48.000+1300", "created": "2011-12-14T12:11:48.000+1300", "description": null, "priority": { "self": "http://localhost:2990/jira/rest/api/2/priority/3", "iconUrl": "http://localhost:2990/jira/images/icons/priority_major.gif", "name": "Major", "id": "3" }, "duedate": null, "issuelinks": [], "watches": { "self": "http://localhost:2990/jira/rest/api/2/issue/SAMPLEPROJECT-4/watchers", "watchCount": 0, "isWatching": false }, "subtasks": [], "status": { "self": "http://localhost:2990/jira/rest/api/2/status/1", "description": "The issue is open and ready for the assignee to start work on it.", "iconUrl": "http://localhost:2990/jira/images/icons/status_open.gif", "name": "Open", "id": "1" }, "labels": [], "assignee": { "self": "http://localhost:2990/jira/rest/api/2/user?username=admin", "name": "admin", "emailAddress": "admin@example.com", "avatarUrls": { "16x16": "http://localhost:2990/jira/secure/useravatar?size=small&avatarId=10122", "48x48": "http://localhost:2990/jira/secure/useravatar?avatarId=10122" }, "displayName": "admin", "active": true }, "workratio": -1, "aggregatetimeestimate": null, "project": { "self": "http://localhost:2990/jira/rest/api/2/project/SAMPLEPROJECT", "id": "10001", "key": "SAMPLEPROJECT", "name": "Sample Project for Developing RoR RESTful API", "avatarUrls": { "16x16": "http://localhost:2990/jira/secure/projectavatar?size=small&pid=10001&avatarId=10011", "48x48": "http://localhost:2990/jira/secure/projectavatar?pid=10001&avatarId=10011" } }, "versions": [], "environment": null, "timeestimate": null, "aggregateprogress": { "progress": 0, "total": 0 }, "components": [], "timeoriginalestimate": null, "aggregatetimespent": null } }, { "expand": "editmeta,renderedFields,transitions,changelog", "id": "10002", "self": "http://localhost:2990/jira/rest/api/2/issue/10002", "key": "SAMPLEPROJECT-1", "fields": { "summary": "MOOOOOOARRR NINJAAAA!", "progress": { "progress": 0, "total": 0 }, "issuetype": { "self": "http://localhost:2990/jira/rest/api/2/issuetype/3", "id": "3", "description": "A task that needs to be done.", "iconUrl": "http://localhost:2990/jira/images/icons/task.gif", "name": "Task", "subtask": false }, "votes": { "self": "http://localhost:2990/jira/rest/api/2/issue/SAMPLEPROJECT-1/votes", "votes": 0, "hasVoted": false }, "resolution": null, "fixVersions": [], "resolutiondate": null, "timespent": null, "reporter": { "self": "http://localhost:2990/jira/rest/api/2/user?username=admin", "name": "admin", "emailAddress": "admin@example.com", "avatarUrls": { "16x16": "http://localhost:2990/jira/secure/useravatar?size=small&avatarId=10122", "48x48": "http://localhost:2990/jira/secure/useravatar?avatarId=10122" }, "displayName": "admin", "active": true }, "aggregatetimeoriginalestimate": null, "updated": "2011-12-15T15:37:33.000+1300", "created": "2011-12-14T10:26:06.000+1300", "description": null, "priority": { "self": "http://localhost:2990/jira/rest/api/2/priority/3", "iconUrl": "http://localhost:2990/jira/images/icons/priority_major.gif", "name": "Major", "id": "3" }, "duedate": "2011-12-14", "issuelinks": [], "watches": { "self": "http://localhost:2990/jira/rest/api/2/issue/SAMPLEPROJECT-1/watchers", "watchCount": 0, "isWatching": false }, "subtasks": [], "status": { "self": "http://localhost:2990/jira/rest/api/2/status/1", "description": "The issue is open and ready for the assignee to start work on it.", "iconUrl": "http://localhost:2990/jira/images/icons/status_open.gif", "name": "Open", "id": "1" }, "labels": [], "assignee": { "self": "http://localhost:2990/jira/rest/api/2/user?username=admin", "name": "admin", "emailAddress": "admin@example.com", "avatarUrls": { "16x16": "http://localhost:2990/jira/secure/useravatar?size=small&avatarId=10122", "48x48": "http://localhost:2990/jira/secure/useravatar?avatarId=10122" }, "displayName": "admin", "active": true }, "workratio": -1, "aggregatetimeestimate": null, "project": { "self": "http://localhost:2990/jira/rest/api/2/project/SAMPLEPROJECT", "id": "10001", "key": "SAMPLEPROJECT", "name": "Sample Project for Developing RoR RESTful API", "avatarUrls": { "16x16": "http://localhost:2990/jira/secure/projectavatar?size=small&pid=10001&avatarId=10011", "48x48": "http://localhost:2990/jira/secure/projectavatar?pid=10001&avatarId=10011" } }, "versions": [], "environment": null, "timeestimate": null, "aggregateprogress": { "progress": 0, "total": 0 }, "components": [], "timeoriginalestimate": null, "aggregatetimespent": null } } ] } jira-ruby-1.4.3/spec/mock_responses/project/SAMPLEPROJECT.json0000644000004100000410000000560613167661427024034 0ustar www-datawww-data{ "self": "http://localhost:2990/jira/rest/api/2/project/SAMPLEPROJECT", "id": "10001", "key": "SAMPLEPROJECT", "lead": { "self": "http://localhost:2990/jira/rest/api/2/user?username=admin", "name": "admin", "avatarUrls": { "16x16": "http://localhost:2990/jira/secure/useravatar?size=small&avatarId=10122", "48x48": "http://localhost:2990/jira/secure/useravatar?avatarId=10122" }, "displayName": "admin", "active": true }, "components": [ { "self": "http://localhost:2990/jira/rest/api/2/component/10001", "id": "10001", "name": "Jamflam", "isAssigneeTypeValid": false }, { "self": "http://localhost:2990/jira/rest/api/2/component/10000", "id": "10000", "name": "Jammy", "description": "Description!", "isAssigneeTypeValid": false } ], "issueTypes": [ { "self": "http://localhost:2990/jira/rest/api/2/issuetype/1", "id": "1", "description": "A problem which impairs or prevents the functions of the product.", "iconUrl": "http://localhost:2990/jira/images/icons/bug.gif", "name": "Bug", "subtask": false }, { "self": "http://localhost:2990/jira/rest/api/2/issuetype/2", "id": "2", "description": "A new feature of the product, which has yet to be developed.", "iconUrl": "http://localhost:2990/jira/images/icons/newfeature.gif", "name": "New Feature", "subtask": false }, { "self": "http://localhost:2990/jira/rest/api/2/issuetype/3", "id": "3", "description": "A task that needs to be done.", "iconUrl": "http://localhost:2990/jira/images/icons/task.gif", "name": "Task", "subtask": false }, { "self": "http://localhost:2990/jira/rest/api/2/issuetype/4", "id": "4", "description": "An improvement or enhancement to an existing feature or task.", "iconUrl": "http://localhost:2990/jira/images/icons/improvement.gif", "name": "Improvement", "subtask": false }, { "self": "http://localhost:2990/jira/rest/api/2/issuetype/5", "id": "5", "description": "The sub-task of the issue", "iconUrl": "http://localhost:2990/jira/images/icons/issue_subtask.gif", "name": "Sub-task", "subtask": true } ], "assigneeType": "PROJECT_LEAD", "versions": [], "name": "Sample Project for Developing RoR RESTful API", "roles": { "Users": "http://localhost:2990/jira/rest/api/2/project/SAMPLEPROJECT/role/10000", "Administrators": "http://localhost:2990/jira/rest/api/2/project/SAMPLEPROJECT/role/10002", "Developers": "http://localhost:2990/jira/rest/api/2/project/SAMPLEPROJECT/role/10001" }, "avatarUrls": { "16x16": "http://localhost:2990/jira/secure/projectavatar?size=small&pid=10001&avatarId=10011", "48x48": "http://localhost:2990/jira/secure/projectavatar?pid=10001&avatarId=10011" } } jira-ruby-1.4.3/spec/mock_responses/issue.post.json0000644000004100000410000000015713167661427022466 0ustar www-datawww-data{ "id": "10005", "key": "SAMPLEPROJECT-4", "self": "http://localhost:2990/jira/rest/api/2/issue/10005" } jira-ruby-1.4.3/spec/mock_responses/field/0000755000004100000410000000000013167661427020537 5ustar www-datawww-datajira-ruby-1.4.3/spec/mock_responses/field/1.json0000644000004100000410000000036013167661427021571 0ustar www-datawww-data{ "id": "1", "name": "Description", "custom": false, "orderable": true, "navigable": true, "searchable": true, "clauseNames": [ "description" ], "schema": { "type": "string", "system": "description" } }jira-ruby-1.4.3/spec/mock_responses/jira/0000755000004100000410000000000013167661427020401 5ustar www-datawww-datajira-ruby-1.4.3/spec/mock_responses/jira/rest/0000755000004100000410000000000013167661427021356 5ustar www-datawww-datajira-ruby-1.4.3/spec/mock_responses/jira/rest/webhooks/0000755000004100000410000000000013167661427023177 5ustar www-datawww-datajira-ruby-1.4.3/spec/mock_responses/jira/rest/webhooks/1.0/0000755000004100000410000000000013167661427023475 5ustar www-datawww-datajira-ruby-1.4.3/spec/mock_responses/jira/rest/webhooks/1.0/webhook/0000755000004100000410000000000013167661427025133 5ustar www-datawww-datajira-ruby-1.4.3/spec/mock_responses/jira/rest/webhooks/1.0/webhook/2.json0000644000004100000410000000052613167661427026172 0ustar www-datawww-data{"name":"from API", "url":"http://localhost:3000/webhooks/1", "excludeBody":false, "filters":{"issue-related-events-section":""}, "events":[], "enabled":true, "self":"http://localhost:2990/jira/rest/webhooks/1.0/webhook/2", "lastUpdatedUser":"admin", "lastUpdatedDisplayName":"admin", "lastUpdated":1453306520188 }jira-ruby-1.4.3/spec/mock_responses/jira/rest/webhooks/1.0/webhook.json0000644000004100000410000000053013167661427026024 0ustar www-datawww-data[{"name":"from API", "url":"http://localhost:3000/webhooks/1", "excludeBody":false, "filters":{"issue-related-events-section":""}, "events":[], "enabled":true, "self":"http://localhost:2990/jira/rest/webhooks/1.0/webhook/2", "lastUpdatedUser":"admin", "lastUpdatedDisplayName":"admin", "lastUpdated":1453306520188 }]jira-ruby-1.4.3/spec/mock_responses/version/0000755000004100000410000000000013167661427021141 5ustar www-datawww-datajira-ruby-1.4.3/spec/mock_responses/version/10000.json0000644000004100000410000000041113167661427022470 0ustar www-datawww-data{ "self": "http://localhost:2990/jira/rest/api/2/version/10000", "id": "10000", "description": "Initial version", "name": "1.0", "overdue": false, "userReleaseDate": "12/Jan/12", "archived": false, "releaseDate": "2012-01-12", "released": false } jira-ruby-1.4.3/spec/mock_responses/version/10000.put.json0000644000004100000410000000022213167661427023277 0ustar www-datawww-data{ "self": "http://localhost:2990/jira/rest/api/2/version/10000", "id": "10000", "name": "2.0.0", "archived": false, "released": false } jira-ruby-1.4.3/spec/mock_responses/version/10000.invalid.put.json0000644000004100000410000000036213167661427024731 0ustar www-datawww-data{ "errorMessages": [ "Unrecognized field \"chump\" (Class com.atlassian.jira.rest.v2.issue.version.VersionBean), not marked as ignorable\n at [Source: org.apache.catalina.connector.CoyoteInputStream@4264a42e; line: 1, column: 2]" ] } jira-ruby-1.4.3/spec/mock_responses/resolution/0000755000004100000410000000000013167661427021657 5ustar www-datawww-datajira-ruby-1.4.3/spec/mock_responses/resolution/1.json0000644000004100000410000000041013167661427022705 0ustar www-datawww-data{ "self": "http://www.example.com/jira/rest/api/2/resolution/1", "description": "A fix for this issue is checked into the tree and tested.", "iconUrl": "http://www.example.com/jira/images/icons/status_resolved.gif", "name": "Fixed", "id": "1" }jira-ruby-1.4.3/spec/support/0000755000004100000410000000000013167661427016136 5ustar www-datawww-datajira-ruby-1.4.3/spec/support/matchers/0000755000004100000410000000000013167661427017744 5ustar www-datawww-datajira-ruby-1.4.3/spec/support/matchers/have_many.rb0000644000004100000410000000045513167661427022244 0ustar www-datawww-dataRSpec::Matchers.define :have_many do |collection, klass| match do |actual| expect(actual.send(collection).class).to eq(JIRA::HasManyProxy) expect(actual.send(collection).length).to be > 0 actual.send(collection).each do |member| expect(member.class).to eq(klass) end end end jira-ruby-1.4.3/spec/support/matchers/have_attributes.rb0000644000004100000410000000040413167661427023460 0ustar www-datawww-dataRSpec::Matchers.define :have_attributes do |expected| match do |actual| expected.each do |key, value| expect(actual.attrs[key]).to eq(value) end end failure_message do |actual| "expected #{actual.attrs} to match #{expected}" end end jira-ruby-1.4.3/spec/support/matchers/have_one.rb0000644000004100000410000000021113167661427022047 0ustar www-datawww-dataRSpec::Matchers.define :have_one do |resource, klass| match do |actual| expect(actual.send(resource).class).to eq(klass) end end jira-ruby-1.4.3/spec/support/shared_examples/0000755000004100000410000000000013167661427021302 5ustar www-datawww-datajira-ruby-1.4.3/spec/support/shared_examples/integration.rb0000644000004100000410000001465313167661427024163 0ustar www-datawww-datarequire 'cgi' def get_mock_from_path(method, options = {}) if defined? belongs_to prefix = belongs_to.path_component + '/' else prefix = '' end if options[:url] url = options[:url] elsif options[:key] url = described_class.singular_path(client, options[:key], prefix) else url = described_class.collection_path(client, prefix) end file_path = url.sub(client.options[:rest_base_path], '') file_path = file_path + '.' + options[:suffix] if options[:suffix] file_path = file_path + '.' + method.to_s unless method == :get value_if_not_found = options.keys.include?(:value_if_not_found) ? options[:value_if_not_found] : false get_mock_response("#{file_path}.json", value_if_not_found) end def class_basename described_class.name.split('::').last end def options options = {} if defined? belongs_to options[belongs_to.to_sym] = belongs_to end options end def prefix prefix = '/' if defined? belongs_to prefix = belongs_to.path_component + '/' end prefix end def build_receiver if defined?(belongs_to) belongs_to.send(described_class.endpoint_name.pluralize.to_sym) else client.send(class_basename) end end shared_examples "a resource" do it "gracefully handles non-json responses" do if defined? target subject = target else subject = client.send(class_basename).build(described_class.key_attribute.to_s => '99999') end stub_request(:put, site_url + subject.url). to_return(:status => 405, :body => "Some HTML") expect(subject.save('foo' => 'bar')).to be_falsey expect(lambda do expect(subject.save!('foo' => 'bar')).to be_falsey end).to raise_error(JIRA::HTTPError) end end shared_examples "a resource with a collection GET endpoint" do it "should get the collection" do stub_request(:get, site_url + described_class.collection_path(client)). to_return(:status => 200, :body => get_mock_from_path(:get)) collection = build_receiver.all expect(collection.length).to eq(expected_collection_length) expect(collection.first).to have_attributes(expected_attributes) end end shared_examples "a resource with JQL inputs and a collection GET endpoint" do it "should get the collection" do stub_request( :get, site_url + client.options[:rest_base_path] + '/search?jql=' + CGI.escape(jql_query_string) ).to_return(:status => 200, :body => get_mock_response('issue.json')) collection = build_receiver.jql(jql_query_string) expect(collection.length).to eq(expected_collection_length) expect(collection.first).to have_attributes(expected_attributes) end end shared_examples "a resource with a singular GET endpoint" do it "GETs a single resource" do # E.g., for JIRA::Resource::Project, we need to call # client.Project.find() stub_request(:get, site_url + described_class.singular_path(client, key, prefix)). to_return(:status => 200, :body => get_mock_from_path(:get, :key => key)) subject = client.send(class_basename).find(key, options) expect(subject).to have_attributes(expected_attributes) end it "builds and fetches a single resource" do # E.g., for JIRA::Resource::Project, we need to call # client.Project.build('key' => 'ABC123') stub_request(:get, site_url + described_class.singular_path(client, key, prefix)). to_return(:status => 200, :body => get_mock_from_path(:get, :key => key)) subject = build_receiver.build(described_class.key_attribute.to_s => key) subject.fetch expect(subject).to have_attributes(expected_attributes) end it "handles a 404" do stub_request(:get, site_url + described_class.singular_path(client, '99999', prefix)). to_return(:status => 404, :body => '{"errorMessages":["'+class_basename+' Does Not Exist"],"errors": {}}') expect( lambda do client.send(class_basename).find('99999', options) end).to raise_exception(JIRA::HTTPError) end end shared_examples "a resource with a DELETE endpoint" do it "deletes a resource" do # E.g., for JIRA::Resource::Project, we need to call # client.Project.delete() stub_request(:delete, site_url + described_class.singular_path(client, key, prefix)). to_return(:status => 204, :body => nil) subject = build_receiver.build(described_class.key_attribute.to_s => key) expect(subject.delete).to be_truthy end end shared_examples "a resource with a POST endpoint" do it "saves a new resource" do stub_request(:post, site_url + described_class.collection_path(client, prefix)). to_return(:status => 201, :body => get_mock_from_path(:post)) subject = build_receiver.build expect(subject.save(attributes_for_post)).to be_truthy expected_attributes_from_post.each do |method_name, value| expect(subject.send(method_name)).to eq(value) end end end shared_examples "a resource with a PUT endpoint" do it "saves an existing component" do stub_request(:get, site_url + described_class.singular_path(client, key, prefix)). to_return(:status => 200, :body => get_mock_from_path(:get, :key =>key)) stub_request(:put, site_url + described_class.singular_path(client, key, prefix)). to_return(:status => 200, :body => get_mock_from_path(:put, :key => key, :value_if_not_found => nil)) subject = build_receiver.build(described_class.key_attribute.to_s => key) subject.fetch expect(subject.save(attributes_for_put)).to be_truthy expected_attributes_from_put.each do |method_name, value| expect(subject.send(method_name)).to eq(value) end end end shared_examples 'a resource with a PUT endpoint that rejects invalid fields' do it "fails to save with an invalid field" do stub_request(:get, site_url + described_class.singular_path(client, key)). to_return(:status => 200, :body => get_mock_from_path(:get, :key => key)) stub_request(:put, site_url + described_class.singular_path(client, key)). to_return(:status => 400, :body => get_mock_from_path(:put, :key => key, :suffix => "invalid")) subject = client.send(class_basename).build(described_class.key_attribute.to_s => key) subject.fetch expect(subject.save('fields'=> {'invalid' => 'field'})).to be_falsey expect(lambda do subject.save!('fields'=> {'invalid' => 'field'}) end).to raise_error(JIRA::HTTPError) end end jira-ruby-1.4.3/spec/support/clients_helper.rb0000644000004100000410000000101213167661427021455 0ustar www-datawww-datamodule ClientsHelper def with_each_client clients = {} oauth_client = JIRA::Client.new({ :consumer_key => 'foo', :consumer_secret => 'bar' }) oauth_client.set_access_token('abc', '123') clients["http://localhost:2990"] = oauth_client basic_client = JIRA::Client.new({ :username => 'foo', :password => 'bar', :auth_type => :basic, :use_ssl => false }) clients["http://foo:bar@localhost:2990"] = basic_client clients.each do |site_url, client| yield site_url, client end end end jira-ruby-1.4.3/spec/jira/0000755000004100000410000000000013167661427015347 5ustar www-datawww-datajira-ruby-1.4.3/spec/jira/resource/0000755000004100000410000000000013167661427017176 5ustar www-datawww-datajira-ruby-1.4.3/spec/jira/resource/user_factory_spec.rb0000644000004100000410000000140613167661427023243 0ustar www-datawww-datarequire 'spec_helper' describe JIRA::Resource::UserFactory do let(:client) { instance_double('Client', options: { rest_base_path: '/jira/rest/api/2' }) } subject { JIRA::Resource::UserFactory.new(client) } describe "#myself" do let(:response) { instance_double( 'Response', body: get_mock_response('user_username=admin.json') ) } let(:user) { subject.myself } before(:each) do allow(client).to receive(:get).with( '/jira/rest/api/2/myself' ).and_return(response) end it "returns a JIRA::Resource::User with correct attrs" do expect(user).to be_a(JIRA::Resource::User) expect(user.name).to eq('admin') expect(user.emailAddress).to eq('admin@example.com') end end end jira-ruby-1.4.3/spec/jira/resource/attachment_spec.rb0000644000004100000410000000443613167661427022674 0ustar www-datawww-datarequire 'spec_helper' describe JIRA::Resource::Attachment do let(:client) { double( 'client', :options => { :rest_base_path => '/jira/rest/api/2' }, :request_client => double( :options => { :username => 'username', :password => 'password' } ) ) } describe "relationships" do subject { JIRA::Resource::Attachment.new(client, :issue => JIRA::Resource::Issue.new(client), :attrs => { 'author' => {'foo' => 'bar'} }) } it "has the correct relationships" do expect(subject).to have_one(:author, JIRA::Resource::User) expect(subject.author.foo).to eq('bar') end end describe '#meta' do let(:response) { double( 'response', :body => '{"enabled":true,"uploadLimit":10485760}' ) } it 'returns meta information about attachment upload' do expect(client).to receive(:get).with('/jira/rest/api/2/attachment/meta').and_return(response) JIRA::Resource::Attachment.meta(client) end subject { JIRA::Resource::AttachmentFactory.new(client) } it 'delegates #meta to to target class' do expect(subject).to respond_to(:meta) end end describe '#save!' do it 'successfully update the attachment' do basic_auth_http_conn = double() response = double( body: [ { "id": 10001, "self": "http://www.example.com/jira/rest/api/2.0/attachments/10000", "filename": "picture.jpg", "created": "2017-07-19T12:23:06.572+0000", "size": 23123, "mimeType": "image/jpeg", } ].to_json ) allow(client.request_client).to receive(:basic_auth_http_conn).and_return(basic_auth_http_conn) allow(basic_auth_http_conn).to receive(:request).and_return(response) issue = JIRA::Resource::Issue.new(client) path_to_file = './spec/mock_responses/issue.json' attachment = JIRA::Resource::Attachment.new(client, issue: issue) attachment.save!('file' => path_to_file) expect(attachment.filename).to eq 'picture.jpg' expect(attachment.mimeType).to eq 'image/jpeg' expect(attachment.size).to eq 23123 end end end jira-ruby-1.4.3/spec/jira/resource/agile_spec.rb0000644000004100000410000001343513167661427021624 0ustar www-datawww-datarequire 'spec_helper' describe JIRA::Resource::Agile do let(:client) do client = double(options: {rest_base_path: '/jira/rest/api/2', context_path: '/jira'}) allow(client).to receive(:Issue).and_return(JIRA::Resource::IssueFactory.new(client)) client end let(:response) { double } describe '#all' do it 'should query url without parameters' do expect(client).to receive(:get).with('/jira/rest/agile/1.0/board').and_return(response) expect(response).to receive(:body).and_return(get_mock_response('board/1.json')) JIRA::Resource::Agile.all(client) end end describe '#get_backlog_issues' do it 'should query the url without parameters' do expect(client).to receive(:get).with('/jira/rest/agile/1.0/board/1/backlog?maxResults=100').and_return(response) expect(response).to receive(:body).and_return(get_mock_response('board/1.json')) JIRA::Resource::Agile.get_backlog_issues(client, 1) end end describe '#get_board_issues' do it 'should query correct url without parameters' do expect(client).to receive(:get).with('/jira/rest/agile/1.0/board/1/issue?').and_return(response) expect(response).to receive(:body).and_return(get_mock_response('board/1_issues.json')) expect(client).to receive(:get).with('/jira/rest/api/2/search?jql=id+IN%2810546%2C+10547%2C+10556%2C+10557%2C+10558%2C+10559%2C+10600%2C+10601%2C+10604%29').and_return(response) expect(response).to receive(:body).and_return(get_mock_response('board/1_issues.json')) issues = JIRA::Resource::Agile.get_board_issues(client, 1) expect(issues).to be_an(Array) expect(issues.size).to eql(9) issues.each do |issue| expect(issue.class).to eq(JIRA::Resource::Issue) expect(issue.expanded?).to be_falsey end end it 'should query correct url with parameters' do expect(client).to receive(:get).with('/jira/rest/agile/1.0/board/1/issue?startAt=50').and_return(response) expect(response).to receive(:body).and_return(get_mock_response('board/1_issues.json')) expect(client).to receive(:get).with('/jira/rest/api/2/search?jql=id+IN%2810546%2C+10547%2C+10556%2C+10557%2C+10558%2C+10559%2C+10600%2C+10601%2C+10604%29').and_return(response) expect(response).to receive(:body).and_return(get_mock_response('board/1_issues.json')) issues = JIRA::Resource::Agile.get_board_issues(client, 1, startAt: 50) expect(issues).to be_an(Array) expect(issues.size).to eql(9) issues.each do |issue| expect(issue.class).to eq(JIRA::Resource::Issue) expect(issue.expanded?).to be_falsey end end end describe '#get_sprints' do it 'should query correct url without parameters' do expect(client).to receive(:get).with('/jira/rest/agile/1.0/board/1/sprint?maxResults=100').and_return(response) expect(response).to receive(:body).and_return(get_mock_response('board/1.json')) JIRA::Resource::Agile.get_sprints(client, 1) end it 'should query correct url with parameters' do expect(client).to receive(:get).with('/jira/rest/agile/1.0/board/1/sprint?startAt=50&maxResults=100').and_return(response) expect(response).to receive(:body).and_return(get_mock_response('board/1.json')) JIRA::Resource::Agile.get_sprints(client, 1, startAt: 50) end it 'should work with pagination starting at 0' do expect(client).to receive(:get).with('/jira/rest/agile/1.0/board/1/sprint?maxResults=1&startAt=0').and_return(response) expect(response).to receive(:body).and_return(get_mock_response('board/1.json')) JIRA::Resource::Agile.get_sprints(client, 1, maxResults: 1, startAt: 0) end it 'should work with pagination not starting at 0' do expect(client).to receive(:get).with('/jira/rest/agile/1.0/board/1/sprint?maxResults=1&startAt=1').and_return(response) expect(response).to receive(:body).and_return(get_mock_response('board/1.json')) JIRA::Resource::Agile.get_sprints(client, 1, maxResults: 1, startAt: 1) end end describe '#get_sprint_issues' do it 'should query correct url without parameters' do expect(client).to receive(:get).with('/jira/rest/agile/1.0/sprint/1/issue?maxResults=100').and_return(response) expect(response).to receive(:body).and_return(get_mock_response('sprint/1_issues.json')) JIRA::Resource::Agile.get_sprint_issues(client, 1) end it 'should query correct url with parameters' do expect(client).to receive(:get).with('/jira/rest/agile/1.0/sprint/1/issue?startAt=50&maxResults=100').and_return(response) expect(response).to receive(:body).and_return(get_mock_response('sprint/1_issues.json')) JIRA::Resource::Agile.get_sprint_issues(client, 1, startAt: 50) end end describe '#get_projects_full' do it 'should query correct url without parameters' do expect(client).to receive(:get).with('/jira/rest/agile/1.0/board/1/project/full').and_return(response) expect(response).to receive(:body).and_return(get_mock_response('board/1.json')) JIRA::Resource::Agile.get_projects_full(client, 1) end end describe '#get_projects' do it 'should query correct url without parameters' do expect(client).to receive(:get).with('/jira/rest/agile/1.0/board/1/project?maxResults=100').and_return(response) expect(response).to receive(:body).and_return(get_mock_response('board/1.json')) JIRA::Resource::Agile.get_projects(client, 1) end it 'should query correct url with parameters' do expect(client).to receive(:get).with('/jira/rest/agile/1.0/board/1/project?startAt=50&maxResults=100').and_return(response) expect(response).to receive(:body).and_return(get_mock_response('board/1.json')) JIRA::Resource::Agile.get_projects(client, 1, startAt: 50) end end end jira-ruby-1.4.3/spec/jira/resource/field_spec.rb0000644000004100000410000001262713167661427021630 0ustar www-datawww-datarequire 'spec_helper' describe JIRA::Resource::Field do let(:cache) { OpenStruct.new } let(:client) do client = double(options: {rest_base_path: '/jira/rest/api/2'} ) field = JIRA::Resource::FieldFactory.new(client) allow(client).to receive(:Field).and_return(field) allow(client).to receive(:cache).and_return(cache) # info about all fields on the client allow(client.Field).to receive(:all).and_return([ JIRA::Resource::Field.new(client, :attrs => {'id' =>"customfield_10666", "name" => "Priority", "custom" => true, "orderable" => true, "navigable" => true, "searchable" => true, "clauseNames" => ["cf[10666]","Priority"], "schema" =>{"type" => "string", "custom" => "com.atlassian.jira.plugin.system.customfieldtypes:select","customId" => 10666}}), JIRA::Resource::Field.new(client, :attrs => {'id' =>"issuekey", "name" => "Key", "custom" => false, "orderable" => false, "navigable" => true, "searchable" => false, "clauseNames" => ["id","issue","issuekey","key"]}), JIRA::Resource::Field.new(client, :attrs => {'id' =>"priority", "name" => "Priority", "custom" => false, "orderable" => true, "navigable" => true, "searchable" => true, "clauseNames" => ["priority"], "schema" =>{"type" => "priority", "system" => "priority"}}), JIRA::Resource::Field.new(client, :attrs => {'id' =>"summary", "name" => "Summary", "custom" => false, "orderable" => true, "navigable" => true, "searchable" => true, "clauseNames" => ["summary"], "schema" =>{"type" => "string", "system" => "summary"}}), JIRA::Resource::Field.new(client, :attrs => {'id' =>"issuetype", "name" => "Issue Type", "custom" => false, "orderable" => true, "navigable" => true, "searchable" => true, "clauseNames" => ["issuetype","type"], "schema" =>{"type" => "issuetype", "system" => "issuetype"}}), JIRA::Resource::Field.new(client, :attrs => {'id' =>"customfield_10111", "name" => "SingleWord", "custom" => true, "orderable" => true, "navigable" => true, "searchable" => true, "clauseNames" => ["cf[10111]","SingleWord"], "schema" =>{"type" => "string", "custom" => "com.atlassian.jira.plugin.system.customfieldtypes:select","customId" => 10111}}), JIRA::Resource::Field.new(client, :attrs => {'id' =>"customfield_10222", "name" => "Multi Word", "custom" => true, "orderable" => true, "navigable" => true, "searchable" => true, "clauseNames" => ["cf[10222]","Multi Word"], "schema" =>{"type" => "string", "custom" => "com.atlassian.jira.plugin.system.customfieldtypes:select","customId" => 10222}}), JIRA::Resource::Field.new(client, :attrs => {'id' =>"customfield_10333", "name" => "Why/N@t", "custom" => true, "orderable" => true, "navigable" => true, "searchable" => true, "clauseNames" => ["cf[10333]","Why/N@t"], "schema" =>{"type" => "string", "custom" => "com.atlassian.jira.plugin.system.customfieldtypes:select","customId" => 10333}}), JIRA::Resource::Field.new(client, :attrs => {'id' =>"customfield_10444", "name" => "SingleWord", "custom" => true, "orderable" => true, "navigable" => true, "searchable" => true, "clauseNames" => ["cf[10444]","SingleWord"], "schema" =>{"type" => "string", "custom" => "com.atlassian.jira.plugin.system.customfieldtypes:select","customId" => 10444}}) ]) client end describe "field_mappings" do shared_context "mapped or not" do subject { JIRA::Resource::Field.new(client, :attrs => { 'priority' => 1, 'customfield_10111' => 'data_in_custom_field', 'customfield_10222' => 'multi word custom name', 'customfield_10333' => 'complex custom name', 'customfield_10444' => 'duplicated custom name', 'customfield_10666' => 'duplicate of a system name', }) } it "can find a standard field by id" do expect(subject.priority).to eq(1) end it "can find a custom field by customfield_##### name" do expect(subject.customfield_10111).to eq('data_in_custom_field') end it "is not confused by common attribute keys" do expect{subject.name}.to raise_error(NoMethodError) expect{subject.custom}.to raise_error(NoMethodError) expect(subject.id).to eq(nil) # picks up ID from the parent - end end context "before fields are mapped" do include_context "mapped or not" it "can find a standard field by id" do expect(subject.priority).to eq(1) end it "cannot find a standard field by name before mapping" do expect{subject.Priority}.to raise_error(NoMethodError) end it "can find a custom field by customfield_##### name" do expect(subject.customfield_10111).to eq('data_in_custom_field') end it "is not confused by common attribute keys and raises error" do expect{subject.name}.to raise_error(NoMethodError) expect{subject.custom}.to raise_error(NoMethodError) expect(subject.id).to eq(nil) # picks up ID from the parent - end end context "after fields are mapped" do include_context "mapped or not" it "warns of duplicate fields" do expect{client.Field.map_fields}.to output(/renaming as Priority_10666/).to_stderr expect{client.Field.map_fields}.to output(/renaming as SingleWord_10444/).to_stderr end end end end jira-ruby-1.4.3/spec/jira/resource/filter_spec.rb0000644000004100000410000000560613167661427022031 0ustar www-datawww-datarequire 'spec_helper' describe JIRA::Resource::Filter do let(:client) do client = double() allow(client).to receive(:Issue).and_return(JIRA::Resource::IssueFactory.new(self)) client end let(:collection_path) { '/rest/api/2/filter' } let(:jira_user) do { :self => "https://localhost/rest/api/2/user?username=ljharb", :name => 'ljharb', :avatarUrls => { '16x16' => 'https://localhost/secure/useravatar?size=small&ownerId=ljharb&avatarId=1', '48x48' => 'https://localhost/secure/useravatar?ownerId=ljharb&avatarId=1' }, :displayName => 'Jordan Harband', :active => true } end let(:filter_attrs) do { :self => "https://localhost#{collection_path}/42", :id => 42, :name => 'Resolved Tickets', :description => '', :owner => jira_user, :jql => '"Git Repository" ~ jira-ruby AND status = Resolved', :viewUrl => 'https://localhost/secure/IssueNavigator.jspa?mode=hide&requestId=42', :searchUrl => 'https://localhost/rest/api/2/search?jql=%22Git+Repository%22+~+jira-ruby+AND+status+%3D+Resolved', :favourite => false, :sharePermissions => [ { :id => 123, :type => 'global' } ], :subscriptions => { :size => 0, :items => [] } } end let(:filter_response) do response = double() allow(response).to receive(:body).and_return(filter_attrs.to_json) response end let(:filter) do expect(client).to receive(:get).with("#{collection_path}/42").and_return(filter_response) allow(JIRA::Resource::Filter).to receive(:collection_path).and_return(collection_path) JIRA::Resource::Filter.find(client, 42) end let(:jql_issue) do { :id => '663147', :self => 'https://localhost/rest/api/2/issue/663147', :key => "JIRARUBY-2386", :fields => { :reporter => jira_user, :created => '2013-12-11T23:28:02.000+0000', :assignee => jira_user } } end let(:jql_attrs) do { :startAt => 0, :maxResults => 50, :total => 2, :issues => [jql_issue] } end let(:issue_jql_response) do response = double() allow(response).to receive(:body).and_return(jql_attrs.to_json) response end it "can be found by ID" do expect(JSON.parse(filter.attrs.to_json)).to eql(JSON.parse(filter_attrs.to_json)) end it "returns issues" do expect(filter).to be_present allow(client).to receive(:options).and_return({ :rest_base_path => 'localhost' }) expect(client).to receive(:get). with("localhost/search?jql=#{CGI.escape(filter.jql)}"). and_return(issue_jql_response) issues = filter.issues expect(issues).to be_an(Array) expect(issues.size).to eql(1) expected_issue = client.Issue.build(JSON.parse(jql_issue.to_json)) expect(issues.first.attrs).to eql(expected_issue.attrs) end end jira-ruby-1.4.3/spec/jira/resource/project_factory_spec.rb0000644000004100000410000000046413167661427023736 0ustar www-datawww-datarequire 'spec_helper' describe JIRA::Resource::ProjectFactory do let(:client) { double() } subject { JIRA::Resource::ProjectFactory.new(client) } it "initializes correctly" do expect(subject.class).to eq(JIRA::Resource::ProjectFactory) expect(subject.client).to eq(client) end end jira-ruby-1.4.3/spec/jira/resource/issuelink_spec.rb0000644000004100000410000000035713167661427022550 0ustar www-datawww-data# require 'spec_helper' # # describe JIRA::Resource::Issuelink do # let(:client) { double() } # # describe "links" do # subject { # JIRA::Resource::Issuelink.new(client, :attrs => { # # } # ) # } # end # endjira-ruby-1.4.3/spec/jira/resource/project_spec.rb0000644000004100000410000001051213167661427022202 0ustar www-datawww-datarequire 'spec_helper' describe JIRA::Resource::Project do let(:client) { double("client", :options => { :rest_base_path => '/jira/rest/api/2' }) } describe "relationships" do subject { JIRA::Resource::Project.new(client, :attrs => { 'lead' => {'foo' => 'bar'}, 'issueTypes' => [{'foo' =>'bar'},{'baz' => 'flum'}], 'versions' => [{'foo' =>'bar'},{'baz' => 'flum'}], }) } it "has the correct relationships" do expect(subject).to have_one(:lead, JIRA::Resource::User) expect(subject.lead.foo).to eq('bar') expect(subject).to have_many(:issuetypes, JIRA::Resource::Issuetype) expect(subject.issuetypes.length).to eq(2) expect(subject).to have_many(:versions, JIRA::Resource::Version) expect(subject.versions.length).to eq(2) end end describe "issues" do subject { JIRA::Resource::Project.new(client, :attrs => { 'key' => 'test' }) } it "returns issues" do response_body = '{"expand":"schema,names","startAt":0,"maxResults":1,"total":1,"issues":[{"expand":"editmeta,renderedFields,transitions,changelog,operations","id":"53062","self":"/rest/api/2/issue/53062","key":"test key","fields":{"summary":"test summary"}}]}' response = double("response", :body => response_body) issue_factory = double("issue factory") expect(client).to receive(:get) .with('/jira/rest/api/2/search?jql=project%3D%22test%22') .and_return(response) expect(client).to receive(:Issue).and_return(issue_factory) expect(issue_factory).to receive(:build) .with(JSON.parse(response_body)["issues"][0]) subject.issues end context "with changelog" do it "returns issues" do response_body = '{"expand":"schema,names","startAt":0,"maxResults":1,"total":1,"issues":[{"expand":"editmeta,renderedFields,transitions,changelog,operations","id":"53062","self":"/rest/api/2/issue/53062","key":"test key","fields":{"summary":"test summary"},"changelog":{}}]}' response = double("response", :body => response_body) issue_factory = double("issue factory") expect(client).to receive(:get) .with('/jira/rest/api/2/search?jql=project%3D%22test%22&expand=changelog&startAt=1&maxResults=100') .and_return(response) expect(client).to receive(:Issue).and_return(issue_factory) expect(issue_factory).to receive(:build) .with(JSON.parse(response_body)["issues"][0]) subject.issues({expand:'changelog', startAt:1, maxResults:100}) end end end describe 'users' do let(:project) { JIRA::Resource::Project.new(client, attrs: { 'key' => project_key }) } let(:project_key) { SecureRandom.hex } let(:response) { double('response', body: '[{}]') } context 'pagination' do before(:each) do user_factory = double('user factory') expect(client).to receive(:User).and_return(user_factory) expect(user_factory).to receive(:build).with(any_args) end it 'doesn\'t use pagination parameters by default' do expect(client).to receive(:get) .with("/jira/rest/api/2/user/assignable/search?project=#{project_key}") .and_return(response) project.users end it 'accepts start_at option' do start_at = rand(1000) expect(client).to receive(:get) .with("/jira/rest/api/2/user/assignable/search?project=#{project_key}&startAt=#{start_at}") .and_return(response) project.users(start_at: start_at) end it 'accepts max_results option' do max_results = rand(1000) expect(client).to receive(:get) .with("/jira/rest/api/2/user/assignable/search?project=#{project_key}&maxResults=#{max_results}") .and_return(response) project.users(max_results: max_results) end it 'accepts start_at and max_results options' do start_at = rand(1000) max_results = rand(1000) expect(client).to receive(:get) .with("/jira/rest/api/2/user/assignable/search?project=#{project_key}&startAt=#{start_at}&maxResults=#{max_results}") .and_return(response) project.users(start_at: start_at, max_results: max_results) end end end end jira-ruby-1.4.3/spec/jira/resource/issue_spec.rb0000644000004100000410000002045413167661427021672 0ustar www-datawww-datarequire 'spec_helper' describe JIRA::Resource::Issue do class JIRAResourceDelegation < SimpleDelegator # :nodoc: end let(:client) do client = double(options: {rest_base_path: '/jira/rest/api/2'} ) allow(client).to receive(:Field).and_return(JIRA::Resource::FieldFactory.new(client)) allow(client).to receive(:cache).and_return(OpenStruct.new) client end describe "#respond_to?" do describe "when decorated by SimpleDelegator" do before(:each) do response = double() allow(response).to receive(:body).and_return('{"key":"foo","id":"101"}') allow(JIRA::Resource::Issue).to receive(:collection_path).and_return('/jira/rest/api/2/issue') allow(client).to receive(:get).with('/jira/rest/api/2/issue/101'). and_return(response) issue = JIRA::Resource::Issue.find(client,101) @decorated = JIRAResourceDelegation.new( issue ) end it "responds to key" do expect(@decorated.respond_to?(:key)).to eq(true) end it "does not raise an error" do expect { @issue.respond_to?(:project) }.not_to raise_error end end end it "should find all issues" do response = double() issue = double() allow(response).to receive(:body).and_return('{"issues":[{"id":"1","summary":"Bugs Everywhere"}]}') expect(client).to receive(:get).with('/jira/rest/api/2/search?expand=transitions.fields'). and_return(response) expect(client).to receive(:Issue).and_return(issue) expect(issue).to receive(:build).with({"id"=>"1","summary"=>"Bugs Everywhere"}) issues = JIRA::Resource::Issue.all(client) end it "should find an issue by key or id" do response = double() allow(response).to receive(:body).and_return('{"key":"foo","id":"101"}') allow(JIRA::Resource::Issue).to receive(:collection_path).and_return('/jira/rest/api/2/issue') expect(client).to receive(:get).with('/jira/rest/api/2/issue/foo'). and_return(response) expect(client).to receive(:get).with('/jira/rest/api/2/issue/101'). and_return(response) issue_from_id = JIRA::Resource::Issue.find(client,101) issue_from_key = JIRA::Resource::Issue.find(client,'foo') expect(issue_from_id.attrs).to eq(issue_from_key.attrs) end it "should search an issue with a jql query string" do response = double() issue = double() allow(response).to receive(:body).and_return('{"issues": {"key":"foo"}}') expect(client).to receive(:get).with('/jira/rest/api/2/search?jql=foo+bar'). and_return(response) expect(client).to receive(:Issue).and_return(issue) expect(issue).to receive(:build).with(["key", "foo"]).and_return('') expect(JIRA::Resource::Issue.jql(client,'foo bar')).to eq(['']) end it "should search an issue with a jql query string and fields" do response = double() issue = double() allow(response).to receive(:body).and_return('{"issues": {"key":"foo"}}') expect(client).to receive(:get) .with('/jira/rest/api/2/search?jql=foo+bar&fields=foo,bar') .and_return(response) expect(client).to receive(:Issue).and_return(issue) expect(issue).to receive(:build).with(["key", "foo"]).and_return('') expect(JIRA::Resource::Issue.jql(client, 'foo bar', fields: ['foo','bar'])).to eq(['']) end it "should search an issue with a jql query string, start at, and maxResults" do response = double() issue = double() allow(response).to receive(:body).and_return('{"issues": {"key":"foo"}}') expect(client).to receive(:get) .with('/jira/rest/api/2/search?jql=foo+bar&startAt=1&maxResults=3') .and_return(response) expect(client).to receive(:Issue).and_return(issue) expect(issue).to receive(:build).with(["key", "foo"]).and_return('') expect(JIRA::Resource::Issue.jql(client,'foo bar', start_at: 1, max_results: 3)).to eq(['']) end it "should search an issue with a jql query string and maxResults equals zero and should return the count of tickets" do response = double() issue = double() allow(response).to receive(:body).and_return('{"total": 1, "issues": []}') expect(client).to receive(:get) .with('/jira/rest/api/2/search?jql=foo+bar&maxResults=0') .and_return(response) expect(JIRA::Resource::Issue.jql(client,'foo bar', max_results: 0)).to eq(1) end it "should search an issue with a jql query string and string expand" do response = double() issue = double() allow(response).to receive(:body).and_return('{"issues": {"key":"foo"}}') expect(client).to receive(:get) .with('/jira/rest/api/2/search?jql=foo+bar&expand=transitions') .and_return(response) expect(client).to receive(:Issue).and_return(issue) expect(issue).to receive(:build).with(["key", "foo"]).and_return('') expect(JIRA::Resource::Issue.jql(client,'foo bar', expand: 'transitions')).to eq(['']) end it "should search an issue with a jql query string and array expand" do response = double() issue = double() allow(response).to receive(:body).and_return('{"issues": {"key":"foo"}}') expect(client).to receive(:get) .with('/jira/rest/api/2/search?jql=foo+bar&expand=transitions') .and_return(response) expect(client).to receive(:Issue).and_return(issue) expect(issue).to receive(:build).with(["key", "foo"]).and_return('') expect(JIRA::Resource::Issue.jql(client,'foo bar', expand: %w(transitions))).to eq(['']) end it 'should return meta data available for editing an issue' do subject = JIRA::Resource::Issue.new(client, :attrs => {'fields' => {'key' =>'TST=123'}}) response = double() allow(response).to receive(:body).and_return( '{"fields":{"summary":{"required":true,"name":"Summary","operations":["set"]}}}' ) expect(client).to receive(:get) .with('/jira/rest/api/2/issue/TST=123/editmeta') .and_return(response) expect(subject.editmeta).to eq({'summary' => {'required' => true, 'name' => 'Summary', 'operations' => ['set']}}) end it "provides direct accessors to the fields" do subject = JIRA::Resource::Issue.new(client, :attrs => {'fields' => {'foo' =>'bar'}}) expect(subject).to respond_to(:foo) expect(subject.foo).to eq('bar') end describe "relationships" do subject { JIRA::Resource::Issue.new(client, :attrs => { 'id' => '123', 'fields' => { 'reporter' => {'foo' => 'bar'}, 'assignee' => {'foo' => 'bar'}, 'project' => {'foo' => 'bar'}, 'priority' => {'foo' => 'bar'}, 'issuetype' => {'foo' => 'bar'}, 'status' => {'foo' => 'bar'}, 'components' => [{'foo' => 'bar'}, {'baz' => 'flum'}], 'versions' => [{'foo' => 'bar'}, {'baz' => 'flum'}], 'comment' => { 'comments' => [{'foo' => 'bar'}, {'baz' => 'flum'}]}, 'attachment' => [{'foo' => 'bar'}, {'baz' => 'flum'}], 'worklog' => { 'worklogs' => [{'foo' => 'bar'}, {'baz' => 'flum'}]}, } }) } it "has the correct relationships" do expect(subject).to have_one(:reporter, JIRA::Resource::User) expect(subject.reporter.foo).to eq('bar') expect(subject).to have_one(:assignee, JIRA::Resource::User) expect(subject.assignee.foo).to eq('bar') expect(subject).to have_one(:project, JIRA::Resource::Project) expect(subject.project.foo).to eq('bar') expect(subject).to have_one(:issuetype, JIRA::Resource::Issuetype) expect(subject.issuetype.foo).to eq('bar') expect(subject).to have_one(:priority, JIRA::Resource::Priority) expect(subject.priority.foo).to eq('bar') expect(subject).to have_one(:status, JIRA::Resource::Status) expect(subject.status.foo).to eq('bar') expect(subject).to have_many(:components, JIRA::Resource::Component) expect(subject.components.length).to eq(2) expect(subject).to have_many(:comments, JIRA::Resource::Comment) expect(subject.comments.length).to eq(2) expect(subject).to have_many(:attachments, JIRA::Resource::Attachment) expect(subject.attachments.length).to eq(2) expect(subject).to have_many(:versions, JIRA::Resource::Version) expect(subject.attachments.length).to eq(2) expect(subject).to have_many(:worklogs, JIRA::Resource::Worklog) expect(subject.worklogs.length).to eq(2) end end end jira-ruby-1.4.3/spec/jira/resource/createmeta_spec.rb0000644000004100000410000002344713167661427022661 0ustar www-datawww-datarequire 'spec_helper' describe JIRA::Resource::Createmeta do let(:client) { double( 'client', :options => { :rest_base_path => '/jira/rest/api/2' } ) } let(:response) { double( 'response', :body => '{"expand":"projects","projects":[{"self":"http://localhost:2029/rest/api/2/project/TST","id":"10200","key":"test_key","name":"Test Name"}]}' ) } describe 'general' do it 'should query correct url without parameters' do expect(client).to receive(:get).with('/jira/rest/api/2/issue/createmeta').and_return(response) JIRA::Resource::Createmeta.all(client) end it 'should query correct url with `expand` parameter' do expect(client).to receive(:get).with('/jira/rest/api/2/issue/createmeta?expand=projects.issuetypes.fields').and_return(response) JIRA::Resource::Createmeta.all(client, :expand => 'projects.issuetypes.fields') end it 'should query correct url with `foo` parameter' do expect(client).to receive(:get).with('/jira/rest/api/2/issue/createmeta?foo=bar').and_return(response) JIRA::Resource::Createmeta.all(client, :foo => 'bar') end it 'should return an array of createmeta objects' do expect(client).to receive(:get).with('/jira/rest/api/2/issue/createmeta').and_return(response) createmetas = JIRA::Resource::Createmeta.all(client) expect(createmetas).to be_an Array createmeta = createmetas.first expect(createmeta.id).to eq '10200' expect(createmeta.key).to eq 'test_key' expect(createmeta.name).to eq 'Test Name' end end describe 'projectKeys' do it 'should query correct url when only one `projectKeys` given as string' do expect(client).to receive(:get).with('/jira/rest/api/2/issue/createmeta?projectKeys=PROJECT_1').and_return(response) JIRA::Resource::Createmeta.all( client, :projectKeys => 'PROJECT_1', ) end it 'should query correct url when multiple `projectKeys` given as string' do expect(client).to receive(:get).with('/jira/rest/api/2/issue/createmeta?projectKeys=PROJECT_1%2CPROJECT_2').and_return(response) JIRA::Resource::Createmeta.all( client, :projectKeys => ['PROJECT_1', 'PROJECT_2'], ) end it 'should query correct url when only one `projectKeys` given as Project' do prj = JIRA::Resource::Project.new(client) allow(prj).to receive(:key).and_return('PRJ') expect(client).to receive(:get).with('/jira/rest/api/2/issue/createmeta?projectKeys=PRJ').and_return(response) JIRA::Resource::Createmeta.all( client, :projectKeys => prj, ) end it 'should query correct url when multiple `projectKeys` given as Project' do prj_1 = JIRA::Resource::Project.new(client) allow(prj_1).to receive(:key).and_return('PRJ_1') prj_2 = JIRA::Resource::Project.new(client) allow(prj_2).to receive(:key).and_return('PRJ_2') expect(client).to receive(:get).with('/jira/rest/api/2/issue/createmeta?projectKeys=PRJ_2%2CPRJ_1').and_return(response) JIRA::Resource::Createmeta.all( client, :projectKeys => [prj_2, prj_1], ) end it 'should query correct url when multiple `projectKeys` given as different types' do prj_5 = JIRA::Resource::Project.new(client) allow(prj_5).to receive(:key).and_return('PRJ_5') expect(client).to receive(:get).with('/jira/rest/api/2/issue/createmeta?projectKeys=PROJECT_1%2CPRJ_5').and_return(response) JIRA::Resource::Createmeta.all( client, :projectKeys => ['PROJECT_1', prj_5], ) end end describe 'projectIds' do it 'should query correct url when only one `projectIds` given as string' do expect(client).to receive(:get).with('/jira/rest/api/2/issue/createmeta?projectIds=10101').and_return(response) JIRA::Resource::Createmeta.all( client, :projectIds => '10101', ) end it 'should query correct url when multiple `projectIds` given as string' do expect(client).to receive(:get).with('/jira/rest/api/2/issue/createmeta?projectIds=10101%2C20202').and_return(response) JIRA::Resource::Createmeta.all( client, :projectIds => ['10101', '20202'], ) end it 'should query correct url when only one `projectIds` given as Project' do prj = JIRA::Resource::Project.new(client) allow(prj).to receive(:id).and_return('30303') expect(client).to receive(:get).with('/jira/rest/api/2/issue/createmeta?projectIds=30303').and_return(response) JIRA::Resource::Createmeta.all( client, :projectIds => prj, ) end it 'should query correct url when multiple `projectIds` given as Project' do prj_1 = JIRA::Resource::Project.new(client) allow(prj_1).to receive(:id).and_return('30303') prj_2 = JIRA::Resource::Project.new(client) allow(prj_2).to receive(:id).and_return('50505') expect(client).to receive(:get).with('/jira/rest/api/2/issue/createmeta?projectIds=50505%2C30303').and_return(response) JIRA::Resource::Createmeta.all( client, :projectIds => [prj_2, prj_1], ) end it 'should query correct url when multiple `projectIds` given as different types' do prj_5 = JIRA::Resource::Project.new(client) allow(prj_5).to receive(:id).and_return('60606') expect(client).to receive(:get).with('/jira/rest/api/2/issue/createmeta?projectIds=10101%2C60606').and_return(response) JIRA::Resource::Createmeta.all( client, :projectIds => ['10101', prj_5], ) end end describe 'issuetypeNames' do it 'should query correct url when only one `issuetypeNames` given as string' do expect(client).to receive(:get).with('/jira/rest/api/2/issue/createmeta?issuetypeNames=Feature').and_return(response) JIRA::Resource::Createmeta.all( client, :issuetypeNames => 'Feature', ) end it 'should query correct url when multiple `issuetypeNames` given as string' do expect(client).to receive(:get).with('/jira/rest/api/2/issue/createmeta?issuetypeNames=Feature%2CBug').and_return(response) JIRA::Resource::Createmeta.all( client, :issuetypeNames => ['Feature', 'Bug'], ) end it 'should query correct url when only one `issuetypeNames` given as Issuetype' do issue_type = JIRA::Resource::Issuetype.new(client) allow(issue_type).to receive(:name).and_return('Epic') expect(client).to receive(:get).with('/jira/rest/api/2/issue/createmeta?issuetypeNames=Epic').and_return(response) JIRA::Resource::Createmeta.all( client, :issuetypeNames => issue_type, ) end it 'should query correct url when multiple `issuetypeNames` given as Issuetype' do issue_type_1 = JIRA::Resource::Issuetype.new(client) allow(issue_type_1).to receive(:name).and_return('Epic') issue_type_2 = JIRA::Resource::Issuetype.new(client) allow(issue_type_2).to receive(:name).and_return('Sub-Task') expect(client).to receive(:get).with('/jira/rest/api/2/issue/createmeta?issuetypeNames=Sub-Task%2CEpic').and_return(response) JIRA::Resource::Createmeta.all( client, :issuetypeNames => [issue_type_2, issue_type_1], ) end it 'should query correct url when multiple `issuetypeNames` given as different types' do issue_type = JIRA::Resource::Issuetype.new(client) allow(issue_type).to receive(:name).and_return('Epic') expect(client).to receive(:get).with('/jira/rest/api/2/issue/createmeta?issuetypeNames=Feature%2CEpic').and_return(response) JIRA::Resource::Createmeta.all( client, :issuetypeNames => ['Feature', issue_type], ) end end describe 'issuetypeIds' do it 'should query correct url when only one `issuetypeIds` given as string' do expect(client).to receive(:get).with('/jira/rest/api/2/issue/createmeta?issuetypeIds=10101').and_return(response) JIRA::Resource::Createmeta.all( client, :issuetypeIds => '10101', ) end it 'should query correct url when multiple `issuetypeIds` given as string' do expect(client).to receive(:get).with('/jira/rest/api/2/issue/createmeta?issuetypeIds=10101%2C20202').and_return(response) JIRA::Resource::Createmeta.all( client, :issuetypeIds => ['10101', '20202'], ) end it 'should query correct url when only one `issuetypeIds` given as Issuetype' do issue_type = JIRA::Resource::Issuetype.new(client) allow(issue_type).to receive(:id).and_return('30303') expect(client).to receive(:get).with('/jira/rest/api/2/issue/createmeta?issuetypeIds=30303').and_return(response) JIRA::Resource::Createmeta.all( client, :issuetypeIds => issue_type, ) end it 'should query correct url when multiple `issuetypeIds` given as Issuetype' do issue_type_1 = JIRA::Resource::Issuetype.new(client) allow(issue_type_1).to receive(:id).and_return('30303') issue_type_2 = JIRA::Resource::Issuetype.new(client) allow(issue_type_2).to receive(:id).and_return('50505') expect(client).to receive(:get).with('/jira/rest/api/2/issue/createmeta?issuetypeIds=50505%2C30303').and_return(response) JIRA::Resource::Createmeta.all( client, :issuetypeIds => [issue_type_2, issue_type_1], ) end it 'should query correct url when multiple `issuetypeIds` given as different types' do issue_type = JIRA::Resource::Issuetype.new(client) allow(issue_type).to receive(:id).and_return('30303') expect(client).to receive(:get).with('/jira/rest/api/2/issue/createmeta?issuetypeIds=10101%2C30303').and_return(response) JIRA::Resource::Createmeta.all( client, :issuetypeIds => ['10101', issue_type], ) end end end jira-ruby-1.4.3/spec/jira/resource/worklog_spec.rb0000644000004100000410000000113413167661427022220 0ustar www-datawww-datarequire 'spec_helper' describe JIRA::Resource::Worklog do let(:client) { double() } describe "relationships" do subject { JIRA::Resource::Worklog.new(client, :issue_id => '99999', :attrs => { 'author' => {'foo' => 'bar'}, 'updateAuthor' => {'foo' => 'bar'} }) } it "has the correct relationships" do expect(subject).to have_one(:author, JIRA::Resource::User) expect(subject.author.foo).to eq('bar') expect(subject).to have_one(:update_author, JIRA::Resource::User) expect(subject.update_author.foo).to eq('bar') end end end jira-ruby-1.4.3/spec/jira/has_many_proxy_spec.rb0000644000004100000410000000250613167661427021751 0ustar www-datawww-datarequire 'spec_helper' describe JIRA::HasManyProxy do class Foo ; end subject { JIRA::HasManyProxy.new(parent, Foo, collection) } let(:parent) { double("parent") } let(:collection) { double("collection") } it "has a target class" do expect(subject.target_class).to eq(Foo) end it "has a parent" do expect(subject.parent).to eq(parent) end it "has a collection" do expect(subject.collection).to eq(collection) end it "can build a new instance" do client = double('client') foo = double('foo') allow(parent).to receive(:client).and_return(client) allow(parent).to receive(:to_sym).and_return(:parent) expect(Foo).to receive(:new).with(client, :attrs => {'foo' => 'bar'}, :parent => parent).and_return(foo) expect(collection).to receive(:<<).with(foo) expect(subject.build('foo' => 'bar')).to eq(foo) end it "can get all the instances" do foo = double('foo') client = double('client') allow(parent).to receive(:client).and_return(client) allow(parent).to receive(:to_sym).and_return(:parent) expect(Foo).to receive(:all).with(client, :parent => parent).and_return(foo) expect(subject.all).to eq(foo) end it "delegates missing methods to the collection" do expect(collection).to receive(:missing_method) subject.missing_method end end jira-ruby-1.4.3/spec/jira/http_error_spec.rb0000644000004100000410000000111113167661427021070 0ustar www-datawww-datarequire 'spec_helper' describe JIRA::HTTPError do let(:response) { response = double("response") allow(response).to receive(:code).and_return(401) allow(response).to receive(:message).and_return("A MESSAGE WOO") response } subject { described_class.new(response) } it "takes the response object as an argument" do expect(subject.response).to eq(response) end it "has a code method" do expect(subject.code).to eq(response.code) end it "returns code and class from message" do expect(subject.message).to eq(response.message) end end jira-ruby-1.4.3/spec/jira/base_factory_spec.rb0000644000004100000410000000246213167661427021353 0ustar www-datawww-datarequire 'spec_helper' describe JIRA::BaseFactory do class JIRA::Resource::FooFactory < JIRA::BaseFactory ; end class JIRA::Resource::Foo ; end let(:client) { double() } subject { JIRA::Resource::FooFactory.new(client) } it "initializes correctly" do expect(subject.class).to eq(JIRA::Resource::FooFactory) expect(subject.client).to eq(client) expect(subject.target_class).to eq(JIRA::Resource::Foo) end it "proxies all to the target class" do expect(JIRA::Resource::Foo).to receive(:all).with(client) subject.all end it "proxies find to the target class" do expect(JIRA::Resource::Foo).to receive(:find).with(client, 'FOO') subject.find('FOO') end it "returns the target class" do expect(subject.target_class).to eq(JIRA::Resource::Foo) end it "proxies build to the target class" do attrs = double() expect(JIRA::Resource::Foo).to receive(:build).with(client, attrs) subject.build(attrs) end it "proxies collection path to the target class" do expect(JIRA::Resource::Foo).to receive(:collection_path).with(client) subject.collection_path end it "proxies singular path to the target class" do expect(JIRA::Resource::Foo).to receive(:singular_path).with(client, 'FOO') subject.singular_path('FOO') end end jira-ruby-1.4.3/spec/jira/client_spec.rb0000644000004100000410000002161113167661427020165 0ustar www-datawww-datarequire 'spec_helper' # We have three forms of authentication with two clases to represent the client for those different authentications. # Some behaviours are shared across all three types of authentication. these are captured here. RSpec.shared_examples 'Client Common Tests' do it { is_expected.to be_a JIRA::Client } it 'freezes the options once initialised' do expect(subject.options).to be_frozen end it 'prepends context path to rest base_path' do options = [:rest_base_path] defaults = JIRA::Client::DEFAULT_OPTIONS options.each { |key| expect(subject.options[key]).to eq(defaults[:context_path] + defaults[key]) } end it 'merges headers' do expect(subject.send(:merge_default_headers, {})).to eq({'Accept' => 'application/json'}) end describe 'http methods' do it 'merges default headers' do # stubbed response for generic client request method expect(subject).to receive(:request).exactly(5).times.and_return(successful_response) # response for merging headers for http methods with no body expect(subject).to receive(:merge_default_headers).exactly(3).times.with({}) # response for merging headers for http methods with body expect(subject).to receive(:merge_default_headers).exactly(2).times.with(content_type_header) [:delete, :get, :head].each { |method| subject.send(method, '/path', {}) } [:post, :put].each {|method| subject.send(method, '/path', '', content_type_header)} end it 'calls the generic request method' do [:delete, :get, :head].each do |method| expect(subject).to receive(:request).with(method, '/path', nil, headers).and_return(successful_response) subject.send(method, '/path', {}) end [:post, :put].each do |method| expect(subject).to receive(:request).with(method, '/path', '', merged_headers) subject.send(method, '/path', '', {}) end end end describe 'Resource Factories' do it 'gets all projects' do expect(JIRA::Resource::Project).to receive(:all).with(subject).and_return([]) expect(subject.Project.all).to eq([]) end it 'finds a single project' do find_result = double expect(JIRA::Resource::Project).to receive(:find).with(subject, '123').and_return(find_result) expect(subject.Project.find('123')).to eq(find_result) end end end RSpec.shared_examples 'HttpClient tests' do it 'makes a valid request' do [:delete, :get, :head].each do |method| expect(subject.request_client).to receive(:make_request).with(method, '/path', nil, headers).and_return(successful_response) subject.send(method, '/path', headers) end [:post, :put].each do |method| expect(subject.request_client).to receive(:make_request).with(method, '/path', '', merged_headers).and_return(successful_response) subject.send(method, '/path', '', headers) end end end describe JIRA::Client do let(:request) { subject.request_client.class } let(:successful_response) do response = double('response') allow(response).to receive(:kind_of?).with(Net::HTTPSuccess).and_return(true) response end let(:content_type_header) { {'Content-Type' => 'application/json'} } let(:headers) { {'Accept' => 'application/json'} } let(:merged_headers) { headers.merge(content_type_header) } context 'behaviour that applies to all client classes irrespective of authentication method' do it 'allows the overriding of some options' do client = JIRA::Client.new({:consumer_key => 'foo', :consumer_secret => 'bar', :site => 'http://foo.com/'}) expect(client.options[:site]).to eq('http://foo.com/') expect(JIRA::Client::DEFAULT_OPTIONS[:site]).not_to eq('http://foo.com/') end end context 'with basic http authentication' do subject { JIRA::Client.new(username: 'foo', password: 'bar', auth_type: :basic) } before(:each) do stub_request(:get, 'https://foo:bar@localhost:2990/jira/rest/api/2/project') .to_return(status: 200, body: '[]', headers: {} ) stub_request(:get, 'https://foo:badpassword@localhost:2990/jira/rest/api/2/project'). to_return(status: 401, headers: {} ) end include_examples 'Client Common Tests' include_examples 'HttpClient tests' specify { expect(subject.request_client).to be_a JIRA::HttpClient } it 'sets the username and password' do expect(subject.options[:username]).to eq('foo') expect(subject.options[:password]).to eq('bar') end it 'fails with wrong user name and password' do bad_login = JIRA::Client.new(username: 'foo', password: 'badpassword', auth_type: :basic) expect(bad_login.authenticated?).to be_falsey expect{bad_login.Project.all}.to raise_error JIRA::HTTPError end it 'only returns a true for #authenticated? once we have requested some data' do expect(subject.authenticated?).to be_falsey expect(subject.Project.all).to be_empty expect(subject.authenticated?).to be_truthy end end context 'with cookie authentication' do subject { JIRA::Client.new(username: 'foo', password: 'bar', auth_type: :cookie) } let(:session_cookie) { '6E3487971234567896704A9EB4AE501F' } let(:session_body) do { 'session': {'name' => "JSESSIONID", 'value' => session_cookie }, 'loginInfo': {'failedLoginCount' => 1, 'loginCount' => 2, 'lastFailedLoginTime' => (DateTime.now - 2).iso8601, 'previousLoginTime' => (DateTime.now - 5).iso8601 } } end before(:each) do # General case of API call with no authentication, or wrong authentication stub_request(:post, 'https://localhost:2990/jira/rest/auth/1/session'). to_return(status: 401, headers: {} ) # Now special case of API with correct authentication. This gets checked first by RSpec. stub_request(:post, 'https://localhost:2990/jira/rest/auth/1/session') .with(body: '{"username":"foo","password":"bar"}') .to_return(status: 200, body: session_body.to_json, headers: { 'Set-Cookie': "JSESSIONID=#{session_cookie}; Path=/; HttpOnly"}) stub_request(:get, 'https://localhost:2990/jira/rest/api/2/project') .with(headers: { cookie: "JSESSIONID=#{session_cookie}" } ) .to_return(status: 200, body: '[]', headers: {} ) end include_examples 'Client Common Tests' include_examples 'HttpClient tests' specify { expect(subject.request_client).to be_a JIRA::HttpClient } it 'authenticates with a correct username and password' do expect(subject).to be_authenticated expect(subject.Project.all).to be_empty end it 'does not authenticate with an incorrect username and password' do bad_client = JIRA::Client.new(username: 'foo', password: 'bad_password', auth_type: :cookie) expect(bad_client).not_to be_authenticated end it 'destroys the username and password once authenticated' do expect(subject.options[:username]).to be_nil expect(subject.options[:password]).to be_nil end end context 'oath2 authentication' do subject { JIRA::Client.new(consumer_key: 'foo', consumer_secret: 'bar') } include_examples 'Client Common Tests' specify { expect(subject.request_client).to be_a JIRA::OauthClient } it 'allows setting an access token' do token = double expect(OAuth::AccessToken).to receive(:new).with(subject.consumer, 'foo', 'bar').and_return(token) expect(subject.authenticated?).to be_falsey access_token = subject.set_access_token('foo', 'bar') expect(access_token).to eq(token) expect(subject.access_token).to eq(token) expect(subject.authenticated?).to be_truthy end it 'allows initializing the access token' do request_token = OAuth::RequestToken.new(subject.consumer) allow(subject.consumer).to receive(:get_request_token).and_return(request_token) mock_access_token = double expect(request_token).to receive(:get_access_token).with(:oauth_verifier => 'abc123').and_return(mock_access_token) subject.init_access_token(:oauth_verifier => 'abc123') expect(subject.access_token).to eq(mock_access_token) end specify 'that has specific default options' do [:signature_method, :private_key_file].each do |key| expect(subject.options[key]).to eq(JIRA::Client::DEFAULT_OPTIONS[key]) end end describe 'that call a oauth client' do specify 'which makes a request' do [:delete, :get, :head].each do |method| expect(subject.request_client).to receive(:make_request).with(method, '/path', nil, headers).and_return(successful_response) subject.send(method, '/path', {}) end [:post, :put].each do |method| expect(subject.request_client).to receive(:make_request).with(method, '/path', '', merged_headers).and_return(successful_response) subject.send(method, '/path', '', {}) end end end end end jira-ruby-1.4.3/spec/jira/request_client_spec.rb0000644000004100000410000000067513167661427021744 0ustar www-datawww-datarequire 'spec_helper' describe JIRA::RequestClient do it "raises an exception for non success responses" do response = double() allow(response).to receive(:kind_of?).with(Net::HTTPSuccess).and_return(false) rc = JIRA::RequestClient.new expect(rc).to receive(:make_request).with(:get, '/foo', '', {}).and_return(response) expect { rc.request(:get, '/foo', '', {}) }.to raise_exception(JIRA::HTTPError) end end jira-ruby-1.4.3/spec/jira/base_spec.rb0000644000004100000410000005262513167661427017632 0ustar www-datawww-datarequire 'spec_helper' describe JIRA::Base do class JIRADelegation < SimpleDelegator # :nodoc: end class JIRA::Resource::Deadbeef < JIRA::Base # :nodoc: end class JIRA::Resource::HasOneExample < JIRA::Base # :nodoc: has_one :deadbeef has_one :muffin, :class => JIRA::Resource::Deadbeef has_one :brunchmuffin, :class => JIRA::Resource::Deadbeef, :nested_under => 'nested' has_one :breakfastscone, :class => JIRA::Resource::Deadbeef, :nested_under => ['nested','breakfastscone'] has_one :irregularly_named_thing, :class => JIRA::Resource::Deadbeef, :attribute_key => 'irregularlyNamedThing' end class JIRA::Resource::HasManyExample < JIRA::Base # :nodoc: has_many :deadbeefs has_many :brunchmuffins, :class => JIRA::Resource::Deadbeef, :nested_under => 'nested' has_many :breakfastscones, :class => JIRA::Resource::Deadbeef, :nested_under => ['nested','breakfastscone'] has_many :irregularly_named_things, :class => JIRA::Resource::Deadbeef, :attribute_key => 'irregularlyNamedThings' end let(:client) { double("client") } let(:attrs) { Hash.new } subject { JIRA::Resource::Deadbeef.new(client, :attrs => attrs) } let(:decorated) { JIRADelegation.new(subject) } describe "#respond_to?" do describe "when decorated using SimpleDelegator" do it "responds to client" do expect(decorated.respond_to?(:client)).to eq(true) end it "does not raise an error" do expect { decorated.respond_to?(:client) }.not_to raise_error end end end it "assigns the client and attrs" do expect(subject.client).to eq(client) expect(subject.attrs).to eq(attrs) end it "returns all the deadbeefs" do response = double() expect(response).to receive(:body).and_return('[{"self":"http://deadbeef/","id":"98765"}]') expect(client).to receive(:get).with('/jira/rest/api/2/deadbeef').and_return(response) expect(JIRA::Resource::Deadbeef).to receive(:collection_path).and_return('/jira/rest/api/2/deadbeef') deadbeefs = JIRA::Resource::Deadbeef.all(client) expect(deadbeefs.length).to eq(1) first = deadbeefs.first expect(first.class).to eq(JIRA::Resource::Deadbeef) expect(first.attrs['self']).to eq('http://deadbeef/') expect(first.attrs['id']).to eq('98765') expect(first.expanded?).to be_falsey end it "finds a deadbeef by id" do response = instance_double("Response", body: '{"self":"http://deadbeef/","id":"98765"}') expect(client).to receive(:get).with('/jira/rest/api/2/deadbeef/98765').and_return(response) expect(JIRA::Resource::Deadbeef).to receive(:collection_path).and_return('/jira/rest/api/2/deadbeef') deadbeef = JIRA::Resource::Deadbeef.find(client, '98765') expect(deadbeef.client).to eq(client) expect(deadbeef.attrs['self']).to eq('http://deadbeef/') expect(deadbeef.attrs['id']).to eq('98765') expect(deadbeef.expanded?).to be_truthy end it "finds a deadbeef containing changelog by id" do response = instance_double( "Response", body: '{"self":"http://deadbeef/","id":"98765","changelog":{"histories":[]}}' ) expect(client).to receive(:get).with('/jira/rest/api/2/deadbeef/98765?expand=changelog').and_return(response) expect(JIRA::Resource::Deadbeef).to receive(:collection_path).and_return('/jira/rest/api/2/deadbeef') deadbeef = JIRA::Resource::Deadbeef.find(client, '98765', {expand:'changelog'}) expect(deadbeef.client).to eq(client) expect(deadbeef.attrs['self']).to eq('http://deadbeef/') expect(deadbeef.attrs['id']).to eq('98765') expect(deadbeef.expanded?).to be_truthy expect(deadbeef.attrs['changelog']['histories']).to eq([]) end it "builds a deadbeef" do deadbeef = JIRA::Resource::Deadbeef.build(client, 'id' => "98765" ) expect(deadbeef.expanded?).to be_falsey expect(deadbeef.client).to eq(client) expect(deadbeef.attrs['id']).to eq('98765') end it "returns the endpoint name" do expect(subject.class.endpoint_name).to eq('deadbeef') end it "returns the path_component" do attrs['id'] = '123' expect(subject.path_component).to eq('/deadbeef/123') end it "returns the path component for unsaved instances" do expect(subject.path_component).to eq('/deadbeef') end it "converts to a symbol" do expect(subject.to_sym).to eq(:deadbeef) end describe "collection_path" do before(:each) do expect(client).to receive(:options).and_return(:rest_base_path => '/deadbeef/bar') end it "returns the collection_path" do expect(subject.collection_path).to eq('/deadbeef/bar/deadbeef') end it "returns the collection_path with a prefix" do expect(subject.collection_path('/baz/')).to eq('/deadbeef/bar/baz/deadbeef') end it "has a class method that returns the collection_path" do expect(subject.class.collection_path(client)).to eq('/deadbeef/bar/deadbeef') end end it "parses json" do expect(described_class.parse_json('{"foo":"bar"}')).to eq({"foo" => "bar"}) end describe "dynamic instance methods" do let(:attrs) { {'foo' => 'bar', 'flum' => 'goo', 'object_id' => 'dummy'} } subject { JIRA::Resource::Deadbeef.new(client, :attrs => attrs) } it "responds to each of the top level attribute names" do expect(subject).to respond_to(:foo) expect(subject).to respond_to('flum') expect(subject).to respond_to(:object_id) expect(subject.foo).to eq('bar') expect(subject.flum).to eq('goo') # Should not override existing method names, but should still allow # access to their values via the attrs[] hash expect(subject.object_id).not_to eq('dummy') expect(subject.attrs['object_id']).to eq('dummy') end end describe "fetch" do subject { JIRA::Resource::Deadbeef.new(client, :attrs => {'id' => '98765'}) } describe "not cached" do before(:each) do response = instance_double("Response", body: '{"self":"http://deadbeef/","id":"98765"}') expect(client).to receive(:get).with('/jira/rest/api/2/deadbeef/98765').and_return(response) expect(JIRA::Resource::Deadbeef).to receive(:collection_path).and_return('/jira/rest/api/2/deadbeef') end it "sets expanded to true after fetch" do expect(subject.expanded?).to be_falsey subject.fetch expect(subject.expanded?).to be_truthy end it "performs a fetch" do expect(subject.expanded?).to be_falsey subject.fetch expect(subject.self).to eq("http://deadbeef/") expect(subject.id).to eq("98765") end it "performs a fetch if already fetched and force flag is true" do subject.expanded = true subject.fetch(true) end end describe "cached" do it "doesn't perform a fetch if already fetched" do subject.expanded = true expect(client).not_to receive(:get) subject.fetch end end context "with expand parameter 'changelog'" do it "fetchs changelogs '" do response = instance_double( "Response", body: '{"self":"http://deadbeef/","id":"98765","changelog":{"histories":[]}}' ) expect(client).to receive(:get).with('/jira/rest/api/2/deadbeef/98765?expand=changelog').and_return(response) expect(JIRA::Resource::Deadbeef).to receive(:collection_path).and_return('/jira/rest/api/2/deadbeef') subject.fetch(false, {expand:'changelog'}) expect(subject.self).to eq("http://deadbeef/") expect(subject.id).to eq("98765") expect(subject.changelog['histories']).to eq([]) end end end describe "save" do let(:response) { double() } subject { JIRA::Resource::Deadbeef.new(client) } before(:each) do expect(subject).to receive(:url).and_return('/foo/bar') end it "POSTs a new record" do response = instance_double("Response", body: '{"id":"123"}') allow(subject).to receive(:new_record?) { true } expect(client).to receive(:post).with('/foo/bar','{"foo":"bar"}').and_return(response) expect(subject.save("foo" => "bar")).to be_truthy expect(subject.id).to eq("123") expect(subject.expanded).to be_falsey end it "PUTs an existing record" do response = instance_double("Response", body: nil) allow(subject).to receive(:new_record?) { false } expect(client).to receive(:put).with('/foo/bar','{"foo":"bar"}').and_return(response) expect(subject.save("foo" => "bar")).to be_truthy expect(subject.expanded).to be_falsey end it "merges attrs on save" do response = instance_double("Response", body: nil) expect(client).to receive(:post).with('/foo/bar','{"foo":{"fum":"dum"}}').and_return(response) subject.attrs = {"foo" => {"bar" => "baz"}} subject.save({"foo" => {"fum" => "dum"}}) expect(subject.foo).to eq({"bar" => "baz", "fum" => "dum"}) end it "returns false when an invalid field is set" do # The JIRA REST API apparently ignores fields that you aren't allowed to set manually response = instance_double("Response", body: '{"errorMessages":["blah"]}', status: 400) allow(subject).to receive(:new_record?) { false } expect(client).to receive(:put).with('/foo/bar','{"invalid_field":"foobar"}').and_raise(JIRA::HTTPError.new(response)) expect(subject.save("invalid_field" => "foobar")).to be_falsey end it "returns false with exception details when non json response body (unauthorized)" do # Unauthorized requests return a non-json body. This makes sure we can handle non-json bodies on HTTPError response = double("Response", body: 'totally invalid json', code: 401, message: "Unauthorized") expect(client).to receive(:post).with('/foo/bar','{"foo":"bar"}').and_raise(JIRA::HTTPError.new(response)) expect(subject.save("foo" => "bar")).to be_falsey expect(subject.attrs["exception"]["code"]).to eq(401) expect(subject.attrs["exception"]["message"]).to eq("Unauthorized") end end describe "save!" do let(:response) { double() } subject { JIRA::Resource::Deadbeef.new(client) } before(:each) do expect(subject).to receive(:url).and_return('/foo/bar') end it "POSTs a new record" do response = instance_double("Response", body: '{"id":"123"}') allow(subject).to receive(:new_record?) { true } expect(client).to receive(:post).with('/foo/bar','{"foo":"bar"}').and_return(response) expect(subject.save!("foo" => "bar")).to be_truthy expect(subject.id).to eq("123") expect(subject.expanded).to be_falsey end it "PUTs an existing record" do response = instance_double("Response", body: nil) allow(subject).to receive(:new_record?) { false } expect(client).to receive(:put).with('/foo/bar','{"foo":"bar"}').and_return(response) expect(subject.save!("foo" => "bar")).to be_truthy expect(subject.expanded).to be_falsey end it "throws an exception when an invalid field is set" do response = instance_double("Response", body: '{"errorMessages":["blah"]}', status: 400) allow(subject).to receive(:new_record?) { false } expect(client).to receive(:put).with('/foo/bar','{"invalid_field":"foobar"}').and_raise(JIRA::HTTPError.new(response)) expect(lambda{ subject.save!("invalid_field" => "foobar") }).to raise_error(JIRA::HTTPError) end end describe "set_attrs" do it "merges hashes correctly when clobber is true (default)" do subject.attrs = {"foo" => {"bar" => "baz"}} subject.set_attrs({"foo" => {"fum" => "dum"}}) expect(subject.foo).to eq({"fum" => "dum"}) end it "merges hashes correctly when clobber is false" do subject.attrs = {"foo" => {"bar" => "baz"}} subject.set_attrs({"foo" => {"fum" => "dum"}}, false) expect(subject.foo).to eq({"bar" => "baz", "fum" => "dum"}) end end describe "delete" do before(:each) do expect(client).to receive(:delete).with('/foo/bar') allow(subject).to receive(:url) { '/foo/bar' } end it "flags itself as deleted" do expect(subject.deleted?).to be_falsey subject.delete expect(subject.deleted?).to be_truthy end it "sends a DELETE request" do subject.delete end end describe "new_record?" do it "returns true for new_record? when new object" do subject.attrs['id'] = nil expect(subject.new_record?).to be_truthy end it "returns false for new_record? when id is set" do subject.attrs['id'] = '123' expect(subject.new_record?).to be_falsey end end describe "has_errors?" do it "returns true when the response contains errors" do attrs["errors"] = {"invalid" => "Field invalid"} expect(subject.has_errors?).to be_truthy end it "returns false when the response does not contain any errors" do expect(subject.has_errors?).to be_falsey end end describe 'url' do before(:each) do allow(client).to receive(:options) { {:rest_base_path => '/foo/bar'} } end it "returns self as the URL if set" do attrs['self'] = 'http://foo/bar' expect(subject.url).to eq("http://foo/bar") end it "generates the URL from id if self not set" do attrs['self'] = nil attrs['id'] = '98765' expect(subject.url).to eq("/foo/bar/deadbeef/98765") end it "generates the URL from collection_path if self and id not set" do attrs['self'] = nil attrs['id'] = nil expect(subject.url).to eq("/foo/bar/deadbeef") end it "has a class method for the collection path" do expect(JIRA::Resource::Deadbeef.collection_path(client)).to eq("/foo/bar/deadbeef") #Should accept an optional prefix (flum in this case) expect(JIRA::Resource::Deadbeef.collection_path(client, '/flum/')).to eq("/foo/bar/flum/deadbeef") end it "has a class method for the singular path" do expect(JIRA::Resource::Deadbeef.singular_path(client, 'abc123')).to eq("/foo/bar/deadbeef/abc123") #Should accept an optional prefix (flum in this case) expect(JIRA::Resource::Deadbeef.singular_path(client, 'abc123', '/flum/')).to eq("/foo/bar/flum/deadbeef/abc123") end end it "returns the formatted attrs from to_s" do subject.attrs['foo'] = 'bar' subject.attrs['dead'] = 'beef' expect(subject.to_s).to match(/#/) end it "returns the key attribute" do expect(subject.class.key_attribute).to eq(:id) end it "returns the key value" do subject.attrs['id'] = '123' expect(subject.key_value).to eq('123') end it "converts to json" do subject.attrs = { 'foo' => 'bar', 'dead' => 'beef' } expect(subject.to_json).to eq(subject.attrs.to_json) h = { 'key' => subject } h_attrs = { 'key' => subject.attrs } expect(h.to_json).to eq(h_attrs.to_json) end describe "extract attrs from response" do subject { JIRA::Resource::Deadbeef.new(client, :attrs => {}) } it "sets the attrs from a response" do response = instance_double("Response", body: '{"foo":"bar"}') expect(subject.set_attrs_from_response(response)).to eq({'foo' => 'bar'}) expect(subject.foo).to eq("bar") end it "doesn't clobber existing attrs not in response" do response = instance_double("Response", body: '{"foo":"bar"}') subject.attrs = {'flum' => 'flar'} expect(subject.set_attrs_from_response(response)).to eq({'foo' => 'bar'}) expect(subject.foo).to eq("bar") expect(subject.flum).to eq("flar") end it "handles nil response body" do response = instance_double("Response", body: nil) subject.attrs = {'flum' => 'flar'} expect(subject.set_attrs_from_response(response)).to be_nil expect(subject.flum).to eq('flar') end end describe "nesting" do it "defaults collection_attributes_are_nested to false" do expect(JIRA::Resource::Deadbeef.collection_attributes_are_nested).to be_falsey end it "allows collection_attributes_are_nested to be set" do JIRA::Resource::Deadbeef.nested_collections true expect(JIRA::Resource::Deadbeef.collection_attributes_are_nested).to be_truthy end end describe "has_many" do subject { JIRA::Resource::HasManyExample.new(client, :attrs => {'deadbeefs' => [{'id' => '123'}]}) } it "returns a collection of instances for has_many relationships" do expect(subject.deadbeefs.class).to eq(JIRA::HasManyProxy) expect(subject.deadbeefs.length).to eq(1) subject.deadbeefs.each do |deadbeef| expect(deadbeef.class).to eq(JIRA::Resource::Deadbeef) end end it "returns an empty collection for empty has_many relationships" do subject = JIRA::Resource::HasManyExample.new(client) expect(subject.deadbeefs.length).to eq(0) end it "allows the has_many attributes to be nested inside another attribute" do subject = JIRA::Resource::HasManyExample.new(client, :attrs => {'nested' => {'brunchmuffins' => [{'id' => '123'},{'id' => '456'}]}}) expect(subject.brunchmuffins.length).to eq(2) subject.brunchmuffins.each do |brunchmuffin| expect(brunchmuffin.class).to eq(JIRA::Resource::Deadbeef) end end it "allows it to be deeply nested" do subject = JIRA::Resource::HasManyExample.new(client, :attrs => {'nested' => { 'breakfastscone' => { 'breakfastscones' => [{'id' => '123'},{'id' => '456'}] } }}) expect(subject.breakfastscones.length).to eq(2) subject.breakfastscones.each do |breakfastscone| expect(breakfastscone.class).to eq(JIRA::Resource::Deadbeef) end end it "short circuits missing deeply nested attrs" do subject = JIRA::Resource::HasManyExample.new(client, :attrs => { 'nested' => {} }) expect(subject.breakfastscones.length).to eq(0) end it "allows the attribute key to be specified" do subject = JIRA::Resource::HasManyExample.new(client, :attrs => {'irregularlyNamedThings' => [{'id' => '123'},{'id' => '456'}]}) expect(subject.irregularly_named_things.length).to eq(2) subject.irregularly_named_things.each do |thing| expect(thing.class).to eq(JIRA::Resource::Deadbeef) end end it "can build child instances" do deadbeef = subject.deadbeefs.build expect(deadbeef.class).to eq(JIRA::Resource::Deadbeef) end end describe "has_one" do subject { JIRA::Resource::HasOneExample.new(client, :attrs => {'deadbeef' => {'id' => '123'}}) } it "returns an instance for a has one relationship" do expect(subject.deadbeef.class).to eq(JIRA::Resource::Deadbeef) expect(subject.deadbeef.id).to eq('123') end it "returns nil when resource attribute is nonexistent" do subject = JIRA::Resource::HasOneExample.new(client) expect(subject.deadbeef).to be_nil end it "returns an instance with a different class name to the attribute name" do subject = JIRA::Resource::HasOneExample.new(client, :attrs => {'muffin' => {'id' => '123'}}) expect(subject.muffin.class).to eq(JIRA::Resource::Deadbeef) expect(subject.muffin.id).to eq('123') end it "allows the has_one attributes to be nested inside another attribute" do subject = JIRA::Resource::HasOneExample.new(client, :attrs => {'nested' => {'brunchmuffin' => {'id' => '123'}}}) expect(subject.brunchmuffin.class).to eq(JIRA::Resource::Deadbeef) expect(subject.brunchmuffin.id).to eq('123') end it "allows it to be deeply nested" do subject = JIRA::Resource::HasOneExample.new(client, :attrs => {'nested' => { 'breakfastscone' => { 'breakfastscone' => {'id' => '123'} } }}) expect(subject.breakfastscone.class).to eq(JIRA::Resource::Deadbeef) expect(subject.breakfastscone.id).to eq('123') end it "allows the attribute key to be specified" do subject = JIRA::Resource::HasOneExample.new(client, :attrs => {'irregularlyNamedThing' => {'id' => '123'}}) expect(subject.irregularly_named_thing.class).to eq(JIRA::Resource::Deadbeef) expect(subject.irregularly_named_thing.id).to eq('123') end end describe "belongs_to" do class JIRA::Resource::BelongsToExample < JIRA::Base belongs_to :deadbeef end let(:deadbeef) { JIRA::Resource::Deadbeef.new(client, :attrs => {'id' => "999"}) } subject { JIRA::Resource::BelongsToExample.new(client, :attrs => {'id' => '123'}, :deadbeef => deadbeef) } it "sets up an accessor for the belongs to relationship" do expect(subject.deadbeef).to eq(deadbeef) end it "raises an exception when initialized without a belongs_to instance" do expect(lambda { JIRA::Resource::BelongsToExample.new(client, :attrs => {'id' => '123'}) }).to raise_exception(ArgumentError,"Required option :deadbeef missing") end it "returns the right url" do allow(client).to receive(:options) { { :rest_base_path => "/foo" } } expect(subject.url).to eq("/foo/deadbeef/999/belongstoexample/123") end it "can be initialized with an instance or a key value" do allow(client).to receive(:options) { { :rest_base_path => "/foo" } } subject = JIRA::Resource::BelongsToExample.new(client, :attrs => {'id' => '123'}, :deadbeef_id => '987') expect(subject.url).to eq("/foo/deadbeef/987/belongstoexample/123") end end end jira-ruby-1.4.3/spec/jira/http_client_spec.rb0000644000004100000410000002012413167661427021222 0ustar www-datawww-datarequire 'spec_helper' describe JIRA::HttpClient do let(:basic_client) do options = JIRA::Client::DEFAULT_OPTIONS.merge(JIRA::HttpClient::DEFAULT_OPTIONS) JIRA::HttpClient.new(options) end let(:basic_cookie_client) do options = JIRA::Client::DEFAULT_OPTIONS.merge(JIRA::HttpClient::DEFAULT_OPTIONS).merge(:use_cookies => true) JIRA::HttpClient.new(options) end let(:basic_cookie_client_with_context_path) do options = JIRA::Client::DEFAULT_OPTIONS.merge(JIRA::HttpClient::DEFAULT_OPTIONS).merge( :use_cookies => true, :context_path => '/context' ) JIRA::HttpClient.new(options) end let(:basic_cookie_client_with_additional_cookies) do options = JIRA::Client::DEFAULT_OPTIONS.merge(JIRA::HttpClient::DEFAULT_OPTIONS).merge( :use_cookies => true, :additional_cookies => ['sessionToken=abc123', 'internal=true'] ) JIRA::HttpClient.new(options) end let(:response) do response = double("response") allow(response).to receive(:kind_of?).with(Net::HTTPSuccess).and_return(true) response end let(:cookie_response) do response = double("response") allow(response).to receive(:kind_of?).with(Net::HTTPSuccess).and_return(true) response end it "creates an instance of Net:HTTP for a basic auth client" do expect(basic_client.basic_auth_http_conn.class).to eq(Net::HTTP) end it "makes a correct HTTP request for make_cookie_auth_request" do request = double() basic_auth_http_conn = double() headers = {"Content-Type" => "application/json"} expected_path = '/context/rest/auth/1/session' expected_body = '{"username":"","password":""}' allow(basic_cookie_client_with_context_path).to receive(:basic_auth_http_conn).and_return(basic_auth_http_conn) expect(basic_auth_http_conn).to receive(:request).with(request).and_return(response) allow(request).to receive(:basic_auth) allow(response).to receive(:get_fields).with('set-cookie') expect(request).to receive(:body=).with(expected_body) expect(Net::HTTP.const_get(:post.to_s.capitalize)).to receive(:new).with(expected_path, headers).and_return(request) basic_cookie_client_with_context_path.make_cookie_auth_request end it "responds to the http methods" do body = '' headers = double() basic_auth_http_conn = double() request = double() allow(basic_client).to receive(:basic_auth_http_conn).and_return(basic_auth_http_conn) expect(request).to receive(:basic_auth).with(basic_client.options[:username], basic_client.options[:password]).exactly(5).times.and_return(request) expect(basic_auth_http_conn).to receive(:request).exactly(5).times.with(request).and_return(response) [:delete, :get, :head].each do |method| expect(Net::HTTP.const_get(method.to_s.capitalize)).to receive(:new).with('/path', headers).and_return(request) expect(basic_client.make_request(method, '/path', nil, headers)).to eq(response) end [:post, :put].each do |method| expect(Net::HTTP.const_get(method.to_s.capitalize)).to receive(:new).with('/path', headers).and_return(request) expect(request).to receive(:body=).with(body).and_return(request) expect(basic_client.make_request(method, '/path', body, headers)).to eq(response) end end it "gets and sets cookies" do body = '' headers = double() basic_auth_http_conn = double() request = double() allow(basic_cookie_client).to receive(:basic_auth_http_conn).and_return(basic_auth_http_conn) expect(request).to receive(:basic_auth).with(basic_cookie_client.options[:username], basic_cookie_client.options[:password]).exactly(5).times.and_return(request) expect(cookie_response).to receive(:get_fields).with('set-cookie').exactly(5).times expect(basic_auth_http_conn).to receive(:request).exactly(5).times.with(request).and_return(cookie_response) [:delete, :get, :head].each do |method| expect(Net::HTTP.const_get(method.to_s.capitalize)).to receive(:new).with('/path', headers).and_return(request) expect(basic_cookie_client.make_request(method, '/path', nil, headers)).to eq(cookie_response) end [:post, :put].each do |method| expect(Net::HTTP.const_get(method.to_s.capitalize)).to receive(:new).with('/path', headers).and_return(request) expect(request).to receive(:body=).with(body).and_return(request) expect(basic_cookie_client.make_request(method, '/path', body, headers)).to eq(cookie_response) end end it "sets additional cookies when they are provided" do client = basic_cookie_client_with_additional_cookies body = '' headers = double() basic_auth_http_conn = double() request = double() allow(client).to receive(:basic_auth_http_conn).and_return(basic_auth_http_conn) expect(request).to receive(:basic_auth).with(client.options[:username], client.options[:password]).exactly(5).times.and_return(request) expect(request).to receive(:add_field).with("Cookie", "sessionToken=abc123; internal=true").exactly(5).times expect(cookie_response).to receive(:get_fields).with('set-cookie').exactly(5).times expect(basic_auth_http_conn).to receive(:request).exactly(5).times.with(request).and_return(cookie_response) [:delete, :get, :head].each do |method| expect(Net::HTTP.const_get(method.to_s.capitalize)).to receive(:new).with('/path', headers).and_return(request) expect(client.make_request(method, '/path', nil, headers)).to eq(cookie_response) end [:post, :put].each do |method| expect(Net::HTTP.const_get(method.to_s.capitalize)).to receive(:new).with('/path', headers).and_return(request) expect(request).to receive(:body=).with(body).and_return(request) expect(client.make_request(method, '/path', body, headers)).to eq(cookie_response) end end it "performs a basic http client request" do body = nil headers = double() basic_auth_http_conn = double() http_request = double() expect(Net::HTTP::Get).to receive(:new).with('/foo', headers).and_return(http_request) expect(basic_auth_http_conn).to receive(:request).with(http_request).and_return(response) expect(http_request).to receive(:basic_auth).with(basic_client.options[:username], basic_client.options[:password]).and_return(http_request) allow(basic_client).to receive(:basic_auth_http_conn).and_return(basic_auth_http_conn) basic_client.make_request(:get, '/foo', body, headers) end it "performs a basic http client request with a full domain" do body = nil headers = double() basic_auth_http_conn = double() http_request = double() expect(Net::HTTP::Get).to receive(:new).with('/foo', headers).and_return(http_request) expect(basic_auth_http_conn).to receive(:request).with(http_request).and_return(response) expect(http_request).to receive(:basic_auth).with(basic_client.options[:username], basic_client.options[:password]).and_return(http_request) allow(basic_client).to receive(:basic_auth_http_conn).and_return(basic_auth_http_conn) basic_client.make_request(:get, 'http://mydomain.com/foo', body, headers) end it "returns a URI" do uri = URI.parse(basic_client.options[:site]) expect(basic_client.uri).to eq(uri) end it "sets up a http connection with options" do http_conn = double() uri = double() host = double() port = double() expect(uri).to receive(:host).and_return(host) expect(uri).to receive(:port).and_return(port) expect(Net::HTTP).to receive(:new).with(host, port).and_return(http_conn) expect(http_conn).to receive(:use_ssl=).with(basic_client.options[:use_ssl]).and_return(http_conn) expect(http_conn).to receive(:verify_mode=).with(basic_client.options[:ssl_verify_mode]).and_return(http_conn) expect(http_conn).to receive(:read_timeout=).with(basic_client.options[:read_timeout]).and_return(http_conn) expect(basic_client.http_conn(uri)).to eq(http_conn) end it "returns a http connection" do http_conn = double() uri = double() expect(basic_client).to receive(:uri).and_return(uri) expect(basic_client).to receive(:http_conn).and_return(http_conn) expect(basic_client.basic_auth_http_conn).to eq(http_conn) end end jira-ruby-1.4.3/spec/jira/oauth_client_spec.rb0000644000004100000410000001020113167661427021356 0ustar www-datawww-datarequire 'spec_helper' describe JIRA::OauthClient do let(:oauth_client) do options = { :consumer_key => 'foo', :consumer_secret => 'bar' } options = JIRA::Client::DEFAULT_OPTIONS.merge(options) JIRA::OauthClient.new(options) end let(:response) do response = double("response") allow(response).to receive(:kind_of?).with(Net::HTTPSuccess).and_return(true) response end describe "authenticating with oauth" do it "prepends the context path to all authorization and rest paths" do options = [:request_token_path, :authorize_path, :access_token_path] defaults = JIRA::Client::DEFAULT_OPTIONS.merge(JIRA::OauthClient::DEFAULT_OPTIONS) options.each do |key| expect(oauth_client.options[key]).to eq(defaults[:context_path] + defaults[key]) end end it "creates a Oauth::Consumer on initialize" do expect(oauth_client.consumer.class).to eq(OAuth::Consumer) expect(oauth_client.consumer.key).to eq(oauth_client.key) expect(oauth_client.consumer.secret).to eq(oauth_client.secret) end it "returns an OAuth request_token" do # Cannot just check for method delegation as http connection will be attempted request_token = OAuth::RequestToken.new(oauth_client.consumer) allow(oauth_client).to receive(:get_request_token).and_return(request_token) expect(oauth_client.get_request_token).to eq(request_token) end it "allows setting the request token" do token = double() expect(OAuth::RequestToken).to receive(:new).with(oauth_client.consumer, 'foo', 'bar').and_return(token) request_token = oauth_client.set_request_token('foo', 'bar') expect(request_token).to eq(token) expect(oauth_client.request_token).to eq(token) end it "allows setting the consumer key" do expect(oauth_client.key).to eq('foo') end it "allows setting the consumer secret" do expect(oauth_client.secret).to eq('bar') end describe "the access token" do it "initializes" do request_token = OAuth::RequestToken.new(oauth_client.consumer) allow(oauth_client).to receive(:get_request_token).and_return(request_token) mock_access_token = double() expect(request_token).to receive(:get_access_token).with(:oauth_verifier => 'abc123').and_return(mock_access_token) oauth_client.init_access_token(:oauth_verifier => 'abc123') expect(oauth_client.access_token).to eq(mock_access_token) end it "raises an exception when accessing without initialisation" do expect { oauth_client.access_token }.to raise_exception(JIRA::OauthClient::UninitializedAccessTokenError, "init_access_token must be called before using the client") end it "allows setting the access token" do token = double() expect(OAuth::AccessToken).to receive(:new).with(oauth_client.consumer, 'foo', 'bar').and_return(token) access_token = oauth_client.set_access_token('foo', 'bar') expect(access_token).to eq(token) expect(oauth_client.access_token).to eq(token) end end describe "http" do it "responds to the http methods" do headers = double() mock_access_token = double() allow(oauth_client).to receive(:access_token).and_return(mock_access_token) [:delete, :get, :head].each do |method| expect(mock_access_token).to receive(method).with('/path', headers).and_return(response) oauth_client.make_request(method, '/path', '', headers) end [:post, :put].each do |method| expect(mock_access_token).to receive(method).with('/path', '', headers).and_return(response) oauth_client.make_request(method, '/path', '', headers) end end it "performs a request" do body = nil headers = double() access_token = double() expect(access_token).to receive(:send).with(:get, '/foo', headers).and_return(response) allow(oauth_client).to receive(:access_token).and_return(access_token) oauth_client.request(:get, '/foo', body, headers) end end end end jira-ruby-1.4.3/.travis.yml0000644000004100000410000000020113167661427015572 0ustar www-datawww-datalanguage: ruby rvm: - 2.3.1 - ruby-head before_script: - rake jira:generate_public_cert script: bundle exec rake specjira-ruby-1.4.3/lib/0000755000004100000410000000000013167661427014236 5ustar www-datawww-datajira-ruby-1.4.3/lib/jira-ruby.rb0000644000004100000410000000241213167661427016466 0ustar www-datawww-data$: << File.expand_path(File.dirname(__FILE__)) require 'active_support/inflector' ActiveSupport::Inflector.inflections do |inflector| inflector.singular /status$/, 'status' end require 'jira/base' require 'jira/base_factory' require 'jira/has_many_proxy' require 'jira/http_error' require 'jira/resource/user' require 'jira/resource/watcher' require 'jira/resource/attachment' require 'jira/resource/component' require 'jira/resource/issuetype' require 'jira/resource/version' require 'jira/resource/status' require 'jira/resource/transition' require 'jira/resource/project' require 'jira/resource/priority' require 'jira/resource/comment' require 'jira/resource/worklog' require 'jira/resource/applinks' require 'jira/resource/issuelinktype' require 'jira/resource/issuelink' require 'jira/resource/remotelink' require 'jira/resource/issue' require 'jira/resource/filter' require 'jira/resource/field' require 'jira/resource/rapidview' require 'jira/resource/resolution' require 'jira/resource/serverinfo' require 'jira/resource/createmeta' require 'jira/resource/webhook' require 'jira/resource/agile' require 'jira/resource/sprint' require 'jira/request_client' require 'jira/oauth_client' require 'jira/http_client' require 'jira/client' require 'jira/railtie' if defined?(Rails) jira-ruby-1.4.3/lib/tasks/0000755000004100000410000000000013167661427015363 5ustar www-datawww-datajira-ruby-1.4.3/lib/tasks/generate.rake0000644000004100000410000000152213167661427020021 0ustar www-datawww-datarequire 'securerandom' namespace :jira do desc "Generate a consumer key for your application" task :generate_consumer_key do key = SecureRandom.hex(16) puts "You can use this as your consumer key: #{key}" end desc "Run the system call to generate a RSA public certificate" task :generate_public_cert do puts "Executing 'openssl req -x509 -nodes -newkey rsa:1024 -sha1 -keyout rsakey.pem -out rsacert.pem'" system('openssl req -x509 -subj "/C=US/ST=New York/L=New York/O=SUMO Heavy Industries/CN=www.sumoheavy.com" -nodes -newkey rsa:1024 -sha1 -keyout rsakey.pem -out rsacert.pem') puts "Done. The RSA-SHA1 private keyfile is in the current directory: \'rsakey.pem\'." puts "You will need to copy the following certificate into your application link configuration in Jira:" system("cat rsacert.pem") end end jira-ruby-1.4.3/lib/jira/0000755000004100000410000000000013167661427015163 5ustar www-datawww-datajira-ruby-1.4.3/lib/jira/request_client.rb0000644000004100000410000000076513167661427020546 0ustar www-datawww-datarequire 'oauth' require 'json' require 'net/https' #require 'pry' module JIRA class RequestClient # Returns the response if the request was successful (HTTP::2xx) and # raises a JIRA::HTTPError if it was not successful, with the response # attached. def request(*args) response = make_request(*args) #binding.pry unless response.kind_of?(Net::HTTPSuccess) raise HTTPError.new(response) unless response.kind_of?(Net::HTTPSuccess) response end end end jira-ruby-1.4.3/lib/jira/resource/0000755000004100000410000000000013167661427017012 5ustar www-datawww-datajira-ruby-1.4.3/lib/jira/resource/worklog.rb0000644000004100000410000000057213167661427021027 0ustar www-datawww-datamodule JIRA module Resource class WorklogFactory < JIRA::BaseFactory # :nodoc: end class Worklog < JIRA::Base has_one :author, :class => JIRA::Resource::User has_one :update_author, :class => JIRA::Resource::User, :attribute_key => "updateAuthor" belongs_to :issue nested_collections true end end end jira-ruby-1.4.3/lib/jira/resource/issue.rb0000644000004100000410000001114613167661427020472 0ustar www-datawww-datarequire 'cgi' module JIRA module Resource class IssueFactory < JIRA::BaseFactory # :nodoc: end class Issue < JIRA::Base has_one :reporter, :class => JIRA::Resource::User, :nested_under => 'fields' has_one :assignee, :class => JIRA::Resource::User, :nested_under => 'fields' has_one :project, :nested_under => 'fields' has_one :issuetype, :nested_under => 'fields' has_one :priority, :nested_under => 'fields' has_one :status, :nested_under => 'fields' has_many :transitions has_many :components, :nested_under => 'fields' has_many :comments, :nested_under => ['fields','comment'] has_many :attachments, :nested_under => 'fields', :attribute_key => 'attachment' has_many :versions, :nested_under => 'fields' has_many :fixVersions, :class => JIRA::Resource::Version, :nested_under => 'fields' has_many :worklogs, :nested_under => ['fields','worklog'] has_many :issuelinks, :nested_under => 'fields' has_many :remotelink, :class => JIRA::Resource::Remotelink has_many :watchers, :attribute_key => 'watches', :nested_under => ['fields', 'watches'] def self.all(client) url = client.options[:rest_base_path] + "/search?expand=transitions.fields" response = client.get(url) json = parse_json(response.body) json['issues'].map do |issue| client.Issue.build(issue) end end def self.jql(client, jql, options = {fields: nil, start_at: nil, max_results: nil, expand: nil, validate_query: true}) url = client.options[:rest_base_path] + "/search?jql=#{CGI.escape(jql)}" url << "&fields=#{options[:fields].map{ |value| CGI.escape(client.Field.name_to_id(value)) }.join(',')}" if options[:fields] url << "&startAt=#{CGI.escape(options[:start_at].to_s)}" if options[:start_at] url << "&maxResults=#{CGI.escape(options[:max_results].to_s)}" if options[:max_results] url << "&validateQuery=false" if options[:validate_query] === false if options[:expand] options[:expand] = [options[:expand]] if options[:expand].is_a?(String) url << "&expand=#{options[:expand].to_a.map{ |value| CGI.escape(value.to_s) }.join(',')}" end response = client.get(url) json = parse_json(response.body) if options[:max_results] and options[:max_results] == 0 return json['total'] end json['issues'].map do |issue| client.Issue.build(issue) end end # Fetches the attributes for the specified resource from JIRA unless # the resource is already expanded and the optional force reload flag # is not set def fetch(reload = false, query_params = {}) return if expanded? && !reload response = client.get(url_with_query_params(url, query_params)) set_attrs_from_response(response) if @attrs and @attrs['fields'] and @attrs['fields']['worklog'] and @attrs['fields']['worklog']['total'] > @attrs['fields']['worklog']['maxResults'] worklog_url = client.options[:rest_base_path] + "/#{self.class.endpoint_name}/#{id}/worklog" response = client.get(worklog_url) unless response.body.nil? or response.body.length < 2 set_attrs({'fields' => { 'worklog' => self.class.parse_json(response.body) }}, false) end end @expanded = true end def editmeta editmeta_url = client.options[:rest_base_path] + "/#{self.class.endpoint_name}/#{key}/editmeta" response = client.get(editmeta_url) json = self.class.parse_json(response.body) json['fields'] end def respond_to?(method_name, include_all=false) if attrs.keys.include?('fields') && [method_name.to_s, client.Field.name_to_id(method_name)].any? {|k| attrs['fields'].key?(k)} true else super(method_name) end end def method_missing(method_name, *args, &block) if attrs.keys.include?('fields') if attrs['fields'].keys.include?(method_name.to_s) attrs['fields'][method_name.to_s] else official_name=client.Field.name_to_id(method_name) if attrs['fields'].keys.include?(official_name) attrs['fields'][official_name] else super(method_name, *args, &block) end end else super(method_name, *args, &block) end end end end end jira-ruby-1.4.3/lib/jira/resource/remotelink.rb0000644000004100000410000000115213167661427021507 0ustar www-datawww-datamodule JIRA module Resource class RemotelinkFactory < JIRA::BaseFactory # :nodoc: end class Remotelink < JIRA::Base belongs_to :issue def self.endpoint_name 'remotelink' end def self.all(client, options = {}) issue = options[:issue] unless issue raise ArgumentError.new("parent issue is required") end path = "#{issue.self}/#{endpoint_name}" response = client.get(path) json = parse_json(response.body) json.map do |link| issue.remotelink.build(link) end end end end end jira-ruby-1.4.3/lib/jira/resource/project.rb0000644000004100000410000000253613167661427021013 0ustar www-datawww-datamodule JIRA module Resource class ProjectFactory < JIRA::BaseFactory # :nodoc: end class Project < JIRA::Base has_one :lead, :class => JIRA::Resource::User has_many :components has_many :issuetypes, :attribute_key => 'issueTypes' has_many :versions def self.key_attribute :key end # Returns all the issues for this project def issues(options={}) search_url = client.options[:rest_base_path] + '/search' query_params = {:jql => "project=\"#{key}\""} query_params.update Base.query_params_for_search(options) response = client.get(url_with_query_params(search_url, query_params)) json = self.class.parse_json(response.body) json['issues'].map do |issue| client.Issue.build(issue) end end def users(start_at: nil, max_results: nil) users_url = client.options[:rest_base_path] + '/user/assignable/search' query_params = { project: self.key_value } query_params['startAt'] = start_at if start_at query_params['maxResults'] = max_results if max_results response = client.get(url_with_query_params(users_url, query_params)) json = self.class.parse_json(response.body) json.map do |jira_user| client.User.build(jira_user) end end end end end jira-ruby-1.4.3/lib/jira/resource/comment.rb0000644000004100000410000000031013167661427020773 0ustar www-datawww-datamodule JIRA module Resource class CommentFactory < JIRA::BaseFactory # :nodoc: end class Comment < JIRA::Base belongs_to :issue nested_collections true end end end jira-ruby-1.4.3/lib/jira/resource/rapidview.rb0000644000004100000410000000222413167661427021331 0ustar www-datawww-datarequire 'cgi' module JIRA module Resource class RapidViewFactory < JIRA::BaseFactory # :nodoc: end class RapidView < JIRA::Base def self.all(client) response = client.get(path_base(client) + '/rapidview') json = parse_json(response.body) json['views'].map do |view| client.RapidView.build(view) end end def self.find(client, key, options = {}) response = client.get(path_base(client) + "/rapidview/#{key}") json = parse_json(response.body) client.RapidView.build(json) end def issues response = client.get(path_base(client) + "/xboard/plan/backlog/data?rapidViewId=#{id}") json = self.class.parse_json(response.body) # To get Issue objects with the same structure as for Issue.all issue_ids = json['issues'].map { |issue| issue['id'] } client.Issue.jql("id IN(#{issue_ids.join(', ')})") end private def self.path_base(client) client.options[:context_path] + '/rest/greenhopper/1.0' end def path_base(client) self.class.path_base(client) end end end end jira-ruby-1.4.3/lib/jira/resource/status.rb0000644000004100000410000000021513167661427020660 0ustar www-datawww-datamodule JIRA module Resource class StatusFactory < JIRA::BaseFactory # :nodoc: end class Status < JIRA::Base ; end end end jira-ruby-1.4.3/lib/jira/resource/agile.rb0000644000004100000410000000477613167661427020436 0ustar www-datawww-datarequire 'cgi' module JIRA module Resource class AgileFactory < JIRA::BaseFactory # :nodoc: end class Agile < JIRA::Base def self.all(client) response = client.get(path_base(client) + '/board') parse_json(response.body) end def self.get_backlog_issues(client, board_id, options = {}) options[:maxResults] ||= 100 response = client.get(path_base(client) + "/board/#{board_id}/backlog?#{hash_to_query_string(options)}") parse_json(response.body) end def self.get_board_issues(client, board_id, options = {}) response = client.get(path_base(client) + "/board/#{board_id}/issue?#{hash_to_query_string(options)}") json = parse_json(response.body) # To get Issue objects with the same structure as for Issue.all issue_ids = json['issues'].map { |issue| issue['id'] } client.Issue.jql("id IN(#{issue_ids.join(', ')})") end def self.get_sprints(client, board_id, options = {}) options[:maxResults] ||= 100 response = client.get(path_base(client) + "/board/#{board_id}/sprint?#{hash_to_query_string(options)}") parse_json(response.body) end def self.get_sprint_issues(client, sprint_id, options = {}) options[:maxResults] ||= 100 response = client.get(path_base(client) + "/sprint/#{sprint_id}/issue?#{hash_to_query_string(options)}") parse_json(response.body) end def self.get_projects_full(client, board_id, options = {}) response = client.get(path_base(client) + "/board/#{board_id}/project/full") parse_json(response.body) end def self.get_projects(client, board_id, options = {}) options[:maxResults] ||= 100 create_meta_url = path_base(client) + "/board/#{board_id}/project" params = hash_to_query_string(options) response = client.get("#{create_meta_url}?#{params}") parse_json(response.body) end # def self.find(client, key, options = {}) # options[:maxResults] ||= 100 # fields = options[:fields].join(',') unless options[:fields].nil? # response = client.get("/rest/api/latest/search?jql=sprint=#{key}&fields=#{fields}&maxResults=#{options[:maxResults]}") # parse_json(response.body) # end private def self.path_base(client) client.options[:context_path] + '/rest/agile/1.0' end def path_base(client) self.class.path_base(client) end end end end jira-ruby-1.4.3/lib/jira/resource/watcher.rb0000644000004100000410000000122213167661427020771 0ustar www-datawww-datamodule JIRA module Resource class WatcherFactory < JIRA::BaseFactory # :nodoc: end class Watcher < JIRA::Base belongs_to :issue nested_collections true def self.endpoint_name 'watchers' end def self.all(client, options = {}) issue = options[:issue] unless issue raise ArgumentError.new("parent issue is required") end path = "#{issue.self}/#{endpoint_name}" response = client.get(path) json = parse_json(response.body) json['watchers'].map do |watcher| issue.watchers.build(watcher) end end end end end jira-ruby-1.4.3/lib/jira/resource/webhook.rb0000644000004100000410000000146013167661427020776 0ustar www-datawww-datamodule JIRA module Resource class WebhookFactory < JIRA::BaseFactory # :nodoc: end class Webhook < JIRA::Base REST_BASE_PATH = '/rest/webhooks/1.0' def self.endpoint_name 'webhook' end def self.full_url(client) client.options[:context_path] + REST_BASE_PATH end def self.collection_path(client, prefix = '/') self.full_url(client) + prefix + self.endpoint_name end def self.all(client, options = {}) response = client.get(collection_path(client)) json = parse_json(response.body) json.map do |attrs| self.new(client, {:attrs => attrs}.merge(options)) end end # def self.save(options={}) # end # def self.delete(options={}) # end end end end jira-ruby-1.4.3/lib/jira/resource/sprint.rb0000644000004100000410000000160713167661427020662 0ustar www-datawww-datarequire 'cgi' module JIRA module Resource class SprintFactory < JIRA::BaseFactory # :nodoc: end class Sprint < JIRA::Base def self.all(client, key) response = client.get(path_base(client) + '/sprintquery/' + key.to_s) parse_json(response.body) end def self.find(client, key, options = {}) options[:maxResults] ||= 100 options[:startAt] ||= 0 fields = options[:fields].join(',') unless options[:fields].nil? response = client.get("/rest/api/latest/search?jql=sprint=#{key}&fields=#{fields}&startAt=#{options[:startAt]}&maxResults=#{options[:maxResults]}") parse_json(response.body) end private def self.path_base(client) client.options[:context_path] + '/rest/greenhopper/1.0' end def path_base(client) self.class.path_base(client) end end end end jira-ruby-1.4.3/lib/jira/resource/component.rb0000644000004100000410000000022313167661427021336 0ustar www-datawww-datamodule JIRA module Resource class ComponentFactory < JIRA::BaseFactory # :nodoc: end class Component < JIRA::Base ; end end end jira-ruby-1.4.3/lib/jira/resource/issuetype.rb0000644000004100000410000000022313167661427021366 0ustar www-datawww-datamodule JIRA module Resource class IssuetypeFactory < JIRA::BaseFactory # :nodoc: end class Issuetype < JIRA::Base ; end end end jira-ruby-1.4.3/lib/jira/resource/issuelinktype.rb0000644000004100000410000000037213167661427022251 0ustar www-datawww-datamodule JIRA module Resource class IssuelinktypeFactory < JIRA::BaseFactory # :nodoc: end class Issuelinktype < JIRA::Base nested_collections true def self.endpoint_name 'issueLinkType' end end end end jira-ruby-1.4.3/lib/jira/resource/filter.rb0000644000004100000410000000046613167661427020632 0ustar www-datawww-datamodule JIRA module Resource class FilterFactory < JIRA::BaseFactory # :nodoc: end class Filter < JIRA::Base has_one :owner, :class => JIRA::Resource::User # Returns all the issues for this filter def issues Issue.jql(self.client, self.jql) end end end end jira-ruby-1.4.3/lib/jira/resource/user.rb0000644000004100000410000000071513167661427020320 0ustar www-datawww-datamodule JIRA module Resource class UserFactory < JIRA::BaseFactory # :nodoc: def myself instance = build response = client.get("#{client.options[:rest_base_path]}/myself") instance.set_attrs_from_response(response) instance end end class User < JIRA::Base def self.singular_path(client, key, prefix = '/') collection_path(client, prefix) + '?username=' + key end end end end jira-ruby-1.4.3/lib/jira/resource/priority.rb0000644000004100000410000000022113167661427021213 0ustar www-datawww-datamodule JIRA module Resource class PriorityFactory < JIRA::BaseFactory # :nodoc: end class Priority < JIRA::Base ; end end end jira-ruby-1.4.3/lib/jira/resource/version.rb0000644000004100000410000000021713167661427021024 0ustar www-datawww-datamodule JIRA module Resource class VersionFactory < JIRA::BaseFactory # :nodoc: end class Version < JIRA::Base ; end end end jira-ruby-1.4.3/lib/jira/resource/resolution.rb0000644000004100000410000000022413167661427021540 0ustar www-datawww-datamodule JIRA module Resource class ResolutionFactory < JIRA::BaseFactory # :nodoc: end class Resolution < JIRA::Base ; end end endjira-ruby-1.4.3/lib/jira/resource/attachment.rb0000644000004100000410000000234613167661427021474 0ustar www-datawww-datarequire 'net/http/post/multipart' module JIRA module Resource class AttachmentFactory < JIRA::BaseFactory # :nodoc: delegate_to_target_class :meta end class Attachment < JIRA::Base belongs_to :issue has_one :author, :class => JIRA::Resource::User def self.endpoint_name 'attachments' end def self.meta(client) response = client.get(client.options[:rest_base_path] + '/attachment/meta') parse_json(response.body) end def save!(attrs) headers = { 'X-Atlassian-Token' => 'nocheck' } data = { 'file' => UploadIO.new(attrs['file'], 'application/binary', attrs['file']) } request = Net::HTTP::Post::Multipart.new url, data, headers request.basic_auth(client.request_client.options[:username], client.request_client.options[:password]) response = client.request_client.basic_auth_http_conn.request(request) set_attrs(attrs, false) unless response.body.nil? || response.body.length < 2 json = self.class.parse_json(response.body) attachment = json[0] set_attrs(attachment) end @expanded = false true end end end end jira-ruby-1.4.3/lib/jira/resource/applinks.rb0000644000004100000410000000201313167661427021154 0ustar www-datawww-datamodule JIRA module Resource class ApplicationLinkFactory < JIRA::BaseFactory # :nodoc: delegate_to_target_class :manifest end class ApplicationLink < JIRA::Base REST_BASE_PATH = '/rest/applinks/1.0' def self.endpoint_name 'listApplicationlinks' end def self.full_url(client) client.options[:context_path] + REST_BASE_PATH end def self.collection_path(client, prefix = '/') self.full_url(client) + prefix + self.endpoint_name end def self.all(client, options = {}) response = client.get(collection_path(client)) json = parse_json(response.body) json = json['list'] json.map do |attrs| self.new(client, {:attrs => attrs}.merge(options)) end end def self.manifest(client) url = self.full_url(client) + '/manifest' response = client.get(url) json = parse_json(response.body) JIRA::Base.new(client, {:attrs => json}) end end end end jira-ruby-1.4.3/lib/jira/resource/field.rb0000644000004100000410000000515213167661427020425 0ustar www-datawww-datamodule JIRA module Resource class FieldFactory < JIRA::BaseFactory # :nodoc: delegate_to_target_class :map_fields, :name_to_id, :field_map end class Field < JIRA::Base #translate a custom field description to a method-safe name def self.safe_name(description) description.gsub(/[^a-zA-Z0-9]/,'_') end # safe_name plus disambiguation if it fails it uses the original jira id (customfield_#####) def self.safer_name(description, jira_id) "#{safe_name(description)}_#{jira_id.split('_')[1]}" rescue jira_id end def self.map_fields(client) field_map = {} field_map_reverse = {} fields = client.Field.all # two pass approach, so that a custom field with the same name # as a system field can't take precedence fields.each do |f| next if f.custom name = safe_name(f.name) field_map_reverse[f.id] = [f.name, name] # capture both the official name, and the mapped name field_map[name] = f.id end fields.each do |f| next unless f.custom name = if field_map.key? f.name renamed = safer_name(f.name, f.id) warn "Duplicate Field name #{f.name} #{f.id} - renaming as #{renamed}" renamed else safe_name(f.name) end field_map_reverse[f.id] = [f.name, name] # capture both the official name, and the mapped name field_map[name] = f.id end client.cache.field_map_reverse = field_map_reverse # not sure where this will be used yet, but sure to be useful client.cache.field_map = field_map end def self.field_map(client) client.cache.field_map end def self.name_to_id(client, field_name) field_name = field_name.to_s return field_name unless client.cache.field_map && client.cache.field_map[field_name] client.cache.field_map[field_name] end def respond_to?(method_name, include_all=false) if [method_name.to_s, client.Field.name_to_id(method_name)].any? {|k| attrs.key?(k)} true else super(method_name) end end def method_missing(method_name, *args, &block) if attrs.keys.include?(method_name.to_s) attrs[method_name.to_s] else official_name=client.Field.name_to_id(method_name) if attrs.keys.include?(official_name) attrs[official_name] else super(method_name, *args, &block) end end end end end end jira-ruby-1.4.3/lib/jira/resource/issuelink.rb0000644000004100000410000000103513167661427021344 0ustar www-datawww-datamodule JIRA module Resource class IssuelinkFactory < JIRA::BaseFactory # :nodoc: end # Because of circular dependency Issue->IssueLink->Issue # we have to declare JIRA::Resource::Issue class. class Issue < JIRA::Base; end class Issuelink < JIRA::Base has_one :type, :class => JIRA::Resource::Issuelinktype has_one :inwardIssue, :class => JIRA::Resource::Issue has_one :outwardIssue, :class => JIRA::Resource::Issue def self.endpoint_name 'issueLink' end end end end jira-ruby-1.4.3/lib/jira/resource/transition.rb0000644000004100000410000000136513167661427021536 0ustar www-datawww-datamodule JIRA module Resource class TransitionFactory < JIRA::BaseFactory # :nodoc: end class Transition < JIRA::Base has_one :to, :class => JIRA::Resource::Status belongs_to :issue nested_collections true def self.endpoint_name 'transitions' end def self.all(client, options = {}) issue = options[:issue] unless issue raise ArgumentError.new("parent issue is required") end path = "#{issue.self}/#{endpoint_name}?expand=transitions.fields" response = client.get(path) json = parse_json(response.body) json['transitions'].map do |transition| issue.transitions.build(transition) end end end end end jira-ruby-1.4.3/lib/jira/resource/createmeta.rb0000644000004100000410000000271613167661427021457 0ustar www-datawww-datamodule JIRA module Resource class CreatemetaFactory < JIRA::BaseFactory # :nodoc: end class Createmeta < JIRA::Base def self.endpoint_name '/issue/createmeta' end def self.all(client, params={}) if params.has_key?(:projectKeys) values = Array(params[:projectKeys]).map{|i| (i.is_a?(JIRA::Resource::Project) ? i.key : i)} params[:projectKeys] = values.join(',') end if params.has_key?(:projectIds) values = Array(params[:projectIds]).map{|i| (i.is_a?(JIRA::Resource::Project) ? i.id : i)} params[:projectIds] = values.join(',') end if params.has_key?(:issuetypeNames) values = Array(params[:issuetypeNames]).map{|i| (i.is_a?(JIRA::Resource::Issuetype) ? i.name : i)} params[:issuetypeNames] = values.join(',') end if params.has_key?(:issuetypeIds) values = Array(params[:issuetypeIds]).map{|i| (i.is_a?(JIRA::Resource::Issuetype) ? i.id : i)} params[:issuetypeIds] = values.join(',') end create_meta_url = client.options[:rest_base_path] + self.endpoint_name params = hash_to_query_string(params) response = params.empty? ? client.get("#{create_meta_url}") : client.get("#{create_meta_url}?#{params}") json = parse_json(response.body) json['projects'].map do |attrs| self.new(client, {:attrs => attrs}) end end end end end jira-ruby-1.4.3/lib/jira/resource/serverinfo.rb0000644000004100000410000000064013167661427021521 0ustar www-datawww-datamodule JIRA module Resource class ServerInfoFactory < JIRA::BaseFactory # :nodoc: end class ServerInfo < JIRA::Base def self.endpoint_name 'serverInfo' end def self.all(client, options = {}) response = client.get(collection_path(client)) json = parse_json(response.body) self.new(client, {:attrs => json}.merge(options)) end end end end jira-ruby-1.4.3/lib/jira/base_factory.rb0000644000004100000410000000320313167661427020147 0ustar www-datawww-datamodule JIRA # This is the base class for all the JIRA resource factory instances. class BaseFactory attr_reader :client def initialize(client) @client = client end # Return the name of the class which this factory generates, i.e. # JIRA::Resource::FooFactory creates JIRA::Resource::Foo instances. def target_class # Need to do a little bit of work here as Module.const_get doesn't work # with nested class names, i.e. JIRA::Resource::Foo. # # So create a method chain from the class components. This code will # unroll to: # Module.const_get('JIRA').const_get('Resource').const_get('Foo') # target_class_name = self.class.name.sub(/Factory$/, '') class_components = target_class_name.split('::') class_components.inject(Module) do |mod, const_name| mod.const_get(const_name) end end def self.delegate_to_target_class(*method_names) method_names.each do |method_name| define_method method_name do |*args| target_class.send(method_name, @client, *args) end end end # The principle purpose of this class is to delegate methods to the corresponding # non-factory class and automatically prepend the client argument to the argument # list. delegate_to_target_class :all, :find, :collection_path, :singular_path, :jql, :get_backlog_issues, :get_board_issues, :get_sprints, :get_sprint_issues, :get_projects, :get_projects_full # This method needs special handling as it has a default argument value def build(attrs={}) target_class.build(@client, attrs) end end end jira-ruby-1.4.3/lib/jira/oauth_client.rb0000644000004100000410000000561613167661427020176 0ustar www-datawww-datarequire 'oauth' require 'json' require 'forwardable' module JIRA class OauthClient < RequestClient DEFAULT_OPTIONS = { :signature_method => 'RSA-SHA1', :request_token_path => "/plugins/servlet/oauth/request-token", :authorize_path => "/plugins/servlet/oauth/authorize", :access_token_path => "/plugins/servlet/oauth/access-token", :private_key_file => "rsakey.pem", :consumer_key => nil, :consumer_secret => nil } # This exception is thrown when the client is used before the OAuth access token # has been initialized. class UninitializedAccessTokenError < StandardError def message "init_access_token must be called before using the client" end end extend Forwardable attr_accessor :consumer attr_reader :options def_instance_delegators :@consumer, :key, :secret, :get_request_token def initialize(options) @options = DEFAULT_OPTIONS.merge(options) @consumer = init_oauth_consumer(@options) end def init_oauth_consumer(options) @options[:request_token_path] = @options[:context_path] + @options[:request_token_path] @options[:authorize_path] = @options[:context_path] + @options[:authorize_path] @options[:access_token_path] = @options[:context_path] + @options[:access_token_path] OAuth::Consumer.new(@options[:consumer_key],@options[:consumer_secret],@options) end # Returns the current request token if it is set, else it creates # and sets a new token. def request_token(options = {}, *arguments, &block) @request_token ||= get_request_token(options, *arguments, block) end # Sets the request token from a given token and secret. def set_request_token(token, secret) @request_token = OAuth::RequestToken.new(@consumer, token, secret) end # Initialises and returns a new access token from the params hash # returned by the OAuth transaction. def init_access_token(params) @access_token = request_token.get_access_token(params) end # Sets the access token from a preexisting token and secret. def set_access_token(token, secret) @access_token = OAuth::AccessToken.new(@consumer, token, secret) @authenticated = true @access_token end # Returns the current access token. Raises an # JIRA::Client::UninitializedAccessTokenError exception if it is not set. def access_token raise UninitializedAccessTokenError.new unless @access_token @access_token end def make_request(http_method, path, body='', headers={}) case http_method when :delete, :get, :head response = access_token.send http_method, path, headers when :post, :put response = access_token.send http_method, path, body, headers end @authenticated = true response end def authenticated? @authenticated end end end jira-ruby-1.4.3/lib/jira/has_many_proxy.rb0000644000004100000410000000263713167661427020560 0ustar www-datawww-data# # Whenever a collection from a has_many relationship is accessed, an instance # of this class is returned. This instance wraps the Array of instances in # the collection with an extra build method, which allows new instances to be # built on the collection with the correct properties. # # In practice, instances of this class behave exactly like an Array. # class JIRA::HasManyProxy attr_reader :target_class, :parent attr_accessor :collection def initialize(parent, target_class, collection = []) @parent = parent @target_class = target_class @collection = collection end # Builds an instance of this class with the correct parent. # For example, issue.comments.build(attrs) will initialize a # comment as follows: # # JIRA::Resource::Comment.new(issue.client, # :attrs => attrs, # :issue => issue) def build(attrs = {}) resource = target_class.new(parent.client, :attrs => attrs, parent.to_sym => parent) collection << resource resource end # Forces an HTTP request to fetch all instances of the target class that # are associated with the parent def all target_class.all(parent.client, parent.to_sym => parent) end # Delegate any missing methods to the collection that this proxy wraps def method_missing(method_name, *args, &block) collection.send(method_name, *args, &block) end end jira-ruby-1.4.3/lib/jira/client.rb0000644000004100000410000001421113167661427016765 0ustar www-datawww-datarequire 'json' require 'forwardable' require 'ostruct' module JIRA # This class is the main access point for all JIRA::Resource instances. # # The client must be initialized with an options hash containing # configuration options. The available options are: # # :site => 'http://localhost:2990', # :context_path => '/jira', # :signature_method => 'RSA-SHA1', # :request_token_path => "/plugins/servlet/oauth/request-token", # :authorize_path => "/plugins/servlet/oauth/authorize", # :access_token_path => "/plugins/servlet/oauth/access-token", # :private_key_file => "rsakey.pem", # :rest_base_path => "/rest/api/2", # :consumer_key => nil, # :consumer_secret => nil, # :ssl_verify_mode => OpenSSL::SSL::VERIFY_PEER, # :use_ssl => true, # :username => nil, # :password => nil, # :auth_type => :oauth, # :proxy_address => nil, # :proxy_port => nil, # :additional_cookies => nil # # See the JIRA::Base class methods for all of the available methods on these accessor # objects. class Client extend Forwardable # The OAuth::Consumer instance returned by the OauthClient # # The authenticated client instance returned by the respective client type # (Oauth, Basic) attr_accessor :consumer, :request_client, :http_debug, :cache # The configuration options for this client instance attr_reader :options def_delegators :@request_client, :init_access_token, :set_access_token, :set_request_token, :request_token, :access_token, :authenticated? DEFAULT_OPTIONS = { :site => 'http://localhost:2990', :context_path => '/jira', :rest_base_path => "/rest/api/2", :ssl_verify_mode => OpenSSL::SSL::VERIFY_PEER, :use_ssl => true, :auth_type => :oauth, :http_debug => false } def initialize(options={}) options = DEFAULT_OPTIONS.merge(options) @options = options @options[:rest_base_path] = @options[:context_path] + @options[:rest_base_path] case options[:auth_type] when :oauth @request_client = OauthClient.new(@options) @consumer = @request_client.consumer when :basic @request_client = HttpClient.new(@options) when :cookie raise ArgumentError, 'Options: :use_cookies must be true for :cookie authorization type' if @options.key?(:use_cookies) && !@options[:use_cookies] @options[:use_cookies] = true @request_client = HttpClient.new(@options) @request_client.make_cookie_auth_request @options.delete(:username) @options.delete(:password) else raise ArgumentError, 'Options: ":auth_type" must be ":oauth", ":cookie" or ":basic"' end @http_debug = @options[:http_debug] @options.freeze @cache = OpenStruct.new end def Project # :nodoc: JIRA::Resource::ProjectFactory.new(self) end def Issue # :nodoc: JIRA::Resource::IssueFactory.new(self) end def Filter # :nodoc: JIRA::Resource::FilterFactory.new(self) end def Component # :nodoc: JIRA::Resource::ComponentFactory.new(self) end def User # :nodoc: JIRA::Resource::UserFactory.new(self) end def Issuetype # :nodoc: JIRA::Resource::IssuetypeFactory.new(self) end def Priority # :nodoc: JIRA::Resource::PriorityFactory.new(self) end def Status # :nodoc: JIRA::Resource::StatusFactory.new(self) end def Resolution # :nodoc: JIRA::Resource::ResolutionFactory.new(self) end def Comment # :nodoc: JIRA::Resource::CommentFactory.new(self) end def Attachment # :nodoc: JIRA::Resource::AttachmentFactory.new(self) end def Worklog # :nodoc: JIRA::Resource::WorklogFactory.new(self) end def Version # :nodoc: JIRA::Resource::VersionFactory.new(self) end def Transition # :nodoc: JIRA::Resource::TransitionFactory.new(self) end def Field # :nodoc: JIRA::Resource::FieldFactory.new(self) end def RapidView JIRA::Resource::RapidViewFactory.new(self) end def ServerInfo JIRA::Resource::ServerInfoFactory.new(self) end def Createmeta JIRA::Resource::CreatemetaFactory.new(self) end def ApplicationLink JIRA::Resource::ApplicationLinkFactory.new(self) end def Watcher JIRA::Resource::WatcherFactory.new(self) end def Webhook JIRA::Resource::WebhookFactory.new(self) end def Issuelink JIRA::Resource::IssuelinkFactory.new(self) end def Issuelinktype JIRA::Resource::IssuelinktypeFactory.new(self) end def Remotelink JIRA::Resource::RemotelinkFactory.new(self) end def Sprint JIRA::Resource::SprintFactory.new(self) end def Agile JIRA::Resource::AgileFactory.new(self) end # HTTP methods without a body def delete(path, headers = {}) request(:delete, path, nil, merge_default_headers(headers)) end def get(path, headers = {}) request(:get, path, nil, merge_default_headers(headers)) end def head(path, headers = {}) request(:head, path, nil, merge_default_headers(headers)) end # HTTP methods with a body def post(path, body = '', headers = {}) headers = {'Content-Type' => 'application/json'}.merge(headers) request(:post, path, body, merge_default_headers(headers)) end def put(path, body = '', headers = {}) headers = {'Content-Type' => 'application/json'}.merge(headers) request(:put, path, body, merge_default_headers(headers)) end # Sends the specified HTTP request to the REST API through the # appropriate method (oauth, basic). def request(http_method, path, body = '', headers={}) puts "#{http_method}: #{path} - [#{body}]" if @http_debug @request_client.request(http_method, path, body, headers) end protected def merge_default_headers(headers) {'Accept' => 'application/json'}.merge(headers) end end end jira-ruby-1.4.3/lib/jira/version.rb0000644000004100000410000000004413167661427017173 0ustar www-datawww-datamodule JIRA VERSION = '1.4.3' end jira-ruby-1.4.3/lib/jira/http_error.rb0000644000004100000410000000037413167661427017704 0ustar www-datawww-datarequire 'forwardable' module JIRA class HTTPError < StandardError extend Forwardable def_instance_delegators :@response, :message, :code attr_reader :response def initialize(response) @response = response end end end jira-ruby-1.4.3/lib/jira/http_client.rb0000644000004100000410000000524213167661427020030 0ustar www-datawww-datarequire 'json' require 'net/https' require 'cgi/cookie' require 'uri' module JIRA class HttpClient < RequestClient DEFAULT_OPTIONS = { :username => '', :password => '' } attr_reader :options def initialize(options) @options = DEFAULT_OPTIONS.merge(options) @cookies = {} end def make_cookie_auth_request body = { :username => @options[:username], :password => @options[:password] }.to_json @options.delete(:username) @options.delete(:password) make_request(:post, @options[:context_path] + '/rest/auth/1/session', body, {'Content-Type' => 'application/json'}) end def make_request(http_method, url, body='', headers={}) # When a proxy is enabled, Net::HTTP expects that the request path omits the domain name path = request_path(url) request = Net::HTTP.const_get(http_method.to_s.capitalize).new(path, headers) request.body = body unless body.nil? add_cookies(request) if options[:use_cookies] request.basic_auth(@options[:username], @options[:password]) if @options[:username] && @options[:password] response = basic_auth_http_conn.request(request) @authenticated = response.is_a? Net::HTTPOK store_cookies(response) if options[:use_cookies] response end def basic_auth_http_conn http_conn(uri) end def http_conn(uri) if @options[:proxy_address] http_class = Net::HTTP::Proxy(@options[:proxy_address], @options[:proxy_port] ? @options[:proxy_port] : 80) else http_class = Net::HTTP end http_conn = http_class.new(uri.host, uri.port) http_conn.use_ssl = @options[:use_ssl] http_conn.verify_mode = @options[:ssl_verify_mode] http_conn.read_timeout = @options[:read_timeout] http_conn end def uri uri = URI.parse(@options[:site]) end def authenticated? @authenticated end private def request_path(url) parsed_uri = URI(url) return url unless parsed_uri.is_a?(URI::HTTP) parsed_uri.request_uri end def store_cookies(response) cookies = response.get_fields('set-cookie') if cookies cookies.each do |cookie| data = CGI::Cookie.parse(cookie) data.delete('Path') @cookies.merge!(data) end end end def add_cookies(request) cookie_array = @cookies.values.map { |cookie| "#{cookie.name}=#{cookie.value[0]}" } cookie_array += Array(@options[:additional_cookies]) if @options.key?(:additional_cookies) request.add_field('Cookie', cookie_array.join('; ')) if cookie_array.any? request end end end jira-ruby-1.4.3/lib/jira/base.rb0000644000004100000410000004511413167661427016427 0ustar www-datawww-datarequire 'active_support/core_ext/string' require 'active_support/inflector' require 'set' module JIRA # This class provides the basic object <-> REST mapping for all JIRA::Resource subclasses, # i.e. the Create, Retrieve, Update, Delete lifecycle methods. # # == Lifecycle methods # # Note that not all lifecycle # methods are available for all resources, for example some resources cannot be updated # or deleted. # # === Retrieving all resources # # client.Resource.all # # === Retrieving a single resource # # client.Resource.find(id) # # === Creating a resource # # resource = client.Resource.build({'name' => '') # resource.save # # === Updating a resource # # resource = client.Resource.find(id) # resource.save('updated_attribute' => 'new value') # # === Deleting a resource # # resource = client.Resource.find(id) # resource.delete # # == Nested resources # # Some resources are not defined in the top level of the URL namespace # within the JIRA API, but are always nested under the context of another # resource. For example, a JIRA::Resource::Comment always belongs to a # JIRA::Resource::Issue. # # These resources must be indexed and built from an instance of the class # they are nested under: # # issue = client.Issue.find(id) # comments = issue.comments # new_comment = issue.comments.build # class Base QUERY_PARAMS_FOR_SINGLE_FETCH = Set.new [:expand, :fields] QUERY_PARAMS_FOR_SEARCH = Set.new [:expand, :fields, :startAt, :maxResults] # A reference to the JIRA::Client used to initialize this resource. attr_reader :client # Returns true if this instance has been fetched from the server attr_accessor :expanded # Returns true if this instance has been deleted from the server attr_accessor :deleted # The hash of attributes belonging to this instance. An exact # representation of the JSON returned from the JIRA API attr_accessor :attrs alias :expanded? :expanded alias :deleted? :deleted def initialize(client, options = {}) @client = client @attrs = options[:attrs] || {} @expanded = options[:expanded] || false @deleted = false # If this class has any belongs_to relationships, a value for # each of them must be passed in to the initializer. self.class.belongs_to_relationships.each do |relation| if options[relation] instance_variable_set("@#{relation.to_s}", options[relation]) instance_variable_set("@#{relation.to_s}_id", options[relation].key_value) elsif options["#{relation}_id".to_sym] instance_variable_set("@#{relation.to_s}_id", options["#{relation}_id".to_sym]) else raise ArgumentError.new("Required option #{relation.inspect} missing") unless options[relation] end end end # The class methods are never called directly, they are always # invoked from a BaseFactory subclass instance. def self.all(client, options = {}) response = client.get(collection_path(client)) json = parse_json(response.body) if collection_attributes_are_nested json = json[endpoint_name.pluralize] end json.map do |attrs| self.new(client, {:attrs => attrs}.merge(options)) end end # Finds and retrieves a resource with the given ID. def self.find(client, key, options = {}) instance = self.new(client, options) instance.attrs[key_attribute.to_s] = key instance.fetch(false, query_params_for_single_fetch(options)) instance end # Builds a new instance of the resource with the given attributes. # These attributes will be posted to the JIRA Api if save is called. def self.build(client, attrs) self.new(client, :attrs => attrs) end # Returns the name of this resource for use in URL components. # E.g. # JIRA::Resource::Issue.endpoint_name # # => issue def self.endpoint_name self.name.split('::').last.downcase end # Returns the full path for a collection of this resource. # E.g. # JIRA::Resource::Issue.collection_path # # => /jira/rest/api/2/issue def self.collection_path(client, prefix = '/') client.options[:rest_base_path] + prefix + self.endpoint_name end # Returns the singular path for the resource with the given key. # E.g. # JIRA::Resource::Issue.singular_path('123') # # => /jira/rest/api/2/issue/123 # # If a prefix parameter is provided it will be injected between the base # path and the endpoint. # E.g. # JIRA::Resource::Comment.singular_path('456','/issue/123/') # # => /jira/rest/api/2/issue/123/comment/456 def self.singular_path(client, key, prefix = '/') collection_path(client, prefix) + '/' + key end # Returns the attribute name of the attribute used for find. # Defaults to :id unless overridden. def self.key_attribute :id end def self.parse_json(string) # :nodoc: JSON.parse(string) end # Declares that this class contains a singular instance of another resource # within the JSON returned from the JIRA API. # # class Example < JIRA::Base # has_one :child # end # # example = client.Example.find(1) # example.child # Returns a JIRA::Resource::Child # # The following options can be used to override the default behaviour of the # relationship: # # [:attribute_key] The relationship will by default reference a JSON key on the # object with the same name as the relationship. # # has_one :child # => {"id":"123",{"child":{"id":"456"}}} # # Use this option if the key in the JSON is named differently. # # # Respond to resource.child, but return the value of resource.attrs['kid'] # has_one :child, :attribute_key => 'kid' # => {"id":"123",{"kid":{"id":"456"}}} # # [:class] The class of the child instance will be inferred from the name of the # relationship. E.g. has_one :child will return a JIRA::Resource::Child. # Use this option to override the inferred class. # # has_one :child, :class => JIRA::Resource::Kid # [:nested_under] In some cases, the JSON return from JIRA is nested deeply for particular # relationships. This option allows the nesting to be specified. # # # Specify a single depth of nesting. # has_one :child, :nested_under => 'foo' # # => Looks for {"foo":{"child":{}}} # # Specify deeply nested JSON # has_one :child, :nested_under => ['foo', 'bar', 'baz'] # # => Looks for {"foo":{"bar":{"baz":{"child":{}}}}} def self.has_one(resource, options = {}) attribute_key = options[:attribute_key] || resource.to_s child_class = options[:class] || ('JIRA::Resource::' + resource.to_s.classify).constantize define_method(resource) do attribute = maybe_nested_attribute(attribute_key, options[:nested_under]) return nil unless attribute child_class.new(client, :attrs => attribute) end end # Declares that this class contains a collection of another resource # within the JSON returned from the JIRA API. # # class Example < JIRA::Base # has_many :children # end # # example = client.Example.find(1) # example.children # Returns an instance of Jira::Resource::HasManyProxy, # # which behaves exactly like an array of # # Jira::Resource::Child # # The following options can be used to override the default behaviour of the # relationship: # # [:attribute_key] The relationship will by default reference a JSON key on the # object with the same name as the relationship. # # has_many :children # => {"id":"123",{"children":[{"id":"456"},{"id":"789"}]}} # # Use this option if the key in the JSON is named differently. # # # Respond to resource.children, but return the value of resource.attrs['kids'] # has_many :children, :attribute_key => 'kids' # => {"id":"123",{"kids":[{"id":"456"},{"id":"789"}]}} # # [:class] The class of the child instance will be inferred from the name of the # relationship. E.g. has_many :children will return an instance # of JIRA::Resource::HasManyProxy containing the collection of # JIRA::Resource::Child. # Use this option to override the inferred class. # # has_many :children, :class => JIRA::Resource::Kid # [:nested_under] In some cases, the JSON return from JIRA is nested deeply for particular # relationships. This option allows the nesting to be specified. # # # Specify a single depth of nesting. # has_many :children, :nested_under => 'foo' # # => Looks for {"foo":{"children":{}}} # # Specify deeply nested JSON # has_many :children, :nested_under => ['foo', 'bar', 'baz'] # # => Looks for {"foo":{"bar":{"baz":{"children":{}}}}} def self.has_many(collection, options = {}) attribute_key = options[:attribute_key] || collection.to_s child_class = options[:class] || ('JIRA::Resource::' + collection.to_s.classify).constantize self_class_basename = self.name.split('::').last.downcase.to_sym define_method(collection) do child_class_options = {self_class_basename => self} attribute = maybe_nested_attribute(attribute_key, options[:nested_under]) || [] collection = attribute.map do |child_attributes| child_class.new(client, child_class_options.merge(:attrs => child_attributes)) end HasManyProxy.new(self, child_class, collection) end end def self.belongs_to_relationships @belongs_to_relationships ||= [] end def self.belongs_to(resource) belongs_to_relationships.push(resource) attr_reader resource attr_reader "#{resource}_id" end def self.collection_attributes_are_nested @collection_attributes_are_nested ||= false end def self.nested_collections(value) @collection_attributes_are_nested = value end def id attrs['id'] end # Returns a symbol for the given instance, for example # JIRA::Resource::Issue returns :issue def to_sym self.class.endpoint_name.to_sym end # Checks if method_name is set in the attributes hash # and returns true when found, otherwise proxies the # call to the superclass. def respond_to?(method_name, include_all=false) if attrs.keys.include? method_name.to_s true else super(method_name) end end # Overrides method_missing to check the attribute hash # for resources matching method_name and proxies the call # to the superclass if no match is found. def method_missing(method_name, *args, &block) if attrs.keys.include? method_name.to_s attrs[method_name.to_s] else super(method_name) end end # Each resource has a unique key attribute, this method returns the value # of that key for this instance. def key_value @attrs[self.class.key_attribute.to_s] end def collection_path(prefix = "/") # Just proxy this to the class method self.class.collection_path(client, prefix) end # This returns the URL path component that is specific to this instance, # for example for Issue id 123 it returns '/issue/123'. For an unsaved # issue it returns '/issue' def path_component path_component = "/#{self.class.endpoint_name}" if key_value path_component += '/' + key_value end path_component end # Fetches the attributes for the specified resource from JIRA unless # the resource is already expanded and the optional force reload flag # is not set def fetch(reload = false, query_params = {}) return if expanded? && !reload response = client.get(url_with_query_params(url, query_params)) set_attrs_from_response(response) @expanded = true end # Saves the specified resource attributes by sending either a POST or PUT # request to JIRA, depending on resource.new_record? # # Accepts an attributes hash of the values to be saved. Will throw a # JIRA::HTTPError if the request fails (response is not HTTP 2xx). def save!(attrs) http_method = new_record? ? :post : :put response = client.send(http_method, new_record? ? url : patched_url, attrs.to_json) set_attrs(attrs, false) set_attrs_from_response(response) @expanded = false true end # Saves the specified resource attributes by sending either a POST or PUT # request to JIRA, depending on resource.new_record? # # Accepts an attributes hash of the values to be saved. Will return false # if the request fails. def save(attrs) begin save_status = save!(attrs) rescue JIRA::HTTPError => exception begin set_attrs_from_response(exception.response) # Merge error status generated by JIRA REST API rescue JSON::ParserError => parse_exception set_attrs("exception" => { "class" => exception.response.class.name, "code" => exception.response.code, "message" => exception.response.message } ) end # raise exception save_status = false end save_status end # Sets the attributes hash from a HTTPResponse object from JIRA if it is # not nil or is not a json response. def set_attrs_from_response(response) unless response.body.nil? or response.body.length < 2 json = self.class.parse_json(response.body) set_attrs(json) end end # Set the current attributes from a hash. If clobber is true, any existing # hash values will be clobbered by the new hash, otherwise the hash will # be deeply merged into attrs. The target paramater is for internal use only # and should not be used. def set_attrs(hash, clobber=true, target = nil) target ||= @attrs if clobber target.merge!(hash) hash else hash.each do |k, v| if v.is_a?(Hash) set_attrs(v, clobber, target[k]) else target[k] = v end end end end # Sends a delete request to the JIRA Api and sets the deleted instance # variable on the object to true. def delete client.delete(url) @deleted = true end def has_errors? respond_to?('errors') end def url prefix = '/' unless self.class.belongs_to_relationships.empty? prefix = self.class.belongs_to_relationships.inject(prefix) do |prefix_so_far, relationship| prefix_so_far.to_s + relationship.to_s + "/" + self.send("#{relationship.to_s}_id").to_s + '/' end end if @attrs['self'] the_url = @attrs['self'] the_url = the_url.sub(@client.options[:site], '') if @client.options[:site] the_url elsif key_value self.class.singular_path(client, key_value.to_s, prefix) else self.class.collection_path(client, prefix) end end # This method fixes issue that there is no / prefix in url. It is happened when we call for instance # Looks like this issue is actual only in case if you use atlassian sdk your app path is not root (like /jira in example below) # issue.save() for existing resource. # As a result we got error 400 from JIRA API: # [07/Jun/2015:15:32:19 +0400] "PUT jira/rest/api/2/issue/10111 HTTP/1.1" 400 - # After applying this fix we have normal response: # [07/Jun/2015:15:17:18 +0400] "PUT /jira/rest/api/2/issue/10111 HTTP/1.1" 204 - def patched_url result = url return result if result.start_with?('/') "/#{result}" end def to_s "#<#{self.class.name}:#{object_id} @attrs=#{@attrs.inspect}>" end # Returns a JSON representation of the current attributes hash. def to_json(options = {}) attrs.to_json(options) end # Determines if the resource is newly created by checking whether its # key_value is set. If it is nil, the record is new and the method # will return true. def new_record? key_value.nil? end protected # This allows conditional lookup of possibly nested attributes. Example usage: # # maybe_nested_attribute('foo') # => @attrs['foo'] # maybe_nested_attribute('foo', 'bar') # => @attrs['bar']['foo'] # maybe_nested_attribute('foo', ['bar', 'baz']) # => @attrs['bar']['baz']['foo'] # def maybe_nested_attribute(attribute_name, nested_under = nil) self.class.maybe_nested_attribute(@attrs, attribute_name, nested_under) end def self.maybe_nested_attribute(attributes, attribute_name, nested_under = nil) return attributes[attribute_name] if nested_under.nil? if nested_under.instance_of? Array final = nested_under.inject(attributes) do |parent, key| break if parent.nil? parent[key] end return nil if final.nil? final[attribute_name] else return attributes[nested_under][attribute_name] end end def url_with_query_params(url, query_params) uri = URI.parse(url) uri.query = uri.query.nil? ? "#{hash_to_query_string query_params}" : "#{uri.query}&#{hash_to_query_string query_params}" unless query_params.empty? uri.to_s end def hash_to_query_string(query_params) self.class.hash_to_query_string(query_params) end def self.hash_to_query_string(query_params) query_params.map do |k,v| CGI.escape(k.to_s) + '=' + CGI.escape(v.to_s) end.join('&') end def self.query_params_for_single_fetch(options) Hash[options.select do |k,v| QUERY_PARAMS_FOR_SINGLE_FETCH.include? k end] end def self.query_params_for_search(options) Hash[options.select do |k,v| QUERY_PARAMS_FOR_SEARCH.include? k end] end end end jira-ruby-1.4.3/lib/jira/railtie.rb0000644000004100000410000000022713167661427017142 0ustar www-datawww-datarequire 'jira-ruby' require 'rails' module JIRA class Railtie < Rails::Railtie rake_tasks do load 'tasks/generate.rake' end end end jira-ruby-1.4.3/lib/jira/tasks.rb0000644000004100000410000000000013167661427016623 0ustar www-datawww-datajira-ruby-1.4.3/.gitignore0000644000004100000410000000011113167661427015451 0ustar www-datawww-data.idea *.gem .bundle Gemfile.lock pkg/* .rvmrc .rspec *.pem .DS_STORE doc jira-ruby-1.4.3/LICENSE0000644000004100000410000000206213167661427014475 0ustar www-datawww-dataCopyright (c) 2015-2016 SUMO Heavy Industries, LLC Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.jira-ruby-1.4.3/jira-ruby.gemspec0000644000004100000410000000264013167661427016743 0ustar www-datawww-data# -*- encoding: utf-8 -*- $:.push File.expand_path('../lib', __FILE__) require 'jira/version' Gem::Specification.new do |s| s.name = 'jira-ruby' s.version = JIRA::VERSION s.authors = ['SUMO Heavy Industries', 'test IO'] s.homepage = 'http://www.sumoheavy.com' s.summary = %q{Ruby Gem for use with the Atlassian JIRA REST API} s.description = %q{API for JIRA} s.licenses = ['MIT'] s.metadata = { 'source_code_uri' => 'https://github.com/sumoheavy/jira-ruby' } s.required_ruby_version = '>= 1.9.3' s.rubyforge_project = 'jira-ruby' s.files = `git ls-files`.split("\n") s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n") s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) } s.require_paths = ['lib'] # Runtime Dependencies s.add_runtime_dependency 'oauth', '~> 0.5', '>= 0.5.0' s.add_runtime_dependency 'activesupport' s.add_runtime_dependency 'multipart-post' # Development Dependencies s.add_development_dependency 'railties' s.add_development_dependency 'webmock', '~> 1.18', '>= 1.18.0' s.add_development_dependency 'rspec', '~> 3.0', '>= 3.0.0' s.add_development_dependency 'rake', '~> 10.3', '>= 10.3.2' s.add_development_dependency 'guard', '~> 2.13', '>= 2.13.0' s.add_development_dependency 'guard-rspec', '~> 4.6', '>= 4.6.5' s.add_development_dependency 'pry', '~> 0.10', '>= 0.10.3' end jira-ruby-1.4.3/README.md0000644000004100000410000002636313167661427014761 0ustar www-datawww-data# JIRA API Gem [![Code Climate](https://codeclimate.com/github/sumoheavy/jira-ruby.svg)](https://codeclimate.com/github/sumoheavy/jira-ruby) [![Build Status](https://travis-ci.org/sumoheavy/jira-ruby.svg?branch=master)](https://travis-ci.org/sumoheavy/jira-ruby) This gem provides access to the Atlassian JIRA REST API. ## Slack Join our Slack channel! You can find us [here](https://jira-ruby-slackin.herokuapp.com/) ## Example usage ```ruby require 'rubygems' require 'jira-ruby' options = { :username => 'username', :password => 'pass1234', :site => 'http://mydomain.atlassian.net:443/', :context_path => '', :auth_type => :basic } client = JIRA::Client.new(options) project = client.Project.find('SAMPLEPROJECT') project.issues.each do |issue| puts "#{issue.id} - #{issue.summary}" end ``` ## Links to JIRA REST API documentation * [Overview](https://developer.atlassian.com/display/JIRADEV/JIRA+REST+APIs) * [Reference](http://docs.atlassian.com/jira/REST/latest/) ## Running tests Before running tests, you will need a public certificate generated. ```shell rake jira:generate_public_cert ``` ## Setting up the JIRA SDK On Mac OS, * Follow the instructions under "Mac OSX Installer" here: https://developer.atlassian.com/display/DOCS/Install+the+Atlassian+SDK+on+a+Linux+or+Mac+System * From within the archive directory, run: ```shell ./bin/atlas-run-standalone --product jira ``` Once this is running, you should be able to connect to http://localhost:2990/ and login to the JIRA admin system using `admin:admin` You'll need to create a dummy project and probably some issues to test using this library. ## Configuring JIRA to use OAuth From the JIRA API tutorial > The first step is to register a new consumer in JIRA. This is done through > the Application Links administration screens in JIRA. Create a new > Application Link. > [Administration/Plugins/Application Links](http://localhost:2990/jira/plugins/servlet/applinks/listApplicationLinks) > > When creating the Application Link use a placeholder URL or the correct URL > to your client (e.g. `http://localhost:3000`), if your client can be reached > via HTTP and choose the Generic Application type. After this Application Link > has been created, edit the configuration and go to the incoming > authentication configuration screen and select OAuth. Enter in this the > public key and the consumer key which your client will use when making > requests to JIRA. This public key and consumer key will need to be generated by the Gem user, using OpenSSL or similar to generate the public key and the provided rake task to generate the consumer key. > After you have entered all the information click OK and ensure OAuth authentication is > enabled. ## Configuring JIRA to use HTTP Basic Auth Follow the same steps described above to set up a new Application Link in JIRA, however there is no need to set up any "incoming authentication" as this defaults to HTTP Basic Auth. ## Configuring JIRA to use Cookie-Based Auth Jira supports cookie based authentication whereby user credentials are passed to JIRA via a JIRA REST API call. This call returns a session cookie which must then be sent to all following JIRA REST API calls. To enable cookie based authentication, set `:auth_type` to `:cookie`, set `:use_cookies` to `true` and set `:username` and `:password` accordingly. ```ruby require 'jira-ruby' options = { :username => 'username', :password => 'pass1234', :site => 'http://mydomain.atlassian.net:443/', :context_path => '', :auth_type => :cookie, # Set cookie based authentication :use_cookies => true, # Send cookies with each request :additional_cookies => ['AUTH=vV7uzixt0SScJKg7'] # Optional cookies to send # with each request } client = JIRA::Client.new(options) project = client.Project.find('SAMPLEPROJECT') project.issues.each do |issue| puts "#{issue.id} - #{issue.summary}" end ``` Some authentication schemes might require additional cookies to be sent with each request. Cookies added to the `:additional_cookies` option will be added to each request. This option should be an array of strings representing each cookie to add to the request. Some authentication schemes that require additional cookies ignore the username and password sent in the JIRA REST API call. For those use cases, `:username` and `:password` may be omitted from `options`. ## Using the API Gem in a command line application Using HTTP Basic Authentication, configure and connect a client to your instance of JIRA. Note: If your Jira install is hosted on [atlassian.net](atlassian.net), it will have no context path by default. If you're having issues connecting, try setting context_path to an empty string in the options hash. ```ruby require 'rubygems' require 'pp' require 'jira-ruby' # Consider the use of :use_ssl and :ssl_verify_mode options if running locally # for tests. username = "myremoteuser" password = "myuserspassword" options = { :username => username, :password => password, :site => 'http://localhost:8080/', :context_path => '/myjira', :auth_type => :basic, :read_timeout => 120 } client = JIRA::Client.new(options) # Show all projects projects = client.Project.all projects.each do |project| puts "Project -> key: #{project.key}, name: #{project.name}" end ``` ## Using the API Gem in your Rails application Using oauth, the gem requires the consumer key and public certificate file (which are generated in their respective rake tasks) to initialize an access token for using the JIRA API. Note that currently the rake task which generates the public certificate requires OpenSSL to be installed on the machine. Below is an example for setting up a rails application for OAuth authorization. Ensure the JIRA gem is loaded correctly ```ruby # Gemfile ... gem 'jira-ruby', :require => 'jira-ruby' ... ``` Add common methods to your application controller and ensure access token errors are handled gracefully ```ruby # app/controllers/application_controller.rb class ApplicationController < ActionController::Base protect_from_forgery rescue_from JIRA::OauthClient::UninitializedAccessTokenError do redirect_to new_jira_session_url end private def get_jira_client # add any extra configuration options for your instance of JIRA, # e.g. :use_ssl, :ssl_verify_mode, :context_path, :site options = { :private_key_file => "rsakey.pem", :consumer_key => 'test' } @jira_client = JIRA::Client.new(options) # Add AccessToken if authorised previously. if session[:jira_auth] @jira_client.set_access_token( session[:jira_auth]['access_token'], session[:jira_auth]['access_key'] ) end end end ``` Create a controller for handling the OAuth conversation. ```ruby # app/controllers/jira_sessions_controller.rb class JiraSessionsController < ApplicationController before_filter :get_jira_client def new callback_url = 'http://callback' request_token = @jira_client.request_token(oauth_callback: callback_url) session[:request_token] = request_token.token session[:request_secret] = request_token.secret redirect_to request_token.authorize_url end def authorize request_token = @jira_client.set_request_token( session[:request_token], session[:request_secret] ) access_token = @jira_client.init_access_token( :oauth_verifier => params[:oauth_verifier] ) session[:jira_auth] = { :access_token => access_token.token, :access_key => access_token.secret } session.delete(:request_token) session.delete(:request_secret) redirect_to projects_path end def destroy session.data.delete(:jira_auth) end end ``` Create your own controllers for the JIRA resources you wish to access. ```ruby # app/controllers/issues_controller.rb class IssuesController < ApplicationController before_filter :get_jira_client def index @issues = @jira_client.Issue.all end def show @issue = @jira_client.Issue.find(params[:id]) end end ``` ## Using the API Gem in your Sinatra application Here's the same example as a Sinatra application: ```ruby require 'jira-ruby' class App < Sinatra::Base enable :sessions # This section gets called before every request. Here, we set up the # OAuth consumer details including the consumer key, private key, # site uri, and the request token, access token, and authorize paths before do options = { :site => 'http://localhost:2990', :context_path => '/jira', :signature_method => 'RSA-SHA1', :request_token_path => "/plugins/servlet/oauth/request-token", :authorize_path => "/plugins/servlet/oauth/authorize", :access_token_path => "/plugins/servlet/oauth/access-token", :private_key_file => "rsakey.pem", :rest_base_path => "/rest/api/2", :consumer_key => "jira-ruby-example" } @jira_client = JIRA::Client.new(options) @jira_client.consumer.http.set_debug_output($stderr) # Add AccessToken if authorised previously. if session[:jira_auth] @jira_client.set_access_token( session[:jira_auth][:access_token], session[:jira_auth][:access_key] ) end end # Starting point: http:/// # This will serve up a login link if you're not logged in. If you are, it'll show some user info and a # signout link get '/' do if !session[:jira_auth] # not logged in <<-eos

jira-ruby (JIRA 5 Ruby Gem) demo

You're not signed in. Why don't you sign in first. eos else #logged in @issues = @jira_client.Issue.all # HTTP response inlined with bind data below... <<-eos You're now signed in. There #{@issues.count == 1 ? "is" : "are"} #{@issues.count} issue#{@issues.count == 1 ? "" : "s"} in this JIRA instance. Signout eos end end # http:///signin # Initiates the OAuth dance by first requesting a token then redirecting to # http:///auth to get the @access_token get '/signin' do callback_url = "#{request.base_url}/callback" request_token = @jira_client.request_token(oauth_callback: callback_url) session[:request_token] = request_token.token session[:request_secret] = request_token.secret redirect request_token.authorize_url end # http:///callback # Retrieves the @access_token then stores it inside a session cookie. In a real app, # you'll want to persist the token in a datastore associated with the user. get "/callback" do request_token = @jira_client.set_request_token( session[:request_token], session[:request_secret] ) access_token = @jira_client.init_access_token( :oauth_verifier => params[:oauth_verifier] ) session[:jira_auth] = { :access_token => access_token.token, :access_key => access_token.secret } session.delete(:request_token) session.delete(:request_secret) redirect "/" end # http:///signout # Expires the session get "/signout" do session.delete(:jira_auth) redirect "/" end end ``` jira-ruby-1.4.3/Guardfile0000644000004100000410000000047113167661427015317 0ustar www-datawww-datagem 'wdm', '>= 0.1.0' if Gem.win_platform? gem 'rspec', '~> 3.0.0' guard 'rspec', cmd: 'bundle exec rspec --color --format doc' do # watch /lib/ files watch(%r{^lib/(.+).rb$}) do |m| "spec/#{m[1]}_spec.rb" end # watch /spec/ files watch(%r{^spec/(.+).rb$}) do |m| "spec/#{m[1]}.rb" end end