Skip to content
Snippets Groups Projects
Select Git revision
  • 00bf898cd77612340655c9729ea66bb1da964012
  • main default protected
  • renovate/main-renovatebot-github-action-43.x
  • next
  • feat/gnupg
  • fix/36615b-branch-reuse-no-cache
  • renovate/main-redis-5.x
  • chore/punycode
  • refactor/pin-new-value
  • feat/36219--git-x509-signing
  • feat/structured-logger
  • hotfix/39.264.1
  • feat/skip-dangling
  • gh-readonly-queue/next/pr-36034-7a061c4ca1024a19e2c295d773d9642625d1c2be
  • hotfix/39.238.3
  • refactor/gitlab-auto-approve
  • feat/template-strings
  • gh-readonly-queue/next/pr-35654-137d934242c784e0c45d4b957362214f0eade1d7
  • fix/32307-global-extends-merging
  • fix/32307-global-extends-repositories
  • gh-readonly-queue/next/pr-35009-046ebf7cb84ab859f7fefceb5fa53a54ce9736f8
  • 41.45.0
  • 41.44.0
  • 41.43.7
  • 41.43.6
  • 41.43.5
  • 41.43.4
  • 41.43.3
  • 41.43.2
  • 41.43.1
  • 41.43.0
  • 41.42.12
  • 41.42.11
  • 41.42.10
  • 41.42.9
  • 41.42.8
  • 41.42.7
  • 41.42.6
  • 41.42.5
  • 41.42.4
  • 41.42.3
41 results

schedule.ts

