From ad7b3ceda800812356b17d7183ced251cd279fc3 Mon Sep 17 00:00:00 2001 From: Sukhdev suthar <70461656+Sukhdev2002@users.noreply.github.com> Date: Wed, 31 Jul 2024 21:42:50 +0530 Subject: [PATCH] feat(schedule): Log descriptive cron schedules (#30472) Co-authored-by: Rhys Arkins --- .../repository/update/branch/schedule.spec.ts | 27 +++++++++++++++++++ .../repository/update/branch/schedule.ts | 5 ++++ package.json | 8 +++++- pnpm-lock.yaml | 10 ++++++- 4 files changed, 48 insertions(+), 2 deletions(-) diff --git a/lib/workers/repository/update/branch/schedule.spec.ts b/lib/workers/repository/update/branch/schedule.spec.ts index 1e7628b026..c510a7b559 100644 --- a/lib/workers/repository/update/branch/schedule.spec.ts +++ b/lib/workers/repository/update/branch/schedule.spec.ts @@ -1,3 +1,4 @@ +import cronstrue from 'cronstrue'; import type { RenovateConfig } from '../../../../config/types'; import * as schedule from './schedule'; @@ -407,4 +408,30 @@ describe('workers/repository/update/branch/schedule', () => { }); }); }); + + describe('cronstrue', () => { + it('should correctly convert "0 22 4 * *" to human-readable format', () => { + const result = cronstrue.toString('0 22 4 * *'); + expect(result).toBe('At 10:00 PM, on day 4 of the month'); + }); + + it('should correctly convert "*/2 * * * *" to human-readable format', () => { + const result = cronstrue.toString('*/2 * * * *'); + expect(result).toBe('Every 2 minutes'); + }); + + it('should correctly convert "0 23 * * *" to human-readable format', () => { + const result = cronstrue.toString('0 23 * * *'); + expect(result).toBe('At 11:00 PM'); + }); + + it('should throw an error for an invalid cron expression "* * */2 6#1"', () => { + const result = cronstrue.toString('* * */2 6#1', { + throwExceptionOnParseError: false, + }); + expect(result).toBe( + 'An error occured when generating the expression description. Check the cron expression syntax.', + ); + }); + }); }); diff --git a/lib/workers/repository/update/branch/schedule.ts b/lib/workers/repository/update/branch/schedule.ts index ec159ba74d..347ef787ae 100644 --- a/lib/workers/repository/update/branch/schedule.ts +++ b/lib/workers/repository/update/branch/schedule.ts @@ -8,6 +8,7 @@ import { MonthRange, parseExpression, } from 'cron-parser'; +import cronstrue from 'cronstrue'; import { DateTime } from 'luxon'; import { fixShortHours } from '../../../../config/migration'; import type { RenovateConfig } from '../../../../config/types'; @@ -25,6 +26,10 @@ function parseCron( timezone?: string, ): CronExpression | undefined { try { + const cronScheduleSummary = cronstrue.toString(scheduleText, { + throwExceptionOnParseError: false, + }); + logger.debug(`Human-readable summary for cron:: ${cronScheduleSummary}`); return parseExpression(scheduleText, { tz: timezone }); } catch (err) { return undefined; diff --git a/package.json b/package.json index c40b1afa79..766910bfbd 100644 --- a/package.json +++ b/package.json @@ -177,6 +177,7 @@ "commander": "12.1.0", "conventional-commits-detector": "1.0.3", "cron-parser": "4.9.0", + "cronstrue": "2.50.0", "deepmerge": "4.3.1", "dequal": "2.0.3", "detect-indent": "6.1.0", @@ -347,7 +348,12 @@ "renovate-schema.json" ], "pnpm": { - "ignoredOptionalDependencies": ["dtrace-provider", "moment", "mv", "safe-json-stringify"], + "ignoredOptionalDependencies": [ + "dtrace-provider", + "moment", + "mv", + "safe-json-stringify" + ], "overrides": { "@semantic-release/github>@octokit/plugin-paginate-rest": "11.3.0", "@types/linkify-it": "<5.0.0" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 5d5aa3a878..7b10d87130 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -129,6 +129,9 @@ importers: cron-parser: specifier: 4.9.0 version: 4.9.0 + cronstrue: + specifier: 2.50.0 + version: 2.50.0 deepmerge: specifier: 4.3.1 version: 4.3.1 @@ -1179,7 +1182,6 @@ packages: '@ls-lint/ls-lint@2.2.3': resolution: {integrity: sha512-ekM12jNm/7O2I/hsRv9HvYkRdfrHpiV1epVuI2NP+eTIcEgdIdKkKCs9KgQydu/8R5YXTov9aHdOgplmCHLupw==} - cpu: [x64, arm64, s390x] os: [darwin, linux, win32] hasBin: true @@ -2790,6 +2792,10 @@ packages: resolution: {integrity: sha512-p0SaNjrHOnQeR8/VnfGbmg9te2kfyYSQ7Sc/j/6DtPL3JQvKxmjO9TSjNFpujqV3vEYYBvNNvXSxzyksBWAx1Q==} engines: {node: '>=12.0.0'} + cronstrue@2.50.0: + resolution: {integrity: sha512-ULYhWIonJzlScCCQrPUG5uMXzXxSixty4djud9SS37DoNxDdkeRocxzHuAo4ImRBUK+mAuU5X9TSwEDccnnuPg==} + hasBin: true + cross-spawn@7.0.3: resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==} engines: {node: '>= 8'} @@ -9359,6 +9365,8 @@ snapshots: dependencies: luxon: 3.4.4 + cronstrue@2.50.0: {} + cross-spawn@7.0.3: dependencies: path-key: 3.1.1