Skip to content
Snippets Groups Projects
Select Git revision
  • 3437ebac7a871c0d457a517ed4456b51d9debbbf
  • main default protected
  • renovate/main-renovatebot-osv-offline-1.x
  • fix/36927-maven-tags
  • renovate/main-redis-5.x
  • next
  • revert-31645-feat/rename-gradle-wrapper-validation-action
  • fix/36615b-branch-reuse-no-cache
  • 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
  • 41.37.7
  • 41.37.6
  • 41.37.5
  • 41.37.4
  • 41.37.3
  • 41.37.2
  • 41.37.1
  • 41.37.0
  • 41.36.2
  • 41.36.1
  • 41.36.0
  • 41.35.2
  • 41.35.1
  • 41.35.0
  • 41.34.1
  • 41.34.0
  • 41.33.0
  • 41.32.3
  • 41.32.2
  • 41.32.1
41 results

renovate.ts

Blame
  • artifacts.ts 4.46 KiB
    import is from '@sindresorhus/is';
    import { logger } from '../../../logger';
    import * as packageCache from '../../../util/cache/package';
    import { hashStream } from '../../../util/hash';
    import { Http } from '../../../util/http';
    import { map as pMap } from '../../../util/promises';
    import { regEx } from '../../../util/regex';
    import type { UpdateArtifact, UpdateArtifactsResult } from '../types';
    import { findCodeFragment, patchCodeAtFragments, updateCode } from './common';
    import type { RecordFragment, StringFragment } from './types';
    
    const http = new Http('bazel');
    
    function getUrlFragments(rule: RecordFragment): StringFragment[] {
      const urls: StringFragment[] = [];
    
      const urlRecord = rule.children['url'];
      if (urlRecord?.type === 'string') {
        urls.push(urlRecord);
      }
    
      const urlsRecord = rule.children['urls'];
      if (urlsRecord?.type === 'array') {
        for (const urlRecord of urlsRecord.children) {
          if (urlRecord.type === 'string') {
            urls.push(urlRecord);
          }
        }
      }
    
      return urls;
    }
    
    const urlMassages = {
      'bazel-skylib.': 'bazel_skylib-',
      '/bazel-gazelle/releases/download/0': '/bazel-gazelle/releases/download/v0',
      '/bazel-gazelle-0': '/bazel-gazelle-v0',
      '/rules_go/releases/download/0': '/rules_go/releases/download/v0',
      '/rules_go-0': '/rules_go-v0',
    };
    
    function massageUrl(url: string): string {
      let result = url;
      for (const [from, to] of Object.entries(urlMassages)) {
        result = result.replace(from, to);
      }
      return result;
    }
    
    function replaceAll(input: string, from: string, to: string): string {
      return input.split(from).join(to);
    }
    
    function replaceValues(
      content: string,
      from: string | null | undefined,
      to: string | null | undefined,
    ): string {
      // istanbul ignore if
      if (!from || !to || from === to) {
        return content;
      }
      const massagedFrom = from.replace(regEx(/^v/), '');
      const massagedTo = to.replace(regEx(/^v/), '');
      return replaceAll(content, massagedFrom, massagedTo);
    }
    
    async function getHashFromUrl(url: string): Promise<string | null> {
      const cacheNamespace = 'url-sha256';
      const cachedResult = await packageCache.get<string | null>(
        cacheNamespace,
        url,
      );
      /* istanbul ignore next line */
      if (cachedResult) {
        return cachedResult;
      }
      try {
        const hash = await hashStream(http.stream(url), 'sha256');
        const cacheMinutes = 3 * 24 * 60; // 3 days
        await packageCache.set(cacheNamespace, url, hash, cacheMinutes);
        return hash;
      } catch /* istanbul ignore next */ {
        return null;
      }
    }
    
    async function getHashFromUrls(urls: string[]): Promise<string | null> {
      const hashes = (
        await pMap(urls, (url) => getHashFromUrl(massageUrl(url)))
      ).filter(is.truthy);
      if (!hashes.length) {
        logger.debug({ urls }, 'Could not calculate hash for URLs');
        return null;
      }
    
      const distinctHashes = new Set(hashes);
      // istanbul ignore if
      if (distinctHashes.size > 1) {
        logger.warn({ urls }, 'Found multiple hashes for single def');
      }
    
      return hashes[0];
    }
    
    export async function updateArtifacts(
      updateArtifact: UpdateArtifact,
    ): Promise<UpdateArtifactsResult[] | null> {
      const { packageFileName: path, updatedDeps: upgrades } = updateArtifact;
      let { newPackageFileContent: contents } = updateArtifact;
      for (const upgrade of upgrades) {
        const { managerData } = upgrade;
        const idx = managerData?.idx as number;
    
        if (upgrade.depType === 'http_file' || upgrade.depType === 'http_archive') {
          const rule = findCodeFragment(contents, [idx]);
          // istanbul ignore if
          if (rule?.type !== 'record') {
            return null;
          }
    
          const urlFragments = getUrlFragments(rule);
          if (!urlFragments?.length) {
            logger.debug(`def: ${rule.value}, urls is empty`);
            return null;
          }
    
          const updateValues = (oldUrl: string): string => {
            let url = oldUrl;
            url = replaceValues(url, upgrade.currentValue, upgrade.newValue);
            url = replaceValues(url, upgrade.currentDigest, upgrade.newDigest);
            return url;
          };
    
          const urls = urlFragments.map(({ value }) => updateValues(value));
          const hash = await getHashFromUrls(urls);
          if (!hash) {
            return null;
          }
    
          contents = patchCodeAtFragments(contents, urlFragments, updateValues);
          contents = updateCode(contents, [idx, 'strip_prefix'], updateValues);
          contents = updateCode(contents, [idx, 'sha256'], hash);
        }
      }
    
      return [
        {
          file: {
            type: 'addition',
            path,
            contents,
          },
        },
      ];
    }