Maintain master
in sync with main repo.
Use worklytics-private
branch with whatever Worklytics-only changes we want.
To develop:
- branch from
worklytics-private
(Eg,{{sprint}}-feature-branch
); make local changes - create PR against
worklytics-private
; after peer review and CI passes, merge toworklytics-private
- if want to get changes back to main project repo:
- branch from
master
- cherry-pick commits from
feature-branch
to
- branch from
- if want to get changes from main project repo:
- update
master
branch from main project - branch from
worklytics-private
- merge
master
to that feature branch - follow regular dev process
- update
To release for Worklytics:
- update version number in
worklytics-private
branch, using pattern{{main-java-asana-version}}-worklytics .{{private-version}}
- tag with that version number
- use
./tools/publish-private-dep
tool in main Worklytics repo to publish
Java client library for the Asana API.
If you use Maven to manage dependencies you can include the "asana" artifact by adding it as a dependency in your pom.xml
file.
<dependency>
<groupId>com.asana</groupId>
<artifactId>asana</artifactId>
<version>0.10.2</version>
</dependency>
Or, you can build the artifact and install it to your local Maven repository:
mvn install
mvn compile
mvn test
Be sure to run mvn compile
first.
Set the ASANA_ACCESS_TOKEN, ASANA_CLIENT_ID, and ASANA_CLIENT_SECRET environment variables. The app's redirect URL should be set to "urn:ietf:wg:oauth:2.0:oob" for command line scripts examples, and "http://localhost:5000/auth/asana/callback" for the server example.
export ASANA_ACCESS_TOKEN="X"
export ASANA_CLIENT_ID="X"
export ASANA_CLIENT_SECRET="X"
Web application example:
mvn exec:java -Dexec.mainClass="com.asana.examples.ExampleServer"
OAuth command line script example:
mvn exec:java -Dexec.mainClass="com.asana.examples.ExampleOAuth"
Personal access token command line script example:
mvn exec:java -Dexec.mainClass="com.asana.examples.ExamplePersonalAccessToken"
Demo create a task and upload an attachment:
mvn exec:java -Dexec.mainClass="com.asana.examples.ExampleCreateTaskAndUpload"
Demo create project and stream change events:
mvn exec:java -Dexec.mainClass="com.asana.examples.ExampleCreateProjectAndStreamEvents"
Create a client using a personal access token:
Client client = Client.accessToken("ASANA_ACCESS_TOKEN");
Asana supports OAuth 2. java-asana
handles some of the details of the OAuth flow for you.
Create a client using your OAuth Client ID and secret:
OAuthApp app = new OAuthApp(
"ASANA_CLIENT_ID",
"ASANA_CLIENT_SECRET",
"urn:ietf:wg:oauth:2.0:oob"
);
Client client = Client.oauth(app);
Redirect the user to the authorization URL obtained from the client's session
object:
String url = app.getAuthorizationUrl()
getAuthorizationUrl()
takes an optional state parameter to be used for preventing CSRF attacks:
String state = UUID.randomUUID().toString();
String url = app.getAuthorizationUrl(state);
When the user is redirected back to your callback, check the state
URL parameter matches, then pass the code
parameter to obtain a bearer token:
if (request.param("state").equals(state)) {
String token = app.fetchToken(request.params("code"));
// ...
} else {
// error! possible CSRF attack
}
Note: if you're writing a non-browser-based application (e.x. a command line tool) you can use the special redirect URI urn:ietf:wg:oauth:2.0:oob
to prompt the user to copy and paste the code into the application.
The client's methods are divided into several resources: attachments
, customFields
, customFieldSettings
, events
, jobs
, organizationExports
, portfolios
, portfolioMemberships
, projects
, projectMemberships
, projectStatuses
, stories
, tags
, tasks
, teams
, users
, userTaskLists
, webhooks
, and workspaces
.
Request methods use the "builder" pattern to set query string or JSON body parameters, and various request options, so a request must be initated using the execute
or executeRaw
methods:
Methods that return a single object return that object directly:
User me = client.users.me().execute();
System.out.println("Hello " + me.name);
String workspaceId = me.workspaces.get(0).gid;
Project project = client.projects.createInWorkspace(workspaceId)
.data("name", "new project")
.execute();
System.out.println("Created project with id: " + project.gid);
Methods that return multiple items (e.x. findAll
) return an Iterable
object. See the "Collections" section
Various options can be set globally on the Client.DEFAULTS
object, per-client on client.options
, or per-request using the option
method. For example:
// global:
Client.DEFAULTS.put("page_size", 1000);
// per-client:
client.options.put("page_size", 1000);
// per-request:
client.tasks.findAll().query("project", 1234).option("page_size", 1000).execute();
base_url
(default: "https://app.asana.com/api/1.0"): API endpoint base URL to connect tomax_retries
(default: 5): number to times to retry if API rate limit is reached or a server error occures. Rate limit retries delay until the rate limit expires, server errors exponentially backoff starting with a 1 second delay.fields
andexpand
: array of field names to include in the response, or sub-objects to expand in the response. For example.option("fields", Arrays.asList("followers", "assignee"))
. See API documentation
Collections (methods returning an array as it's 'data' property):
item_limit
(default: -1): limits the total number of items of a collection to return (spanning multiple requests in the case of an iterator).page_size
(default: 50): limits the number of items per page to fetch at a time when using an iterator.offset
: offset token returned by previous calls to the same method, when usingexecuteRaw()
(inresponse.nextPage.offset
)
Events:
poll_interval
(default: 5): polling interval for getting new events via anEventsRequest
iterator (e.x.for (Event event : client.events.get(resourceId)) { ... }
)sync
: sync token returned by previous calls toevents.get
(e.x.client.events.get(resourceId, syncToken).executeRaw().sync
)
To add global headers (like for our deprecation framework), you simply add them to the client.
client.headers.put("asana-enable", "string_ids");
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 place it on the client for all requests.
client.headers.put("asana-enable", "string_ids,new_sections");
or
client.headers.put("asana-disable", "string_ids");
If you would rather suppress these warnings, you can set
client.logAsanaChangeWarnings = false;
APIs that return a collection return a CollectionsRequest, which is an iterable:
Iterable<Workspace> workspaces = client.workspaces.findAll();
for (Workspace workspace: workspaces) {
System.out.println("Workspace: " + workspace.name);
}
Internally the iterator may make multiple HTTP requests, with the number of requested results per page being controlled by the page_size
option.
You can also use the raw API to fetch a page at a time:
String offset = null;
while (true) {
ResultBodyCollection<Workspace> page = client.workspaces.findAll()
.option("offset", offset)
.option("limit", 2)
.executeRaw();
System.out.println("received " + page.data.size() + " results");
if (page.nextPage != null) {
offset = page.nextPage.offset;
} else {
break;
}
}
To deploy a new version to the Maven Central Repository, you can run:
mvn deploy -P release --settings settings.xml
Before you do this, you must set a few environment variables to authenticate:
- Maven credentials:
MAVEN_USERNAME
andMAVEN_PASSWORD
- GPG keyname and password:
MAVEN_GPG_KEYNAME
andMAVEN_GPG_PASSWORD
You can log in to verify the new version landed, and after some time it will be deployed to maven.