Skip to content
Snippets Groups Projects
Select Git revision
  • d33ca43e17dc7afd66f91f4b9d3be2daf31c157a
  • main default protected
  • renovate/migrate-config
  • next
  • fix/36615b-branch-reuse-no-cache
  • renovate/main-redis-5.x
  • revert-31645-feat/rename-gradle-wrapper-validation-action
  • 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.42.2
  • 41.42.1
  • 41.42.0
  • 41.41.0
  • 41.40.0
  • 41.39.0
  • 41.38.2
  • 41.38.1
  • 41.38.0
  • 41.37.12
  • 41.37.11
  • 41.37.10
  • 41.37.9
  • 41.37.8
  • 41.37.7
  • 41.37.6
  • 41.37.5
  • 41.37.4
  • 41.37.3
  • 41.37.2
41 results

build-gradle.spec.ts

Blame
  • package-files.ts 5.45 KiB
    import is from '@sindresorhus/is';
    import type { RenovateConfig } from '../../config/types';
    import { logger } from '../../logger';
    import type { PackageFile } from '../../modules/manager/types';
    import { clone } from '../../util/clone';
    
    export class PackageFiles {
      private static data = new Map<string, Record<string, PackageFile[]> | null>();
    
      static add(
        baseBranch: string,
        packageFiles: Record<string, PackageFile[]> | null
      ): void {
        logger.debug(
          { baseBranch },
          `PackageFiles.add() - Package file saved for branch`
        );
        this.data.set(baseBranch, clone(packageFiles));
      }
    
      static clear(): void {
        logger.debug(
          { baseBranches: [...this.data.keys()] },
          'PackageFiles.clear() - Package files deleted'
        );
        this.data.clear();
      }
    
      /**
       * Truncates the detected dependencies' section until it fits the available space
       * i.e. It has length smaller than maxLength.
       * This does not mutate the original PackageFiles data
       * Note:  setHeader=false is used for testing purposes only
       *        Mainly for comparing truncated and non-truncated markdown
       * @param config
       * @param maxLength
       * @param setHeader
       */
      static getDashboardMarkdown(
        config: RenovateConfig,
        maxLength: number,
        setHeader = true
      ): string {
        const note =
          '> **Note**\n> Detected dependencies section has been truncated\n';
        const title = `## Detected dependencies\n\n`;
    
        // exclude header length from the available space
        const maxHeaderLen = setHeader ? (title + note).length : 0;
        const mdMaxLength = maxLength - maxHeaderLen;
    
        let md: string;
        let header = '';
        let removed = false;
        let truncated = false;
        let restore: (() => void) | null = null;
    
        do {
          // shorten markdown until it fits
          md = PackageFiles.getDashboardMarkdownInternal(config);
          if (md.length > mdMaxLength) {
            // backup data
            if (!restore) {
              restore = this.backup();
            }
            // truncate data
            removed = PackageFiles.pop();
          }
          if (removed) {
            truncated = true; // used to set the truncation Note
          }
        } while (removed && md.length > mdMaxLength);
    
        if (restore) {
          restore();
        } // restore original PackageFiles data
    
        header += title;
        header += truncated ? note : '';
    
        return (setHeader ? header : '') + md;
      }
    
      /**
       * Generates the "detected dependencies" markdown
       * @param config
       */
      private static getDashboardMarkdownInternal(config: RenovateConfig): string {
        const none = 'None detected\n\n';
        const pad = this.data.size > 1; // padding condition for a multi base branch repo
        let deps = '';
    
        for (const [branch, packageFiles] of this.data) {
          deps += pad
            ? `<details><summary>Branch ${branch}</summary>\n<blockquote>\n\n`
            : '';
          if (packageFiles === null) {
            deps += none;
            deps += pad ? '</blockquote>\n</details>\n\n' : '';
            continue;
          }
    
          const managers = Object.keys(packageFiles);
          if (managers.length === 0) {
            deps += none;
            deps += pad ? '</blockquote>\n</details>\n\n' : '';
            continue;
          }
    
          const placeHolder = `no version found`;
    
          for (const manager of managers) {
            deps += `<details><summary>${manager}</summary>\n<blockquote>\n\n`;
            for (const packageFile of packageFiles[manager]) {
              // TODO: types (#7154)
              deps += `<details><summary>${packageFile.packageFile!}</summary>\n\n`;
              for (const dep of packageFile.deps) {
                const ver = dep.currentValue;
                const digest = dep.currentDigest;
                const version =
                  ver && digest
                    ? `${ver}@${digest}`
                    : `${digest ?? ver ?? placeHolder}`;
                // TODO: types (#7154)
                deps += ` - \`${dep.depName!} ${version}\`\n`;
              }
              deps += '\n</details>\n\n';
            }
            deps += `</blockquote>\n</details>\n\n`;
          }
          deps += pad ? '</blockquote>\n</details>\n\n' : '';
        }
    
        return deps;
      }
    
      private static backup(): () => void {
        const backup = this.data; // backup data
        // deep clone data
        this.data = new Map(clone(Array.from(this.data))); // only mutate cloned data
    
        return () => {
          this.data = backup;
        };
      }
    
      /**
       * Removes the last dependency/entry in the PackageFiles data
       * i.e. the last line in the tobe generated detected dependency section
       * @Returns true if anything that translates to a markdown written line was deleted
       *          otherwise false is returned
       */
      private static pop(): boolean {
        // get detected managers list of the last listed base branch
        const [branch, managers] = Array.from(this.data).pop() ?? [];
        if (!branch) {
          return false;
        }
    
        // delete base branch listing if it has no managers left
        if (!managers || is.emptyObject(managers)) {
          return this.data.delete(branch);
        }
    
        // get all manifest files for the last listed manager
        const [manager, packageFiles] = Object.entries(managers).pop() ?? [];
    
        // delete current manager if it has no manifest files left
        if (!packageFiles || is.emptyArray(packageFiles)) {
          return delete managers[manager!];
        }
    
        // delete manifest file if it has no deps left
        const len = packageFiles.length - 1;
        if (is.emptyArray(packageFiles[len].deps)) {
          return !!packageFiles.pop();
        }
    
        // remove the last listed dependency
        return !!packageFiles[len].deps.pop();
      }
    }