From ef770ac878fd14a04fb7c693e0fd0184a157437c Mon Sep 17 00:00:00 2001 From: ashif323 Date: Tue, 7 Apr 2026 23:14:12 +0530 Subject: [PATCH 1/4] feat(wakatime): add time-based badges for user and project fix: resolve lint issues chore: trigger CI rerun --- services/wakatime/wakatime-time.service.js | 63 ++++++++++++++++++++++ services/wakatime/wakatime-time.tester.js | 27 ++++++++++ 2 files changed, 90 insertions(+) create mode 100644 services/wakatime/wakatime-time.service.js create mode 100644 services/wakatime/wakatime-time.tester.js diff --git a/services/wakatime/wakatime-time.service.js b/services/wakatime/wakatime-time.service.js new file mode 100644 index 0000000000000..5c09713cec0ac --- /dev/null +++ b/services/wakatime/wakatime-time.service.js @@ -0,0 +1,63 @@ +import { BaseService, pathParams } from '../index.js' + +export default class WakaTimeBadge extends BaseService { + static category = 'activity' + + static route = { + base: 'wakatime', + pattern: ':type(user|project)/:id', + } + + static openApi = { + '/wakatime/{type}/{id}': { + get: { + summary: 'WakaTime coding time badge', + parameters: [ + ...pathParams({ + name: 'type', + example: 'user', + }), + ...pathParams({ + name: 'id', + example: '73d84531-5bb3-4938-91c9-5ca9e6507df9', + }), + ], + }, + }, + } + + static _cacheLength = 3600 + + static defaultBadgeData = { + label: 'wakatime', + color: 'blue', + } + + async fetch({ type, id }) { + const url = `https://wakatime.com/badge/${type}/${id}.svg` + const { buffer } = await this._request({ url }) + return buffer.toString() + } + + extractTime(svg) { + const match = svg.match(/>([\d,]+\s+hrs?.*?) + nock('https://wakatime.com') + .get('/badge/user/test-id.svg') + .reply(200, `1,200 hrs 10 mins`), + ) + .expectBadge({ + label: 'wakatime', + message: '1,200 hrs 10 mins', + }) + +t.create('invalid response') + .get('/user/test-id.json') + .intercept(nock => + nock('https://wakatime.com') + .get('/badge/user/test-id.svg') + .reply(200, ``), + ) + .expectBadge({ + label: 'wakatime', + message: 'invalid', + }) From 34ffa7b614e8c3dd899a50e992c8305732e5fd3d Mon Sep 17 00:00:00 2001 From: ashif323 Date: Sun, 12 Apr 2026 21:13:04 +0530 Subject: [PATCH 2/4] refactor(wakatime): extend BaseSvgScrapingService instead of BaseService --- services/wakatime/wakatime-time.service.js | 34 ++++++++-------------- services/wakatime/wakatime-time.tester.js | 13 ++++++++- 2 files changed, 24 insertions(+), 23 deletions(-) diff --git a/services/wakatime/wakatime-time.service.js b/services/wakatime/wakatime-time.service.js index 5c09713cec0ac..a885bea0d80d9 100644 --- a/services/wakatime/wakatime-time.service.js +++ b/services/wakatime/wakatime-time.service.js @@ -1,8 +1,7 @@ -import { BaseService, pathParams } from '../index.js' +import { BaseSvgScrapingService, pathParams } from '../index.js' -export default class WakaTimeBadge extends BaseService { +export default class WakaTimeBadge extends BaseSvgScrapingService { static category = 'activity' - static route = { base: 'wakatime', pattern: ':type(user|project)/:id', @@ -33,31 +32,22 @@ export default class WakaTimeBadge extends BaseService { color: 'blue', } + static render({ message }) { + return { message, color: 'blue' } + } + async fetch({ type, id }) { const url = `https://wakatime.com/badge/${type}/${id}.svg` const { buffer } = await this._request({ url }) - return buffer.toString() - } - - extractTime(svg) { - const match = svg.match(/>([\d,]+\s+hrs?.*?)([\d,]+\s+hrs?.*?) + nock('https://wakatime.com') + .get('/badge/project/test-id.svg') + .reply(200, `500 hrs 30 mins`), + ) + .expectBadge({ + label: 'wakatime', + message: '500 hrs 30 mins', + }) + t.create('invalid response') .get('/user/test-id.json') .intercept(nock => From 83c230eec69f5cadc86cfc8ea4ea80094498ebf8 Mon Sep 17 00:00:00 2001 From: ashif323 Date: Sat, 18 Apr 2026 21:46:27 +0530 Subject: [PATCH 3/4] refactor(wakatime): use pathParams without spread and add enum to type schema --- services/wakatime/wakatime-time.service.js | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/services/wakatime/wakatime-time.service.js b/services/wakatime/wakatime-time.service.js index a885bea0d80d9..20348a54b81d4 100644 --- a/services/wakatime/wakatime-time.service.js +++ b/services/wakatime/wakatime-time.service.js @@ -11,16 +11,17 @@ export default class WakaTimeBadge extends BaseSvgScrapingService { '/wakatime/{type}/{id}': { get: { summary: 'WakaTime coding time badge', - parameters: [ - ...pathParams({ + parameters: pathParams( + { name: 'type', example: 'user', - }), - ...pathParams({ + schema: { type: 'string', enum: ['user', 'project'] }, + }, + { name: 'id', example: '73d84531-5bb3-4938-91c9-5ca9e6507df9', - }), - ], + }, + ), }, }, } From 4f3c326284377ba7f1c41df18858595f457d2caa Mon Sep 17 00:00:00 2001 From: ashif323 Date: Sun, 19 Apr 2026 13:13:08 +0530 Subject: [PATCH 4/4] refactor(wakatime): use getEnum for type parameter schema --- services/wakatime/wakatime-time.service.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/wakatime/wakatime-time.service.js b/services/wakatime/wakatime-time.service.js index 20348a54b81d4..501498e106b91 100644 --- a/services/wakatime/wakatime-time.service.js +++ b/services/wakatime/wakatime-time.service.js @@ -15,7 +15,7 @@ export default class WakaTimeBadge extends BaseSvgScrapingService { { name: 'type', example: 'user', - schema: { type: 'string', enum: ['user', 'project'] }, + schema: { type: 'string', enum: this.getEnum('type') }, }, { name: 'id',