ruby-fogbugz-0.3.0/0000755000004100000410000000000013322513133014160 5ustar www-datawww-dataruby-fogbugz-0.3.0/.travis.yml0000644000004100000410000000040413322513133016267 0ustar www-datawww-datalanguage: ruby rvm: - 2.0.0-p648 - 2.1.10 - 2.2.6 - 2.3.3 - jruby-9.0.0.0 sudo: false after_success: - bundle exec codeclimate-test-reporter addons: code_climate: repo_token: ef52b4659b14e65b70be219cf870eaffcef8ee9c260b767b26694e2c7f59e88c ruby-fogbugz-0.3.0/.rspec0000644000004100000410000000003613322513133015274 0ustar www-datawww-data--color --require spec_helper ruby-fogbugz-0.3.0/README.md0000644000004100000410000001010213322513133015431 0ustar www-datawww-data[![Gem Version](https://img.shields.io/gem/v/ruby-fogbugz.svg)][gem] [![Build Status](https://img.shields.io/travis/firmafon/ruby-fogbugz.svg)][travis] [![Dependency Status](https://img.shields.io/gemnasium/firmafon/ruby-fogbugz.svg)][gemnasium] [![Code Climate](https://img.shields.io/codeclimate/github/firmafon/ruby-fogbugz.svg)][codeclimate] [![Test Coverage](https://img.shields.io/codeclimate/coverage/github/firmafon/ruby-fogbugz.svg)][coverage] [gem]: https://rubygems.org/gems/ruby-fogbugz [travis]: https://travis-ci.org/firmafon/ruby-fogbugz [gemnasium]: https://gemnasium.com/firmafon/ruby-fogbugz [codeclimate]: https://codeclimate.com/github/firmafon/ruby-fogbugz [coverage]: https://codeclimate.com/github/firmafon/ruby-fogbugz/coverage # ruby-fogbugz A very simple wrapper for the Fogbugz API. It won't give you fancy classes for everything, it'll simply aid you in sending the API requests, parsing the returned XML finally retuning you a Hash. ## Installation Add this line to your application's Gemfile: ```ruby gem 'ruby-fogbugz' ``` And then execute: $ bundle Or install it yourself as: $ gem install ruby-fogbugz ## Usage The Fogbugz API works by sending HTTP GET parameters to the API where the GET parameter `cmd` invokes a Fogbugz method, e.g. `cmd=listProjects` to get a list of all projects, `cmd`s then accept further arguments, such as listing all cases assigned to a specific person: cmd=search&ixAssignedTo=2&cols=sTitle,sStatus # list all cases associated to the user with ID of 2 in Fogbugz In `ruby-fogbugz` that request would be: ```ruby fogbugz.command(:search, :ixAssignedTo => 2, :cols => "sTitle,sStatus") ``` Returns your parsed XML: ```ruby { "description"=>"All open cases assigned to Simon Eskildsen", "cases" => { "case"=> [ {"ixBug"=>"143", "sTitle"=>"Write ruby-fogbugz documentation", "sStatus"=>"active", "operations"=>"edit,assign,resolve,email,remind"}, {"ixBug"=>"146", "sTitle"=>"Tame a unicorn", "sStatus"=>"active", "operations"=>"edit,assign,resolve,email,remind"}, {"ixBug"=>"152", "sTitle"=>"Hug a walrus", "sStatus"=>"active", "operations"=>"edit,assign,resolve,email,remind"}, ], "count"=>"3" } } ``` As you see, `ruby-fogbugz` is without magic and leaves most to the user. `cmd` is the first argument to `Fogbugz#command`, the second argument being a `Hash` of additional GET arguments to specify the request further. You can see available `cmd`'s and arguments at the [Fogbugz API documentation][fad]. All Fogbugz API requests require a token. Thus `#authenticate` must be called on the `ruby-fogbugz` instance before `#command`'s are sent: ```ruby require 'fogbugz' fogbugz = Fogbugz::Interface.new(:email => 'my@email.com', :password => 'seekrit', :uri => 'https://company.fogbugz.com') # remember to use https! fogbugz.authenticate # token is now automatically attached to every future requests p fogbugz.command(:listPeople) ``` `#authenticate` fetches a new token every time. To avoid the extra request, obtain a token: ```ruby require 'fogbugz' fogbugz = Fogbugz::Interface.new(:email => 'my@email.com', :password => 'seekrit', :uri => 'https://company.fogbugz.com') # remember to use https! fogbugz.authenticate # token is now automatically attached to every future requests puts "Token: #{fogbugz.token}" ``` Run the script, and initialize with the returned token: ```ruby fogbugz = Fogbugz::Interface.new(:token => "some token to use from now on", :uri => 'https://company.fogbugz.com') # remember to use https! ``` ### Attachments This library supports multipart file uploads to include attachments in your API request. A multipart request body is created (using the [multipart-post][mpp] gem) if `File1` is found in the command parameters. Files can be attached as follows: ```ruby fogbugz.command(:new, sProject: "SomeProject", sArea: "someArea", sTitle: "Case title", File1: UploadIO.new(f, "text/plain", "someFile.rb")) ``` [fad]:http://fogbugz.stackexchange.com/fogbugz-xml-api [mpp]:https://github.com/nicksieger/multipart-post ## License `ruby-fogbugz` is released under the MIT license. ruby-fogbugz-0.3.0/spec/0000755000004100000410000000000013322513133015112 5ustar www-datawww-dataruby-fogbugz-0.3.0/spec/adapters/0000755000004100000410000000000013322513133016715 5ustar www-datawww-dataruby-fogbugz-0.3.0/spec/adapters/xml/0000755000004100000410000000000013322513133017515 5ustar www-datawww-dataruby-fogbugz-0.3.0/spec/adapters/xml/crack_spec.rb0000644000004100000410000000137713322513133022147 0ustar www-datawww-dataRSpec.describe 'Cracker' do context 'valid response xml' do let(:xml) { %q( 2 ) } it 'parses the response' do expect(parse_xml(xml)).to eq({ 'version' => '2' }) end end context 'invalid response xml' do let(:xml) { %q(Object moved

Object moved to here.

) } it 'returns nil' do expect(parse_xml(xml)).to be_nil end end def parse_xml(xml) Fogbugz::Adapter::XML::Cracker.parse(xml) end end ruby-fogbugz-0.3.0/spec/interface_spec.rb0000644000004100000410000000324213322513133020412 0ustar www-datawww-dataRSpec.describe 'Interface' do let(:credentials) { { email: 'test@example.com', password: 'seekrit', uri: 'https://fogbugz.example.com' } } context 'initialization' do it 'options are publicly available' do fogbugz = Fogbugz::Interface.new(credentials) expect(fogbugz.options).to eq(credentials) end it 'raises exception without URI' do expect { Fogbugz::Interface.new }.to raise_error(Fogbugz::Interface::InitializationError) end end context 'when credentials are valid' do let(:fogbugz) { Fogbugz::Interface.new(credentials) } it '#authenticate returns a token' do token = fogbugz.authenticate expect(token).not_to be_nil end it '#command returns result' do fogbugz.token = 'abcdefabcdefabcdef' fogbugz.command(:search, q: '1') end end context 'when credentials are invalid' do let(:credentials) { super().merge(password: 'invalid') } let(:fogbugz) { Fogbugz::Interface.new(credentials) } it '#authenticate raises an exception' do expect { fogbugz.authenticate }.to raise_error(Fogbugz::AuthenticationException, 'Incorrect password or username') end it '#command raises an exception' do fogbugz.token = nil expect { fogbugz.command(:search, q: 'case') }.to raise_error(Fogbugz::Interface::RequestError) end end context 'when server does not reply as expected' do let(:credentials) { super().merge(uri: 'https://notfogbugz.example.com') } let(:fogbugz) { Fogbugz::Interface.new(credentials) } it '#authenticate raises an exception' do expect { fogbugz.authenticate }.to raise_error(Fogbugz::AuthenticationException) end end end ruby-fogbugz-0.3.0/spec/spec_helper.rb0000644000004100000410000000351713322513133017736 0ustar www-datawww-datarequire 'simplecov' SimpleCov.start require 'webmock/rspec' WebMock.disable_net_connect!(allow: 'codeclimate.com') require 'fogbugz' RSpec.configure do |config| config.expect_with :rspec do |expectations| expectations.include_chain_clauses_in_custom_matcher_descriptions = true end config.mock_with :rspec do |mocks| mocks.verify_partial_doubles = true end config.filter_run :focus config.run_all_when_everything_filtered = true config.example_status_persistence_file_path = 'spec/examples.txt' config.disable_monkey_patching! config.warnings = true config.default_formatter = 'doc' if config.files_to_run.one? # config.profile_examples = 10 config.order = :random Kernel.srand config.seed config.before(:each) do stub_request(:post, 'https://fogbugz.example.com/api.asp') .with(body: { cmd: 'logon', email: 'test@example.com', password: 'seekrit' }) .to_return(body: '') stub_request(:post, 'https://fogbugz.example.com/api.asp') .with(body: { cmd: 'logon', email: 'test@example.com', password: 'invalid' }) .to_return(body: '') stub_request(:post, 'https://fogbugz.example.com/api.asp') .with(body: { cmd: 'search', q: '1', token: 'abcdefabcdefabcdef' }) .to_return(body: '') stub_request(:post, 'https://notfogbugz.example.com/api.asp') .with(body: { cmd: 'logon', email: 'test@example.com', password: 'seekrit' }) .to_return(body: '') end end ruby-fogbugz-0.3.0/.rubocop.yml0000644000004100000410000000023513322513133016432 0ustar www-datawww-dataStyle/Documentation: Enabled: false Style/SignalException: Enabled: false Metrics/LineLength: Enabled: false Metrics/MethodLength: Enabled: false ruby-fogbugz-0.3.0/ruby-fogbugz.gemspec0000644000004100000410000000221213322513133020144 0ustar www-datawww-data# -*- encoding: utf-8 -*- $LOAD_PATH.push File.expand_path('../lib', __FILE__) require 'ruby_fogbugz/version' Gem::Specification.new do |s| s.name = 'ruby-fogbugz' s.version = Fogbugz::VERSION s.platform = Gem::Platform::RUBY s.authors = ['Simon Hørup Eskildsen', 'Jared Szechy'] s.email = ['sirup@sirupsen.com', 'jared.szechy@gmail.com'] s.homepage = 'https://github.com/firmafon/ruby-fogbugz' s.summary = 'Ruby wrapper for the Fogbugz API' s.description = 'A simple Ruby wrapper for the Fogbugz XML API' s.license = 'MIT' s.rubyforge_project = 'ruby-fogbugz' s.add_dependency 'crack', '~> 0.4' s.add_dependency 'multipart-post', '~> 2.0' s.add_development_dependency 'rake', '< 11.0' s.add_development_dependency 'webmock', '~> 1.21' s.add_development_dependency 'rspec', '~> 3.3' s.add_development_dependency 'codeclimate-test-reporter', '~> 1.0.0' 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'] end ruby-fogbugz-0.3.0/.gitignore0000644000004100000410000000006313322513133016147 0ustar www-datawww-data*.gem .bundle Gemfile.lock pkg/* spec/examples.txt ruby-fogbugz-0.3.0/.codeclimate.yml0000640000004100000410000000016013322513133017223 0ustar www-datawww-dataengines: rubocop: enabled: true fixme: enabled: true ratings: paths: - "lib/**" - "**.rb" ruby-fogbugz-0.3.0/Rakefile0000644000004100000410000000021313322513133015621 0ustar www-datawww-datarequire 'bundler' Bundler::GemHelper.install_tasks require 'rspec/core/rake_task' RSpec::Core::RakeTask.new(:spec) task default: [:spec] ruby-fogbugz-0.3.0/lib/0000755000004100000410000000000013322513133014726 5ustar www-datawww-dataruby-fogbugz-0.3.0/lib/ruby_fogbugz/0000755000004100000410000000000013322513133017432 5ustar www-datawww-dataruby-fogbugz-0.3.0/lib/ruby_fogbugz/interface.rb0000644000004100000410000000303513322513133021720 0ustar www-datawww-datamodule Fogbugz class Interface class RequestError < StandardError; end class InitializationError < StandardError; end attr_accessor :options, :http, :xml, :token def initialize(options = {}) @options = {}.merge(options) raise InitializationError, 'Must supply URI (e.g. https://fogbugz.company.com)' unless options[:uri] @token = options[:token] if options[:token] @http = Fogbugz.adapter[:http].new(uri: options[:uri], ca_file: options[:ca_file]) @xml = Fogbugz.adapter[:xml] end def authenticate response = @http.request :logon, params: { email: @options[:email], password: @options[:password] } begin @token ||= @xml.parse(response)['token'] if @token.nil? || @token == '' raise Fogbugz::AuthenticationException, @xml.parse(response)['error'] end rescue REXML::ParseException raise Fogbugz::AuthenticationException, "Looks like there was an issue with authentication (to #{@options[:uri]} as #{@options[:email]}) - probably the host/url." end @token end def command(action, parameters = {}) raise RequestError, 'No token available, #authenticate first' unless @token parameters[:token] = @token response = @http.request action, params: parameters.merge(options[:params] || {}) @xml.parse(response) end end class AuthenticationException < Exception end end ruby-fogbugz-0.3.0/lib/ruby_fogbugz/version.rb0000644000004100000410000000004713322513133021445 0ustar www-datawww-datamodule Fogbugz VERSION = '0.3.0' end ruby-fogbugz-0.3.0/lib/ruby_fogbugz/adapters/0000755000004100000410000000000013322513133021235 5ustar www-datawww-dataruby-fogbugz-0.3.0/lib/ruby_fogbugz/adapters/xml/0000755000004100000410000000000013322513133022035 5ustar www-datawww-dataruby-fogbugz-0.3.0/lib/ruby_fogbugz/adapters/xml/cracker.rb0000644000004100000410000000033513322513133023775 0ustar www-datawww-datarequire 'crack/util' require 'crack/xml' module Fogbugz module Adapter module XML class Cracker def self.parse(xml) Crack::XML.parse(xml)['response'] end end end end end ruby-fogbugz-0.3.0/lib/ruby_fogbugz/adapters/http/0000755000004100000410000000000013322513133022214 5ustar www-datawww-dataruby-fogbugz-0.3.0/lib/ruby_fogbugz/adapters/http/net_http.rb0000644000004100000410000000207213322513133024367 0ustar www-datawww-datarequire 'cgi' require 'net/https' require 'net/http/post/multipart' module Fogbugz module Adapter module HTTP class NetHttp attr_accessor :root_url, :requester def initialize(options = {}) @root_url = options[:uri] @ca_file = options[:ca_file] end def build_request(uri, params) return Net::HTTP::Post::Multipart.new(uri.request_uri, params) if params.key? :File1 request = Net::HTTP::Post.new(uri.request_uri) request.set_form_data(params) request end def request(action, options) uri = URI("#{@root_url}/api.asp") params = { 'cmd' => action } params.merge!(options[:params]) request = build_request(uri, params) http = Net::HTTP.new(uri.host, uri.port) if @root_url.start_with? 'https' http.use_ssl = true http.ca_file = @ca_file end response = http.start { |h| h.request(request) } response.body end end end end end ruby-fogbugz-0.3.0/lib/fogbugz.rb0000644000004100000410000000043113322513133016714 0ustar www-datawww-datarequire 'ruby_fogbugz/adapters/http/net_http' require 'ruby_fogbugz/adapters/xml/cracker' require 'ruby_fogbugz/interface' module Fogbugz class << self attr_accessor :adapter end self.adapter = { xml: Adapter::XML::Cracker, http: Adapter::HTTP::NetHttp } end ruby-fogbugz-0.3.0/Gemfile0000644000004100000410000000014013322513133015446 0ustar www-datawww-datasource 'http://rubygems.org' # Specify your gem's dependencies in ruby-fogbugz.gemspec gemspec