@rushstack/rush-amazon-s3-build-cache-plugin
Advanced tools
Comparing version 5.62.0-pr3059 to 5.62.0
@@ -0,2 +1,6 @@ | ||
/// <reference types="node" /> | ||
import * as fetch from 'node-fetch'; | ||
import type { IRushPlugin } from '@rushstack/rush-sdk'; | ||
import { ITerminal } from '@rushstack/node-core-library'; | ||
import type { RushConfiguration } from '@rushstack/rush-sdk'; | ||
@@ -6,4 +10,101 @@ import type { RushSession } from '@rushstack/rush-sdk'; | ||
/** | ||
* A helper for reading and updating objects on Amazon S3 | ||
* | ||
* @public | ||
*/ | ||
export declare class AmazonS3Client { | ||
private readonly _credentials; | ||
private readonly _s3Endpoint; | ||
private readonly _s3Region; | ||
private readonly _webClient; | ||
private readonly _terminal; | ||
constructor(credentials: IAmazonS3Credentials | undefined, options: IAmazonS3BuildCacheProviderOptionsAdvanced, webClient: WebClient, terminal: ITerminal); | ||
static UriEncode(input: string): string; | ||
static tryDeserializeCredentials(credentialString: string | undefined): IAmazonS3Credentials | undefined; | ||
getObjectAsync(objectName: string): Promise<Buffer | undefined>; | ||
uploadObjectAsync(objectName: string, objectBuffer: Buffer): Promise<void>; | ||
private _writeDebugLine; | ||
private _makeRequestAsync; | ||
_getSha256Hmac(key: string | Buffer, data: string): Buffer; | ||
_getSha256Hmac(key: string | Buffer, data: string, encoding: 'hex'): string; | ||
private _getSha256; | ||
private _getIsoDateString; | ||
private _safeReadResponseText; | ||
private _throwS3Error; | ||
/** | ||
* Validates a S3 endpoint which is http(s):// + hostname + port. Hostname validated according to RFC 1123 | ||
* {@link https://docs.aws.amazon.com/general/latest/gr/s3.html} | ||
*/ | ||
private _validateEndpoint; | ||
} | ||
/** | ||
* Advanced options where user has the specify the full http endpoint | ||
* @public | ||
*/ | ||
export declare interface IAmazonS3BuildCacheProviderOptionsAdvanced extends IAmazonS3BuildCacheProviderOptionsBase { | ||
s3Endpoint: string; | ||
} | ||
/** | ||
* @public | ||
*/ | ||
export declare interface IAmazonS3BuildCacheProviderOptionsBase { | ||
s3Region: string; | ||
s3Prefix: string | undefined; | ||
isCacheWriteAllowed: boolean; | ||
} | ||
/** | ||
* Simple options where user only provides the bucket and the endpoint is automatically built | ||
* @public | ||
*/ | ||
export declare interface IAmazonS3BuildCacheProviderOptionsSimple extends IAmazonS3BuildCacheProviderOptionsBase { | ||
s3Bucket: string; | ||
} | ||
/** | ||
* Credentials for authorizing and signing requests to an Amazon S3 endpoint. | ||
* | ||
* @public | ||
*/ | ||
export declare interface IAmazonS3Credentials { | ||
accessKeyId: string; | ||
secretAccessKey: string; | ||
sessionToken: string | undefined; | ||
} | ||
/** | ||
* For use with {@link WebClient}. | ||
* | ||
* @public | ||
*/ | ||
export declare interface IGetFetchOptions extends IWebFetchOptionsBase { | ||
verb: 'GET' | never; | ||
} | ||
/** | ||
* For use with {@link WebClient}. | ||
* | ||
* @public | ||
*/ | ||
export declare interface IPutFetchOptions extends IWebFetchOptionsBase { | ||
verb: 'PUT'; | ||
body?: Buffer; | ||
} | ||
/** | ||
* For use with {@link WebClient}. | ||
* | ||
* @public | ||
*/ | ||
declare interface IWebFetchOptionsBase { | ||
timeoutMs?: number; | ||
verb?: 'GET' | 'PUT'; | ||
headers?: fetch.Headers; | ||
} | ||
/** | ||
* @public | ||
*/ | ||
declare class RushAmazonS3BuildCachePlugin implements IRushPlugin { | ||
@@ -15,2 +116,35 @@ pluginName: string; | ||
/** | ||
* A helper for issuing HTTP requests. | ||
* | ||
* @public | ||
*/ | ||
export declare class WebClient { | ||
readonly standardHeaders: fetch.Headers; | ||
accept: string | undefined; | ||
userAgent: string | undefined; | ||
proxy: WebClientProxy; | ||
constructor(); | ||
static mergeHeaders(target: fetch.Headers, source: fetch.Headers): void; | ||
addBasicAuthHeader(userName: string, password: string): void; | ||
fetchAsync(url: string, options?: IGetFetchOptions | IPutFetchOptions): Promise<WebClientResponse>; | ||
} | ||
/** | ||
* For use with {@link WebClient}. | ||
* @public | ||
*/ | ||
declare enum WebClientProxy { | ||
None = 0, | ||
Detect = 1, | ||
Fiddler = 2 | ||
} | ||
/** | ||
* For use with {@link WebClient}. | ||
* | ||
* @public | ||
*/ | ||
export declare type WebClientResponse = fetch.Response; | ||
export { } |
/// <reference types="node" /> | ||
import { ITerminal } from '@rushstack/node-core-library'; | ||
import { ICloudBuildCacheProvider, RushSession } from '@rushstack/rush-sdk'; | ||
export interface IAmazonS3BuildCacheProviderOptions { | ||
s3Bucket: string; | ||
/** | ||
* @public | ||
*/ | ||
export interface IAmazonS3BuildCacheProviderOptionsBase { | ||
s3Region: string; | ||
s3Prefix?: string; | ||
s3Prefix: string | undefined; | ||
isCacheWriteAllowed: boolean; | ||
} | ||
/** | ||
* Advanced options where user has the specify the full http endpoint | ||
* @public | ||
*/ | ||
export interface IAmazonS3BuildCacheProviderOptionsAdvanced extends IAmazonS3BuildCacheProviderOptionsBase { | ||
s3Endpoint: string; | ||
} | ||
/** | ||
* Simple options where user only provides the bucket and the endpoint is automatically built | ||
* @public | ||
*/ | ||
export interface IAmazonS3BuildCacheProviderOptionsSimple extends IAmazonS3BuildCacheProviderOptionsBase { | ||
s3Bucket: string; | ||
} | ||
export declare class AmazonS3BuildCacheProvider implements ICloudBuildCacheProvider { | ||
@@ -19,3 +35,4 @@ private readonly _options; | ||
private __s3Client; | ||
constructor(options: IAmazonS3BuildCacheProviderOptions, rushSession: RushSession); | ||
constructor(options: IAmazonS3BuildCacheProviderOptionsSimple | IAmazonS3BuildCacheProviderOptionsAdvanced, rushSession: RushSession); | ||
private get _s3Endpoint(); | ||
private get _credentialCacheId(); | ||
@@ -22,0 +39,0 @@ private _getS3ClientAsync; |
@@ -9,2 +9,3 @@ "use strict"; | ||
const WebClient_1 = require("./WebClient"); | ||
const DEFAULT_S3_REGION = 'us-east-1'; | ||
class AmazonS3BuildCacheProvider { | ||
@@ -22,5 +23,20 @@ constructor(options, rushSession) { | ||
} | ||
get _s3Endpoint() { | ||
const options = this._options; | ||
if ('s3Bucket' in options) { | ||
// options: IAmazonS3BuildCacheProviderOptionsSimple | ||
const bucket = options.s3Bucket; | ||
if (options.s3Region === DEFAULT_S3_REGION) { | ||
return `https://${bucket}.s3.amazonaws.com`; | ||
} | ||
else { | ||
return `https://${bucket}.s3-${options.s3Region}.amazonaws.com`; | ||
} | ||
} | ||
// options: IAmazonS3BuildCacheProviderOptionsAdvanced | ||
return options.s3Endpoint; | ||
} | ||
get _credentialCacheId() { | ||
if (!this.__credentialCacheId) { | ||
const cacheIdParts = ['aws-s3', this._options.s3Region, this._options.s3Bucket]; | ||
const cacheIdParts = ['aws-s3', this._options.s3Region, this._s3Endpoint]; | ||
if (this._isCacheWriteAllowedByConfiguration) { | ||
@@ -33,3 +49,3 @@ cacheIdParts.push('cacheWriteAllowed'); | ||
} | ||
async _getS3ClientAsync() { | ||
async _getS3ClientAsync(terminal) { | ||
var _a; | ||
@@ -62,3 +78,5 @@ if (!this.__s3Client) { | ||
} | ||
this.__s3Client = new AmazonS3Client_1.AmazonS3Client(credentials, this._options, new WebClient_1.WebClient()); | ||
this.__s3Client = new AmazonS3Client_1.AmazonS3Client(credentials, Object.assign(Object.assign({}, this._options), { | ||
// advanced options | ||
s3Endpoint: this._s3Endpoint }), new WebClient_1.WebClient(), terminal); | ||
} | ||
@@ -69,3 +87,3 @@ return this.__s3Client; | ||
try { | ||
const client = await this._getS3ClientAsync(); | ||
const client = await this._getS3ClientAsync(terminal); | ||
return await client.getObjectAsync(this._s3Prefix ? `${this._s3Prefix}/${cacheId}` : cacheId); | ||
@@ -83,4 +101,5 @@ } | ||
} | ||
terminal.writeDebugLine('Uploading object with cacheId: ', cacheId); | ||
try { | ||
const client = await this._getS3ClientAsync(); | ||
const client = await this._getS3ClientAsync(terminal); | ||
await client.uploadObjectAsync(this._s3Prefix ? `${this._s3Prefix}/${cacheId}` : cacheId, objectBuffer); | ||
@@ -87,0 +106,0 @@ return true; |
/// <reference types="node" /> | ||
import { IAmazonS3BuildCacheProviderOptions } from './AmazonS3BuildCacheProvider'; | ||
import { ITerminal } from '@rushstack/node-core-library'; | ||
import { IAmazonS3BuildCacheProviderOptionsAdvanced } from './AmazonS3BuildCacheProvider'; | ||
import { WebClient } from './WebClient'; | ||
/** | ||
* Credentials for authorizing and signing requests to an Amazon S3 endpoint. | ||
* | ||
* @public | ||
*/ | ||
export interface IAmazonS3Credentials { | ||
@@ -9,11 +15,19 @@ accessKeyId: string; | ||
} | ||
/** | ||
* A helper for reading and updating objects on Amazon S3 | ||
* | ||
* @public | ||
*/ | ||
export declare class AmazonS3Client { | ||
private readonly _credentials; | ||
private readonly _s3Bucket; | ||
private readonly _s3Endpoint; | ||
private readonly _s3Region; | ||
private readonly _webClient; | ||
constructor(credentials: IAmazonS3Credentials | undefined, options: IAmazonS3BuildCacheProviderOptions, webClient: WebClient); | ||
private readonly _terminal; | ||
constructor(credentials: IAmazonS3Credentials | undefined, options: IAmazonS3BuildCacheProviderOptionsAdvanced, webClient: WebClient, terminal: ITerminal); | ||
static UriEncode(input: string): string; | ||
static tryDeserializeCredentials(credentialString: string | undefined): IAmazonS3Credentials | undefined; | ||
getObjectAsync(objectName: string): Promise<Buffer | undefined>; | ||
uploadObjectAsync(objectName: string, objectBuffer: Buffer): Promise<void>; | ||
private _writeDebugLine; | ||
private _makeRequestAsync; | ||
@@ -24,10 +38,10 @@ _getSha256Hmac(key: string | Buffer, data: string): Buffer; | ||
private _getIsoDateString; | ||
private _safeReadResponseText; | ||
private _throwS3Error; | ||
private _getHost; | ||
/** | ||
* Validates a S3 bucket name. | ||
* {@link https://docs.aws.amazon.com/awscloudtrail/latest/userguide/cloudtrail-s3-bucket-naming-requirements.html} | ||
* Validates a S3 endpoint which is http(s):// + hostname + port. Hostname validated according to RFC 1123 | ||
* {@link https://docs.aws.amazon.com/general/latest/gr/s3.html} | ||
*/ | ||
private _validateBucketName; | ||
private _validateEndpoint; | ||
} | ||
//# sourceMappingURL=AmazonS3Client.d.ts.map |
@@ -25,2 +25,3 @@ "use strict"; | ||
exports.AmazonS3Client = void 0; | ||
const node_core_library_1 = require("@rushstack/node-core-library"); | ||
const crypto = __importStar(require("crypto")); | ||
@@ -32,11 +33,38 @@ const fetch = __importStar(require("node-fetch")); | ||
const SECURITY_TOKEN_HEADER_NAME = 'x-amz-security-token'; | ||
const DEFAULT_S3_REGION = 'us-east-1'; | ||
const protocolRegex = /^https?:\/\//; | ||
const portRegex = /:(\d{1,5})$/; | ||
/** | ||
* A helper for reading and updating objects on Amazon S3 | ||
* | ||
* @public | ||
*/ | ||
class AmazonS3Client { | ||
constructor(credentials, options, webClient) { | ||
constructor(credentials, options, webClient, terminal) { | ||
this._credentials = credentials; | ||
this._validateBucketName(options.s3Bucket); | ||
this._s3Bucket = options.s3Bucket; | ||
this._terminal = terminal; | ||
this._validateEndpoint(options.s3Endpoint); | ||
this._s3Endpoint = options.s3Endpoint; | ||
this._s3Region = options.s3Region; | ||
this._webClient = webClient; | ||
} | ||
// https://docs.aws.amazon.com/AmazonS3/latest/API/sig-v4-header-based-auth.html#create-signature-presign-entire-payload | ||
// We want to keep all slashes non encoded | ||
static UriEncode(input) { | ||
let output = ''; | ||
for (let i = 0; i < input.length; i += 1) { | ||
const ch = input[i]; | ||
if (ch.match(/[A-Za-z0-9~._-]|\//)) { | ||
output += ch; | ||
} | ||
else { | ||
if (ch === ' ') { | ||
output += '%20'; | ||
} | ||
else { | ||
output += `%${ch.charCodeAt(0).toString(16).toUpperCase()}`; | ||
} | ||
} | ||
} | ||
return output; | ||
} | ||
static tryDeserializeCredentials(credentialString) { | ||
@@ -57,2 +85,3 @@ if (!credentialString) { | ||
async getObjectAsync(objectName) { | ||
this._writeDebugLine('Reading object from S3'); | ||
const response = await this._makeRequestAsync('GET', objectName); | ||
@@ -69,3 +98,3 @@ if (response.ok) { | ||
else { | ||
this._throwS3Error(response); | ||
this._throwS3Error(response, await this._safeReadResponseText(response)); | ||
} | ||
@@ -79,15 +108,26 @@ } | ||
if (!response.ok) { | ||
this._throwS3Error(response); | ||
this._throwS3Error(response, await this._safeReadResponseText(response)); | ||
} | ||
} | ||
_writeDebugLine(...messageParts) { | ||
// if the terminal has been closed then don't bother sending a debug message | ||
try { | ||
this._terminal.writeDebugLine(...messageParts); | ||
} | ||
catch (err) { | ||
// | ||
} | ||
} | ||
async _makeRequestAsync(verb, objectName, body) { | ||
const isoDateString = this._getIsoDateString(); | ||
const bodyHash = this._getSha256(body); | ||
const host = this._getHost(); | ||
const headers = new fetch.Headers(); | ||
headers.set(DATE_HEADER_NAME, isoDateString.dateTime); | ||
headers.set(CONTENT_HASH_HEADER_NAME, bodyHash); | ||
// the host can be e.g. https://s3.aws.com or http://localhost:9000 | ||
const host = this._s3Endpoint.replace(protocolRegex, ''); | ||
const canonicalUri = AmazonS3Client.UriEncode(`/${objectName}`); | ||
this._writeDebugLine(node_core_library_1.Colors.bold('Canonical URI: '), canonicalUri); | ||
if (this._credentials) { | ||
// Compute the authorization header. See https://docs.aws.amazon.com/AmazonS3/latest/API/sig-v4-header-based-auth.html | ||
const signedHeaderNames = [HOST_HEADER_NAME, CONTENT_HASH_HEADER_NAME, DATE_HEADER_NAME]; | ||
const canonicalHeaders = [ | ||
@@ -100,6 +140,23 @@ `${HOST_HEADER_NAME}:${host}`, | ||
if (this._credentials.sessionToken) { | ||
signedHeaderNames.push(SECURITY_TOKEN_HEADER_NAME); | ||
canonicalHeaders.push(`${SECURITY_TOKEN_HEADER_NAME}:${this._credentials.sessionToken}`); | ||
} | ||
const signedHeaderNamesString = signedHeaderNames.join(';'); | ||
// the canonical headers must be sorted by header name | ||
canonicalHeaders.sort((aHeader, bHeader) => { | ||
const aHeaderName = aHeader.split(':')[0]; | ||
const bHeaderName = bHeader.split(':')[0]; | ||
if (aHeaderName < bHeaderName) { | ||
return -1; | ||
} | ||
if (aHeaderName > bHeaderName) { | ||
return 1; | ||
} | ||
return 0; | ||
}); | ||
// the singed header names are derived from the canonicalHeaders | ||
const signedHeaderNamesString = canonicalHeaders | ||
.map((header) => { | ||
const headerName = header.split(':')[0]; | ||
return headerName; | ||
}) | ||
.join(';'); | ||
// The canonical request looks like this: | ||
@@ -118,3 +175,3 @@ // GET | ||
verb, | ||
`/${objectName}`, | ||
canonicalUri, | ||
'', | ||
@@ -158,3 +215,10 @@ ...canonicalHeaders, | ||
} | ||
const response = await this._webClient.fetchAsync(`https://${host}/${objectName}`, webFetchOptions); | ||
const url = `${this._s3Endpoint}${canonicalUri}`; | ||
this._writeDebugLine(node_core_library_1.Colors.bold(node_core_library_1.Colors.underline('Sending request to S3'))); | ||
this._writeDebugLine(node_core_library_1.Colors.bold('HOST: '), url); | ||
this._writeDebugLine(node_core_library_1.Colors.bold('Headers: ')); | ||
headers.forEach((value, name) => { | ||
this._writeDebugLine(node_core_library_1.Colors.cyan(`\t${name}: ${value}`)); | ||
}); | ||
const response = await this._webClient.fetchAsync(url, webFetchOptions); | ||
return response; | ||
@@ -194,39 +258,55 @@ } | ||
} | ||
_throwS3Error(response) { | ||
throw new Error(`Amazon S3 responded with status code ${response.status} (${response.statusText})`); | ||
} | ||
_getHost() { | ||
if (this._s3Region === DEFAULT_S3_REGION) { | ||
return `${this._s3Bucket}.s3.amazonaws.com`; | ||
async _safeReadResponseText(response) { | ||
try { | ||
return await response.text(); | ||
} | ||
else { | ||
return `${this._s3Bucket}.s3-${this._s3Region}.amazonaws.com`; | ||
catch (err) { | ||
// ignore the error | ||
} | ||
return undefined; | ||
} | ||
_throwS3Error(response, text) { | ||
throw new Error(`Amazon S3 responded with status code ${response.status} (${response.statusText})${text ? `\n${text}` : ''}`); | ||
} | ||
/** | ||
* Validates a S3 bucket name. | ||
* {@link https://docs.aws.amazon.com/awscloudtrail/latest/userguide/cloudtrail-s3-bucket-naming-requirements.html} | ||
* Validates a S3 endpoint which is http(s):// + hostname + port. Hostname validated according to RFC 1123 | ||
* {@link https://docs.aws.amazon.com/general/latest/gr/s3.html} | ||
*/ | ||
_validateBucketName(s3BucketName) { | ||
if (!s3BucketName) { | ||
throw new Error('A S3 bucket name must be provided'); | ||
_validateEndpoint(s3Endpoint) { | ||
let host = s3Endpoint; | ||
if (!s3Endpoint) { | ||
throw new Error('A S3 endpoint must be provided'); | ||
} | ||
if (!s3BucketName.match(/^[a-z\d-.]{3,63}$/)) { | ||
throw new Error(`The bucket name "${s3BucketName}" is invalid. A S3 bucket name must only contain lowercase ` + | ||
'alphanumerical characters, dashes, and periods and must be between 3 and 63 characters long.'); | ||
if (!s3Endpoint.match(protocolRegex)) { | ||
throw new Error('The S3 endpoint must start with https:// or http://'); | ||
} | ||
if (!s3BucketName.match(/^[a-z\d]/)) { | ||
throw new Error(`The bucket name "${s3BucketName}" is invalid. A S3 bucket name must start with a lowercase ` + | ||
'alphanumerical character.'); | ||
host = host.replace(protocolRegex, ''); | ||
if (host.match(/\//)) { | ||
throw new Error('The path should be omitted from the endpoint. Use s3Prefix to specify a path'); | ||
} | ||
if (s3BucketName.match(/-$/)) { | ||
throw new Error(`The bucket name "${s3BucketName}" is invalid. A S3 bucket name must not end in a dash.`); | ||
const portMatch = s3Endpoint.match(portRegex); | ||
if (portMatch) { | ||
const port = Number(portMatch[1]); | ||
if (Number.isNaN(port) || port > 65535) { | ||
throw new Error(`Port: ${port} is an invalid port number`); | ||
} | ||
host = host.replace(portRegex, ''); | ||
} | ||
if (s3BucketName.match(/(\.\.)|(\.-)|(-\.)/)) { | ||
throw new Error(`The bucket name "${s3BucketName}" is invalid. A S3 bucket name must not have consecutive periods or ` + | ||
'dashes adjacent to periods.'); | ||
if (host.endsWith('.')) { | ||
host = host.slice(0, host.length - 1); | ||
} | ||
if (s3BucketName.match(/^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/)) { | ||
throw new Error(`The bucket name "${s3BucketName}" is invalid. A S3 bucket name must not be formatted as an IP address.`); | ||
if (host.length > 253) { | ||
throw new Error('The S3 endpoint is too long. RFC 1123 specifies a hostname should be no longer than 253 characters.'); | ||
} | ||
const subDomains = host.split('.'); | ||
const subDomainRegex = /^[a-zA-Z0-9-]+$/; | ||
const isValid = subDomains.every((subDomain) => { | ||
return (subDomainRegex.test(subDomain) && | ||
subDomain.length < 64 && | ||
!subDomain.startsWith('-') && | ||
!subDomain.endsWith('-')); | ||
}); | ||
if (!isValid) { | ||
throw new Error('Invalid S3 endpoint. Some part of the hostname contains invalid characters or is too long'); | ||
} | ||
} | ||
@@ -233,0 +313,0 @@ } |
import { RushAmazonS3BuildCachePlugin } from './RushAmazonS3BuildCachePlugin'; | ||
export { AmazonS3Client, IAmazonS3Credentials } from './AmazonS3Client'; | ||
export { WebClient, IGetFetchOptions, IPutFetchOptions, WebClientResponse } from './WebClient'; | ||
export default RushAmazonS3BuildCachePlugin; | ||
export { IAmazonS3BuildCacheProviderOptionsBase, IAmazonS3BuildCacheProviderOptionsAdvanced, IAmazonS3BuildCacheProviderOptionsSimple } from './AmazonS3BuildCacheProvider'; | ||
//# sourceMappingURL=index.d.ts.map |
@@ -5,4 +5,9 @@ "use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.WebClient = exports.AmazonS3Client = void 0; | ||
const RushAmazonS3BuildCachePlugin_1 = require("./RushAmazonS3BuildCachePlugin"); | ||
var AmazonS3Client_1 = require("./AmazonS3Client"); | ||
Object.defineProperty(exports, "AmazonS3Client", { enumerable: true, get: function () { return AmazonS3Client_1.AmazonS3Client; } }); | ||
var WebClient_1 = require("./WebClient"); | ||
Object.defineProperty(exports, "WebClient", { enumerable: true, get: function () { return WebClient_1.WebClient; } }); | ||
exports.default = RushAmazonS3BuildCachePlugin_1.RushAmazonS3BuildCachePlugin; | ||
//# sourceMappingURL=index.js.map |
@@ -7,2 +7,10 @@ import type { IRushPlugin, RushSession, RushConfiguration } from '@rushstack/rush-sdk'; | ||
/** | ||
* (Required unless s3Endpoint is specified) The name of the bucket to use for build cache (e.g. "my-bucket"). | ||
*/ | ||
s3Bucket?: string; | ||
/** | ||
* (Required unless s3Bucket is specified) The Amazon S3 endpoint of the bucket to use for build cache (e.g. "my-bucket.s3.us-east-2.amazonaws.com" or "http://localhost:9000"). | ||
*/ | ||
s3Endpoint?: string; | ||
/** | ||
* The Amazon S3 region of the bucket to use for build cache (e.g. "us-east-1"). | ||
@@ -12,6 +20,2 @@ */ | ||
/** | ||
* The name of the bucket in Amazon S3 to use for build cache. | ||
*/ | ||
s3Bucket: string; | ||
/** | ||
* An optional prefix ("folder") for cache items. | ||
@@ -18,0 +22,0 @@ */ |
@@ -20,8 +20,35 @@ "use strict"; | ||
const { amazonS3Configuration } = buildCacheConfig; | ||
return new AmazonS3BuildCacheProviderModule.AmazonS3BuildCacheProvider({ | ||
s3Region: amazonS3Configuration.s3Region, | ||
s3Bucket: amazonS3Configuration.s3Bucket, | ||
s3Prefix: amazonS3Configuration.s3Prefix, | ||
isCacheWriteAllowed: !!amazonS3Configuration.isCacheWriteAllowed | ||
}, rushSession); | ||
let options; | ||
const { s3Endpoint, s3Bucket, s3Region } = amazonS3Configuration; | ||
const s3Prefix = amazonS3Configuration.s3Prefix || undefined; | ||
const isCacheWriteAllowed = !!amazonS3Configuration.isCacheWriteAllowed; | ||
if (s3Prefix && s3Prefix[0] === '/') { | ||
throw new Error('s3Prefix should not have a leading /'); | ||
} | ||
// mutually exclusive | ||
if (s3Bucket && s3Endpoint) { | ||
throw new Error('Only one of "s3Bucket" or "s3Endpoint" must be provided.'); | ||
} | ||
if (s3Endpoint) { | ||
options = { | ||
// IAmazonS3BuildCacheProviderOptionsAdvanced | ||
s3Region, | ||
s3Endpoint, | ||
s3Prefix, | ||
isCacheWriteAllowed | ||
}; | ||
} | ||
if (s3Bucket) { | ||
options = { | ||
// IAmazonS3BuildCacheProviderOptionsSimple | ||
s3Region, | ||
s3Bucket, | ||
s3Prefix, | ||
isCacheWriteAllowed | ||
}; | ||
} | ||
if (!options) { | ||
throw new Error('You must provide either an s3Endpoint or s3Bucket'); | ||
} | ||
return new AmazonS3BuildCacheProviderModule.AmazonS3BuildCacheProvider(options, rushSession); | ||
}); | ||
@@ -28,0 +55,0 @@ }); |
{ | ||
"$schema": "http://json-schema.org/draft-04/schema#", | ||
"title": "Configuration for build cache with Amazon S3 configuration", | ||
"type": "object", | ||
"additionalProperties": false, | ||
"required": ["s3Region", "s3Bucket"], | ||
"properties": { | ||
"s3Region": { | ||
"type": "string", | ||
"description": "(Required) The Amazon S3 region of the bucket to use for build cache (e.g. \"us-east-1\")." | ||
"oneOf": [ | ||
{ | ||
"type": "object", | ||
"required": ["s3Endpoint", "s3Region"], | ||
"properties": { | ||
"s3Endpoint": { | ||
"type": "string", | ||
"description": "(Required) The Amazon S3 endpoint of the bucket to use for build cache (e.g. \"s3.us-east-2.amazonaws.com\")." | ||
}, | ||
"s3Region": { | ||
"type": "string", | ||
"description": "(Required) The Amazon S3 region of the bucket to use for build cache (e.g. \"us-east-1\")." | ||
}, | ||
"s3Prefix": { | ||
"type": "string", | ||
"description": "An optional prefix (\"folder\") for cache items." | ||
}, | ||
"isCacheWriteAllowed": { | ||
"type": "boolean", | ||
"description": "If set to true, allow writing to the cache. Defaults to false." | ||
} | ||
} | ||
}, | ||
"s3Bucket": { | ||
"type": "string", | ||
"description": "(Required) The name of the bucket in Amazon S3 to use for build cache." | ||
}, | ||
"s3Prefix": { | ||
"type": "string", | ||
"description": "An optional prefix (\"folder\") for cache items." | ||
}, | ||
"isCacheWriteAllowed": { | ||
"type": "boolean", | ||
"description": "If set to true, allow writing to the cache. Defaults to false." | ||
{ | ||
"type": "object", | ||
"required": ["s3Bucket", "s3Region"], | ||
"properties": { | ||
"s3Bucket": { | ||
"type": "string", | ||
"description": "(Required unless s3Endpoint is specified) The name of the bucket to use for build cache (e.g. \"my-bucket\")." | ||
}, | ||
"s3Region": { | ||
"type": "string", | ||
"description": "(Required) The Amazon S3 region of the bucket to use for build cache (e.g. \"us-east-1\")." | ||
}, | ||
"s3Prefix": { | ||
"type": "string", | ||
"description": "An optional prefix (\"folder\") for cache items." | ||
}, | ||
"isCacheWriteAllowed": { | ||
"type": "boolean", | ||
"description": "If set to true, allow writing to the cache. Defaults to false." | ||
} | ||
} | ||
} | ||
} | ||
] | ||
} |
@@ -5,2 +5,4 @@ /// <reference types="node" /> | ||
* For use with {@link WebClient}. | ||
* | ||
* @public | ||
*/ | ||
@@ -10,2 +12,4 @@ export declare type WebClientResponse = fetch.Response; | ||
* For use with {@link WebClient}. | ||
* | ||
* @public | ||
*/ | ||
@@ -19,2 +23,4 @@ export interface IWebFetchOptionsBase { | ||
* For use with {@link WebClient}. | ||
* | ||
* @public | ||
*/ | ||
@@ -26,2 +32,4 @@ export interface IGetFetchOptions extends IWebFetchOptionsBase { | ||
* For use with {@link WebClient}. | ||
* | ||
* @public | ||
*/ | ||
@@ -34,2 +42,3 @@ export interface IPutFetchOptions extends IWebFetchOptionsBase { | ||
* For use with {@link WebClient}. | ||
* @public | ||
*/ | ||
@@ -43,2 +52,4 @@ export declare enum WebClientProxy { | ||
* A helper for issuing HTTP requests. | ||
* | ||
* @public | ||
*/ | ||
@@ -45,0 +56,0 @@ export declare class WebClient { |
@@ -39,2 +39,3 @@ "use strict"; | ||
* For use with {@link WebClient}. | ||
* @public | ||
*/ | ||
@@ -49,2 +50,4 @@ var WebClientProxy; | ||
* A helper for issuing HTTP requests. | ||
* | ||
* @public | ||
*/ | ||
@@ -51,0 +54,0 @@ class WebClient { |
{ | ||
"name": "@rushstack/rush-amazon-s3-build-cache-plugin", | ||
"version": "5.62.0-pr3059", | ||
"version": "5.62.0", | ||
"description": "Rush plugin for Amazon S3 cloud build cache", | ||
@@ -15,3 +15,3 @@ "repository": { | ||
"@rushstack/node-core-library": "3.45.0", | ||
"@rushstack/rush-sdk": "5.62.0-pr3059", | ||
"@rushstack/rush-sdk": "5.62.0", | ||
"https-proxy-agent": "~5.0.0", | ||
@@ -21,3 +21,3 @@ "node-fetch": "2.6.7" | ||
"devDependencies": { | ||
"@microsoft/rush-lib": "5.62.0-pr3059", | ||
"@microsoft/rush-lib": "5.62.0", | ||
"@rushstack/eslint-config": "2.5.1", | ||
@@ -24,0 +24,0 @@ "@rushstack/heft": "0.44.2", |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
94923
1020
0
+ Added@rushstack/rush-sdk@5.62.0(transitive)
- Removed@rushstack/rush-sdk@5.62.0-pr3059(transitive)
Updated@rushstack/rush-sdk@5.62.0