Files
renovate/lib/util/s3.ts
RahulGautamSingh c6578a476b feat(datasource/helm): support aws s3 as helm charts repository (#45584)
* support AWS S3 as a chart repository

* support creds via hostRules

* apply suggestions

* fix(datasource/helm): classify s3 lookup errors

* test: use await expect().resolves
2026-09-07 14:04:08 +00:00

58 lines
1.6 KiB
TypeScript

// Singleton S3 instance initialized on-demand.
import type { S3ClientConfig } from '@aws-sdk/client-s3';
import { S3Client } from '@aws-sdk/client-s3';
import { isString, isUndefined } from '@sindresorhus/is';
import { GlobalConfig } from '../config/global.ts';
import { parseUrl } from './url.ts';
let s3Instance: S3Client | undefined;
export function getS3Client(
// Only needed if GlobalConfig is not initialized due to some error
s3Endpoint?: string,
s3PathStyle?: boolean,
credentials?: S3ClientConfig['credentials'],
): S3Client {
// Credentials come from host rules, so such clients must not be shared
if (credentials) {
return newS3Client(s3Endpoint, s3PathStyle, credentials);
}
s3Instance ??= newS3Client(s3Endpoint, s3PathStyle);
return s3Instance;
}
function newS3Client(
s3Endpoint: string | undefined,
s3PathStyle: boolean | undefined,
credentials?: S3ClientConfig['credentials'],
): S3Client {
const endpoint = s3Endpoint ?? GlobalConfig.get('s3Endpoint');
const forcePathStyle = isUndefined(s3PathStyle)
? !!GlobalConfig.get('s3PathStyle')
: s3PathStyle;
return new S3Client({
...(endpoint && { endpoint }),
...(forcePathStyle && { forcePathStyle: true }),
...(credentials && { credentials }),
});
}
export interface S3UrlParts {
Bucket: string;
Key: string;
}
export function parseS3Url(rawUrl: URL | string): S3UrlParts | null {
const parsedUrl = isString(rawUrl) ? parseUrl(rawUrl) : rawUrl;
if (parsedUrl === null) {
return null;
}
if (parsedUrl.protocol !== 's3:') {
return null;
}
return {
Bucket: parsedUrl.host,
Key: parsedUrl.pathname.substring(1),
};
}