renovate 44.153.0 → 44.154.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/config/global.d.ts +4 -0
- package/dist/config/global.js +13 -1
- package/dist/config/global.js.map +1 -1
- package/dist/modules/datasource/metadata.js +7 -6
- package/dist/modules/datasource/metadata.js.map +1 -1
- package/dist/modules/datasource/rpm/providers/common.js +16 -6
- package/dist/modules/datasource/rpm/providers/common.js.map +1 -1
- package/dist/modules/manager/terraform/lockfile/hash.js +2 -2
- package/dist/modules/manager/terraform/lockfile/hash.js.map +1 -1
- package/dist/modules/platform/github/index.js +6 -2
- package/dist/modules/platform/github/index.js.map +1 -1
- package/dist/util/compress.d.ts +2 -0
- package/dist/util/compress.js +44 -1
- package/dist/util/compress.js.map +1 -1
- package/dist/util/fs/index.js +2 -2
- package/dist/util/fs/index.js.map +1 -1
- package/dist/workers/global/config/parse/index.js +40 -1
- package/dist/workers/global/config/parse/index.js.map +1 -1
- package/dist/workers/global/index.js +3 -15
- package/dist/workers/global/index.js.map +1 -1
- package/dist/workers/repository/dependency-dashboard.js +2 -2
- package/dist/workers/repository/dependency-dashboard.js.map +1 -1
- package/package.json +1 -1
- package/renovate-schema.json +2 -2
package/dist/config/global.d.ts
CHANGED
|
@@ -8,5 +8,9 @@ export declare class GlobalConfig {
|
|
|
8
8
|
static set(config: RenovateConfig & RepoGlobalConfig & InternalGlobalConfigOptions): RenovateConfig;
|
|
9
9
|
static reset(): void;
|
|
10
10
|
}
|
|
11
|
+
/**
|
|
12
|
+
* Sets the global options which HTTP requests consult, for the requests made before the full global config is set.
|
|
13
|
+
*/
|
|
14
|
+
export declare function setHttpGlobalConfig(config: RenovateConfig & RepoGlobalConfig): void;
|
|
11
15
|
//#endregion
|
|
12
16
|
//# sourceMappingURL=global.d.ts.map
|
package/dist/config/global.js
CHANGED
|
@@ -79,7 +79,19 @@ var GlobalConfig = class GlobalConfig {
|
|
|
79
79
|
GlobalConfig.config = {};
|
|
80
80
|
}
|
|
81
81
|
};
|
|
82
|
+
/**
|
|
83
|
+
* Sets the global options which HTTP requests consult, for the requests made before the full global config is set.
|
|
84
|
+
*/
|
|
85
|
+
function setHttpGlobalConfig(config) {
|
|
86
|
+
GlobalConfig.set({
|
|
87
|
+
allowedHeaders: config.allowedHeaders,
|
|
88
|
+
endpoint: config.endpoint,
|
|
89
|
+
internalHostAccess: config.internalHostAccess,
|
|
90
|
+
platform: config.platform,
|
|
91
|
+
userAgent: config.userAgent
|
|
92
|
+
});
|
|
93
|
+
}
|
|
82
94
|
//#endregion
|
|
83
|
-
export { GlobalConfig };
|
|
95
|
+
export { GlobalConfig, setHttpGlobalConfig };
|
|
84
96
|
|
|
85
97
|
//# sourceMappingURL=global.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"global.js","names":[],"sources":["../../lib/config/global.ts"],"sourcesContent":["import { globalConfigOptionDefaults } from '../global-config-option-defaults.generated.ts';\nimport type {\n InternalGlobalConfigOptions,\n RenovateConfig,\n RepoGlobalConfig,\n} from './types.ts';\n\nexport class GlobalConfig {\n // TODO: once global config work is complete, add a test to make sure this list includes all options with globalOnly=true (#9603)\n static OPTIONS = [\n 'allowCustomCrateGitRegistries',\n 'allowPlugins',\n 'allowScripts',\n 'allowShellExecutorForPostUpgradeCommands',\n 'allowedCommands',\n 'allowedEnv',\n 'allowedHeaders',\n 'allowedUnsafeExecutions',\n 'autodiscoverRepoOrder',\n 'autodiscoverRepoSort',\n 'bbUseDevelopmentBranch',\n 'binarySource',\n 'cacheDir',\n 'cacheHardTtlMinutes',\n 'cachePrivatePackages',\n 'cacheTtlOverride',\n 'checkedBranches',\n 'configFileNames',\n 'containerbaseDir',\n 'customEnvVariables',\n 'dockerChildPrefix',\n 'dockerCliOptions',\n 'dockerMaxPages',\n 'dockerSidecarImage',\n 'dockerUser',\n 'dryRun',\n 'encryptedWarning',\n 'endpoint',\n 'executionTimeout',\n 'exposeAllEnv',\n 'gitTimeout',\n 'githubTokenWarn',\n 'httpCacheTtlDays',\n 'ignorePrAuthor',\n 'includeMirrors',\n 'inheritConfigTrusted',\n 'internalHostAccess',\n /** NOTE that this is not a config option, but an internal variable **/\n 'localDir',\n 'migratePresets',\n 'onboarding',\n 'onboardingAutoCloseAge',\n 'onboardingBranch',\n 'onboardingCommitMessage',\n 'onboardingConfig',\n 'onboardingConfigFileName',\n 'onboardingNoDeps',\n 'onboardingPrTitle',\n 'platform',\n 'prCacheSyncMaxPages',\n 'presetCachePersistence',\n 'productLinks',\n 'rebaseAllOpenBranches',\n 'repositoryCacheForceLocal',\n 'requireConfig',\n 's3Endpoint',\n 's3PathStyle',\n 'toolSettings',\n 'userAgent',\n ] as const satisfies readonly (\n keyof RepoGlobalConfig | keyof InternalGlobalConfigOptions\n )[];\n\n private static config: RepoGlobalConfig & InternalGlobalConfigOptions = {};\n\n static get(): RepoGlobalConfig & InternalGlobalConfigOptions;\n static get<\n Key extends keyof RepoGlobalConfig | keyof InternalGlobalConfigOptions,\n >(key: Key): Required<RepoGlobalConfig & InternalGlobalConfigOptions>[Key];\n static get<\n Key extends keyof RepoGlobalConfig | keyof InternalGlobalConfigOptions,\n >(\n key?: Key,\n ):\n | (RepoGlobalConfig & InternalGlobalConfigOptions)\n | Required<RepoGlobalConfig & InternalGlobalConfigOptions>[Key] {\n const defaultValue = key\n ? (globalConfigOptionDefaults[key] as Required<\n RepoGlobalConfig & InternalGlobalConfigOptions\n >[Key])\n : undefined;\n\n return key\n ? ((GlobalConfig.config[key] ?? defaultValue) as Required<\n RepoGlobalConfig & InternalGlobalConfigOptions\n >[Key])\n : GlobalConfig.config;\n }\n\n static set(\n config: RenovateConfig & RepoGlobalConfig & InternalGlobalConfigOptions,\n ): RenovateConfig {\n GlobalConfig.reset();\n\n const result = { ...config };\n for (const option of GlobalConfig.OPTIONS) {\n GlobalConfig.config[option] = config[option] as never;\n delete result[option];\n }\n\n return result;\n }\n\n static reset(): void {\n GlobalConfig.config = {};\n }\n}\n"],"mappings":";;AAOA,IAAa,eAAb,MAAa,aAAa;CAExB,OAAO,UAAU;EACf;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EAEA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;CACF;CAIA,OAAe,SAAyD,CAAC;CAMzE,OAAO,IAGL,KAGgE;EAChE,MAAM,eAAe,MAChB,2BAA2B,OAG5B,KAAA;EAEJ,OAAO,MACD,aAAa,OAAO,QAAQ,eAG9B,aAAa;CACnB;CAEA,OAAO,IACL,QACgB;EAChB,aAAa,MAAM;EAEnB,MAAM,SAAS,EAAE,GAAG,OAAO;EAC3B,KAAK,MAAM,UAAU,aAAa,SAAS;GACzC,aAAa,OAAO,UAAU,OAAO;GACrC,OAAO,OAAO;EAChB;EAEA,OAAO;CACT;CAEA,OAAO,QAAc;EACnB,aAAa,SAAS,CAAC;CACzB;AACF"}
|
|
1
|
+
{"version":3,"file":"global.js","names":[],"sources":["../../lib/config/global.ts"],"sourcesContent":["import { globalConfigOptionDefaults } from '../global-config-option-defaults.generated.ts';\nimport type {\n InternalGlobalConfigOptions,\n RenovateConfig,\n RepoGlobalConfig,\n} from './types.ts';\n\nexport class GlobalConfig {\n // TODO: once global config work is complete, add a test to make sure this list includes all options with globalOnly=true (#9603)\n static OPTIONS = [\n 'allowCustomCrateGitRegistries',\n 'allowPlugins',\n 'allowScripts',\n 'allowShellExecutorForPostUpgradeCommands',\n 'allowedCommands',\n 'allowedEnv',\n 'allowedHeaders',\n 'allowedUnsafeExecutions',\n 'autodiscoverRepoOrder',\n 'autodiscoverRepoSort',\n 'bbUseDevelopmentBranch',\n 'binarySource',\n 'cacheDir',\n 'cacheHardTtlMinutes',\n 'cachePrivatePackages',\n 'cacheTtlOverride',\n 'checkedBranches',\n 'configFileNames',\n 'containerbaseDir',\n 'customEnvVariables',\n 'dockerChildPrefix',\n 'dockerCliOptions',\n 'dockerMaxPages',\n 'dockerSidecarImage',\n 'dockerUser',\n 'dryRun',\n 'encryptedWarning',\n 'endpoint',\n 'executionTimeout',\n 'exposeAllEnv',\n 'gitTimeout',\n 'githubTokenWarn',\n 'httpCacheTtlDays',\n 'ignorePrAuthor',\n 'includeMirrors',\n 'inheritConfigTrusted',\n 'internalHostAccess',\n /** NOTE that this is not a config option, but an internal variable **/\n 'localDir',\n 'migratePresets',\n 'onboarding',\n 'onboardingAutoCloseAge',\n 'onboardingBranch',\n 'onboardingCommitMessage',\n 'onboardingConfig',\n 'onboardingConfigFileName',\n 'onboardingNoDeps',\n 'onboardingPrTitle',\n 'platform',\n 'prCacheSyncMaxPages',\n 'presetCachePersistence',\n 'productLinks',\n 'rebaseAllOpenBranches',\n 'repositoryCacheForceLocal',\n 'requireConfig',\n 's3Endpoint',\n 's3PathStyle',\n 'toolSettings',\n 'userAgent',\n ] as const satisfies readonly (\n keyof RepoGlobalConfig | keyof InternalGlobalConfigOptions\n )[];\n\n private static config: RepoGlobalConfig & InternalGlobalConfigOptions = {};\n\n static get(): RepoGlobalConfig & InternalGlobalConfigOptions;\n static get<\n Key extends keyof RepoGlobalConfig | keyof InternalGlobalConfigOptions,\n >(key: Key): Required<RepoGlobalConfig & InternalGlobalConfigOptions>[Key];\n static get<\n Key extends keyof RepoGlobalConfig | keyof InternalGlobalConfigOptions,\n >(\n key?: Key,\n ):\n | (RepoGlobalConfig & InternalGlobalConfigOptions)\n | Required<RepoGlobalConfig & InternalGlobalConfigOptions>[Key] {\n const defaultValue = key\n ? (globalConfigOptionDefaults[key] as Required<\n RepoGlobalConfig & InternalGlobalConfigOptions\n >[Key])\n : undefined;\n\n return key\n ? ((GlobalConfig.config[key] ?? defaultValue) as Required<\n RepoGlobalConfig & InternalGlobalConfigOptions\n >[Key])\n : GlobalConfig.config;\n }\n\n static set(\n config: RenovateConfig & RepoGlobalConfig & InternalGlobalConfigOptions,\n ): RenovateConfig {\n GlobalConfig.reset();\n\n const result = { ...config };\n for (const option of GlobalConfig.OPTIONS) {\n GlobalConfig.config[option] = config[option] as never;\n delete result[option];\n }\n\n return result;\n }\n\n static reset(): void {\n GlobalConfig.config = {};\n }\n}\n\n/**\n * Sets the global options which HTTP requests consult, for the requests made before the full global config is set.\n */\nexport function setHttpGlobalConfig(\n config: RenovateConfig & RepoGlobalConfig,\n): void {\n GlobalConfig.set({\n allowedHeaders: config.allowedHeaders,\n endpoint: config.endpoint,\n internalHostAccess: config.internalHostAccess,\n platform: config.platform,\n userAgent: config.userAgent,\n });\n}\n"],"mappings":";;AAOA,IAAa,eAAb,MAAa,aAAa;CAExB,OAAO,UAAU;EACf;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EAEA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;CACF;CAIA,OAAe,SAAyD,CAAC;CAMzE,OAAO,IAGL,KAGgE;EAChE,MAAM,eAAe,MAChB,2BAA2B,OAG5B,KAAA;EAEJ,OAAO,MACD,aAAa,OAAO,QAAQ,eAG9B,aAAa;CACnB;CAEA,OAAO,IACL,QACgB;EAChB,aAAa,MAAM;EAEnB,MAAM,SAAS,EAAE,GAAG,OAAO;EAC3B,KAAK,MAAM,UAAU,aAAa,SAAS;GACzC,aAAa,OAAO,UAAU,OAAO;GACrC,OAAO,OAAO;EAChB;EAEA,OAAO;CACT;CAEA,OAAO,QAAc;EACnB,aAAa,SAAS,CAAC;CACzB;AACF;;;;AAKA,SAAgB,oBACd,QACM;CACN,aAAa,IAAI;EACf,gBAAgB,OAAO;EACvB,UAAU,OAAO;EACjB,oBAAoB,OAAO;EAC3B,UAAU,OAAO;EACjB,WAAW,OAAO;CACpB,CAAC;AACH"}
|
|
@@ -9,22 +9,23 @@ import { isEmptyString, isNullOrUndefined, isString, isUndefined } from "@sindre
|
|
|
9
9
|
import parse from "github-url-from-git";
|
|
10
10
|
//#region lib/modules/datasource/metadata.ts
|
|
11
11
|
const githubPages = regEx("^https://([^.]+).github.com/([^/]+)$");
|
|
12
|
+
const gitPlusPrefix = regEx("^git\\+");
|
|
12
13
|
const gitPrefix = regEx("^git:/?/?");
|
|
13
14
|
function massageUrl(sourceUrl) {
|
|
14
|
-
const massagedUrl =
|
|
15
|
+
const massagedUrl = massageGitPrefixes(sourceUrl);
|
|
15
16
|
if (!parseUrl(massagedUrl)) return "";
|
|
16
17
|
if (detectPlatform(massagedUrl) === "gitlab") return massageGitlabUrl(sourceUrl);
|
|
17
18
|
return massageGithubUrl(sourceUrl);
|
|
18
19
|
}
|
|
19
20
|
function massageGithubUrl(url) {
|
|
20
|
-
return
|
|
21
|
+
return massageGitPrefixes(url).replace("http:", "https:").replace("http+git:", "https:").replace("https+git:", "https:").replace("ssh://git@", "https://").replace(gitPrefix, "https://").replace(githubPages, "https://github.com/$1/$2").replace("www.github.com", "github.com").split("/").slice(0, 5).join("/");
|
|
21
22
|
}
|
|
22
23
|
function massageGitlabUrl(url) {
|
|
23
|
-
return
|
|
24
|
+
return massageGitPrefixes(url).replace("http:", "https:").replace("ssh://git@", "https://").replace(gitPrefix, "https://").replace(regEx(/\/tree\/.*$/i), "").replace(regEx(/\/$/i), "").replace(regEx(/\.git$/i), "");
|
|
24
25
|
}
|
|
25
|
-
function
|
|
26
|
-
let massagedUrl = url;
|
|
27
|
-
if (
|
|
26
|
+
function massageGitPrefixes(url) {
|
|
27
|
+
let massagedUrl = url.replace(gitPlusPrefix, "");
|
|
28
|
+
if (massagedUrl.startsWith("git@")) massagedUrl = massagedUrl.replace(":", "/").replace("git@", "https://");
|
|
28
29
|
return massagedUrl;
|
|
29
30
|
}
|
|
30
31
|
function massageTimestamps(dep) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"metadata.js","names":[],"sources":["../../../lib/modules/datasource/metadata.ts"],"sourcesContent":["import {\n isEmptyString,\n isNullOrUndefined,\n isString,\n isUndefined,\n} from '@sindresorhus/is';\nimport parse from 'github-url-from-git';\nimport { detectPlatform } from '../../util/common.ts';\nimport { parseGitUrl } from '../../util/git/url.ts';\nimport * as hostRules from '../../util/host-rules.ts';\nimport { regEx } from '../../util/regex.ts';\nimport { asTimestamp } from '../../util/timestamp.ts';\nimport { isHttpUrl, parseUrl, trimTrailingSlash } from '../../util/url.ts';\nimport { manualChangelogUrls, manualSourceUrls } from './metadata-manual.ts';\nimport type { ReleaseResult } from './types.ts';\n\nconst githubPages = regEx('^https://([^.]+).github.com/([^/]+)$');\nconst gitPrefix = regEx('^git:/?/?');\n\nexport function massageUrl(sourceUrl: string): string {\n // Replace git@ sourceUrl with https so hostname can be parsed\n const massagedUrl =
|
|
1
|
+
{"version":3,"file":"metadata.js","names":[],"sources":["../../../lib/modules/datasource/metadata.ts"],"sourcesContent":["import {\n isEmptyString,\n isNullOrUndefined,\n isString,\n isUndefined,\n} from '@sindresorhus/is';\nimport parse from 'github-url-from-git';\nimport { detectPlatform } from '../../util/common.ts';\nimport { parseGitUrl } from '../../util/git/url.ts';\nimport * as hostRules from '../../util/host-rules.ts';\nimport { regEx } from '../../util/regex.ts';\nimport { asTimestamp } from '../../util/timestamp.ts';\nimport { isHttpUrl, parseUrl, trimTrailingSlash } from '../../util/url.ts';\nimport { manualChangelogUrls, manualSourceUrls } from './metadata-manual.ts';\nimport type { ReleaseResult } from './types.ts';\n\nconst githubPages = regEx('^https://([^.]+).github.com/([^/]+)$');\nconst gitPlusPrefix = regEx('^git\\\\+');\nconst gitPrefix = regEx('^git:/?/?');\n\nexport function massageUrl(sourceUrl: string): string {\n // Replace git@ sourceUrl with https so hostname can be parsed\n const massagedUrl = massageGitPrefixes(sourceUrl);\n\n // Check if URL is valid\n const parsedUrl = parseUrl(massagedUrl);\n if (!parsedUrl) {\n return '';\n }\n\n if (detectPlatform(massagedUrl) === 'gitlab') {\n return massageGitlabUrl(sourceUrl);\n }\n return massageGithubUrl(sourceUrl);\n}\n\nexport function massageGithubUrl(url: string): string {\n const massagedUrl = massageGitPrefixes(url);\n\n return massagedUrl\n .replace('http:', 'https:')\n .replace('http+git:', 'https:')\n .replace('https+git:', 'https:')\n .replace('ssh://git@', 'https://')\n .replace(gitPrefix, 'https://')\n .replace(githubPages, 'https://github.com/$1/$2')\n .replace('www.github.com', 'github.com')\n .split('/')\n .slice(0, 5)\n .join('/');\n}\n\nexport function massageGitlabUrl(url: string): string {\n const massagedUrl = massageGitPrefixes(url);\n\n return massagedUrl\n .replace('http:', 'https:')\n .replace('ssh://git@', 'https://')\n .replace(gitPrefix, 'https://')\n .replace(regEx(/\\/tree\\/.*$/i), '')\n .replace(regEx(/\\/$/i), '')\n .replace(regEx(/\\.git$/i), '');\n}\n\nfunction massageGitPrefixes(url: string): string {\n let massagedUrl = url.replace(gitPlusPrefix, '');\n\n if (massagedUrl.startsWith('git@')) {\n massagedUrl = massagedUrl.replace(':', '/').replace('git@', 'https://');\n }\n\n return massagedUrl;\n}\n\nfunction massageTimestamps(dep: ReleaseResult): void {\n for (const release of dep.releases || []) {\n let { releaseTimestamp } = release;\n delete release.releaseTimestamp;\n releaseTimestamp = asTimestamp(releaseTimestamp);\n if (releaseTimestamp) {\n release.releaseTimestamp = releaseTimestamp;\n }\n }\n}\n\nexport function addMetaData(\n dep: ReleaseResult,\n datasource: string,\n packageName: string,\n): void {\n massageTimestamps(dep);\n\n const packageNameLowercase = packageName.toLowerCase();\n const manualChangelogUrl =\n manualChangelogUrls[datasource]?.[packageNameLowercase];\n if (manualChangelogUrl) {\n dep.changelogUrl = manualChangelogUrl;\n }\n\n const manualSourceUrl = manualSourceUrls[datasource]?.[packageNameLowercase];\n if (manualSourceUrl) {\n dep.sourceUrl = manualSourceUrl;\n }\n\n if (dep.sourceUrl && !dep.sourceDirectory) {\n try {\n const parsed = parseGitUrl(dep.sourceUrl);\n if (parsed.filepathtype === 'tree' && parsed.filepath !== '') {\n dep.sourceUrl = parsed.toString();\n dep.sourceDirectory = parsed.filepath;\n }\n } catch {\n // ignore invalid urls\n }\n }\n\n if (\n !dep.sourceUrl &&\n dep.changelogUrl &&\n detectPlatform(dep.changelogUrl) === 'github'\n ) {\n dep.sourceUrl = dep.changelogUrl;\n }\n\n if (!dep.sourceUrl && dep.homepage) {\n const platform = detectPlatform(dep.homepage);\n if (platform === 'github' || platform === 'gitlab') {\n dep.sourceUrl = dep.homepage;\n }\n }\n const extraBaseUrls = [];\n // istanbul ignore next\n hostRules.hosts({ hostType: 'github' }).forEach((host) => {\n extraBaseUrls.push(host, `gist.${host}`);\n });\n extraBaseUrls.push('gitlab.com');\n if (dep.sourceUrl) {\n // try massaging it\n const massagedUrl = massageUrl(dep.sourceUrl);\n if (isEmptyString(massagedUrl)) {\n delete dep.sourceUrl;\n } else {\n // parse from github-url-from-git only supports Github URLs as its name implies\n dep.sourceUrl =\n parse(massagedUrl, {\n extraBaseUrls,\n }) || dep.sourceUrl;\n // prefer massaged URL to source URL if the latter does not start with http:// or https://\n // (e.g. git@somehost.com) and the detected platform is gitlab.\n // this allows to retrieve changelogs from git hosts other than Github\n if (\n !isHttpUrl(dep.sourceUrl) &&\n detectPlatform(massagedUrl) === 'gitlab'\n ) {\n dep.sourceUrl = massagedUrl;\n }\n }\n }\n if (shouldDeleteHomepage(dep.sourceUrl, dep.homepage)) {\n delete dep.homepage;\n }\n // Clean up any empty urls\n const urlKeys: (keyof ReleaseResult)[] = [\n 'homepage',\n 'sourceUrl',\n 'changelogUrl',\n 'dependencyUrl',\n ];\n for (const urlKey of urlKeys) {\n const urlVal = dep[urlKey];\n if (isString(urlVal) && isHttpUrl(urlVal.trim())) {\n dep[urlKey] = urlVal.trim() as never;\n } else {\n delete dep[urlKey];\n }\n }\n}\n\n/**\n * Returns true if\n * 1. it's a github or gitlab url and not a path within the repo.\n * 2. it's equal to sourceURl\n * @param sourceUrl\n * @param homepage\n */\nexport function shouldDeleteHomepage(\n sourceUrl: string | null | undefined,\n homepage: string | undefined,\n): boolean {\n if (isNullOrUndefined(sourceUrl) || isUndefined(homepage)) {\n return false;\n }\n const massagedSourceUrl = massageUrl(sourceUrl);\n const platform = detectPlatform(homepage);\n if (platform === 'github' || platform === 'gitlab') {\n const sourceUrlParsed = parseUrl(massagedSourceUrl);\n if (isNullOrUndefined(sourceUrlParsed)) {\n return false;\n }\n const homepageParsed = parseUrl(homepage);\n return (\n homepageParsed !== null &&\n trimTrailingSlash(homepageParsed.pathname) ===\n trimTrailingSlash(sourceUrlParsed.pathname)\n );\n }\n return massagedSourceUrl === homepage;\n}\n"],"mappings":"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"}
|
|
@@ -2,10 +2,10 @@ import { logger } from "../../../../logger/index.js";
|
|
|
2
2
|
import { toSha256 } from "../../../../util/hash.js";
|
|
3
3
|
import { cachePathExists, createCacheReadStream, createCacheWriteStream, ensureCacheDir, pipeline, renameCacheFile, rmCache, statCacheFile } from "../../../../util/fs/index.js";
|
|
4
4
|
import { acquireLock } from "../../../../util/mutex.js";
|
|
5
|
+
import { createDecompressStream } from "../../../../util/compress.js";
|
|
5
6
|
import { isNullOrUndefined } from "@sindresorhus/is";
|
|
6
7
|
import { randomUUID } from "node:crypto";
|
|
7
8
|
import upath from "upath";
|
|
8
|
-
import { createGunzip } from "node:zlib";
|
|
9
9
|
//#region lib/modules/datasource/rpm/providers/common.ts
|
|
10
10
|
const cacheSubDir = "rpm";
|
|
11
11
|
function formatRpmVersion(ver, rel) {
|
|
@@ -53,7 +53,20 @@ async function downloadFileToCache(url, cachePath, http, lastDownloadTimestamp)
|
|
|
53
53
|
return true;
|
|
54
54
|
}
|
|
55
55
|
async function decompressFile(compressedFile, decompressedFile) {
|
|
56
|
-
|
|
56
|
+
const readStream = createCacheReadStream(compressedFile);
|
|
57
|
+
const decompressStream = await createDecompressStream(readStream);
|
|
58
|
+
if (decompressStream === readStream) {
|
|
59
|
+
readStream.destroy();
|
|
60
|
+
await renameCacheFile(compressedFile, decompressedFile);
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
const tempFile = `${decompressedFile}.${randomUUID()}.tmp`;
|
|
64
|
+
try {
|
|
65
|
+
await pipeline(decompressStream, createCacheWriteStream(tempFile));
|
|
66
|
+
await renameCacheFile(tempFile, decompressedFile);
|
|
67
|
+
} finally {
|
|
68
|
+
await rmCache(tempFile);
|
|
69
|
+
}
|
|
57
70
|
}
|
|
58
71
|
async function getCachedDecompressedFile(http, url, extension) {
|
|
59
72
|
const releaseLock = await acquireLock(`decompressed-file:${url}:${extension}`, "datasource-rpm");
|
|
@@ -63,11 +76,9 @@ async function getCachedDecompressedFile(http, url, extension) {
|
|
|
63
76
|
const decompressedFile = upath.join(cacheDir, `${urlHash}.${extension}`);
|
|
64
77
|
let lastTimestamp = await getFileCreationTime(decompressedFile);
|
|
65
78
|
const compressedFile = upath.join(cacheDir, `${randomUUID()}_${urlHash}.gz`);
|
|
66
|
-
const decompressedTempFile = upath.join(cacheDir, `${randomUUID()}_${urlHash}.${extension}`);
|
|
67
79
|
try {
|
|
68
80
|
if (await downloadFileToCache(url, compressedFile, http, lastTimestamp) || !lastTimestamp) try {
|
|
69
|
-
await decompressFile(compressedFile,
|
|
70
|
-
await renameCacheFile(decompressedTempFile, decompressedFile);
|
|
81
|
+
await decompressFile(compressedFile, decompressedFile);
|
|
71
82
|
lastTimestamp = await getFileCreationTime(decompressedFile);
|
|
72
83
|
} catch (err) {
|
|
73
84
|
logger.warn({
|
|
@@ -82,7 +93,6 @@ async function getCachedDecompressedFile(http, url, extension) {
|
|
|
82
93
|
return decompressedFile;
|
|
83
94
|
} finally {
|
|
84
95
|
if (await cachePathExists(compressedFile)) await rmCache(compressedFile);
|
|
85
|
-
if (await cachePathExists(decompressedTempFile)) await rmCache(decompressedTempFile);
|
|
86
96
|
}
|
|
87
97
|
} finally {
|
|
88
98
|
releaseLock();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"common.js","names":["fs.statCacheFile","fs.createCacheWriteStream","fs.pipeline","fs.createCacheReadStream","fs.
|
|
1
|
+
{"version":3,"file":"common.js","names":["fs.statCacheFile","fs.createCacheWriteStream","fs.pipeline","fs.createCacheReadStream","fs.renameCacheFile","fs.rmCache","fs.ensureCacheDir","fs.cachePathExists"],"sources":["../../../../../lib/modules/datasource/rpm/providers/common.ts"],"sourcesContent":["import { randomUUID } from 'node:crypto';\nimport { isNullOrUndefined } from '@sindresorhus/is';\nimport upath from 'upath';\nimport { logger } from '../../../../logger/index.ts';\nimport { createDecompressStream } from '../../../../util/compress.ts';\nimport * as fs from '../../../../util/fs/index.ts';\nimport { toSha256 } from '../../../../util/hash.ts';\nimport type { Http, HttpOptions } from '../../../../util/http/index.ts';\nimport { acquireLock } from '../../../../util/mutex.ts';\nimport type { ReleaseResult } from '../../types.ts';\nimport { datasource } from '../common.ts';\n\nconst cacheSubDir = datasource;\n\ntype RpmVersionValue = boolean | number | string | null | undefined;\n\nexport function formatRpmVersion(\n ver: RpmVersionValue,\n rel?: RpmVersionValue,\n): string | null {\n if (isNullOrUndefined(ver)) {\n return null;\n }\n\n const version = String(ver);\n\n if (isNullOrUndefined(rel)) {\n return version;\n }\n\n return `${version}-${String(rel)}`;\n}\n\nexport function buildReleaseResult(\n versions: Iterable<string>,\n): ReleaseResult | null {\n const uniqueVersions = [...new Set(versions)];\n\n if (uniqueVersions.length === 0) {\n return null;\n }\n\n return {\n releases: uniqueVersions.map((version) => ({ version })),\n };\n}\n\nasync function getFileCreationTime(\n filePath: string,\n): Promise<Date | undefined> {\n const stats = await fs.statCacheFile(filePath);\n return stats?.ctime;\n}\n\nasync function checkIfModified(\n url: string,\n lastDownloadTimestamp: Date,\n http: Http,\n): Promise<boolean> {\n const options: HttpOptions = {\n headers: {\n 'If-Modified-Since': lastDownloadTimestamp.toUTCString(),\n },\n };\n\n try {\n const response = await http.head(url, options);\n return response.statusCode !== 304;\n } catch (err) {\n logger.warn(\n {\n err,\n lastDownloadTimestamp,\n url,\n },\n 'Could not determine if metadata file is modified since last download',\n );\n return true;\n }\n}\n\nasync function downloadFileToCache(\n url: string,\n cachePath: string,\n http: Http,\n lastDownloadTimestamp?: Date,\n): Promise<boolean> {\n let needsToDownload = true;\n\n if (lastDownloadTimestamp) {\n needsToDownload = await checkIfModified(url, lastDownloadTimestamp, http);\n }\n\n if (!needsToDownload) {\n logger.debug(`No need to download ${url}, file is up to date.`);\n return false;\n }\n\n const readStream = http.stream(url);\n const writeStream = fs.createCacheWriteStream(cachePath);\n await fs.pipeline(readStream, writeStream);\n\n const compressedStats = await fs.statCacheFile(cachePath);\n if (!compressedStats || compressedStats.size === 0) {\n logger.debug(`Empty response body from getting ${url}.`);\n throw new Error(`Empty response body from getting ${url}.`);\n }\n\n return true;\n}\n\nasync function decompressFile(\n compressedFile: string,\n decompressedFile: string,\n): Promise<void> {\n const readStream = fs.createCacheReadStream(compressedFile);\n const decompressStream = await createDecompressStream(readStream);\n\n if (decompressStream === readStream) {\n // The file is not compressed: rename it into place instead of copying it\n readStream.destroy();\n await fs.renameCacheFile(compressedFile, decompressedFile);\n return;\n }\n\n const tempFile = `${decompressedFile}.${randomUUID()}.tmp`;\n\n try {\n await fs.pipeline(decompressStream, fs.createCacheWriteStream(tempFile));\n // Only replace the shared cache file after a successful decompress.\n await fs.renameCacheFile(tempFile, decompressedFile);\n } finally {\n await fs.rmCache(tempFile);\n }\n}\n\nexport async function getCachedDecompressedFile(\n http: Http,\n url: string,\n extension: 'xml',\n): Promise<string> {\n const releaseLock = await acquireLock(\n `decompressed-file:${url}:${extension}`,\n 'datasource-rpm',\n );\n\n try {\n const cacheDir = await fs.ensureCacheDir(cacheSubDir);\n const urlHash = toSha256(url);\n const decompressedFile = upath.join(cacheDir, `${urlHash}.${extension}`);\n let lastTimestamp = await getFileCreationTime(decompressedFile);\n\n const compressedFile = upath.join(\n cacheDir,\n `${randomUUID()}_${urlHash}.gz`,\n );\n\n try {\n const wasUpdated = await downloadFileToCache(\n url,\n compressedFile,\n http,\n lastTimestamp,\n );\n\n if (wasUpdated || !lastTimestamp) {\n try {\n await decompressFile(compressedFile, decompressedFile);\n lastTimestamp = await getFileCreationTime(decompressedFile);\n } catch (err) {\n logger.warn(\n {\n compressedFile,\n err,\n extension,\n decompressedFile,\n url,\n },\n 'Failed to extract RPM metadata file from compressed file',\n );\n }\n }\n\n if (!lastTimestamp) {\n throw new Error('Missing metadata in extracted RPM metadata file!');\n }\n\n return decompressedFile;\n } finally {\n if (await fs.cachePathExists(compressedFile)) {\n await fs.rmCache(compressedFile);\n }\n }\n } finally {\n releaseLock();\n }\n}\n"],"mappings":"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"}
|
|
@@ -2,7 +2,7 @@ import { coerceArray, deduplicateArray, isNotNullOrUndefined } from "../../../..
|
|
|
2
2
|
import { logger } from "../../../../logger/index.js";
|
|
3
3
|
import { buildCacheKey } from "../../../../util/cache/package/key.js";
|
|
4
4
|
import { hashStream } from "../../../../util/hash.js";
|
|
5
|
-
import { createCacheWriteStream, ensureCacheDir, pipeline, rmCache } from "../../../../util/fs/index.js";
|
|
5
|
+
import { createCacheWriteStream, ensureCacheDir, pipeline as pipeline$1, rmCache } from "../../../../util/fs/index.js";
|
|
6
6
|
import { withCache } from "../../../../util/cache/package/with-cache.js";
|
|
7
7
|
import { Http } from "../../../../util/http/index.js";
|
|
8
8
|
import { map } from "../../../../util/promises.js";
|
|
@@ -82,7 +82,7 @@ var TerraformProviderHash = class TerraformProviderHash {
|
|
|
82
82
|
const readStream = TerraformProviderHash.http.stream(build.url);
|
|
83
83
|
const writeStream = createCacheWriteStream(downloadFileName);
|
|
84
84
|
try {
|
|
85
|
-
await pipeline(readStream, writeStream);
|
|
85
|
+
await pipeline$1(readStream, writeStream);
|
|
86
86
|
const hash = await this.hashOfZipContent(downloadFileName);
|
|
87
87
|
logger.debug(`Hash generation for ${build.url} took ${Date.now() - startTime}ms for ${build.name}-${build.version}`);
|
|
88
88
|
return hash;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hash.js","names":["fs.createCacheWriteStream","fs.pipeline","fs.rmCache","fs.ensureCacheDir","p.map"],"sources":["../../../../../lib/modules/manager/terraform/lockfile/hash.ts"],"sourcesContent":["import crypto from 'node:crypto';\nimport { once } from 'node:events';\nimport { Transform, type TransformCallback } from 'node:stream';\nimport { crc32 } from 'node:zlib';\nimport upath from 'upath';\nimport { openPromise, validateFileName } from 'yauzl';\nimport { logger } from '../../../../logger/index.ts';\nimport {\n coerceArray,\n deduplicateArray,\n isNotNullOrUndefined,\n} from '../../../../util/array.ts';\nimport { buildCacheKey } from '../../../../util/cache/package/key.ts';\nimport { withCache } from '../../../../util/cache/package/with-cache.ts';\nimport * as fs from '../../../../util/fs/index.ts';\nimport { hashStream } from '../../../../util/hash.ts';\nimport { Http } from '../../../../util/http/index.ts';\nimport * as p from '../../../../util/promises.ts';\nimport { TerraformProviderDatasource } from '../../../datasource/terraform-provider/index.ts';\nimport type { TerraformBuild } from '../../../datasource/terraform-provider/schema.ts';\n\nclass Crc32Stream extends Transform {\n checksum = 0;\n\n override _transform(\n chunk: Buffer,\n _encoding: BufferEncoding,\n callback: TransformCallback,\n ): void {\n this.checksum = crc32(chunk, this.checksum);\n callback(null, chunk);\n }\n}\n\nexport class TerraformProviderHash {\n static http = new Http(TerraformProviderDatasource.id);\n\n static terraformDatasource = new TerraformProviderDatasource();\n\n static hashCacheTTL = 10080; // in minutes == 1 week\n\n /**\n * Computes the `h1:` checksum used in Terraform dependency lock files.\n *\n * Terraform verifies extracted providers with Go's `HashDir`, which ignores\n * ZIP directory entries. Ignore them here so the archive produces the same\n * checksum as the extracted provider.\n *\n * See https://github.com/golang/go/issues/53448.\n */\n static async hashOfZipContent(zipFilePath: string): Promise<string> {\n const zipFile = await openPromise(zipFilePath, {\n autoClose: false,\n decodeStrings: false,\n });\n const entryHashes: { path: Buffer; hash: string }[] = [];\n const entryPaths = new Set<string>();\n\n try {\n for await (const entry of zipFile.eachEntry()) {\n // Go's ZIP reader preserves the central-directory name bytes instead of decoding CP437 or Unicode path fields.\n const fileName = entry.fileNameRaw\n .toString('latin1')\n .replaceAll('\\\\', '/');\n\n // Terraform verifies extracted packages with Go HashDir semantics, which omit directory records.\n if (fileName.endsWith('/')) {\n continue;\n }\n if (fileName.includes('\\n')) {\n throw new Error('ZIP entry name contains a newline');\n }\n const fileNameError = validateFileName(fileName);\n if (fileNameError) {\n throw new Error(fileNameError);\n }\n const normalizedPath = upath.normalize(fileName);\n if (entryPaths.has(normalizedPath)) {\n throw new Error(`Duplicate ZIP entry path: ${normalizedPath}`);\n }\n entryPaths.add(normalizedPath);\n const path = Buffer.from(normalizedPath, 'latin1');\n\n const entryStream = await zipFile.openReadStreamPromise(entry);\n const crc32Stream = new Crc32Stream();\n const hash = await hashStream(\n entryStream.compose(crc32Stream),\n 'sha256',\n );\n if (crc32Stream.checksum !== entry.crc32) {\n throw new Error(\n `CRC-32 mismatch for ZIP entry ${entry.fileNameRaw.toString('utf8')}`,\n );\n }\n entryHashes.push({ path, hash });\n }\n } finally {\n const closePromise = once(zipFile, 'close');\n zipFile.close();\n await closePromise;\n }\n\n entryHashes.sort((left, right) => Buffer.compare(left.path, right.path));\n\n const rootHash = crypto.createHash('sha256');\n for (const entry of entryHashes) {\n rootHash.update(`${entry.hash} `);\n rootHash.update(entry.path);\n rootHash.update('\\n');\n }\n\n return rootHash.digest('base64');\n }\n\n private static async _calculateSingleHash(\n build: TerraformBuild,\n cacheDir: string,\n ): Promise<string> {\n const downloadFileName = upath.join(cacheDir, crypto.randomUUID());\n logger.trace(\n `Downloading archive and generating hash for ${build.name}-${build.version}...`,\n );\n const startTime = Date.now();\n const readStream = TerraformProviderHash.http.stream(build.url);\n const writeStream = fs.createCacheWriteStream(downloadFileName);\n\n try {\n await fs.pipeline(readStream, writeStream);\n\n const hash = await this.hashOfZipContent(downloadFileName);\n logger.debug(\n `Hash generation for ${build.url} took ${Date.now() - startTime}ms for ${build.name}-${build.version}`,\n );\n return hash;\n } finally {\n await fs.rmCache(downloadFileName);\n }\n }\n\n static calculateSingleHash(\n build: TerraformBuild,\n cacheDir: string,\n ): Promise<string> {\n return withCache(\n {\n namespace: `terraform-provider-hash`,\n key: buildCacheKey('calculateSingleHash', build.url),\n ttlMinutes: TerraformProviderHash.hashCacheTTL,\n },\n () => TerraformProviderHash._calculateSingleHash(build, cacheDir),\n );\n }\n\n static async calculateHashScheme1Hashes(\n builds: TerraformBuild[],\n ): Promise<string[]> {\n logger.debug(`Calculating hashes for ${builds.length} builds`);\n const cacheDir = await fs.ensureCacheDir('terraform');\n\n return p.map(builds, (build) => this.calculateSingleHash(build, cacheDir), {\n concurrency: 4,\n });\n }\n\n static async createHashes(\n registryURL: string,\n repository: string,\n version: string,\n ): Promise<string[] | null> {\n logger.debug(\n `Creating hashes for ${repository}@${version} (${registryURL})`,\n );\n\n if (\n registryURL === TerraformProviderDatasource.openTofuRegistryUrl ||\n registryURL === TerraformProviderDatasource.openTofuApiUrl\n ) {\n const packagesHashes =\n await TerraformProviderHash.terraformDatasource.getProviderPackages(\n repository,\n version,\n );\n if (packagesHashes?.length) {\n logger.debug(\n `Using OpenTofu packages API for ${repository}@${version}`,\n );\n // hashes are a logical set which Terraform deduplicates and sorts\n return deduplicateArray(packagesHashes).sort();\n }\n logger.debug(\n `OpenTofu packages field unavailable for ${repository}@${version}, falling back to zip download`,\n );\n }\n\n const builds = await TerraformProviderHash.terraformDatasource.getBuilds(\n registryURL,\n repository,\n version,\n );\n if (!builds) {\n return null;\n }\n\n // check if the publisher uses one shasum file for all builds or separate ones\n // we deduplicate to reduce the number of API calls\n const shaUrls = deduplicateArray(\n builds.map((build) => build.shasums_url).filter(isNotNullOrUndefined),\n );\n\n logger.debug(\n `Getting zip hashes for ${shaUrls.length} shasum URL(s) for ${repository}@${version}`,\n );\n\n const zhHashes: string[] = [];\n for (const shaUrl of shaUrls) {\n const hashes =\n await TerraformProviderHash.terraformDatasource.getZipHashes(shaUrl);\n\n zhHashes.push(...coerceArray(hashes));\n }\n\n logger.debug(\n `Got ${zhHashes.length} zip hashes for ${repository}@${version}`,\n );\n\n const h1Hashes =\n await TerraformProviderHash.calculateHashScheme1Hashes(builds);\n\n const hashes = [];\n hashes.push(...h1Hashes.map((hash) => `h1:${hash}`));\n hashes.push(...zhHashes.map((hash) => `zh:${hash}`));\n\n // hashes are a logical set which Terraform deduplicates and sorts\n return deduplicateArray(hashes).sort();\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"hash.js","names":["fs.createCacheWriteStream","fs.pipeline","fs.rmCache","fs.ensureCacheDir","p.map"],"sources":["../../../../../lib/modules/manager/terraform/lockfile/hash.ts"],"sourcesContent":["import crypto from 'node:crypto';\nimport { once } from 'node:events';\nimport { Transform, type TransformCallback } from 'node:stream';\nimport { crc32 } from 'node:zlib';\nimport upath from 'upath';\nimport { openPromise, validateFileName } from 'yauzl';\nimport { logger } from '../../../../logger/index.ts';\nimport {\n coerceArray,\n deduplicateArray,\n isNotNullOrUndefined,\n} from '../../../../util/array.ts';\nimport { buildCacheKey } from '../../../../util/cache/package/key.ts';\nimport { withCache } from '../../../../util/cache/package/with-cache.ts';\nimport * as fs from '../../../../util/fs/index.ts';\nimport { hashStream } from '../../../../util/hash.ts';\nimport { Http } from '../../../../util/http/index.ts';\nimport * as p from '../../../../util/promises.ts';\nimport { TerraformProviderDatasource } from '../../../datasource/terraform-provider/index.ts';\nimport type { TerraformBuild } from '../../../datasource/terraform-provider/schema.ts';\n\nclass Crc32Stream extends Transform {\n checksum = 0;\n\n override _transform(\n chunk: Buffer,\n _encoding: BufferEncoding,\n callback: TransformCallback,\n ): void {\n this.checksum = crc32(chunk, this.checksum);\n callback(null, chunk);\n }\n}\n\nexport class TerraformProviderHash {\n static http = new Http(TerraformProviderDatasource.id);\n\n static terraformDatasource = new TerraformProviderDatasource();\n\n static hashCacheTTL = 10080; // in minutes == 1 week\n\n /**\n * Computes the `h1:` checksum used in Terraform dependency lock files.\n *\n * Terraform verifies extracted providers with Go's `HashDir`, which ignores\n * ZIP directory entries. Ignore them here so the archive produces the same\n * checksum as the extracted provider.\n *\n * See https://github.com/golang/go/issues/53448.\n */\n static async hashOfZipContent(zipFilePath: string): Promise<string> {\n const zipFile = await openPromise(zipFilePath, {\n autoClose: false,\n decodeStrings: false,\n });\n const entryHashes: { path: Buffer; hash: string }[] = [];\n const entryPaths = new Set<string>();\n\n try {\n for await (const entry of zipFile.eachEntry()) {\n // Go's ZIP reader preserves the central-directory name bytes instead of decoding CP437 or Unicode path fields.\n const fileName = entry.fileNameRaw\n .toString('latin1')\n .replaceAll('\\\\', '/');\n\n // Terraform verifies extracted packages with Go HashDir semantics, which omit directory records.\n if (fileName.endsWith('/')) {\n continue;\n }\n if (fileName.includes('\\n')) {\n throw new Error('ZIP entry name contains a newline');\n }\n const fileNameError = validateFileName(fileName);\n if (fileNameError) {\n throw new Error(fileNameError);\n }\n const normalizedPath = upath.normalize(fileName);\n if (entryPaths.has(normalizedPath)) {\n throw new Error(`Duplicate ZIP entry path: ${normalizedPath}`);\n }\n entryPaths.add(normalizedPath);\n const path = Buffer.from(normalizedPath, 'latin1');\n\n const entryStream = await zipFile.openReadStreamPromise(entry);\n const crc32Stream = new Crc32Stream();\n const hash = await hashStream(\n entryStream.compose(crc32Stream),\n 'sha256',\n );\n if (crc32Stream.checksum !== entry.crc32) {\n throw new Error(\n `CRC-32 mismatch for ZIP entry ${entry.fileNameRaw.toString('utf8')}`,\n );\n }\n entryHashes.push({ path, hash });\n }\n } finally {\n const closePromise = once(zipFile, 'close');\n zipFile.close();\n await closePromise;\n }\n\n entryHashes.sort((left, right) => Buffer.compare(left.path, right.path));\n\n const rootHash = crypto.createHash('sha256');\n for (const entry of entryHashes) {\n rootHash.update(`${entry.hash} `);\n rootHash.update(entry.path);\n rootHash.update('\\n');\n }\n\n return rootHash.digest('base64');\n }\n\n private static async _calculateSingleHash(\n build: TerraformBuild,\n cacheDir: string,\n ): Promise<string> {\n const downloadFileName = upath.join(cacheDir, crypto.randomUUID());\n logger.trace(\n `Downloading archive and generating hash for ${build.name}-${build.version}...`,\n );\n const startTime = Date.now();\n const readStream = TerraformProviderHash.http.stream(build.url);\n const writeStream = fs.createCacheWriteStream(downloadFileName);\n\n try {\n await fs.pipeline(readStream, writeStream);\n\n const hash = await this.hashOfZipContent(downloadFileName);\n logger.debug(\n `Hash generation for ${build.url} took ${Date.now() - startTime}ms for ${build.name}-${build.version}`,\n );\n return hash;\n } finally {\n await fs.rmCache(downloadFileName);\n }\n }\n\n static calculateSingleHash(\n build: TerraformBuild,\n cacheDir: string,\n ): Promise<string> {\n return withCache(\n {\n namespace: `terraform-provider-hash`,\n key: buildCacheKey('calculateSingleHash', build.url),\n ttlMinutes: TerraformProviderHash.hashCacheTTL,\n },\n () => TerraformProviderHash._calculateSingleHash(build, cacheDir),\n );\n }\n\n static async calculateHashScheme1Hashes(\n builds: TerraformBuild[],\n ): Promise<string[]> {\n logger.debug(`Calculating hashes for ${builds.length} builds`);\n const cacheDir = await fs.ensureCacheDir('terraform');\n\n return p.map(builds, (build) => this.calculateSingleHash(build, cacheDir), {\n concurrency: 4,\n });\n }\n\n static async createHashes(\n registryURL: string,\n repository: string,\n version: string,\n ): Promise<string[] | null> {\n logger.debug(\n `Creating hashes for ${repository}@${version} (${registryURL})`,\n );\n\n if (\n registryURL === TerraformProviderDatasource.openTofuRegistryUrl ||\n registryURL === TerraformProviderDatasource.openTofuApiUrl\n ) {\n const packagesHashes =\n await TerraformProviderHash.terraformDatasource.getProviderPackages(\n repository,\n version,\n );\n if (packagesHashes?.length) {\n logger.debug(\n `Using OpenTofu packages API for ${repository}@${version}`,\n );\n // hashes are a logical set which Terraform deduplicates and sorts\n return deduplicateArray(packagesHashes).sort();\n }\n logger.debug(\n `OpenTofu packages field unavailable for ${repository}@${version}, falling back to zip download`,\n );\n }\n\n const builds = await TerraformProviderHash.terraformDatasource.getBuilds(\n registryURL,\n repository,\n version,\n );\n if (!builds) {\n return null;\n }\n\n // check if the publisher uses one shasum file for all builds or separate ones\n // we deduplicate to reduce the number of API calls\n const shaUrls = deduplicateArray(\n builds.map((build) => build.shasums_url).filter(isNotNullOrUndefined),\n );\n\n logger.debug(\n `Getting zip hashes for ${shaUrls.length} shasum URL(s) for ${repository}@${version}`,\n );\n\n const zhHashes: string[] = [];\n for (const shaUrl of shaUrls) {\n const hashes =\n await TerraformProviderHash.terraformDatasource.getZipHashes(shaUrl);\n\n zhHashes.push(...coerceArray(hashes));\n }\n\n logger.debug(\n `Got ${zhHashes.length} zip hashes for ${repository}@${version}`,\n );\n\n const h1Hashes =\n await TerraformProviderHash.calculateHashScheme1Hashes(builds);\n\n const hashes = [];\n hashes.push(...h1Hashes.map((hash) => `h1:${hash}`));\n hashes.push(...zhHashes.map((hash) => `zh:${hash}`));\n\n // hashes are a logical set which Terraform deduplicates and sorts\n return deduplicateArray(hashes).sort();\n }\n}\n"],"mappings":"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"}
|
|
@@ -88,6 +88,10 @@ let config;
|
|
|
88
88
|
let platformConfig;
|
|
89
89
|
const defaultGithubApiUrl = "https://api.github.com/";
|
|
90
90
|
const GitHubMaxPrBodyLen = 58e3;
|
|
91
|
+
const noteAlertRegex = regEx(/> ℹ️? \*\*Note\*\*\n> ?\n/g);
|
|
92
|
+
const warningAlertRegex = regEx(/> ⚠️? \*\*Warning\*\*\n> ?\n/g);
|
|
93
|
+
const cautionAlertRegex = regEx(/> 🛑 \*\*Caution\*\*\n> ?\n/g);
|
|
94
|
+
const importantAlertRegex = regEx(/> ❗ \*\*Important\*\*\n> ?\n/g);
|
|
91
95
|
function resetConfigs() {
|
|
92
96
|
config = {};
|
|
93
97
|
platformConfig = { host: {
|
|
@@ -1448,8 +1452,8 @@ async function directMergePr(prNo, strategy) {
|
|
|
1448
1452
|
}
|
|
1449
1453
|
function massageMarkdown(input) {
|
|
1450
1454
|
if (platformConfig.host.type !== "github") return smartTruncate(input, maxBodyLength());
|
|
1451
|
-
const
|
|
1452
|
-
return smartTruncate(
|
|
1455
|
+
const linkifiedInput = massageMarkdownLinks(input).replace(regEx(/href="https?:\/\/github.com\//g), "href=\"https://redirect.github.com/").replace(regEx(/]\(https:\/\/github\.com\//g), "](https://redirect.github.com/").replace(regEx(/]: https:\/\/github\.com\//g), "]: https://redirect.github.com/");
|
|
1456
|
+
return smartTruncate(linkifiedInput, maxBodyLength()).replaceAll(noteAlertRegex, "> [!NOTE]\n").replaceAll(warningAlertRegex, "> [!WARNING]\n").replaceAll(cautionAlertRegex, "> [!CAUTION]\n").replaceAll(importantAlertRegex, "> [!IMPORTANT]\n");
|
|
1453
1457
|
}
|
|
1454
1458
|
function maxBodyLength() {
|
|
1455
1459
|
return GitHubMaxPrBodyLen;
|