项目作者: Asana

项目描述 :
Asana API v1的官方Ruby客户端库
高级语言: Ruby
项目地址: git://github.com/Asana/ruby-asana.git
创建时间: 2015-03-04T22:01:10Z
项目社区:https://github.com/Asana/ruby-asana

开源协议:MIT License

下载


Asana

Gem Version
Build Status
Code Climate

[!CAUTION]
The Asana Ruby SDK is no longer supported. While it remains available on RubyGems, it will not receive bug fixes or enhancements (including new endpoints or data model changes). We recommend using Ruby’s Net::HTTP or similar HTTP libraries to make direct API requests instead.

A Ruby client for the 1.0 version of the Asana API.

Supported rubies:

  • MRI 2.7.x
  • MRI 3.0.x
  • MRI 3.1.x

Gem Installation

Add this line to your application’s Gemfile:

  1. gem 'asana'

And then execute:

  1. $ bundle

Or install it yourself as:

  1. $ gem install asana

Usage

To do anything, you’ll need always an instance of Asana::Client configured
with your preferred authentication method (see the Authentication section below
for more complex scenarios) and other options.

The most minimal example would be as follows:

  1. require 'asana'
  2. client = Asana::Client.new do |c|
  3. c.authentication :access_token, 'personal_access_token'
  4. end
  5. client.workspaces.get_workspaces.first

A full-blown customized client using OAuth2 wih a previously obtained refresh
token, Typhoeus as a Faraday adapter, a custom user agent and custom Faraday
middleware:

  1. require 'asana'
  2. client = Asana::Client.new do |c|
  3. c.authentication :oauth2,
  4. refresh_token: 'abc',
  5. client_id: 'bcd',
  6. client_secret: 'cde',
  7. redirect_uri: 'http://example.org/auth'
  8. c.faraday_adapter :typhoeus
  9. c.configure_faraday { |conn| conn.use SomeFaradayMiddleware }
  10. end
  11. workspace = client.workspaces.get_workspace(12)
  12. workspace.users
  13. # => #<Asana::Collection<User> ...>
  14. client.tags.create_in_workspace(workspace: workspace.id, name: 'foo')
  15. # => #<Asana::Tag id: ..., name: "foo">

All resources are exposed as methods on the Asana::Client instance. Check out
the documentation for each of them.

Authentication

This gem supports authenticating against the Asana API with either an API token or through OAuth2.

Personal Access Token

  1. Asana::Client.new do |c|
  2. c.authentication :access_token, 'personal_access_token'
  3. end

OAuth2

Authenticating through OAuth2 is preferred. There are many ways you can do this.

With a plain bearer token (doesn’t support auto-refresh)

If you have a plain bearer token obtained somewhere else and you don’t mind not
having your token auto-refresh, you can authenticate with it as follows:

  1. Asana::Client.new do |c|
  2. c.authentication :oauth2, bearer_token: 'my_bearer_token'
  3. end
With a refresh token and client credentials

If you obtained a refresh token, you can use it together with your client
credentials to authenticate:

  1. Asana::Client.new do |c|
  2. c.authentication :oauth2,
  3. refresh_token: 'abc',
  4. client_id: 'bcd',
  5. client_secret: 'cde',
  6. redirect_uri: 'http://example.org/auth'
  7. end
With an ::OAuth2::AccessToken object (from omniauth-asana for example)

If you use omniauth-asana or a browser-based OAuth2 authentication strategy in
general, possibly because your application is a web application, you can reuse
those credentials to authenticate with this API client. Here’s how to do it from
the callback method:

  1. # assuming we're using Sinatra and omniauth-asana
  2. get '/auth/:name/callback' do
  3. creds = request.env["omniauth.auth"]["credentials"].tap { |h| h.delete('expires') }
  4. strategy = request.env["omniauth.strategy"]
  5. # We need to refresh the omniauth OAuth2 token
  6. access_token = OAuth2::AccessToken.from_hash(strategy.client, creds).refresh!
  7. $client = Asana::Client.new do |c|
  8. c.authentication :oauth2, access_token
  9. end
  10. redirect '/'
  11. end

See examples/omniauth_integration.rb for a working example of this.

Using an OAuth2 offline authentication flow (for CLI applications)

If your application can’t receive HTTP requests and thus you can’t use
omniauth-asana, for example if it’s a CLI application, you can authenticate as
follows:

  1. access_token = Asana::Authentication::OAuth2.offline_flow(client_id: ...,
  2. client_secret: ...)
  3. client = Asana::Client.new do |c|
  4. c.authentication :oauth2, access_token
  5. end
  6. client.tasks.get_task(12)

This will print an authorization URL on STDOUT, and block until you paste in the
authorization code, which you can get by visiting that URL and granting the
necessary permissions.

Pagination

Whenever you ask for a collection of resources, you can provide a number of
results per page to fetch, between 1 and 100. If you don’t provide any, it
defaults to 20.

  1. my_tasks = client.tasks.get_tasks_for_tag(tag: tag_id, per_page: 5)
  2. # => #<Asana::Collection<Task> ...>

An Asana::Collection is a paginated collection — it holds the first
per_page results, and a reference to the next page if any.

When you iterate an Asana::Collection, it’ll transparently keep fetching all
the pages, and caching them along the way:

  1. my_tasks.size # => 23, not 5
  2. my_tasks.take(14)
  3. # => [#<Asana::Task ...>, #<Asana::Task ...>, ... until 14]

Manual pagination

If you only want to deal with one page at a time and manually paginate, you can
get the elements of the current page with #elements and ask for the next page
with #next_page, which will return an Asana::Collection with the next page
of elements:

  1. my_tasks.elements # => [#<Asana::Task ...>, #<Asana::Task ...>, ... until 5]
  2. my_tasks.next_page # => #<Asana::Collection ...>

