UNPKG

bookr-cli

Version:

A terminal-based CLI tool to book time in Jira using the Tempo plugin by parsing your current Git branch name

163 lines 6.48 kB
/** * Tempo API client for worklog-related tasks * Docs: https://apidocs.tempo.io/ */ import { loadConfigFromFile } from '../utils/config.js'; export class TempoClient { constructor(baseUrl, apiToken) { this.baseUrl = baseUrl; this.apiToken = apiToken; } /** * Fetch worklogs for a user for a given date range (Tempo API v4) */ async getWorklogsForUser(accountId, from, to) { const url = `${this.baseUrl}/worklogs/user/${encodeURIComponent(accountId)}`; const params = new URLSearchParams({ from, to, limit: '1000' }); const response = await fetch(`${url}?${params.toString()}`, { method: 'GET', headers: { 'Authorization': `Bearer ${this.apiToken}`, 'Accept': 'application/json', }, }); if (!response.ok) { const errorText = await response.text(); throw new Error(`Failed to fetch Tempo worklogs: ${response.status} ${response.statusText} - ${errorText}`); } let data = await response.json(); // Map worklogs to add 'started' field if (Array.isArray(data.results)) { data.results = data.results.map((worklog) => { const worklogObj = worklog; let started = undefined; if (worklogObj['startDate']) { // If startTime is present, combine, else use 00:00:00 const time = worklogObj['startTime'] ? worklogObj['startTime'] : '00:00:00'; started = `${worklogObj['startDate']}T${time}`; } return { ...worklogObj, started }; }); } else if (Array.isArray(data)) { // Defensive: if API returns array directly data = data.map((worklog) => { const worklogObj = worklog; let started = undefined; if (worklogObj['startDate']) { const time = worklogObj['startTime'] ? worklogObj['startTime'] : '00:00:00'; started = `${worklogObj['startDate']}T${time}`; } return { ...worklogObj, started }; }); } return data; } /** * Add a worklog for a user */ async addWorklog(worklogData) { const url = `${this.baseUrl}/worklogs`; const payload = { issueId: worklogData.issueId, issueKey: worklogData.issueKey, timeSpentSeconds: worklogData.timeSpentSeconds, description: worklogData.comment || '', startDate: worklogData.startDate, // must be yyyy-MM-dd authorAccountId: worklogData.authorAccountId, ...(worklogData.startTime && { startTime: worklogData.startTime }), }; const response = await fetch(url, { method: 'POST', headers: { 'Authorization': `Bearer ${this.apiToken}`, 'Content-Type': 'application/json', 'Accept': 'application/json', }, body: JSON.stringify(payload), }); if (!response.ok) { const errorText = await response.text(); throw new Error(`Failed to add Tempo worklog: ${response.status} ${response.statusText} - ${errorText}`); } return (await response.json()); } /** * Delete a worklog by ID */ async deleteWorklog(worklogId) { const url = `${this.baseUrl}/worklogs/${worklogId}`; const response = await fetch(url, { method: 'DELETE', headers: { 'Authorization': `Bearer ${this.apiToken}`, 'Accept': 'application/json', }, }); if (!response.ok) { const errorText = await response.text(); throw new Error(`Failed to delete Tempo worklog: ${response.status} ${response.statusText} - ${errorText}`); } return true; } /** * Get workload scheme for a user */ async getUserWorkload(accountId) { // Try the user-specific endpoint first let url = `${this.baseUrl}/workload-schemes/users/${encodeURIComponent(accountId)}`; let response = await fetch(url, { method: 'GET', headers: { 'Authorization': `Bearer ${this.apiToken}`, 'Accept': 'application/json', }, }); // If user-specific endpoint fails, try the general workload schemes endpoint if (!response.ok) { url = `${this.baseUrl}/workload-schemes`; response = await fetch(url, { method: 'GET', headers: { 'Authorization': `Bearer ${this.apiToken}`, 'Accept': 'application/json', }, }); if (!response.ok) { const errorText = await response.text(); throw new Error(`Failed to fetch user workload: ${response.status} ${response.statusText} - ${errorText}`); } // If we get the general schemes, try to find the default one const schemes = await response.json(); const defaultScheme = schemes.results?.find(scheme => scheme.defaultScheme) || schemes.results?.[0]; if (!defaultScheme) { throw new Error('No workload schemes found'); } return { accountId, workloadScheme: defaultScheme, }; } const data = await response.json(); // The user-specific endpoint returns the workload scheme directly, not wrapped // Check if it's already in the expected format if (typeof data === 'object' && data !== null && 'accountId' in data && 'workloadScheme' in data) { return data; } // If it's just the workload scheme, wrap it return { accountId, workloadScheme: data, }; } } export function createTempoClient() { const fileConfig = loadConfigFromFile(); const baseUrl = 'https://api.tempo.io/4'; const apiToken = fileConfig?.tempoApiToken; if (!baseUrl || !apiToken) { throw new Error('Missing Tempo configuration. Please set tempoApiToken in your config file.'); } return new TempoClient(baseUrl, apiToken); } //# sourceMappingURL=tempo-client.js.map