Blame
  • user avatar
    renovate[bot] authored and GitHub committed
    * chore(deps): update dependency prettier to v2
    
    * Run prettier-fix
    
    Co-authored-by: default avatarRenovate Bot <bot@renovateapp.com>
    Co-authored-by: default avatarJamie Magee <jamie.magee@gmail.com>
    4f59b62d
    History
    schedule.ts 6.25 KiB
    import is from '@sindresorhus/is';
    import later from 'later';
    import moment from 'moment-timezone';
    import { logger } from '../../logger';
    
    const scheduleMappings = {
      'every month': 'before 3am on the first day of the month',
      monthly: 'before 3am on the first day of the month',
    };
    
    function fixShortHours(input: string): string {
      return input.replace(/( \d?\d)((a|p)m)/g, '$1:00$2');
    }
    
    export function hasValidTimezone(
      timezone: string
    ): [boolean] | [boolean, string] {
      if (!moment.tz.zone(timezone)) {
        return [false, `Invalid schedule: Unsupported timezone ${timezone}`];
      }
      return [true];
    }
    
    export function hasValidSchedule(
      schedule: string[] | null | 'at any time'
    ): [boolean] | [boolean, string] {
      let message: string;
      if (
        !schedule ||
        schedule === 'at any time' ||
        schedule[0] === 'at any time'
      ) {
        return [true];
      }
      // check if any of the schedules fail to parse
      const hasFailedSchedules = schedule.some((scheduleText) => {
        const massagedText = fixShortHours(
          scheduleMappings[scheduleText] || scheduleText
        );
        const parsedSchedule = later.parse.text(massagedText);
        if (parsedSchedule.error !== -1) {
          message = `Invalid schedule: Failed to parse "${scheduleText}"`;
          // It failed to parse
          return true;
        }
        if (parsedSchedule.schedules.some((s) => s.m)) {
          message = `Invalid schedule: "${scheduleText}" should not specify minutes`;
          return true;
        }
        if (
          !parsedSchedule.schedules.some(
            (s) => s.M || s.d !== undefined || s.D || s.t_a !== undefined || s.t_b
          )
        ) {
          message = `Invalid schedule: "${scheduleText}" has no months, days of week or time of day`;
          return true;
        }
        // It must be OK
        return false;
      });
      if (hasFailedSchedules) {
        // If any fail then we invalidate the whole thing
        return [false, message];
      }
      return [true, ''];
    }
    
    export function isScheduledNow(config): boolean {
      let configSchedule = config.schedule;
      logger.debug(`Checking schedule(${configSchedule}, ${config.timezone})`);
      if (
        !configSchedule ||
        configSchedule.length === 0 ||
        configSchedule[0] === '' ||
        configSchedule === 'at any time' ||
        configSchedule[0] === 'at any time'
      ) {
        logger.debug('No schedule defined');
        return true;
      }
      if (!is.array(configSchedule)) {
        logger.warn(
          `config schedule is not an array: ${JSON.stringify(configSchedule)}`
        );
        configSchedule = [configSchedule];
      }
      const [validSchedule, errorMessage] = hasValidSchedule(configSchedule);
      if (!validSchedule) {
        logger.warn(errorMessage);
        return true;
      }
      let now = moment();
      logger.trace(`now=${now.format()}`);
      // Adjust the time if repo is in a different timezone to renovate
      if (config.timezone) {
        logger.debug({ timezone: config.timezone }, 'Found timezone');
        const [validTimezone, error] = hasValidTimezone(config.timezone);
        if (!validTimezone) {
          logger.warn(error);
          return true;
        }
        logger.debug('Adjusting now for timezone');
        now = now.tz(config.timezone);
        logger.trace(`now=${now.format()}`);
      }
      // Get today in text form, e.g. "Monday";
      const currentDay = now.format('dddd');
      logger.trace(`currentDay=${currentDay}`);
      // Get the number of seconds since midnight
      const currentSeconds =
        now.hours() * 3600 + now.minutes() * 60 + now.seconds();
      logger.trace(`currentSeconds=${currentSeconds}`);
      // Support a single string but massage to array for processing
      logger.debug(`Checking ${configSchedule.length} schedule(s)`);
      // We run if any schedule matches
      const isWithinSchedule = configSchedule.some((scheduleText) => {
        const massagedText = scheduleMappings[scheduleText] || scheduleText;
        const parsedSchedule = later.parse.text(fixShortHours(massagedText));
        logger.debug({ parsedSchedule }, `Checking schedule "${scheduleText}"`);
        // Later library returns array of schedules
        return parsedSchedule.schedules.some((schedule) => {
          // Check if months are defined
          if (schedule.M) {
            const currentMonth = parseInt(now.format('M'), 10);
            if (!schedule.M.includes(currentMonth)) {
              logger.debug(
                `Does not match schedule because ${currentMonth} is not in ${schedule.M}`
              );
              return false;
            }
          }
          // Check if days are defined
          if (schedule.d) {
            // We need to compare text instead of numbers because
            // 'moment' adjusts day of week for locale while 'later' does not
            // later days run from 1..7
            const dowMap = [
              null,
              'Sunday',
              'Monday',
              'Tuesday',
              'Wednesday',
              'Thursday',
              'Friday',
              'Saturday',
            ];
            const scheduledDays = schedule.d.map((day) => dowMap[day]);
            logger.trace({ scheduledDays }, `scheduledDays`);
            if (!scheduledDays.includes(currentDay)) {
              logger.debug(
                `Does not match schedule because ${currentDay} is not in ${scheduledDays}`
              );
              return false;
            }
          }
          if (schedule.D) {
            logger.debug({ schedule_D: schedule.D }, `schedule.D`);
            // moment outputs as string but later outputs as integer
            const currentDayOfMonth = parseInt(now.format('D'), 10);
            if (!schedule.D.includes(currentDayOfMonth)) {
              return false;
            }
          }
          // Check for start time
          if (schedule.t_a) {
            const startSeconds = schedule.t_a[0];
            if (currentSeconds < startSeconds) {
              logger.debug(
                `Does not match schedule because ${currentSeconds} is earlier than ${startSeconds}`
              );
              return false;
            }
          }
          // Check for end time
          if (schedule.t_b) {
            const endSeconds = schedule.t_b[0];
            if (currentSeconds > endSeconds) {
              logger.debug(
                `Does not match schedule because ${currentSeconds} is later than ${endSeconds}`
              );
              return false;
            }
          }
          // Check for week of year
          if (schedule.wy && !schedule.wy.includes(now.week())) {
            return false;
          }
          logger.debug(`Matches schedule ${scheduleText}`);
          return true;
        });
      });
      if (!isWithinSchedule) {
        logger.debug('Package not scheduled');
        return false;
      }
      return true;
    }