Lazy pagination

Because an Asana::Collection represents the entire collection, it is often
handy to just take what you need from it, rather than let it fetch all its
contents from the network. You can accomplish this by turning it into a lazy
collection with #lazy:

  1. # let my_tasks be an Asana::Collection of 10 pages of 100 elements each
  2. my_tasks.lazy.drop(120).take(15).to_a
  3. # Fetches only 2 pages, enough to get elements 120 to 135
  4. # => [#<Asana::Task ...>, #<Asana::Task ...>, ...]

Error handling

In any request against the Asana API, there a number of errors that could
arise. Those are well documented in the Asana API Documentation, and
are represented as exceptions under the namespace Asana::Errors.

The Asana client automatically handles and retries requests upon receipt of
500 (Internal Server Error) responses from the Asana API. If you want to handle
any 4xx errors, you will have to do that yourself; you can do this by rescuing
Asana::Errors::APIError, the parent class of all Asana API errors.

I/O options

All requests (except DELETE) accept extra I/O options
as documented in the API docs. Just pass an extra options hash to any
request:

  1. client.tasks.get_task(12, options: { expand: ['workspace'] })

Attachment uploading

To attach a file to a task or a project, you just need its absolute path on your
filesystem and its MIME type, and the file will be uploaded for you:

  1. task = client.tasks.get_task(12)
  2. attachment = task.attach(filename: '/absolute/path/to/my/file.png',
  3. mime: 'image/png')
  4. attachment.name # => 'file.png'

Event streams

To subscribe to an event stream of a task or a project, just call #events on
it:

  1. task = client.tasks.get_task(12)
  2. task.events # => #<Asana::Events ...>
  3. # You can do the same with only the task id:
  4. events = client.events.for(task.id)

An Asana::Events object is an infinite collection of Asana::Event
instances. Be warned that if you call #each on it, it will block forever!

Note that, by default, an event stream will wait at least 1 second between
polls, but that’s configurable with the wait parameter:

  1. # wait at least 3 and a half seconds between each poll to the API
  2. task.events(wait: 3.5) # => #<Asana::Events ...>

There are some interesting things you can do with an event stream, as it is a
normal Ruby Enumerable. Read below to get some ideas.

Subscribe to the event stream with a callback, polling every 2 seconds

  1. # Run this in another thread so that we don't block forever
  2. events = client.tasks.get_task(12).events(wait: 2)
  3. Thread.new do
  4. events.each do |event|
  5. notify_someone "New event arrived! #{event}"
  6. end
  7. end

Make the stream lazy and filter it by a specific pattern

To do that we need to call #lazy on the Events instance, just like with any
other Enumerable.

  1. events = client.tasks.get_task(12).events
  2. only_change_events = events.lazy.select { |event| event.action == 'changed' }
  3. Thread.new do
  4. only_change_events.each do |event|
  5. notify_someone "New change event arrived! #{event}"
  6. end
  7. end

Asana Change Warnings

You will receive warning logs if performing requests that may be affected by a deprecation. The warning contains a link that explains the deprecation.

If you receive one of these warnings, you should:

  • Read about the deprecation.
  • Resolve sections of your code that would be affected by the deprecation.
  • Add the deprecation flag to your “asana-enable” header.

You can add global headers, by setting default_headers

  1. c.default_headers "asana-enable" => "string_ids"

Or you can add a header field to the options of each request.

If you would rather suppress these warnings, you can set

  1. c.log_asana_change_warnings false

Development

You’ll need Ruby 2.7+ and Node v0.10.26+ / NPM 1.4.3+ installed.

After checking out the repo, run bin/setup to install dependencies. Then, run
bin/console for an interactive prompt that will allow you to experiment.

Run the build with rake. This is equivalent to:

  1. $ rake spec && rake rubocop && rake yard

To install this gem onto your local machine, run bundle exec rake install.

Releasing a new version

Prerequisite: Before deployment, make sure you have Ruby version 2.7 installed

Automatic Deployment

First, install dependencies:

  1. bundle install

Then, to release a new version, run one of these commands:

  1. rake bump:patch
  2. rake bump:minor
  3. rake bump:major

This will: update lib/asana/version.rb and VERSION, commit and tag the commit. Then you
just need to push --tags to let GitHub Actions build and release the new version to
Rubygems:

  1. git push --tags origin master:master

Manual Deployment

  1. Merge in the desired changes into the master branch and commit them.
  2. Clone the repo, work on master.
  3. Edit package version in lib/asana/version.rb and VERSION to indicate the semantic version change.
  4. Commit the change
  5. Tag the commit with v plus the same version number you set in the file.
    git tag v1.2.3
  6. Push changes to origin, including tags:
    git push --tags origin master:master

Code generation

The specific Asana resource classes (Tag, Workspace, Task, etc) are
generated code, hence they shouldn’t be modified by hand. The code that
generates it lives in lib/templates/resource.ejs, and is tested by generating
spec/templates/unicorn.rb and running spec/templates/unicorn_spec.rb as part
of the build.

If you wish to make changes on the code generation script:

  1. Add/modify a spec on spec/templates/unicorn_spec.rb
  2. Add your new feature or change to lib/templates/resource.ejs
  3. Run rake or, more granularly, rake codegen && rspec spec/templates/unicorn_spec.rb

Once you’re sure your code works, submit a pull request and ask the maintainer
to make a release, as they’ll need to run a release script.

Contributing

  1. Fork it ( https://github.com/[my-github-username]/asana/fork )
  2. Create your feature branch (git checkout -b my-new-feature)
  3. Commit your changes (git commit -am 'Add some feature')
  4. Push to the branch (git push origin my-new-feature)
  5. Create a new Pull Request