Task Trackers & Work Items¶
This repo normalizes Jira issues, GitHub issues/Projects items, GitLab issues, and Linear issues into a unified WorkItem model (src/dev_health_ops/models/work_items.py) and computes daily aggregates + cycle times.
Jira is used to track associated project work (planning/throughput/WIP). Pull request metrics are computed from PR/MR data synced via the CLI (dev-hops sync ...) and are independent of Jira.
Provider Credentials (env vars)¶
Jira (Cloud)¶
JIRA_BASE_URL(e.g.your-org.atlassian.netorhttps://your-org.atlassian.net; normalized tohttps://)JIRA_EMAILJIRA_API_TOKENJIRA_PROJECT_KEYS(optional, comma-separated, e.g.ABC,XYZ)JIRA_JQL(optional override; if set, used as-is instead of the built-in windowed query)JIRA_FETCH_ALL(optional; set to1to fetch all issues in the project(s) regardless of date window — can be very slow)JIRA_FETCH_COMMENTS(optional; set to0to disable comment metadata ingestion; default:1)
Optional Jira field mappings (instance-specific):
- JIRA_STORY_POINTS_FIELD (e.g. customfield_10016)
- JIRA_SPRINT_FIELD (default: customfield_10020)
- JIRA_EPIC_LINK_FIELD (e.g. customfield_10014)
GitHub¶
GITHUB_TOKEN- Optional CLI override:
dev-hops sync work-items --provider github --auth "$GITHUB_TOKEN" ...
Optional Projects v2 ingestion:
- GITHUB_PROJECTS_V2 as comma-separated org_login:project_number entries, e.g.:
- GITHUB_PROJECTS_V2="myorg:3,anotherorg:12"
GitLab¶
GITLAB_TOKENGITLAB_URL(optional, default:https://gitlab.com)- Optional CLI override:
dev-hops sync work-items --provider gitlab --auth "$GITLAB_TOKEN" ...
Linear¶
LINEAR_API_KEY(required)
Optional configuration:
- LINEAR_FETCH_COMMENTS (default: true) - fetch issue comments
- LINEAR_FETCH_HISTORY (default: true) - fetch status change history for transitions
- LINEAR_FETCH_CYCLES (default: true) - fetch cycles as sprints
- LINEAR_COMMENTS_LIMIT (default: 100) - max comments per issue
Usage:
# Sync all teams
dev-hops sync work-items --provider linear --db "$DATABASE_URI"
# Sync specific team by key (e.g., ENG, PROD)
dev-hops sync work-items --provider linear --repo ENG --db "$DATABASE_URI"
Status & Type Normalization¶
Status normalization is config-driven via src/dev_health_ops/config/status_mapping.yaml.
Status categories¶
Normalized categories are:
- backlog
- todo
- in_progress
- in_review
- blocked
- done
- canceled
Provider-specific rules¶
The mapping file supports:
- Jira: providers.jira.statuses (maps Jira status names)
- GitHub/GitLab: providers.<provider>.status_labels (maps label names to categories)
- Linear: providers.linear.state_types (maps Linear state.type to categories)
If no label/status match exists:
- GitHub: open → todo, closed → done
- GitLab: opened → todo, closed → done
- Linear: Maps state.type directly (backlog, unstarted → todo, started → in_progress, completed → done, canceled)
Identity Mapping (optional)¶
To keep user metrics consistent across providers, populate src/dev_health_ops/config/identity_mapping.yaml.
Schema:
- canonical: stable identity (prefer email)
- aliases: provider-qualified logins (e.g. github:octocat) or Jira account IDs (e.g. jira:accountid:abcd123)
Team Mapping (optional)¶
To enable team filtering in Grafana, you can sync teams from various sources.
Config-based Mapping¶
Populate src/dev_health_ops/config/team_mapping.yaml (schema: team_id, team_name, members).
Then run:
dev-hops sync teams --path src/dev_health_ops/config/team_mapping.yaml
Jira Project Mapping¶
Automatically import Jira projects as teams:
dev-hops sync teams --provider jira
Running Jira work metrics¶
Jira work items are fetched via the work item sync job:
dev-hops sync work-items --provider jira --date 2025-02-01 --backfill 30 --db "clickhouse://localhost:8123/default"
Use -s/--search to filter repos by name (glob pattern), e.g.:
dev-hops sync work-items --provider github -s "org/*" --date 2025-02-01 --backfill 30 --db "clickhouse://localhost:8123/default"
Atlassian Client Migration¶
The project is migrating from a legacy custom Jira client to a shared atlassian client library. This migration is managed via feature flags and runs in parallel with the legacy implementation.
See Atlassian Client Integration Plan for the full phased roadmap.
Feature Flags¶
| Variable | Default | Description |
|---|---|---|
ATLASSIAN_CLIENT_ENABLED |
false |
Enable the new atlassian client library for Jira sync. When false, the legacy JiraClient is used. |
ATLASSIAN_GQL_ENABLED |
false |
Enable Atlassian GraphQL Gateway (AGG) enrichment (Phase 5). Requires OAuth credentials. |
JIRA_USE_PROVIDER |
false |
Use JiraProvider in the work items pipeline instead of the standalone sync function. |
New Atlassian Environment Variables¶
When ATLASSIAN_CLIENT_ENABLED=true, configure these variables (they fall back to legacy JIRA_* vars if unset):
| Variable | Description |
|---|---|
ATLASSIAN_EMAIL |
Atlassian account email (falls back to JIRA_EMAIL) |
ATLASSIAN_API_TOKEN |
API token (falls back to JIRA_API_TOKEN) |
ATLASSIAN_JIRA_BASE_URL |
Jira Cloud base URL, e.g. https://your-org.atlassian.net (falls back to JIRA_BASE_URL) |
ATLASSIAN_CLOUD_ID |
Atlassian Cloud ID (auto-derived from base URL if omitted) |
Optional: Custom field IDs¶
| Variable | Description |
|---|---|
ATLASSIAN_JIRA_STORY_POINTS_FIELD |
Custom field ID for story points (e.g. customfield_10016) |
ATLASSIAN_JIRA_SPRINT_IDS_FIELD |
Custom field ID for sprint (default: customfield_10020) |
Optional: GraphQL / OAuth (Phase 5)¶
| Variable | Description |
|---|---|
ATLASSIAN_OAUTH_ACCESS_TOKEN |
OAuth access token for AGG |
ATLASSIAN_OAUTH_REFRESH_TOKEN |
OAuth refresh token |
ATLASSIAN_CLIENT_ID |
OAuth client ID |
ATLASSIAN_CLIENT_SECRET |
OAuth client secret |
ATLASSIAN_GQL_BASE_URL |
Tenant GraphQL endpoint (e.g. https://your-org.atlassian.net/gateway/api/graphql) |
ATLASSIAN_GQL_EXPERIMENTAL_APIS |
Comma-separated experimental APIs (e.g. jira-software) |
ATLASSIAN_COOKIES_JSON |
Cookie auth for AGG (JSON object) |
Migration Approach¶
The migration uses a parallel-run strategy:
1. Both legacy and new client run side by side
2. Feature flag toggles which implementation is active
3. Rollback is instant by setting ATLASSIAN_CLIENT_ENABLED=false
4. No database schema changes are required for Phases 1-4
Quick Jira API smoke test (curl)¶
Jira Cloud has removed GET /rest/api/3/search; use GET /rest/api/3/search/jql:
curl -sS -u "$JIRA_EMAIL:$JIRA_API_TOKEN" \
--get "https://$JIRA_BASE_URL/rest/api/3/search/jql" \
--data-urlencode "jql=(updated >= '2025-09-10' OR (statusCategory != Done AND created <= '2025-12-18')) ORDER BY updated DESC" \
--data-urlencode "maxResults=5" \
--data-urlencode "fields=key,summary,updated,status"