Skip to content
Snippets Groups Projects
Select Git revision
  • 8c479071fd99240a304739c35b6c4f7f21853e9b
  • main default protected
  • renovate/main-ghcr.io-renovatebot-base-image-10.x
  • renovate/main-ghcr.io-containerbase-devcontainer-13.x
  • next
  • revert-31645-feat/rename-gradle-wrapper-validation-action
  • renovate/main-redis-5.x
  • fix/36615b-branch-reuse-no-cache
  • chore/punycode
  • fix/36615-branch-reuse-bug
  • 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
  • 41.31.1
  • 41.31.0
  • 41.30.5
  • 41.30.4
  • 41.30.3
  • 41.30.2
  • 41.30.1
  • 41.30.0
  • 41.29.1
  • 41.29.0
  • 41.28.2
  • 41.28.1
  • 41.28.0
  • 41.27.1
  • 41.27.0
  • 41.26.2
  • 41.26.1
  • 41.26.0
  • 41.25.1
  • 41.25.0
41 results

semantic.js

Blame
  • package-files.ts 5.21 KiB
    import is from '@sindresorhus/is';
    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 base branch`,
        );
        this.data.set(baseBranch, packageFiles);
      }
    
      static clear(): void {
        logger.debug('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 maxLength
       * @param setHeader
       */
      static getDashboardMarkdown(maxLength: number, setHeader = true): string {
        const note =
          '> ℹ **Note**\n> \n> Detected dependencies section has been truncated\n\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;
    
        const data = new Map(clone(Array.from(this.data)));
    
        // filter all deps with skip reason
        for (const managers of [...data.values()].filter(is.truthy)) {
          for (const files of Object.values(managers).filter(is.truthy)) {
            for (const file of files.filter((f) => is.truthy(f.deps))) {
              file.deps = file.deps.filter(is.truthy).filter((d) => !d.skipReason);
            }
          }
        }
    
        do {
          // shorten markdown until it fits
          md = PackageFiles.getDashboardMarkdownInternal(data);
          if (md.length > mdMaxLength) {
            // truncate data
            removed = PackageFiles.pop(data);
          }
          if (removed) {
            truncated = true; // used to set the truncation Note
          }
        } while (removed && md.length > mdMaxLength);
    
        header += title;
        header += truncated ? note : '';
    
        return (setHeader ? header : '') + md;
      }
    
      /**
       * Generates the "detected dependencies" markdown
       * @param data
       */
      private static getDashboardMarkdownInternal(
        data: Map<string, Record<string, PackageFile[]> | null>,
      ): string {
        const none = 'None detected\n\n';
        const pad = data.size > 1; // padding condition for a multi base branch repo
        let deps = '';
    
        for (const [branch, packageFiles] of 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;
          }
    
          for (const manager of managers) {
            deps += `<details><summary>${manager}</summary>\n<blockquote>\n\n`;
            for (const packageFile of packageFiles[manager]) {
              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!}`;
                // TODO: types (#22198)
                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;
      }
    
      /**
       * Removes the last dependency/entry in the PackageFiles data
       * i.e. the last line in the tobe generated detected dependency section
       * @param data
       * @Returns true if anything that translates to a markdown written line was deleted
       *          otherwise false is returned
       */
      private static pop(
        data: Map<string, Record<string, PackageFile[]> | null>,
      ): boolean {
        // get detected managers list of the last listed base branch
        const [branch, managers] = Array.from(data).pop() ?? [];
        if (!branch) {
          return false;
        }
    
        // delete base branch listing if it has no managers left
        if (!managers || is.emptyObject(managers)) {
          return 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();
      }
    }