dotnet add package DevOp.Jira
using DevOp.Jira;
var options = new JiraClientOptions
{
BaseUrl = new Uri("https://your-domain.atlassian.net"),
Email = "[email protected]",
ApiToken = "your-api-token",
UserAgent = "DevOp.Jira/1.0"
};
using var client = new JiraClient(options);
var issue = await client.Issues.GetAsync("PROJ-123");
Console.WriteLine(issue?.Summary);
using DevOp.Jira;
using DevOp.Jira.Extensions;
services.AddJiraClient(options =>
{
options.BaseUrl = new Uri("https://your-domain.atlassian.net");
options.Email = "[email protected]";
options.ApiToken = "your-api-token";
});
Configuration binding is supported:
services.AddJiraClient(configuration, sectionName: "Jira");
Example configuration:
{
"Jira": {
"BaseUrl": "https://your-domain.atlassian.net",
"Email": "[email protected]",
"ApiToken": "your-api-token",
"UserAgent": "DevOp.Jira/1.0",
"Timeout": "00:00:30",
"MaxPageSize": 300,
"RetryCount": 3,
"RetryDelay": "00:00:00.200",
"RetryMaxDelay": "00:00:05",
"TeamFieldKey": "customfield_10001",
"CustomFieldMappings": {
"Customer": "customfield_12345",
"Team": "customfield_67890"
}
}
}
Options are validated when the client is created or resolved from dependency injection.
var issues = await client.Issues.Query()
.ForSpace("PROJ")
.ForStatus("In Progress", "Blocked")
.AssignedToCurrentUser()
.OrderByDescending(x => x.Updated)
.Take(25)
.ToListAsync();
LINQ predicates are translated to JQL for common query shapes:
var recentDone = await client.Issues.Query()
.Where(x => x.Space == "PROJ" && x.Status == "Done" && x.Created >= DateTime.UtcNow.AddDays(-30))
.OrderByDescending(x => x.Created)
.ToListAsync();
Raw JQL is available when Jira syntax is clearer:
var page = await client.Issues.SearchAsync(
"project = PROJ AND statusCategory != Done ORDER BY updated DESC",
maxResults: 50);
Jira Cloud issue search uses nextPageToken; DevOp.Jira follows that model for /rest/api/3/search/jql.