chore: import upstream snapshot with attribution
Fuzzer / Run Fuzzer (push) Has been cancelled
Race tests / Go race tests (ubuntu-22.04) (push) Has been cancelled

This commit is contained in:
wehub-resource-sync
2026-07-13 13:01:40 +08:00
commit 5357c39144
2379 changed files with 670828 additions and 0 deletions
+3
View File
@@ -0,0 +1,3 @@
# These are supported funding model platforms
github: dolthub
@@ -0,0 +1,5 @@
name: 'Dolt Benchmark Runner Utility Test'
description: "Smoke tests for Dolt's benchmark runner utility"
runs:
using: 'docker'
image: '../../../SysbenchDockerfile'
+51
View File
@@ -0,0 +1,51 @@
name: 'Build dolt'
description: 'Builds dolt (and optionally remotesrv and noms) into $GITHUB_WORKSPACE/.ci_bin and prepends that directory to $GITHUB_PATH so the binaries are on PATH for subsequent steps. On Windows, builds run inside the msys2 shell (this action expects setup-go-toolchain to have been run first so that msys2 is installed).'
inputs:
remotesrv:
description: 'Also build remotesrv.'
required: false
default: 'false'
noms:
description: 'Also build noms.'
required: false
default: 'false'
runs:
using: 'composite'
steps:
- name: Add .ci_bin to PATH
shell: bash
run: |
mkdir -p "$GITHUB_WORKSPACE/.ci_bin"
echo "$GITHUB_WORKSPACE/.ci_bin" >> "$GITHUB_PATH"
- name: Build dolt
if: runner.os != 'Windows'
shell: bash
working-directory: ./go
run: go build -mod=readonly -o ../.ci_bin/dolt ./cmd/dolt/.
- name: Build remotesrv
if: runner.os != 'Windows' && inputs.remotesrv == 'true'
shell: bash
working-directory: ./go
run: go build -mod=readonly -o ../.ci_bin/remotesrv ./utils/remotesrv/.
- name: Build noms
if: runner.os != 'Windows' && inputs.noms == 'true'
shell: bash
working-directory: ./go
run: go build -mod=readonly -o ../.ci_bin/noms ./store/cmd/noms/.
- name: Build dolt (Windows)
if: runner.os == 'Windows'
shell: 'msys2 {0}'
working-directory: ./go
run: go.exe build -mod=readonly -o ../.ci_bin/dolt ./cmd/dolt/.
- name: Build remotesrv (Windows)
if: runner.os == 'Windows' && inputs.remotesrv == 'true'
shell: 'msys2 {0}'
working-directory: ./go
run: go.exe build -mod=readonly -o ../.ci_bin/remotesrv ./utils/remotesrv/.
- name: Build noms (Windows)
if: runner.os == 'Windows' && inputs.noms == 'true'
shell: 'msys2 {0}'
working-directory: ./go
run: go.exe build -mod=readonly -o ../.ci_bin/noms ./store/cmd/noms/.
@@ -0,0 +1,5 @@
name: 'Dolt loading dump file integration tests'
description: 'Smoke tests for loading dump file into Dolt'
runs:
using: 'docker'
image: '../../../integration-tests/DataDumpLoadDockerfile'
@@ -0,0 +1,50 @@
name: 'SES email action'
description: 'Send email with aws ses'
inputs:
region:
description: 'aws region'
required: true
default: ''
version:
description: 'dolt version being benchmarked or ref of bats windows job'
required: true
default: ''
format:
description: 'dolt noms bin format'
required: true
default: '__DOLT__'
template:
description: 'email template'
required: false
default: 'PerformanceBenchmarkingReleaseTemplate'
dataFile:
required: false
description: 'path to email data file'
default: ''
bodyPath:
required: false
description: 'path to email body file'
default: ''
subject:
required: false
description: 'path to email subject'
default: ''
toAddresses:
description: 'json string list of to addresses'
required: true
default: "[]"
ccAddresses:
description: 'json string list of cc addresses'
required: false
default: "[]"
replyToAddresses:
description: 'json string list of reply to addresses'
required: false
default: "[]"
workflowURL:
description: 'url of the workflow run'
default: ''
required: false
runs:
using: 'node20'
main: 'dist/index.js'
@@ -0,0 +1,898 @@
"use strict";
exports.id = 136;
exports.ids = [136];
exports.modules = {
/***/ 3723:
/***/ ((__unused_webpack_module, exports, __webpack_require__) => {
Object.defineProperty(exports, "__esModule", ({ value: true }));
exports.STSClient = exports.__Client = void 0;
const middleware_host_header_1 = __webpack_require__(2590);
const middleware_logger_1 = __webpack_require__(5242);
const middleware_recursion_detection_1 = __webpack_require__(1568);
const middleware_user_agent_1 = __webpack_require__(2959);
const config_resolver_1 = __webpack_require__(9316);
const core_1 = __webpack_require__(402);
const schema_1 = __webpack_require__(6890);
const middleware_content_length_1 = __webpack_require__(7212);
const middleware_endpoint_1 = __webpack_require__(99);
const middleware_retry_1 = __webpack_require__(9618);
const smithy_client_1 = __webpack_require__(1411);
Object.defineProperty(exports, "__Client", ({ enumerable: true, get: function () { return smithy_client_1.Client; } }));
const httpAuthSchemeProvider_1 = __webpack_require__(7851);
const EndpointParameters_1 = __webpack_require__(6811);
const runtimeConfig_1 = __webpack_require__(6578);
const runtimeExtensions_1 = __webpack_require__(7742);
class STSClient extends smithy_client_1.Client {
config;
constructor(...[configuration]) {
const _config_0 = (0, runtimeConfig_1.getRuntimeConfig)(configuration || {});
super(_config_0);
this.initConfig = _config_0;
const _config_1 = (0, EndpointParameters_1.resolveClientEndpointParameters)(_config_0);
const _config_2 = (0, middleware_user_agent_1.resolveUserAgentConfig)(_config_1);
const _config_3 = (0, middleware_retry_1.resolveRetryConfig)(_config_2);
const _config_4 = (0, config_resolver_1.resolveRegionConfig)(_config_3);
const _config_5 = (0, middleware_host_header_1.resolveHostHeaderConfig)(_config_4);
const _config_6 = (0, middleware_endpoint_1.resolveEndpointConfig)(_config_5);
const _config_7 = (0, httpAuthSchemeProvider_1.resolveHttpAuthSchemeConfig)(_config_6);
const _config_8 = (0, runtimeExtensions_1.resolveRuntimeExtensions)(_config_7, configuration?.extensions || []);
this.config = _config_8;
this.middlewareStack.use((0, schema_1.getSchemaSerdePlugin)(this.config));
this.middlewareStack.use((0, middleware_user_agent_1.getUserAgentPlugin)(this.config));
this.middlewareStack.use((0, middleware_retry_1.getRetryPlugin)(this.config));
this.middlewareStack.use((0, middleware_content_length_1.getContentLengthPlugin)(this.config));
this.middlewareStack.use((0, middleware_host_header_1.getHostHeaderPlugin)(this.config));
this.middlewareStack.use((0, middleware_logger_1.getLoggerPlugin)(this.config));
this.middlewareStack.use((0, middleware_recursion_detection_1.getRecursionDetectionPlugin)(this.config));
this.middlewareStack.use((0, core_1.getHttpAuthSchemeEndpointRuleSetPlugin)(this.config, {
httpAuthSchemeParametersProvider: httpAuthSchemeProvider_1.defaultSTSHttpAuthSchemeParametersProvider,
identityProviderConfigProvider: async (config) => new core_1.DefaultIdentityProviderConfig({
"aws.auth#sigv4": config.credentials,
}),
}));
this.middlewareStack.use((0, core_1.getHttpSigningPlugin)(this.config));
}
destroy() {
super.destroy();
}
}
exports.STSClient = STSClient;
/***/ }),
/***/ 4532:
/***/ ((__unused_webpack_module, exports) => {
Object.defineProperty(exports, "__esModule", ({ value: true }));
exports.resolveHttpAuthRuntimeConfig = exports.getHttpAuthExtensionConfiguration = void 0;
const getHttpAuthExtensionConfiguration = (runtimeConfig) => {
const _httpAuthSchemes = runtimeConfig.httpAuthSchemes;
let _httpAuthSchemeProvider = runtimeConfig.httpAuthSchemeProvider;
let _credentials = runtimeConfig.credentials;
return {
setHttpAuthScheme(httpAuthScheme) {
const index = _httpAuthSchemes.findIndex((scheme) => scheme.schemeId === httpAuthScheme.schemeId);
if (index === -1) {
_httpAuthSchemes.push(httpAuthScheme);
}
else {
_httpAuthSchemes.splice(index, 1, httpAuthScheme);
}
},
httpAuthSchemes() {
return _httpAuthSchemes;
},
setHttpAuthSchemeProvider(httpAuthSchemeProvider) {
_httpAuthSchemeProvider = httpAuthSchemeProvider;
},
httpAuthSchemeProvider() {
return _httpAuthSchemeProvider;
},
setCredentials(credentials) {
_credentials = credentials;
},
credentials() {
return _credentials;
},
};
};
exports.getHttpAuthExtensionConfiguration = getHttpAuthExtensionConfiguration;
const resolveHttpAuthRuntimeConfig = (config) => {
return {
httpAuthSchemes: config.httpAuthSchemes(),
httpAuthSchemeProvider: config.httpAuthSchemeProvider(),
credentials: config.credentials(),
};
};
exports.resolveHttpAuthRuntimeConfig = resolveHttpAuthRuntimeConfig;
/***/ }),
/***/ 7851:
/***/ ((__unused_webpack_module, exports, __webpack_require__) => {
Object.defineProperty(exports, "__esModule", ({ value: true }));
exports.resolveHttpAuthSchemeConfig = exports.resolveStsAuthConfig = exports.defaultSTSHttpAuthSchemeProvider = exports.defaultSTSHttpAuthSchemeParametersProvider = void 0;
const core_1 = __webpack_require__(8704);
const util_middleware_1 = __webpack_require__(6324);
const STSClient_1 = __webpack_require__(3723);
const defaultSTSHttpAuthSchemeParametersProvider = async (config, context, input) => {
return {
operation: (0, util_middleware_1.getSmithyContext)(context).operation,
region: (await (0, util_middleware_1.normalizeProvider)(config.region)()) ||
(() => {
throw new Error("expected `region` to be configured for `aws.auth#sigv4`");
})(),
};
};
exports.defaultSTSHttpAuthSchemeParametersProvider = defaultSTSHttpAuthSchemeParametersProvider;
function createAwsAuthSigv4HttpAuthOption(authParameters) {
return {
schemeId: "aws.auth#sigv4",
signingProperties: {
name: "sts",
region: authParameters.region,
},
propertiesExtractor: (config, context) => ({
signingProperties: {
config,
context,
},
}),
};
}
function createSmithyApiNoAuthHttpAuthOption(authParameters) {
return {
schemeId: "smithy.api#noAuth",
};
}
const defaultSTSHttpAuthSchemeProvider = (authParameters) => {
const options = [];
switch (authParameters.operation) {
case "AssumeRoleWithWebIdentity": {
options.push(createSmithyApiNoAuthHttpAuthOption(authParameters));
break;
}
default: {
options.push(createAwsAuthSigv4HttpAuthOption(authParameters));
}
}
return options;
};
exports.defaultSTSHttpAuthSchemeProvider = defaultSTSHttpAuthSchemeProvider;
const resolveStsAuthConfig = (input) => Object.assign(input, {
stsClientCtor: STSClient_1.STSClient,
});
exports.resolveStsAuthConfig = resolveStsAuthConfig;
const resolveHttpAuthSchemeConfig = (config) => {
const config_0 = (0, exports.resolveStsAuthConfig)(config);
const config_1 = (0, core_1.resolveAwsSdkSigV4Config)(config_0);
return Object.assign(config_1, {
authSchemePreference: (0, util_middleware_1.normalizeProvider)(config.authSchemePreference ?? []),
});
};
exports.resolveHttpAuthSchemeConfig = resolveHttpAuthSchemeConfig;
/***/ }),
/***/ 6811:
/***/ ((__unused_webpack_module, exports) => {
Object.defineProperty(exports, "__esModule", ({ value: true }));
exports.commonParams = exports.resolveClientEndpointParameters = void 0;
const resolveClientEndpointParameters = (options) => {
return Object.assign(options, {
useDualstackEndpoint: options.useDualstackEndpoint ?? false,
useFipsEndpoint: options.useFipsEndpoint ?? false,
useGlobalEndpoint: options.useGlobalEndpoint ?? false,
defaultSigningName: "sts",
});
};
exports.resolveClientEndpointParameters = resolveClientEndpointParameters;
exports.commonParams = {
UseGlobalEndpoint: { type: "builtInParams", name: "useGlobalEndpoint" },
UseFIPS: { type: "builtInParams", name: "useFipsEndpoint" },
Endpoint: { type: "builtInParams", name: "endpoint" },
Region: { type: "builtInParams", name: "region" },
UseDualStack: { type: "builtInParams", name: "useDualstackEndpoint" },
};
/***/ }),
/***/ 9765:
/***/ ((__unused_webpack_module, exports, __webpack_require__) => {
Object.defineProperty(exports, "__esModule", ({ value: true }));
exports.defaultEndpointResolver = void 0;
const util_endpoints_1 = __webpack_require__(3068);
const util_endpoints_2 = __webpack_require__(9674);
const ruleset_1 = __webpack_require__(1670);
const cache = new util_endpoints_2.EndpointCache({
size: 50,
params: ["Endpoint", "Region", "UseDualStack", "UseFIPS", "UseGlobalEndpoint"],
});
const defaultEndpointResolver = (endpointParams, context = {}) => {
return cache.get(endpointParams, () => (0, util_endpoints_2.resolveEndpoint)(ruleset_1.ruleSet, {
endpointParams: endpointParams,
logger: context.logger,
}));
};
exports.defaultEndpointResolver = defaultEndpointResolver;
util_endpoints_2.customEndpointFunctions.aws = util_endpoints_1.awsEndpointFunctions;
/***/ }),
/***/ 1670:
/***/ ((__unused_webpack_module, exports) => {
Object.defineProperty(exports, "__esModule", ({ value: true }));
exports.ruleSet = void 0;
const F = "required", G = "type", H = "fn", I = "argv", J = "ref";
const a = false, b = true, c = "booleanEquals", d = "stringEquals", e = "sigv4", f = "sts", g = "us-east-1", h = "endpoint", i = "https://sts.{Region}.{PartitionResult#dnsSuffix}", j = "tree", k = "error", l = "getAttr", m = { [F]: false, [G]: "string" }, n = { [F]: true, "default": false, [G]: "boolean" }, o = { [J]: "Endpoint" }, p = { [H]: "isSet", [I]: [{ [J]: "Region" }] }, q = { [J]: "Region" }, r = { [H]: "aws.partition", [I]: [q], "assign": "PartitionResult" }, s = { [J]: "UseFIPS" }, t = { [J]: "UseDualStack" }, u = { "url": "https://sts.amazonaws.com", "properties": { "authSchemes": [{ "name": e, "signingName": f, "signingRegion": g }] }, "headers": {} }, v = {}, w = { "conditions": [{ [H]: d, [I]: [q, "aws-global"] }], [h]: u, [G]: h }, x = { [H]: c, [I]: [s, true] }, y = { [H]: c, [I]: [t, true] }, z = { [H]: l, [I]: [{ [J]: "PartitionResult" }, "supportsFIPS"] }, A = { [J]: "PartitionResult" }, B = { [H]: c, [I]: [true, { [H]: l, [I]: [A, "supportsDualStack"] }] }, C = [{ [H]: "isSet", [I]: [o] }], D = [x], E = [y];
const _data = { version: "1.0", parameters: { Region: m, UseDualStack: n, UseFIPS: n, Endpoint: m, UseGlobalEndpoint: n }, rules: [{ conditions: [{ [H]: c, [I]: [{ [J]: "UseGlobalEndpoint" }, b] }, { [H]: "not", [I]: C }, p, r, { [H]: c, [I]: [s, a] }, { [H]: c, [I]: [t, a] }], rules: [{ conditions: [{ [H]: d, [I]: [q, "ap-northeast-1"] }], endpoint: u, [G]: h }, { conditions: [{ [H]: d, [I]: [q, "ap-south-1"] }], endpoint: u, [G]: h }, { conditions: [{ [H]: d, [I]: [q, "ap-southeast-1"] }], endpoint: u, [G]: h }, { conditions: [{ [H]: d, [I]: [q, "ap-southeast-2"] }], endpoint: u, [G]: h }, w, { conditions: [{ [H]: d, [I]: [q, "ca-central-1"] }], endpoint: u, [G]: h }, { conditions: [{ [H]: d, [I]: [q, "eu-central-1"] }], endpoint: u, [G]: h }, { conditions: [{ [H]: d, [I]: [q, "eu-north-1"] }], endpoint: u, [G]: h }, { conditions: [{ [H]: d, [I]: [q, "eu-west-1"] }], endpoint: u, [G]: h }, { conditions: [{ [H]: d, [I]: [q, "eu-west-2"] }], endpoint: u, [G]: h }, { conditions: [{ [H]: d, [I]: [q, "eu-west-3"] }], endpoint: u, [G]: h }, { conditions: [{ [H]: d, [I]: [q, "sa-east-1"] }], endpoint: u, [G]: h }, { conditions: [{ [H]: d, [I]: [q, g] }], endpoint: u, [G]: h }, { conditions: [{ [H]: d, [I]: [q, "us-east-2"] }], endpoint: u, [G]: h }, { conditions: [{ [H]: d, [I]: [q, "us-west-1"] }], endpoint: u, [G]: h }, { conditions: [{ [H]: d, [I]: [q, "us-west-2"] }], endpoint: u, [G]: h }, { endpoint: { url: i, properties: { authSchemes: [{ name: e, signingName: f, signingRegion: "{Region}" }] }, headers: v }, [G]: h }], [G]: j }, { conditions: C, rules: [{ conditions: D, error: "Invalid Configuration: FIPS and custom endpoint are not supported", [G]: k }, { conditions: E, error: "Invalid Configuration: Dualstack and custom endpoint are not supported", [G]: k }, { endpoint: { url: o, properties: v, headers: v }, [G]: h }], [G]: j }, { conditions: [p], rules: [{ conditions: [r], rules: [{ conditions: [x, y], rules: [{ conditions: [{ [H]: c, [I]: [b, z] }, B], rules: [{ endpoint: { url: "https://sts-fips.{Region}.{PartitionResult#dualStackDnsSuffix}", properties: v, headers: v }, [G]: h }], [G]: j }, { error: "FIPS and DualStack are enabled, but this partition does not support one or both", [G]: k }], [G]: j }, { conditions: D, rules: [{ conditions: [{ [H]: c, [I]: [z, b] }], rules: [{ conditions: [{ [H]: d, [I]: [{ [H]: l, [I]: [A, "name"] }, "aws-us-gov"] }], endpoint: { url: "https://sts.{Region}.amazonaws.com", properties: v, headers: v }, [G]: h }, { endpoint: { url: "https://sts-fips.{Region}.{PartitionResult#dnsSuffix}", properties: v, headers: v }, [G]: h }], [G]: j }, { error: "FIPS is enabled but this partition does not support FIPS", [G]: k }], [G]: j }, { conditions: E, rules: [{ conditions: [B], rules: [{ endpoint: { url: "https://sts.{Region}.{PartitionResult#dualStackDnsSuffix}", properties: v, headers: v }, [G]: h }], [G]: j }, { error: "DualStack is enabled but this partition does not support DualStack", [G]: k }], [G]: j }, w, { endpoint: { url: i, properties: v, headers: v }, [G]: h }], [G]: j }], [G]: j }, { error: "Invalid Configuration: Missing Region", [G]: k }] };
exports.ruleSet = _data;
/***/ }),
/***/ 1136:
/***/ ((__unused_webpack_module, exports, __webpack_require__) => {
var STSClient = __webpack_require__(3723);
var smithyClient = __webpack_require__(1411);
var middlewareEndpoint = __webpack_require__(99);
var EndpointParameters = __webpack_require__(6811);
var schema = __webpack_require__(6890);
var client = __webpack_require__(5152);
var regionConfigResolver = __webpack_require__(6463);
class STSServiceException extends smithyClient.ServiceException {
constructor(options) {
super(options);
Object.setPrototypeOf(this, STSServiceException.prototype);
}
}
class ExpiredTokenException extends STSServiceException {
name = "ExpiredTokenException";
$fault = "client";
constructor(opts) {
super({
name: "ExpiredTokenException",
$fault: "client",
...opts,
});
Object.setPrototypeOf(this, ExpiredTokenException.prototype);
}
}
class MalformedPolicyDocumentException extends STSServiceException {
name = "MalformedPolicyDocumentException";
$fault = "client";
constructor(opts) {
super({
name: "MalformedPolicyDocumentException",
$fault: "client",
...opts,
});
Object.setPrototypeOf(this, MalformedPolicyDocumentException.prototype);
}
}
class PackedPolicyTooLargeException extends STSServiceException {
name = "PackedPolicyTooLargeException";
$fault = "client";
constructor(opts) {
super({
name: "PackedPolicyTooLargeException",
$fault: "client",
...opts,
});
Object.setPrototypeOf(this, PackedPolicyTooLargeException.prototype);
}
}
class RegionDisabledException extends STSServiceException {
name = "RegionDisabledException";
$fault = "client";
constructor(opts) {
super({
name: "RegionDisabledException",
$fault: "client",
...opts,
});
Object.setPrototypeOf(this, RegionDisabledException.prototype);
}
}
class IDPRejectedClaimException extends STSServiceException {
name = "IDPRejectedClaimException";
$fault = "client";
constructor(opts) {
super({
name: "IDPRejectedClaimException",
$fault: "client",
...opts,
});
Object.setPrototypeOf(this, IDPRejectedClaimException.prototype);
}
}
class InvalidIdentityTokenException extends STSServiceException {
name = "InvalidIdentityTokenException";
$fault = "client";
constructor(opts) {
super({
name: "InvalidIdentityTokenException",
$fault: "client",
...opts,
});
Object.setPrototypeOf(this, InvalidIdentityTokenException.prototype);
}
}
class IDPCommunicationErrorException extends STSServiceException {
name = "IDPCommunicationErrorException";
$fault = "client";
constructor(opts) {
super({
name: "IDPCommunicationErrorException",
$fault: "client",
...opts,
});
Object.setPrototypeOf(this, IDPCommunicationErrorException.prototype);
}
}
const _A = "Arn";
const _AKI = "AccessKeyId";
const _AR = "AssumeRole";
const _ARI = "AssumedRoleId";
const _ARR = "AssumeRoleRequest";
const _ARRs = "AssumeRoleResponse";
const _ARU = "AssumedRoleUser";
const _ARWWI = "AssumeRoleWithWebIdentity";
const _ARWWIR = "AssumeRoleWithWebIdentityRequest";
const _ARWWIRs = "AssumeRoleWithWebIdentityResponse";
const _Au = "Audience";
const _C = "Credentials";
const _CA = "ContextAssertion";
const _DS = "DurationSeconds";
const _E = "Expiration";
const _EI = "ExternalId";
const _ETE = "ExpiredTokenException";
const _IDPCEE = "IDPCommunicationErrorException";
const _IDPRCE = "IDPRejectedClaimException";
const _IITE = "InvalidIdentityTokenException";
const _K = "Key";
const _MPDE = "MalformedPolicyDocumentException";
const _P = "Policy";
const _PA = "PolicyArns";
const _PAr = "ProviderArn";
const _PC = "ProvidedContexts";
const _PCLT = "ProvidedContextsListType";
const _PCr = "ProvidedContext";
const _PDT = "PolicyDescriptorType";
const _PI = "ProviderId";
const _PPS = "PackedPolicySize";
const _PPTLE = "PackedPolicyTooLargeException";
const _Pr = "Provider";
const _RA = "RoleArn";
const _RDE = "RegionDisabledException";
const _RSN = "RoleSessionName";
const _SAK = "SecretAccessKey";
const _SFWIT = "SubjectFromWebIdentityToken";
const _SI = "SourceIdentity";
const _SN = "SerialNumber";
const _ST = "SessionToken";
const _T = "Tags";
const _TC = "TokenCode";
const _TTK = "TransitiveTagKeys";
const _Ta = "Tag";
const _V = "Value";
const _WIT = "WebIdentityToken";
const _a = "arn";
const _aKST = "accessKeySecretType";
const _aQE = "awsQueryError";
const _c = "client";
const _cTT = "clientTokenType";
const _e = "error";
const _hE = "httpError";
const _m = "message";
const _pDLT = "policyDescriptorListType";
const _s = "smithy.ts.sdk.synthetic.com.amazonaws.sts";
const _tLT = "tagListType";
const n0 = "com.amazonaws.sts";
var accessKeySecretType = [0, n0, _aKST, 8, 0];
var clientTokenType = [0, n0, _cTT, 8, 0];
var AssumedRoleUser$ = [3, n0, _ARU, 0, [_ARI, _A], [0, 0], 2];
var AssumeRoleRequest$ = [
3,
n0,
_ARR,
0,
[_RA, _RSN, _PA, _P, _DS, _T, _TTK, _EI, _SN, _TC, _SI, _PC],
[0, 0, () => policyDescriptorListType, 0, 1, () => tagListType, 64 | 0, 0, 0, 0, 0, () => ProvidedContextsListType],
2,
];
var AssumeRoleResponse$ = [
3,
n0,
_ARRs,
0,
[_C, _ARU, _PPS, _SI],
[[() => Credentials$, 0], () => AssumedRoleUser$, 1, 0],
];
var AssumeRoleWithWebIdentityRequest$ = [
3,
n0,
_ARWWIR,
0,
[_RA, _RSN, _WIT, _PI, _PA, _P, _DS],
[0, 0, [() => clientTokenType, 0], 0, () => policyDescriptorListType, 0, 1],
3,
];
var AssumeRoleWithWebIdentityResponse$ = [
3,
n0,
_ARWWIRs,
0,
[_C, _SFWIT, _ARU, _PPS, _Pr, _Au, _SI],
[[() => Credentials$, 0], 0, () => AssumedRoleUser$, 1, 0, 0, 0],
];
var Credentials$ = [
3,
n0,
_C,
0,
[_AKI, _SAK, _ST, _E],
[0, [() => accessKeySecretType, 0], 0, 4],
4,
];
var ExpiredTokenException$ = [
-3,
n0,
_ETE,
{ [_aQE]: [`ExpiredTokenException`, 400], [_e]: _c, [_hE]: 400 },
[_m],
[0],
];
schema.TypeRegistry.for(n0).registerError(ExpiredTokenException$, ExpiredTokenException);
var IDPCommunicationErrorException$ = [
-3,
n0,
_IDPCEE,
{ [_aQE]: [`IDPCommunicationError`, 400], [_e]: _c, [_hE]: 400 },
[_m],
[0],
];
schema.TypeRegistry.for(n0).registerError(IDPCommunicationErrorException$, IDPCommunicationErrorException);
var IDPRejectedClaimException$ = [
-3,
n0,
_IDPRCE,
{ [_aQE]: [`IDPRejectedClaim`, 403], [_e]: _c, [_hE]: 403 },
[_m],
[0],
];
schema.TypeRegistry.for(n0).registerError(IDPRejectedClaimException$, IDPRejectedClaimException);
var InvalidIdentityTokenException$ = [
-3,
n0,
_IITE,
{ [_aQE]: [`InvalidIdentityToken`, 400], [_e]: _c, [_hE]: 400 },
[_m],
[0],
];
schema.TypeRegistry.for(n0).registerError(InvalidIdentityTokenException$, InvalidIdentityTokenException);
var MalformedPolicyDocumentException$ = [
-3,
n0,
_MPDE,
{ [_aQE]: [`MalformedPolicyDocument`, 400], [_e]: _c, [_hE]: 400 },
[_m],
[0],
];
schema.TypeRegistry.for(n0).registerError(MalformedPolicyDocumentException$, MalformedPolicyDocumentException);
var PackedPolicyTooLargeException$ = [
-3,
n0,
_PPTLE,
{ [_aQE]: [`PackedPolicyTooLarge`, 400], [_e]: _c, [_hE]: 400 },
[_m],
[0],
];
schema.TypeRegistry.for(n0).registerError(PackedPolicyTooLargeException$, PackedPolicyTooLargeException);
var PolicyDescriptorType$ = [3, n0, _PDT, 0, [_a], [0]];
var ProvidedContext$ = [3, n0, _PCr, 0, [_PAr, _CA], [0, 0]];
var RegionDisabledException$ = [
-3,
n0,
_RDE,
{ [_aQE]: [`RegionDisabledException`, 403], [_e]: _c, [_hE]: 403 },
[_m],
[0],
];
schema.TypeRegistry.for(n0).registerError(RegionDisabledException$, RegionDisabledException);
var Tag$ = [3, n0, _Ta, 0, [_K, _V], [0, 0], 2];
var STSServiceException$ = [-3, _s, "STSServiceException", 0, [], []];
schema.TypeRegistry.for(_s).registerError(STSServiceException$, STSServiceException);
var policyDescriptorListType = [1, n0, _pDLT, 0, () => PolicyDescriptorType$];
var ProvidedContextsListType = [1, n0, _PCLT, 0, () => ProvidedContext$];
var tagListType = [1, n0, _tLT, 0, () => Tag$];
var AssumeRole$ = [9, n0, _AR, 0, () => AssumeRoleRequest$, () => AssumeRoleResponse$];
var AssumeRoleWithWebIdentity$ = [
9,
n0,
_ARWWI,
0,
() => AssumeRoleWithWebIdentityRequest$,
() => AssumeRoleWithWebIdentityResponse$,
];
class AssumeRoleCommand extends smithyClient.Command
.classBuilder()
.ep(EndpointParameters.commonParams)
.m(function (Command, cs, config, o) {
return [middlewareEndpoint.getEndpointPlugin(config, Command.getEndpointParameterInstructions())];
})
.s("AWSSecurityTokenServiceV20110615", "AssumeRole", {})
.n("STSClient", "AssumeRoleCommand")
.sc(AssumeRole$)
.build() {
}
class AssumeRoleWithWebIdentityCommand extends smithyClient.Command
.classBuilder()
.ep(EndpointParameters.commonParams)
.m(function (Command, cs, config, o) {
return [middlewareEndpoint.getEndpointPlugin(config, Command.getEndpointParameterInstructions())];
})
.s("AWSSecurityTokenServiceV20110615", "AssumeRoleWithWebIdentity", {})
.n("STSClient", "AssumeRoleWithWebIdentityCommand")
.sc(AssumeRoleWithWebIdentity$)
.build() {
}
const commands = {
AssumeRoleCommand,
AssumeRoleWithWebIdentityCommand,
};
class STS extends STSClient.STSClient {
}
smithyClient.createAggregatedClient(commands, STS);
const getAccountIdFromAssumedRoleUser = (assumedRoleUser) => {
if (typeof assumedRoleUser?.Arn === "string") {
const arnComponents = assumedRoleUser.Arn.split(":");
if (arnComponents.length > 4 && arnComponents[4] !== "") {
return arnComponents[4];
}
}
return undefined;
};
const resolveRegion = async (_region, _parentRegion, credentialProviderLogger, loaderConfig = {}) => {
const region = typeof _region === "function" ? await _region() : _region;
const parentRegion = typeof _parentRegion === "function" ? await _parentRegion() : _parentRegion;
let stsDefaultRegion = "";
const resolvedRegion = region ?? parentRegion ?? (stsDefaultRegion = await regionConfigResolver.stsRegionDefaultResolver(loaderConfig)());
credentialProviderLogger?.debug?.("@aws-sdk/client-sts::resolveRegion", "accepting first of:", `${region} (credential provider clientConfig)`, `${parentRegion} (contextual client)`, `${stsDefaultRegion} (STS default: AWS_REGION, profile region, or us-east-1)`);
return resolvedRegion;
};
const getDefaultRoleAssumer$1 = (stsOptions, STSClient) => {
let stsClient;
let closureSourceCreds;
return async (sourceCreds, params) => {
closureSourceCreds = sourceCreds;
if (!stsClient) {
const { logger = stsOptions?.parentClientConfig?.logger, profile = stsOptions?.parentClientConfig?.profile, region, requestHandler = stsOptions?.parentClientConfig?.requestHandler, credentialProviderLogger, userAgentAppId = stsOptions?.parentClientConfig?.userAgentAppId, } = stsOptions;
const resolvedRegion = await resolveRegion(region, stsOptions?.parentClientConfig?.region, credentialProviderLogger, {
logger,
profile,
});
const isCompatibleRequestHandler = !isH2(requestHandler);
stsClient = new STSClient({
...stsOptions,
userAgentAppId,
profile,
credentialDefaultProvider: () => async () => closureSourceCreds,
region: resolvedRegion,
requestHandler: isCompatibleRequestHandler ? requestHandler : undefined,
logger: logger,
});
}
const { Credentials, AssumedRoleUser } = await stsClient.send(new AssumeRoleCommand(params));
if (!Credentials || !Credentials.AccessKeyId || !Credentials.SecretAccessKey) {
throw new Error(`Invalid response from STS.assumeRole call with role ${params.RoleArn}`);
}
const accountId = getAccountIdFromAssumedRoleUser(AssumedRoleUser);
const credentials = {
accessKeyId: Credentials.AccessKeyId,
secretAccessKey: Credentials.SecretAccessKey,
sessionToken: Credentials.SessionToken,
expiration: Credentials.Expiration,
...(Credentials.CredentialScope && { credentialScope: Credentials.CredentialScope }),
...(accountId && { accountId }),
};
client.setCredentialFeature(credentials, "CREDENTIALS_STS_ASSUME_ROLE", "i");
return credentials;
};
};
const getDefaultRoleAssumerWithWebIdentity$1 = (stsOptions, STSClient) => {
let stsClient;
return async (params) => {
if (!stsClient) {
const { logger = stsOptions?.parentClientConfig?.logger, profile = stsOptions?.parentClientConfig?.profile, region, requestHandler = stsOptions?.parentClientConfig?.requestHandler, credentialProviderLogger, userAgentAppId = stsOptions?.parentClientConfig?.userAgentAppId, } = stsOptions;
const resolvedRegion = await resolveRegion(region, stsOptions?.parentClientConfig?.region, credentialProviderLogger, {
logger,
profile,
});
const isCompatibleRequestHandler = !isH2(requestHandler);
stsClient = new STSClient({
...stsOptions,
userAgentAppId,
profile,
region: resolvedRegion,
requestHandler: isCompatibleRequestHandler ? requestHandler : undefined,
logger: logger,
});
}
const { Credentials, AssumedRoleUser } = await stsClient.send(new AssumeRoleWithWebIdentityCommand(params));
if (!Credentials || !Credentials.AccessKeyId || !Credentials.SecretAccessKey) {
throw new Error(`Invalid response from STS.assumeRoleWithWebIdentity call with role ${params.RoleArn}`);
}
const accountId = getAccountIdFromAssumedRoleUser(AssumedRoleUser);
const credentials = {
accessKeyId: Credentials.AccessKeyId,
secretAccessKey: Credentials.SecretAccessKey,
sessionToken: Credentials.SessionToken,
expiration: Credentials.Expiration,
...(Credentials.CredentialScope && { credentialScope: Credentials.CredentialScope }),
...(accountId && { accountId }),
};
if (accountId) {
client.setCredentialFeature(credentials, "RESOLVED_ACCOUNT_ID", "T");
}
client.setCredentialFeature(credentials, "CREDENTIALS_STS_ASSUME_ROLE_WEB_ID", "k");
return credentials;
};
};
const isH2 = (requestHandler) => {
return requestHandler?.metadata?.handlerProtocol === "h2";
};
const getCustomizableStsClientCtor = (baseCtor, customizations) => {
if (!customizations)
return baseCtor;
else
return class CustomizableSTSClient extends baseCtor {
constructor(config) {
super(config);
for (const customization of customizations) {
this.middlewareStack.use(customization);
}
}
};
};
const getDefaultRoleAssumer = (stsOptions = {}, stsPlugins) => getDefaultRoleAssumer$1(stsOptions, getCustomizableStsClientCtor(STSClient.STSClient, stsPlugins));
const getDefaultRoleAssumerWithWebIdentity = (stsOptions = {}, stsPlugins) => getDefaultRoleAssumerWithWebIdentity$1(stsOptions, getCustomizableStsClientCtor(STSClient.STSClient, stsPlugins));
const decorateDefaultCredentialProvider = (provider) => (input) => provider({
roleAssumer: getDefaultRoleAssumer(input),
roleAssumerWithWebIdentity: getDefaultRoleAssumerWithWebIdentity(input),
...input,
});
Object.defineProperty(exports, "$Command", ({
enumerable: true,
get: function () { return smithyClient.Command; }
}));
exports.AssumeRole$ = AssumeRole$;
exports.AssumeRoleCommand = AssumeRoleCommand;
exports.AssumeRoleRequest$ = AssumeRoleRequest$;
exports.AssumeRoleResponse$ = AssumeRoleResponse$;
exports.AssumeRoleWithWebIdentity$ = AssumeRoleWithWebIdentity$;
exports.AssumeRoleWithWebIdentityCommand = AssumeRoleWithWebIdentityCommand;
exports.AssumeRoleWithWebIdentityRequest$ = AssumeRoleWithWebIdentityRequest$;
exports.AssumeRoleWithWebIdentityResponse$ = AssumeRoleWithWebIdentityResponse$;
exports.AssumedRoleUser$ = AssumedRoleUser$;
exports.Credentials$ = Credentials$;
exports.ExpiredTokenException = ExpiredTokenException;
exports.ExpiredTokenException$ = ExpiredTokenException$;
exports.IDPCommunicationErrorException = IDPCommunicationErrorException;
exports.IDPCommunicationErrorException$ = IDPCommunicationErrorException$;
exports.IDPRejectedClaimException = IDPRejectedClaimException;
exports.IDPRejectedClaimException$ = IDPRejectedClaimException$;
exports.InvalidIdentityTokenException = InvalidIdentityTokenException;
exports.InvalidIdentityTokenException$ = InvalidIdentityTokenException$;
exports.MalformedPolicyDocumentException = MalformedPolicyDocumentException;
exports.MalformedPolicyDocumentException$ = MalformedPolicyDocumentException$;
exports.PackedPolicyTooLargeException = PackedPolicyTooLargeException;
exports.PackedPolicyTooLargeException$ = PackedPolicyTooLargeException$;
exports.PolicyDescriptorType$ = PolicyDescriptorType$;
exports.ProvidedContext$ = ProvidedContext$;
exports.RegionDisabledException = RegionDisabledException;
exports.RegionDisabledException$ = RegionDisabledException$;
exports.STS = STS;
exports.STSServiceException = STSServiceException;
exports.STSServiceException$ = STSServiceException$;
exports.Tag$ = Tag$;
exports.decorateDefaultCredentialProvider = decorateDefaultCredentialProvider;
exports.getDefaultRoleAssumer = getDefaultRoleAssumer;
exports.getDefaultRoleAssumerWithWebIdentity = getDefaultRoleAssumerWithWebIdentity;
Object.keys(STSClient).forEach(function (k) {
if (k !== 'default' && !Object.prototype.hasOwnProperty.call(exports, k)) Object.defineProperty(exports, k, {
enumerable: true,
get: function () { return STSClient[k]; }
});
});
/***/ }),
/***/ 6578:
/***/ ((__unused_webpack_module, exports, __webpack_require__) => {
Object.defineProperty(exports, "__esModule", ({ value: true }));
exports.getRuntimeConfig = void 0;
const tslib_1 = __webpack_require__(1860);
const package_json_1 = tslib_1.__importDefault(__webpack_require__(9955));
const core_1 = __webpack_require__(8704);
const util_user_agent_node_1 = __webpack_require__(1656);
const config_resolver_1 = __webpack_require__(9316);
const core_2 = __webpack_require__(402);
const hash_node_1 = __webpack_require__(2711);
const middleware_retry_1 = __webpack_require__(9618);
const node_config_provider_1 = __webpack_require__(5704);
const node_http_handler_1 = __webpack_require__(1279);
const smithy_client_1 = __webpack_require__(1411);
const util_body_length_node_1 = __webpack_require__(3638);
const util_defaults_mode_node_1 = __webpack_require__(5435);
const util_retry_1 = __webpack_require__(5518);
const runtimeConfig_shared_1 = __webpack_require__(4443);
const getRuntimeConfig = (config) => {
(0, smithy_client_1.emitWarningIfUnsupportedVersion)(process.version);
const defaultsMode = (0, util_defaults_mode_node_1.resolveDefaultsModeConfig)(config);
const defaultConfigProvider = () => defaultsMode().then(smithy_client_1.loadConfigsForDefaultMode);
const clientSharedValues = (0, runtimeConfig_shared_1.getRuntimeConfig)(config);
(0, core_1.emitWarningIfUnsupportedVersion)(process.version);
const loaderConfig = {
profile: config?.profile,
logger: clientSharedValues.logger,
};
return {
...clientSharedValues,
...config,
runtime: "node",
defaultsMode,
authSchemePreference: config?.authSchemePreference ?? (0, node_config_provider_1.loadConfig)(core_1.NODE_AUTH_SCHEME_PREFERENCE_OPTIONS, loaderConfig),
bodyLengthChecker: config?.bodyLengthChecker ?? util_body_length_node_1.calculateBodyLength,
defaultUserAgentProvider: config?.defaultUserAgentProvider ??
(0, util_user_agent_node_1.createDefaultUserAgentProvider)({ serviceId: clientSharedValues.serviceId, clientVersion: package_json_1.default.version }),
httpAuthSchemes: config?.httpAuthSchemes ?? [
{
schemeId: "aws.auth#sigv4",
identityProvider: (ipc) => ipc.getIdentityProvider("aws.auth#sigv4") ||
(async (idProps) => await config.credentialDefaultProvider(idProps?.__config || {})()),
signer: new core_1.AwsSdkSigV4Signer(),
},
{
schemeId: "smithy.api#noAuth",
identityProvider: (ipc) => ipc.getIdentityProvider("smithy.api#noAuth") || (async () => ({})),
signer: new core_2.NoAuthSigner(),
},
],
maxAttempts: config?.maxAttempts ?? (0, node_config_provider_1.loadConfig)(middleware_retry_1.NODE_MAX_ATTEMPT_CONFIG_OPTIONS, config),
region: config?.region ??
(0, node_config_provider_1.loadConfig)(config_resolver_1.NODE_REGION_CONFIG_OPTIONS, { ...config_resolver_1.NODE_REGION_CONFIG_FILE_OPTIONS, ...loaderConfig }),
requestHandler: node_http_handler_1.NodeHttpHandler.create(config?.requestHandler ?? defaultConfigProvider),
retryMode: config?.retryMode ??
(0, node_config_provider_1.loadConfig)({
...middleware_retry_1.NODE_RETRY_MODE_CONFIG_OPTIONS,
default: async () => (await defaultConfigProvider()).retryMode || util_retry_1.DEFAULT_RETRY_MODE,
}, config),
sha256: config?.sha256 ?? hash_node_1.Hash.bind(null, "sha256"),
streamCollector: config?.streamCollector ?? node_http_handler_1.streamCollector,
useDualstackEndpoint: config?.useDualstackEndpoint ?? (0, node_config_provider_1.loadConfig)(config_resolver_1.NODE_USE_DUALSTACK_ENDPOINT_CONFIG_OPTIONS, loaderConfig),
useFipsEndpoint: config?.useFipsEndpoint ?? (0, node_config_provider_1.loadConfig)(config_resolver_1.NODE_USE_FIPS_ENDPOINT_CONFIG_OPTIONS, loaderConfig),
userAgentAppId: config?.userAgentAppId ?? (0, node_config_provider_1.loadConfig)(util_user_agent_node_1.NODE_APP_ID_CONFIG_OPTIONS, loaderConfig),
};
};
exports.getRuntimeConfig = getRuntimeConfig;
/***/ }),
/***/ 4443:
/***/ ((__unused_webpack_module, exports, __webpack_require__) => {
Object.defineProperty(exports, "__esModule", ({ value: true }));
exports.getRuntimeConfig = void 0;
const core_1 = __webpack_require__(8704);
const protocols_1 = __webpack_require__(7288);
const core_2 = __webpack_require__(402);
const smithy_client_1 = __webpack_require__(1411);
const url_parser_1 = __webpack_require__(4494);
const util_base64_1 = __webpack_require__(8385);
const util_utf8_1 = __webpack_require__(1577);
const httpAuthSchemeProvider_1 = __webpack_require__(7851);
const endpointResolver_1 = __webpack_require__(9765);
const getRuntimeConfig = (config) => {
return {
apiVersion: "2011-06-15",
base64Decoder: config?.base64Decoder ?? util_base64_1.fromBase64,
base64Encoder: config?.base64Encoder ?? util_base64_1.toBase64,
disableHostPrefix: config?.disableHostPrefix ?? false,
endpointProvider: config?.endpointProvider ?? endpointResolver_1.defaultEndpointResolver,
extensions: config?.extensions ?? [],
httpAuthSchemeProvider: config?.httpAuthSchemeProvider ?? httpAuthSchemeProvider_1.defaultSTSHttpAuthSchemeProvider,
httpAuthSchemes: config?.httpAuthSchemes ?? [
{
schemeId: "aws.auth#sigv4",
identityProvider: (ipc) => ipc.getIdentityProvider("aws.auth#sigv4"),
signer: new core_1.AwsSdkSigV4Signer(),
},
{
schemeId: "smithy.api#noAuth",
identityProvider: (ipc) => ipc.getIdentityProvider("smithy.api#noAuth") || (async () => ({})),
signer: new core_2.NoAuthSigner(),
},
],
logger: config?.logger ?? new smithy_client_1.NoOpLogger(),
protocol: config?.protocol ?? protocols_1.AwsQueryProtocol,
protocolSettings: config?.protocolSettings ?? {
defaultNamespace: "com.amazonaws.sts",
xmlNamespace: "https://sts.amazonaws.com/doc/2011-06-15/",
version: "2011-06-15",
serviceTarget: "AWSSecurityTokenServiceV20110615",
},
serviceId: config?.serviceId ?? "STS",
urlParser: config?.urlParser ?? url_parser_1.parseUrl,
utf8Decoder: config?.utf8Decoder ?? util_utf8_1.fromUtf8,
utf8Encoder: config?.utf8Encoder ?? util_utf8_1.toUtf8,
};
};
exports.getRuntimeConfig = getRuntimeConfig;
/***/ }),
/***/ 7742:
/***/ ((__unused_webpack_module, exports, __webpack_require__) => {
Object.defineProperty(exports, "__esModule", ({ value: true }));
exports.resolveRuntimeExtensions = void 0;
const region_config_resolver_1 = __webpack_require__(6463);
const protocol_http_1 = __webpack_require__(2356);
const smithy_client_1 = __webpack_require__(1411);
const httpAuthExtensionConfiguration_1 = __webpack_require__(4532);
const resolveRuntimeExtensions = (runtimeConfig, extensions) => {
const extensionConfiguration = Object.assign((0, region_config_resolver_1.getAwsRegionExtensionConfiguration)(runtimeConfig), (0, smithy_client_1.getDefaultExtensionConfiguration)(runtimeConfig), (0, protocol_http_1.getHttpHandlerExtensionConfiguration)(runtimeConfig), (0, httpAuthExtensionConfiguration_1.getHttpAuthExtensionConfiguration)(runtimeConfig));
extensions.forEach((extension) => extension.configure(extensionConfiguration));
return Object.assign(runtimeConfig, (0, region_config_resolver_1.resolveAwsRegionExtensionConfiguration)(extensionConfiguration), (0, smithy_client_1.resolveDefaultRuntimeConfig)(extensionConfiguration), (0, protocol_http_1.resolveHttpHandlerRuntimeConfig)(extensionConfiguration), (0, httpAuthExtensionConfiguration_1.resolveHttpAuthRuntimeConfig)(extensionConfiguration));
};
exports.resolveRuntimeExtensions = resolveRuntimeExtensions;
/***/ }),
/***/ 9955:
/***/ ((module) => {
module.exports = /*#__PURE__*/JSON.parse('{"name":"@aws-sdk/nested-clients","version":"3.982.0","description":"Nested clients for AWS SDK packages.","main":"./dist-cjs/index.js","module":"./dist-es/index.js","types":"./dist-types/index.d.ts","scripts":{"build":"yarn lint && concurrently \'yarn:build:types\' \'yarn:build:es\' && yarn build:cjs","build:cjs":"node ../../scripts/compilation/inline nested-clients","build:es":"tsc -p tsconfig.es.json","build:include:deps":"yarn g:turbo run build -F=\\"$npm_package_name\\"","build:types":"tsc -p tsconfig.types.json","build:types:downlevel":"downlevel-dts dist-types dist-types/ts3.4","clean":"premove dist-cjs dist-es dist-types tsconfig.cjs.tsbuildinfo tsconfig.es.tsbuildinfo tsconfig.types.tsbuildinfo","lint":"node ../../scripts/validation/submodules-linter.js --pkg nested-clients","test":"yarn g:vitest run","test:watch":"yarn g:vitest watch"},"engines":{"node":">=20.0.0"},"sideEffects":false,"author":{"name":"AWS SDK for JavaScript Team","url":"https://aws.amazon.com/javascript/"},"license":"Apache-2.0","dependencies":{"@aws-crypto/sha256-browser":"5.2.0","@aws-crypto/sha256-js":"5.2.0","@aws-sdk/core":"^3.973.6","@aws-sdk/middleware-host-header":"^3.972.3","@aws-sdk/middleware-logger":"^3.972.3","@aws-sdk/middleware-recursion-detection":"^3.972.3","@aws-sdk/middleware-user-agent":"^3.972.6","@aws-sdk/region-config-resolver":"^3.972.3","@aws-sdk/types":"^3.973.1","@aws-sdk/util-endpoints":"3.982.0","@aws-sdk/util-user-agent-browser":"^3.972.3","@aws-sdk/util-user-agent-node":"^3.972.4","@smithy/config-resolver":"^4.4.6","@smithy/core":"^3.22.0","@smithy/fetch-http-handler":"^5.3.9","@smithy/hash-node":"^4.2.8","@smithy/invalid-dependency":"^4.2.8","@smithy/middleware-content-length":"^4.2.8","@smithy/middleware-endpoint":"^4.4.12","@smithy/middleware-retry":"^4.4.29","@smithy/middleware-serde":"^4.2.9","@smithy/middleware-stack":"^4.2.8","@smithy/node-config-provider":"^4.3.8","@smithy/node-http-handler":"^4.4.8","@smithy/protocol-http":"^5.3.8","@smithy/smithy-client":"^4.11.1","@smithy/types":"^4.12.0","@smithy/url-parser":"^4.2.8","@smithy/util-base64":"^4.3.0","@smithy/util-body-length-browser":"^4.2.0","@smithy/util-body-length-node":"^4.2.1","@smithy/util-defaults-mode-browser":"^4.3.28","@smithy/util-defaults-mode-node":"^4.2.31","@smithy/util-endpoints":"^3.2.8","@smithy/util-middleware":"^4.2.8","@smithy/util-retry":"^4.2.8","@smithy/util-utf8":"^4.2.0","tslib":"^2.6.2"},"devDependencies":{"concurrently":"7.0.0","downlevel-dts":"0.10.1","premove":"4.0.0","typescript":"~5.8.3"},"typesVersions":{"<4.0":{"dist-types/*":["dist-types/ts3.4/*"]}},"files":["./signin.d.ts","./signin.js","./sso-oidc.d.ts","./sso-oidc.js","./sts.d.ts","./sts.js","dist-*/**"],"browser":{"./dist-es/submodules/signin/runtimeConfig":"./dist-es/submodules/signin/runtimeConfig.browser","./dist-es/submodules/sso-oidc/runtimeConfig":"./dist-es/submodules/sso-oidc/runtimeConfig.browser","./dist-es/submodules/sts/runtimeConfig":"./dist-es/submodules/sts/runtimeConfig.browser"},"react-native":{},"homepage":"https://github.com/aws/aws-sdk-js-v3/tree/main/packages/nested-clients","repository":{"type":"git","url":"https://github.com/aws/aws-sdk-js-v3.git","directory":"packages/nested-clients"},"exports":{"./package.json":"./package.json","./sso-oidc":{"types":"./dist-types/submodules/sso-oidc/index.d.ts","module":"./dist-es/submodules/sso-oidc/index.js","node":"./dist-cjs/submodules/sso-oidc/index.js","import":"./dist-es/submodules/sso-oidc/index.js","require":"./dist-cjs/submodules/sso-oidc/index.js"},"./sts":{"types":"./dist-types/submodules/sts/index.d.ts","module":"./dist-es/submodules/sts/index.js","node":"./dist-cjs/submodules/sts/index.js","import":"./dist-es/submodules/sts/index.js","require":"./dist-cjs/submodules/sts/index.js"},"./signin":{"types":"./dist-types/submodules/signin/index.d.ts","module":"./dist-es/submodules/signin/index.js","node":"./dist-cjs/submodules/signin/index.js","import":"./dist-es/submodules/signin/index.js","require":"./dist-cjs/submodules/signin/index.js"}}}');
/***/ })
};
;
@@ -0,0 +1,93 @@
"use strict";
exports.id = 360;
exports.ids = [360];
exports.modules = {
/***/ 5360:
/***/ ((__unused_webpack_module, exports, __webpack_require__) => {
var sharedIniFileLoader = __webpack_require__(4964);
var propertyProvider = __webpack_require__(8857);
var child_process = __webpack_require__(5317);
var util = __webpack_require__(9023);
var client = __webpack_require__(5152);
const getValidatedProcessCredentials = (profileName, data, profiles) => {
if (data.Version !== 1) {
throw Error(`Profile ${profileName} credential_process did not return Version 1.`);
}
if (data.AccessKeyId === undefined || data.SecretAccessKey === undefined) {
throw Error(`Profile ${profileName} credential_process returned invalid credentials.`);
}
if (data.Expiration) {
const currentTime = new Date();
const expireTime = new Date(data.Expiration);
if (expireTime < currentTime) {
throw Error(`Profile ${profileName} credential_process returned expired credentials.`);
}
}
let accountId = data.AccountId;
if (!accountId && profiles?.[profileName]?.aws_account_id) {
accountId = profiles[profileName].aws_account_id;
}
const credentials = {
accessKeyId: data.AccessKeyId,
secretAccessKey: data.SecretAccessKey,
...(data.SessionToken && { sessionToken: data.SessionToken }),
...(data.Expiration && { expiration: new Date(data.Expiration) }),
...(data.CredentialScope && { credentialScope: data.CredentialScope }),
...(accountId && { accountId }),
};
client.setCredentialFeature(credentials, "CREDENTIALS_PROCESS", "w");
return credentials;
};
const resolveProcessCredentials = async (profileName, profiles, logger) => {
const profile = profiles[profileName];
if (profiles[profileName]) {
const credentialProcess = profile["credential_process"];
if (credentialProcess !== undefined) {
const execPromise = util.promisify(sharedIniFileLoader.externalDataInterceptor?.getTokenRecord?.().exec ?? child_process.exec);
try {
const { stdout } = await execPromise(credentialProcess);
let data;
try {
data = JSON.parse(stdout.trim());
}
catch {
throw Error(`Profile ${profileName} credential_process returned invalid JSON.`);
}
return getValidatedProcessCredentials(profileName, data, profiles);
}
catch (error) {
throw new propertyProvider.CredentialsProviderError(error.message, { logger });
}
}
else {
throw new propertyProvider.CredentialsProviderError(`Profile ${profileName} did not contain credential_process.`, { logger });
}
}
else {
throw new propertyProvider.CredentialsProviderError(`Profile ${profileName} could not be found in shared credentials file.`, {
logger,
});
}
};
const fromProcess = (init = {}) => async ({ callerClientConfig } = {}) => {
init.logger?.debug("@aws-sdk/credential-provider-process - fromProcess");
const profiles = await sharedIniFileLoader.parseKnownFiles(init);
return resolveProcessCredentials(sharedIniFileLoader.getProfileName({
profile: init.profile ?? callerClientConfig?.profile,
}), profiles, init.logger);
};
exports.fromProcess = fromProcess;
/***/ })
};
;
@@ -0,0 +1,738 @@
"use strict";
exports.id = 443;
exports.ids = [443];
exports.modules = {
/***/ 8396:
/***/ ((__unused_webpack_module, exports, __webpack_require__) => {
Object.defineProperty(exports, "__esModule", ({ value: true }));
exports.resolveHttpAuthSchemeConfig = exports.defaultSSOOIDCHttpAuthSchemeProvider = exports.defaultSSOOIDCHttpAuthSchemeParametersProvider = void 0;
const core_1 = __webpack_require__(8704);
const util_middleware_1 = __webpack_require__(6324);
const defaultSSOOIDCHttpAuthSchemeParametersProvider = async (config, context, input) => {
return {
operation: (0, util_middleware_1.getSmithyContext)(context).operation,
region: (await (0, util_middleware_1.normalizeProvider)(config.region)()) ||
(() => {
throw new Error("expected `region` to be configured for `aws.auth#sigv4`");
})(),
};
};
exports.defaultSSOOIDCHttpAuthSchemeParametersProvider = defaultSSOOIDCHttpAuthSchemeParametersProvider;
function createAwsAuthSigv4HttpAuthOption(authParameters) {
return {
schemeId: "aws.auth#sigv4",
signingProperties: {
name: "sso-oauth",
region: authParameters.region,
},
propertiesExtractor: (config, context) => ({
signingProperties: {
config,
context,
},
}),
};
}
function createSmithyApiNoAuthHttpAuthOption(authParameters) {
return {
schemeId: "smithy.api#noAuth",
};
}
const defaultSSOOIDCHttpAuthSchemeProvider = (authParameters) => {
const options = [];
switch (authParameters.operation) {
case "CreateToken": {
options.push(createSmithyApiNoAuthHttpAuthOption(authParameters));
break;
}
default: {
options.push(createAwsAuthSigv4HttpAuthOption(authParameters));
}
}
return options;
};
exports.defaultSSOOIDCHttpAuthSchemeProvider = defaultSSOOIDCHttpAuthSchemeProvider;
const resolveHttpAuthSchemeConfig = (config) => {
const config_0 = (0, core_1.resolveAwsSdkSigV4Config)(config);
return Object.assign(config_0, {
authSchemePreference: (0, util_middleware_1.normalizeProvider)(config.authSchemePreference ?? []),
});
};
exports.resolveHttpAuthSchemeConfig = resolveHttpAuthSchemeConfig;
/***/ }),
/***/ 546:
/***/ ((__unused_webpack_module, exports, __webpack_require__) => {
Object.defineProperty(exports, "__esModule", ({ value: true }));
exports.defaultEndpointResolver = void 0;
const util_endpoints_1 = __webpack_require__(3068);
const util_endpoints_2 = __webpack_require__(9674);
const ruleset_1 = __webpack_require__(9947);
const cache = new util_endpoints_2.EndpointCache({
size: 50,
params: ["Endpoint", "Region", "UseDualStack", "UseFIPS"],
});
const defaultEndpointResolver = (endpointParams, context = {}) => {
return cache.get(endpointParams, () => (0, util_endpoints_2.resolveEndpoint)(ruleset_1.ruleSet, {
endpointParams: endpointParams,
logger: context.logger,
}));
};
exports.defaultEndpointResolver = defaultEndpointResolver;
util_endpoints_2.customEndpointFunctions.aws = util_endpoints_1.awsEndpointFunctions;
/***/ }),
/***/ 9947:
/***/ ((__unused_webpack_module, exports) => {
Object.defineProperty(exports, "__esModule", ({ value: true }));
exports.ruleSet = void 0;
const u = "required", v = "fn", w = "argv", x = "ref";
const a = true, b = "isSet", c = "booleanEquals", d = "error", e = "endpoint", f = "tree", g = "PartitionResult", h = "getAttr", i = { [u]: false, "type": "string" }, j = { [u]: true, "default": false, "type": "boolean" }, k = { [x]: "Endpoint" }, l = { [v]: c, [w]: [{ [x]: "UseFIPS" }, true] }, m = { [v]: c, [w]: [{ [x]: "UseDualStack" }, true] }, n = {}, o = { [v]: h, [w]: [{ [x]: g }, "supportsFIPS"] }, p = { [x]: g }, q = { [v]: c, [w]: [true, { [v]: h, [w]: [p, "supportsDualStack"] }] }, r = [l], s = [m], t = [{ [x]: "Region" }];
const _data = { version: "1.0", parameters: { Region: i, UseDualStack: j, UseFIPS: j, Endpoint: i }, rules: [{ conditions: [{ [v]: b, [w]: [k] }], rules: [{ conditions: r, error: "Invalid Configuration: FIPS and custom endpoint are not supported", type: d }, { conditions: s, error: "Invalid Configuration: Dualstack and custom endpoint are not supported", type: d }, { endpoint: { url: k, properties: n, headers: n }, type: e }], type: f }, { conditions: [{ [v]: b, [w]: t }], rules: [{ conditions: [{ [v]: "aws.partition", [w]: t, assign: g }], rules: [{ conditions: [l, m], rules: [{ conditions: [{ [v]: c, [w]: [a, o] }, q], rules: [{ endpoint: { url: "https://oidc-fips.{Region}.{PartitionResult#dualStackDnsSuffix}", properties: n, headers: n }, type: e }], type: f }, { error: "FIPS and DualStack are enabled, but this partition does not support one or both", type: d }], type: f }, { conditions: r, rules: [{ conditions: [{ [v]: c, [w]: [o, a] }], rules: [{ conditions: [{ [v]: "stringEquals", [w]: [{ [v]: h, [w]: [p, "name"] }, "aws-us-gov"] }], endpoint: { url: "https://oidc.{Region}.amazonaws.com", properties: n, headers: n }, type: e }, { endpoint: { url: "https://oidc-fips.{Region}.{PartitionResult#dnsSuffix}", properties: n, headers: n }, type: e }], type: f }, { error: "FIPS is enabled but this partition does not support FIPS", type: d }], type: f }, { conditions: s, rules: [{ conditions: [q], rules: [{ endpoint: { url: "https://oidc.{Region}.{PartitionResult#dualStackDnsSuffix}", properties: n, headers: n }, type: e }], type: f }, { error: "DualStack is enabled but this partition does not support DualStack", type: d }], type: f }, { endpoint: { url: "https://oidc.{Region}.{PartitionResult#dnsSuffix}", properties: n, headers: n }, type: e }], type: f }], type: f }, { error: "Invalid Configuration: Missing Region", type: d }] };
exports.ruleSet = _data;
/***/ }),
/***/ 9443:
/***/ ((__unused_webpack_module, exports, __webpack_require__) => {
var __webpack_unused_export__;
var middlewareHostHeader = __webpack_require__(2590);
var middlewareLogger = __webpack_require__(5242);
var middlewareRecursionDetection = __webpack_require__(1568);
var middlewareUserAgent = __webpack_require__(2959);
var configResolver = __webpack_require__(9316);
var core = __webpack_require__(402);
var schema = __webpack_require__(6890);
var middlewareContentLength = __webpack_require__(7212);
var middlewareEndpoint = __webpack_require__(99);
var middlewareRetry = __webpack_require__(9618);
var smithyClient = __webpack_require__(1411);
var httpAuthSchemeProvider = __webpack_require__(8396);
var runtimeConfig = __webpack_require__(6901);
var regionConfigResolver = __webpack_require__(6463);
var protocolHttp = __webpack_require__(2356);
const resolveClientEndpointParameters = (options) => {
return Object.assign(options, {
useDualstackEndpoint: options.useDualstackEndpoint ?? false,
useFipsEndpoint: options.useFipsEndpoint ?? false,
defaultSigningName: "sso-oauth",
});
};
const commonParams = {
UseFIPS: { type: "builtInParams", name: "useFipsEndpoint" },
Endpoint: { type: "builtInParams", name: "endpoint" },
Region: { type: "builtInParams", name: "region" },
UseDualStack: { type: "builtInParams", name: "useDualstackEndpoint" },
};
const getHttpAuthExtensionConfiguration = (runtimeConfig) => {
const _httpAuthSchemes = runtimeConfig.httpAuthSchemes;
let _httpAuthSchemeProvider = runtimeConfig.httpAuthSchemeProvider;
let _credentials = runtimeConfig.credentials;
return {
setHttpAuthScheme(httpAuthScheme) {
const index = _httpAuthSchemes.findIndex((scheme) => scheme.schemeId === httpAuthScheme.schemeId);
if (index === -1) {
_httpAuthSchemes.push(httpAuthScheme);
}
else {
_httpAuthSchemes.splice(index, 1, httpAuthScheme);
}
},
httpAuthSchemes() {
return _httpAuthSchemes;
},
setHttpAuthSchemeProvider(httpAuthSchemeProvider) {
_httpAuthSchemeProvider = httpAuthSchemeProvider;
},
httpAuthSchemeProvider() {
return _httpAuthSchemeProvider;
},
setCredentials(credentials) {
_credentials = credentials;
},
credentials() {
return _credentials;
},
};
};
const resolveHttpAuthRuntimeConfig = (config) => {
return {
httpAuthSchemes: config.httpAuthSchemes(),
httpAuthSchemeProvider: config.httpAuthSchemeProvider(),
credentials: config.credentials(),
};
};
const resolveRuntimeExtensions = (runtimeConfig, extensions) => {
const extensionConfiguration = Object.assign(regionConfigResolver.getAwsRegionExtensionConfiguration(runtimeConfig), smithyClient.getDefaultExtensionConfiguration(runtimeConfig), protocolHttp.getHttpHandlerExtensionConfiguration(runtimeConfig), getHttpAuthExtensionConfiguration(runtimeConfig));
extensions.forEach((extension) => extension.configure(extensionConfiguration));
return Object.assign(runtimeConfig, regionConfigResolver.resolveAwsRegionExtensionConfiguration(extensionConfiguration), smithyClient.resolveDefaultRuntimeConfig(extensionConfiguration), protocolHttp.resolveHttpHandlerRuntimeConfig(extensionConfiguration), resolveHttpAuthRuntimeConfig(extensionConfiguration));
};
class SSOOIDCClient extends smithyClient.Client {
config;
constructor(...[configuration]) {
const _config_0 = runtimeConfig.getRuntimeConfig(configuration || {});
super(_config_0);
this.initConfig = _config_0;
const _config_1 = resolveClientEndpointParameters(_config_0);
const _config_2 = middlewareUserAgent.resolveUserAgentConfig(_config_1);
const _config_3 = middlewareRetry.resolveRetryConfig(_config_2);
const _config_4 = configResolver.resolveRegionConfig(_config_3);
const _config_5 = middlewareHostHeader.resolveHostHeaderConfig(_config_4);
const _config_6 = middlewareEndpoint.resolveEndpointConfig(_config_5);
const _config_7 = httpAuthSchemeProvider.resolveHttpAuthSchemeConfig(_config_6);
const _config_8 = resolveRuntimeExtensions(_config_7, configuration?.extensions || []);
this.config = _config_8;
this.middlewareStack.use(schema.getSchemaSerdePlugin(this.config));
this.middlewareStack.use(middlewareUserAgent.getUserAgentPlugin(this.config));
this.middlewareStack.use(middlewareRetry.getRetryPlugin(this.config));
this.middlewareStack.use(middlewareContentLength.getContentLengthPlugin(this.config));
this.middlewareStack.use(middlewareHostHeader.getHostHeaderPlugin(this.config));
this.middlewareStack.use(middlewareLogger.getLoggerPlugin(this.config));
this.middlewareStack.use(middlewareRecursionDetection.getRecursionDetectionPlugin(this.config));
this.middlewareStack.use(core.getHttpAuthSchemeEndpointRuleSetPlugin(this.config, {
httpAuthSchemeParametersProvider: httpAuthSchemeProvider.defaultSSOOIDCHttpAuthSchemeParametersProvider,
identityProviderConfigProvider: async (config) => new core.DefaultIdentityProviderConfig({
"aws.auth#sigv4": config.credentials,
}),
}));
this.middlewareStack.use(core.getHttpSigningPlugin(this.config));
}
destroy() {
super.destroy();
}
}
class SSOOIDCServiceException extends smithyClient.ServiceException {
constructor(options) {
super(options);
Object.setPrototypeOf(this, SSOOIDCServiceException.prototype);
}
}
class AccessDeniedException extends SSOOIDCServiceException {
name = "AccessDeniedException";
$fault = "client";
error;
reason;
error_description;
constructor(opts) {
super({
name: "AccessDeniedException",
$fault: "client",
...opts,
});
Object.setPrototypeOf(this, AccessDeniedException.prototype);
this.error = opts.error;
this.reason = opts.reason;
this.error_description = opts.error_description;
}
}
class AuthorizationPendingException extends SSOOIDCServiceException {
name = "AuthorizationPendingException";
$fault = "client";
error;
error_description;
constructor(opts) {
super({
name: "AuthorizationPendingException",
$fault: "client",
...opts,
});
Object.setPrototypeOf(this, AuthorizationPendingException.prototype);
this.error = opts.error;
this.error_description = opts.error_description;
}
}
class ExpiredTokenException extends SSOOIDCServiceException {
name = "ExpiredTokenException";
$fault = "client";
error;
error_description;
constructor(opts) {
super({
name: "ExpiredTokenException",
$fault: "client",
...opts,
});
Object.setPrototypeOf(this, ExpiredTokenException.prototype);
this.error = opts.error;
this.error_description = opts.error_description;
}
}
class InternalServerException extends SSOOIDCServiceException {
name = "InternalServerException";
$fault = "server";
error;
error_description;
constructor(opts) {
super({
name: "InternalServerException",
$fault: "server",
...opts,
});
Object.setPrototypeOf(this, InternalServerException.prototype);
this.error = opts.error;
this.error_description = opts.error_description;
}
}
class InvalidClientException extends SSOOIDCServiceException {
name = "InvalidClientException";
$fault = "client";
error;
error_description;
constructor(opts) {
super({
name: "InvalidClientException",
$fault: "client",
...opts,
});
Object.setPrototypeOf(this, InvalidClientException.prototype);
this.error = opts.error;
this.error_description = opts.error_description;
}
}
class InvalidGrantException extends SSOOIDCServiceException {
name = "InvalidGrantException";
$fault = "client";
error;
error_description;
constructor(opts) {
super({
name: "InvalidGrantException",
$fault: "client",
...opts,
});
Object.setPrototypeOf(this, InvalidGrantException.prototype);
this.error = opts.error;
this.error_description = opts.error_description;
}
}
class InvalidRequestException extends SSOOIDCServiceException {
name = "InvalidRequestException";
$fault = "client";
error;
reason;
error_description;
constructor(opts) {
super({
name: "InvalidRequestException",
$fault: "client",
...opts,
});
Object.setPrototypeOf(this, InvalidRequestException.prototype);
this.error = opts.error;
this.reason = opts.reason;
this.error_description = opts.error_description;
}
}
class InvalidScopeException extends SSOOIDCServiceException {
name = "InvalidScopeException";
$fault = "client";
error;
error_description;
constructor(opts) {
super({
name: "InvalidScopeException",
$fault: "client",
...opts,
});
Object.setPrototypeOf(this, InvalidScopeException.prototype);
this.error = opts.error;
this.error_description = opts.error_description;
}
}
class SlowDownException extends SSOOIDCServiceException {
name = "SlowDownException";
$fault = "client";
error;
error_description;
constructor(opts) {
super({
name: "SlowDownException",
$fault: "client",
...opts,
});
Object.setPrototypeOf(this, SlowDownException.prototype);
this.error = opts.error;
this.error_description = opts.error_description;
}
}
class UnauthorizedClientException extends SSOOIDCServiceException {
name = "UnauthorizedClientException";
$fault = "client";
error;
error_description;
constructor(opts) {
super({
name: "UnauthorizedClientException",
$fault: "client",
...opts,
});
Object.setPrototypeOf(this, UnauthorizedClientException.prototype);
this.error = opts.error;
this.error_description = opts.error_description;
}
}
class UnsupportedGrantTypeException extends SSOOIDCServiceException {
name = "UnsupportedGrantTypeException";
$fault = "client";
error;
error_description;
constructor(opts) {
super({
name: "UnsupportedGrantTypeException",
$fault: "client",
...opts,
});
Object.setPrototypeOf(this, UnsupportedGrantTypeException.prototype);
this.error = opts.error;
this.error_description = opts.error_description;
}
}
const _ADE = "AccessDeniedException";
const _APE = "AuthorizationPendingException";
const _AT = "AccessToken";
const _CS = "ClientSecret";
const _CT = "CreateToken";
const _CTR = "CreateTokenRequest";
const _CTRr = "CreateTokenResponse";
const _CV = "CodeVerifier";
const _ETE = "ExpiredTokenException";
const _ICE = "InvalidClientException";
const _IGE = "InvalidGrantException";
const _IRE = "InvalidRequestException";
const _ISE = "InternalServerException";
const _ISEn = "InvalidScopeException";
const _IT = "IdToken";
const _RT = "RefreshToken";
const _SDE = "SlowDownException";
const _UCE = "UnauthorizedClientException";
const _UGTE = "UnsupportedGrantTypeException";
const _aT = "accessToken";
const _c = "client";
const _cI = "clientId";
const _cS = "clientSecret";
const _cV = "codeVerifier";
const _co = "code";
const _dC = "deviceCode";
const _e = "error";
const _eI = "expiresIn";
const _ed = "error_description";
const _gT = "grantType";
const _h = "http";
const _hE = "httpError";
const _iT = "idToken";
const _r = "reason";
const _rT = "refreshToken";
const _rU = "redirectUri";
const _s = "scope";
const _se = "server";
const _sm = "smithy.ts.sdk.synthetic.com.amazonaws.ssooidc";
const _tT = "tokenType";
const n0 = "com.amazonaws.ssooidc";
var AccessToken = [0, n0, _AT, 8, 0];
var ClientSecret = [0, n0, _CS, 8, 0];
var CodeVerifier = [0, n0, _CV, 8, 0];
var IdToken = [0, n0, _IT, 8, 0];
var RefreshToken = [0, n0, _RT, 8, 0];
var AccessDeniedException$ = [
-3,
n0,
_ADE,
{ [_e]: _c, [_hE]: 400 },
[_e, _r, _ed],
[0, 0, 0],
];
schema.TypeRegistry.for(n0).registerError(AccessDeniedException$, AccessDeniedException);
var AuthorizationPendingException$ = [
-3,
n0,
_APE,
{ [_e]: _c, [_hE]: 400 },
[_e, _ed],
[0, 0],
];
schema.TypeRegistry.for(n0).registerError(AuthorizationPendingException$, AuthorizationPendingException);
var CreateTokenRequest$ = [
3,
n0,
_CTR,
0,
[_cI, _cS, _gT, _dC, _co, _rT, _s, _rU, _cV],
[0, [() => ClientSecret, 0], 0, 0, 0, [() => RefreshToken, 0], 64 | 0, 0, [() => CodeVerifier, 0]],
3,
];
var CreateTokenResponse$ = [
3,
n0,
_CTRr,
0,
[_aT, _tT, _eI, _rT, _iT],
[[() => AccessToken, 0], 0, 1, [() => RefreshToken, 0], [() => IdToken, 0]],
];
var ExpiredTokenException$ = [-3, n0, _ETE, { [_e]: _c, [_hE]: 400 }, [_e, _ed], [0, 0]];
schema.TypeRegistry.for(n0).registerError(ExpiredTokenException$, ExpiredTokenException);
var InternalServerException$ = [-3, n0, _ISE, { [_e]: _se, [_hE]: 500 }, [_e, _ed], [0, 0]];
schema.TypeRegistry.for(n0).registerError(InternalServerException$, InternalServerException);
var InvalidClientException$ = [-3, n0, _ICE, { [_e]: _c, [_hE]: 401 }, [_e, _ed], [0, 0]];
schema.TypeRegistry.for(n0).registerError(InvalidClientException$, InvalidClientException);
var InvalidGrantException$ = [-3, n0, _IGE, { [_e]: _c, [_hE]: 400 }, [_e, _ed], [0, 0]];
schema.TypeRegistry.for(n0).registerError(InvalidGrantException$, InvalidGrantException);
var InvalidRequestException$ = [
-3,
n0,
_IRE,
{ [_e]: _c, [_hE]: 400 },
[_e, _r, _ed],
[0, 0, 0],
];
schema.TypeRegistry.for(n0).registerError(InvalidRequestException$, InvalidRequestException);
var InvalidScopeException$ = [-3, n0, _ISEn, { [_e]: _c, [_hE]: 400 }, [_e, _ed], [0, 0]];
schema.TypeRegistry.for(n0).registerError(InvalidScopeException$, InvalidScopeException);
var SlowDownException$ = [-3, n0, _SDE, { [_e]: _c, [_hE]: 400 }, [_e, _ed], [0, 0]];
schema.TypeRegistry.for(n0).registerError(SlowDownException$, SlowDownException);
var UnauthorizedClientException$ = [
-3,
n0,
_UCE,
{ [_e]: _c, [_hE]: 400 },
[_e, _ed],
[0, 0],
];
schema.TypeRegistry.for(n0).registerError(UnauthorizedClientException$, UnauthorizedClientException);
var UnsupportedGrantTypeException$ = [
-3,
n0,
_UGTE,
{ [_e]: _c, [_hE]: 400 },
[_e, _ed],
[0, 0],
];
schema.TypeRegistry.for(n0).registerError(UnsupportedGrantTypeException$, UnsupportedGrantTypeException);
var SSOOIDCServiceException$ = [-3, _sm, "SSOOIDCServiceException", 0, [], []];
schema.TypeRegistry.for(_sm).registerError(SSOOIDCServiceException$, SSOOIDCServiceException);
var CreateToken$ = [
9,
n0,
_CT,
{ [_h]: ["POST", "/token", 200] },
() => CreateTokenRequest$,
() => CreateTokenResponse$,
];
class CreateTokenCommand extends smithyClient.Command
.classBuilder()
.ep(commonParams)
.m(function (Command, cs, config, o) {
return [middlewareEndpoint.getEndpointPlugin(config, Command.getEndpointParameterInstructions())];
})
.s("AWSSSOOIDCService", "CreateToken", {})
.n("SSOOIDCClient", "CreateTokenCommand")
.sc(CreateToken$)
.build() {
}
const commands = {
CreateTokenCommand,
};
class SSOOIDC extends SSOOIDCClient {
}
smithyClient.createAggregatedClient(commands, SSOOIDC);
const AccessDeniedExceptionReason = {
KMS_ACCESS_DENIED: "KMS_AccessDeniedException",
};
const InvalidRequestExceptionReason = {
KMS_DISABLED_KEY: "KMS_DisabledException",
KMS_INVALID_KEY_USAGE: "KMS_InvalidKeyUsageException",
KMS_INVALID_STATE: "KMS_InvalidStateException",
KMS_KEY_NOT_FOUND: "KMS_NotFoundException",
};
__webpack_unused_export__ = ({
enumerable: true,
get: function () { return smithyClient.Command; }
});
__webpack_unused_export__ = ({
enumerable: true,
get: function () { return smithyClient.Client; }
});
__webpack_unused_export__ = AccessDeniedException;
__webpack_unused_export__ = AccessDeniedException$;
__webpack_unused_export__ = AccessDeniedExceptionReason;
__webpack_unused_export__ = AuthorizationPendingException;
__webpack_unused_export__ = AuthorizationPendingException$;
__webpack_unused_export__ = CreateToken$;
exports.CreateTokenCommand = CreateTokenCommand;
__webpack_unused_export__ = CreateTokenRequest$;
__webpack_unused_export__ = CreateTokenResponse$;
__webpack_unused_export__ = ExpiredTokenException;
__webpack_unused_export__ = ExpiredTokenException$;
__webpack_unused_export__ = InternalServerException;
__webpack_unused_export__ = InternalServerException$;
__webpack_unused_export__ = InvalidClientException;
__webpack_unused_export__ = InvalidClientException$;
__webpack_unused_export__ = InvalidGrantException;
__webpack_unused_export__ = InvalidGrantException$;
__webpack_unused_export__ = InvalidRequestException;
__webpack_unused_export__ = InvalidRequestException$;
__webpack_unused_export__ = InvalidRequestExceptionReason;
__webpack_unused_export__ = InvalidScopeException;
__webpack_unused_export__ = InvalidScopeException$;
__webpack_unused_export__ = SSOOIDC;
exports.SSOOIDCClient = SSOOIDCClient;
__webpack_unused_export__ = SSOOIDCServiceException;
__webpack_unused_export__ = SSOOIDCServiceException$;
__webpack_unused_export__ = SlowDownException;
__webpack_unused_export__ = SlowDownException$;
__webpack_unused_export__ = UnauthorizedClientException;
__webpack_unused_export__ = UnauthorizedClientException$;
__webpack_unused_export__ = UnsupportedGrantTypeException;
__webpack_unused_export__ = UnsupportedGrantTypeException$;
/***/ }),
/***/ 6901:
/***/ ((__unused_webpack_module, exports, __webpack_require__) => {
Object.defineProperty(exports, "__esModule", ({ value: true }));
exports.getRuntimeConfig = void 0;
const tslib_1 = __webpack_require__(1860);
const package_json_1 = tslib_1.__importDefault(__webpack_require__(9955));
const core_1 = __webpack_require__(8704);
const util_user_agent_node_1 = __webpack_require__(1656);
const config_resolver_1 = __webpack_require__(9316);
const hash_node_1 = __webpack_require__(2711);
const middleware_retry_1 = __webpack_require__(9618);
const node_config_provider_1 = __webpack_require__(5704);
const node_http_handler_1 = __webpack_require__(1279);
const smithy_client_1 = __webpack_require__(1411);
const util_body_length_node_1 = __webpack_require__(3638);
const util_defaults_mode_node_1 = __webpack_require__(5435);
const util_retry_1 = __webpack_require__(5518);
const runtimeConfig_shared_1 = __webpack_require__(1546);
const getRuntimeConfig = (config) => {
(0, smithy_client_1.emitWarningIfUnsupportedVersion)(process.version);
const defaultsMode = (0, util_defaults_mode_node_1.resolveDefaultsModeConfig)(config);
const defaultConfigProvider = () => defaultsMode().then(smithy_client_1.loadConfigsForDefaultMode);
const clientSharedValues = (0, runtimeConfig_shared_1.getRuntimeConfig)(config);
(0, core_1.emitWarningIfUnsupportedVersion)(process.version);
const loaderConfig = {
profile: config?.profile,
logger: clientSharedValues.logger,
};
return {
...clientSharedValues,
...config,
runtime: "node",
defaultsMode,
authSchemePreference: config?.authSchemePreference ?? (0, node_config_provider_1.loadConfig)(core_1.NODE_AUTH_SCHEME_PREFERENCE_OPTIONS, loaderConfig),
bodyLengthChecker: config?.bodyLengthChecker ?? util_body_length_node_1.calculateBodyLength,
defaultUserAgentProvider: config?.defaultUserAgentProvider ??
(0, util_user_agent_node_1.createDefaultUserAgentProvider)({ serviceId: clientSharedValues.serviceId, clientVersion: package_json_1.default.version }),
maxAttempts: config?.maxAttempts ?? (0, node_config_provider_1.loadConfig)(middleware_retry_1.NODE_MAX_ATTEMPT_CONFIG_OPTIONS, config),
region: config?.region ??
(0, node_config_provider_1.loadConfig)(config_resolver_1.NODE_REGION_CONFIG_OPTIONS, { ...config_resolver_1.NODE_REGION_CONFIG_FILE_OPTIONS, ...loaderConfig }),
requestHandler: node_http_handler_1.NodeHttpHandler.create(config?.requestHandler ?? defaultConfigProvider),
retryMode: config?.retryMode ??
(0, node_config_provider_1.loadConfig)({
...middleware_retry_1.NODE_RETRY_MODE_CONFIG_OPTIONS,
default: async () => (await defaultConfigProvider()).retryMode || util_retry_1.DEFAULT_RETRY_MODE,
}, config),
sha256: config?.sha256 ?? hash_node_1.Hash.bind(null, "sha256"),
streamCollector: config?.streamCollector ?? node_http_handler_1.streamCollector,
useDualstackEndpoint: config?.useDualstackEndpoint ?? (0, node_config_provider_1.loadConfig)(config_resolver_1.NODE_USE_DUALSTACK_ENDPOINT_CONFIG_OPTIONS, loaderConfig),
useFipsEndpoint: config?.useFipsEndpoint ?? (0, node_config_provider_1.loadConfig)(config_resolver_1.NODE_USE_FIPS_ENDPOINT_CONFIG_OPTIONS, loaderConfig),
userAgentAppId: config?.userAgentAppId ?? (0, node_config_provider_1.loadConfig)(util_user_agent_node_1.NODE_APP_ID_CONFIG_OPTIONS, loaderConfig),
};
};
exports.getRuntimeConfig = getRuntimeConfig;
/***/ }),
/***/ 1546:
/***/ ((__unused_webpack_module, exports, __webpack_require__) => {
Object.defineProperty(exports, "__esModule", ({ value: true }));
exports.getRuntimeConfig = void 0;
const core_1 = __webpack_require__(8704);
const protocols_1 = __webpack_require__(7288);
const core_2 = __webpack_require__(402);
const smithy_client_1 = __webpack_require__(1411);
const url_parser_1 = __webpack_require__(4494);
const util_base64_1 = __webpack_require__(8385);
const util_utf8_1 = __webpack_require__(1577);
const httpAuthSchemeProvider_1 = __webpack_require__(8396);
const endpointResolver_1 = __webpack_require__(546);
const getRuntimeConfig = (config) => {
return {
apiVersion: "2019-06-10",
base64Decoder: config?.base64Decoder ?? util_base64_1.fromBase64,
base64Encoder: config?.base64Encoder ?? util_base64_1.toBase64,
disableHostPrefix: config?.disableHostPrefix ?? false,
endpointProvider: config?.endpointProvider ?? endpointResolver_1.defaultEndpointResolver,
extensions: config?.extensions ?? [],
httpAuthSchemeProvider: config?.httpAuthSchemeProvider ?? httpAuthSchemeProvider_1.defaultSSOOIDCHttpAuthSchemeProvider,
httpAuthSchemes: config?.httpAuthSchemes ?? [
{
schemeId: "aws.auth#sigv4",
identityProvider: (ipc) => ipc.getIdentityProvider("aws.auth#sigv4"),
signer: new core_1.AwsSdkSigV4Signer(),
},
{
schemeId: "smithy.api#noAuth",
identityProvider: (ipc) => ipc.getIdentityProvider("smithy.api#noAuth") || (async () => ({})),
signer: new core_2.NoAuthSigner(),
},
],
logger: config?.logger ?? new smithy_client_1.NoOpLogger(),
protocol: config?.protocol ?? protocols_1.AwsRestJsonProtocol,
protocolSettings: config?.protocolSettings ?? {
defaultNamespace: "com.amazonaws.ssooidc",
version: "2019-06-10",
serviceTarget: "AWSSSOOIDCService",
},
serviceId: config?.serviceId ?? "SSO OIDC",
urlParser: config?.urlParser ?? url_parser_1.parseUrl,
utf8Decoder: config?.utf8Decoder ?? util_utf8_1.fromUtf8,
utf8Encoder: config?.utf8Encoder ?? util_utf8_1.toUtf8,
};
};
exports.getRuntimeConfig = getRuntimeConfig;
/***/ }),
/***/ 9955:
/***/ ((module) => {
module.exports = /*#__PURE__*/JSON.parse('{"name":"@aws-sdk/nested-clients","version":"3.982.0","description":"Nested clients for AWS SDK packages.","main":"./dist-cjs/index.js","module":"./dist-es/index.js","types":"./dist-types/index.d.ts","scripts":{"build":"yarn lint && concurrently \'yarn:build:types\' \'yarn:build:es\' && yarn build:cjs","build:cjs":"node ../../scripts/compilation/inline nested-clients","build:es":"tsc -p tsconfig.es.json","build:include:deps":"yarn g:turbo run build -F=\\"$npm_package_name\\"","build:types":"tsc -p tsconfig.types.json","build:types:downlevel":"downlevel-dts dist-types dist-types/ts3.4","clean":"premove dist-cjs dist-es dist-types tsconfig.cjs.tsbuildinfo tsconfig.es.tsbuildinfo tsconfig.types.tsbuildinfo","lint":"node ../../scripts/validation/submodules-linter.js --pkg nested-clients","test":"yarn g:vitest run","test:watch":"yarn g:vitest watch"},"engines":{"node":">=20.0.0"},"sideEffects":false,"author":{"name":"AWS SDK for JavaScript Team","url":"https://aws.amazon.com/javascript/"},"license":"Apache-2.0","dependencies":{"@aws-crypto/sha256-browser":"5.2.0","@aws-crypto/sha256-js":"5.2.0","@aws-sdk/core":"^3.973.6","@aws-sdk/middleware-host-header":"^3.972.3","@aws-sdk/middleware-logger":"^3.972.3","@aws-sdk/middleware-recursion-detection":"^3.972.3","@aws-sdk/middleware-user-agent":"^3.972.6","@aws-sdk/region-config-resolver":"^3.972.3","@aws-sdk/types":"^3.973.1","@aws-sdk/util-endpoints":"3.982.0","@aws-sdk/util-user-agent-browser":"^3.972.3","@aws-sdk/util-user-agent-node":"^3.972.4","@smithy/config-resolver":"^4.4.6","@smithy/core":"^3.22.0","@smithy/fetch-http-handler":"^5.3.9","@smithy/hash-node":"^4.2.8","@smithy/invalid-dependency":"^4.2.8","@smithy/middleware-content-length":"^4.2.8","@smithy/middleware-endpoint":"^4.4.12","@smithy/middleware-retry":"^4.4.29","@smithy/middleware-serde":"^4.2.9","@smithy/middleware-stack":"^4.2.8","@smithy/node-config-provider":"^4.3.8","@smithy/node-http-handler":"^4.4.8","@smithy/protocol-http":"^5.3.8","@smithy/smithy-client":"^4.11.1","@smithy/types":"^4.12.0","@smithy/url-parser":"^4.2.8","@smithy/util-base64":"^4.3.0","@smithy/util-body-length-browser":"^4.2.0","@smithy/util-body-length-node":"^4.2.1","@smithy/util-defaults-mode-browser":"^4.3.28","@smithy/util-defaults-mode-node":"^4.2.31","@smithy/util-endpoints":"^3.2.8","@smithy/util-middleware":"^4.2.8","@smithy/util-retry":"^4.2.8","@smithy/util-utf8":"^4.2.0","tslib":"^2.6.2"},"devDependencies":{"concurrently":"7.0.0","downlevel-dts":"0.10.1","premove":"4.0.0","typescript":"~5.8.3"},"typesVersions":{"<4.0":{"dist-types/*":["dist-types/ts3.4/*"]}},"files":["./signin.d.ts","./signin.js","./sso-oidc.d.ts","./sso-oidc.js","./sts.d.ts","./sts.js","dist-*/**"],"browser":{"./dist-es/submodules/signin/runtimeConfig":"./dist-es/submodules/signin/runtimeConfig.browser","./dist-es/submodules/sso-oidc/runtimeConfig":"./dist-es/submodules/sso-oidc/runtimeConfig.browser","./dist-es/submodules/sts/runtimeConfig":"./dist-es/submodules/sts/runtimeConfig.browser"},"react-native":{},"homepage":"https://github.com/aws/aws-sdk-js-v3/tree/main/packages/nested-clients","repository":{"type":"git","url":"https://github.com/aws/aws-sdk-js-v3.git","directory":"packages/nested-clients"},"exports":{"./package.json":"./package.json","./sso-oidc":{"types":"./dist-types/submodules/sso-oidc/index.d.ts","module":"./dist-es/submodules/sso-oidc/index.js","node":"./dist-cjs/submodules/sso-oidc/index.js","import":"./dist-es/submodules/sso-oidc/index.js","require":"./dist-cjs/submodules/sso-oidc/index.js"},"./sts":{"types":"./dist-types/submodules/sts/index.d.ts","module":"./dist-es/submodules/sts/index.js","node":"./dist-cjs/submodules/sts/index.js","import":"./dist-es/submodules/sts/index.js","require":"./dist-cjs/submodules/sts/index.js"},"./signin":{"types":"./dist-types/submodules/signin/index.d.ts","module":"./dist-es/submodules/signin/index.js","node":"./dist-cjs/submodules/signin/index.js","import":"./dist-es/submodules/signin/index.js","require":"./dist-cjs/submodules/signin/index.js"}}}');
/***/ })
};
;
@@ -0,0 +1,387 @@
"use strict";
exports.id = 566;
exports.ids = [566];
exports.modules = {
/***/ 566:
/***/ ((__unused_webpack_module, exports, __webpack_require__) => {
var __webpack_unused_export__;
var propertyProvider = __webpack_require__(8857);
var url = __webpack_require__(7016);
var buffer = __webpack_require__(181);
var http = __webpack_require__(8611);
var nodeConfigProvider = __webpack_require__(5704);
var urlParser = __webpack_require__(4494);
function httpRequest(options) {
return new Promise((resolve, reject) => {
const req = http.request({
method: "GET",
...options,
hostname: options.hostname?.replace(/^\[(.+)\]$/, "$1"),
});
req.on("error", (err) => {
reject(Object.assign(new propertyProvider.ProviderError("Unable to connect to instance metadata service"), err));
req.destroy();
});
req.on("timeout", () => {
reject(new propertyProvider.ProviderError("TimeoutError from instance metadata service"));
req.destroy();
});
req.on("response", (res) => {
const { statusCode = 400 } = res;
if (statusCode < 200 || 300 <= statusCode) {
reject(Object.assign(new propertyProvider.ProviderError("Error response received from instance metadata service"), { statusCode }));
req.destroy();
}
const chunks = [];
res.on("data", (chunk) => {
chunks.push(chunk);
});
res.on("end", () => {
resolve(buffer.Buffer.concat(chunks));
req.destroy();
});
});
req.end();
});
}
const isImdsCredentials = (arg) => Boolean(arg) &&
typeof arg === "object" &&
typeof arg.AccessKeyId === "string" &&
typeof arg.SecretAccessKey === "string" &&
typeof arg.Token === "string" &&
typeof arg.Expiration === "string";
const fromImdsCredentials = (creds) => ({
accessKeyId: creds.AccessKeyId,
secretAccessKey: creds.SecretAccessKey,
sessionToken: creds.Token,
expiration: new Date(creds.Expiration),
...(creds.AccountId && { accountId: creds.AccountId }),
});
const DEFAULT_TIMEOUT = 1000;
const DEFAULT_MAX_RETRIES = 0;
const providerConfigFromInit = ({ maxRetries = DEFAULT_MAX_RETRIES, timeout = DEFAULT_TIMEOUT, }) => ({ maxRetries, timeout });
const retry = (toRetry, maxRetries) => {
let promise = toRetry();
for (let i = 0; i < maxRetries; i++) {
promise = promise.catch(toRetry);
}
return promise;
};
const ENV_CMDS_FULL_URI = "AWS_CONTAINER_CREDENTIALS_FULL_URI";
const ENV_CMDS_RELATIVE_URI = "AWS_CONTAINER_CREDENTIALS_RELATIVE_URI";
const ENV_CMDS_AUTH_TOKEN = "AWS_CONTAINER_AUTHORIZATION_TOKEN";
const fromContainerMetadata = (init = {}) => {
const { timeout, maxRetries } = providerConfigFromInit(init);
return () => retry(async () => {
const requestOptions = await getCmdsUri({ logger: init.logger });
const credsResponse = JSON.parse(await requestFromEcsImds(timeout, requestOptions));
if (!isImdsCredentials(credsResponse)) {
throw new propertyProvider.CredentialsProviderError("Invalid response received from instance metadata service.", {
logger: init.logger,
});
}
return fromImdsCredentials(credsResponse);
}, maxRetries);
};
const requestFromEcsImds = async (timeout, options) => {
if (process.env[ENV_CMDS_AUTH_TOKEN]) {
options.headers = {
...options.headers,
Authorization: process.env[ENV_CMDS_AUTH_TOKEN],
};
}
const buffer = await httpRequest({
...options,
timeout,
});
return buffer.toString();
};
const CMDS_IP = "169.254.170.2";
const GREENGRASS_HOSTS = {
localhost: true,
"127.0.0.1": true,
};
const GREENGRASS_PROTOCOLS = {
"http:": true,
"https:": true,
};
const getCmdsUri = async ({ logger }) => {
if (process.env[ENV_CMDS_RELATIVE_URI]) {
return {
hostname: CMDS_IP,
path: process.env[ENV_CMDS_RELATIVE_URI],
};
}
if (process.env[ENV_CMDS_FULL_URI]) {
const parsed = url.parse(process.env[ENV_CMDS_FULL_URI]);
if (!parsed.hostname || !(parsed.hostname in GREENGRASS_HOSTS)) {
throw new propertyProvider.CredentialsProviderError(`${parsed.hostname} is not a valid container metadata service hostname`, {
tryNextLink: false,
logger,
});
}
if (!parsed.protocol || !(parsed.protocol in GREENGRASS_PROTOCOLS)) {
throw new propertyProvider.CredentialsProviderError(`${parsed.protocol} is not a valid container metadata service protocol`, {
tryNextLink: false,
logger,
});
}
return {
...parsed,
port: parsed.port ? parseInt(parsed.port, 10) : undefined,
};
}
throw new propertyProvider.CredentialsProviderError("The container metadata credential provider cannot be used unless" +
` the ${ENV_CMDS_RELATIVE_URI} or ${ENV_CMDS_FULL_URI} environment` +
" variable is set", {
tryNextLink: false,
logger,
});
};
class InstanceMetadataV1FallbackError extends propertyProvider.CredentialsProviderError {
tryNextLink;
name = "InstanceMetadataV1FallbackError";
constructor(message, tryNextLink = true) {
super(message, tryNextLink);
this.tryNextLink = tryNextLink;
Object.setPrototypeOf(this, InstanceMetadataV1FallbackError.prototype);
}
}
exports.yI = void 0;
(function (Endpoint) {
Endpoint["IPv4"] = "http://169.254.169.254";
Endpoint["IPv6"] = "http://[fd00:ec2::254]";
})(exports.yI || (exports.yI = {}));
const ENV_ENDPOINT_NAME = "AWS_EC2_METADATA_SERVICE_ENDPOINT";
const CONFIG_ENDPOINT_NAME = "ec2_metadata_service_endpoint";
const ENDPOINT_CONFIG_OPTIONS = {
environmentVariableSelector: (env) => env[ENV_ENDPOINT_NAME],
configFileSelector: (profile) => profile[CONFIG_ENDPOINT_NAME],
default: undefined,
};
var EndpointMode;
(function (EndpointMode) {
EndpointMode["IPv4"] = "IPv4";
EndpointMode["IPv6"] = "IPv6";
})(EndpointMode || (EndpointMode = {}));
const ENV_ENDPOINT_MODE_NAME = "AWS_EC2_METADATA_SERVICE_ENDPOINT_MODE";
const CONFIG_ENDPOINT_MODE_NAME = "ec2_metadata_service_endpoint_mode";
const ENDPOINT_MODE_CONFIG_OPTIONS = {
environmentVariableSelector: (env) => env[ENV_ENDPOINT_MODE_NAME],
configFileSelector: (profile) => profile[CONFIG_ENDPOINT_MODE_NAME],
default: EndpointMode.IPv4,
};
const getInstanceMetadataEndpoint = async () => urlParser.parseUrl((await getFromEndpointConfig()) || (await getFromEndpointModeConfig()));
const getFromEndpointConfig = async () => nodeConfigProvider.loadConfig(ENDPOINT_CONFIG_OPTIONS)();
const getFromEndpointModeConfig = async () => {
const endpointMode = await nodeConfigProvider.loadConfig(ENDPOINT_MODE_CONFIG_OPTIONS)();
switch (endpointMode) {
case EndpointMode.IPv4:
return exports.yI.IPv4;
case EndpointMode.IPv6:
return exports.yI.IPv6;
default:
throw new Error(`Unsupported endpoint mode: ${endpointMode}.` + ` Select from ${Object.values(EndpointMode)}`);
}
};
const STATIC_STABILITY_REFRESH_INTERVAL_SECONDS = 5 * 60;
const STATIC_STABILITY_REFRESH_INTERVAL_JITTER_WINDOW_SECONDS = 5 * 60;
const STATIC_STABILITY_DOC_URL = "https://docs.aws.amazon.com/sdkref/latest/guide/feature-static-credentials.html";
const getExtendedInstanceMetadataCredentials = (credentials, logger) => {
const refreshInterval = STATIC_STABILITY_REFRESH_INTERVAL_SECONDS +
Math.floor(Math.random() * STATIC_STABILITY_REFRESH_INTERVAL_JITTER_WINDOW_SECONDS);
const newExpiration = new Date(Date.now() + refreshInterval * 1000);
logger.warn("Attempting credential expiration extension due to a credential service availability issue. A refresh of these " +
`credentials will be attempted after ${new Date(newExpiration)}.\nFor more information, please visit: ` +
STATIC_STABILITY_DOC_URL);
const originalExpiration = credentials.originalExpiration ?? credentials.expiration;
return {
...credentials,
...(originalExpiration ? { originalExpiration } : {}),
expiration: newExpiration,
};
};
const staticStabilityProvider = (provider, options = {}) => {
const logger = options?.logger || console;
let pastCredentials;
return async () => {
let credentials;
try {
credentials = await provider();
if (credentials.expiration && credentials.expiration.getTime() < Date.now()) {
credentials = getExtendedInstanceMetadataCredentials(credentials, logger);
}
}
catch (e) {
if (pastCredentials) {
logger.warn("Credential renew failed: ", e);
credentials = getExtendedInstanceMetadataCredentials(pastCredentials, logger);
}
else {
throw e;
}
}
pastCredentials = credentials;
return credentials;
};
};
const IMDS_PATH = "/latest/meta-data/iam/security-credentials/";
const IMDS_TOKEN_PATH = "/latest/api/token";
const AWS_EC2_METADATA_V1_DISABLED = "AWS_EC2_METADATA_V1_DISABLED";
const PROFILE_AWS_EC2_METADATA_V1_DISABLED = "ec2_metadata_v1_disabled";
const X_AWS_EC2_METADATA_TOKEN = "x-aws-ec2-metadata-token";
const fromInstanceMetadata = (init = {}) => staticStabilityProvider(getInstanceMetadataProvider(init), { logger: init.logger });
const getInstanceMetadataProvider = (init = {}) => {
let disableFetchToken = false;
const { logger, profile } = init;
const { timeout, maxRetries } = providerConfigFromInit(init);
const getCredentials = async (maxRetries, options) => {
const isImdsV1Fallback = disableFetchToken || options.headers?.[X_AWS_EC2_METADATA_TOKEN] == null;
if (isImdsV1Fallback) {
let fallbackBlockedFromProfile = false;
let fallbackBlockedFromProcessEnv = false;
const configValue = await nodeConfigProvider.loadConfig({
environmentVariableSelector: (env) => {
const envValue = env[AWS_EC2_METADATA_V1_DISABLED];
fallbackBlockedFromProcessEnv = !!envValue && envValue !== "false";
if (envValue === undefined) {
throw new propertyProvider.CredentialsProviderError(`${AWS_EC2_METADATA_V1_DISABLED} not set in env, checking config file next.`, { logger: init.logger });
}
return fallbackBlockedFromProcessEnv;
},
configFileSelector: (profile) => {
const profileValue = profile[PROFILE_AWS_EC2_METADATA_V1_DISABLED];
fallbackBlockedFromProfile = !!profileValue && profileValue !== "false";
return fallbackBlockedFromProfile;
},
default: false,
}, {
profile,
})();
if (init.ec2MetadataV1Disabled || configValue) {
const causes = [];
if (init.ec2MetadataV1Disabled)
causes.push("credential provider initialization (runtime option ec2MetadataV1Disabled)");
if (fallbackBlockedFromProfile)
causes.push(`config file profile (${PROFILE_AWS_EC2_METADATA_V1_DISABLED})`);
if (fallbackBlockedFromProcessEnv)
causes.push(`process environment variable (${AWS_EC2_METADATA_V1_DISABLED})`);
throw new InstanceMetadataV1FallbackError(`AWS EC2 Metadata v1 fallback has been blocked by AWS SDK configuration in the following: [${causes.join(", ")}].`);
}
}
const imdsProfile = (await retry(async () => {
let profile;
try {
profile = await getProfile(options);
}
catch (err) {
if (err.statusCode === 401) {
disableFetchToken = false;
}
throw err;
}
return profile;
}, maxRetries)).trim();
return retry(async () => {
let creds;
try {
creds = await getCredentialsFromProfile(imdsProfile, options, init);
}
catch (err) {
if (err.statusCode === 401) {
disableFetchToken = false;
}
throw err;
}
return creds;
}, maxRetries);
};
return async () => {
const endpoint = await getInstanceMetadataEndpoint();
if (disableFetchToken) {
logger?.debug("AWS SDK Instance Metadata", "using v1 fallback (no token fetch)");
return getCredentials(maxRetries, { ...endpoint, timeout });
}
else {
let token;
try {
token = (await getMetadataToken({ ...endpoint, timeout })).toString();
}
catch (error) {
if (error?.statusCode === 400) {
throw Object.assign(error, {
message: "EC2 Metadata token request returned error",
});
}
else if (error.message === "TimeoutError" || [403, 404, 405].includes(error.statusCode)) {
disableFetchToken = true;
}
logger?.debug("AWS SDK Instance Metadata", "using v1 fallback (initial)");
return getCredentials(maxRetries, { ...endpoint, timeout });
}
return getCredentials(maxRetries, {
...endpoint,
headers: {
[X_AWS_EC2_METADATA_TOKEN]: token,
},
timeout,
});
}
};
};
const getMetadataToken = async (options) => httpRequest({
...options,
path: IMDS_TOKEN_PATH,
method: "PUT",
headers: {
"x-aws-ec2-metadata-token-ttl-seconds": "21600",
},
});
const getProfile = async (options) => (await httpRequest({ ...options, path: IMDS_PATH })).toString();
const getCredentialsFromProfile = async (profile, options, init) => {
const credentialsResponse = JSON.parse((await httpRequest({
...options,
path: IMDS_PATH + profile,
})).toString());
if (!isImdsCredentials(credentialsResponse)) {
throw new propertyProvider.CredentialsProviderError("Invalid response received from instance metadata service.", {
logger: init.logger,
});
}
return fromImdsCredentials(credentialsResponse);
};
__webpack_unused_export__ = DEFAULT_MAX_RETRIES;
__webpack_unused_export__ = DEFAULT_TIMEOUT;
__webpack_unused_export__ = ENV_CMDS_AUTH_TOKEN;
exports.ENV_CMDS_FULL_URI = ENV_CMDS_FULL_URI;
exports.ENV_CMDS_RELATIVE_URI = ENV_CMDS_RELATIVE_URI;
exports.fromContainerMetadata = fromContainerMetadata;
exports.fromInstanceMetadata = fromInstanceMetadata;
exports.getInstanceMetadataEndpoint = getInstanceMetadataEndpoint;
exports.httpRequest = httpRequest;
__webpack_unused_export__ = providerConfigFromInit;
/***/ })
};
;
@@ -0,0 +1,270 @@
"use strict";
exports.id = 579;
exports.ids = [579];
exports.modules = {
/***/ 6579:
/***/ ((__unused_webpack_module, exports, __webpack_require__) => {
var utilUtf8 = __webpack_require__(1577);
class EventStreamSerde {
marshaller;
serializer;
deserializer;
serdeContext;
defaultContentType;
constructor({ marshaller, serializer, deserializer, serdeContext, defaultContentType, }) {
this.marshaller = marshaller;
this.serializer = serializer;
this.deserializer = deserializer;
this.serdeContext = serdeContext;
this.defaultContentType = defaultContentType;
}
async serializeEventStream({ eventStream, requestSchema, initialRequest, }) {
const marshaller = this.marshaller;
const eventStreamMember = requestSchema.getEventStreamMember();
const unionSchema = requestSchema.getMemberSchema(eventStreamMember);
const serializer = this.serializer;
const defaultContentType = this.defaultContentType;
const initialRequestMarker = Symbol("initialRequestMarker");
const eventStreamIterable = {
async *[Symbol.asyncIterator]() {
if (initialRequest) {
const headers = {
":event-type": { type: "string", value: "initial-request" },
":message-type": { type: "string", value: "event" },
":content-type": { type: "string", value: defaultContentType },
};
serializer.write(requestSchema, initialRequest);
const body = serializer.flush();
yield {
[initialRequestMarker]: true,
headers,
body,
};
}
for await (const page of eventStream) {
yield page;
}
},
};
return marshaller.serialize(eventStreamIterable, (event) => {
if (event[initialRequestMarker]) {
return {
headers: event.headers,
body: event.body,
};
}
const unionMember = Object.keys(event).find((key) => {
return key !== "__type";
}) ?? "";
const { additionalHeaders, body, eventType, explicitPayloadContentType } = this.writeEventBody(unionMember, unionSchema, event);
const headers = {
":event-type": { type: "string", value: eventType },
":message-type": { type: "string", value: "event" },
":content-type": { type: "string", value: explicitPayloadContentType ?? defaultContentType },
...additionalHeaders,
};
return {
headers,
body,
};
});
}
async deserializeEventStream({ response, responseSchema, initialResponseContainer, }) {
const marshaller = this.marshaller;
const eventStreamMember = responseSchema.getEventStreamMember();
const unionSchema = responseSchema.getMemberSchema(eventStreamMember);
const memberSchemas = unionSchema.getMemberSchemas();
const initialResponseMarker = Symbol("initialResponseMarker");
const asyncIterable = marshaller.deserialize(response.body, async (event) => {
const unionMember = Object.keys(event).find((key) => {
return key !== "__type";
}) ?? "";
const body = event[unionMember].body;
if (unionMember === "initial-response") {
const dataObject = await this.deserializer.read(responseSchema, body);
delete dataObject[eventStreamMember];
return {
[initialResponseMarker]: true,
...dataObject,
};
}
else if (unionMember in memberSchemas) {
const eventStreamSchema = memberSchemas[unionMember];
if (eventStreamSchema.isStructSchema()) {
const out = {};
let hasBindings = false;
for (const [name, member] of eventStreamSchema.structIterator()) {
const { eventHeader, eventPayload } = member.getMergedTraits();
hasBindings = hasBindings || Boolean(eventHeader || eventPayload);
if (eventPayload) {
if (member.isBlobSchema()) {
out[name] = body;
}
else if (member.isStringSchema()) {
out[name] = (this.serdeContext?.utf8Encoder ?? utilUtf8.toUtf8)(body);
}
else if (member.isStructSchema()) {
out[name] = await this.deserializer.read(member, body);
}
}
else if (eventHeader) {
const value = event[unionMember].headers[name]?.value;
if (value != null) {
if (member.isNumericSchema()) {
if (value && typeof value === "object" && "bytes" in value) {
out[name] = BigInt(value.toString());
}
else {
out[name] = Number(value);
}
}
else {
out[name] = value;
}
}
}
}
if (hasBindings) {
return {
[unionMember]: out,
};
}
if (body.byteLength === 0) {
return {
[unionMember]: {},
};
}
}
return {
[unionMember]: await this.deserializer.read(eventStreamSchema, body),
};
}
else {
return {
$unknown: event,
};
}
});
const asyncIterator = asyncIterable[Symbol.asyncIterator]();
const firstEvent = await asyncIterator.next();
if (firstEvent.done) {
return asyncIterable;
}
if (firstEvent.value?.[initialResponseMarker]) {
if (!responseSchema) {
throw new Error("@smithy::core/protocols - initial-response event encountered in event stream but no response schema given.");
}
for (const [key, value] of Object.entries(firstEvent.value)) {
initialResponseContainer[key] = value;
}
}
return {
async *[Symbol.asyncIterator]() {
if (!firstEvent?.value?.[initialResponseMarker]) {
yield firstEvent.value;
}
while (true) {
const { done, value } = await asyncIterator.next();
if (done) {
break;
}
yield value;
}
},
};
}
writeEventBody(unionMember, unionSchema, event) {
const serializer = this.serializer;
let eventType = unionMember;
let explicitPayloadMember = null;
let explicitPayloadContentType;
const isKnownSchema = (() => {
const struct = unionSchema.getSchema();
return struct[4].includes(unionMember);
})();
const additionalHeaders = {};
if (!isKnownSchema) {
const [type, value] = event[unionMember];
eventType = type;
serializer.write(15, value);
}
else {
const eventSchema = unionSchema.getMemberSchema(unionMember);
if (eventSchema.isStructSchema()) {
for (const [memberName, memberSchema] of eventSchema.structIterator()) {
const { eventHeader, eventPayload } = memberSchema.getMergedTraits();
if (eventPayload) {
explicitPayloadMember = memberName;
}
else if (eventHeader) {
const value = event[unionMember][memberName];
let type = "binary";
if (memberSchema.isNumericSchema()) {
if ((-2) ** 31 <= value && value <= 2 ** 31 - 1) {
type = "integer";
}
else {
type = "long";
}
}
else if (memberSchema.isTimestampSchema()) {
type = "timestamp";
}
else if (memberSchema.isStringSchema()) {
type = "string";
}
else if (memberSchema.isBooleanSchema()) {
type = "boolean";
}
if (value != null) {
additionalHeaders[memberName] = {
type,
value,
};
delete event[unionMember][memberName];
}
}
}
if (explicitPayloadMember !== null) {
const payloadSchema = eventSchema.getMemberSchema(explicitPayloadMember);
if (payloadSchema.isBlobSchema()) {
explicitPayloadContentType = "application/octet-stream";
}
else if (payloadSchema.isStringSchema()) {
explicitPayloadContentType = "text/plain";
}
serializer.write(payloadSchema, event[unionMember][explicitPayloadMember]);
}
else {
serializer.write(eventSchema, event[unionMember]);
}
}
else {
throw new Error("@smithy/core/event-streams - non-struct member not supported in event stream union.");
}
}
const messageSerialization = serializer.flush();
const body = typeof messageSerialization === "string"
? (this.serdeContext?.utf8Decoder ?? utilUtf8.fromUtf8)(messageSerialization)
: messageSerialization;
return {
body,
eventType,
explicitPayloadContentType,
additionalHeaders,
};
}
}
exports.EventStreamSerde = EventStreamSerde;
/***/ })
};
;
@@ -0,0 +1,234 @@
"use strict";
exports.id = 605;
exports.ids = [605];
exports.modules = {
/***/ 1509:
/***/ ((__unused_webpack_module, exports, __webpack_require__) => {
Object.defineProperty(exports, "__esModule", ({ value: true }));
exports.checkUrl = void 0;
const property_provider_1 = __webpack_require__(8857);
const LOOPBACK_CIDR_IPv4 = "127.0.0.0/8";
const LOOPBACK_CIDR_IPv6 = "::1/128";
const ECS_CONTAINER_HOST = "169.254.170.2";
const EKS_CONTAINER_HOST_IPv4 = "169.254.170.23";
const EKS_CONTAINER_HOST_IPv6 = "[fd00:ec2::23]";
const checkUrl = (url, logger) => {
if (url.protocol === "https:") {
return;
}
if (url.hostname === ECS_CONTAINER_HOST ||
url.hostname === EKS_CONTAINER_HOST_IPv4 ||
url.hostname === EKS_CONTAINER_HOST_IPv6) {
return;
}
if (url.hostname.includes("[")) {
if (url.hostname === "[::1]" || url.hostname === "[0000:0000:0000:0000:0000:0000:0000:0001]") {
return;
}
}
else {
if (url.hostname === "localhost") {
return;
}
const ipComponents = url.hostname.split(".");
const inRange = (component) => {
const num = parseInt(component, 10);
return 0 <= num && num <= 255;
};
if (ipComponents[0] === "127" &&
inRange(ipComponents[1]) &&
inRange(ipComponents[2]) &&
inRange(ipComponents[3]) &&
ipComponents.length === 4) {
return;
}
}
throw new property_provider_1.CredentialsProviderError(`URL not accepted. It must either be HTTPS or match one of the following:
- loopback CIDR 127.0.0.0/8 or [::1/128]
- ECS container host 169.254.170.2
- EKS container host 169.254.170.23 or [fd00:ec2::23]`, { logger });
};
exports.checkUrl = checkUrl;
/***/ }),
/***/ 8712:
/***/ ((__unused_webpack_module, exports, __webpack_require__) => {
Object.defineProperty(exports, "__esModule", ({ value: true }));
exports.fromHttp = void 0;
const tslib_1 = __webpack_require__(1860);
const client_1 = __webpack_require__(5152);
const node_http_handler_1 = __webpack_require__(1279);
const property_provider_1 = __webpack_require__(8857);
const promises_1 = tslib_1.__importDefault(__webpack_require__(1943));
const checkUrl_1 = __webpack_require__(1509);
const requestHelpers_1 = __webpack_require__(8914);
const retry_wrapper_1 = __webpack_require__(1122);
const AWS_CONTAINER_CREDENTIALS_RELATIVE_URI = "AWS_CONTAINER_CREDENTIALS_RELATIVE_URI";
const DEFAULT_LINK_LOCAL_HOST = "http://169.254.170.2";
const AWS_CONTAINER_CREDENTIALS_FULL_URI = "AWS_CONTAINER_CREDENTIALS_FULL_URI";
const AWS_CONTAINER_AUTHORIZATION_TOKEN_FILE = "AWS_CONTAINER_AUTHORIZATION_TOKEN_FILE";
const AWS_CONTAINER_AUTHORIZATION_TOKEN = "AWS_CONTAINER_AUTHORIZATION_TOKEN";
const fromHttp = (options = {}) => {
options.logger?.debug("@aws-sdk/credential-provider-http - fromHttp");
let host;
const relative = options.awsContainerCredentialsRelativeUri ?? process.env[AWS_CONTAINER_CREDENTIALS_RELATIVE_URI];
const full = options.awsContainerCredentialsFullUri ?? process.env[AWS_CONTAINER_CREDENTIALS_FULL_URI];
const token = options.awsContainerAuthorizationToken ?? process.env[AWS_CONTAINER_AUTHORIZATION_TOKEN];
const tokenFile = options.awsContainerAuthorizationTokenFile ?? process.env[AWS_CONTAINER_AUTHORIZATION_TOKEN_FILE];
const warn = options.logger?.constructor?.name === "NoOpLogger" || !options.logger?.warn
? console.warn
: options.logger.warn.bind(options.logger);
if (relative && full) {
warn("@aws-sdk/credential-provider-http: " +
"you have set both awsContainerCredentialsRelativeUri and awsContainerCredentialsFullUri.");
warn("awsContainerCredentialsFullUri will take precedence.");
}
if (token && tokenFile) {
warn("@aws-sdk/credential-provider-http: " +
"you have set both awsContainerAuthorizationToken and awsContainerAuthorizationTokenFile.");
warn("awsContainerAuthorizationToken will take precedence.");
}
if (full) {
host = full;
}
else if (relative) {
host = `${DEFAULT_LINK_LOCAL_HOST}${relative}`;
}
else {
throw new property_provider_1.CredentialsProviderError(`No HTTP credential provider host provided.
Set AWS_CONTAINER_CREDENTIALS_FULL_URI or AWS_CONTAINER_CREDENTIALS_RELATIVE_URI.`, { logger: options.logger });
}
const url = new URL(host);
(0, checkUrl_1.checkUrl)(url, options.logger);
const requestHandler = node_http_handler_1.NodeHttpHandler.create({
requestTimeout: options.timeout ?? 1000,
connectionTimeout: options.timeout ?? 1000,
});
return (0, retry_wrapper_1.retryWrapper)(async () => {
const request = (0, requestHelpers_1.createGetRequest)(url);
if (token) {
request.headers.Authorization = token;
}
else if (tokenFile) {
request.headers.Authorization = (await promises_1.default.readFile(tokenFile)).toString();
}
try {
const result = await requestHandler.handle(request);
return (0, requestHelpers_1.getCredentials)(result.response).then((creds) => (0, client_1.setCredentialFeature)(creds, "CREDENTIALS_HTTP", "z"));
}
catch (e) {
throw new property_provider_1.CredentialsProviderError(String(e), { logger: options.logger });
}
}, options.maxRetries ?? 3, options.timeout ?? 1000);
};
exports.fromHttp = fromHttp;
/***/ }),
/***/ 8914:
/***/ ((__unused_webpack_module, exports, __webpack_require__) => {
Object.defineProperty(exports, "__esModule", ({ value: true }));
exports.createGetRequest = createGetRequest;
exports.getCredentials = getCredentials;
const property_provider_1 = __webpack_require__(8857);
const protocol_http_1 = __webpack_require__(2356);
const smithy_client_1 = __webpack_require__(1411);
const util_stream_1 = __webpack_require__(4252);
function createGetRequest(url) {
return new protocol_http_1.HttpRequest({
protocol: url.protocol,
hostname: url.hostname,
port: Number(url.port),
path: url.pathname,
query: Array.from(url.searchParams.entries()).reduce((acc, [k, v]) => {
acc[k] = v;
return acc;
}, {}),
fragment: url.hash,
});
}
async function getCredentials(response, logger) {
const stream = (0, util_stream_1.sdkStreamMixin)(response.body);
const str = await stream.transformToString();
if (response.statusCode === 200) {
const parsed = JSON.parse(str);
if (typeof parsed.AccessKeyId !== "string" ||
typeof parsed.SecretAccessKey !== "string" ||
typeof parsed.Token !== "string" ||
typeof parsed.Expiration !== "string") {
throw new property_provider_1.CredentialsProviderError("HTTP credential provider response not of the required format, an object matching: " +
"{ AccessKeyId: string, SecretAccessKey: string, Token: string, Expiration: string(rfc3339) }", { logger });
}
return {
accessKeyId: parsed.AccessKeyId,
secretAccessKey: parsed.SecretAccessKey,
sessionToken: parsed.Token,
expiration: (0, smithy_client_1.parseRfc3339DateTime)(parsed.Expiration),
};
}
if (response.statusCode >= 400 && response.statusCode < 500) {
let parsedBody = {};
try {
parsedBody = JSON.parse(str);
}
catch (e) { }
throw Object.assign(new property_provider_1.CredentialsProviderError(`Server responded with status: ${response.statusCode}`, { logger }), {
Code: parsedBody.Code,
Message: parsedBody.Message,
});
}
throw new property_provider_1.CredentialsProviderError(`Server responded with status: ${response.statusCode}`, { logger });
}
/***/ }),
/***/ 1122:
/***/ ((__unused_webpack_module, exports) => {
Object.defineProperty(exports, "__esModule", ({ value: true }));
exports.retryWrapper = void 0;
const retryWrapper = (toRetry, maxRetries, delayMs) => {
return async () => {
for (let i = 0; i < maxRetries; ++i) {
try {
return await toRetry();
}
catch (e) {
await new Promise((resolve) => setTimeout(resolve, delayMs));
}
}
return await toRetry();
};
};
exports.retryWrapper = retryWrapper;
/***/ }),
/***/ 8605:
/***/ ((__unused_webpack_module, exports, __webpack_require__) => {
var __webpack_unused_export__;
__webpack_unused_export__ = ({ value: true });
exports.fromHttp = void 0;
var fromHttp_1 = __webpack_require__(8712);
Object.defineProperty(exports, "fromHttp", ({ enumerable: true, get: function () { return fromHttp_1.fromHttp; } }));
/***/ })
};
;
@@ -0,0 +1,587 @@
"use strict";
exports.id = 762;
exports.ids = [762];
exports.modules = {
/***/ 7709:
/***/ ((__unused_webpack_module, exports, __webpack_require__) => {
Object.defineProperty(exports, "__esModule", ({ value: true }));
exports.resolveHttpAuthSchemeConfig = exports.defaultSigninHttpAuthSchemeProvider = exports.defaultSigninHttpAuthSchemeParametersProvider = void 0;
const core_1 = __webpack_require__(8704);
const util_middleware_1 = __webpack_require__(6324);
const defaultSigninHttpAuthSchemeParametersProvider = async (config, context, input) => {
return {
operation: (0, util_middleware_1.getSmithyContext)(context).operation,
region: (await (0, util_middleware_1.normalizeProvider)(config.region)()) ||
(() => {
throw new Error("expected `region` to be configured for `aws.auth#sigv4`");
})(),
};
};
exports.defaultSigninHttpAuthSchemeParametersProvider = defaultSigninHttpAuthSchemeParametersProvider;
function createAwsAuthSigv4HttpAuthOption(authParameters) {
return {
schemeId: "aws.auth#sigv4",
signingProperties: {
name: "signin",
region: authParameters.region,
},
propertiesExtractor: (config, context) => ({
signingProperties: {
config,
context,
},
}),
};
}
function createSmithyApiNoAuthHttpAuthOption(authParameters) {
return {
schemeId: "smithy.api#noAuth",
};
}
const defaultSigninHttpAuthSchemeProvider = (authParameters) => {
const options = [];
switch (authParameters.operation) {
case "CreateOAuth2Token": {
options.push(createSmithyApiNoAuthHttpAuthOption(authParameters));
break;
}
default: {
options.push(createAwsAuthSigv4HttpAuthOption(authParameters));
}
}
return options;
};
exports.defaultSigninHttpAuthSchemeProvider = defaultSigninHttpAuthSchemeProvider;
const resolveHttpAuthSchemeConfig = (config) => {
const config_0 = (0, core_1.resolveAwsSdkSigV4Config)(config);
return Object.assign(config_0, {
authSchemePreference: (0, util_middleware_1.normalizeProvider)(config.authSchemePreference ?? []),
});
};
exports.resolveHttpAuthSchemeConfig = resolveHttpAuthSchemeConfig;
/***/ }),
/***/ 2547:
/***/ ((__unused_webpack_module, exports, __webpack_require__) => {
Object.defineProperty(exports, "__esModule", ({ value: true }));
exports.defaultEndpointResolver = void 0;
const util_endpoints_1 = __webpack_require__(3068);
const util_endpoints_2 = __webpack_require__(9674);
const ruleset_1 = __webpack_require__(6904);
const cache = new util_endpoints_2.EndpointCache({
size: 50,
params: ["Endpoint", "Region", "UseDualStack", "UseFIPS"],
});
const defaultEndpointResolver = (endpointParams, context = {}) => {
return cache.get(endpointParams, () => (0, util_endpoints_2.resolveEndpoint)(ruleset_1.ruleSet, {
endpointParams: endpointParams,
logger: context.logger,
}));
};
exports.defaultEndpointResolver = defaultEndpointResolver;
util_endpoints_2.customEndpointFunctions.aws = util_endpoints_1.awsEndpointFunctions;
/***/ }),
/***/ 6904:
/***/ ((__unused_webpack_module, exports) => {
Object.defineProperty(exports, "__esModule", ({ value: true }));
exports.ruleSet = void 0;
const u = "required", v = "fn", w = "argv", x = "ref";
const a = true, b = "isSet", c = "booleanEquals", d = "error", e = "endpoint", f = "tree", g = "PartitionResult", h = "stringEquals", i = { [u]: true, "default": false, "type": "boolean" }, j = { [u]: false, "type": "string" }, k = { [x]: "Endpoint" }, l = { [v]: c, [w]: [{ [x]: "UseFIPS" }, true] }, m = { [v]: c, [w]: [{ [x]: "UseDualStack" }, true] }, n = {}, o = { [v]: "getAttr", [w]: [{ [x]: g }, "name"] }, p = { [v]: c, [w]: [{ [x]: "UseFIPS" }, false] }, q = { [v]: c, [w]: [{ [x]: "UseDualStack" }, false] }, r = { [v]: "getAttr", [w]: [{ [x]: g }, "supportsFIPS"] }, s = { [v]: c, [w]: [true, { [v]: "getAttr", [w]: [{ [x]: g }, "supportsDualStack"] }] }, t = [{ [x]: "Region" }];
const _data = { version: "1.0", parameters: { UseDualStack: i, UseFIPS: i, Endpoint: j, Region: j }, rules: [{ conditions: [{ [v]: b, [w]: [k] }], rules: [{ conditions: [l], error: "Invalid Configuration: FIPS and custom endpoint are not supported", type: d }, { rules: [{ conditions: [m], error: "Invalid Configuration: Dualstack and custom endpoint are not supported", type: d }, { endpoint: { url: k, properties: n, headers: n }, type: e }], type: f }], type: f }, { rules: [{ conditions: [{ [v]: b, [w]: t }], rules: [{ conditions: [{ [v]: "aws.partition", [w]: t, assign: g }], rules: [{ conditions: [{ [v]: h, [w]: [o, "aws"] }, p, q], endpoint: { url: "https://{Region}.signin.aws.amazon.com", properties: n, headers: n }, type: e }, { conditions: [{ [v]: h, [w]: [o, "aws-cn"] }, p, q], endpoint: { url: "https://{Region}.signin.amazonaws.cn", properties: n, headers: n }, type: e }, { conditions: [{ [v]: h, [w]: [o, "aws-us-gov"] }, p, q], endpoint: { url: "https://{Region}.signin.amazonaws-us-gov.com", properties: n, headers: n }, type: e }, { conditions: [l, m], rules: [{ conditions: [{ [v]: c, [w]: [a, r] }, s], rules: [{ endpoint: { url: "https://signin-fips.{Region}.{PartitionResult#dualStackDnsSuffix}", properties: n, headers: n }, type: e }], type: f }, { error: "FIPS and DualStack are enabled, but this partition does not support one or both", type: d }], type: f }, { conditions: [l, q], rules: [{ conditions: [{ [v]: c, [w]: [r, a] }], rules: [{ endpoint: { url: "https://signin-fips.{Region}.{PartitionResult#dnsSuffix}", properties: n, headers: n }, type: e }], type: f }, { error: "FIPS is enabled but this partition does not support FIPS", type: d }], type: f }, { conditions: [p, m], rules: [{ conditions: [s], rules: [{ endpoint: { url: "https://signin.{Region}.{PartitionResult#dualStackDnsSuffix}", properties: n, headers: n }, type: e }], type: f }, { error: "DualStack is enabled but this partition does not support DualStack", type: d }], type: f }, { endpoint: { url: "https://signin.{Region}.{PartitionResult#dnsSuffix}", properties: n, headers: n }, type: e }], type: f }], type: f }, { error: "Invalid Configuration: Missing Region", type: d }], type: f }] };
exports.ruleSet = _data;
/***/ }),
/***/ 9762:
/***/ ((__unused_webpack_module, exports, __webpack_require__) => {
var __webpack_unused_export__;
var middlewareHostHeader = __webpack_require__(2590);
var middlewareLogger = __webpack_require__(5242);
var middlewareRecursionDetection = __webpack_require__(1568);
var middlewareUserAgent = __webpack_require__(2959);
var configResolver = __webpack_require__(9316);
var core = __webpack_require__(402);
var schema = __webpack_require__(6890);
var middlewareContentLength = __webpack_require__(7212);
var middlewareEndpoint = __webpack_require__(99);
var middlewareRetry = __webpack_require__(9618);
var smithyClient = __webpack_require__(1411);
var httpAuthSchemeProvider = __webpack_require__(7709);
var runtimeConfig = __webpack_require__(2836);
var regionConfigResolver = __webpack_require__(6463);
var protocolHttp = __webpack_require__(2356);
const resolveClientEndpointParameters = (options) => {
return Object.assign(options, {
useDualstackEndpoint: options.useDualstackEndpoint ?? false,
useFipsEndpoint: options.useFipsEndpoint ?? false,
defaultSigningName: "signin",
});
};
const commonParams = {
UseFIPS: { type: "builtInParams", name: "useFipsEndpoint" },
Endpoint: { type: "builtInParams", name: "endpoint" },
Region: { type: "builtInParams", name: "region" },
UseDualStack: { type: "builtInParams", name: "useDualstackEndpoint" },
};
const getHttpAuthExtensionConfiguration = (runtimeConfig) => {
const _httpAuthSchemes = runtimeConfig.httpAuthSchemes;
let _httpAuthSchemeProvider = runtimeConfig.httpAuthSchemeProvider;
let _credentials = runtimeConfig.credentials;
return {
setHttpAuthScheme(httpAuthScheme) {
const index = _httpAuthSchemes.findIndex((scheme) => scheme.schemeId === httpAuthScheme.schemeId);
if (index === -1) {
_httpAuthSchemes.push(httpAuthScheme);
}
else {
_httpAuthSchemes.splice(index, 1, httpAuthScheme);
}
},
httpAuthSchemes() {
return _httpAuthSchemes;
},
setHttpAuthSchemeProvider(httpAuthSchemeProvider) {
_httpAuthSchemeProvider = httpAuthSchemeProvider;
},
httpAuthSchemeProvider() {
return _httpAuthSchemeProvider;
},
setCredentials(credentials) {
_credentials = credentials;
},
credentials() {
return _credentials;
},
};
};
const resolveHttpAuthRuntimeConfig = (config) => {
return {
httpAuthSchemes: config.httpAuthSchemes(),
httpAuthSchemeProvider: config.httpAuthSchemeProvider(),
credentials: config.credentials(),
};
};
const resolveRuntimeExtensions = (runtimeConfig, extensions) => {
const extensionConfiguration = Object.assign(regionConfigResolver.getAwsRegionExtensionConfiguration(runtimeConfig), smithyClient.getDefaultExtensionConfiguration(runtimeConfig), protocolHttp.getHttpHandlerExtensionConfiguration(runtimeConfig), getHttpAuthExtensionConfiguration(runtimeConfig));
extensions.forEach((extension) => extension.configure(extensionConfiguration));
return Object.assign(runtimeConfig, regionConfigResolver.resolveAwsRegionExtensionConfiguration(extensionConfiguration), smithyClient.resolveDefaultRuntimeConfig(extensionConfiguration), protocolHttp.resolveHttpHandlerRuntimeConfig(extensionConfiguration), resolveHttpAuthRuntimeConfig(extensionConfiguration));
};
class SigninClient extends smithyClient.Client {
config;
constructor(...[configuration]) {
const _config_0 = runtimeConfig.getRuntimeConfig(configuration || {});
super(_config_0);
this.initConfig = _config_0;
const _config_1 = resolveClientEndpointParameters(_config_0);
const _config_2 = middlewareUserAgent.resolveUserAgentConfig(_config_1);
const _config_3 = middlewareRetry.resolveRetryConfig(_config_2);
const _config_4 = configResolver.resolveRegionConfig(_config_3);
const _config_5 = middlewareHostHeader.resolveHostHeaderConfig(_config_4);
const _config_6 = middlewareEndpoint.resolveEndpointConfig(_config_5);
const _config_7 = httpAuthSchemeProvider.resolveHttpAuthSchemeConfig(_config_6);
const _config_8 = resolveRuntimeExtensions(_config_7, configuration?.extensions || []);
this.config = _config_8;
this.middlewareStack.use(schema.getSchemaSerdePlugin(this.config));
this.middlewareStack.use(middlewareUserAgent.getUserAgentPlugin(this.config));
this.middlewareStack.use(middlewareRetry.getRetryPlugin(this.config));
this.middlewareStack.use(middlewareContentLength.getContentLengthPlugin(this.config));
this.middlewareStack.use(middlewareHostHeader.getHostHeaderPlugin(this.config));
this.middlewareStack.use(middlewareLogger.getLoggerPlugin(this.config));
this.middlewareStack.use(middlewareRecursionDetection.getRecursionDetectionPlugin(this.config));
this.middlewareStack.use(core.getHttpAuthSchemeEndpointRuleSetPlugin(this.config, {
httpAuthSchemeParametersProvider: httpAuthSchemeProvider.defaultSigninHttpAuthSchemeParametersProvider,
identityProviderConfigProvider: async (config) => new core.DefaultIdentityProviderConfig({
"aws.auth#sigv4": config.credentials,
}),
}));
this.middlewareStack.use(core.getHttpSigningPlugin(this.config));
}
destroy() {
super.destroy();
}
}
class SigninServiceException extends smithyClient.ServiceException {
constructor(options) {
super(options);
Object.setPrototypeOf(this, SigninServiceException.prototype);
}
}
class AccessDeniedException extends SigninServiceException {
name = "AccessDeniedException";
$fault = "client";
error;
constructor(opts) {
super({
name: "AccessDeniedException",
$fault: "client",
...opts,
});
Object.setPrototypeOf(this, AccessDeniedException.prototype);
this.error = opts.error;
}
}
class InternalServerException extends SigninServiceException {
name = "InternalServerException";
$fault = "server";
error;
constructor(opts) {
super({
name: "InternalServerException",
$fault: "server",
...opts,
});
Object.setPrototypeOf(this, InternalServerException.prototype);
this.error = opts.error;
}
}
class TooManyRequestsError extends SigninServiceException {
name = "TooManyRequestsError";
$fault = "client";
error;
constructor(opts) {
super({
name: "TooManyRequestsError",
$fault: "client",
...opts,
});
Object.setPrototypeOf(this, TooManyRequestsError.prototype);
this.error = opts.error;
}
}
class ValidationException extends SigninServiceException {
name = "ValidationException";
$fault = "client";
error;
constructor(opts) {
super({
name: "ValidationException",
$fault: "client",
...opts,
});
Object.setPrototypeOf(this, ValidationException.prototype);
this.error = opts.error;
}
}
const _ADE = "AccessDeniedException";
const _AT = "AccessToken";
const _COAT = "CreateOAuth2Token";
const _COATR = "CreateOAuth2TokenRequest";
const _COATRB = "CreateOAuth2TokenRequestBody";
const _COATRBr = "CreateOAuth2TokenResponseBody";
const _COATRr = "CreateOAuth2TokenResponse";
const _ISE = "InternalServerException";
const _RT = "RefreshToken";
const _TMRE = "TooManyRequestsError";
const _VE = "ValidationException";
const _aKI = "accessKeyId";
const _aT = "accessToken";
const _c = "client";
const _cI = "clientId";
const _cV = "codeVerifier";
const _co = "code";
const _e = "error";
const _eI = "expiresIn";
const _gT = "grantType";
const _h = "http";
const _hE = "httpError";
const _iT = "idToken";
const _jN = "jsonName";
const _m = "message";
const _rT = "refreshToken";
const _rU = "redirectUri";
const _s = "server";
const _sAK = "secretAccessKey";
const _sT = "sessionToken";
const _sm = "smithy.ts.sdk.synthetic.com.amazonaws.signin";
const _tI = "tokenInput";
const _tO = "tokenOutput";
const _tT = "tokenType";
const n0 = "com.amazonaws.signin";
var RefreshToken = [0, n0, _RT, 8, 0];
var AccessDeniedException$ = [-3, n0, _ADE, { [_e]: _c }, [_e, _m], [0, 0], 2];
schema.TypeRegistry.for(n0).registerError(AccessDeniedException$, AccessDeniedException);
var AccessToken$ = [
3,
n0,
_AT,
8,
[_aKI, _sAK, _sT],
[
[0, { [_jN]: _aKI }],
[0, { [_jN]: _sAK }],
[0, { [_jN]: _sT }],
],
3,
];
var CreateOAuth2TokenRequest$ = [
3,
n0,
_COATR,
0,
[_tI],
[[() => CreateOAuth2TokenRequestBody$, 16]],
1,
];
var CreateOAuth2TokenRequestBody$ = [
3,
n0,
_COATRB,
0,
[_cI, _gT, _co, _rU, _cV, _rT],
[
[0, { [_jN]: _cI }],
[0, { [_jN]: _gT }],
0,
[0, { [_jN]: _rU }],
[0, { [_jN]: _cV }],
[() => RefreshToken, { [_jN]: _rT }],
],
2,
];
var CreateOAuth2TokenResponse$ = [
3,
n0,
_COATRr,
0,
[_tO],
[[() => CreateOAuth2TokenResponseBody$, 16]],
1,
];
var CreateOAuth2TokenResponseBody$ = [
3,
n0,
_COATRBr,
0,
[_aT, _tT, _eI, _rT, _iT],
[
[() => AccessToken$, { [_jN]: _aT }],
[0, { [_jN]: _tT }],
[1, { [_jN]: _eI }],
[() => RefreshToken, { [_jN]: _rT }],
[0, { [_jN]: _iT }],
],
4,
];
var InternalServerException$ = [-3, n0, _ISE, { [_e]: _s, [_hE]: 500 }, [_e, _m], [0, 0], 2];
schema.TypeRegistry.for(n0).registerError(InternalServerException$, InternalServerException);
var TooManyRequestsError$ = [-3, n0, _TMRE, { [_e]: _c, [_hE]: 429 }, [_e, _m], [0, 0], 2];
schema.TypeRegistry.for(n0).registerError(TooManyRequestsError$, TooManyRequestsError);
var ValidationException$ = [-3, n0, _VE, { [_e]: _c, [_hE]: 400 }, [_e, _m], [0, 0], 2];
schema.TypeRegistry.for(n0).registerError(ValidationException$, ValidationException);
var SigninServiceException$ = [-3, _sm, "SigninServiceException", 0, [], []];
schema.TypeRegistry.for(_sm).registerError(SigninServiceException$, SigninServiceException);
var CreateOAuth2Token$ = [
9,
n0,
_COAT,
{ [_h]: ["POST", "/v1/token", 200] },
() => CreateOAuth2TokenRequest$,
() => CreateOAuth2TokenResponse$,
];
class CreateOAuth2TokenCommand extends smithyClient.Command
.classBuilder()
.ep(commonParams)
.m(function (Command, cs, config, o) {
return [middlewareEndpoint.getEndpointPlugin(config, Command.getEndpointParameterInstructions())];
})
.s("Signin", "CreateOAuth2Token", {})
.n("SigninClient", "CreateOAuth2TokenCommand")
.sc(CreateOAuth2Token$)
.build() {
}
const commands = {
CreateOAuth2TokenCommand,
};
class Signin extends SigninClient {
}
smithyClient.createAggregatedClient(commands, Signin);
const OAuth2ErrorCode = {
AUTHCODE_EXPIRED: "AUTHCODE_EXPIRED",
INSUFFICIENT_PERMISSIONS: "INSUFFICIENT_PERMISSIONS",
INVALID_REQUEST: "INVALID_REQUEST",
SERVER_ERROR: "server_error",
TOKEN_EXPIRED: "TOKEN_EXPIRED",
USER_CREDENTIALS_CHANGED: "USER_CREDENTIALS_CHANGED",
};
__webpack_unused_export__ = ({
enumerable: true,
get: function () { return smithyClient.Command; }
});
__webpack_unused_export__ = ({
enumerable: true,
get: function () { return smithyClient.Client; }
});
__webpack_unused_export__ = AccessDeniedException;
__webpack_unused_export__ = AccessDeniedException$;
__webpack_unused_export__ = AccessToken$;
__webpack_unused_export__ = CreateOAuth2Token$;
exports.CreateOAuth2TokenCommand = CreateOAuth2TokenCommand;
__webpack_unused_export__ = CreateOAuth2TokenRequest$;
__webpack_unused_export__ = CreateOAuth2TokenRequestBody$;
__webpack_unused_export__ = CreateOAuth2TokenResponse$;
__webpack_unused_export__ = CreateOAuth2TokenResponseBody$;
__webpack_unused_export__ = InternalServerException;
__webpack_unused_export__ = InternalServerException$;
__webpack_unused_export__ = OAuth2ErrorCode;
__webpack_unused_export__ = Signin;
exports.SigninClient = SigninClient;
__webpack_unused_export__ = SigninServiceException;
__webpack_unused_export__ = SigninServiceException$;
__webpack_unused_export__ = TooManyRequestsError;
__webpack_unused_export__ = TooManyRequestsError$;
__webpack_unused_export__ = ValidationException;
__webpack_unused_export__ = ValidationException$;
/***/ }),
/***/ 2836:
/***/ ((__unused_webpack_module, exports, __webpack_require__) => {
Object.defineProperty(exports, "__esModule", ({ value: true }));
exports.getRuntimeConfig = void 0;
const tslib_1 = __webpack_require__(1860);
const package_json_1 = tslib_1.__importDefault(__webpack_require__(9955));
const core_1 = __webpack_require__(8704);
const util_user_agent_node_1 = __webpack_require__(1656);
const config_resolver_1 = __webpack_require__(9316);
const hash_node_1 = __webpack_require__(2711);
const middleware_retry_1 = __webpack_require__(9618);
const node_config_provider_1 = __webpack_require__(5704);
const node_http_handler_1 = __webpack_require__(1279);
const smithy_client_1 = __webpack_require__(1411);
const util_body_length_node_1 = __webpack_require__(3638);
const util_defaults_mode_node_1 = __webpack_require__(5435);
const util_retry_1 = __webpack_require__(5518);
const runtimeConfig_shared_1 = __webpack_require__(357);
const getRuntimeConfig = (config) => {
(0, smithy_client_1.emitWarningIfUnsupportedVersion)(process.version);
const defaultsMode = (0, util_defaults_mode_node_1.resolveDefaultsModeConfig)(config);
const defaultConfigProvider = () => defaultsMode().then(smithy_client_1.loadConfigsForDefaultMode);
const clientSharedValues = (0, runtimeConfig_shared_1.getRuntimeConfig)(config);
(0, core_1.emitWarningIfUnsupportedVersion)(process.version);
const loaderConfig = {
profile: config?.profile,
logger: clientSharedValues.logger,
};
return {
...clientSharedValues,
...config,
runtime: "node",
defaultsMode,
authSchemePreference: config?.authSchemePreference ?? (0, node_config_provider_1.loadConfig)(core_1.NODE_AUTH_SCHEME_PREFERENCE_OPTIONS, loaderConfig),
bodyLengthChecker: config?.bodyLengthChecker ?? util_body_length_node_1.calculateBodyLength,
defaultUserAgentProvider: config?.defaultUserAgentProvider ??
(0, util_user_agent_node_1.createDefaultUserAgentProvider)({ serviceId: clientSharedValues.serviceId, clientVersion: package_json_1.default.version }),
maxAttempts: config?.maxAttempts ?? (0, node_config_provider_1.loadConfig)(middleware_retry_1.NODE_MAX_ATTEMPT_CONFIG_OPTIONS, config),
region: config?.region ??
(0, node_config_provider_1.loadConfig)(config_resolver_1.NODE_REGION_CONFIG_OPTIONS, { ...config_resolver_1.NODE_REGION_CONFIG_FILE_OPTIONS, ...loaderConfig }),
requestHandler: node_http_handler_1.NodeHttpHandler.create(config?.requestHandler ?? defaultConfigProvider),
retryMode: config?.retryMode ??
(0, node_config_provider_1.loadConfig)({
...middleware_retry_1.NODE_RETRY_MODE_CONFIG_OPTIONS,
default: async () => (await defaultConfigProvider()).retryMode || util_retry_1.DEFAULT_RETRY_MODE,
}, config),
sha256: config?.sha256 ?? hash_node_1.Hash.bind(null, "sha256"),
streamCollector: config?.streamCollector ?? node_http_handler_1.streamCollector,
useDualstackEndpoint: config?.useDualstackEndpoint ?? (0, node_config_provider_1.loadConfig)(config_resolver_1.NODE_USE_DUALSTACK_ENDPOINT_CONFIG_OPTIONS, loaderConfig),
useFipsEndpoint: config?.useFipsEndpoint ?? (0, node_config_provider_1.loadConfig)(config_resolver_1.NODE_USE_FIPS_ENDPOINT_CONFIG_OPTIONS, loaderConfig),
userAgentAppId: config?.userAgentAppId ?? (0, node_config_provider_1.loadConfig)(util_user_agent_node_1.NODE_APP_ID_CONFIG_OPTIONS, loaderConfig),
};
};
exports.getRuntimeConfig = getRuntimeConfig;
/***/ }),
/***/ 357:
/***/ ((__unused_webpack_module, exports, __webpack_require__) => {
Object.defineProperty(exports, "__esModule", ({ value: true }));
exports.getRuntimeConfig = void 0;
const core_1 = __webpack_require__(8704);
const protocols_1 = __webpack_require__(7288);
const core_2 = __webpack_require__(402);
const smithy_client_1 = __webpack_require__(1411);
const url_parser_1 = __webpack_require__(4494);
const util_base64_1 = __webpack_require__(8385);
const util_utf8_1 = __webpack_require__(1577);
const httpAuthSchemeProvider_1 = __webpack_require__(7709);
const endpointResolver_1 = __webpack_require__(2547);
const getRuntimeConfig = (config) => {
return {
apiVersion: "2023-01-01",
base64Decoder: config?.base64Decoder ?? util_base64_1.fromBase64,
base64Encoder: config?.base64Encoder ?? util_base64_1.toBase64,
disableHostPrefix: config?.disableHostPrefix ?? false,
endpointProvider: config?.endpointProvider ?? endpointResolver_1.defaultEndpointResolver,
extensions: config?.extensions ?? [],
httpAuthSchemeProvider: config?.httpAuthSchemeProvider ?? httpAuthSchemeProvider_1.defaultSigninHttpAuthSchemeProvider,
httpAuthSchemes: config?.httpAuthSchemes ?? [
{
schemeId: "aws.auth#sigv4",
identityProvider: (ipc) => ipc.getIdentityProvider("aws.auth#sigv4"),
signer: new core_1.AwsSdkSigV4Signer(),
},
{
schemeId: "smithy.api#noAuth",
identityProvider: (ipc) => ipc.getIdentityProvider("smithy.api#noAuth") || (async () => ({})),
signer: new core_2.NoAuthSigner(),
},
],
logger: config?.logger ?? new smithy_client_1.NoOpLogger(),
protocol: config?.protocol ?? protocols_1.AwsRestJsonProtocol,
protocolSettings: config?.protocolSettings ?? {
defaultNamespace: "com.amazonaws.signin",
version: "2023-01-01",
serviceTarget: "Signin",
},
serviceId: config?.serviceId ?? "Signin",
urlParser: config?.urlParser ?? url_parser_1.parseUrl,
utf8Decoder: config?.utf8Decoder ?? util_utf8_1.fromUtf8,
utf8Encoder: config?.utf8Encoder ?? util_utf8_1.toUtf8,
};
};
exports.getRuntimeConfig = getRuntimeConfig;
/***/ }),
/***/ 9955:
/***/ ((module) => {
module.exports = /*#__PURE__*/JSON.parse('{"name":"@aws-sdk/nested-clients","version":"3.982.0","description":"Nested clients for AWS SDK packages.","main":"./dist-cjs/index.js","module":"./dist-es/index.js","types":"./dist-types/index.d.ts","scripts":{"build":"yarn lint && concurrently \'yarn:build:types\' \'yarn:build:es\' && yarn build:cjs","build:cjs":"node ../../scripts/compilation/inline nested-clients","build:es":"tsc -p tsconfig.es.json","build:include:deps":"yarn g:turbo run build -F=\\"$npm_package_name\\"","build:types":"tsc -p tsconfig.types.json","build:types:downlevel":"downlevel-dts dist-types dist-types/ts3.4","clean":"premove dist-cjs dist-es dist-types tsconfig.cjs.tsbuildinfo tsconfig.es.tsbuildinfo tsconfig.types.tsbuildinfo","lint":"node ../../scripts/validation/submodules-linter.js --pkg nested-clients","test":"yarn g:vitest run","test:watch":"yarn g:vitest watch"},"engines":{"node":">=20.0.0"},"sideEffects":false,"author":{"name":"AWS SDK for JavaScript Team","url":"https://aws.amazon.com/javascript/"},"license":"Apache-2.0","dependencies":{"@aws-crypto/sha256-browser":"5.2.0","@aws-crypto/sha256-js":"5.2.0","@aws-sdk/core":"^3.973.6","@aws-sdk/middleware-host-header":"^3.972.3","@aws-sdk/middleware-logger":"^3.972.3","@aws-sdk/middleware-recursion-detection":"^3.972.3","@aws-sdk/middleware-user-agent":"^3.972.6","@aws-sdk/region-config-resolver":"^3.972.3","@aws-sdk/types":"^3.973.1","@aws-sdk/util-endpoints":"3.982.0","@aws-sdk/util-user-agent-browser":"^3.972.3","@aws-sdk/util-user-agent-node":"^3.972.4","@smithy/config-resolver":"^4.4.6","@smithy/core":"^3.22.0","@smithy/fetch-http-handler":"^5.3.9","@smithy/hash-node":"^4.2.8","@smithy/invalid-dependency":"^4.2.8","@smithy/middleware-content-length":"^4.2.8","@smithy/middleware-endpoint":"^4.4.12","@smithy/middleware-retry":"^4.4.29","@smithy/middleware-serde":"^4.2.9","@smithy/middleware-stack":"^4.2.8","@smithy/node-config-provider":"^4.3.8","@smithy/node-http-handler":"^4.4.8","@smithy/protocol-http":"^5.3.8","@smithy/smithy-client":"^4.11.1","@smithy/types":"^4.12.0","@smithy/url-parser":"^4.2.8","@smithy/util-base64":"^4.3.0","@smithy/util-body-length-browser":"^4.2.0","@smithy/util-body-length-node":"^4.2.1","@smithy/util-defaults-mode-browser":"^4.3.28","@smithy/util-defaults-mode-node":"^4.2.31","@smithy/util-endpoints":"^3.2.8","@smithy/util-middleware":"^4.2.8","@smithy/util-retry":"^4.2.8","@smithy/util-utf8":"^4.2.0","tslib":"^2.6.2"},"devDependencies":{"concurrently":"7.0.0","downlevel-dts":"0.10.1","premove":"4.0.0","typescript":"~5.8.3"},"typesVersions":{"<4.0":{"dist-types/*":["dist-types/ts3.4/*"]}},"files":["./signin.d.ts","./signin.js","./sso-oidc.d.ts","./sso-oidc.js","./sts.d.ts","./sts.js","dist-*/**"],"browser":{"./dist-es/submodules/signin/runtimeConfig":"./dist-es/submodules/signin/runtimeConfig.browser","./dist-es/submodules/sso-oidc/runtimeConfig":"./dist-es/submodules/sso-oidc/runtimeConfig.browser","./dist-es/submodules/sts/runtimeConfig":"./dist-es/submodules/sts/runtimeConfig.browser"},"react-native":{},"homepage":"https://github.com/aws/aws-sdk-js-v3/tree/main/packages/nested-clients","repository":{"type":"git","url":"https://github.com/aws/aws-sdk-js-v3.git","directory":"packages/nested-clients"},"exports":{"./package.json":"./package.json","./sso-oidc":{"types":"./dist-types/submodules/sso-oidc/index.d.ts","module":"./dist-es/submodules/sso-oidc/index.js","node":"./dist-cjs/submodules/sso-oidc/index.js","import":"./dist-es/submodules/sso-oidc/index.js","require":"./dist-cjs/submodules/sso-oidc/index.js"},"./sts":{"types":"./dist-types/submodules/sts/index.d.ts","module":"./dist-es/submodules/sts/index.js","node":"./dist-cjs/submodules/sts/index.js","import":"./dist-es/submodules/sts/index.js","require":"./dist-cjs/submodules/sts/index.js"},"./signin":{"types":"./dist-types/submodules/signin/index.d.ts","module":"./dist-es/submodules/signin/index.js","node":"./dist-cjs/submodules/signin/index.js","import":"./dist-es/submodules/signin/index.js","require":"./dist-cjs/submodules/signin/index.js"}}}');
/***/ })
};
;
@@ -0,0 +1,531 @@
"use strict";
exports.id = 869;
exports.ids = [869];
exports.modules = {
/***/ 5869:
/***/ ((__unused_webpack_module, exports, __webpack_require__) => {
var sharedIniFileLoader = __webpack_require__(4964);
var propertyProvider = __webpack_require__(8857);
var client = __webpack_require__(5152);
var credentialProviderLogin = __webpack_require__(4072);
const resolveCredentialSource = (credentialSource, profileName, logger) => {
const sourceProvidersMap = {
EcsContainer: async (options) => {
const { fromHttp } = await __webpack_require__.e(/* import() */ 605).then(__webpack_require__.bind(__webpack_require__, 8605));
const { fromContainerMetadata } = await __webpack_require__.e(/* import() */ 566).then(__webpack_require__.t.bind(__webpack_require__, 566, 19));
logger?.debug("@aws-sdk/credential-provider-ini - credential_source is EcsContainer");
return async () => propertyProvider.chain(fromHttp(options ?? {}), fromContainerMetadata(options))().then(setNamedProvider);
},
Ec2InstanceMetadata: async (options) => {
logger?.debug("@aws-sdk/credential-provider-ini - credential_source is Ec2InstanceMetadata");
const { fromInstanceMetadata } = await __webpack_require__.e(/* import() */ 566).then(__webpack_require__.t.bind(__webpack_require__, 566, 19));
return async () => fromInstanceMetadata(options)().then(setNamedProvider);
},
Environment: async (options) => {
logger?.debug("@aws-sdk/credential-provider-ini - credential_source is Environment");
const { fromEnv } = await Promise.resolve(/* import() */).then(__webpack_require__.t.bind(__webpack_require__, 5606, 19));
return async () => fromEnv(options)().then(setNamedProvider);
},
};
if (credentialSource in sourceProvidersMap) {
return sourceProvidersMap[credentialSource];
}
else {
throw new propertyProvider.CredentialsProviderError(`Unsupported credential source in profile ${profileName}. Got ${credentialSource}, ` +
`expected EcsContainer or Ec2InstanceMetadata or Environment.`, { logger });
}
};
const setNamedProvider = (creds) => client.setCredentialFeature(creds, "CREDENTIALS_PROFILE_NAMED_PROVIDER", "p");
const isAssumeRoleProfile = (arg, { profile = "default", logger } = {}) => {
return (Boolean(arg) &&
typeof arg === "object" &&
typeof arg.role_arn === "string" &&
["undefined", "string"].indexOf(typeof arg.role_session_name) > -1 &&
["undefined", "string"].indexOf(typeof arg.external_id) > -1 &&
["undefined", "string"].indexOf(typeof arg.mfa_serial) > -1 &&
(isAssumeRoleWithSourceProfile(arg, { profile, logger }) || isCredentialSourceProfile(arg, { profile, logger })));
};
const isAssumeRoleWithSourceProfile = (arg, { profile, logger }) => {
const withSourceProfile = typeof arg.source_profile === "string" && typeof arg.credential_source === "undefined";
if (withSourceProfile) {
logger?.debug?.(` ${profile} isAssumeRoleWithSourceProfile source_profile=${arg.source_profile}`);
}
return withSourceProfile;
};
const isCredentialSourceProfile = (arg, { profile, logger }) => {
const withProviderProfile = typeof arg.credential_source === "string" && typeof arg.source_profile === "undefined";
if (withProviderProfile) {
logger?.debug?.(` ${profile} isCredentialSourceProfile credential_source=${arg.credential_source}`);
}
return withProviderProfile;
};
const resolveAssumeRoleCredentials = async (profileName, profiles, options, callerClientConfig, visitedProfiles = {}, resolveProfileData) => {
options.logger?.debug("@aws-sdk/credential-provider-ini - resolveAssumeRoleCredentials (STS)");
const profileData = profiles[profileName];
const { source_profile, region } = profileData;
if (!options.roleAssumer) {
const { getDefaultRoleAssumer } = await __webpack_require__.e(/* import() */ 136).then(__webpack_require__.t.bind(__webpack_require__, 1136, 23));
options.roleAssumer = getDefaultRoleAssumer({
...options.clientConfig,
credentialProviderLogger: options.logger,
parentClientConfig: {
...callerClientConfig,
...options?.parentClientConfig,
region: region ?? options?.parentClientConfig?.region ?? callerClientConfig?.region,
},
}, options.clientPlugins);
}
if (source_profile && source_profile in visitedProfiles) {
throw new propertyProvider.CredentialsProviderError(`Detected a cycle attempting to resolve credentials for profile` +
` ${sharedIniFileLoader.getProfileName(options)}. Profiles visited: ` +
Object.keys(visitedProfiles).join(", "), { logger: options.logger });
}
options.logger?.debug(`@aws-sdk/credential-provider-ini - finding credential resolver using ${source_profile ? `source_profile=[${source_profile}]` : `profile=[${profileName}]`}`);
const sourceCredsProvider = source_profile
? resolveProfileData(source_profile, profiles, options, callerClientConfig, {
...visitedProfiles,
[source_profile]: true,
}, isCredentialSourceWithoutRoleArn(profiles[source_profile] ?? {}))
: (await resolveCredentialSource(profileData.credential_source, profileName, options.logger)(options))();
if (isCredentialSourceWithoutRoleArn(profileData)) {
return sourceCredsProvider.then((creds) => client.setCredentialFeature(creds, "CREDENTIALS_PROFILE_SOURCE_PROFILE", "o"));
}
else {
const params = {
RoleArn: profileData.role_arn,
RoleSessionName: profileData.role_session_name || `aws-sdk-js-${Date.now()}`,
ExternalId: profileData.external_id,
DurationSeconds: parseInt(profileData.duration_seconds || "3600", 10),
};
const { mfa_serial } = profileData;
if (mfa_serial) {
if (!options.mfaCodeProvider) {
throw new propertyProvider.CredentialsProviderError(`Profile ${profileName} requires multi-factor authentication, but no MFA code callback was provided.`, { logger: options.logger, tryNextLink: false });
}
params.SerialNumber = mfa_serial;
params.TokenCode = await options.mfaCodeProvider(mfa_serial);
}
const sourceCreds = await sourceCredsProvider;
return options.roleAssumer(sourceCreds, params).then((creds) => client.setCredentialFeature(creds, "CREDENTIALS_PROFILE_SOURCE_PROFILE", "o"));
}
};
const isCredentialSourceWithoutRoleArn = (section) => {
return !section.role_arn && !!section.credential_source;
};
const isLoginProfile = (data) => {
return Boolean(data && data.login_session);
};
const resolveLoginCredentials = async (profileName, options, callerClientConfig) => {
const credentials = await credentialProviderLogin.fromLoginCredentials({
...options,
profile: profileName,
})({ callerClientConfig });
return client.setCredentialFeature(credentials, "CREDENTIALS_PROFILE_LOGIN", "AC");
};
const isProcessProfile = (arg) => Boolean(arg) && typeof arg === "object" && typeof arg.credential_process === "string";
const resolveProcessCredentials = async (options, profile) => __webpack_require__.e(/* import() */ 360).then(__webpack_require__.t.bind(__webpack_require__, 5360, 19)).then(({ fromProcess }) => fromProcess({
...options,
profile,
})().then((creds) => client.setCredentialFeature(creds, "CREDENTIALS_PROFILE_PROCESS", "v")));
const resolveSsoCredentials = async (profile, profileData, options = {}, callerClientConfig) => {
const { fromSSO } = await __webpack_require__.e(/* import() */ 998).then(__webpack_require__.t.bind(__webpack_require__, 998, 19));
return fromSSO({
profile,
logger: options.logger,
parentClientConfig: options.parentClientConfig,
clientConfig: options.clientConfig,
})({
callerClientConfig,
}).then((creds) => {
if (profileData.sso_session) {
return client.setCredentialFeature(creds, "CREDENTIALS_PROFILE_SSO", "r");
}
else {
return client.setCredentialFeature(creds, "CREDENTIALS_PROFILE_SSO_LEGACY", "t");
}
});
};
const isSsoProfile = (arg) => arg &&
(typeof arg.sso_start_url === "string" ||
typeof arg.sso_account_id === "string" ||
typeof arg.sso_session === "string" ||
typeof arg.sso_region === "string" ||
typeof arg.sso_role_name === "string");
const isStaticCredsProfile = (arg) => Boolean(arg) &&
typeof arg === "object" &&
typeof arg.aws_access_key_id === "string" &&
typeof arg.aws_secret_access_key === "string" &&
["undefined", "string"].indexOf(typeof arg.aws_session_token) > -1 &&
["undefined", "string"].indexOf(typeof arg.aws_account_id) > -1;
const resolveStaticCredentials = async (profile, options) => {
options?.logger?.debug("@aws-sdk/credential-provider-ini - resolveStaticCredentials");
const credentials = {
accessKeyId: profile.aws_access_key_id,
secretAccessKey: profile.aws_secret_access_key,
sessionToken: profile.aws_session_token,
...(profile.aws_credential_scope && { credentialScope: profile.aws_credential_scope }),
...(profile.aws_account_id && { accountId: profile.aws_account_id }),
};
return client.setCredentialFeature(credentials, "CREDENTIALS_PROFILE", "n");
};
const isWebIdentityProfile = (arg) => Boolean(arg) &&
typeof arg === "object" &&
typeof arg.web_identity_token_file === "string" &&
typeof arg.role_arn === "string" &&
["undefined", "string"].indexOf(typeof arg.role_session_name) > -1;
const resolveWebIdentityCredentials = async (profile, options, callerClientConfig) => __webpack_require__.e(/* import() */ 956).then(__webpack_require__.t.bind(__webpack_require__, 9956, 23)).then(({ fromTokenFile }) => fromTokenFile({
webIdentityTokenFile: profile.web_identity_token_file,
roleArn: profile.role_arn,
roleSessionName: profile.role_session_name,
roleAssumerWithWebIdentity: options.roleAssumerWithWebIdentity,
logger: options.logger,
parentClientConfig: options.parentClientConfig,
})({
callerClientConfig,
}).then((creds) => client.setCredentialFeature(creds, "CREDENTIALS_PROFILE_STS_WEB_ID_TOKEN", "q")));
const resolveProfileData = async (profileName, profiles, options, callerClientConfig, visitedProfiles = {}, isAssumeRoleRecursiveCall = false) => {
const data = profiles[profileName];
if (Object.keys(visitedProfiles).length > 0 && isStaticCredsProfile(data)) {
return resolveStaticCredentials(data, options);
}
if (isAssumeRoleRecursiveCall || isAssumeRoleProfile(data, { profile: profileName, logger: options.logger })) {
return resolveAssumeRoleCredentials(profileName, profiles, options, callerClientConfig, visitedProfiles, resolveProfileData);
}
if (isStaticCredsProfile(data)) {
return resolveStaticCredentials(data, options);
}
if (isWebIdentityProfile(data)) {
return resolveWebIdentityCredentials(data, options, callerClientConfig);
}
if (isProcessProfile(data)) {
return resolveProcessCredentials(options, profileName);
}
if (isSsoProfile(data)) {
return await resolveSsoCredentials(profileName, data, options, callerClientConfig);
}
if (isLoginProfile(data)) {
return resolveLoginCredentials(profileName, options, callerClientConfig);
}
throw new propertyProvider.CredentialsProviderError(`Could not resolve credentials using profile: [${profileName}] in configuration/credentials file(s).`, { logger: options.logger });
};
const fromIni = (init = {}) => async ({ callerClientConfig } = {}) => {
init.logger?.debug("@aws-sdk/credential-provider-ini - fromIni");
const profiles = await sharedIniFileLoader.parseKnownFiles(init);
return resolveProfileData(sharedIniFileLoader.getProfileName({
profile: init.profile ?? callerClientConfig?.profile,
}), profiles, init, callerClientConfig);
};
exports.fromIni = fromIni;
/***/ }),
/***/ 4072:
/***/ ((__unused_webpack_module, exports, __webpack_require__) => {
var client = __webpack_require__(5152);
var propertyProvider = __webpack_require__(8857);
var sharedIniFileLoader = __webpack_require__(4964);
var protocolHttp = __webpack_require__(2356);
var node_crypto = __webpack_require__(7598);
var node_fs = __webpack_require__(3024);
var node_os = __webpack_require__(8161);
var node_path = __webpack_require__(6760);
class LoginCredentialsFetcher {
profileData;
init;
callerClientConfig;
static REFRESH_THRESHOLD = 5 * 60 * 1000;
constructor(profileData, init, callerClientConfig) {
this.profileData = profileData;
this.init = init;
this.callerClientConfig = callerClientConfig;
}
async loadCredentials() {
const token = await this.loadToken();
if (!token) {
throw new propertyProvider.CredentialsProviderError(`Failed to load a token for session ${this.loginSession}, please re-authenticate using aws login`, { tryNextLink: false, logger: this.logger });
}
const accessToken = token.accessToken;
const now = Date.now();
const expiryTime = new Date(accessToken.expiresAt).getTime();
const timeUntilExpiry = expiryTime - now;
if (timeUntilExpiry <= LoginCredentialsFetcher.REFRESH_THRESHOLD) {
return this.refresh(token);
}
return {
accessKeyId: accessToken.accessKeyId,
secretAccessKey: accessToken.secretAccessKey,
sessionToken: accessToken.sessionToken,
accountId: accessToken.accountId,
expiration: new Date(accessToken.expiresAt),
};
}
get logger() {
return this.init?.logger;
}
get loginSession() {
return this.profileData.login_session;
}
async refresh(token) {
const { SigninClient, CreateOAuth2TokenCommand } = await __webpack_require__.e(/* import() */ 762).then(__webpack_require__.t.bind(__webpack_require__, 9762, 19));
const { logger, userAgentAppId } = this.callerClientConfig ?? {};
const isH2 = (requestHandler) => {
return requestHandler?.metadata?.handlerProtocol === "h2";
};
const requestHandler = isH2(this.callerClientConfig?.requestHandler)
? undefined
: this.callerClientConfig?.requestHandler;
const region = this.profileData.region ?? (await this.callerClientConfig?.region?.()) ?? process.env.AWS_REGION;
const client = new SigninClient({
credentials: {
accessKeyId: "",
secretAccessKey: "",
},
region,
requestHandler,
logger,
userAgentAppId,
...this.init?.clientConfig,
});
this.createDPoPInterceptor(client.middlewareStack);
const commandInput = {
tokenInput: {
clientId: token.clientId,
refreshToken: token.refreshToken,
grantType: "refresh_token",
},
};
try {
const response = await client.send(new CreateOAuth2TokenCommand(commandInput));
const { accessKeyId, secretAccessKey, sessionToken } = response.tokenOutput?.accessToken ?? {};
const { refreshToken, expiresIn } = response.tokenOutput ?? {};
if (!accessKeyId || !secretAccessKey || !sessionToken || !refreshToken) {
throw new propertyProvider.CredentialsProviderError("Token refresh response missing required fields", {
logger: this.logger,
tryNextLink: false,
});
}
const expiresInMs = (expiresIn ?? 900) * 1000;
const expiration = new Date(Date.now() + expiresInMs);
const updatedToken = {
...token,
accessToken: {
...token.accessToken,
accessKeyId: accessKeyId,
secretAccessKey: secretAccessKey,
sessionToken: sessionToken,
expiresAt: expiration.toISOString(),
},
refreshToken: refreshToken,
};
await this.saveToken(updatedToken);
const newAccessToken = updatedToken.accessToken;
return {
accessKeyId: newAccessToken.accessKeyId,
secretAccessKey: newAccessToken.secretAccessKey,
sessionToken: newAccessToken.sessionToken,
accountId: newAccessToken.accountId,
expiration,
};
}
catch (error) {
if (error.name === "AccessDeniedException") {
const errorType = error.error;
let message;
switch (errorType) {
case "TOKEN_EXPIRED":
message = "Your session has expired. Please reauthenticate.";
break;
case "USER_CREDENTIALS_CHANGED":
message =
"Unable to refresh credentials because of a change in your password. Please reauthenticate with your new password.";
break;
case "INSUFFICIENT_PERMISSIONS":
message =
"Unable to refresh credentials due to insufficient permissions. You may be missing permission for the 'CreateOAuth2Token' action.";
break;
default:
message = `Failed to refresh token: ${String(error)}. Please re-authenticate using \`aws login\``;
}
throw new propertyProvider.CredentialsProviderError(message, { logger: this.logger, tryNextLink: false });
}
throw new propertyProvider.CredentialsProviderError(`Failed to refresh token: ${String(error)}. Please re-authenticate using aws login`, { logger: this.logger });
}
}
async loadToken() {
const tokenFilePath = this.getTokenFilePath();
try {
let tokenData;
try {
tokenData = await sharedIniFileLoader.readFile(tokenFilePath, { ignoreCache: this.init?.ignoreCache });
}
catch {
tokenData = await node_fs.promises.readFile(tokenFilePath, "utf8");
}
const token = JSON.parse(tokenData);
const missingFields = ["accessToken", "clientId", "refreshToken", "dpopKey"].filter((k) => !token[k]);
if (!token.accessToken?.accountId) {
missingFields.push("accountId");
}
if (missingFields.length > 0) {
throw new propertyProvider.CredentialsProviderError(`Token validation failed, missing fields: ${missingFields.join(", ")}`, {
logger: this.logger,
tryNextLink: false,
});
}
return token;
}
catch (error) {
throw new propertyProvider.CredentialsProviderError(`Failed to load token from ${tokenFilePath}: ${String(error)}`, {
logger: this.logger,
tryNextLink: false,
});
}
}
async saveToken(token) {
const tokenFilePath = this.getTokenFilePath();
const directory = node_path.dirname(tokenFilePath);
try {
await node_fs.promises.mkdir(directory, { recursive: true });
}
catch (error) {
}
await node_fs.promises.writeFile(tokenFilePath, JSON.stringify(token, null, 2), "utf8");
}
getTokenFilePath() {
const directory = process.env.AWS_LOGIN_CACHE_DIRECTORY ?? node_path.join(node_os.homedir(), ".aws", "login", "cache");
const loginSessionBytes = Buffer.from(this.loginSession, "utf8");
const loginSessionSha256 = node_crypto.createHash("sha256").update(loginSessionBytes).digest("hex");
return node_path.join(directory, `${loginSessionSha256}.json`);
}
derToRawSignature(derSignature) {
let offset = 2;
if (derSignature[offset] !== 0x02) {
throw new Error("Invalid DER signature");
}
offset++;
const rLength = derSignature[offset++];
let r = derSignature.subarray(offset, offset + rLength);
offset += rLength;
if (derSignature[offset] !== 0x02) {
throw new Error("Invalid DER signature");
}
offset++;
const sLength = derSignature[offset++];
let s = derSignature.subarray(offset, offset + sLength);
r = r[0] === 0x00 ? r.subarray(1) : r;
s = s[0] === 0x00 ? s.subarray(1) : s;
const rPadded = Buffer.concat([Buffer.alloc(32 - r.length), r]);
const sPadded = Buffer.concat([Buffer.alloc(32 - s.length), s]);
return Buffer.concat([rPadded, sPadded]);
}
createDPoPInterceptor(middlewareStack) {
middlewareStack.add((next) => async (args) => {
if (protocolHttp.HttpRequest.isInstance(args.request)) {
const request = args.request;
const actualEndpoint = `${request.protocol}//${request.hostname}${request.port ? `:${request.port}` : ""}${request.path}`;
const dpop = await this.generateDpop(request.method, actualEndpoint);
request.headers = {
...request.headers,
DPoP: dpop,
};
}
return next(args);
}, {
step: "finalizeRequest",
name: "dpopInterceptor",
override: true,
});
}
async generateDpop(method = "POST", endpoint) {
const token = await this.loadToken();
try {
const privateKey = node_crypto.createPrivateKey({
key: token.dpopKey,
format: "pem",
type: "sec1",
});
const publicKey = node_crypto.createPublicKey(privateKey);
const publicDer = publicKey.export({ format: "der", type: "spki" });
let pointStart = -1;
for (let i = 0; i < publicDer.length; i++) {
if (publicDer[i] === 0x04) {
pointStart = i;
break;
}
}
const x = publicDer.slice(pointStart + 1, pointStart + 33);
const y = publicDer.slice(pointStart + 33, pointStart + 65);
const header = {
alg: "ES256",
typ: "dpop+jwt",
jwk: {
kty: "EC",
crv: "P-256",
x: x.toString("base64url"),
y: y.toString("base64url"),
},
};
const payload = {
jti: crypto.randomUUID(),
htm: method,
htu: endpoint,
iat: Math.floor(Date.now() / 1000),
};
const headerB64 = Buffer.from(JSON.stringify(header)).toString("base64url");
const payloadB64 = Buffer.from(JSON.stringify(payload)).toString("base64url");
const message = `${headerB64}.${payloadB64}`;
const asn1Signature = node_crypto.sign("sha256", Buffer.from(message), privateKey);
const rawSignature = this.derToRawSignature(asn1Signature);
const signatureB64 = rawSignature.toString("base64url");
return `${message}.${signatureB64}`;
}
catch (error) {
throw new propertyProvider.CredentialsProviderError(`Failed to generate Dpop proof: ${error instanceof Error ? error.message : String(error)}`, { logger: this.logger, tryNextLink: false });
}
}
}
const fromLoginCredentials = (init) => async ({ callerClientConfig } = {}) => {
init?.logger?.debug?.("@aws-sdk/credential-providers - fromLoginCredentials");
const profiles = await sharedIniFileLoader.parseKnownFiles(init || {});
const profileName = sharedIniFileLoader.getProfileName({
profile: init?.profile ?? callerClientConfig?.profile,
});
const profile = profiles[profileName];
if (!profile?.login_session) {
throw new propertyProvider.CredentialsProviderError(`Profile ${profileName} does not contain login_session.`, {
tryNextLink: true,
logger: init?.logger,
});
}
const fetcher = new LoginCredentialsFetcher(profile, init, callerClientConfig);
const credentials = await fetcher.loadCredentials();
return client.setCredentialFeature(credentials, "CREDENTIALS_LOGIN", "AD");
};
exports.fromLoginCredentials = fromLoginCredentials;
/***/ })
};
;
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
+50
View File
@@ -0,0 +1,50 @@
const core = require('@actions/core');
const { SES } = require("@aws-sdk/client-ses");
const fs = require('fs');
const region = core.getInput('region');
const version = core.getInput('version');
const format = core.getInput('format');
const Template = core.getInput('template');
const dataFilePath = core.getInput('dataFile');
const CcAddresses = JSON.parse(core.getInput('ccAddresses'));
const ToAddresses = JSON.parse(core.getInput('toAddresses'));
const ReplyToAddresses = JSON.parse(core.getInput('replyToAddresses'));
const workflowURL = core.getInput('workflowURL');
const subject = core.getInput('subject');
const bodyPath = core.getInput('bodyPath');
const data = dataFilePath ? fs.readFileSync(dataFilePath, { encoding: 'utf-8' }) : "";
const body = bodyPath ? fs.readFileSync(bodyPath, { encoding: 'utf-8' }) : "";
const templated = {
version,
format,
results: data,
workflowURL,
subject,
body,
};
// Create sendEmail params
const params = {
Destination: { /* required */
CcAddresses,
ToAddresses,
},
Source: 'github-actions-bot@corp.ld-corp.com', /* required */
Template,
TemplateData: JSON.stringify(templated),
ReplyToAddresses,
};
console.log(params)
// Create the promise and SES service object
const sendPromise = new SES({region}).sendTemplatedEmail(params);
// Handle promise's fulfilled/rejected states
sendPromise
.then((data) => console.log("Successfully sent email:", data.MessageId))
.catch((err) => console.error(err, err.stack));
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,22 @@
{
"name": "ses-email-action",
"version": "0.1.0",
"description": "",
"main": "index.js",
"keywords": [],
"author": "dolthub",
"license": "ISC",
"scripts": {
"build": "ncc build index.js"
},
"dependencies": {
"@actions/core": "^2.0.3",
"@aws-sdk/client-ses": "^3.982.0"
},
"devDependencies": {
"@vercel/ncc": "^0.38.4"
},
"overrides": {
"fast-xml-parser": "^5.3.6"
}
}
@@ -0,0 +1,12 @@
name: 'Set up dolt config'
description: 'Sets the global dolt user.name and user.email used by CI workflows. Requires the dolt binary to already be on PATH (e.g. via the build-dolt action).'
runs:
using: 'composite'
steps:
- name: Configure dolt
shell: bash
run: |
dolt config --global --add metrics.disabled true
dolt config --global --add user.name 'Dolthub Actions'
dolt config --global --add user.email 'actions@dolthub.com'
@@ -0,0 +1,31 @@
name: 'Set up Go toolchain'
description: 'Set up Go and platform-specific dependencies (ICU4C) needed to build dolt. On macOS, sets CGO flags pointing at brew icu4c. On Windows, installs MSYS2 with icu/toolchain/pkg-config and exposes the install path via the msys2-location output. On Linux, just sets up Go.'
outputs:
msys2-location:
description: 'Path to the MSYS2 installation (Windows only).'
value: ${{ steps.msys2.outputs.msys2-location }}
runs:
using: 'composite'
steps:
- name: Set up Go
uses: actions/setup-go@v5
with:
go-version-file: go/go.mod
- name: Install ICU4C (MacOS)
if: runner.os == 'macOS'
shell: bash
run: |
dir=$(brew --cellar icu4c)
dir="$dir"/$(ls "$dir")
echo CGO_CPPFLAGS=-I$dir/include >> $GITHUB_ENV
echo CGO_LDFLAGS=-L$dir/lib >> $GITHUB_ENV
- name: Install ICU4C (Windows)
id: msys2
if: runner.os == 'Windows'
uses: msys2/setup-msys2@v2
with:
path-type: inherit
msystem: UCRT64
pacboy: icu:p toolchain:p pkg-config:p
+14
View File
@@ -0,0 +1,14 @@
:coffee: *An Automated Dependency Version Bump PR* :crown:
### Initial Changes
The initial changes contained in this PR were produced by `go get`ing the dependency.
```
$ cd ./go
$ go get github.com/dolthub/<dependency>/go@<commit>
```
### Before Merging
This PR must have passing CI and a review before merging.
+55
View File
@@ -0,0 +1,55 @@
#!/bin/sh
set -e
if [ "$#" -ne 2 ]; then
echo "Usage: ./get-dolt-correctness-job-json.sh <jobname> <version>"
exit 1
fi
jobname="$1"
version="$2"
echo '
{
"apiVersion": "batch/v1",
"kind": "Job",
"metadata": {
"name": "'$jobname'",
"namespace": "fuzzer"
},
"spec": {
"backoffLimit": 2,
"template": {
"metadata": {
"labels": {
"k8s-liquidata-inc-monitored-job": "created-by-static-config",
"app": "fuzzer"
}
},
"spec": {
"serviceAccountName": "fuzzer",
"containers": [
{
"name": "fuzzer",
"image": "407903926827.dkr.ecr.us-west-2.amazonaws.com/liquidata/fuzzer:latest",
"env": [
{ "name": "REPO_ACCESS_TOKEN", "value": "'$REPO_ACCESS_TOKEN'"},
{ "name": "ACTOR", "value": "'$ACTOR'"},
{ "name": "DOLT_BIN", "value": "/usr/local/bin"}
],
"args": [
"--dolt-version='$version'",
"--bucket=dolt-fuzzer-runs",
"--region=us-west-2",
"--version-gate-job",
"--fuzzer-args=basic, --cycles=5"
]
}
],
"restartPolicy": "OnFailure"
}
}
}
}
'
+52
View File
@@ -0,0 +1,52 @@
#!/bin/bash
set -e
if [ -z "$KUBECONFIG" ]; then
echo "Must set KUBECONFIG"
exit 1
fi
if [ -z "$TEMPLATE_SCRIPT" ]; then
echo "Must set TEMPLATE_SCRIPT"
exit 1
fi
if [ -z "$VERSION" ]; then
echo "Must set VERSION"
exit 1
fi
echo "using dolt version: $VERSION"
if [ -z "$ACTOR" ]; then
echo "Must set ACTOR"
exit 1
fi
nomsFormat="ldnbf"
if [ "$NOMS_BIN_FORMAT" == "__DOLT__"]; then
nomsFormat="doltnbf"
fi
# use first 8 characters of TO_VERSION to differentiate
# jobs
short=${VERSION:0:8}
lowered=$(echo "$ACTOR" | tr '[:upper:]' '[:lower:]')
actorShort="$lowered-$nomsFormat-$short"
jobname="$actorShort"
source "$TEMPLATE_SCRIPT" "$jobname" "$VERSION" > job.json
out=$(KUBECONFIG="$KUBECONFIG" kubectl apply -f job.json || true)
if [ "$out" != "job.batch/$jobname created" ]; then
echo "something went wrong creating job... this job likely already exists in the cluster"
echo "$out"
exit 1
else
echo "$out"
fi
exit 0
+109
View File
@@ -0,0 +1,109 @@
import os
import shutil
import sys
import random
if len(sys.argv) != 7:
print("usage: python3 data.py <output-dir> <table-num> <row-num> <add-num> <delete-num> <update-num>")
sys.exit(1)
table_dir = sys.argv[1]
tables = int(sys.argv[2])
rows = int(sys.argv[3])
adds = int(sys.argv[4])
deletes = int(sys.argv[5])
updates = int(sys.argv[6])
if __name__=="__main__":
if deletes + updates > rows:
raise ValueError(f"deletes({deletes}) + updates({updates}) = {updates+deletes} > total rows({rows})")
if not os.path.exists(table_dir):
shutil.rmtree(table_dir, ignore_errors=True)
os.makedirs(table_dir)
ys = [i for i in range(rows+adds+deletes+updates)]
random.shuffle(ys)
with open(f"{table_dir}/create.sql", "+w") as f:
for i in range(tables):
if i == 0:
f.write(f"create table table{i} (x int primary key, y int, z int, key y_idx(y));\n")
else:
f.write(f"create table table{i} (x int primary key, y int, z int, key y_idx(y), foreign key (y) references table{i-1}(y));\n")
for j in range(tables):
with open(f"{table_dir}/table{j}.csv", "+w") as f:
f.write("x,y,z\n")
for i in range(rows+deletes+updates):
f.write(f"{i},{ys[i]},{i}\n")
with open(f"{table_dir}/branch.sql", "+w") as f:
for i in range(tables):
f.write(f"set foreign_key_checks = 0;\n")
f.write(f"set unique_checks = 0;\n")
if adds > 0:
f.write(f"insert into table{i} values\n")
for j,k in enumerate(ys[rows+deletes+updates:rows+deletes+updates+adds]):
if j == 0:
f.write(f" ")
else:
f.write(f", ")
f.write(f"({rows+deletes+updates+j},{k},{rows+deletes+updates+j})")
f.write(f";\n")
if deletes > 0:
f.write(f"delete from table{i} where x in\n")
for j, y in enumerate(ys[:deletes]):
if j == 0:
f.write(f" (")
else:
f.write(f", ")
f.write(f"{y}")
f.write(f");\n")
if updates > 0:
f.write(f"update table{i} set y=y+1 where x in\n")
for j, y in enumerate(ys[deletes:deletes+updates]):
if j == 0:
f.write(f" (")
else:
f.write(f", ")
f.write(f"{y}")
f.write(f");\n")
with open(f"{table_dir}/diverge_main.sql", "+w") as f:
for i in range(tables):
f.write(f"set foreign_key_checks = 0;\n")
f.write(f"set unique_checks = 0;\n")
if adds > 0:
# y value is one higher, conflict
f.write(f"insert into table{i} values\n")
for j,k in enumerate(ys[rows+deletes+updates:rows+deletes+updates+adds]):
if j == 0:
f.write(f" ")
else:
f.write(f", ")
f.write(f"({rows+deletes+updates+j},{k+1},{rows+deletes+updates+j})")
f.write(f";\n")
if deletes > 0:
f.write(f"delete from table{i} where y in\n")
for j, y in enumerate(ys[:deletes]):
if j == 0:
f.write(f" (")
else:
f.write(f", ")
f.write(f"{y}")
f.write(f");\n")
if updates > 0:
f.write(f"update table{i} set y=y+1 where y in\n")
for j, y in enumerate(ys[deletes:deletes+updates]):
if j == 0:
f.write(f" (")
else:
f.write(f", ")
f.write(f"{y}")
f.write(f");\n")
+37
View File
@@ -0,0 +1,37 @@
#!/bin/bash
if [ "$#" -ne 2 ]; then
echo "usage: setup.sh <dolt-dir> <data-dir>"
exit 1
fi
DIR=$1
DATA=$2
rm -rf $DIR
mkdir $DIR
cd $DIR
dolt init
dolt sql < $DATA/create.sql
i=0
for t in $(ls $DATA/ | grep "table"); do
echo $t
dolt table import --disable-fk-checks -u "table${i}" "$DATA/$t"
((i++))
done
dolt commit -Am "add tables"
dolt sql < $DATA/diverge_main.sql
dolt commit -Am "add rows to conflict"
dolt checkout -b feature
dolt reset --hard head~1
dolt sql < $DATA/branch.sql
dolt commit -Am "new branch"
@@ -0,0 +1,135 @@
#!/bin/sh
set -e
if [ "$#" -lt 10 ]; then
echo "Usage: ./get-job-json.sh <jobname> <fromServer> <fromVersion> <toServer> <toVersion> <timePrefix> <actorPrefix> <format> <issueNumber> <initBigRepo> <nomsBinFormat> <sysbenchTestTime> <withTpcc>"
exit 1
fi
jobName="$1"
fromServer="$2"
fromVersion="$3"
toServer="$4"
toVersion="$5"
timePrefix="$6"
actorPrefix="$7"
format="$8"
issueNumber="$9"
initBigRepo="${10}"
nomsBinFormat="${11}"
sysbenchTestTime="${12}"
withTpcc="${13}"
tpccRegex="tpcc%"
if [ -n "$initBigRepo" ]; then
initBigRepo="\"--init-big-repo=$initBigRepo\","
fi
if [ -n "$nomsBinFormat" ]; then
nomsBinFormat="\"--noms-bin-format=$nomsBinFormat\","
fi
if [ -n "$sysbenchTestTime" ]; then
sysbenchTestTime="\"--sysbench-test-time=$sysbenchTestTime\","
fi
if [ -n "$withTpcc" ]; then
withTpcc="\"--withTpcc=$withTpcc\","
fi
readTests="('oltp_read_only','oltp_point_select','select_random_points','select_random_ranges','covering_index_scan','index_scan','table_scan','groupby_scan','index_join_scan','types_table_scan','index_join')"
medianLatencyChangeReadsQuery="with result(test_name, from_latency, to_latency) as (select f.test_name, avg(f.latency_percentile), avg(t.latency_percentile) from from_results as f join to_results as t on f.test_name = t.test_name where f.test_name in $readTests group by f.test_name) select test_name as read_tests, from_latency, to_latency, round(100 * ((to_latency - from_latency) / from_latency), 2) as percent_change from result;"
writeTests="('oltp_read_write','oltp_update_index','oltp_update_non_index','oltp_insert','oltp_write_only','oltp_delete_insert','types_delete_insert')"
medianLatencyChangeWritesQuery="with result(test_name, from_latency, to_latency) as (select f.test_name, avg(f.latency_percentile), avg(t.latency_percentile) from from_results as f join to_results as t on f.test_name = t.test_name where f.test_name in $writeTests group by f.test_name) select test_name as write_tests, from_latency, to_latency, round(100 * ((to_latency - from_latency) / from_latency), 2) as percent_change from result;"
tpccLatencyQuery="with result(test_name, from_latency, to_latency) as (select f.test_name, avg(f.latency_percentile), avg(t.latency_percentile) from from_results as f join to_results as t on f.test_name = t.test_name where f.test_name LIKE '$tpccRegex' group by f.test_name) select test_name, from_latency as from_latency_p95, to_latency as to_latency_p95, round(100 * ((to_latency - from_latency) / from_latency), 2) as percent_change from result;"
tpccTpsQuery="with result(test_name, from_server_name, from_server_version, from_tps, to_server_name, to_server_version, to_tps) as (select f.test_name, f.server_name, f.server_version, avg(f.sql_transactions_per_second), t.server_name, t.server_version, avg(t.sql_transactions_per_second) from from_results as f join to_results as t on f.test_name = t.test_name where f.test_name LIKE 'tpcc%' group by f.test_name) select test_name, from_server_name, from_server_version, from_tps, to_server_name, to_server_version, to_tps, round(100 * ((to_tps - from_tps) / from_tps), 2) as percent_change from result;"
perfRegressionQuery="with result(from_lat, to_lat) as (select avg(f.latency_percentile), avg(t.latency_percentile) from from_results as f join to_results as t on f.test_name = t.test_name group by t.test_name) select sum((to_lat - from_lat) / from_lat > 0.05) from result;"
echo '
{
"apiVersion": "batch/v1",
"kind": "Job",
"metadata": {
"name": "'$jobName'",
"namespace": "performance-benchmarking"
},
"spec": {
"backoffLimit": 1,
"template": {
"metadata": {
"annotations": {
"alert_recipients": "'$ACTOR_EMAIL'"
},
"labels": {
"k8s-liquidata-inc-monitored-job": "created-by-static-config",
"app": "performance-benchmarking"
}
},
"spec": {
"serviceAccountName": "performance-benchmarking",
"containers": [
{
"name": "performance-benchmarking",
"image": "407903926827.dkr.ecr.us-west-2.amazonaws.com/liquidata/performance-benchmarking:latest",
"resources": {
"limits": {
"cpu": "7000m"
}
},
"env": [
{ "name": "GOMAXPROCS", "value": "7" },
{ "name": "GOEXPERIMENT", "value": "greenteagc" },
{ "name": "ACTOR", "value": "'$ACTOR'" },
{ "name": "ACTOR_EMAIL", "value": "'$ACTOR_EMAIL'" },
{ "name": "REPO_ACCESS_TOKEN", "value": "'$REPO_ACCESS_TOKEN'" }
],
"imagePullPolicy": "Always",
"args": [
"--schema=/app/schema.sql",
"--useDoltHubLuaScriptsRepo",
"--output='$format'",
"--from-server='$fromServer'",
"--from-version='$fromVersion'",
"--to-server='$toServer'",
"--to-version='$toVersion'",
"--bucket=performance-benchmarking-github-actions-results",
"--region=us-west-2",
"--issue-number='$issueNumber'",
"--results-dir='$timePrefix'",
"--results-prefix='$actorPrefix'",
"--perf-regression-query='"$perfRegressionQuery"'",
'"$sysbenchTestTime"'
'"$withTpcc"'
'"$initBigRepo"'
'"$nomsBinFormat"'
"--sysbenchQueries='"$medianLatencyChangeReadsQuery"'",
"--sysbenchQueries='"$medianLatencyChangeWritesQuery"'",
"--tpccQueries='"$tpccLatencyQuery"'",
"--tpccQueries='"$tpccTpsQuery"'"
]
}
],
"restartPolicy": "Never",
"nodeSelector": {
"performance-benchmarking-worker": "true"
},
"tolerations": [
{
"effect": "NoSchedule",
"key": "dedicated",
"operator": "Equal",
"value": "performance-benchmarking-worker"
}
]
}
}
}
}
'
@@ -0,0 +1,98 @@
#!/bin/sh
set -e
if [ "$#" -lt 6 ]; then
echo "Usage: ./get-job-json.sh <jobname> <version> <futureVersion> <timePrefix> <actorPrefix> <format> <initBigRepo> <nomsBinFormat>"
exit 1
fi
jobName="$1"
version="$2"
futureVersion="$3"
timePrefix="$4"
actorPrefix="$5"
format="$6"
initBigRepo="$7"
nomsBinFormat="$8"
if [ -n "$initBigRepo" ]; then
initBigRepo="\"--init-big-repo=$initBigRepo\","
fi
if [ -n "$nomsBinFormat" ]; then
nomsBinFormat="\"--noms-bin-format=$nomsBinFormat\","
fi
echo '
{
"apiVersion": "batch/v1",
"kind": "Job",
"metadata": {
"name": "'$jobName'",
"namespace": "performance-benchmarking"
},
"spec": {
"backoffLimit": 1,
"template": {
"metadata": {
"annotations": {
"alert_recipients": "'$ACTOR_EMAIL'"
},
"labels": {
"k8s-liquidata-inc-monitored-job": "created-by-static-config",
"app": "performance-benchmarking"
}
},
"spec": {
"serviceAccountName": "performance-benchmarking",
"containers": [
{
"name": "performance-benchmarking",
"image": "407903926827.dkr.ecr.us-west-2.amazonaws.com/liquidata/performance-benchmarking:latest",
"resources": {
"limits": {
"cpu": "7000m"
}
},
"env": [
{ "name": "GOMAXPROCS", "value": "7" },
{ "name": "GOEXPERIMENT", "value": "greenteagc" },
{ "name": "ACTOR", "value": "'$ACTOR'" },
{ "name": "ACTOR_EMAIL", "value": "'$ACTOR_EMAIL'" },
{ "name": "REPO_ACCESS_TOKEN", "value": "'$REPO_ACCESS_TOKEN'" },
{ "name": "BRANCH", "value": "'$BRANCH'" }
],
"imagePullPolicy": "Always",
"args": [
"--schema=/app/schema.sql",
"--useDoltHubLuaScriptsRepo",
"--profile-version='"$version"'",
"--future-version='"$futureVersion"'",
"--bucket=performance-benchmarking-github-actions-results",
"--region=us-west-2",
"--results-dir='$timePrefix'",
"--results-prefix='$actorPrefix'",
'"$initBigRepo"'
'"$nomsBinFormat"'
"--output='$format'"
]
}
],
"restartPolicy": "Never",
"nodeSelector": {
"performance-benchmarking-worker": "true"
},
"tolerations": [
{
"effect": "NoSchedule",
"key": "dedicated",
"operator": "Equal",
"value": "performance-benchmarking-worker"
}
]
}
}
}
}
'
@@ -0,0 +1,147 @@
#!/bin/sh
set -e
if [ "$#" -lt 12 ]; then
echo "Usage: ./get-job-json.sh <jobname> <fromServer> <fromVersion> <toServer> <toVersion> <timeprefix> <actorprefix> <format> <issueNumber> <initBigRepo> <nomsBinFormat> <sysbenchTestTime> <withTpcc>"
exit 1
fi
jobname="$1"
fromServer="$2"
fromVersion="$3"
toServer="$4"
toVersion="$5"
timeprefix="$6"
actorprefix="$7"
format="$8"
issueNumber="$9"
initBigRepo="${10}"
nomsBinFormat="${11}"
sysbenchTestTime="${12}"
withTpcc="${13}"
precision="2"
tpccRegex="tpcc%"
toProfileKey=""
if [ -n "$initBigRepo" ]; then
initBigRepo="\"--init-big-repo=$initBigRepo\","
fi
if [ -n "$nomsBinFormat" ]; then
nomsBinFormat="\"--noms-bin-format=$nomsBinFormat\","
fi
if [ -n "$sysbenchTestTime" ]; then
sysbenchTestTime="\"--sysbench-test-time=$sysbenchTestTime\","
fi
if [ -n "$withTpcc" ]; then
withTpcc="\"--withTpcc=$withTpcc\","
fi
if [ -n "$TO_PROFILE_KEY" ]; then
toProfileKey="\"--to-profile-key=$TO_PROFILE_KEY\","
fi
readTests="('oltp_read_only', 'oltp_point_select', 'select_random_points', 'select_random_ranges', 'covering_index_scan', 'index_scan', 'table_scan', 'groupby_scan', 'index_join_scan', 'types_table_scan', 'index_join')"
medianLatencyMultiplierReadsQuery="select f.test_name as read_tests, f.server_name, f.server_version, avg(f.latency_percentile) as from_latency_median, t.server_name, t.server_version, avg(t.latency_percentile) as to_latency_median, ROUND(avg(t.latency_percentile) / (avg(f.latency_percentile) + .000001), $precision) as multiplier from from_results as f join to_results as t on f.test_name = t.test_name where f.test_name in $readTests group by f.test_name;"
meanMultiplierReadsQuery="select round(avg(multipliers), $precision) as reads_mean_multiplier from (select (round(avg(t.latency_percentile) / (avg(f.latency_percentile) + .000001), $precision)) as multipliers from from_results as f join to_results as t on f.test_name = t.test_name where f.test_name in $readTests group by f.test_name)"
writeTests="('oltp_read_write', 'oltp_update_index', 'oltp_update_non_index', 'oltp_insert', 'oltp_write_only', 'oltp_delete_insert', 'types_delete_insert')"
medianLatencyMultiplierWritesQuery="select f.test_name as write_tests, f.server_name, f.server_version, avg(f.latency_percentile) as from_latency_median, t.server_name, t.server_version, avg(t.latency_percentile) as to_latency_median, ROUND(avg(t.latency_percentile) / (avg(f.latency_percentile) + .000001), $precision) as multiplier from from_results as f join to_results as t on f.test_name = t.test_name where f.test_name in $writeTests group by f.test_name;"
meanMultiplierWritesQuery="select round(avg(multipliers), $precision) as writes_mean_multiplier from (select (round(avg(t.latency_percentile) / (avg(f.latency_percentile) + .000001), $precision)) as multipliers from from_results as f join to_results as t on f.test_name = t.test_name where f.test_name in $writeTests group by f.test_name)"
meanMultiplierOverallQuery="select round(avg(multipliers), $precision) as overall_mean_multiplier from (select (round(avg(t.latency_percentile) / (avg(f.latency_percentile) + .000001), $precision)) as multipliers from from_results as f join to_results as t on f.test_name = t.test_name where f.test_name != 'bulk_insert' group by f.test_name)"
tpccLatencyQuery="select f.test_name as tpcc_latency, f.server_name, f.server_version, avg(f.latency_percentile) as from_latency_p95, t.server_name, t.server_version, avg(t.latency_percentile) as to_latency_p95, ROUND(avg(t.latency_percentile) / (avg(f.latency_percentile) + .000001), $precision) as multiplier from from_results as f join to_results as t on f.test_name = t.test_name where f.test_name LIKE '$tpccRegex' group by f.test_name;"
tpccTpsQuery="select f.test_name as tpcc_tps, f.server_name, f.server_version, avg(f.sql_transactions_per_second) as from_tps, t.test_name as test_name, t.server_name, t.server_version, avg(t.sql_transactions_per_second) as to_tps, ROUND(avg(f.sql_transactions_per_second) / (avg(t.sql_transactions_per_second) + .000001), $precision) as multiplier from from_results as f join to_results as t on f.test_name = t.test_name where f.test_name LIKE 'tpcc%' group by f.test_name;"
tpccTpsMultiplierQuery="select ROUND(avg(f.sql_transactions_per_second) / (avg(t.sql_transactions_per_second) + .000001), $precision) as tpcc_tps_multiplier from from_results as f join to_results as t on f.test_name = t.test_name where f.test_name like 'tpcc%' group by f.test_name"
echo '
{
"apiVersion": "batch/v1",
"kind": "Job",
"metadata": {
"name": "'$jobname'",
"namespace": "performance-benchmarking"
},
"spec": {
"backoffLimit": 3,
"template": {
"metadata": {
"annotations": {
"alert_recipients": "'$ACTOR_EMAIL'"
},
"labels": {
"k8s-liquidata-inc-monitored-job": "created-by-static-config",
"app": "performance-benchmarking"
}
},
"spec": {
"serviceAccountName": "performance-benchmarking",
"containers": [
{
"name": "performance-benchmarking",
"image": "407903926827.dkr.ecr.us-west-2.amazonaws.com/liquidata/performance-benchmarking:latest",
"resources": {
"limits": {
"cpu": "7000m"
}
},
"env": [
{ "name": "GOMAXPROCS", "value": "7" },
{ "name": "GOEXPERIMENT", "value": "greenteagc" },
{ "name": "ACTOR", "value": "'$ACTOR'" },
{ "name": "ACTOR_EMAIL", "value": "'$ACTOR_EMAIL'" },
{ "name": "REPO_ACCESS_TOKEN", "value": "'$REPO_ACCESS_TOKEN'" }
],
"imagePullPolicy": "Always",
"args": [
"--schema=/app/schema.sql",
"--useDoltHubLuaScriptsRepo",
"--output='$format'",
"--mysql-exec=/usr/sbin/mysqld",
"--mysql-socket=/home/tester/.mysql/mysqld.sock",
"--mysql-protocol=unix",
"--from-server='$fromServer'",
"--from-version='$fromVersion'",
"--to-server='$toServer'",
"--to-version='$toVersion'",
'"$toProfileKey"'
"--bucket=performance-benchmarking-github-actions-results",
"--region=us-west-2",
"--results-dir='$timeprefix'",
"--results-prefix='$actorprefix'",
'"$sysbenchTestTime"'
'"$withTpcc"'
'"$initBigRepo"'
'"$nomsBinFormat"'
"--sysbenchQueries='"$medianLatencyMultiplierReadsQuery"'",
"--sysbenchQueries='"$meanMultiplierReadsQuery"'",
"--sysbenchQueries='"$medianLatencyMultiplierWritesQuery"'",
"--sysbenchQueries='"$meanMultiplierWritesQuery"'",
"--sysbenchQueries='"$meanMultiplierOverallQuery"'",
"--tpccQueries='"$tpccLatencyQuery"'",
"--tpccQueries='"$tpccTpsQuery"'",
"--tpccQueries='"$tpccTpsMultiplierQuery"'"
]
}
],
"restartPolicy": "Never",
"nodeSelector": {
"performance-benchmarking-worker": "true"
},
"tolerations": [
{
"effect": "NoSchedule",
"key": "dedicated",
"operator": "Equal",
"value": "performance-benchmarking-worker"
}
]
}
}
}
}
'
+133
View File
@@ -0,0 +1,133 @@
#!/bin/bash
set -e
if [ -z "$KUBECONFIG" ]; then
echo "Must set KUBECONFIG"
exit 1
fi
if [ -z "$TEMPLATE_SCRIPT" ]; then
echo "Must set TEMPLATE_SCRIPT"
exit 1
fi
if [ -z "$NOMS_BIN_FORMAT" ]; then
echo "Must set NOMS_BIN_FORMAT"
exit 1
fi
if [ -n "$PROFILE" ]; then
if [ -z "$FROM_VERSION" ]; then
echo "Must set FROM_VERSION"
exit 1
fi
if [ -z "$FUTURE_VERSION" ]; then
echo "Setting FUTURE_VERSION to $FROM_VERSION"
export FUTURE_VERSION="$FROM_VERSION"
fi
echo "Setting profile version to $FROM_VERSION"
else
if [ -z "$FROM_SERVER" ] || [ -z "$FROM_VERSION" ] || [ -z "$TO_SERVER" ] || [ -z "$TO_VERSION" ]; then
echo "Must set FROM_SERVER FROM_VERSION TO_SERVER and TO_VERSION"
exit 1
fi
echo "Setting from $FROM_SERVER: $FROM_VERSION"
echo "Setting to $TO_SERVER: $TO_VERSION"
fi
if [ -z "$ACTOR" ]; then
echo "Must set ACTOR"
exit 1
fi
if [ -z "$MODE" ]; then
echo "Must set MODE"
exit 1
fi
if [ "$NOMS_BIN_FORMAT" = "__DOLT__" ]; then
INIT_BIG_REPO="false"
fi
# use first 8 characters of FROM_VERSION | TO_VERSION to differentiate
# jobs
short=${TO_VERSION:0:8}
if [ -n "$PROFILE" ]; then
short=${FROM_VERSION:0:8}
fi
lowered=$(echo "$ACTOR" | tr '[:upper:]' '[:lower:]')
actorShort="$lowered-$short"
# random sleep
sleep 0.$[ ( $RANDOM % 10 ) + 1 ]s
timesuffix=`date +%s%N`
jobname="$actorShort"
if [ -n "$WITH_TPCC" ]; then
jobname="$jobname-tpcc"
elif [ -n "$PROFILE" ]; then
jobname="$jobname-profile"
fi
jobname="$jobname-$timesuffix"
timeprefix=$(date +%Y/%m/%d)
actorprefix="$MODE/$lowered/$jobname/$NOMS_BIN_FORMAT"
format="markdown"
if [[ "$MODE" = "release" || "$MODE" = "nightly" ]]; then
format="html"
fi
export TO_PROFILE_KEY
# set value to ISSUE_NUMBER environment variable
# or default to -1
issuenumber=${ISSUE_NUMBER:-"-1"}
if [ -n "$PROFILE" ]; then
source \
"$TEMPLATE_SCRIPT" \
"$jobname" \
"$FROM_VERSION" \
"$FUTURE_VERSION" \
"$timeprefix" \
"$actorprefix" \
"$format" \
"$INIT_BIG_REPO" \
"$NOMS_BIN_FORMAT" > job.json
else
source \
"$TEMPLATE_SCRIPT" \
"$jobname" \
"$FROM_SERVER" \
"$FROM_VERSION" \
"$TO_SERVER" \
"$TO_VERSION" \
"$timeprefix" \
"$actorprefix" \
"$format" \
"$issuenumber" \
"$INIT_BIG_REPO" \
"$NOMS_BIN_FORMAT" \
"$SYSBENCH_TEST_TIME" \
"$WITH_TPCC" > job.json
fi
out=$(KUBECONFIG="$KUBECONFIG" kubectl apply -f job.json || true)
if [ "$out" != "job.batch/$jobname created" ]; then
echo "something went wrong creating job... this job likely already exists in the cluster"
echo "$out"
exit 1
else
echo "$out"
fi
exit 0
@@ -0,0 +1,16 @@
#!/bin/bash
set -e
if [[ $# -ne 1 ]]; then
echo "Usage: ./validate-commentor.sh COMMENTOR"
exit 1
fi
validcommentors="coffeegoddd bheni Hydrocharged reltuk tbantle22 timsehn zachmu nicktobey fulghum macneale4 jycor angelamayxie elianddb"
contains() {
[[ $1 =~ (^|[[:space:]])$2($|[[:space:]]) ]] && echo "valid=true" >> $GITHUB_OUTPUT || exit 0
}
contains "$validcommentors" "$1"
+67
View File
@@ -0,0 +1,67 @@
#!/usr/bin/env bash
set -euo pipefail
IFS=$'\n\t'
# Inputs via environment variables
RAW_DEP=${RAW_DEP:-}
RAW_SHA=${RAW_SHA:-}
RAW_USER=${RAW_USER:-}
RAW_MAIL=${RAW_MAIL:-}
# --- Validate dependency via allow-list and map to module path + label
case "${RAW_DEP:-}" in
go-mysql-server)
MODULE='github.com/dolthub/go-mysql-server'
LABEL='gms-bump'
;;
eventsapi_schema)
MODULE='github.com/dolthub/eventsapi_schema'
LABEL='eventsapi_schema-bump'
;;
*)
echo "Unsupported dependency '${RAW_DEP:-}'" >&2
exit 1
;;
esac
# --- Validate head SHA/tag (conservative)
# allow only hex SHAs or safe tag-ish: letters, digits, dot, dash, underscore, plus
if [ -z "${RAW_SHA:-}" ] || ! printf '%s' "$RAW_SHA" | grep -qE '^[A-Za-z0-9._+-]+$'; then
echo "Invalid head_commit_sha" >&2
exit 1
fi
# Keep a short 8-char form if it's a hex SHA; otherwise derive short safe token
if printf '%s' "$RAW_SHA" | grep -qiE '^[0-9a-f]{40}$'; then
SHORT_SHA="${RAW_SHA:0:8}"
else
SHORT_SHA="$(printf '%s' "$RAW_SHA" | tr -cd 'A-Za-z0-9._+-' | cut -c1-12)"
fi
# --- Validate assignee username (GitHub-compatible subset)
if [ -z "${RAW_USER:-}" ] || ! printf '%s' "$RAW_USER" | grep -qE '^[A-Za-z0-9-]{1,39}$'; then
echo "Invalid assignee username" >&2
exit 1
fi
# --- Validate email; if invalid, fall back to GitHub noreply
if [ -n "${RAW_MAIL:-}" ] && printf '%s' "$RAW_MAIL" | grep -qE '^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}$'; then
SAFE_EMAIL="$RAW_MAIL"
else
SAFE_EMAIL="${RAW_USER}+noreply@users.noreply.github.com"
fi
# --- Build a safe branch name: <assignee>-<short>
BRANCH_NAME="$(printf '%s-%s' "$RAW_USER" "$SHORT_SHA" | tr -cd 'A-Za-z0-9._-')"
# Expose sanitized values as step outputs
{
echo "label=$LABEL"
echo "safe_module=$MODULE"
echo "safe_head=$RAW_SHA"
echo "safe_assignee=$RAW_USER"
echo "safe_email=$SAFE_EMAIL"
echo "safe_branch=$BRANCH_NAME"
echo "safe_short=$SHORT_SHA"
} >> "${GITHUB_OUTPUT}"
@@ -0,0 +1 @@
100
@@ -0,0 +1,114 @@
#!/bin/sh
set -e
if [ "$#" -lt 5 ]; then
echo "Usage: ./get-dolt-correctness-job-json.sh <jobname> <version> <timeprefix> <actorprefix> <format> <nomsBinFormat> <issueNumber> <regressComp> <branchRef>"
exit 1
fi
jobname="$1"
version="$2"
timeprefix="$3"
actorprefix="$4"
format="$5"
nomsBinFormat="$6"
issueNumber="$7"
regressComp="$8"
branchRef="$9"
precision="6"
if [ -n "$nomsBinFormat" ]; then
nomsBinFormat="\"--noms-bin-format=$nomsBinFormat\","
fi
if [ -n "$issueNumber" ]; then
issueNumber="\"--issue-number=$issueNumber\","
fi
regressPrec=""
if [ -n "$regressComp" ]; then
regressComp="\"--regress-compare=$regressComp\","
regressPrec="\"--regress-precision=$precision\","
branchRef="\"--branch=$branchRef\","
fi
resultCountQuery="select version, result, count(*) as total from results where result != 'skipped' group by result;"
testCountQuery="select version, count(*) as total_tests from results where result != 'skipped';"
correctnessQuery="select ROUND(100.0 * (cast(ok_results.total as decimal) / (cast(all_results.total as decimal) + .000001)), $precision) as correctness_percentage from (select count(*) as total from results where result = 'ok') as ok_results join (select count(*) as total from results where result != 'skipped') as all_results"
echo '
{
"apiVersion": "batch/v1",
"kind": "Job",
"metadata": {
"name": "'$jobname'",
"namespace": "sql-correctness"
},
"spec": {
"backoffLimit": 3,
"template": {
"metadata": {
"annotations": {
"alert_recipients": "'$ACTOR_EMAIL'"
},
"labels": {
"k8s-liquidata-inc-monitored-job": "created-by-static-config",
"app": "sql-correctness"
}
},
"spec": {
"serviceAccountName": "sql-correctness",
"containers": [
{
"name": "sql-correctness",
"image": "407903926827.dkr.ecr.us-west-2.amazonaws.com/liquidata/sql-correctness:latest",
"resources": {
"limits": {
"cpu": "7000m"
}
},
"env": [
{ "name": "REPO_ACCESS_TOKEN", "value": "'$REPO_ACCESS_TOKEN'"},
{ "name": "ACTOR", "value": "'$ACTOR'"},
{ "name": "ACTOR_EMAIL", "value": "'$ACTOR_EMAIL'"}
],
"args": [
"--schema=/app/correctness.sql",
"--concurrent",
"--output='$format'",
"--version='$version'",
"--timeout=600",
'"$nomsBinFormat"'
'"$issueNumber"'
'"$regressComp"'
'"$regressPrec"'
'"$branchRef"'
"--bucket=sql-correctness-github-actions-results",
"--region=us-west-2",
"--results-dir='$timeprefix'",
"--results-prefix='$actorprefix'",
"'"$resultCountQuery"'",
"'"$testCountQuery"'",
"'"$correctnessQuery"'"
]
}
],
"restartPolicy": "Never",
"nodeSelector": {
"sql-correctness-worker": "true"
},
"tolerations": [
{
"effect": "NoSchedule",
"key": "dedicated",
"operator": "Equal",
"value": "sql-correctness-worker"
}
]
}
}
}
}
'
+106
View File
@@ -0,0 +1,106 @@
#!/bin/bash
set -e
if [ -z "$KUBECONFIG" ]; then
echo "Must set KUBECONFIG"
exit 1
fi
if [ -z "$TEMPLATE_SCRIPT" ]; then
echo "Must set TEMPLATE_SCRIPT"
exit 1
fi
if [ -z "$NOMS_BIN_FORMAT" ]; then
echo "Must set NOMS_BIN_FORMAT"
exit 1
fi
if [ -z "$VERSION" ]; then
echo "Must set VERSION for correctness run"
exit 1
fi
if [ -z "$ACTOR" ]; then
echo "Must set ACTOR"
exit 1
fi
if [ -z "$MODE" ]; then
echo "Must set MODE"
exit 1
fi
if [ -n "$PR_NUMBER" ]; then
if [ -z "$REGRESS_COMP" ]; then
echo "Must set REGRESS_COMP for PR correctness comparisons"
exit 1
fi
if [ -z "$PR_BRANCH_REF" ]; then
echo "Must set PR_BRANCH_REF for PR correctness comparisons"
exit 1
fi
fi
# use first 8 characters of VERSION to differentiate
# jobs
short=${VERSION:0:8}
lowered=$(echo "$ACTOR" | tr '[:upper:]' '[:lower:]')
actorShort="$lowered-$short"
# random sleep
sleep 0.$[ ( $RANDOM % 10 ) + 1 ]s
timesuffix=`date +%s%N`
jobname=""
if [ -n "$PR_NUMBER" ]; then
jobname="$lowered-$PR_NUMBER"
else
jobname="$actorShort-$timesuffix"
fi
timeprefix=$(date +%Y/%m/%d)
actorprefix="$MODE/$lowered/$jobname/$NOMS_BIN_FORMAT"
format="markdown"
if [[ "$MODE" = "release" || "$MODE" = "nightly" ]]; then
format="html"
fi
# set value to PR_NUMBER environment variable
# or default to -1
issuenumber=${PR_NUMBER:-"-1"}
source \
"$TEMPLATE_SCRIPT" \
"$jobname" \
"$VERSION" \
"$timeprefix" \
"$actorprefix" \
"$format" \
"$NOMS_BIN_FORMAT" \
"$issuenumber" \
"$REGRESS_COMP" \
"$PR_BRANCH_REF" > job.json
# delete existing job with same name if this is a pr job
if [ -n "$PR_NUMBER" ]; then
out=$(KUBECONFIG="$KUBECONFIG" kubectl delete job/"$jobname" -n sql-correctness || true)
echo "Delete pr job if exists: $out"
sleep 45
fi
out=$(KUBECONFIG="$KUBECONFIG" kubectl apply -f job.json || true)
if [ "$out" != "job.batch/$jobname created" ]; then
echo "something went wrong creating job... this job likely already exists in the cluster"
echo "$out"
exit 1
else
echo "$out"
fi
exit 0
+28
View File
@@ -0,0 +1,28 @@
# Dolt's GitHub Actions
This doc will provide context for the types of Workflows we use in this repository. This doc is not a comprehensive GitHub Actions tutorial. To familiarize yourself with GitHub Actions concepts and the terminology, please see the [documentation](https://docs.github.com/en/actions/learn-github-actions/understanding-github-actions).
Dolt uses GitHub Actions Workflows in four primary ways:
* To run continuous integration tests on pull requests and pushes to `main`
* To release and publish new Dolt assets
* To deploy various benchmarking jobs to contexts _other_ than GitHub Actions (like in a Kubernetes cluster, for example).
* To handle misc. [repository_dispatch](https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#repository_dispatch) events triggered by external clients.
## Continuous Integration Workflows
Workflows prefixed with `ci-` are run on pull requests to `main`, though some run on pushes to `main` (after a pull request is merged). These workflows are synchronous and don't trigger any other workflows to run.
## Dolt Release Workflows
Workflows prefixed with `cd-` are used for releasing Dolt. Some of these workflows are asynchronous, meaning that they only perform part of a task before triggering the next part of a task to run in a _different_ workflow, sometimes in other GitHub repositories, using `repository_dispatch` events.
## Benchmarking Workflows
Benchmarking workflows are used as an interface for deploying benchmarking jobs to one of our Kubernetes Clusters. Workflows that deploy Kubernetes Jobs are prefixed with `k8s-` and can only be triggered with `repository_dispatch` events. Notice that benchmarking workflows, like `workflows/performance-benchmarks-email-report.yaml` for example, trigger these events using the `peter-evans/repository-dispatch@v2.0.0` Action.
These Kubernetes Jobs do not run on GitHub Actions Hosted Runners, so the workflow logs do not contain any information about the deployed Kubernetes Job or any errors it might have encountered. The workflow logs can only tell you if a Job was created successfully or not. To investigate an error or issue with a Job in our Kubernetes Cluster, see the debugging guide [here](https://github.com/dolthub/ld/blob/main/k8s/README.md#debug-performance-benchmarks-and-sql-correctness-jobs).
## Misc. Repository Dispatch Workflows
Some workflows perform single, common tasks and are triggered by `repository_dispatch` events. These include the `workflows/email-report.yaml` that emails the results of performance benchmarks to the team, or the `workflows/pull-report.yaml` that posts those same results to an open pull request. Workflows like these are triggered by external clients.
+221
View File
@@ -0,0 +1,221 @@
name: Bump Deps
on:
repository_dispatch:
types: [ bump-dependency ]
jobs:
sanitize-payload:
name: Sanitize Payload
runs-on: ubuntu-22.04
outputs:
label: ${{ steps.sanitize.outputs.label }}
safe_module: ${{ steps.sanitize.outputs.safe_module }}
safe_head: ${{ steps.sanitize.outputs.safe_head }}
safe_assignee: ${{ steps.sanitize.outputs.safe_assignee }}
safe_email: ${{ steps.sanitize.outputs.safe_email }}
safe_branch: ${{ steps.sanitize.outputs.safe_branch }}
safe_short: ${{ steps.sanitize.outputs.safe_short }}
steps:
- uses: actions/checkout@v6
- name: Validate & Sanitize Payload (script)
id: sanitize
env:
RAW_DEP: ${{ github.event.client_payload.dependency }}
RAW_SHA: ${{ github.event.client_payload.head_commit_sha }}
RAW_USER: ${{ github.event.client_payload.assignee }}
RAW_MAIL: ${{ github.event.client_payload.assignee_email }}
run: bash .github/scripts/sanitize_payload.sh
stale-bump-prs:
name: Retrieving Stale Bump PRs
needs: sanitize-payload
outputs:
stale-pulls: ${{ steps.get-stale-prs.outputs.open-pulls }}
runs-on: ubuntu-22.04
steps:
- name: Get Open Bump PRs
id: get-stale-prs
uses: actions/github-script@v7
env:
LABEL: ${{ needs.sanitize-payload.outputs.label }}
with:
debug: true
github-token: ${{ secrets.REPO_ACCESS_TOKEN }}
script: |
try {
const { LABEL } = process.env;
const { owner, repo } = context.repo;
const res = await github.rest.pulls.list({
owner,
repo,
state: 'open',
sort: 'created',
direction: 'desc',
});
const { data } = res;
const reduced = data.reduce((acc, p) => {
if (p.labels.length < 1) return acc;
let keepAlive = false;
let shouldPush = false;
for (const label of p.labels) {
if (label.name === LABEL) {
shouldPush = true;
}
if (label.name === "keep-alive") {
keepAlive = true;
}
}
if (shouldPush) {
acc.push({
number: p.number,
keepAlive,
headRef: p.head.ref,
});
}
return acc;
}, []);
console.log(reduced);
if (reduced.length > 0) core.setOutput("open-pulls", JSON.stringify(reduced));
process.exit(0);
} catch(err) {
console.log("Error:", err);
process.exit(1);
}
open-bump-pr:
needs: [sanitize-payload, stale-bump-prs]
name: Open Bump PR
runs-on: ubuntu-22.04
outputs:
latest-pr: ${{ steps.latest-pr.outputs.pr_url }}
steps:
- uses: actions/checkout@v6
with:
token: ${{ secrets.REPO_ACCESS_TOKEN || secrets.GITHUB_TOKEN }}
- name: Set up Go 1.x
uses: actions/setup-go@v5
with:
go-version-file: go/go.mod
- name: Bump dependency (safe)
working-directory: go
env:
SAFE_MODULE: ${{ needs.sanitize-payload.outputs.safe_module }}
SAFE_HEAD: ${{ needs.sanitize-payload.outputs.safe_head }}
run: |
GOOS=linux go get "${SAFE_MODULE}@${SAFE_HEAD}"
go mod tidy
- name: Get Assignee and Reviewer (safe)
id: get_reviewer
env:
ASSIGNEE: ${{ needs.sanitize-payload.outputs.safe_assignee }}
run: |
if [ "${ASSIGNEE}" == "zachmu" ]
then
echo "reviewer=Hydrocharged" >> $GITHUB_OUTPUT
else
echo "reviewer=zachmu" >> $GITHUB_OUTPUT
fi
- name: Create and Push new branch (safe)
env:
GIT_USER: ${{ needs.sanitize-payload.outputs.safe_assignee }}
GIT_MAIL: ${{ needs.sanitize-payload.outputs.safe_email }}
BRANCH: ${{ needs.sanitize-payload.outputs.safe_branch }}
COMMIT_BY: ${{ needs.sanitize-payload.outputs.safe_assignee }}
run: |
set -euo pipefail
git config --global user.name "${GIT_USER}"
git config --global user.email "${GIT_MAIL}"
git checkout -b "${BRANCH}"
git add .
git commit -m "[ga-bump-dep] Bump dependency in Dolt by ${COMMIT_BY}"
git push origin "${BRANCH}"
- name: pull-request
uses: repo-sync/pull-request@v2
id: latest-pr
with:
source_branch: ${{ needs.sanitize-payload.outputs.safe_branch }}
destination_branch: "main"
github_token: ${{ secrets.REPO_ACCESS_TOKEN }}
pr_title: "[auto-bump] [no-release-notes] dependency by ${{ needs.sanitize-payload.outputs.safe_assignee }}"
pr_template: ".github/markdown-templates/dep-bump.md"
pr_reviewer: ${{ steps.get_reviewer.outputs.reviewer }}
pr_assignee: ${{ needs.sanitize-payload.outputs.safe_assignee }}
pr_label: ${{ needs.sanitize-payload.outputs.label }}
comment-on-stale-prs:
needs: [open-bump-pr, stale-bump-prs]
if: ${{ needs.stale-bump-prs.outputs.stale-pulls != '' }}
runs-on: ubuntu-22.04
strategy:
matrix:
pull: ${{ fromJson(needs.stale-bump-prs.outputs.stale-pulls) }}
steps:
- name: Comment/Close Stale PRs
id: get-stale-prs
uses: actions/github-script@v7
env:
PULL: ${{ toJson(matrix.pull) }}
SUPERSEDED_BY: ${{ needs.open-bump-pr.outputs.latest-pr }}
with:
debug: true
github-token: ${{ secrets.REPO_ACCESS_TOKEN }}
script: |
try {
const { owner, repo } = context.repo;
const { PULL, SUPERSEDED_BY } = process.env;
const pull = JSON.parse(PULL);
if (pull.keepAlive) process.exit(0);
const checkSuiteRes = await github.rest.checks.listSuitesForRef({
owner,
repo,
ref: pull.headRef,
});
if (checkSuiteRes.data) {
const okConclusions = new Set(["success", "neutral", "skipped"]);
for (const suite of checkSuiteRes.data.check_suites) {
console.log("suite id:", suite.id);
console.log("suite app slug:", suite.app.slug);
console.log("suite status:", suite.status);
console.log("suite conclusion:", suite.conclusion);
if (suite.app.slug === "github-actions") {
if (suite.status !== "completed") {
console.log(`Leaving pr open due to status:${suite.status} conclusion:${suite.conclusion}`);
process.exit(0);
}
if (!suite.conclusion || !okConclusions.has(suite.conclusion)) {
console.log(`Leaving pr open due to status:${suite.status} conclusion:${suite.conclusion}`);
process.exit(0);
}
}
}
}
console.log(`Closing open pr ${pull.number}`);
await github.rest.issues.createComment({
issue_number: pull.number,
owner,
repo,
body: `This PR has been superseded by ${SUPERSEDED_BY}`
});
await github.rest.pulls.update({
owner,
repo,
pull_number: pull.number,
state: 'closed',
});
process.exit(0);
} catch(err) {
console.log("Error:", err);
process.exit(1);
}
+48
View File
@@ -0,0 +1,48 @@
name: Bump Dolt on winget
on:
workflow_dispatch:
inputs:
version:
description: 'SemVer format release tag, i.e. 0.24.5'
required: true
repository_dispatch:
types: [ bump-winget ]
jobs:
get-version:
name: Get Version
runs-on: ubuntu-22.04
outputs:
version: ${{ steps.get_version.outputs.version }}
steps:
- name: Get version
id: get_version
run: |
version=""
if [ "${{ github.event_name }}" == "repository_dispatch" ]
then
version="${{ github.event.client_payload.version }}"
else
version="${{ github.event.inputs.version }}"
fi
echo "version=$version" >> $GITHUB_OUTPUT
winget-bump:
needs: get-version
name: Bump Dolt winget
runs-on: windows-latest
defaults:
run:
shell: powershell
steps:
- name: Create winget PR
run: |
iwr https://aka.ms/wingetcreate/latest -OutFile wingetcreate.exe
.\wingetcreate.exe update DoltHub.Dolt -u $Env:URL -v $Env:VERSION -t $Env:TOKEN --submit
env:
TOKEN: ${{ secrets.REPO_ACCESS_TOKEN }}
VERSION: ${{ needs.get-version.outputs.version }}
URL: ${{ format('https://github.com/dolthub/dolt/releases/download/v{0}/dolt-windows-amd64.msi', needs.get-version.outputs.version) }}
@@ -0,0 +1,71 @@
name: Create Release Notes
on:
workflow_dispatch:
inputs:
version:
description: 'SemVer format release tag, i.e. 0.24.5'
required: true
repository_dispatch:
types: [ release-notes ]
jobs:
create-release-notes:
runs-on: ubuntu-22.04
steps:
- name: Get Vars
id: get_vars
run: |
if [ "$EVENT_NAME" == "workflow_dispatch" ]
then
release_id=$(curl -H "Accept: application/vnd.github.v3+json" https://api.github.com/repos/dolthub/dolt/releases/tags/v${{ github.event.inputs.version }} | jq '.id')
echo "version=${{ github.event.inputs.version }}" >> $GITHUB_OUTPUT
echo "release_id=$release_id" >> $GITHUB_OUTPUT
else
echo "version=${{ github.event.client_payload.version }}" >> $GITHUB_OUTPUT
echo "release_id=${{ github.event.client_payload.release_id }}" >> $GITHUB_OUTPUT
fi
env:
EVENT_NAME: ${{ github.event_name }}
- name: Checkout Release Notes Generator
uses: actions/checkout@v6
with:
repository: dolthub/release-notes-generator
token: ${{ secrets.REPO_ACCESS_TOKEN }}
- name: Install Dependencies
run: sudo ./install-deps.sh
env:
PERL_MM_USE_DEFAULT: 1
- name: Create Notes
run: |
git clone https://github.com/dolthub/dolt.git
./gen_release_notes.pl \
--token "$TOKEN" \
-d dolthub/go-mysql-server \
-d dolthub/vitess dolthub/dolt v${{ steps.get_vars.outputs.version }} > changelog.txt
env:
TOKEN: ${{ secrets.REPO_ACCESS_TOKEN }}
- name: Post Changelog to Release
uses: actions/github-script@v7
with:
debug: true
github-token: ${{ secrets.REPO_ACCESS_TOKEN }}
script: |
const fs = require('fs');
const path = require('path')
try {
const body = fs.readFileSync(path.join(process.env.WORKSPACE, "changelog.txt"), { encoding: "utf8" })
const res = await github.rest.repos.updateRelease({
owner: "dolthub",
repo: "dolt",
release_id: parseInt(process.env.RELEASE_ID, 10),
body,
});
console.log("Successfully updated release notes", res)
} catch (err) {
console.log("Error", err);
process.exit(1);
}
env:
WORKSPACE: ${{ github.workspace }}
RELEASE_ID: ${{ steps.get_vars.outputs.release_id }}
@@ -0,0 +1,98 @@
name: Push Docker Image to DockerHub
on:
workflow_dispatch:
inputs:
version:
description: 'SemVer format release tag, i.e. 0.24.5'
required: true
push_latest:
description: 'Also tag and push as latest'
type: boolean
default: true
repository_dispatch:
types: [ push-docker-image ]
jobs:
get-release-id:
name: Get Dolt Release Id
runs-on: ubuntu-22.04
outputs:
release_id: ${{ steps.get_release.outputs.release_id }}
steps:
- name: Get Release
id: get_release
run: |
release_id="$RELEASE_ID"
if [ "$EVENT_TYPE" == "workflow_dispatch" ]; then
release_id=$(curl -H "Accept: application/vnd.github.v3+json" https://api.github.com/repos/dolthub/dolt/releases/tags/v${{ github.event.inputs.version }} | jq '.id')
fi
echo "release_id=$release_id" >> $GITHUB_OUTPUT
env:
EVENT_TYPE: ${{ github.event_name }}
RELEASE_ID: ${{ github.event.client_payload.release_id }}
docker-image-push:
name: Push Docker Image
needs: get-release-id
runs-on: ubuntu-22.04
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Login to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKER_HUB_USERNAME }}
password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }}
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
with:
platforms: linux/amd64,linux/arm64
- name: Build and push dolt image
uses: docker/build-push-action@v5
with:
platforms: linux/amd64,linux/arm64
context: .
file: ./docker/Dockerfile
push: true
tags: dolthub/dolt:${{ github.event.inputs.version || github.event.client_payload.version }}${{ (github.event_name != 'workflow_dispatch' || inputs.push_latest) && ' , dolthub/dolt:latest' || '' }}
build-args: |
DOLT_VERSION=${{ github.event.inputs.version || github.event.client_payload.version }}
- name: Build and push dolt-sql-server image
uses: docker/build-push-action@v5
with:
platforms: linux/amd64,linux/arm64
context: .
file: ./docker/serverDockerfile
push: true
tags: dolthub/dolt-sql-server:${{ github.event.inputs.version || github.event.client_payload.version }}${{ (github.event_name != 'workflow_dispatch' || inputs.push_latest) && ' , dolthub/dolt-sql-server:latest' || '' }}
build-args: |
DOLT_VERSION=${{ github.event.inputs.version || github.event.client_payload.version }}
- name: Update Docker Hub Readme for dolt image
uses: peter-evans/dockerhub-description@v4
with:
username: ${{ secrets.DOCKER_HUB_USERNAME }}
password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }}
repository: dolthub/dolt
readme-filepath: ./docker/README.md
- name: Update Docker Hub Readme for dolt-sql-server image
uses: peter-evans/dockerhub-description@v4
with:
username: ${{ secrets.DOCKER_HUB_USERNAME }}
password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }}
repository: dolthub/dolt-sql-server
readme-filepath: ./docker/serverREADME.md
- run: |
gh api \
--method PATCH \
-H "Accept: application/vnd.github+json" \
-H "X-GitHub-Api-Version: 2022-11-28" \
/repos/$REPO_OWNER/$REPO_NAME/releases/$RELEASE_ID \
-F "draft=false" -F "prerelease=false" -F "make_latest=true"
env:
GH_TOKEN: ${{ secrets.REPO_ACCESS_TOKEN || secrets.GITHUB_TOKEN }}
REPO_OWNER: dolthub
REPO_NAME: dolt
RELEASE_ID: ${{ needs.get-release-id.outputs.release_id }}
+256
View File
@@ -0,0 +1,256 @@
name: Release PGO Dolt
on:
workflow_dispatch:
inputs:
version:
description: 'SemVer format release tag, i.e. 0.24.5'
required: true
profile_bucket:
description: 's3 bucket of dolt profile used to build pgo'
required: true
profile_key:
description: 's3 key of dolt profile used to build pgo'
required: true
branch:
description: 'git branch to release from'
required: false
default: 'main'
commit_sha:
description: 'exact commit SHA to build from'
required: false
skip_rpm:
description: 'skips rpm releases for older dolt releases'
required: false
default: false
repository_dispatch:
types: [ pgo-release ]
jobs:
format-version:
runs-on: ubuntu-22.04
outputs:
version: ${{ steps.format_version.outputs.version }}
steps:
- name: Format Input
id: format_version
run: |
version="${{ github.event.inputs.version || github.event.client_payload.version }}"
if [[ $version == v* ]];
then
version="${version:1}"
fi
echo "version=$version" >> $GITHUB_OUTPUT
create-pgo-release:
needs: format-version
runs-on: ubuntu-22.04
name: Release PGO Dolt
outputs:
release_id: ${{ steps.create_release.outputs.id }}
steps:
- uses: actions/checkout@v6
with:
ref: ${{ github.event.inputs.branch || github.event.client_payload.branch || 'main' }}
token: ${{ secrets.DOLT_RELEASE_TOKEN }}
- name: Pin to exact commit SHA
if: ${{ github.event.inputs.commit_sha || github.event.client_payload.from_version }}
run: git checkout -B "$BRANCH" "$SHA"
env:
BRANCH: ${{ github.event.inputs.branch || github.event.client_payload.branch || 'main' }}
SHA: ${{ github.event.inputs.commit_sha || github.event.client_payload.from_version }}
- name: Set up Go 1.x
uses: actions/setup-go@v5
with:
go-version-file: go/go.mod
- name: Configure AWS Credentials
uses: aws-actions/configure-aws-credentials@v4
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: us-west-2
- name: Get Results
id: get-results
run: aws s3api get-object --bucket="$BUCKET" --key="$KEY" dolt-cpu-profile.pprof
env:
KEY: ${{ github.event.inputs.profile_key || github.event.client_payload.profile_key }}
BUCKET: ${{ github.event.inputs.profile_bucket || github.event.client_payload.bucket }}
- name: Update dolt version command
run: sed -i -e 's/ Version = ".*"/ Version = "'"$NEW_VERSION"'"/' "$FILE"
env:
FILE: ${{ format('{0}/go/cmd/dolt/doltversion/version.go', github.workspace) }}
NEW_VERSION: ${{ needs.format-version.outputs.version }}
- name: Set minver TBD to version
run: sed -i -e 's/minver:"TBD"/minver:"'"$NEW_VERSION"'"/' "$FILE"
env:
FILE: ${{ format('{0}/go/libraries/doltcore/servercfg/yaml_config.go', github.workspace) }}
NEW_VERSION: ${{ needs.format-version.outputs.version }}
- name: update minver_validation.txt
working-directory: ./go
run: go run -mod=readonly ./utils/genminver_validation/ $FILE
env:
FILE: ${{ format('{0}/go/libraries/doltcore/servercfg/testdata/minver_validation.txt', github.workspace) }}
- uses: EndBug/add-and-commit@v9.1.4
with:
message: ${{ format('[ga-bump-release] Update Dolt version to {0} and release v{0}', needs.format-version.outputs.version) }}
add: ${{ format('["{0}/go/cmd/dolt/doltversion/version.go", "{0}/go/libraries/doltcore/servercfg/yaml_config.go", "{0}/go/libraries/doltcore/servercfg/testdata/minver_validation.txt"]', github.workspace) }}
cwd: "."
pull: "--ff"
- name: Build PGO Binaries
id: build_binaries
run: |
latest=$(git rev-parse HEAD)
echo "commitish=$latest" >> $GITHUB_OUTPUT
GO_BUILD_VERSION=1.26.2 go/utils/publishrelease/buildpgobinaries.sh
env:
GO_BUILD_VERSION: "1.26.2"
PROFILE: ${{ format('{0}/dolt-cpu-profile.pprof', github.workspace) }}
- name: Create Release
id: create_release
uses: dolthub/create-release@v2
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tag_name: v${{ needs.format-version.outputs.version }}
release_name: ${{ needs.format-version.outputs.version }}
draft: false
prerelease: true
commitish: ${{ steps.build_binaries.outputs.commitish }}
- name: Upload Linux AMD64 Distro
id: upload-linux-amd64-distro
uses: dolthub/upload-release-asset@v2
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_path: go/out/dolt-linux-amd64.tar.gz
asset_name: dolt-linux-amd64.tar.gz
asset_content_type: application/zip
- name: Upload Linux ARM64 Distro
id: upload-linux-arm64-distro
uses: dolthub/upload-release-asset@v2
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_path: go/out/dolt-linux-arm64.tar.gz
asset_name: dolt-linux-arm64.tar.gz
asset_content_type: application/zip
- name: Upload OSX AMD64 Distro
id: upload-osx-amd64-distro
uses: dolthub/upload-release-asset@v2
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_path: go/out/dolt-darwin-amd64.tar.gz
asset_name: dolt-darwin-amd64.tar.gz
asset_content_type: application/zip
- name: Upload OSX ARM64 Distro
id: upload-osx-arm64-distro
uses: dolthub/upload-release-asset@v2
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_path: go/out/dolt-darwin-arm64.tar.gz
asset_name: dolt-darwin-arm64.tar.gz
asset_content_type: application/zip
- name: Upload Windows Distro
id: upload-windows-distro
uses: dolthub/upload-release-asset@v2
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_path: go/out/dolt-windows-amd64.zip
asset_name: dolt-windows-amd64.zip
asset_content_type: application/zip
- name: Upload Windows Distro 7z
id: upload-windows-distro-7z
uses: dolthub/upload-release-asset@v2
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_path: go/out/dolt-windows-amd64.7z
asset_name: dolt-windows-amd64.7z
asset_content_type: application/x-7z-compressed
- name: Upload Install Script
id: upload-install-script
uses: dolthub/upload-release-asset@v2
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_path: go/out/install.sh
asset_name: install.sh
asset_content_type: text/plain
- name: Upload Linux AMD64 RPM
if: ${{ !github.event.inputs.skip_rpm }}
id: upload-linux-amd64-rpm
uses: dolthub/upload-release-asset@v2
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_path: go/out/dolt-${{ needs.format-version.outputs.version }}-1.x86_64.rpm
asset_name: dolt-${{ needs.format-version.outputs.version }}-1.x86_64.rpm
asset_content_type: application/zip
- name: Upload Linux ARM64 RPM
if: ${{ !github.event.inputs.skip_rpm }}
id: upload-linux-arm64-rpm
uses: dolthub/upload-release-asset@v2
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_path: go/out/dolt-${{ needs.format-version.outputs.version }}-1.aarch64.rpm
asset_name: dolt-${{ needs.format-version.outputs.version }}-1.aarch64.rpm
asset_content_type: application/zip
create-windows-msi:
needs: [format-version, create-pgo-release]
runs-on: ubuntu-22.04
steps:
- name: Trigger Upload MSI
uses: peter-evans/repository-dispatch@v3
with:
token: ${{ secrets.REPO_ACCESS_TOKEN }}
event-type: upload-msi
repository: dolthub/windows-msi-creator
client-payload: '{"tag": "${{ needs.format-version.outputs.version }}", "release_id": "${{ needs.create-pgo-release.outputs.release_id }}", "actor": "${{ github.actor }}", "bucket": "${{ github.event.inputs.profile_bucket || github.event.client_payload.bucket }}", "profile_key": "${{ github.event.inputs.profile_key || github.event.client_payload.profile_key }}"}'
create-release-notes:
needs: [format-version, create-pgo-release]
runs-on: ubuntu-22.04
steps:
- name: Trigger Release Notes
uses: peter-evans/repository-dispatch@v3
with:
token: ${{ secrets.REPO_ACCESS_TOKEN }}
event-type: release-notes
client-payload: '{"version": "${{ needs.format-version.outputs.version }}", "release_id": "${{ needs.create-pgo-release.outputs.release_id }}"}'
trigger-performance-benchmark-email:
needs: [format-version, create-pgo-release]
runs-on: ubuntu-22.04
steps:
- name: Trigger Performance Benchmarks
uses: peter-evans/repository-dispatch@v3
with:
token: ${{ secrets.REPO_ACCESS_TOKEN }}
event-type: release-dolt
client-payload: '{"version": "${{ needs.format-version.outputs.version }}", "actor": "${{ github.actor }}", "profile_key": "${{ github.event.inputs.profile_key || github.event.client_payload.profile_key }}"}'
docker-image-push:
needs: [format-version, create-pgo-release]
runs-on: ubuntu-22.04
steps:
- name: Trigger Push Docker Image
uses: peter-evans/repository-dispatch@v3
with:
token: ${{ secrets.REPO_ACCESS_TOKEN }}
event-type: push-docker-image
client-payload: '{"version": "${{ needs.format-version.outputs.version }}", "release_id": "${{ needs.create-pgo-release.outputs.release_id }}" }'
+47
View File
@@ -0,0 +1,47 @@
name: Release Dolt
on:
workflow_dispatch:
inputs:
version:
description: 'SemVer format release tag, i.e. 0.24.5'
required: true
branch:
description: 'git branch to release from'
required: false
default: 'main'
jobs:
format-version:
runs-on: ubuntu-22.04
outputs:
version: ${{ steps.format_version.outputs.version }}
steps:
- name: Format Input
id: format_version
run: |
version="${{ github.event.inputs.version }}"
if [[ $version == v* ]];
then
version="${version:1}"
fi
echo "version=$version" >> $GITHUB_OUTPUT
profile-benchmark-dolt:
runs-on: ubuntu-22.04
needs: format-version
name: Trigger Benchmark Profile K8s Workflows
steps:
- uses: actions/checkout@v6
with:
ref: ${{ github.event.inputs.branch }}
- name: Get sha
id: get_sha
run: |
sha=$(git rev-parse --short HEAD)
echo "sha=$sha" >> $GITHUB_OUTPUT
- uses: peter-evans/repository-dispatch@v3
with:
token: ${{ secrets.REPO_ACCESS_TOKEN }}
event-type: profile-dolt
client-payload: '{"from_version": "${{ steps.get_sha.outputs.sha }}", "future_version": "${{ needs.format-version.outputs.version }}", "mode": "release", "actor": "${{ github.actor }}", "actor_email": "dustin@dolthub.com", "template_script": "./.github/scripts/performance-benchmarking/get-dolt-profile-job-json.sh", "branch": "${{ github.event.inputs.branch }}"}'
+138
View File
@@ -0,0 +1,138 @@
name: Test Bats MacOS
on:
workflow_dispatch:
schedule:
- cron: '0 1 * * *'
concurrency:
group: ci-bats-mac-nightly
cancel-in-progress: true
jobs:
test:
name: Bats tests
defaults:
run:
shell: bash
runs-on: macos-latest
strategy:
fail-fast: true
env:
use_credentials: ${{ secrets.AWS_SECRET_ACCESS_KEY != '' && secrets.AWS_ACCESS_KEY_ID != '' }}
steps:
- name: Conditionally Set ENV VARS for AWS tests
run: |
if [[ $use_credentials == true ]]; then
echo "AWS_SDK_LOAD_CONFIG=1" >> $GITHUB_ENV
echo "AWS_REGION=us-west-2" >> $GITHUB_ENV
echo "DOLT_BATS_AWS_TABLE=dolt-ci-bats-manifests-us-west-2" >> $GITHUB_ENV
echo "DOLT_BATS_AWS_BUCKET=dolt-ci-bats-chunks-us-west-2" >> $GITHUB_ENV
echo "DOLT_BATS_AWS_EXISTING_REPO=aws_remote_bats_tests__dolt__" >> $GITHUB_ENV
fi
- name: Configure AWS Credentials
if: ${{ env.use_credentials == 'true' }}
uses: aws-actions/configure-aws-credentials@v4
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: us-west-2
role-to-assume: ${{ secrets.AWS_ROLE_TO_ASSUME }}
role-duration-seconds: 10800 # 3 hours D:
- uses: actions/checkout@v6
- name: Set up Go toolchain
uses: ./.github/actions/setup-go-toolchain
- name: Setup Python 3.x
uses: actions/setup-python@v5
with:
python-version: "3.10"
- uses: actions/setup-node@v4
with:
node-version: ^16
- name: Build dolt
uses: ./.github/actions/build-dolt
with:
remotesrv: 'true'
noms: 'true'
- name: Install Bats
run: |
npm i bats
echo "$(pwd)/node_modules/.bin" >> $GITHUB_PATH
working-directory: ./.ci_bin
- name: Install Python Deps
run: |
pip install mysql-connector-python
pip install pandas
pip install pyarrow
- name: Install MySQL client LTS release (8.4)
run: |
brew update
brew install mysql-client@8.4
brew link mysql-client@8.4 --force
mysql --version
- name: Setup Dolt Config
uses: ./.github/actions/setup-dolt-config
- name: Install Maven
working-directory: ./.ci_bin
run: |
curl -LO https://dlcdn.apache.org/maven/maven-3/3.9.15/binaries/apache-maven-3.9.15-bin.tar.gz
tar -xf apache-maven-3.9.15-bin.tar.gz
echo "$(pwd)/apache-maven-3.9.15/bin" >> $GITHUB_PATH
- name: Install Hadoop
working-directory: ./.ci_bin
run: |
curl -LO https://downloads.apache.org/hadoop/common/hadoop-3.3.6/hadoop-3.3.6.tar.gz
tar xvf hadoop-3.3.6.tar.gz
echo "$(pwd)/hadoop-3.3.6/bin" >> $GITHUB_PATH
- name: Install parquet-cli
id: parquet_cli
working-directory: ./.ci_bin
run: |
curl -OL https://github.com/apache/parquet-mr/archive/refs/tags/apache-parquet-1.12.3.tar.gz
tar zxvf apache-parquet-1.12.3.tar.gz
cd parquet-java-apache-parquet-1.12.3/parquet-cli
mvn clean install -DskipTests
runtime_jar="$(pwd)"/target/parquet-cli-1.12.3-runtime.jar
echo "runtime_jar=$runtime_jar" >> $GITHUB_OUTPUT
- name: Check expect
run: expect -v
- name: Test all Mac
env:
SQL_ENGINE: "local-engine"
PARQUET_RUNTIME_JAR: ${{ steps.parquet_cli.outputs.runtime_jar }}
BATS_TEST_RETRIES: "3"
run: |
bats --tap $BATS_FILTER .
working-directory: ./integration-tests/bats
report-bats-failure:
name: Report Bats MacOS Failure via Email
needs: test
runs-on: ubuntu-22.04
if: always() && (needs.test.result == 'failure')
steps:
- uses: actions/checkout@v6
- name: Configure AWS Credentials
uses: aws-actions/configure-aws-credentials@v4
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: us-west-2
- name: Send Email
if: ${{ github.event_name == 'workflow_dispatch' }}
uses: ./.github/actions/ses-email-action
with:
region: us-west-2
version: ${{ github.ref }}
template: 'BatsMacFailureTemplate'
toAddresses: '["${{ github.event.inputs.email }}"]'
workflowURL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
- name: Send Email
if: ${{ github.event_name == 'schedule' }}
uses: ./.github/actions/ses-email-action
with:
region: us-west-2
version: ${{ github.event.client_payload.ref }}
template: 'BatsMacFailureTemplate'
toAddresses: '["dolts@dolthub.com", "tim@dolthub.com"]'
workflowURL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
+101
View File
@@ -0,0 +1,101 @@
name: Test Bats Unix Remote
on:
pull_request:
branches: [ main ]
paths:
- 'go/**'
- 'integration-tests/**'
concurrency:
group: ci-bats-unix-remote${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
jobs:
test:
name: Bats tests
defaults:
run:
shell: bash
runs-on: ubuntu-22.04
strategy:
fail-fast: true
env:
use_credentials: ${{ secrets.AWS_SECRET_ACCESS_KEY != '' && secrets.AWS_ACCESS_KEY_ID != '' }}
# We only run these as seaparte workflow if we do not have AWS credentials.
steps:
- uses: actions/checkout@v6
if: ${{ env.use_credentials != 'true' }}
- name: Set up Go toolchain
if: ${{ env.use_credentials != 'true' }}
uses: ./.github/actions/setup-go-toolchain
- name: Setup Python 3.x
if: ${{ env.use_credentials != 'true' }}
uses: actions/setup-python@v5
with:
python-version: "3.10"
- uses: actions/setup-node@v4
if: ${{ env.use_credentials != 'true' }}
with:
node-version: ^16
- name: Build dolt
if: ${{ env.use_credentials != 'true' }}
uses: ./.github/actions/build-dolt
with:
remotesrv: 'true'
noms: 'true'
- name: Install Bats
if: ${{ env.use_credentials != 'true' }}
run: |
npm i bats
echo "$(pwd)/node_modules/.bin" >> $GITHUB_PATH
working-directory: ./.ci_bin
- name: Install Python Deps
if: ${{ env.use_credentials != 'true' }}
run: |
pip install mysql-connector-python
pip install pandas
pip install pyarrow
- name: Setup Dolt Config
if: ${{ env.use_credentials != 'true' }}
uses: ./.github/actions/setup-dolt-config
- name: Install expect
if: ${{ env.use_credentials != 'true' }}
run: sudo apt-get install -y expect
- name: Install Maven
if: ${{ env.use_credentials != 'true' }}
working-directory: ./.ci_bin
run: |
curl -LO https://dlcdn.apache.org/maven/maven-3/3.9.15/binaries/apache-maven-3.9.15-bin.tar.gz
tar -xf apache-maven-3.9.15-bin.tar.gz
echo "$(pwd)/apache-maven-3.9.15/bin" >> $GITHUB_PATH
- name: Install Hadoop
if: ${{ env.use_credentials != 'true' }}
working-directory: ./.ci_bin
run: |
curl -LO https://downloads.apache.org/hadoop/common/hadoop-3.3.6/hadoop-3.3.6.tar.gz
tar xvf hadoop-3.3.6.tar.gz
echo "$(pwd)/hadoop-3.3.6/bin" >> $GITHUB_PATH
- name: Install parquet-cli
if: ${{ env.use_credentials != 'true' }}
id: parquet_cli
working-directory: ./.ci_bin
run: |
curl -OL https://github.com/apache/parquet-mr/archive/refs/tags/apache-parquet-1.12.3.tar.gz
tar zxvf apache-parquet-1.12.3.tar.gz
cd parquet-java-apache-parquet-1.12.3/parquet-cli
mvn clean install -DskipTests
runtime_jar="$(pwd)"/target/parquet-cli-1.12.3-runtime.jar
echo "runtime_jar=$runtime_jar" >> $GITHUB_OUTPUT
- name: Check expect
if: ${{ env.use_credentials != 'true' }}
run: expect -v
- name: Test all Unix
if: ${{ env.use_credentials != 'true' }}
env:
SQL_ENGINE: "remote-engine"
PARQUET_RUNTIME_JAR: ${{ steps.parquet_cli.outputs.runtime_jar }}
BATS_TEST_RETRIES: "3"
run: |
bats --print-output-on-failure --tap .
working-directory: ./integration-tests/bats
+134
View File
@@ -0,0 +1,134 @@
name: Test Bats Unix
on:
pull_request:
branches: [ main ]
paths:
- 'go/**'
- 'integration-tests/**'
concurrency:
group: ci-bats-unix-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
jobs:
test:
name: Bats tests
defaults:
run:
shell: bash
runs-on: ${{ matrix.os }}
strategy:
fail-fast: true
matrix:
os: [ ubuntu-22.04 ]
env:
use_credentials: ${{ secrets.AWS_SECRET_ACCESS_KEY != '' && secrets.AWS_ACCESS_KEY_ID != '' }}
steps:
# Docker entrypoint and docker tests in general may use more space than is available in the GitHub default runner,
# so we remove unused pre-installed programs.
- name: Free disk space
run: |
NAME="DISK-CLEANUP"
echo "[${NAME}] Starting background cleanup..."
[ -d /usr/share/dotnet ] && sudo rm -rf /usr/share/dotnet &
[ -d /usr/local/lib/android ] && sudo rm -rf /usr/local/lib/android &
[ -d /opt/ghc ] && sudo rm -rf /opt/ghc &
[ -d /usr/local/share/boost ] && sudo rm -rf /usr/local/share/boost &
- name: Conditionally Set ENV VARS for AWS tests
run: |
if [[ $use_credentials == true ]]; then
echo "AWS_SDK_LOAD_CONFIG=1" >> $GITHUB_ENV
echo "AWS_REGION=us-west-2" >> $GITHUB_ENV
echo "DOLT_BATS_AWS_TABLE=dolt-ci-bats-manifests-us-west-2" >> $GITHUB_ENV
echo "DOLT_BATS_AWS_BUCKET=dolt-ci-bats-chunks-us-west-2" >> $GITHUB_ENV
echo "DOLT_BATS_AWS_EXISTING_REPO=aws_remote_bats_tests__dolt__" >> $GITHUB_ENV
fi
- name: Configure filter tags for lambda bats
if: ${{ matrix.os == 'ubuntu-22.04' && env.use_credentials == 'true' }}
run: |
echo "BATS_FILTER=--filter-tags no_lambda" >> $GITHUB_ENV
- name: Configure AWS Credentials
if: ${{ env.use_credentials == 'true' }}
uses: aws-actions/configure-aws-credentials@v4
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: us-west-2
role-to-assume: ${{ secrets.AWS_ROLE_TO_ASSUME }}
role-duration-seconds: 10800 # 3 hours D:
- uses: actions/checkout@v6
- name: Set up Go toolchain
uses: ./.github/actions/setup-go-toolchain
- name: Setup Python 3.x
uses: actions/setup-python@v5
with:
python-version: "3.10"
- uses: actions/setup-node@v4
with:
node-version: ^16
- name: Build dolt
uses: ./.github/actions/build-dolt
with:
remotesrv: 'true'
noms: 'true'
- name: Install Bats
run: |
npm i bats
echo "$(pwd)/node_modules/.bin" >> $GITHUB_PATH
working-directory: ./.ci_bin
- name: Install Python Deps
run: |
pip install mysql-connector-python
pip install pandas
pip install pyarrow
- name: Setup Dolt Config
uses: ./.github/actions/setup-dolt-config
- name: Install expect
if: matrix.os == 'ubuntu-22.04'
run: sudo apt-get install -y expect
- name: Install pcre2grep
if: matrix.os == 'ubuntu-22.04'
run: sudo apt-get install -y pcre2-utils
- name: Install openssh-server
if: matrix.os == 'ubuntu-22.04'
run: sudo apt-get install -y openssh-server
- name: Install Maven
run: sudo apt-get install -y maven
- name: Install Hadoop
working-directory: ./.ci_bin
run: |
curl -LO https://downloads.apache.org/hadoop/common/hadoop-3.3.6/hadoop-3.3.6.tar.gz
tar xvf hadoop-3.3.6.tar.gz
echo "$(pwd)/hadoop-3.3.6/bin" >> $GITHUB_PATH
- name: Install parquet-cli
id: parquet_cli
working-directory: ./.ci_bin
run: |
curl -OL https://github.com/apache/parquet-mr/archive/refs/tags/apache-parquet-1.12.3.tar.gz
tar zxvf apache-parquet-1.12.3.tar.gz
cd parquet-java-apache-parquet-1.12.3/parquet-cli
mvn clean install -DskipTests
runtime_jar="$(pwd)"/target/parquet-cli-1.12.3-runtime.jar
echo "runtime_jar=$runtime_jar" >> $GITHUB_OUTPUT
- name: Check expect
run: expect -v
- name: Test all Unix
env:
SQL_ENGINE: "local-engine"
PARQUET_RUNTIME_JAR: ${{ steps.parquet_cli.outputs.runtime_jar }}
BATS_TEST_RETRIES: "3"
run: |
bats --print-output-on-failure --tap $BATS_FILTER .
working-directory: ./integration-tests/bats
- name: Test all Unix, SQL_ENGINE=remote-engine
# If we have AWS credentials, we run these remote-engine tests here instead of in the separate job.
if: ${{ env.use_credentials == 'true' && matrix.os == 'ubuntu-22.04' }}
env:
SQL_ENGINE: "remote-engine"
PARQUET_RUNTIME_JAR: ${{ steps.parquet_cli.outputs.runtime_jar }}
BATS_TEST_RETRIES: "3"
run: |
bats --print-output-on-failure --tap $BATS_FILTER .
working-directory: ./integration-tests/bats
+173
View File
@@ -0,0 +1,173 @@
name: Test Bats Windows
on:
workflow_dispatch:
inputs:
email:
description: 'Email address to receive bats failure notification'
required: true
default: ''
repository_dispatch:
types: [ bats-windows ]
jobs:
get-files:
name: Get file list
runs-on: ubuntu-22.04
outputs:
files: ${{ steps.get_file_list.outputs.files }}
steps:
- uses: actions/checkout@v6
if: ${{ github.event_name == 'repository_dispatch' }}
with:
ref: ${{ github.event.client_payload.ref }}
- uses: actions/checkout@v6
if: ${{ github.event_name == 'workflow_dispatch' }}
- name: Get file list
id: get_file_list
run: |
files=$(ls *.bats)
SAVEIFS=$IFS
IFS=$'\n'
file_arr=($files)
echo "files=${file_arr[@]}" >> $GITHUB_OUTPUT
IFS=$SAVEIFS
working-directory: ./integration-tests/bats
format-files-output:
name: Format files output
runs-on: ubuntu-22.04
needs: get-files
outputs:
files: ${{ steps.format_files.outputs.files }}
steps:
- name: Format
id: format_files
uses: actions/github-script@v7
env:
FILES: ${{ needs.get-files.outputs.files }}
with:
debug: true
github-token: ${{ secrets.REPO_ACCESS_TOKEN || secrets.GITHUB_TOKEN }}
script: |
try {
const { FILES } = process.env;
const fileList = FILES.split(" ");
core.setOutput("files", JSON.stringify(fileList));
process.exit(0);
} catch(err) {
console.log("Error:", err);
process.exit(1);
}
test-per-file:
name: Test file
needs: format-files-output
defaults:
run:
shell: bash
runs-on: windows-latest
env:
use_credentials: ${{ secrets.AWS_SECRET_ACCESS_KEY != '' && secrets.AWS_ACCESS_KEY_ID != '' }}
strategy:
matrix:
file: ${{ fromJson(needs.format-files-output.outputs.files) }}
steps:
- name: Conditionally Set ENV VARS for AWS tests
run: |
if [[ $use_credentials == true ]]; then
echo "AWS_SDK_LOAD_CONFIG=1" >> $GITHUB_ENV
echo "AWS_REGION=us-west-2" >> $GITHUB_ENV
echo "DOLT_BATS_AWS_TABLE=dolt-ci-bats-manifests-us-west-2" >> $GITHUB_ENV
echo "DOLT_BATS_AWS_BUCKET=dolt-ci-bats-chunks-us-west-2" >> $GITHUB_ENV
echo "DOLT_BATS_AWS_EXISTING_REPO=aws_remote_bats_tests" >> $GITHUB_ENV
fi
- name: Configure AWS Credentials
if: ${{ env.use_credentials == 'true' }}
uses: aws-actions/configure-aws-credentials@v4
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: us-west-2
role-to-assume: ${{ secrets.AWS_ROLE_TO_ASSUME }}
role-duration-seconds: 3600
- uses: actions/checkout@v6
if: ${{ github.event_name == 'repository_dispatch' }}
with:
ref: ${{ github.event.client_payload.ref }}
- name: Set up Go toolchain
uses: ./.github/actions/setup-go-toolchain
- name: Setup Python 3.x
uses: actions/setup-python@v5
with:
python-version: "3.10"
- uses: actions/checkout@v6
if: ${{ github.event_name == 'workflow_dispatch' }}
- uses: actions/setup-node@v4
with:
node-version: ^16
- name: Build dolt
uses: ./.github/actions/build-dolt
with:
remotesrv: 'true'
noms: 'true'
- name: Install Bats Windows
run: |
git clone https://github.com/bats-core/bats-core.git
cd bats-core
./install.sh $HOME
working-directory: ./.ci_bin
- name: Install wslpath
run: |
choco install wget
wget 'https://raw.githubusercontent.com/laurent22/wslpath/master/wslpath'
chmod 755 wslpath
mv wslpath /usr/bin/
cp /c/tools/php/php /usr/bin/
- name: Install Python Deps
run: |
pip install mysql-connector-python
pip install pandas
pip install pyarrow
- name: Setup Dolt Config
uses: ./.github/actions/setup-dolt-config
- name: Test file
run: bats --tap ${{ matrix.file }}
working-directory: ./integration-tests/bats
env:
IS_WINDOWS: true
WINDOWS_BASE_DIR: "/d/a"
BATS_TEST_RETRIES: "3"
report-bats-failure:
name: Report Bats Windows Failure via Email
needs: test-per-file
runs-on: ubuntu-22.04
if: always() && (needs.test-per-file.result == 'failure')
steps:
- uses: actions/checkout@v6
- name: Configure AWS Credentials
uses: aws-actions/configure-aws-credentials@v4
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: us-west-2
- name: Send Email
if: ${{ github.event_name == 'workflow_dispatch' }}
uses: ./.github/actions/ses-email-action
with:
region: us-west-2
version: ${{ github.ref }}
template: 'BatsWindowsFailureTemplate'
toAddresses: '["${{ github.event.inputs.email }}"]'
workflowURL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
- name: Send Email
if: ${{ github.event_name == 'repository_dispatch' }}
uses: ./.github/actions/ses-email-action
with:
region: us-west-2
version: ${{ github.event.client_payload.ref }}
template: 'BatsWindowsFailureTemplate'
toAddresses: '["${{ github.event.client_payload.actor_email }}", "tim@dolthub.com"]'
workflowURL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
@@ -0,0 +1,24 @@
name: Test Benchmark Runner Utility Works
on:
pull_request:
branches: [ main ]
paths:
- 'go/**'
- 'integration-tests/**'
concurrency:
group: ci-benchmark-runner-tests-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
jobs:
benchmark_runner:
runs-on: ubuntu-22.04
name: Test Benchmark Runner
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Copy Dockerfile
run: cp -r ./go/performance/continuous_integration/. .
- name: Test runner
uses: ./.github/actions/benchmark-runner-tests
+56
View File
@@ -0,0 +1,56 @@
name: Test Binlog
on:
pull_request:
branches: [ main ]
paths:
- 'go/**'
workflow_dispatch:
concurrency:
group: ci-binlog-tests-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
jobs:
binlog-test:
name: Binlog tests
defaults:
run:
shell: bash
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-22.04]
steps:
- uses: actions/checkout@v6
- name: Set up Go toolchain
uses: ./.github/actions/setup-go-toolchain
- name: Test Binlog
working-directory: ./go
run: |
# Test binlog packages
go test -vet=off -timeout 60m ./libraries/doltcore/sqle/binlogreplication/...
env:
MATRIX_OS: ${{ matrix.os }}
binlog-race-test:
name: Binlog tests - race
defaults:
run:
shell: bash
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-22.04]
steps:
- uses: actions/checkout@v6
- name: Set up Go toolchain
uses: ./.github/actions/setup-go-toolchain
- name: Test Binlog with Race
working-directory: ./go
run: |
# Test binlog packages with race detector
go test -vet=off -timeout 60m -race ./libraries/doltcore/sqle/binlogreplication/...
env:
MATRIX_OS: ${{ matrix.os }}
@@ -0,0 +1,22 @@
name: Check for correctness_approved label
on:
pull_request:
paths:
- 'go/**'
branches: [main]
types: [opened, labeled, unlabeled, synchronize]
jobs:
label:
runs-on: ubuntu-latest
permissions:
issues: write
pull-requests: write
steps:
- uses: mheap/github-action-required-labels@v5
if: github.actor != 'dependabot[bot]'
with:
mode: exactly
count: 1
labels: "correctness_approved"
add_comment: true
message: "This PR is being tested for SQL correctness. Please allow ~25 mins for this to complete. If this PR does not result in a SQL correctness regression, the `correctness_approved` label will be automatically added to this PR and the `Check for correctness_approved` workflow will succeed."
@@ -0,0 +1,22 @@
name: Check for performance_approved label
on:
pull_request:
paths:
- 'go/**'
branches: [main]
types: [opened, labeled, unlabeled, synchronize]
jobs:
label:
if: github.actor != 'dependabot[bot]'
runs-on: ubuntu-latest
permissions:
issues: write
pull-requests: write
steps:
- uses: mheap/github-action-required-labels@v5
with:
mode: exactly
count: 1
labels: "performance_approved"
add_comment: true
message: "<!-- go-run-output -->\nThis PR is being tested for performance. Please allow ~25 mins for this to complete. If this PR does not result in a performance regression, the `performance_approved` label will be automatically added to this PR."
+157
View File
@@ -0,0 +1,157 @@
name: Check Formatting, Committers and Generated Code
on:
pull_request:
branches: [ main ]
concurrency:
group: ci-check-repo-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
jobs:
verify:
name: Verify format and committers
runs-on: ubuntu-22.04
outputs:
format: ${{ steps.should_format.outputs.format }}
steps:
- uses: actions/checkout@v6
with:
submodules: true
- name: Setup Go 1.x
uses: actions/setup-go@v5
with:
go-version-file: go/go.mod
- name: Check all
id: should_format
working-directory: ./go
# Keep this in sync with //go/utils/prepr/prepr.sh.
run: |
GOFLAGS="-mod=readonly" go build ./...
go vet -mod=readonly ./...
go run -mod=readonly ./utils/copyrightshdrs/
./Godeps/verify.sh
./utils/repofmt/check_bats_fmt.sh
if ./utils/repofmt/check_fmt.sh ; then
echo "code is formatted"
else
echo "code is not formatted"
if [ "${{ github.repository }}" != "dolthub/dolt" ]; then
echo "Pull requests from forks must be manually formatted."
echo "Please run dolt/go/utils/repofmt/format_repo.sh to format this pull request."
exit 1;
fi
echo "format=true" >> $GITHUB_OUTPUT
fi
env:
BRANCH_NAME: ${{ github.head_ref }}
CHANGE_TARGET: ${{ github.base_ref }}
- name: Check generated protobufs and flatbuffers
working-directory: ./proto
run: |
bazel run //:update
changes=$(git status --porcelain)
diff=$(git diff)
if [ ! -z "$changes" ]; then
echo "ERROR: Generated protobuf structs and/or flatbuffer messages are different from the checked in version."
echo "$changes"
echo "$diff"
exit 1
fi
get-artifacts:
needs: verify
if: ${{ needs.verify.outputs.format == 'true' }}
name: Get artifacts
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v6
with:
ref: "main"
repository: "dolthub/dolt"
submodules: true
- name: Setup Go 1.x
uses: actions/setup-go@v5
with:
go-version-file: go/go.mod
- name: Copy script
working-directory: ./go/utils/repofmt
run: cp format_repo.sh _format_repo.sh
- name: Build go deps tool
working-directory: go/utils/3pdeps
run: go build .
- uses: actions/upload-artifact@v4
with:
name: update-godeps-tool
path: go/utils/3pdeps/3pdeps
- uses: actions/upload-artifact@v4
with:
name: format-code-script
path: go/utils/repofmt/_format_repo.sh
format:
needs: [verify, get-artifacts]
if: ${{ needs.verify.outputs.format == 'true' }}
name: Format PR
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v6
with:
ref: ${{ github.event.pull_request.head.ref || github.ref }}
repository: ${{ github.event.pull_request.head.repo.full_name || github.repository }}
submodules: true
token: ${{ secrets.REPO_ACCESS_TOKEN || secrets.GITHUB_TOKEN }}
- name: Setup Go 1.x
uses: actions/setup-go@v5
with:
go-version-file: go/go.mod
- name: Run go mod tidy
run: go mod tidy
working-directory: ./go
- name: Install goimports
run: go install golang.org/x/tools/cmd/goimports@latest
- uses: actions/download-artifact@v4
with:
name: format-code-script
path: go/utils/repofmt
- uses: actions/download-artifact@v4
with:
name: update-godeps-tool
path: go
- name: Format repo
working-directory: ./go
run: |
chmod +x ./utils/repofmt/_format_repo.sh
./utils/repofmt/_format_repo.sh
env:
BRANCH_NAME: ${{ github.head_ref }}
CHANGE_TARGET: ${{ github.base_ref }}
- name: Update Go deps
working-directory: ./go
run: |
chmod +x ./3pdeps
( GOOS=linux GOARCH=amd64 go list -deps -json ./cmd/dolt/. && \
GOOS=linux GOARCH=386 go list -deps -json ./cmd/dolt/. && \
GOOS=linux GOARCH=arm64 go list -deps -json ./cmd/dolt/. && \
GOOS=windows GOARCH=amd64 go list -deps -json ./cmd/dolt/. && \
GOOS=windows GOARCH=arm64 go list -deps -json ./cmd/dolt/. && \
GOOS=darwin GOARCH=amd64 go list -deps -json ./cmd/dolt/. && \
GOOS=darwin GOARCH=arm64 go list -deps -json ./cmd/dolt/. ) \
| ./3pdeps > ./Godeps/LICENSES
- name: Remove artifacts
run: |
rm go/3pdeps
rm go/utils/repofmt/_format_repo.sh
- name: Changes detected
id: detect-changes
run: |
changes=$(git status --porcelain)
if [ ! -z "$changes" ]; then
echo "has-changes=true" >> $GITHUB_OUTPUT
fi
- uses: EndBug/add-and-commit@v9.1.4
if: ${{ steps.detect-changes.outputs.has-changes == 'true' }}
with:
message: "[ga-format-pr] Run go/utils/repofmt/format_repo.sh and go/Godeps/update.sh"
add: "."
cwd: "."
pull: "--ff"
@@ -0,0 +1,42 @@
name: Check Compatibility
on:
pull_request:
branches: [ main ]
paths:
- 'go/**'
- 'integration-tests/**'
concurrency:
group: ci-compatibility-tests-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
jobs:
test:
name: Compatibility Test
runs-on: ${{ matrix.os }}
strategy:
fail-fast: true
matrix:
os: [ ubuntu-22.04 ]
steps:
- uses: actions/checkout@v6
- name: Set up Go toolchain
uses: ./.github/actions/setup-go-toolchain
- uses: actions/setup-node@v4
with:
node-version: ^16
- name: Install netcat
run: sudo apt-get update && sudo apt-get install -y netcat-openbsd
- name: Build dolt
uses: ./.github/actions/build-dolt
- name: Install Bats
run: |
npm i bats
echo "$(pwd)/node_modules/.bin" >> $GITHUB_PATH
working-directory: ./.ci_bin
- name: Setup Dolt Config
uses: ./.github/actions/setup-dolt-config
- name: Test all
run: ./runner.sh
working-directory: ./integration-tests/compatibility
@@ -0,0 +1,24 @@
name: Test Data Dump Loading integrations
on:
pull_request:
paths:
- 'go/**'
- 'integration-tests/**'
concurrency:
group: ci-data-dump-loading-tests-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
jobs:
data_dump_laoding_integrations_job:
runs-on: ubuntu-22.04
timeout-minutes: 30
name: Run tests
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Copy go package
run: cp -r ./go ./integration-tests/go
- name: Test data dump loading integrations
uses: ./.github/actions/data-dump-loading-tests
+32
View File
@@ -0,0 +1,32 @@
name: Race tests
on:
push:
branches: [ main ]
paths:
- 'go/**'
workflow_dispatch:
jobs:
racetests:
name: Go race tests
defaults:
run:
shell: bash
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ ubuntu-22.04 ]
steps:
- uses: actions/checkout@v6
- name: Set up Go toolchain
uses: ./.github/actions/setup-go-toolchain
- name: Test engine
working-directory: ./go
run: |
DOLT_SKIP_PREPARED_ENGINETESTS=1 go test -vet=off -v -race -timeout 30m github.com/dolthub/dolt/go/libraries/doltcore/sqle/enginetest
- name: Test concurrentmap
working-directory: ./go
run: |
go test -vet=off -v -race -timeout 1m github.com/dolthub/dolt/go/libraries/utils/concurrentmap
+96
View File
@@ -0,0 +1,96 @@
name: Test Go
on:
pull_request:
branches: [ main ]
paths:
- 'go/**'
- '.github/workflows/ci-go-tests.yaml'
workflow_dispatch:
concurrency:
group: ci-go-tests-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
jobs:
test:
name: Go tests
defaults:
run:
shell: bash
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [macos-latest, ubuntu-22.04, windows-latest]
steps:
- uses: actions/checkout@v6
- name: Set up Go toolchain
id: toolchain
uses: ./.github/actions/setup-go-toolchain
- name: Test All
working-directory: ./go
run: |
files=$(go list ./...)
SAVEIFS=$IFS
IFS=$'\n'
file_arr=($files)
IFS=$SAVEIFS
if [ "$MATRIX_OS" == 'windows-latest' ]; then
export PATH=$(cygpath -u "$MSYS2_LOCATION"/ucrt64/bin):"$PATH"
fi
for (( i=0; i<${#file_arr[@]}; i++ ))
do
# Skip binlog tests as they run in a separate CI job
if [[ "${file_arr[$i]}" == *binlogreplication* ]]; then
echo "Skipping binlog package: ${file_arr[$i]} (runs in separate CI)"
continue
fi
echo "Testing Package: ${file_arr[$i]}"
if [ "$MATRIX_OS" == 'ubuntu-22.04' ]
then
if [[ "${file_arr[$i]}" != *enginetest* ]]; then
go test -vet=off -timeout 45m -race "${file_arr[$i]}"
else
echo "skipping enginetests for -race"
fi
else
go test -vet=off -timeout 45m "${file_arr[$i]}"
fi
succeeded=$(echo "$?")
if [ "$succeeded" -ne 0 ]; then
echo "Testing failed in package ${file_arr[$i]}"
exit 1;
fi
done
env:
MATRIX_OS: ${{ matrix.os }}
MSYS2_LOCATION: ${{ steps.toolchain.outputs.msys2-location }}
noracetest:
name: Go tests - no race
defaults:
run:
shell: bash
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [macos-latest, ubuntu-22.04, windows-latest]
steps:
- uses: actions/checkout@v6
- name: Set up Go toolchain
id: toolchain
uses: ./.github/actions/setup-go-toolchain
- name: Test All
working-directory: ./go
run: |
if [ "$MATRIX_OS" == 'windows-latest' ]; then
export PATH=$(cygpath -u "$MSYS2_LOCATION"/ucrt64/bin):"$PATH"
fi
go test -vet=off -timeout 30m ./libraries/doltcore/sqle/integration_test
env:
MATRIX_OS: ${{ matrix.os }}
DOLT_TEST_RUN_NON_RACE_TESTS: "true"
MSYS2_LOCATION: ${{ steps.toolchain.outputs.msys2-location }}
+63
View File
@@ -0,0 +1,63 @@
name: Test Bats Unix
on:
pull_request:
branches: [ main ]
paths:
- 'go/**'
- 'integration-tests/**'
concurrency:
group: ci-lambdabats-unix-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
jobs:
test:
name: Bats tests, run with lambdabats
defaults:
run:
shell: bash
runs-on: ubuntu-22.04
strategy:
fail-fast: true
env:
use_credentials: ${{ secrets.AWS_SECRET_ACCESS_KEY != '' && secrets.AWS_ACCESS_KEY_ID != '' }}
steps:
- name: Conditionally Set ENV VARS for AWS tests
if: ${{ env.use_credentials == 'true' }}
run: |
echo "AWS_SDK_LOAD_CONFIG=1" >> $GITHUB_ENV
echo "AWS_REGION=us-west-2" >> $GITHUB_ENV
echo "DOLT_BATS_AWS_TABLE=dolt-ci-bats-manifests-us-west-2" >> $GITHUB_ENV
echo "DOLT_BATS_AWS_BUCKET=dolt-ci-bats-chunks-us-west-2" >> $GITHUB_ENV
echo "DOLT_BATS_AWS_EXISTING_REPO=aws_remote_bats_tests__dolt__" >> $GITHUB_ENV
- name: Configure AWS Credentials
if: ${{ env.use_credentials == 'true' }}
uses: aws-actions/configure-aws-credentials@v4
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: us-west-2
role-to-assume: ${{ secrets.AWS_ROLE_TO_ASSUME }}
role-duration-seconds: 10800 # 3 hours D:
- uses: actions/checkout@v6
if: ${{ env.use_credentials == 'true' }}
- name: Setup Go 1.x
uses: actions/setup-go@v5
if: ${{ env.use_credentials == 'true' }}
with:
go-version-file: go/go.mod
id: go
- name: install lambdabats
if: ${{ env.use_credentials == 'true' }}
run: go install github.com/dolthub/lambdabats/lambdabats@latest
- name: Test all Unix
if: ${{ env.use_credentials == 'true' }}
run: |
lambdabats -use-aws-environment-credentials -s lambda_skip -F tap .
working-directory: ./integration-tests/bats
- name: Test all Unix, SQL_ENGINE=remote-engine
if: ${{ env.use_credentials == 'true' }}
run: |
lambdabats -env SQL_ENGINE=remote-engine -s lambda_skip -use-aws-environment-credentials -F tap .
working-directory: ./integration-tests/bats
@@ -0,0 +1,60 @@
name: Test MySQL Client integrations
on:
pull_request:
paths:
- 'go/**'
- 'integration-tests/**'
concurrency:
group: ci-mysql-client-tests-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
jobs:
mysql_client_integrations:
runs-on: ubuntu-22.04
timeout-minutes: 45
steps:
- name: Checkout
uses: actions/checkout@v6
with:
path: dolt
- name: Free disk space
run: |
NAME="DISK-CLEANUP"
echo "[${NAME}] Starting background cleanup..."
[ -d "$AGENT_TOOLSDIRECTORY" ] && sudo rm -rf "$AGENT_TOOLSDIRECTORY" &
[ -d /usr/share/dotnet ] && sudo rm -rf /usr/share/dotnet &
[ -d /usr/local/lib/android ] && sudo rm -rf /usr/local/lib/android &
[ -d /opt/ghc ] && sudo rm -rf /opt/ghc &
[ -d /usr/local/share/boost ] && sudo rm -rf /usr/local/share/boost &
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
- name: Ensure cache directory exists
run: |
sudo mkdir -p /mnt/.buildx-cache
sudo chown $USER:$USER /mnt/.buildx-cache
- name: Cache Docker layers
uses: actions/cache@v3
with:
path: /mnt/.buildx-cache
key: ${{ runner.os }}-docker-mysql-client-integrations
restore-keys: |
${{ runner.os }}-docker
- name: Build MySQL test image
uses: docker/build-push-action@v6
with:
context: .
file: dolt/integration-tests/mysql-client-tests/Dockerfile
tags: mysql-client-tests:latest
load: true
cache-from: type=local,src=/mnt/.buildx-cache
cache-to: type=local,dest=/mnt/.buildx-cache
- name: Test MySQL client integrations
run: docker run --rm mysql-client-tests:latest
+54
View File
@@ -0,0 +1,54 @@
name: Test ORM integrations
on:
pull_request:
paths:
- 'go/**'
- 'integration-tests/**'
workflow_dispatch:
repository_dispatch:
types: [ test-orm-integrations ]
concurrency:
group: ci-orm-tests-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
jobs:
orm_integrations_job:
runs-on: ubuntu-22.04
timeout-minutes: 30
name: ORM tests
steps:
- name: Checkout
uses: actions/checkout@v6
with:
path: dolt
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
- name: Build ORM test image
uses: docker/build-push-action@v6
with:
context: .
file: dolt/integration-tests/orm-tests/Dockerfile
tags: orm-tests:latest
load: true
cache-from: type=gha
cache-to: type=gha,mode=max
- name: Test ORM integrations
run: docker run --rm orm-tests:latest
- name: Configure AWS Credentials
if: ${{ failure() && !env.ACT }}
uses: aws-actions/configure-aws-credentials@v4
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: us-west-2
- name: Send Email
if: ${{ failure() && !env.ACT }}
uses: ./.github/actions/ses-email-action
with:
template: 'OrmIntegrationFailureTemplate'
region: us-west-2
version: ${{ github.ref }}
toAddresses: '["jennifer@dolthub.com", "tim@dolthub.com"]'
workflowURL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
@@ -0,0 +1,33 @@
name: sql-server Integration Tests
on:
pull_request:
branches: [main]
paths:
- "go/**"
- "integration-tests/go-sql-server-driver/**"
concurrency:
group: ci-sql-server-integration-tests-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
jobs:
test:
name: sql-server Integration Tests
defaults:
run:
shell: bash
runs-on: ${{ matrix.os }}
strategy:
fail-fast: true
matrix:
os: [ubuntu-22.04]
steps:
- uses: actions/checkout@v6
- name: Set up Go toolchain
uses: ./.github/actions/setup-go-toolchain
- name: Build dolt
uses: ./.github/actions/build-dolt
- name: Test all
run: go test .
working-directory: ./integration-tests/go-sql-server-driver
+92
View File
@@ -0,0 +1,92 @@
name: Test Integration with DoltgreSQL
on:
pull_request:
types: [opened, synchronize, reopened]
issue_comment:
types: [created, edited, deleted]
jobs:
test-integration:
if: github.event_name == 'issue_comment' && github.event.issue.pull_request != '' || github.event_name == 'pull_request'
runs-on: ubuntu-latest
steps:
- name: Set timezone for Unix
uses: szenius/set-timezone@v2.0
with:
timezoneLinux: "America/Los_Angeles"
- name: Checkout Dolt
uses: actions/checkout@v6
with:
ref: ${{ github.event.pull_request.head.sha }}
- name: Setup Git User
uses: fregante/setup-git-user@v2
- name: Merge main into PR
id: merge_main
run: |
git fetch --all --unshallow
git merge origin/main --no-commit --no-ff
if [ $? -ne 0 ]; then
echo "Skipping the remainder of the workflow due to a merge conflict."
echo "skip=true" >> $GITHUB_OUTPUT
else
echo "Merge performed successfully, continuing workflow."
echo "skip=false" >> $GITHUB_OUTPUT
fi
- name: Check for a DoltgreSQL PR link
id: check_doltgresql_pr
if: steps.merge_main.outputs.skip == 'false'
run: |
PR_DESCRIPTION=$(curl -s -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \
https://api.github.com/repos/${{ github.repository }}/pulls/${{ github.event.pull_request.number != '' && github.event.pull_request.number || github.event.issue.number }})
COMMENTS=$(curl -s -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \
https://api.github.com/repos/${{ github.repository }}/issues/${{ github.event.pull_request.number != '' && github.event.pull_request.number || github.event.issue.number }}/comments)
echo "$PR_DESCRIPTION$COMMENTS"
if echo "$PR_DESCRIPTION$COMMENTS" | grep -q "github.com/dolthub/doltgresql/pull/"; then
echo "comment_exists=true" >> $GITHUB_OUTPUT
echo "DoltgreSQL PR link exists"
else
echo "comment_exists=false" >> $GITHUB_OUTPUT
echo "DoltgreSQL PR link does not exist"
fi
- name: Install Go
uses: actions/setup-go@v5
if: steps.merge_main.outputs.skip == 'false'
with:
go-version-file: go/go.mod
- name: Clone DoltgreSQL repository
if: steps.merge_main.outputs.skip == 'false' && steps.check_doltgresql_pr.outputs.comment_exists == 'false'
run: git clone https://github.com/dolthub/doltgresql.git
- name: Build DoltgreSQL's parser
if: steps.merge_main.outputs.skip == 'false' && steps.check_doltgresql_pr.outputs.comment_exists == 'false'
run: |
cd doltgresql
./postgres/parser/build.sh
- name: Test DoltgreSQL against main
id: test_doltgresql_main
if: steps.merge_main.outputs.skip == 'false' && steps.check_doltgresql_pr.outputs.comment_exists == 'false'
continue-on-error: true
run: |
cd doltgresql
go get github.com/dolthub/dolt/go@main
go mod tidy
cd testing/go
go test ./... --count=1 -skip Replication
- name: Test DoltgreSQL against PR
if: steps.merge_main.outputs.skip == 'false' && steps.check_doltgresql_pr.outputs.comment_exists == 'false' && steps.test_doltgresql_main.outcome == 'success'
run: |
cd doltgresql
git reset --hard
go mod edit -replace github.com/dolthub/dolt/go=../go
go mod tidy
cd testing/go
go test ./... --count=1 -skip Replication
+44
View File
@@ -0,0 +1,44 @@
name: Email Team Members
on:
repository_dispatch:
types: [ email-report ]
jobs:
email-team:
runs-on: ubuntu-22.04
name: Email Team Members
steps:
- uses: actions/checkout@v6
- name: Configure AWS Credentials
uses: aws-actions/configure-aws-credentials@v4
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: us-west-2
- name: Get Results
id: get-results
run: aws s3api get-object --bucket="$BUCKET" --key="$KEY" results.log
env:
KEY: ${{ github.event.client_payload.key }}
BUCKET: ${{ github.event.client_payload.bucket }}
- name: Get Addresses
id: get-addresses
run: |
addresses="$TEAM"
if [ ! -z "$RECIPIENT" ]; then
addresses="[\"$RECIPIENT\"]"
fi
echo "addresses=$addresses" >> $GITHUB_OUTPUT
env:
RECIPIENT: ${{ github.event.client_payload.email_recipient }}
TEAM: '["${{ secrets.PERF_REPORTS_EMAIL_ADDRESS }}"]'
- name: Send Email
uses: ./.github/actions/ses-email-action
with:
template: ${{ github.event.client_payload.template }}
region: us-west-2
version: ${{ github.event.client_payload.version }}
format: ${{ github.event.client_payload.noms_bin_format }}
toAddresses: ${{ steps.get-addresses.outputs.addresses }}
dataFile: ${{ format('{0}/results.log', github.workspace) }}
@@ -0,0 +1,73 @@
name: Run Import Benchmark on Pull Requests
on:
pull_request:
types: [ opened ]
issue_comment:
types: [ created ]
jobs:
validate-commentor:
runs-on: ubuntu-22.04
outputs:
valid: ${{ steps.set_valid.outputs.valid }}
steps:
- uses: actions/checkout@v6
- name: Validate Commentor
id: set_valid
run: ./.github/scripts/performance-benchmarking/validate-commentor.sh "$ACTOR"
env:
ACTOR: ${{ github.actor }}
check-comments:
runs-on: ubuntu-22.04
needs: validate-commentor
if: ${{ needs.validate-commentor.outputs.valid == 'true' }}
outputs:
benchmark: ${{ steps.set_benchmark.outputs.benchmark }}
comment-body: ${{ steps.set_body.outputs.body }}
steps:
- name: Check for Deploy Trigger
uses: dolthub/pull-request-comment-trigger@v2
id: check
with:
trigger: '#import-benchmark'
reaction: rocket
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Set Benchmark
if: ${{ steps.check.outputs.triggered == 'true' }}
id: set_benchmark
run: |
echo "benchmark=true" >> $GITHUB_OUTPUT
performance:
runs-on: ubuntu-22.04
needs: [validate-commentor, check-comments]
if: ${{ needs.check-comments.outputs.benchmark == 'true' }}
name: Trigger Benchmark Import Workflow
steps:
- uses: dolthub/pull-request-comment-branch@v3
id: comment-branch
with:
repo_token: ${{ secrets.GITHUB_TOKEN }}
- name: Get pull number
uses: actions/github-script@v7
id: get_pull_number
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: core.setOutput("pull_number", JSON.stringify(context.issue.number));
- uses: peter-evans/repository-dispatch@v3
with:
token: ${{ secrets.REPO_ACCESS_TOKEN }}
event-type: benchmark-import
client-payload: |
{
"version": "${{ steps.comment-branch.outputs.head_sha }}",
"run_file": "ci.yaml",
"summary": "summary.sql",
"report": "three_way_compare.sql",
"commit_to_branch": "${{ steps.comment-branch.outputs.head_sha }}",
"actor": "${{ github.actor }}",
"issue_id": "${{ steps.get_pull_number.outputs.pull_number }}"
}
+177
View File
@@ -0,0 +1,177 @@
name: Import Benchmarks
on:
repository_dispatch:
types: [ benchmark-import ]
env:
BENCH_DIR: 'go/performance/import_benchmarker'
MYSQL_PORT: 3309
MYSQL_PASSWORD: password
jobs:
bench:
name: Benchmark
defaults:
run:
shell: bash
strategy:
fail-fast: true
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
with:
ref: ${{ github.event.client_payload.version }}
- name: Set up Go 1.x
id: go
uses: actions/setup-go@v5
with:
go-version-file: go/go.mod
- name: Dolt version
id: version
run: |
version=${{ github.event.client_payload.version }}
- name: Install dolt
working-directory: ./go
run: go install ./cmd/dolt
- uses: shogo82148/actions-setup-mysql@v1
with:
mysql-version: '8.0'
auto-start: true
root-password: ${{ env.MYSQL_PASSWORD }}
my-cnf: |
local_infile=1
socket=/tmp/mysqld2.sock
port=${{ env.MYSQL_PORT }}
- name: Setup MySQL
run: mysql -uroot -p${{ env.MYSQL_PASSWORD }} -h127.0.0.1 -P${{ env.MYSQL_PORT }} -e 'create database test;'
- name: Run bench
id: bench
working-directory: go/
run: |
out="$GITHUB_WORKSPACE/results.sql"
testspec="../${{ env.BENCH_DIR }}/testdata/${{ github.event.client_payload.run_file }}"
go run \
"github.com/dolthub/dolt/${{ env.BENCH_DIR }}/cmd" \
-test "$testspec" \
-out "$out"
echo "result_path=$out" >> $GITHUB_OUTPUT
- name: Report
id: report
run: |
gw=$GITHUB_WORKSPACE
in="${{ steps.bench.outputs.result_path }}"
query="$(pwd)/${{ env.BENCH_DIR }}/reporting/${{ github.event.client_payload.report }}"
summaryq="$(pwd)/${{ env.BENCH_DIR }}/reporting/${{ github.event.client_payload.summary }}"
out="$gw/results.csv"
dolt_dir="$gw/import-perf"
dolt config --global --add user.email "import-perf@dolthub.com"
dolt config --global --add user.name "import-perf"
echo '${{ secrets.DOLTHUB_IMPORT_PERF_CREDS_VALUE }}' | dolt creds import
dolt clone import-perf/import-perf "$dolt_dir"
cd "$dolt_dir"
branch="${{ github.event.client_payload.commit_to_branch }}"
# checkout branch
if [ -z $(dolt sql -q "select 1 from dolt_branches where name = '$branch';") ]; then
dolt checkout -b $branch
else
dolt checkout $branch
fi
dolt sql -q "drop table if exists import_perf_results"
# load results
dolt sql < "$in"
# push results to dolthub
dolt add import_perf_results
dolt commit -m "CI commit"
dolt push -f origin $branch
# generate report
dolt sql -r csv < "$query" > "$out"
cat "$out"
echo "report_path=$out" >> $GITHUB_OUTPUT
avg=$(dolt sql -r csv < "$summaryq" | tail -1)
echo "avg=$avg" >> $GITHUB_OUTPUT
- name: Format HTML
id: html
if: ${{ github.event.client_payload.email_recipient }} != ""
run: |
gw="$GITHUB_WORKSPACE"
in="${{ steps.report.outputs.report_path }}"
out="$gw/results.html"
echo "<table>" > "$out"
print_header=true
while read line; do
if "$print_header"; then
echo " <tr><th>${line//,/</th><th>}</th></tr>" >> "$out"
print_header=false
continue
fi
echo " <tr><td>${line//,/</td><td>}</td></tr>" >> "$out"
done < "$in"
echo "</table>" >> "$out"
avg="${{ steps.report.outputs.avg }}"
echo "<table><tr><th>Average</th></tr><tr><td>$avg</tr></td></table>" >> "$out"
cat "$out"
echo "html=$(echo $out)" >> $GITHUB_OUTPUT
- name: Configure AWS Credentials
if: ${{ github.event.client_payload.email_recipient }} != ""
uses: aws-actions/configure-aws-credentials@v4
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: us-west-2
- name: Send Email
uses: ./.github/actions/ses-email-action
if: ${{ github.event.client_payload.email_recipient }} != ""
with:
region: us-west-2
toAddresses: '["${{ github.event.client_payload.email_recipient }}"]'
subject: 'Import Performance Benchmarks: ${{ github.event.client_payload.version }}'
bodyPath: ${{ steps.html.outputs.html }}
template: 'SysbenchTemplate'
- name: Read CSV
if: ${{ github.event.client_payload.issue_id }} != ""
id: csv
uses: juliangruber/read-file-action@v1
with:
path: "${{ steps.report.outputs.report_path }}"
- name: Create MD
if: ${{ github.event.client_payload.issue_id }} != ""
uses: dolthub/csv-to-md-table-action@v4
id: md
with:
csvinput: ${{ steps.csv.outputs.content }}
- uses: mshick/add-pr-comment@v2
if: ${{ github.event.client_payload.issue_id }} != ""
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
issue: ${{ github.event.client_payload.issue_id }}
message-failure: import benchmark failed
message-cancelled: import benchmark cancelled
allow-repeats: true
message: |
@${{ github.event.client_payload.actor }} __DOLT__
${{ steps.md.outputs.markdown-table }}
@@ -0,0 +1,74 @@
name: Benchmark Latency
on:
repository_dispatch:
types: [ benchmark-latency ]
jobs:
performance:
runs-on: ubuntu-22.04
name: Benchmark Performance
strategy:
matrix:
dolt_fmt: [ "__DOLT__" ]
steps:
- name: Checkout
uses: actions/checkout@v6
- uses: azure/setup-kubectl@v4
with:
version: 'v1.23.6'
- name: Install aws-iam-authenticator
run: |
curl -o aws-iam-authenticator https://amazon-eks.s3.us-west-2.amazonaws.com/1.18.8/2020-09-18/bin/linux/amd64/aws-iam-authenticator && \
chmod +x ./aws-iam-authenticator && \
sudo cp ./aws-iam-authenticator /usr/local/bin/aws-iam-authenticator
aws-iam-authenticator version
- name: Configure AWS Credentials
uses: aws-actions/configure-aws-credentials@v4
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: us-west-2
- name: Create and Auth kubeconfig
run: |
echo "$CONFIG" > kubeconfig
KUBECONFIG=kubeconfig kubectl config set-credentials github-actions-dolt --exec-api-version=client.authentication.k8s.io/v1alpha1 --exec-command=aws-iam-authenticator --exec-arg=token --exec-arg=-i --exec-arg=eks-cluster-1
KUBECONFIG=kubeconfig kubectl config set-context github-actions-dolt-context --cluster=eks-cluster-1 --user=github-actions-dolt --namespace=performance-benchmarking
KUBECONFIG=kubeconfig kubectl config use-context github-actions-dolt-context
env:
CONFIG: ${{ secrets.CORP_KUBECONFIG }}
- name: Create Sysbench Performance Benchmarking K8s Job
run: ./.github/scripts/performance-benchmarking/run-benchmarks.sh
env:
FROM_SERVER: ${{ github.event.client_payload.from_server }}
FROM_VERSION: ${{ github.event.client_payload.from_version }}
TO_SERVER: ${{ github.event.client_payload.to_server }}
TO_VERSION: ${{ github.event.client_payload.to_version }}
TO_PROFILE_KEY: ${{ github.event.client_payload.to_profile_key }}
MODE: ${{ github.event.client_payload.mode }}
ISSUE_NUMBER: ${{ github.event.client_payload.issue_number }}
ACTOR: ${{ github.event.client_payload.actor }}
ACTOR_EMAIL: ${{ github.event.client_payload.actor_email }}
REPO_ACCESS_TOKEN: ${{ secrets.REPO_ACCESS_TOKEN }}
KUBECONFIG: "./kubeconfig"
INIT_BIG_REPO: ${{ github.event.client_payload.init_big_repo }}
NOMS_BIN_FORMAT: ${{ matrix.dolt_fmt }}
SYSBENCH_TEST_TIME: ${{ github.event.client_payload.sysbench_test_time }}
TEMPLATE_SCRIPT: ${{ github.event.client_payload.template_script }}
- name: Create TPCC Performance Benchmarking K8s Job
run: ./.github/scripts/performance-benchmarking/run-benchmarks.sh
env:
FROM_SERVER: ${{ github.event.client_payload.from_server }}
FROM_VERSION: ${{ github.event.client_payload.from_version }}
TO_SERVER: ${{ github.event.client_payload.to_server }}
TO_VERSION: ${{ github.event.client_payload.to_version }}
MODE: ${{ github.event.client_payload.mode }}
ISSUE_NUMBER: ${{ github.event.client_payload.issue_number }}
ACTOR: ${{ github.event.client_payload.actor }}
ACTOR_EMAIL: ${{ github.event.client_payload.actor_email }}
REPO_ACCESS_TOKEN: ${{ secrets.REPO_ACCESS_TOKEN }}
KUBECONFIG: "./kubeconfig"
INIT_BIG_REPO: ${{ github.event.client_payload.init_big_repo }}
NOMS_BIN_FORMAT: ${{ matrix.dolt_fmt }}
WITH_TPCC: "true"
TEMPLATE_SCRIPT: ${{ github.event.client_payload.template_script }}
+51
View File
@@ -0,0 +1,51 @@
name: Profile Dolt while Benchmarking
on:
repository_dispatch:
types: [ profile-dolt ]
jobs:
performance:
runs-on: ubuntu-22.04
name: Profile Dolt while Benchmarking
steps:
- name: Checkout
uses: actions/checkout@v6
- uses: azure/setup-kubectl@v4
with:
version: 'v1.23.6'
- name: Install aws-iam-authenticator
run: |
curl -o aws-iam-authenticator https://amazon-eks.s3.us-west-2.amazonaws.com/1.18.8/2020-09-18/bin/linux/amd64/aws-iam-authenticator && \
chmod +x ./aws-iam-authenticator && \
sudo cp ./aws-iam-authenticator /usr/local/bin/aws-iam-authenticator
aws-iam-authenticator version
- name: Configure AWS Credentials
uses: aws-actions/configure-aws-credentials@v4
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: us-west-2
- name: Create and Auth kubeconfig
run: |
echo "$CONFIG" > kubeconfig
KUBECONFIG=kubeconfig kubectl config set-credentials github-actions-dolt --exec-api-version=client.authentication.k8s.io/v1alpha1 --exec-command=aws-iam-authenticator --exec-arg=token --exec-arg=-i --exec-arg=eks-cluster-1
KUBECONFIG=kubeconfig kubectl config set-context github-actions-dolt-context --cluster=eks-cluster-1 --user=github-actions-dolt --namespace=performance-benchmarking
KUBECONFIG=kubeconfig kubectl config use-context github-actions-dolt-context
env:
CONFIG: ${{ secrets.CORP_KUBECONFIG }}
- name: Create Profile Benchmarking K8s Job
run: ./.github/scripts/performance-benchmarking/run-benchmarks.sh
env:
PROFILE: "true"
FUTURE_VERSION: ${{ github.event.client_payload.future_version }}
FROM_VERSION: ${{ github.event.client_payload.from_version }}
MODE: ${{ github.event.client_payload.mode }}
ACTOR: ${{ github.event.client_payload.actor }}
ACTOR_EMAIL: ${{ github.event.client_payload.actor_email }}
REPO_ACCESS_TOKEN: ${{ secrets.REPO_ACCESS_TOKEN }}
KUBECONFIG: "./kubeconfig"
INIT_BIG_REPO: ${{ github.event.client_payload.init_big_repo }}
NOMS_BIN_FORMAT: "__DOLT__"
TEMPLATE_SCRIPT: ${{ github.event.client_payload.template_script }}
BRANCH: ${{ github.event.client_payload.branch || 'main' }}
+47
View File
@@ -0,0 +1,47 @@
name: Fuzzer
on:
workflow_dispatch:
push:
paths:
- 'go/**'
branches:
- 'main'
jobs:
fuzzer:
runs-on: ubuntu-22.04
name: Run Fuzzer
steps:
- uses: actions/checkout@v6
- uses: azure/setup-kubectl@v4
with:
version: 'v1.23.6'
- name: Configure AWS Credentials
uses: aws-actions/configure-aws-credentials@v4
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: us-west-2
- name: Install aws-iam-authenticator
run: |
curl -o aws-iam-authenticator https://amazon-eks.s3.us-west-2.amazonaws.com/1.18.8/2020-09-18/bin/linux/amd64/aws-iam-authenticator && \
chmod +x ./aws-iam-authenticator && \
sudo cp ./aws-iam-authenticator /usr/local/bin/aws-iam-authenticator
aws-iam-authenticator version
- name: Create and Auth kubeconfig
run: |
echo "$CONFIG" > kubeconfig
KUBECONFIG=kubeconfig kubectl config set-credentials github-actions-dolt --exec-api-version=client.authentication.k8s.io/v1alpha1 --exec-command=aws-iam-authenticator --exec-arg=token --exec-arg=-i --exec-arg=eks-cluster-1
KUBECONFIG=kubeconfig kubectl config set-context github-actions-dolt-context --cluster=eks-cluster-1 --user=github-actions-dolt --namespace=fuzzer
KUBECONFIG=kubeconfig kubectl config use-context github-actions-dolt-context
env:
CONFIG: ${{ secrets.CORP_KUBECONFIG }}
- name: Create Fuzzer (GateKeeper) K8s Job
run: ./.github/scripts/fuzzer/run-fuzzer.sh
env:
VERSION: ${{ github.sha }}
ACTOR: "Hydrocharged"
REPO_ACCESS_TOKEN: ${{ secrets.REPO_ACCESS_TOKEN }}
KUBECONFIG: "./kubeconfig"
TEMPLATE_SCRIPT: "./.github/scripts/fuzzer/get-fuzzer-job-json.sh"
@@ -0,0 +1,52 @@
name: SQL Correctness
on:
repository_dispatch:
types: [ sql-correctness ]
jobs:
correctness:
runs-on: ubuntu-22.04
name: Dolt SQL Correctness
strategy:
matrix:
dolt_fmt: [ "__DOLT__" ]
steps:
- uses: actions/checkout@v6
- uses: azure/setup-kubectl@v4
with:
version: 'v1.23.6'
- name: Configure AWS Credentials
uses: aws-actions/configure-aws-credentials@v4
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: us-west-2
- name: Install aws-iam-authenticator
run: |
curl -o aws-iam-authenticator https://amazon-eks.s3.us-west-2.amazonaws.com/1.18.8/2020-09-18/bin/linux/amd64/aws-iam-authenticator && \
chmod +x ./aws-iam-authenticator && \
sudo cp ./aws-iam-authenticator /usr/local/bin/aws-iam-authenticator
aws-iam-authenticator version
- name: Create and Auth kubeconfig
run: |
echo "$CONFIG" > kubeconfig
KUBECONFIG=kubeconfig kubectl config set-credentials github-actions-dolt --exec-api-version=client.authentication.k8s.io/v1alpha1 --exec-command=aws-iam-authenticator --exec-arg=token --exec-arg=-i --exec-arg=eks-cluster-1
KUBECONFIG=kubeconfig kubectl config set-context github-actions-dolt-context --cluster=eks-cluster-1 --user=github-actions-dolt --namespace=performance-benchmarking
KUBECONFIG=kubeconfig kubectl config use-context github-actions-dolt-context
env:
CONFIG: ${{ secrets.CORP_KUBECONFIG }}
- name: Create SQL Correctness K8s Job
run: ./.github/scripts/sql-correctness/run-correctness.sh
env:
PR_BRANCH_REF: ${{ github.event.client_payload.branch_ref }}
REGRESS_COMP: ${{ github.event.client_payload.regress_comp }}
PR_NUMBER: ${{ github.event.client_payload.issue_number }}
VERSION: ${{ github.event.client_payload.version }}
MODE: ${{ github.event.client_payload.mode }}
ACTOR: ${{ github.event.client_payload.actor }}
ACTOR_EMAIL: ${{ github.event.client_payload.actor_email }}
REPO_ACCESS_TOKEN: ${{ secrets.REPO_ACCESS_TOKEN }}
KUBECONFIG: "./kubeconfig"
NOMS_BIN_FORMAT: ${{ matrix.dolt_fmt }}
TEMPLATE_SCRIPT: ${{ github.event.client_payload.template_script }}
@@ -0,0 +1,19 @@
name: Label Customer Issues
on:
issues:
types: [opened]
pull_request_target:
branches: [main]
types: [opened]
jobs:
label_customer_issues:
runs-on: ubuntu-latest
steps:
- uses: dolthub/label-customer-issues@main
with:
repo-token: ${{ secrets.REPO_ACCESS_TOKEN }}
issue-label: customer issue
pr-label: contribution
exclude: dependabot
+70
View File
@@ -0,0 +1,70 @@
name: Run Merge Benchmark on Pull Requests
on:
pull_request:
types: [ opened ]
issue_comment:
types: [ created ]
jobs:
validate-commentor:
runs-on: ubuntu-22.04
outputs:
valid: ${{ steps.set_valid.outputs.valid }}
steps:
- uses: actions/checkout@v6
- name: Validate Commentor
id: set_valid
run: ./.github/scripts/performance-benchmarking/validate-commentor.sh "$ACTOR"
env:
ACTOR: ${{ github.actor }}
check-comments:
runs-on: ubuntu-22.04
needs: validate-commentor
if: ${{ needs.validate-commentor.outputs.valid == 'true' }}
outputs:
benchmark: ${{ steps.set_benchmark.outputs.benchmark }}
comment-body: ${{ steps.set_body.outputs.body }}
steps:
- name: Check for Deploy Trigger
uses: dolthub/pull-request-comment-trigger@v2
id: check
with:
trigger: '#merge-benchmark'
reaction: rocket
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Set Benchmark
if: ${{ steps.check.outputs.triggered == 'true' }}
id: set_benchmark
run: |
echo "benchmark=true" >> $GITHUB_OUTPUT
performance:
runs-on: ubuntu-22.04
needs: [validate-commentor, check-comments]
if: ${{ needs.check-comments.outputs.benchmark == 'true' }}
name: Trigger Benchmark Merge Workflow
steps:
- uses: dolthub/pull-request-comment-branch@v3
id: comment-branch
with:
repo_token: ${{ secrets.GITHUB_TOKEN }}
- name: Get pull number
uses: actions/github-script@v7
id: get_pull_number
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: core.setOutput("pull_number", JSON.stringify(context.issue.number));
- uses: peter-evans/repository-dispatch@v3
with:
token: ${{ secrets.REPO_ACCESS_TOKEN }}
event-type: benchmark-merge
client-payload: |
{
"version": "${{ steps.comment-branch.outputs.head_sha }}",
"commit_to_branch": "${{ steps.comment-branch.outputs.head_sha }}",
"actor": "${{ github.actor }}",
"issue_id": "${{ steps.get_pull_number.outputs.pull_number }}"
}
+207
View File
@@ -0,0 +1,207 @@
name: Merge Benchmarks
on:
repository_dispatch:
types: [ benchmark-merge ]
env:
SCRIPT_DIR: '.github/scripts/merge-perf'
RESULT_TABLE_NAME: 'merge_perf_results'
DOLTHUB_DB: 'import-perf/merge-perf'
jobs:
bench:
name: Benchmark
defaults:
run:
shell: bash
strategy:
fail-fast: true
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
with:
ref: ${{ github.event.client_payload.version }}
- name: Set up Go 1.x
id: go
uses: actions/setup-go@v5
with:
go-version-file: go/go.mod
- name: Setup Python 3.x
uses: actions/setup-python@v5
with:
python-version: "3.10"
- name: Dolt version
id: version
run: |
version=${{ github.event.client_payload.version }}
- name: Install dolt
working-directory: ./go
run: go install ./cmd/dolt
- name: Config dolt
id: config
run: |
dolt config --global --add user.email "merge-perf@dolthub.com"
dolt config --global --add user.name "merge-perf"
- name: Run bench
id: bench
run: |
gw=$GITHUB_WORKSPACE
DATADIR=$gw/data
# initialize results sql import
RESULTS=$gw/results.sql
echo "CREATE TABLE ${{env.RESULT_TABLE_NAME }} (name varchar(50) primary key, table_cnt int, run_cnt int, add_cnt int, delete_cnt int, update_cnt int, conflict_cnt int, fks bool, latency float);" >> $RESULTS
# parameters for testing
ROW_NUM=1000000
TABLE_NUM=2
EDIT_CNT=60000
names=('adds_only' 'deletes_only' 'updates_only' 'adds_updates_deletes')
adds=($EDIT_CNT 0 0 $EDIT_CNT)
deletes=(0 $EDIT_CNT 0 $EDIT_CNT)
updates=(0 0 $EDIT_CNT $EDIT_CNT)
wd=$(pwd)
for i in {0..3}; do
cd $wd
echo "${names[$i]}, ${adds[$i]}, ${deletes[$i]}, ${updates[$i]}"
# data.py creates files for import
python ${{ env.SCRIPT_DIR }}/data.py $DATADIR $TABLE_NUM $ROW_NUM ${adds[$i]} ${deletes[$i]} ${updates[$i]}
# setup.sh runs the import and commit process for a set of data files
TMPDIR=$gw/tmp
./${{ env.SCRIPT_DIR}}/setup.sh $TMPDIR $DATADIR
# small python script times merge, we suppress errcodes but print error messages
cd $TMPDIR
python3 -c "import time, subprocess, sys; start = time.time(); res=subprocess.run(['dolt', 'merge', '--squash', 'main'], capture_output=True); err = res.stdout + res.stderr if res.returncode != 0 else ''; latency = time.time() -start; print(latency); sys.stderr.write(str(err))" 1> lat.log 2>err.log
latency=$(cat lat.log)
cat err.log
# count conflicts in first table
conflicts=$(dolt sql -r csv -q "select count(*) from dolt_conflicts_table0;" | tail -1)
echo "INSERT INTO ${{ env.RESULT_TABLE_NAME }} values ('"${names[$i]}"', $TABLE_NUM, $ROW_NUM, ${adds[$i]}, ${deletes[$i]}, ${updates[$i]}, $conflicts, true, $latency);" >> $RESULTS
done
echo "result_path=$RESULTS" >> $GITHUB_OUTPUT
- name: Report
id: report
run: |
gw=$GITHUB_WORKSPACE
in="${{ steps.bench.outputs.result_path }}"
query="select name, add_cnt, delete_cnt, update_cnt, round(latency, 2) as latency from ${{ env.RESULT_TABLE_NAME }}"
summaryq="select round(avg(latency), 2) as avg from ${{ env.RESULT_TABLE_NAME }}"
out="$gw/results.csv"
dolt_dir="$gw/merge-perf"
dolt config --global --add user.email "merge-perf@dolthub.com"
dolt config --global --add user.name "merge-perf"
echo '${{ secrets.DOLTHUB_IMPORT_PERF_CREDS_VALUE }}' | dolt creds import
dolt clone ${{ env.DOLTHUB_DB }} "$dolt_dir"
cd "$dolt_dir"
branch="${{ github.event.client_payload.commit_to_branch }}"
# checkout branch
if [ -z $(dolt sql -q "select 1 from dolt_branches where name = '$branch';") ]; then
dolt checkout -b $branch
else
dolt checkout $branch
fi
dolt sql -q "drop table if exists ${{ env.RESULT_TABLE_NAME }}"
# load results
dolt sql < "$in"
# push results to dolthub
dolt add ${{ env.RESULT_TABLE_NAME }}
dolt commit -m "CI commit"
dolt push -f origin $branch
# generate report
dolt sql -r csv -q "$query" > "$out"
cat "$out"
echo "report_path=$out" >> $GITHUB_OUTPUT
avg=$(dolt sql -r csv -q "$summaryq" | tail -1)
echo "avg=$avg" >> $GITHUB_OUTPUT
- name: Format Results
id: html
if: ${{ github.event.client_payload.email_recipient }} != ""
run: |
gw="$GITHUB_WORKSPACE"
in="${{ steps.report.outputs.report_path }}"
out="$gw/results.html"
echo "<table>" > "$out"
print_header=true
while read line; do
if "$print_header"; then
echo " <tr><th>${line//,/</th><th>}</th></tr>" >> "$out"
print_header=false
continue
fi
echo " <tr><td>${line//,/</td><td>}</td></tr>" >> "$out"
done < "$in"
echo "</table>" >> "$out"
avg="${{ steps.report.outputs.avg }}"
echo "<table><tr><th>Average</th></tr><tr><td>$avg</tr></td></table>" >> "$out"
cat "$out"
echo "html=$(echo $out)" >> $GITHUB_OUTPUT
- name: Configure AWS Credentials
if: ${{ github.event.client_payload.email_recipient }} != ""
uses: aws-actions/configure-aws-credentials@v4
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: us-west-2
- name: Send Email
uses: ./.github/actions/ses-email-action
if: ${{ github.event.client_payload.email_recipient }} != ""
with:
region: us-west-2
toAddresses: '["${{ github.event.client_payload.email_recipient }}"]'
subject: 'Merge Performance Benchmarks: ${{ github.event.client_payload.version }}'
bodyPath: ${{ steps.html.outputs.html }}
template: 'SysbenchTemplate'
- name: Read CSV
if: ${{ github.event.client_payload.issue_id }} != ""
id: csv
uses: juliangruber/read-file-action@v1
with:
path: "${{ steps.report.outputs.report_path }}"
- name: Create MD
if: ${{ github.event.client_payload.issue_id }} != ""
uses: dolthub/csv-to-md-table-action@v4
id: md
with:
csvinput: ${{ steps.csv.outputs.content }}
- uses: mshick/add-pr-comment@v2
if: ${{ github.event.client_payload.issue_id }} != ""
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
issue: ${{ github.event.client_payload.issue_id }}
message-failure: merge benchmark failed
message-cancelled: merge benchmark cancelled
allow-repeats: true
message: |
@${{ github.event.client_payload.actor }} __DOLT__
${{ steps.md.outputs.markdown-table }}
@@ -0,0 +1,65 @@
name: Nightly Benchmarks
on:
workflow_dispatch:
schedule:
- cron: '0 2 * * *'
jobs:
perf:
runs-on: ubuntu-22.04
name: Trigger Benchmark Latency, Benchmark Import, and SQL Correctness K8s Workflows
steps:
- uses: peter-evans/repository-dispatch@v3
with:
token: ${{ secrets.REPO_ACCESS_TOKEN }}
event-type: benchmark-latency
client-payload: '{"from_server": "mysql", "from_version": "8.0.35", "to_server": "dolt", "to_version": "${{ github.sha }}", "mode": "nightly", "actor": "${{ github.actor }}", "template_script": "./.github/scripts/performance-benchmarking/get-mysql-dolt-job-json.sh"}'
- uses: peter-evans/repository-dispatch@v3
with:
token: ${{ secrets.REPO_ACCESS_TOKEN }}
event-type: sql-correctness
client-payload: '{"version": "${{ github.sha }}", "mode": "nightly", "actor": "${{ github.actor }}", "template_script": "./.github/scripts/sql-correctness/get-dolt-correctness-job-json.sh"}'
- uses: peter-evans/repository-dispatch@v3
with:
token: ${{ secrets.REPO_ACCESS_TOKEN }}
event-type: benchmark-import
client-payload: |
{
"email_recipient": "${{ secrets.PERF_REPORTS_EMAIL_ADDRESS }}",
"version": "${{ github.sha }}",
"run_file": "ci.yaml",
"summary": "summary.sql",
"report": "three_way_compare.sql",
"commit_to_branch": "nightly",
"actor": "${{ github.actor }}"
}
- uses: peter-evans/repository-dispatch@v3
with:
token: ${{ secrets.REPO_ACCESS_TOKEN }}
event-type: test-orm-integrations
- uses: peter-evans/repository-dispatch@v3
with:
token: ${{ secrets.REPO_ACCESS_TOKEN }}
event-type: benchmark-systab
client-payload: |
{
"email_recipient": "${{ secrets.PERF_REPORTS_EMAIL_ADDRESS }}",
"version": "${{ github.sha }}",
"run_file": "systab.yaml",
"report": "systab.sql",
"summary": "systab_summary.sql",
"commit_to_branch": "nightly",
"actor": "${{ github.actor }}"
}
- uses: peter-evans/repository-dispatch@v3
with:
token: ${{ secrets.REPO_ACCESS_TOKEN }}
event-type: benchmark-merge
client-payload: |
{
"email_recipient": "${{ secrets.PERF_REPORTS_EMAIL_ADDRESS }}",
"version": "${{ github.sha }}",
"commit_to_branch": "nightly",
"actor": "${{ github.actor }}"
}
@@ -0,0 +1,81 @@
name: Benchmark Dolt vs MySQL
on:
repository_dispatch:
types: [ release-dolt ]
workflow_dispatch:
inputs:
version:
description: 'SemVer format release tag, i.e. 0.24.5'
required: true
default: ''
email:
description: 'Email address to receive results'
required: true
default: ''
jobs:
set-version-actor:
name: Set Version and Actor
runs-on: ubuntu-22.04
outputs:
version: ${{ steps.set-vars.outputs.version }}
actor: ${{ steps.set-vars.outputs.actor }}
actor_email: ${{ steps.set-vars.outputs.actor_email }}
steps:
- name: Set variables
id: set-vars
run: |
echo "version=$VERSION" >> $GITHUB_OUTPUT
echo "actor=$ACTOR" >> $GITHUB_OUTPUT
echo "actor_email=$ACTOR_EMAIL" >> $GITHUB_OUTPUT
env:
VERSION: ${{ github.event.inputs.version || github.event.client_payload.version }}
ACTOR: ${{ github.event.client_payload.actor || github.actor }}
ACTOR_EMAIL: ${{ github.event.inputs.email }}
benchmark-dolt-mysql:
runs-on: ubuntu-22.04
needs: set-version-actor
name: Trigger Benchmark Latency and Benchmark Import K8s Workflows
steps:
- uses: peter-evans/repository-dispatch@v3
if: ${{ github.event.client_payload.profile_key == '' }}
with:
token: ${{ secrets.REPO_ACCESS_TOKEN }}
event-type: benchmark-latency
client-payload: '{"from_server": "mysql", "from_version": "8.0.35", "to_server": "dolt", "to_version": "${{ needs.set-version-actor.outputs.version }}", "mode": "release", "actor": "${{ needs.set-version-actor.outputs.actor }}", "actor_email": "${{ needs.set-version-actor.outputs.actor_email }}", "template_script": "./.github/scripts/performance-benchmarking/get-mysql-dolt-job-json.sh"}'
- uses: peter-evans/repository-dispatch@v3
if: ${{ github.event.client_payload.profile_key != '' }}
with:
token: ${{ secrets.REPO_ACCESS_TOKEN }}
event-type: benchmark-latency
client-payload: '{"from_server": "mysql", "from_version": "8.0.35", "to_server": "dolt", "to_version": "${{ needs.set-version-actor.outputs.version }}", "profile_key": "${{ github.event.client_payload.profile_key }}", "mode": "release", "actor": "${{ needs.set-version-actor.outputs.actor }}", "actor_email": "${{ needs.set-version-actor.outputs.actor_email }}", "template_script": "./.github/scripts/performance-benchmarking/get-mysql-dolt-job-json.sh"}'
- uses: peter-evans/repository-dispatch@v3
with:
token: ${{ secrets.REPO_ACCESS_TOKEN }}
event-type: benchmark-import
client-payload: |
{
"email_recipient": "${{ needs.set-version-actor.outputs.actor_email }}",
"version": "${{ github.sha }}",
"run_file": "ci.yaml",
"report": "three_way_compare.sql",
"summary": "summary.sql",
"commit_to_branch": "main",
"actor": "${{ github.actor }}"
}
- uses: peter-evans/repository-dispatch@v3
with:
token: ${{ secrets.REPO_ACCESS_TOKEN }}
event-type: benchmark-systab
client-payload: |
{
"email_recipient": "${{ needs.set-version-actor.outputs.actor_email }}",
"version": "${{ github.sha }}",
"run_file": "systab.yaml",
"report": "systab.sql",
"summary": "systab_summary.sql",
"commit_to_branch": "main",
"actor": "${{ github.actor }}"
}
@@ -0,0 +1,79 @@
name: Benchmark Pull Requests
on:
pull_request:
types: [ opened ]
issue_comment:
types: [ created ]
jobs:
validate-commentor:
runs-on: ubuntu-22.04
outputs:
valid: ${{ steps.set_valid.outputs.valid }}
steps:
- uses: actions/checkout@v6
- name: Validate Commentor
id: set_valid
run: ./.github/scripts/performance-benchmarking/validate-commentor.sh "$ACTOR"
env:
ACTOR: ${{ github.actor }}
check-comments:
runs-on: ubuntu-22.04
needs: validate-commentor
if: ${{ needs.validate-commentor.outputs.valid == 'true' }}
outputs:
benchmark: ${{ steps.set_benchmark.outputs.benchmark }}
sysbench-test-time: ${{ steps.set_benchmark_mini.outputs.sysbench-test-time }}
comment-body: ${{ steps.set_body.outputs.body }}
steps:
- name: Check for Deploy Trigger
uses: dolthub/pull-request-comment-trigger@v2
id: check
with:
trigger: '#benchmark'
reaction: rocket
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Set Benchmark
if: ${{ steps.check.outputs.triggered == 'true' }}
id: set_benchmark
run: |
echo "benchmark=true" >> $GITHUB_OUTPUT
- name: Check for Deploy Mini Trigger
uses: dolthub/pull-request-comment-trigger@v2
id: check_mini
with:
trigger: '#benchmark-mini'
reaction: rocket
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Set Benchmark Mini
if: ${{ steps.check_mini.outputs.triggered == 'true' }}
id: set_benchmark_mini
run: |
echo "benchmark=true" >> $GITHUB_OUTPUT
echo "sysbench-test-time=20" >> $GITHUB_OUTPUT
performance:
runs-on: ubuntu-22.04
needs: [validate-commentor, check-comments]
if: ${{ needs.check-comments.outputs.benchmark == 'true' }}
name: Trigger Benchmark Latency K8s Workflow
steps:
- uses: dolthub/pull-request-comment-branch@v3
id: comment-branch
with:
repo_token: ${{ secrets.GITHUB_TOKEN }}
- name: Get pull number
uses: actions/github-script@v7
id: get_pull_number
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: core.setOutput("pull_number", JSON.stringify(context.issue.number));
- uses: peter-evans/repository-dispatch@v3
with:
token: ${{ secrets.REPO_ACCESS_TOKEN }}
event-type: benchmark-latency
client-payload: '{"from_server": "dolt", "from_version": "${{ github.sha }}", "to_server": "dolt", "to_version": "${{ steps.comment-branch.outputs.head_sha }}", "mode": "pullRequest", "issue_number": "${{ steps.get_pull_number.outputs.pull_number }}", "init_big_repo": "true", "actor": "${{ github.actor }}", "sysbench_test_time": "${{ needs.check-comments.outputs.sysbench-test-time }}", "template_script": "./.github/scripts/performance-benchmarking/get-dolt-dolt-job-json.sh"}'
+293
View File
@@ -0,0 +1,293 @@
name: Post to Pull Request
on:
repository_dispatch:
types: [ pull-report ]
jobs:
report-pull-request:
name: Report Performance Benchmarks/Correctness on Pull Request
runs-on: ubuntu-22.04
if: ${{ github.event.client_payload.issue_number != -1 }}
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Configure AWS Credentials
uses: aws-actions/configure-aws-credentials@v4
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: us-west-2
- name: Print Correctness Info
run: |
echo "correctness info: is_regression: $IS_REGRESSION"
echo "correctness info: correctness_percentage: $CORRECTNESS_PERCENTAGE"
echo "correctness info: branch_ref: $BRANCH_REF"
echo "job_type: $JOB_TYPE"
env:
IS_REGRESSION: ${{ github.event.client_payload.correctness_info.is_regression }}
CORRECTNESS_PERCENTAGE: ${{ github.event.client_payload.correctness_info.correctness_percentage }}
BRANCH_REF: ${{ github.event.client_payload.correctness_info.branch_ref }}
JOB_TYPE: ${{ github.event.client_payload.job_type }}
CORRECTNESS_REGRESSION: ${{ github.event.client_payload.correctness_info.is_regression == 'true' && github.event.client_payload.job_type == 'sql-correctness' }}
- name: Get benchmark/correctness results
id: get-results
run: aws s3api get-object --bucket="$BUCKET" --key="$KEY" results.log
env:
KEY: ${{ github.event.client_payload.key }}
BUCKET: ${{ github.event.client_payload.bucket }}
- name: Post results to PR
uses: actions/github-script@v7
with:
github-token: ${{ secrets.REPO_ACCESS_TOKEN || secrets.GITHUB_TOKEN }}
script: |
const { ACTOR, FORMAT, ISSUE_NUMBER, JOB_TYPE, GITHUB_WORKSPACE } = process.env;
const { owner, repo } = context.repo;
const issue_number = parseInt(ISSUE_NUMBER, 10);
const fs = require('fs').promises;
const resData = await fs.readFile(`${GITHUB_WORKSPACE}/results.log`, 'utf8');
// Consider also deleting stale sql-correctness comments
// Both correctness and performance are posted/deleted here, they may delete each other
if (JOB_TYPE == "performance-benchmarking") {
const commentMarker = '<!-- go-run-output -->';
// List comments on the PR
const { data: comments } = await github.rest.issues.listComments({
issue_number: issue_number,
owner: context.repo.owner,
repo: context.repo.repo
});
// Find correct comment to update
let comment = null;
if (resData.includes("tpcc-scale-factor-1")) {
comment = comments.find(comment => comment.body.includes(commentMarker) && comment.body.includes("tpcc-scale-factor-1"))
} else if (resData.includes("read_tests")) {
comment = comments.find(comment => comment.body.includes(commentMarker) && comment.body.includes("read_tests"))
}
if (comment) {
// Update the existing comment
await github.rest.issues.updateComment({
comment_id: comment.id,
owner: context.repo.owner,
repo: context.repo.repo,
body: `${commentMarker}\n@${ACTOR} ${FORMAT}\n${resData}`
})
} else {
// Create a new comment
await github.rest.issues.createComment({
issue_number: issue_number,
owner: context.repo.owner,
repo: context.repo.repo,
body: `${commentMarker}\n@${ACTOR} ${FORMAT}\n${resData}`
});
}
} else {
await github.rest.issues.createComment({
issue_number: issue_number,
owner: context.repo.owner,
repo: context.repo.repo,
body: `@${ACTOR} ${FORMAT}\n${resData}`
});
}
env:
ACTOR: ${{ github.event.client_payload.actor }}
FORMAT: ${{ github.event.client_payload.noms_bin_format }}
ISSUE_NUMBER: ${{ github.event.client_payload.issue_number }}
JOB_TYPE: ${{ github.event.client_payload.job_type }}
- name: Remove Passing Labels if regression detected
if: ${{ github.event.client_payload.correctness_info.is_regression == true && github.event.client_payload.job_type == 'sql-correctness' }}
uses: actions/github-script@v7
with:
github-token: ${{ secrets.REPO_ACCESS_TOKEN || secrets.GITHUB_TOKEN }}
script: |
const { ACTOR, ISSUE_NUMBER, LABEL, GITHUB_WORKSPACE } = process.env;
const issue_number = parseInt(ISSUE_NUMBER, 10);
const { owner, repo } = context.repo;
try {
const res = await github.rest.issues.listLabelsOnIssue({
issue_number,
owner,
repo,
});
if (res.data) {
const labels = res.data;
for (const label of labels) {
if (label.name === LABEL) {
await github.rest.issues.removeLabel({
issue_number,
owner,
repo,
name: label.name,
});
}
}
}
} catch(e) {
console.error(e)
}
env:
ACTOR: ${{ github.event.client_payload.actor }}
ISSUE_NUMBER: ${{ github.event.client_payload.issue_number }}
LABEL: 'correctness_approved'
- name: Add Passing Labels if no regression detected
if: ${{ github.event.client_payload.correctness_info.is_regression != true && github.event.client_payload.job_type == 'sql-correctness' }}
uses: actions/github-script@v7
with:
github-token: ${{ secrets.REPO_ACCESS_TOKEN || secrets.GITHUB_TOKEN }}
script: |
const { ACTOR, ISSUE_NUMBER, LABEL, GITHUB_WORKSPACE } = process.env;
const issue_number = parseInt(ISSUE_NUMBER, 10);
const { owner, repo } = context.repo;
try {
const res = await github.rest.issues.listLabelsOnIssue({
issue_number,
owner,
repo,
});
if (res.data) {
const labels = res.data;
for (const label of labels) {
if (label.name === LABEL) {
return;
}
}
await github.rest.issues.addLabels({
issue_number,
owner,
repo,
labels: [LABEL],
});
}
} catch(e) {
console.error(e)
}
env:
ACTOR: ${{ github.event.client_payload.actor }}
ISSUE_NUMBER: ${{ github.event.client_payload.issue_number }}
LABEL: 'correctness_approved'
- name: Remove Passing Performance Labels if performance regression detected
if: ${{ github.event.client_payload.is_performance_regression == true && github.event.client_payload.job_type == 'performance-benchmarking' }}
uses: actions/github-script@v7
with:
github-token: ${{ secrets.REPO_ACCESS_TOKEN || secrets.GITHUB_TOKEN }}
script: |
const { ACTOR, ISSUE_NUMBER, LABEL, GITHUB_WORKSPACE } = process.env;
const issue_number = parseInt(ISSUE_NUMBER, 10);
const { owner, repo } = context.repo;
try {
const res = await github.rest.issues.listLabelsOnIssue({
issue_number,
owner,
repo,
});
if (res.data) {
const labels = res.data;
for (const label of labels) {
if (label.name === LABEL) {
await github.rest.issues.removeLabel({
issue_number,
owner,
repo,
name: label.name,
});
}
}
}
} catch(e) {
console.error(e)
}
env:
ACTOR: ${{ github.event.client_payload.actor }}
ISSUE_NUMBER: ${{ github.event.client_payload.issue_number }}
LABEL: 'performance_approved'
- name: Add Passing Performance Labels if no regression detected
if: ${{ github.event.client_payload.is_performance_regression != true && github.event.client_payload.job_type == 'performance-benchmarking' }}
uses: actions/github-script@v7
with:
github-token: ${{ secrets.REPO_ACCESS_TOKEN || secrets.GITHUB_TOKEN }}
script: |
const { ACTOR, ISSUE_NUMBER, LABEL, GITHUB_WORKSPACE } = process.env;
const issue_number = parseInt(ISSUE_NUMBER, 10);
const { owner, repo } = context.repo;
try {
const res = await github.rest.issues.listLabelsOnIssue({
issue_number,
owner,
repo,
});
if (res.data) {
const labels = res.data;
for (const label of labels) {
if (label.name === LABEL) {
return;
}
}
await github.rest.issues.addLabels({
issue_number,
owner,
repo,
labels: [LABEL],
});
}
} catch(e) {
console.error(e)
}
env:
ACTOR: ${{ github.event.client_payload.actor }}
ISSUE_NUMBER: ${{ github.event.client_payload.issue_number }}
LABEL: 'performance_approved'
update-correctness-file:
name: Update Correctness File
needs: report-pull-request
runs-on: ubuntu-22.04
if: ${{ github.event.client_payload.correctness_info.is_regression != 'true' && github.event.client_payload.job_type == 'sql-correctness' }}
steps:
- name: Checkout
uses: actions/checkout@v6
with:
ref: ${{ github.event.client_payload.correctness_info.branch_ref }}
repository: ${{ github.repository }}
token: ${{ secrets.REPO_ACCESS_TOKEN || secrets.GITHUB_TOKEN }}
- name: Write new correctness file
working-directory: ./.github/scripts/sql-correctness
env:
CORRECTNESS_PERCENTAGE: ${{ github.event.client_payload.correctness_info.correctness_percentage }}
run: |
if [ -z "$CORRECTNESS_PERCENTAGE" ]; then
echo "correctness percentage was empty, something went wrong"
exit 1
fi
echo "$CORRECTNESS_PERCENTAGE" > current_correctness.txt
- name: Changes detected
id: detect-changes
run: |
changes=$(git status --porcelain)
if [ ! -z "$changes" ]; then
echo "has-changes=true" >> $GITHUB_OUTPUT
fi
- uses: EndBug/add-and-commit@v9.1.4
if: ${{ steps.detect-changes.outputs.has-changes == 'true' }}
with:
message: ${{ format('[skip actions] [ga-update-correctness] SQL Correctness updated to {0}', github.event.client_payload.correctness_info.correctness_percentage) }}
add: "./current_correctness.txt"
cwd: "./.github/scripts/sql-correctness"
pull: "--ff"
+43
View File
@@ -0,0 +1,43 @@
name: Benchmark SQL Correctness
on:
repository_dispatch:
types: [ release-dolt ]
workflow_dispatch:
inputs:
version:
description: 'SemVer format release tag, i.e. 0.24.5'
required: true
default: ''
email:
description: 'Email address to receive results'
required: true
default: ''
jobs:
set-version-actor:
name: Set Version and Actor
runs-on: ubuntu-22.04
outputs:
version: ${{ steps.set-vars.outputs.version }}
actor: ${{ steps.set-vars.outputs.actor }}
steps:
- name: Set variables
id: set-vars
run: |
echo "version=$VERSION" >> $GITHUB_OUTPUT
echo "actor=$ACTOR" >> $GITHUB_OUTPUT
env:
VERSION: ${{ github.event.inputs.version || github.event.client_payload.version }}
ACTOR: ${{ github.event.client_payload.actor || github.actor }}
correctness:
runs-on: ubuntu-22.04
needs: set-version-actor
name: Trigger SQL Correctness K8s Workflow
steps:
- uses: peter-evans/repository-dispatch@v3
with:
token: ${{ secrets.REPO_ACCESS_TOKEN }}
event-type: sql-correctness
client-payload: '{"version": "${{ needs.set-version-actor.outputs.version }}", "mode": "release", "actor": "${{ needs.set-version-actor.outputs.actor }}", "actor_email": "${{ needs.set-version-actor.outputs.actor_email }}", "template_script": "./.github/scripts/sql-correctness/get-dolt-correctness-job-json.sh"}'
+57
View File
@@ -0,0 +1,57 @@
name: Benchmark SQL Correctness on PR
on:
pull_request:
paths:
- 'go/**'
branches: [ main ]
jobs:
set-version-actor:
if: github.actor != 'dependabot[bot]'
name: Set Version and Actor
runs-on: ubuntu-22.04
outputs:
regress_comp: ${{ steps.regress-comp.outputs.regress_comp }}
version: ${{ steps.set-vars.outputs.version }}
actor: ${{ steps.set-vars.outputs.actor }}
steps:
- name: Checkout BASE REF
uses: actions/checkout@v6
with:
ref: ${{ github.base_ref }}
- name: Get Current Correctness
id: regress-comp
working-directory: ./.github/scripts/sql-correctness
run: |
out=$(cat current_correctness.txt)
echo "regress_comp=$out" >> $GITHUB_OUTPUT
- name: Checkout PR HEAD REF
uses: actions/checkout@v6
with:
ref: ${{ github.head_ref }}
- name: Set variables
id: set-vars
run: |
echo "actor=$ACTOR" >> $GITHUB_OUTPUT
sha=$(git rev-parse --short HEAD)
echo "version=$sha" >> $GITHUB_OUTPUT
env:
ACTOR: ${{ github.event.client_payload.actor || github.actor }}
correctness:
runs-on: ubuntu-22.04
needs: set-version-actor
name: Trigger SQL Correctness K8s Workflow
steps:
- name: Get pull number
uses: actions/github-script@v7
id: get_pull_number
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: core.setOutput("pull_number", JSON.stringify(context.issue.number));
- uses: peter-evans/repository-dispatch@v3
with:
token: ${{ secrets.REPO_ACCESS_TOKEN }}
event-type: sql-correctness
client-payload: '{"issue_number": "${{ steps.get_pull_number.outputs.pull_number }}", "branch_ref": "${{ github.head_ref }}", "regress_comp": "${{ needs.set-version-actor.outputs.regress_comp }}", "version": "${{ needs.set-version-actor.outputs.version }}", "mode": "release", "actor": "${{ needs.set-version-actor.outputs.actor }}", "actor_email": "${{ needs.set-version-actor.outputs.actor_email }}", "template_script": "./.github/scripts/sql-correctness/get-dolt-correctness-job-json.sh"}'
@@ -0,0 +1,73 @@
name: Run Systab Benchmark on Pull Requests
on:
pull_request:
types: [ opened ]
issue_comment:
types: [ created ]
jobs:
validate-commentor:
runs-on: ubuntu-22.04
outputs:
valid: ${{ steps.set_valid.outputs.valid }}
steps:
- uses: actions/checkout@v6
- name: Validate Commentor
id: set_valid
run: ./.github/scripts/performance-benchmarking/validate-commentor.sh "$ACTOR"
env:
ACTOR: ${{ github.actor }}
check-comments:
runs-on: ubuntu-22.04
needs: validate-commentor
if: ${{ needs.validate-commentor.outputs.valid == 'true' }}
outputs:
benchmark: ${{ steps.set_benchmark.outputs.benchmark }}
comment-body: ${{ steps.set_body.outputs.body }}
steps:
- name: Check for Deploy Trigger
uses: dolthub/pull-request-comment-trigger@v2
id: check
with:
trigger: '#systab-benchmark'
reaction: rocket
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Set Benchmark
if: ${{ steps.check.outputs.triggered == 'true' }}
id: set_benchmark
run: |
echo "benchmark=true" >> $GITHUB_OUTPUT
performance:
runs-on: ubuntu-22.04
needs: [validate-commentor, check-comments]
if: ${{ needs.check-comments.outputs.benchmark == 'true' }}
name: Trigger Benchmark Systab Workflow
steps:
- uses: dolthub/pull-request-comment-branch@v3
id: comment-branch
with:
repo_token: ${{ secrets.GITHUB_TOKEN }}
- name: Get pull number
uses: actions/github-script@v7
id: get_pull_number
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: core.setOutput("pull_number", JSON.stringify(context.issue.number));
- uses: peter-evans/repository-dispatch@v3
with:
token: ${{ secrets.REPO_ACCESS_TOKEN }}
event-type: benchmark-systab
client-payload: |
{
"version": "${{ steps.comment-branch.outputs.head_sha }}",
"run_file": "systab.yaml",
"report": "systab.sql",
"summary": "systab_summary.sql",
"commit_to_branch": "${{ steps.comment-branch.outputs.head_sha }}",
"actor": "${{ github.actor }}",
"issue_id": "${{ steps.get_pull_number.outputs.pull_number }}"
}
+178
View File
@@ -0,0 +1,178 @@
name: Systab Benchmarks
on:
repository_dispatch:
types: [ benchmark-systab ]
env:
BENCH_DIR: 'go/performance/sysbench'
RESULT_TABLE_NAME: 'sysbench_results'
DOLTHUB_DB: 'import-perf/systab-perf'
jobs:
bench:
name: Benchmark
defaults:
run:
shell: bash
strategy:
fail-fast: true
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
with:
ref: ${{ github.event.client_payload.version }}
- name: Set up Go 1.x
id: go
uses: actions/setup-go@v5
with:
go-version-file: go/go.mod
- name: Dolt version
id: version
run: |
version=${{ github.event.client_payload.version }}
- name: install sysbench
run: |
curl -s https://packagecloud.io/install/repositories/akopytov/sysbench/script.deb.sh | sudo bash
sudo apt -y install sysbench
- name: Install dolt
working-directory: ./go
run: go install ./cmd/dolt
- name: Clone sysbench scripts
run: |
scripts=$GITHUB_WORKSPACE/scripts
git clone https://github.com/dolthub/systab-sysbench-scripts.git "$scripts"
- name: Run bench
id: bench
working-directory: go/
run: |
out="$GITHUB_WORKSPACE/results.sql"
testspec="../${{ env.BENCH_DIR }}/testdata/${{ github.event.client_payload.run_file }}"
config="../${{ env.BENCH_DIR }}/testdata/default-config.yaml"
scripts="$GITHUB_WORKSPACE/scripts"
go run \
"github.com/dolthub/dolt/${{ env.BENCH_DIR }}/cmd" \
-run "$testspec" \
-config "$config" \
-script-dir "$scripts" \
-out "$out"
echo "result_path=$out" >> $GITHUB_OUTPUT
- name: Report
id: report
run: |
gw=$GITHUB_WORKSPACE
in="${{ steps.bench.outputs.result_path }}"
query="$(pwd)/${{ env.BENCH_DIR }}/reporting/${{ github.event.client_payload.report }}"
summaryq="$(pwd)/${{ env.BENCH_DIR }}/reporting/${{ github.event.client_payload.summary }}"
out="$gw/results.csv"
dolt_dir="$gw/systab-perf"
dolt config --global --add user.email "systab-perf@dolthub.com"
dolt config --global --add user.name "systab-perf"
echo '${{ secrets.DOLTHUB_IMPORT_PERF_CREDS_VALUE }}' | dolt creds import
dolt clone ${{ env.DOLTHUB_DB }} "$dolt_dir"
cd "$dolt_dir"
branch="${{ github.event.client_payload.commit_to_branch }}"
# checkout branch
if [ -z $(dolt sql -q "select 1 from dolt_branches where name = '$branch';") ]; then
dolt checkout -b $branch
else
dolt checkout $branch
fi
dolt sql -q "drop table if exists sysbench_results"
# load results
dolt sql < "$in"
# push results to dolthub
dolt add sysbench_results
dolt commit -m "CI commit"
dolt push -f origin $branch
# generate report
dolt sql -r csv < "$query" > "$out"
cat "$out"
echo "report_path=$out" >> $GITHUB_OUTPUT
avg=$(dolt sql -r csv < "$summaryq" | tail -1)
echo "avg=$avg" >> $GITHUB_OUTPUT
- name: Format Results
id: html
if: ${{ github.event.client_payload.email_recipient }} != ""
run: |
gw="$GITHUB_WORKSPACE"
in="${{ steps.report.outputs.report_path }}"
out="$gw/results.html"
echo "<table>" > "$out"
print_header=true
while read line; do
if "$print_header"; then
echo " <tr><th>${line//,/</th><th>}</th></tr>" >> "$out"
print_header=false
continue
fi
echo " <tr><td>${line//,/</td><td>}</td></tr>" >> "$out"
done < "$in"
echo "</table>" >> "$out"
avg="${{ steps.report.outputs.avg }}"
echo "<table><tr><th>Average</th></tr><tr><td>$avg</tr></td></table>" >> "$out"
cat "$out"
echo "html=$(echo $out)" >> $GITHUB_OUTPUT
- name: Configure AWS Credentials
if: ${{ github.event.client_payload.email_recipient }} != ""
uses: aws-actions/configure-aws-credentials@v4
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: us-west-2
- name: Send Email
uses: ./.github/actions/ses-email-action
if: ${{ github.event.client_payload.email_recipient }} != ""
with:
region: us-west-2
toAddresses: '["${{ github.event.client_payload.email_recipient }}"]'
subject: 'System Table Performance Benchmarks: ${{ github.event.client_payload.version }}'
bodyPath: ${{ steps.html.outputs.html }}
template: 'SysbenchTemplate'
- name: Read CSV
if: ${{ github.event.client_payload.issue_id }} != ""
id: csv
uses: juliangruber/read-file-action@v1
with:
path: "${{ steps.report.outputs.report_path }}"
- name: Create MD
if: ${{ github.event.client_payload.issue_id }} != ""
uses: dolthub/csv-to-md-table-action@v4
id: md
with:
csvinput: ${{ steps.csv.outputs.content }}
- uses: mshick/add-pr-comment@v2
if: ${{ github.event.client_payload.issue_id }} != ""
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
issue: ${{ github.event.client_payload.issue_id }}
message-failure: systab benchmark failed
message-cancelled: systab benchmark cancelled
allow-repeats: true
message: |
@${{ github.event.client_payload.actor }} __DOLT__
${{ steps.md.outputs.markdown-table }}
@@ -0,0 +1,53 @@
name: Benchmark Mini Sysbench Performance on PR
on:
pull_request:
paths:
- 'go/**'
branches: [ main ]
jobs:
performance:
name: Trigger Mini Benchmark Latency K8s Workflow
if: github.actor != 'dependabot[bot]'
runs-on: ubuntu-22.04
steps:
- name: Build benchmark payload (main HEAD + PR HEAD)
uses: actions/github-script@v7
id: build_payload
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
// For PR benchmarks, use the PR base commit (the exact target commit this PR was opened/updated against),
// not the moving HEAD of `main`.
const fromSha = context.payload.pull_request.base.sha;
// The latest commit on the PR branch.
const toSha = context.payload.pull_request.head.sha;
const payload = {
from_server: "dolt",
from_version: fromSha,
to_server: "dolt",
to_version: toSha,
mode: "pullRequest",
issue_number: String(context.issue.number),
init_big_repo: "true",
actor: context.actor,
sysbench_test_time: "20",
template_script: "./.github/scripts/performance-benchmarking/get-dolt-dolt-job-json.sh",
};
core.setOutput("from_sha", fromSha);
core.setOutput("to_sha", toSha);
core.setOutput("payload", JSON.stringify(payload));
- name: Log benchmark versions
shell: bash
run: |
echo "from_version_sha=${{ steps.build_payload.outputs.from_sha }}"
echo "to_version_sha=${{ steps.build_payload.outputs.to_sha }}"
- uses: peter-evans/repository-dispatch@v3
with:
token: ${{ secrets.REPO_ACCESS_TOKEN }}
event-type: benchmark-latency
client-payload: ${{ steps.build_payload.outputs.payload }}
+32
View File
@@ -0,0 +1,32 @@
**/.idea/
**/.dolt/
.vscode
.run
venv
.DS_Store
.sqlhistory
.doltcfg
test.sh
*eventsapi@*
# ignore cp'd sysbench runner testing files
SysbenchDockerfile
SysbenchDockerfile.dockerignore
sysbench-runner-tests-entrypoint.sh
config.json
integration-tests/bats/batsee_results
# ignore CLAUDE.md for now
CLAUDE.md
*~
.dir-locals.el
.beads
.gitattributes
.de/
.cursor
AGENTS.md
.claude/
.cursorrules
+4
View File
@@ -0,0 +1,4 @@
[submodule "integration-tests/mysql-client-tests/cpp/third_party/mysql-connector-cpp"]
path = integration-tests/mysql-client-tests/cpp/third_party/mysql-connector-cpp
url = https://github.com/mysql/mysql-connector-cpp.git
ignore = dirty
+23
View File
@@ -0,0 +1,23 @@
# Lines starting with '#' are comments.
# Each line is a file pattern followed by one or more owners.
# These owners will be the default owners for everything in the repo.
# * @defunkt
# Order is important. The last matching pattern has the most precedence.
# So if a pull request only touches javascript files, only these owners
# will be requested to review.
# *.js @octocat @github/js
# You can also use email addresses if you prefer.
# docs/* docs@example.com
# Begin dolt repository owners
integration-tests/mysql-client-tests/node/* @tbantle22
+202
View File
@@ -0,0 +1,202 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
+849
View File
@@ -0,0 +1,849 @@
<img height="100" src="./images/Dolt-Logo@3x.svg"/>
# Dolt is Git for Data!
Dolt is a SQL database that you can fork, clone, branch, merge, push
and pull just like a Git repository.
Connect to Dolt just like any MySQL database to read or modify schema
and data. Version control functionality is exposed in SQL via system
tables, functions, and procedures.
Or, use the Git-like command line interface to import CSV files, commit
your changes, push them to a remote, or merge your teammate's changes.
All the commands you know for Git work exactly the same for Dolt.
Git versions files. Dolt versions tables. It's like Git and MySQL had a
baby.
We also built [DoltHub](https://www.dolthub.com), a place to share
Dolt databases. We host public data for free. If you want to host
your own version of DoltHub, we have [DoltLab](https://www.doltlab.com).
If you want us to run a Dolt server for you, we have [Hosted Dolt](https://hosted.doltdb.com).
Prefer Postgres instead of MySQL? Try [Doltgres](https://github.com/dolthub/doltgresql), now
in its Beta release.
[Join us on Discord](https://discord.com/invite/RFwfYpu) to say hi and
ask questions, or [check out our roadmap](https://dolthub.com/docs/other/roadmap)
to see what we're building next.
# Video Introduction
[![Dolt Explainer Video](https://img.youtube.com/vi/H2iZy0Cme10/maxresdefault.jpg)](https://www.youtube.com/watch?v=H2iZy0Cme10)
# What's it for?
Lots of things! Dolt is a generally useful tool with countless
applications. But if you want some ideas, [here's how people are using
it so far](https://dolthub.com/blog/2024-10-15-dolt-use-cases/).
Dolt powers [Beads](https://github.com/gastownhall/beads) and
[Gas Town](https://github.com/steveyegge/gastown). It's the best database
for agent memory, especially as you move up the ladder to multi-agent and
multi-machine workflows.
# Dolt CLI
The `dolt` CLI has the same commands as `git`, with some extras.
```
$ dolt
Valid commands for dolt are
init - Create an empty Dolt data repository.
status - Show the working tree status.
add - Add table changes to the list of staged table changes.
diff - Diff a table.
reset - Remove table changes from the list of staged table changes.
clean - Remove untracked tables from working set.
commit - Record changes to the repository.
sql - Run a SQL query against tables in repository.
sql-server - Start a MySQL-compatible server.
log - Show commit logs.
branch - Create, list, edit, delete branches.
checkout - Checkout a branch or overwrite a table from HEAD.
merge - Merge a branch.
conflicts - Commands for viewing and resolving merge conflicts.
cherry-pick - Apply the changes introduced by an existing commit.
revert - Undo the changes introduced in a commit.
clone - Clone from a remote data repository.
fetch - Update the database from a remote data repository.
pull - Fetch from a dolt remote data repository and merge.
push - Push to a dolt remote.
config - Dolt configuration.
remote - Manage set of tracked repositories.
backup - Manage a set of server backups.
login - Login to a dolt remote host.
creds - Commands for managing credentials.
ls - List tables in the working set.
schema - Commands for showing and importing table schemas.
table - Commands for copying, renaming, deleting, and exporting tables.
tag - Create, list, delete tags.
blame - Show what revision and author last modified each row of a table.
constraints - Commands for handling constraints.
migrate - Executes a database migration to use the latest Dolt data format.
read-tables - Fetch table(s) at a specific commit into a new dolt repo
gc - Cleans up unreferenced data from the repository.
filter-branch - Edits the commit history using the provided query.
merge-base - Find the common ancestor of two commits.
version - Displays the current Dolt cli version.
dump - Export all tables in the working set into a file.
```
# Installation
Dolt is a single ~103 megabyte program.
```bash
dolt $ du -h /Users/timsehn/go/bin/dolt
103M /Users/timsehn/go/bin/dolt
```
It's really easy to install. Download it and put it on your `PATH`.
We have a bunch of ways to make this even easier for most platforms.
## From Latest Release
To install on Linux or Mac based systems run this command in your
terminal:
```
sudo bash -c 'curl -L https://github.com/dolthub/dolt/releases/latest/download/install.sh | bash'
```
This will download the latest `dolt` release and put it in
`/usr/local/bin/`, which is probably on your `$PATH`.
The install script needs sudo in order to put `dolt` in `/usr/local/bin`. If you don't have root
privileges or aren't comfortable running a script with them, you can download the dolt binary
for your platform from [the latest release](https://github.com/dolthub/dolt/releases), unzip it,
and put the binary somewhere on your `$PATH`.
### Linux
#### Arch Linux
Dolt is packaged in the official repositories for Arch Linux.
```
pacman -S dolt
```
### Mac
#### Homebrew
Dolt is on Homebrew, updated every release.
```
brew install dolt
```
#### MacPorts
On macOS, Dolt can also be installed via a [community-managed port](https://ports.macports.org/port/dolt/) via [MacPorts](https://www.macports.org):
```sh
sudo port install dolt
```
### Windows
Download the latest Microsoft Installer (`.msi` file) in
[releases](https://github.com/dolthub/dolt/releases) and run
it.
For information on running on Windows, see [here](https://dolthub.com/docs/introduction/installation/windows).
#### Chocolatey
You can install `dolt` using [Chocolatey](https://chocolatey.org/):
```sh
choco install dolt
```
#### Docker
There are following official Docker images for Dolt:
* [`dolthub/dolt`](https://hub.docker.com/r/dolthub/dolt) for running Dolt
as CLI tool.
* [`dolthub/dolt-sql-server`](https://hub.docker.com/r/dolthub/dolt-sql-server) for running Dolt in server mode.
## From Source
Make sure you have Go installed, and that `go` is in your path. Dolt has a dependency on [cgo](https://pkg.go.dev/cmd/cgo), so you will need a working C compiler and toolchain as well.
Clone this repository and cd into the `go` directory. Then run:
```
go install ./cmd/dolt
```
The output will be in `$GOPATH/bin`, which defaults to `~/go/bin`. To test your build, try:
```
~/go/bin/dolt version
```
# Configuration
Verify that your installation has succeeded by running `dolt` in your
terminal.
```
$ dolt
Valid commands for dolt are
[...]
```
Configure `dolt` with your user name and email, which you'll need to
create commits. The commands work exactly the same as git.
```
$ dolt config --global --add user.email YOU@DOMAIN.COM
$ dolt config --global --add user.name "YOUR NAME"
```
# Getting started
## Navigate to the directory where you would like your data stored
Dolt needs a place to store your databases. I'm going to put my databases in `~/dolt`.
```bash
% cd ~
% mkdir dolt
% cd dolt
```
Any databases you create will be stored in this directory. So, for this example, a directory named `getting_started` will be created here once you run `create database getting_started`. Navigating to `~/dolt/getting_started` will allow you to access this database using the Dolt command line.
NOTE: For this example, the `getting_started` directory will be created after you run `create database getting_started;` in a SQL shell in the [Create a schema section](#create-a-schema). Don't do anything except make the directory and navigate to it just yet.
## Start a MySQL-compatible database server
Dolt ships with a MySQL compatible database server built in. To start it you use the command `dolt sql-server`. Running this command starts the server on port 3306.
```bash
dolt sql-server
Starting server with Config HP="localhost:3306"|T="28800000"|R="false"|L="info"
```
Your terminal will just hang there. This means the server is running. Any errors will be printed in this terminal. Just leave it there and open a new terminal.
## Connect with a MySQL client (up to version 8.4)
In the new terminal, we will now connect to the running database server using a client. Dolt also ships with a MySQL compatible client.
```bash
% dolt -u root -p "" sql
# Welcome to the Dolt MySQL client.
# Statements must be terminated with ';'.
# "exit" or "quit" (or Ctrl-D) to exit.
mysql>
```
In the other terminal where you ran `dolt sql-server`, you'll see the following log line.
```
2022-06-06T13:14:32-07:00 INFO [conn 1] NewConnection {DisableClientMultiStatements=false}
```
You are connected!
While we're here let's grab a copy of MySQL so we can connect with that client. Head over to the [MySQL Getting Started](https://dev.mysql.com/doc/mysql-getting-started/en/) documentation and install MySQL on your machine. I used [Homebrew](https://brew.sh/) to install MySQL on my Mac: `brew install mysql@8.4`. Alternatively, you can install only the client component by running `brew install mysql-client@8.4`.
NOTE: Make sure you install a MySQL 8.4 release. MySQL 8.4 is the current Long Term Support (LTS) release, meaning this is the stable and supported version of MySQL. MySQL 9.0 is also available, but is an "innovation" release, meaning it has more recent changes and features, but may not be as stable as the LTS release. The 9.0 release changes authentication support and isn't able to connect to a Dolt SQL server by default. You can install MySQL 8.4 with Homebrew by running `brew install mysql@8.4`. If you do want to use MySQL-9.0, read [our post on how to configure Dolt for `caching_sha2_password` authentication](https://www.dolthub.com/blog/2024-12-11-mysql9-and-caching-sha2-auth-support/).
MySQL comes with a MySQL server called `mysqld` and a MySQL client called `mysql`. You're only interested in the client. After following the instructions from MySQL's documentation, make sure you have a copy of the `mysql` client on your path:
```bash
% mysql --version
mysql Ver 8.0.29 for macos12.2 on x86_64 (Homebrew)
```
Now, to connect the `mysql` client to Dolt, you are going to force the MySQL client through the TCP interface by passing in a host and port. The default is the socket interface which Dolt supports, but is only available on `localhost`. So, it's better to show off the TCP interface. The MySQL client also requires you specify a user, in this case `root`.
```bash
% mysql --host 127.0.0.1 --port 3306 -uroot
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 2
Server version: 5.7.9-Vitess
Copyright (c) 2000, 2022, Oracle and/or its affiliates.
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
mysql>
```
Again, to ensure the client actually connected, you should see the following in the `dolt sql-server` terminal
```
2022-06-06T13:26:55-07:00 INFO [conn 2] NewConnection {DisableClientMultiStatements=false}
```
As you can see, Dolt supports any MySQL-compatible client. Dolt ships with a client but you can use any MySQL client, like the one that comes with MySQL.
## Create a schema
Now we're actually ready to do something interesting. I'll stay in the `mysql` client and execute the following SQL statements to create a database called `getting_started`. The `getting_started` database will have three tables: `employees`, `teams`, and `employees_teams`.
```
mysql> create database getting_started;
Query OK, 1 row affected (0.04 sec)
mysql> use getting_started;
Database changed
mysql> create table employees (
id int,
last_name varchar(255),
first_name varchar(255),
primary key(id));
Query OK, 0 rows affected (0.01 sec)
mysql> create table teams (
id int,
team_name varchar(255),
primary key(id));
Query OK, 0 rows affected (0.00 sec)
mysql> create table employees_teams(
team_id int,
employee_id int,
primary key(team_id, employee_id),
foreign key (team_id) references teams(id),
foreign key (employee_id) references employees(id));
Query OK, 0 rows affected (0.01 sec)
mysql> show tables;
+---------------------------+
| Tables_in_getting_started |
+---------------------------+
| employees |
| employees_teams |
| teams |
+---------------------------+
3 rows in set (0.00 sec)
```
Dolt supports foreign keys, secondary indexes, triggers, check constraints, and stored procedures. It's a modern, feature-rich SQL database.
## Make a Dolt commit
It's time to use your first Dolt feature. We're going to make a Dolt [commit](https://dolthub.com/docs/concepts/dolt/commits). A Dolt commit allows you to time travel and see lineage. Make a Dolt commit whenever you want to restore or compare to this point in time.
Dolt exposes version control functionality through a Git-style interface. On the command line, Dolt commands map exactly to their Git equivalent with the targets being tables instead of files. In SQL, Dolt exposes version control read operations as [system tables](https://dolthub.com/docs/sql-reference/version-control/dolt-system-tables) and version control write operations as [stored procedures](https://dolthub.com/docs/sql-reference/version-control/dolt-sql-procedures).
The naming of the system tables and stored procedures follows the `dolt_<command>` pattern. So `dolt add` on the CLI becomes `dolt_add` as a stored procedure. Passing options also follows the command line model. For instance, to specify tables to add, send the table names in as options to the `dolt_add` procedure. For named arguments like sending a message into the `dolt_commit` command use two arguments in sequence like `('-m', 'This is a message')`. If you know Git, the version control procedures and system tables should feel familiar.
So, we add and commit our new schema like so.
```
mysql> call dolt_add('teams', 'employees', 'employees_teams');
+--------+
| status |
+--------+
| 0 |
+--------+
1 row in set (0.03 sec)
mysql> call dolt_commit('-m', 'Created initial schema');
+----------------------------------+
| hash |
+----------------------------------+
| ne182jemgrlm8jnjmoubfqsstlfi1s98 |
+----------------------------------+
1 row in set (0.02 sec)
mysql> select * from dolt_log;
+----------------------------------+-----------+-----------------+-------------------------+----------------------------+
| commit_hash | committer | email | date | message |
+----------------------------------+-----------+-----------------+-------------------------+----------------------------+
| ne182jemgrlm8jnjmoubfqsstlfi1s98 | Tim Sehn | tim@dolthub.com | 2022-06-07 16:35:49.277 | Created initial schema |
| vluuhvd0bn59598utedt77ed9q5okbcb | Tim Sehn | tim@dolthub.com | 2022-06-07 16:33:59.531 | Initialize data repository |
+----------------------------------+-----------+-----------------+-------------------------+----------------------------+
2 rows in set (0.01 sec)
```
There you have it. Your schema is created and you have a Dolt commit tracking the creation, as seen in the `dolt_log` system table.
Note, a Dolt commit is different than a standard SQL transaction `COMMIT`. In this case, I am running the database with [`AUTOCOMMIT`](https://dev.mysql.com/doc/refman/5.6/en/innodb-autocommit-commit-rollback.html) on, so each SQL statement is automatically generating a transaction `COMMIT`. If you want system to generate a Dolt commit for every transaction use the system variable, [`@@dolt_transaction_commit`](https://dolthub.com/docs/sql-reference/version-control/dolt-sysvars#dolt_transaction_commit).
## Insert some data
Now, I'm going to populate the database with a few employees here at DoltHub. Then, I'll assign the employees to two teams: engineering and sales. The CEO wears many hats at a start up so he'll be assigned to multiple teams.
```
mysql> insert into employees values
(0, 'Sehn', 'Tim'),
(1, 'Hendriks', 'Brian'),
(2, 'Son','Aaron'),
(3, 'Fitzgerald', 'Brian');
Query OK, 4 rows affected (0.01 sec)
mysql> select * from employees where first_name='Brian';
+------+------------+------------+
| id | last_name | first_name |
+------+------------+------------+
| 1 | Hendriks | Brian |
| 3 | Fitzgerald | Brian |
+------+------------+------------+
2 rows in set (0.00 sec)
mysql> insert into teams values
(0, 'Engineering'),
(1, 'Sales');
Query OK, 2 rows affected (0.00 sec)
mysql> insert into employees_teams values
(0,0),
(1,0),
(2,0),
(0,1),
(3,1);
ERROR 1452 (HY000): cannot add or update a child row - Foreign key violation on fk: `rv9ek7ft`, table: `employees_teams`, referenced table: `teams`, key: `[2]`
```
Oops, I violated a constraint. It looks like I created the table with teams before employees. You should always specify your columns when you insert, not rely on natural ordering. Serves me right! Dolt comes with the full power of a modern SQL relational database to ensure data integrity.
```
mysql> insert into employees_teams(employee_id, team_id) values
(0,0),
(1,0),
(2,0),
(0,1),
(3,1);
Query OK, 5 rows affected (0.01 sec)
mysql> select first_name, last_name, team_name from employees
join employees_teams on (employees.id=employees_teams.employee_id)
join teams on (teams.id=employees_teams.team_id)
where team_name='Engineering';
+------------+-----------+-------------+
| first_name | last_name | team_name |
+------------+-----------+-------------+
| Tim | Sehn | Engineering |
| Brian | Hendriks | Engineering |
| Aaron | Son | Engineering |
+------------+-----------+-------------+
3 rows in set (0.00 sec)
```
Looks like everything is inserted and correct. I was able to list the members of the engineering team using that three table `JOIN`. Dolt supports up to twelve table `JOIN`s. Again, Dolt is a modern SQL relational database paired with Git-style version control.
## Examine the diff
Now, what if you want to see what changed in your working set before you make a commit? You use the `dolt_status` and `dolt_diff_<tablename>` system tables.
```
mysql> select * from dolt_status;
+-----------------+--------+----------+
| table_name | staged | status |
+-----------------+--------+----------+
| teams | 0 | modified |
| employees | 0 | modified |
| employees_teams | 0 | modified |
+-----------------+--------+----------+
3 rows in set (0.01 sec)
mysql> select * from dolt_diff_employees;
+--------------+---------------+-------+-----------+----------------+----------------+-----------------+---------+----------------------------------+-------------------------+-----------+
| to_last_name | to_first_name | to_id | to_commit | to_commit_date | from_last_name | from_first_name | from_id | from_commit | from_commit_date | diff_type |
+--------------+---------------+-------+-----------+----------------+----------------+-----------------+---------+----------------------------------+-------------------------+-----------+
| Sehn | Tim | 0 | WORKING | NULL | NULL | NULL | NULL | ne182jemgrlm8jnjmoubfqsstlfi1s98 | 2022-06-07 16:35:49.277 | added |
| Hendriks | Brian | 1 | WORKING | NULL | NULL | NULL | NULL | ne182jemgrlm8jnjmoubfqsstlfi1s98 | 2022-06-07 16:35:49.277 | added |
| Son | Aaron | 2 | WORKING | NULL | NULL | NULL | NULL | ne182jemgrlm8jnjmoubfqsstlfi1s98 | 2022-06-07 16:35:49.277 | added |
| Fitzgerald | Brian | 3 | WORKING | NULL | NULL | NULL | NULL | ne182jemgrlm8jnjmoubfqsstlfi1s98 | 2022-06-07 16:35:49.277 | added |
+--------------+---------------+-------+-----------+----------------+----------------+-----------------+---------+----------------------------------+-------------------------+-----------+
4 rows in set (0.00 sec)
```
As you can see from the diff I've added the correct values to the `employees` table. The values were previously `NULL` and now they are populated.
Let's finish off with another Dolt commit this time adding all effected tables using `-am`.
```
mysql> call dolt_commit('-am', 'Populated tables with data');
+----------------------------------+
| hash |
+----------------------------------+
| 13qfqa5rojq18j84d1n2htjkm6fletg4 |
+----------------------------------+
1 row in set (0.02 sec)
```
You can inspect the log using `dolt_log` and see which tables changed in each commit using an unscoped `dolt_diff`. Unscoped `dolt_diff` tells you whether schema, data, or both changed in that particular commit for the table.
```
mysql> select * from dolt_log;
+----------------------------------+-----------+-----------------+-------------------------+----------------------------+
| commit_hash | committer | email | date | message |
+----------------------------------+-----------+-----------------+-------------------------+----------------------------+
| 13qfqa5rojq18j84d1n2htjkm6fletg4 | Tim Sehn | tim@dolthub.com | 2022-06-07 16:39:32.066 | Populated tables with data |
| ne182jemgrlm8jnjmoubfqsstlfi1s98 | Tim Sehn | tim@dolthub.com | 2022-06-07 16:35:49.277 | Created initial schema |
| vluuhvd0bn59598utedt77ed9q5okbcb | Tim Sehn | tim@dolthub.com | 2022-06-07 16:33:59.531 | Initialize data repository |
+----------------------------------+-----------+-----------------+-------------------------+----------------------------+
3 rows in set (0.00 sec)
mysql> select * from dolt_diff;
+----------------------------------+-----------------+-----------+-----------------+-------------------------+----------------------------+-------------+---------------+
| commit_hash | table_name | committer | email | date | message | data_change | schema_change |
+----------------------------------+-----------------+-----------+-----------------+-------------------------+----------------------------+-------------+---------------+
| 13qfqa5rojq18j84d1n2htjkm6fletg4 | teams | Tim Sehn | tim@dolthub.com | 2022-06-07 16:39:32.066 | Populated tables with data | 1 | 0 |
| 13qfqa5rojq18j84d1n2htjkm6fletg4 | employees | Tim Sehn | tim@dolthub.com | 2022-06-07 16:39:32.066 | Populated tables with data | 1 | 0 |
| 13qfqa5rojq18j84d1n2htjkm6fletg4 | employees_teams | Tim Sehn | tim@dolthub.com | 2022-06-07 16:39:32.066 | Populated tables with data | 1 | 0 |
| ne182jemgrlm8jnjmoubfqsstlfi1s98 | employees | Tim Sehn | tim@dolthub.com | 2022-06-07 16:35:49.277 | Created initial schema | 0 | 1 |
| ne182jemgrlm8jnjmoubfqsstlfi1s98 | employees_teams | Tim Sehn | tim@dolthub.com | 2022-06-07 16:35:49.277 | Created initial schema | 0 | 1 |
| ne182jemgrlm8jnjmoubfqsstlfi1s98 | teams | Tim Sehn | tim@dolthub.com | 2022-06-07 16:35:49.277 | Created initial schema | 0 | 1 |
+----------------------------------+-----------------+-----------+-----------------+-------------------------+----------------------------+-------------+---------------+
6 rows in set (0.00 sec)
```
## Oh no! I made a mistake.
Dolt supports undoing changes via `call dolt_reset()`. Let's imagine I accidentally drop a table.
```
mysql> drop table employees_teams;
Query OK, 0 rows affected (0.01 sec)
mysql> show tables;
+---------------------------+
| Tables_in_getting_started |
+---------------------------+
| employees |
| teams |
+---------------------------+
2 rows in set (0.00 sec)
```
In a traditional database, this could be disastrous. In Dolt, you're one command away from getting your table back.
```
mysql> call dolt_reset('--hard');
+--------+
| status |
+--------+
| 0 |
+--------+
1 row in set (0.01 sec)
mysql> show tables;
+---------------------------+
| Tables_in_getting_started |
+---------------------------+
| employees |
| employees_teams |
| teams |
+---------------------------+
3 rows in set (0.01 sec)
```
Dolt makes operating databases less error prone. You can always back out changes you have in progress or rewind to a known good state. You also have the ability to undo specific commits using [`dolt_revert()`](https://dolthub.com/docs/sql-reference/version-control/dolt-sql-procedures#dolt_revert). Even if you accidentally run `drop database` on the wrong database, Dolt lets you undo that by calling the [`dolt_undrop()` stored procedure](https://dolthub.com/docs/sql-reference/version-control/dolt-sql-procedures#dolt_undrop).
## See the data in a SQL Workbench
Hate the command line? Let's use [Tableplus](https://tableplus.com/) to make some modifications. Tableplus is a free SQL Workbench. Follow the installation instructions from their website.
Now, to connect you must select MySQL as the connection type. Then enter a name for your connection, `getting_started` as your database, and `root` as your user.
![Tableplus Connection](./images/getting-started-tp-connect.png)
Click connect and you'll be presented with a familiar database workbench GUI.
![Tableplus](./images/getting-started-tp.png)
## Make changes on a branch
To make changes on a branch, I use the `dolt_checkout()` stored procedure. Using the `-b` option creates a branch, just like in Git.
Tableplus gives me the ability to enter a multiple line SQL script on the SQL tab. I entered the following SQL to checkout a branch, update, insert, delete, and finally Dolt commit my changes.
```SQL
call dolt_checkout('-b','modifications');
update employees SET first_name='Timothy' where first_name='Tim';
insert INTO employees (id, first_name, last_name) values (4,'Daylon', 'Wilkins');
insert into employees_teams(team_id, employee_id) values (0,4);
delete from employees_teams where employee_id=0 and team_id=1;
call dolt_commit('-am', 'Modifications on a branch');
```
Here's the result in Tableplus.
![New Updates](./images/getting-started-new-updates.png)
Back in my terminal, I cannot see the table modifications made in Tableplus because they happened on a different branch than the one I have checked out in my session.
```
mysql> select * from dolt_branches;
+---------------+----------------------------------+------------------+------------------------+-------------------------+----------------------------+
| name | hash | latest_committer | latest_committer_email | latest_commit_date | latest_commit_message |
+---------------+----------------------------------+------------------+------------------------+-------------------------+----------------------------+
| main | 13qfqa5rojq18j84d1n2htjkm6fletg4 | Tim Sehn | tim@dolthub.com | 2022-06-07 16:39:32.066 | Populated tables with data |
| modifications | uhkv57j4bp2v16vcnmev9lshgkqq8ppb | Tim Sehn | tim@dolthub.com | 2022-06-07 16:41:49.847 | Modifications on a branch |
+---------------+----------------------------------+------------------+------------------------+-------------------------+----------------------------+
2 rows in set (0.00 sec)
mysql> select active_branch();
+-----------------+
| active_branch() |
+-----------------+
| main |
+-----------------+
1 row in set (0.00 sec)
mysql> select * from employees;
+------+------------+------------+
| id | last_name | first_name |
+------+------------+------------+
| 0 | Sehn | Tim |
| 1 | Hendriks | Brian |
| 2 | Son | Aaron |
| 3 | Fitzgerald | Brian |
+------+------------+------------+
4 rows in set (0.00 sec)
```
I can query the branch no matter what I have checked out using SQL `as of` syntax.
```
mysql> select * from employees as of 'modifications';
+------+------------+------------+
| id | last_name | first_name |
+------+------------+------------+
| 0 | Sehn | Timothy |
| 1 | Hendriks | Brian |
| 2 | Son | Aaron |
| 3 | Fitzgerald | Brian |
| 4 | Wilkins | Daylon |
+------+------------+------------+
5 rows in set (0.01 sec)
```
If I'd like to see the diff between the two branches, I can use the `dolt_diff()` table function. It takes two branches and the table name as arguments.
```
mysql> select * from dolt_diff('main', 'modifications', 'employees');
+--------------+---------------+-------+---------------+-------------------------+----------------+-----------------+---------+-------------+-------------------------+-----------+
| to_last_name | to_first_name | to_id | to_commit | to_commit_date | from_last_name | from_first_name | from_id | from_commit | from_commit_date | diff_type |
+--------------+---------------+-------+---------------+-------------------------+----------------+-----------------+---------+-------------+-------------------------+-----------+
| Sehn | Timothy | 0 | modifications | 2022-06-07 16:41:49.847 | Sehn | Tim | 0 | main | 2022-06-07 16:39:32.066 | modified |
| Wilkins | Daylon | 4 | modifications | 2022-06-07 16:41:49.847 | NULL | NULL | NULL | main | 2022-06-07 16:39:32.066 | added |
+--------------+---------------+-------+---------------+-------------------------+----------------+-----------------+---------+-------------+-------------------------+-----------+
2 rows in set (0.00 sec)
```
As you can see, you have the full power of Git-style branches and diffs in a SQL database with Dolt.
## Make a schema change on another branch
I can also make schema changes on branches for isolated testing of new schema. I'm going to add a `start_date` column on a new branch and populate it.
```
mysql> call dolt_checkout('-b', 'schema_changes');
+--------+
| status |
+--------+
| 0 |
+--------+
1 row in set (0.01 sec)
mysql> alter table employees add column start_date date;
Query OK, 0 rows affected (0.02 sec)
mysql> update employees set start_date='2018-09-08';
Query OK, 4 rows affected (0.01 sec)
Rows matched: 4 Changed: 4 Warnings: 0
mysql> update employees set start_date='2021-04-19' where last_name='Fitzgerald';
Query OK, 1 row affected (0.01 sec)
Rows matched: 1 Changed: 1 Warnings: 0
mysql> select * from employees;
+------+------------+------------+------------+
| id | last_name | first_name | start_date |
+------+------------+------------+------------+
| 0 | Sehn | Tim | 2018-09-08 |
| 1 | Hendriks | Brian | 2018-09-08 |
| 2 | Son | Aaron | 2018-09-08 |
| 3 | Fitzgerald | Brian | 2021-04-19 |
+------+------------+------------+------------+
4 rows in set (0.00 sec)
mysql> call dolt_commit('-am', 'Added start_date column to employees');
+----------------------------------+
| hash |
+----------------------------------+
| pg3nfi0j1dpc5pf1rfgckpmlteaufdrt |
+----------------------------------+
1 row in set (0.01 sec)
```
Changing schema on a branch gives you a new method for doing isolated integration testing of new schema changes.
## Merge it all together
Let's assume all the testing of the new schema on the `schema_changes` branch and data on the `modifications` branch completed flawlessly. It's time to merge all our edits together onto `main`. This is done using the `dolt_merge` stored procedure.
```
mysql> call dolt_checkout('main');
+--------+
| status |
+--------+
| 0 |
+--------+
1 row in set (0.01 sec)
mysql> select * from dolt_status;
Empty set (0.00 sec)
mysql> call dolt_merge('schema_changes');
+--------------+
| no_conflicts |
+--------------+
| 1 |
+--------------+
1 row in set (0.01 sec)
mysql> select * from employees;
+------+------------+------------+------------+
| id | last_name | first_name | start_date |
+------+------------+------------+------------+
| 0 | Sehn | Tim | 2018-09-08 |
| 1 | Hendriks | Brian | 2018-09-08 |
| 2 | Son | Aaron | 2018-09-08 |
| 3 | Fitzgerald | Brian | 2021-04-19 |
+------+------------+------------+------------+
4 rows in set (0.00 sec)
```
Schema change successful. We now have start dates. Data changes are next.
```
mysql> call dolt_merge('modifications');
+--------------+
| no_conflicts |
+--------------+
| 1 |
+--------------+
1 row in set (0.02 sec)
mysql> select * from employees;
+------+------------+------------+------------+
| id | last_name | first_name | start_date |
+------+------------+------------+------------+
| 0 | Sehn | Timothy | 2018-09-08 |
| 1 | Hendriks | Brian | 2018-09-08 |
| 2 | Son | Aaron | 2018-09-08 |
| 3 | Fitzgerald | Brian | 2021-04-19 |
| 4 | Wilkins | Daylon | NULL |
+------+------------+------------+------------+
5 rows in set (0.00 sec)
```
Data changes successful as well. As you can see, I am now "Timothy" instead of "Tim", Daylon is added, and we all have start dates except for Daylon who was added on a different branch.
```
mysql> select first_name, last_name, team_name from employees
join employees_teams on (employees.id=employees_teams.employee_id)
join teams on (teams.id=employees_teams.team_id)
where team_name='Sales';
+------------+------------+-----------+
| first_name | last_name | team_name |
+------------+------------+-----------+
| Brian | Fitzgerald | Sales |
+------------+------------+-----------+
1 row in set (0.01 sec)
```
I'm also gone from the Sales Team. Engineering is life.
I have to commit all my changes because the last merge was not a fast-forward merge.
```
mysql> call dolt_commit('-m', 'Merged all branches');
+----------------------------------+
| hash |
+----------------------------------+
| vn9b0qcematsj2f6ka0hfoflhr5s6p0b |
+----------------------------------+
1 row in set (0.01 sec)
mysql> select * from dolt_log;
+----------------------------------+-----------+-----------------+-------------------------+--------------------------------------+
| commit_hash | committer | email | date | message |
+----------------------------------+-----------+-----------------+-------------------------+--------------------------------------+
| vn9b0qcematsj2f6ka0hfoflhr5s6p0b | Tim Sehn | tim@dolthub.com | 2022-06-07 17:10:02.07 | Merged all branches |
| pg3nfi0j1dpc5pf1rfgckpmlteaufdrt | Tim Sehn | tim@dolthub.com | 2022-06-07 16:44:37.513 | Added start_date column to employees |
| uhkv57j4bp2v16vcnmev9lshgkqq8ppb | Tim Sehn | tim@dolthub.com | 2022-06-07 16:41:49.847 | Modifications on a branch |
| 13qfqa5rojq18j84d1n2htjkm6fletg4 | Tim Sehn | tim@dolthub.com | 2022-06-07 16:39:32.066 | Populated tables with data |
| ne182jemgrlm8jnjmoubfqsstlfi1s98 | Tim Sehn | tim@dolthub.com | 2022-06-07 16:35:49.277 | Created initial schema |
| vluuhvd0bn59598utedt77ed9q5okbcb | Tim Sehn | tim@dolthub.com | 2022-06-07 16:33:59.531 | Initialize data repository |
+----------------------------------+-----------+-----------------+-------------------------+--------------------------------------+
6 rows in set (0.00 sec)
```
Now, we have a database with all the schema and data changes merged and ready for use.
## Audit Cell Lineage
Which commit changed my first name? With Dolt you have lineage for every cell in your database. Let's use the `dolt_history_<tablename>` and `dolt_diff_<tablename>` to explore the lineage features in Dolt.
`dolt_history_<tablename>` shows you the state of the row at every commit.
```
mysql> select * from dolt_history_employees where id=0 order by commit_date;
+------+-----------+------------+------------+----------------------------------+-----------+-------------------------+
| id | last_name | first_name | start_date | commit_hash | committer | commit_date |
+------+-----------+------------+------------+----------------------------------+-----------+-------------------------+
| 0 | Sehn | Tim | NULL | 13qfqa5rojq18j84d1n2htjkm6fletg4 | Tim Sehn | 2022-06-07 16:39:32.066 |
| 0 | Sehn | Timothy | NULL | uhkv57j4bp2v16vcnmev9lshgkqq8ppb | Tim Sehn | 2022-06-07 16:41:49.847 |
| 0 | Sehn | Tim | 2018-09-08 | pg3nfi0j1dpc5pf1rfgckpmlteaufdrt | Tim Sehn | 2022-06-07 16:44:37.513 |
| 0 | Sehn | Timothy | 2018-09-08 | vn9b0qcematsj2f6ka0hfoflhr5s6p0b | Tim Sehn | 2022-06-07 17:10:02.07 |
+------+-----------+------------+------------+----------------------------------+-----------+-------------------------+
4 rows in set (0.00 sec)
```
`dolt_diff_<tablename>` allows you to filter the history down to only commits when the cell in question changed. In this case, I'm interested in the commits that are changing my first name. Note, there are two commits that changed my name because one is the original change and the second is the merge commit.
```
mysql> select to_commit,from_first_name,to_first_name from dolt_diff_employees
where (from_id=0 or to_id=0) and (from_first_name <> to_first_name or from_first_name is NULL)
order by to_commit_date;
+----------------------------------+-----------------+---------------+
| to_commit | from_first_name | to_first_name |
+----------------------------------+-----------------+---------------+
| 13qfqa5rojq18j84d1n2htjkm6fletg4 | NULL | Tim |
| uhkv57j4bp2v16vcnmev9lshgkqq8ppb | Tim | Timothy |
| vn9b0qcematsj2f6ka0hfoflhr5s6p0b | Tim | Timothy |
+----------------------------------+-----------------+---------------+
3 rows in set (0.01 sec)
```
Dolt provides powerful data audit capabilities down to individual cells. When, how, and why has each cell in your database changed over time?
# Additional Reading
Head over to [our documentation](https://dolthub.com/docs/introduction/what-is-dolt) now that you have a feel for Dolt. You can also read about what we've been working on in [our blog](https://www.dolthub.com/blog/).
# Security Policy
[Dolt's current security policy](https://github.com/dolthub/dolt/blob/main/SECURITY.md) is maintained in this repository. Please follow the disclosure instructions there. Please do not initially report security issues in this repository's public GitHub issues.
# Credits and License
Dolt relies heavily on open source code and ideas from the
[Noms](https://github.com/attic-labs/noms) project. We are very
thankful to the Noms team for making this code freely available,
without which we would not have been able to build Dolt so rapidly.
Dolt is licensed under the Apache License, Version 2.0. See
[LICENSE](https://github.com/dolthub/dolt/blob/master/LICENSE) for
details.
+7
View File
@@ -0,0 +1,7 @@
# WeHub 来源说明
- 原始项目:`dolthub/dolt`
- 原始仓库:https://github.com/dolthub/dolt
- 导入方式:上游默认分支的最新快照
- 原作者、版权和许可证信息以原始仓库及本仓库 LICENSE 为准
- 本文件仅用于记录来源,不代表 WeHub 是原项目作者
+16
View File
@@ -0,0 +1,16 @@
# Security Policy
## Supported Versions
By default, the most recent release of Dolt is the version which is
supported for all security updates. If you need ongoing security
support for an older version of Dolt, please [contact us](https://www.dolthub.com/contact).
## Reporting a Vulnerability
Any security issues with Dolt can be reported to [security@dolthub.com](security@dolthub.com).
Reports will be responded to within one business day. The majority of
our team operates on Pacific Time and on a US holiday schedule.
DoltHub does not currently run a security bounty program for Dolt.
+21
View File
@@ -0,0 +1,21 @@
# syntax=docker/dockerfile:1.3-labs
FROM ubuntu:22.04
ARG DOLT_VERSION
RUN apt update -y && \
apt install -y \
curl \
git \
tini \
ca-certificates && \
apt clean && \
rm -rf /var/lib/apt/lists/*
# we install dolt with the install.sh script, which will determine the platform/arch of the container
# and install the proper dolt binary
RUN bash -c 'curl -L https://github.com/dolthub/dolt/releases/download/v${DOLT_VERSION}/install.sh | bash'
RUN /usr/local/bin/dolt version
WORKDIR /var/lib/dolt
ENTRYPOINT ["tini", "--", "/usr/local/bin/dolt"]
+78
View File
@@ -0,0 +1,78 @@
# Dolt is Git for Data!
[Dolt](https://doltdb.com) is a SQL database that you can fork, clone, branch, merge, push
and pull just like a Git repository. Connect to Dolt just like any
MySQL database to run queries or update the data using SQL
commands. Use the command line interface to import CSV files, commit
your changes, push them to a remote, or merge your teammate's changes.
All the commands you know for Git work exactly the same for Dolt. Git
versions files, Dolt versions tables. It's like Git and MySQL had a
baby.
We also built [DoltHub](https://www.dolthub.com), a place to share
Dolt databases. We host public data for free. If you want to host
your own version of DoltHub, we have [DoltLab](https://www.doltlab.com). If you want us to run a Dolt server for you, we have [Hosted Dolt](https://hosted.doltdb.com).
[Join us on Discord](https://discord.com/invite/RFwfYpu) to say hi and
ask questions, or [check out our roadmap](https://dolthub.com/docs/other/roadmap)
to see what we're building next.
## What's it for?
Lots of things! Dolt is a generally useful tool with countless
applications. But if you want some ideas, [here's how people are using
it so far](https://www.dolthub.com/blog/2022-07-11-dolt-case-studies/).
Learn more about Dolt use cases, configuration and guides to use dolt on our [documentation page](https://dolthub.com/docs/introduction/what-is-dolt).
# How to use this image
This image is for Dolt CLI, which has the same commands as `git`, with some extras. Running this image without any
arguments is equivalent to running `dolt` command locally.
```shell
$ docker run dolthub/dolt:latest
Valid commands for dolt are
init - Create an empty Dolt data repository.
status - Show the working tree status.
add - Add table changes to the list of staged table changes.
diff - Diff a table.
reset - Remove table changes from the list of staged table changes.
clean - Remove untracked tables from working set.
commit - Record changes to the repository.
sql - Run a SQL query against tables in repository.
sql-server - Start a MySQL-compatible server.
sql-client - Starts a built-in MySQL client.
log - Show commit logs.
branch - Create, list, edit, delete branches.
checkout - Checkout a branch or overwrite a table from HEAD.
merge - Merge a branch.
conflicts - Commands for viewing and resolving merge conflicts.
cherry-pick - Apply the changes introduced by an existing commit.
revert - Undo the changes introduced in a commit.
clone - Clone from a remote data repository.
fetch - Update the database from a remote data repository.
pull - Fetch from a dolt remote data repository and merge.
push - Push to a dolt remote.
config - Dolt configuration.
remote - Manage set of tracked repositories.
backup - Manage a set of server backups.
login - Login to a dolt remote host.
creds - Commands for managing credentials.
ls - List tables in the working set.
schema - Commands for showing and importing table schemas.
table - Commands for copying, renaming, deleting, and exporting tables.
tag - Create, list, delete tags.
blame - Show what revision and author last modified each row of a table.
constraints - Commands for handling constraints.
migrate - Executes a database migration to use the latest Dolt data format.
read-tables - Fetch table(s) at a specific commit into a new dolt repo
gc - Cleans up unreferenced data from the repository.
filter-branch - Edits the commit history using the provided query.
merge-base - Find the common ancestor of two commits.
version - Displays the current Dolt cli version.
dump - Export all tables in the working set into a file.
```
This image is useful for creating custom Docker Image using this image as base image.
+441
View File
@@ -0,0 +1,441 @@
#!/bin/bash
set -eo pipefail
# mysql_log prints a timestamped (ISO 8601), color-coded structured log message.
# The message includes a log level and the message itself.
# If <MESSAGE> is omitted, it reads from stdin, allowing multi-line input.
#
# Arguments:
# $1 - <LEVEL> : Log level (e.g., Warn, Error, Debug)
# $2 - <MESSAGE> : Message to log; if omitted, the function reads from stdin
#
# Usage:
# mysql_log <LEVEL> [MESSAGE]
# mysql_log Warn "Disk space low"
# echo "Database connection lost" | mysql_log Error
#
# Output:
# 2025-10-16T12:34:56+00:00 [Warn] [Entrypoint] Disk space low
# 2025-10-16T12:35:01+00:00 [Error] [Entrypoint] Database connection lost
_mysql_log() {
local level="$1"; shift
local dt
dt="$(date --rfc-3339=seconds)"
local color_reset="\033[0m"
local color=""
case "$level" in
Warn) color="\033[1;33m" ;; # yellow
Error) color="\033[1;31m" ;; # red
Debug) color="\033[1;34m" ;; # blue
esac
local msg="$*"
if [ "$#" -eq 0 ]; then
msg="$(cat)"
fi
printf '%b%s [%s] [Entrypoint] %s%b\n' "$color" "$dt" "$level" "$msg" "$color_reset"
}
# _dbg logs a message of type 'Debug' using mysql_log.
_dbg() {
_mysql_log Debug "$@"
}
# mysql_note logs a message of type 'Note' using mysql_log.
mysql_note() {
_mysql_log Note "$@"
}
# mysql_warn logs a message of type 'Warning' using mysql_log and writes to stderr.
mysql_warn() {
_mysql_log Warn "$@" >&2
}
# mysql_error logs a message of type 'ERROR' using mysql_log, writes to stderr, prints a container removal hint, and
# exits with status 1.
mysql_error() {
_mysql_log Error "$@" >&2
mysql_note "Remove this container with 'docker rm -f <container_name>' before retrying"
exit 1
}
# exec_mysql executes a SQL query using Dolt, retrying until success or timeout. Ensures reliability during slow
# container or resource startup. On timeout, it prints the provided error prefix followed by filtered Dolt output.
# Errors are parsed to remove blank lines and extract only relevant error text. Use --show-result to display successful
# query results.
#
# Usage:
# exec_mysql [--show-result] "<ERROR_MESSAGE>" "<QUERY>"
# exec_mysql [--show-result] "<ERROR_MESSAGE>" < /docker-entrypoint-initdb.d/init.sql
# cat /docker-entrypoint-initdb.d/init.sql | exec_mysql [--show-result] "<ERROR_MESSAGE>"
#
# Output:
# Prints query output only if --show-result is specified.
exec_mysql() {
local show_result=0
if [ "$1" = "--show-result" ]; then
show_result=1
shift
fi
local error_message="$1"
local query="${2:-}"
local timeout="${DOLT_SERVER_TIMEOUT:-300}"
local start_time now output status
start_time=$(date +%s)
while true; do
if [ -n "$query" ]; then
output=$(dolt sql -q "$query" 2>&1)
status=$?
else
set +e # tmp disabled to initdb.d/ file err
output=$(dolt sql < /dev/stdin 2>&1)
status=$?
set -e
fi
if [ "$status" -eq 0 ]; then
[ "$show_result" -eq 1 ] && echo "$output" | grep -v "^$" || true
return 0
fi
if echo "$output" | grep -qiE "Error [0-9]+ \([A-Z0-9]+\)"; then
mysql_error "$error_message$(echo "$output" | grep -iE "Error|error")"
fi
if [ "$timeout" -ne 0 ]; then
now=$(date +%s)
if [ $((now - start_time)) -ge "$timeout" ]; then
mysql_error "$error_message$(echo "$output" | grep -iE "Error|error" || true)"
fi
fi
sleep 1
done
}
CONTAINER_DATA_DIR="/var/lib/dolt"
INIT_COMPLETED="$CONTAINER_DATA_DIR/.init_completed"
DOLT_CONFIG_DIR="/etc/dolt/doltcfg.d"
SERVER_CONFIG_DIR="/etc/dolt/servercfg.d"
DOLT_ROOT_PATH="/.dolt"
SERVER_PID=-1
# check_for_dolt_binary verifies that the dolt binary is present and executable in the system PATH.
# If not found or not executable, it logs an error and exits.
check_for_dolt_binary() {
local dolt_bin
dolt_bin=$(which dolt)
if [ ! -x "$dolt_bin" ]; then
mysql_error "dolt binary executable not found"
fi
}
# get_env_var returns the value of an environment variable, preferring DOLT_* over MYSQL_*.
# Arguments:
# $1 - The base variable name (e.g., "USER" for MYSQL_USER or DOLT_USER)
# Output:
# Prints the value of the first set variable, or an empty string if neither is set.
get_env_var() {
local var_name="$1"
local dolt_var="DOLT_${var_name}"
local mysql_var="MYSQL_${var_name}"
if [ -n "${!dolt_var}" ]; then
echo "${!dolt_var}"
elif [ -n "${!mysql_var}" ]; then
echo "${!mysql_var}"
else
echo ""
fi
}
# get_env_var_name returns the name of the environment variable that is set, preferring DOLT_* over MYSQL_*.
# Arguments:
# $1 - The base variable name (e.g., "USER" for MYSQL_USER or DOLT_USER)
# Output:
# Prints the name of the first set variable, or both names if neither is set.
get_env_var_name() {
local var_name="$1"
local dolt_var="DOLT_${var_name}"
local mysql_var="MYSQL_${var_name}"
if [ -n "${!dolt_var}" ]; then
echo "DOLT_${var_name}"
elif [ -n "${!mysql_var}" ]; then
echo "MYSQL_${var_name}"
else
echo "MYSQL_${var_name}/DOLT_${var_name}"
fi
}
# get_config_file_path_if_exists checks for config files of a given type in a directory.
# Arguments:
# $1 - Directory to search in
# $2 - File type/extension to search for (e.g., 'json', 'yaml')
# Output:
# Sets CONFIG_PROVIDED to the path of the config file if exactly one is found, or empty otherwise.
# Logs a warning if multiple config files are found and uses the default config.
get_config_file_path_if_exists() {
CONFIG_PROVIDED=
local CONFIG_DIR=$1
local FILE_TYPE=$2
if [ -d "$CONFIG_DIR" ]; then
mysql_note "Checking for config provided in $CONFIG_DIR"
local number_of_files_found
number_of_files_found=$(find "$CONFIG_DIR" -type f -name "*.$FILE_TYPE" | wc -l)
if [ "$number_of_files_found" -gt 1 ]; then
CONFIG_PROVIDED=
mysql_warn "Multiple config files found in $CONFIG_DIR, using default config"
elif [ "$number_of_files_found" -eq 1 ]; then
local files_found
files_found=$(ls "$CONFIG_DIR"/*."$FILE_TYPE")
mysql_note "$files_found file is found"
CONFIG_PROVIDED=$files_found
else
CONFIG_PROVIDED=
fi
fi
}
# docker_process_init_files Runs files found in /docker-entrypoint-initdb.d before the server is started.
# Taken from https://github.com/docker-library/mysql/blob/master/8.0/docker-entrypoint.sh
# Usage:
# docker_process_init_files [file [file ...]]
# e.g., docker_process_init_files /always-initdb.d/*
# Processes initializer files based on file extensions.
docker_process_init_files() {
local f
echo
for f; do
case "$f" in
*.sh)
if [ -x "$f" ]; then
mysql_note "$0: running $f"
if ! "$f"; then
mysql_error "Failed to execute $f: "
fi
else
mysql_note "$0: sourcing $f"
if ! . "$f"; then
mysql_error "Failed to execute $f: "
fi
fi
;;
*.sql)
mysql_note "$0: running $f"
exec_mysql --show-result "Failed to execute $f: " < "$f"
;;
*.sql.bz2)
mysql_note "$0: running $f"
bunzip2 -c "$f" | exec_mysql --show-result "Failed to execute $f: "
;;
*.sql.gz)
mysql_note "$0: running $f"
gunzip -c "$f" | exec_mysql --show-result "Failed to execute $f: "
;;
*.sql.xz)
mysql_note "$0: running $f"
xzcat "$f" | exec_mysql --show-result "Failed to execute $f: "
;;
*.sql.zst)
mysql_note "$0: running $f"
zstd -dc "$f" | exec_mysql --show-result "Failed to execute $f: "
;;
*)
mysql_warn "$0: ignoring $f"
;;
esac
echo
done
}
# set_dolt_config_if_defined checks for a user-provided Dolt config file in $DOLT_CONFIG_DIR.
# If a single JSON config file is found, it copies it to $HOME/$DOLT_ROOT_PATH/config_global.json,
# overwriting the default config. Logs an error and exits if the copy fails.
set_dolt_config_if_defined() {
get_config_file_path_if_exists "$DOLT_CONFIG_DIR" "json"
if [ ! -z "$CONFIG_PROVIDED" ]; then
if ! /bin/cp -rf "$CONFIG_PROVIDED" "$HOME/$DOLT_ROOT_PATH/config_global.json" 2>&1; then
mysql_error "Failed to copy config file from '$CONFIG_PROVIDED' to '$HOME/$DOLT_ROOT_PATH/config_global.json'. Check file permissions and paths."
fi
fi
}
# create_database_from_env creates a database if the DATABASE environment variable is set.
# It retrieves the database name from environment variables (preferring DOLT_DATABASE over MYSQL_DATABASE)
# and attempts to create the database using exec_mysql.
create_database_from_env() {
local database
database=$(get_env_var "DATABASE")
if [ -n "$database" ]; then
mysql_note "Creating database '${database}'"
exec_mysql "Failed to create database '$database': " "CREATE DATABASE IF NOT EXISTS \`$database\`;"
fi
}
# create_user_from_env creates a new database user from environment variables.
# It prefers DOLT_USER/PASSWORD over MYSQL_USER/PASSWORD, and optionally grants access to a database.
# Requires both USER and PASSWORD to be set; if only the password is set, it logs a warning and does nothing.
# It does not allow creating a 'root' user via these environment variables.
create_user_from_env() {
local user
local password
local database
user=$(get_env_var "USER")
password=$(get_env_var "PASSWORD")
database=$(get_env_var "DATABASE")
if [ "$user" = 'root' ]; then
mysql_error "$(get_env_var_name "USER")="root", $(get_env_var_name "USER") and $(get_env_var_name "PASSWORD") are for configuring the regular user and cannot be used for the root user."
fi
if [ -n "$user" ] && [ -z "$password" ]; then
mysql_error "$(get_env_var_name "USER") specified, but missing $(get_env_var_name "PASSWORD"); user creation requires a password."
elif [ -z "$user" ] && [ -n "$password" ]; then
mysql_warn "$(get_env_var_name "PASSWORD") specified, but missing $(get_env_var_name "USER"); password will be ignored"
return
fi
if [ -n "$user" ]; then
local user_host
user_host=$(get_env_var "USER_HOST")
user_host="${user_host:-${DOLT_ROOT_HOST:-localhost}}"
mysql_note "Creating user '${user}@${user_host}'"
exec_mysql "Failed to create user '$user': " "CREATE USER IF NOT EXISTS '$user'@'$user_host' IDENTIFIED BY '$password';"
exec_mysql "Failed to grant server access to user '$user': " "GRANT USAGE ON *.* TO '$user'@'$user_host';"
if [ -n "$database" ]; then
exec_mysql "Failed to grant permissions to user '$user' on database '$database': " "GRANT ALL ON \`$database\`.* TO '$user'@'$user_host';"
fi
fi
}
# is_port_open checks if a TCP port is open on a given host.
# Arguments:
# $1 - Host (IP or hostname)
# $2 - Port number
# Returns:
# 0 if the port is open, non-zero otherwise.
is_port_open() {
local host="$1"
local port="$2"
timeout 1 bash -c "cat < /dev/null > /dev/tcp/$host/$port" &>/dev/null
return $?
}
# dolt_server_initializer starts the Dolt SQL server in the background and waits until it is ready to accept connections.
# It manages the server process, restarts it if necessary, and checks for readiness by probing the configured port.
# The function retries until the server is available or a timeout is reached, handling process management and logging.
# Arguments:
# $@ - Additional arguments to pass to `dolt sql-server`
# Returns:
# 0 if the server starts successfully and is ready to accept connections; exits with error otherwise.
dolt_server_initializer() {
local timeout="${DOLT_SERVER_TIMEOUT:-300}"
local start_time
start_time=$(date +%s)
SERVER_PID=-1
trap 'mysql_note "Caught Ctrl+C, shutting down Dolt server..."; [ $SERVER_PID -ne -1 ] && kill "$SERVER_PID"; exit 1' INT TERM
while true; do
if [ "$SERVER_PID" -eq -1 ] || ! kill -0 "$SERVER_PID" 2>/dev/null; then
[ "$SERVER_PID" -ne -1 ] && wait "$SERVER_PID" 2>/dev/null || true
SERVER_PID=-1
dolt sql-server --host=0.0.0.0 --port=3306 "$@" 2>&1 &
SERVER_PID=$!
fi
if is_port_open "0.0.0.0" 3306; then
mysql_note "Dolt server started."
return 0
fi
local now elapsed
now=$(date +%s)
elapsed=$((now - start_time))
if [ "$elapsed" -ge "$timeout" ]; then
kill "$SERVER_PID" 2>/dev/null || true
wait "$SERVER_PID" 2>/dev/null || true
SERVER_PID=-1
mysql_error "Dolt server failed to start within $timeout seconds"
fi
sleep 1
done
}
# _main is the main entrypoint for the Dolt Docker container initialization.
_main() {
check_for_dolt_binary
local dolt_version
dolt_version=$(dolt version | grep 'dolt version' | cut -f3 -d " ")
mysql_note "Entrypoint script for Dolt Server $dolt_version starting..."
declare -g CONFIG_PROVIDED
# dolt config will be set if user provided a single json file in /etc/dolt/doltcfg.d directory.
# It will overwrite config_global.json file in $HOME/.dolt
set_dolt_config_if_defined
CONFIG_PROVIDED=
# if there is a single yaml provided in /etc/dolt/servercfg.d directory,
# it will be used to start the server with --config flag.
get_config_file_path_if_exists "$SERVER_CONFIG_DIR" "yaml"
if [ -n "$CONFIG_PROVIDED" ]; then
set -- "$@" --config="$CONFIG_PROVIDED"
fi
mysql_note "Starting Dolt server"
# Attempt to configure the root user directly through the sql-server using built-in environment variable support
# The user creation queries with `dolt sql` can interfere with this process so we run them after the server is started
DOLT_ROOT_HOST="${DOLT_ROOT_HOST:-localhost}"
# `dolt sql` can hold locks that prevent the server from starting during system hangs without this func
dolt_server_initializer "$@"
# Ran in a subshell to avoid exiting the main script, and so, we can use fallback below
local has_correct_host
has_correct_host=$(exec_mysql --show-result "Could not check root host: " \
"SELECT User, Host FROM mysql.user WHERE User='root' AND Host='${DOLT_ROOT_HOST}' LIMIT 1;" | \
grep -c "$DOLT_ROOT_HOST" || true)
# args or system hangs may conflict with sql-server root env vars support
if [ "$has_correct_host" -eq 0 ]; then
mysql_warn "Environment variables failed to initialize 'root@${DOLT_ROOT_HOST}'; docker-entrypoint-initdb.d scripts queries may have conflicted. Overriding root user..."
exec_mysql "Could not create root user: " "CREATE USER IF NOT EXISTS 'root'@'${DOLT_ROOT_HOST}' IDENTIFIED BY '${DOLT_ROOT_PASSWORD}';" # override password
exec_mysql "Could not set root privileges: " "GRANT ALL PRIVILEGES ON *.* TO 'root'@'${DOLT_ROOT_HOST}' WITH GRANT OPTION;"
fi
create_database_from_env
create_user_from_env
exec_mysql --show-result "Could not list users: " "SELECT User, Host FROM mysql.user;"
if [[ ! -f $INIT_COMPLETED ]]; then
if ls /docker-entrypoint-initdb.d/* >/dev/null 2>&1; then
docker_process_init_files /docker-entrypoint-initdb.d/*
else
mysql_warn "No files found in /docker-entrypoint-initdb.d/ to process"
fi
touch "$INIT_COMPLETED"
fi
mysql_note "Dolt init process done. Ready for connections."
wait "$SERVER_PID"
}
_main "$@"
+85
View File
@@ -0,0 +1,85 @@
# syntax=docker/dockerfile:1.3-labs
FROM debian:bookworm-slim AS base
ENV DEBIAN_FRONTEND=noninteractive
RUN apt-get update -y && \
apt-get install -y --no-install-recommends \
curl git tini ca-certificates && \
rm -rf /var/lib/apt/lists/*
# We use bookworm since the icu dependency ver. between the base and golang images is the same
FROM golang:1.26.2-bookworm AS build-from-source
ENV DEBIAN_FRONTEND=noninteractive
ARG DOLT_VERSION
# COPY doesn't support conditionals, so we rely on the path context to maybe have a dolt/ directory
# to distinguish between source and binary builds using DOLT_VERSION=source too.
COPY dolt*/go*/go.mod* /tmp/dolt/go/
WORKDIR /tmp/dolt/go/
# Check for source to avoid unnecessary installation of build dependencies
RUN if [ "$DOLT_VERSION" = "source" ]; then \
cd /tmp/dolt/go || { echo "Make sure the `dolt/` directory exists in your workspace to build from source."; exit 1; }; \
apt-get update -y && \
apt-get install -y libicu-dev && \
rm -rf /var/lib/apt/lists/*; \
fi
# Separate layers to avoid redundant downloads
RUN if [ "$DOLT_VERSION" = "source" ]; then \
go mod download; \
fi
COPY dolt*/go/ /tmp/dolt/go/
RUN if [ "$DOLT_VERSION" = "source" ]; then \
go build -o /usr/local/bin/dolt ./cmd/dolt && \
chmod +x /usr/local/bin/dolt; \
fi
FROM base AS download-binary
ARG DOLT_VERSION
RUN if [ "$DOLT_VERSION" = "latest" ]; then \
# Fetch latest version number from GitHub API
DOLT_VERSION=$(curl -s https://api.github.com/repos/dolthub/dolt/releases/latest \
| grep '"tag_name"' \
| cut -d'"' -f4 \
| sed 's/^v//'); \
fi && \
if [ "$DOLT_VERSION" != "source" ]; then \
curl -L "https://github.com/dolthub/dolt/releases/download/v${DOLT_VERSION}/install.sh" | bash; \
fi
FROM base AS runtime
ARG DOLT_VERSION
RUN apt-get update -y && apt-get install -y --no-install-recommends bzip2 gzip xz-utils zstd \
&& rm -rf /var/lib/apt/lists/*
# icu dependency for source builds
RUN if [ "$DOLT_VERSION" = "source" ]; then \
apt-get update -y && \
apt-get install -y --no-install-recommends libicu-dev && \
rm -rf /var/lib/apt/lists/*; \
fi
# Only one binary is possible due to DOLT_VERSION, so we optionally copy from either stage
COPY --from=download-binary /usr/local/bin/dolt* /usr/local/bin/
COPY --from=build-from-source /usr/local/bin/dolt* /usr/local/bin/
RUN /usr/local/bin/dolt version
RUN mkdir /docker-entrypoint-initdb.d && \
mkdir -p /var/lib/dolt && \
chmod 755 /var/lib/dolt
COPY docker*/docker-entrypoint*.sh /usr/local/bin/
COPY dolt*/docker*/docker-entrypoint*.sh /usr/local/bin/
RUN chmod +x /usr/local/bin/docker-entrypoint.sh
VOLUME /var/lib/dolt
EXPOSE 3306 33060 7007
WORKDIR /var/lib/dolt
ENTRYPOINT ["tini", "--", "docker-entrypoint.sh"]
+184
View File
@@ -0,0 +1,184 @@
# Dolt is Git for Data!
[Dolt](https://doltdb.com) is a SQL database that you can fork, clone, branch, merge, push
and pull just like a Git repository. Connect to Dolt just like any
MySQL database to run queries or update the data using SQL
commands. Use the command line interface to import CSV files, commit
your changes, push them to a remote, or merge your teammate's changes.
All the commands you know for Git work exactly the same for Dolt. Git
versions files, Dolt versions tables. It's like Git and MySQL had a
baby.
We also built [DoltHub](https://www.dolthub.com), a place to share
Dolt databases. We host public data for free. If you want to host
your own version of DoltHub, we have [DoltLab](https://www.doltlab.com). If you want us to run a Dolt server for you, we have [Hosted Dolt](https://hosted.doltdb.com).
[Join us on Discord](https://discord.com/invite/RFwfYpu) to say hi and
ask questions, or [check out our roadmap](https://dolthub.com/docs/other/roadmap)
to see what we're building next.
## What's it for?
Lots of things! Dolt is a generally useful tool with countless
applications. But if you want some ideas, [here's how people are using
it so far](https://www.dolthub.com/blog/2022-07-11-dolt-case-studies/).
# Dolt CLI
The `dolt` CLI has the same commands as `git`, with some extras.
```
$ dolt
Valid commands for dolt are
init - Create an empty Dolt data repository.
status - Show the working tree status.
add - Add table changes to the list of staged table changes.
diff - Diff a table.
reset - Remove table changes from the list of staged table changes.
clean - Remove untracked tables from working set.
commit - Record changes to the repository.
sql - Run a SQL query against tables in repository.
sql-server - Start a MySQL-compatible server.
sql-client - Starts a built-in MySQL client.
log - Show commit logs.
branch - Create, list, edit, delete branches.
checkout - Checkout a branch or overwrite a table from HEAD.
merge - Merge a branch.
conflicts - Commands for viewing and resolving merge conflicts.
cherry-pick - Apply the changes introduced by an existing commit.
revert - Undo the changes introduced in a commit.
clone - Clone from a remote data repository.
fetch - Update the database from a remote data repository.
pull - Fetch from a dolt remote data repository and merge.
push - Push to a dolt remote.
config - Dolt configuration.
remote - Manage set of tracked repositories.
backup - Manage a set of server backups.
login - Login to a dolt remote host.
creds - Commands for managing credentials.
ls - List tables in the working set.
schema - Commands for showing and importing table schemas.
table - Commands for copying, renaming, deleting, and exporting tables.
tag - Create, list, delete tags.
blame - Show what revision and author last modified each row of a table.
constraints - Commands for handling constraints.
migrate - Executes a database migration to use the latest Dolt data format.
read-tables - Fetch table(s) at a specific commit into a new dolt repo
gc - Cleans up unreferenced data from the repository.
filter-branch - Edits the commit history using the provided query.
merge-base - Find the common ancestor of two commits.
version - Displays the current Dolt cli version.
dump - Export all tables in the working set into a file.
```
Learn more about Dolt use cases, configuration and guides to use dolt on our [documentation page](https://dolthub.com/docs/introduction/what-is-dolt).
# How to use this image
This image is for Dolt SQL Server, which is similar to the MySQL Docker image. Running this image without any arguments
is equivalent to running `dolt sql-server --host 0.0.0.0 --port 3306` command inside a Docker container.
To see all supported options for `dolt sql-server`, you can run the image with `--help` flag.
```shell
$ docker run dolthub/dolt-sql-server:latest --help
```
## Building the image
To build this image from source, use the `serverDockerfile`:
*WARNING* When building from source you cannot have any other folders that start with dolt in the same directory as
your workspace folder. This is because we use a wildcard to conditionally copy the dolt source folder into
the image. Other folders starting with dolt could cause the build to fail.
```shell
# Build with the latest Dolt version (automatically fetches the latest release)
$ docker build -f docker/serverDockerfile --build-arg DOLT_VERSION=latest -t dolt-sql-server:latest .
# Build with a specific Dolt version
$ docker build -f docker/serverDockerfile --build-arg DOLT_VERSION=1.59.7 -t dolt-sql-server:1.59.7 .
# Note: To run the local build replace `dolthub/dolt-sql-server:latest` with `dolt-sql-server:latest`
```
## Building from Source
To build from your local source code instead of downloading a pre-built binary:
```shell
# Build from local source code (requires workspace directory with source dependencies, e.g., dolt_workspace/)
$ docker build -f dolt/docker/serverDockerfile --build-arg DOLT_VERSION=source -t dolt-sql-server:source .
# Note: This should contain dolt/ at the minimum, any other repos need to be
# added via COPY in serverDockerfile.
$ docker run -e DOLT_ROOT_PASSWORD=secret2 -e DOLT_ROOT_HOST=% -p 3307:3306 dolt-sql-server:source
```
### Connect to the server in the container from the host system
From the host system, to connect to a server running in a container, we need to map a port on the host system to the port our sql-server is running on in the container.
We also need a user account that has permission to connect to the server
from the host system's address. By default, as of Dolt version 1.46.0, the `root` superuser is configured to only allow connections from localhost. This is a security feature to prevent unauthorized access to the server. If you don't want to log in to the container and then connect to your sql-server, you can use the `DOLT_ROOT_HOST` and `DOLT_ROOT_PASSWORD` environment variables to control how the `root` superuser is initialized. When the Docker container is started, it will ensure the `root` superuser is configured according to those environment variables.
In our example below, we're using `DOLT_ROOT_HOST` to override the host of the `root` superuser account to `%` in order to allow any host to connect to our server and log in as `root`. We're also using `DOLT_ROOT_PASSWORD` to override the default, empty password and specify a password for the `root` account. Setting a password is strongly advised for security when allowing the `root` account to connect from any host.
```bash
> docker run -e DOLT_ROOT_PASSWORD=secret2 -e DOLT_ROOT_HOST=% -p 3307:3306 dolthub/dolt-sql-server:latest
```
If we run the command above with -d or switch to a separate window we can connect with MySQL:
```bash
> mysql --host 0.0.0.0 -P 3307 -u root -p secret2
```
### Define configuration for the server
You can specify server configuration with commandline arguments, or you can use a YAML configuration file.
For commandline arguments, you can simply add arguments at the end of the docker command, as shown below.
```shell
$ docker run -p 3307:3306 dolthub/dolt-sql-server:latest -l debug --no-auto-commit
```
To use a configuration file, you can map a local directory to location in the container.
The special directory for server configuration is `/etc/dolt/servercfg.d/`. You can only have one `.yaml` configuration
file in this directory. If there are multiple, the default configuration will be used. If the location of
configuration file was `/Users/jennifer/docker/server/config.yaml`, this is how to use `-v` flag which mounts
`/Users/jennifer/docker/server/` local directory to `/etc/dolt/servercfg.d/` directory in the container.
```shell
$ docker run -p 3307:3306 -v /Users/jennifer/docker/server/:/etc/dolt/servercfg.d/ dolthub/dolt-sql-server:latest
```
The Dolt configuration and data directories can be configured similarly:
- The dolt configuration directory is `/etc/dolt/doltcfg.d/`
There should be one `.json` Dolt configuration file. It will replace the global Dolt configuration file in the
container.
- We set the location of where data to be stored to default location at `/var/lib/dolt/` in the container.
The data directory does not need to be defined in server configuration for container, but to store the data
on the host system, it can also be mounted to this default location.
```shell
$ docker run -p 3307:3306 -v /Users/jennifer/docker/databases/:/var/lib/dolt/ dolthub/dolt-sql-server:latest
```
If the run command errors out during the entrypoint process, you'll have to remove the created container from the last run.
## Environment Variables
The Dolt SQL Server image supports the following environment variables:
- `DOLT_ROOT_PASSWORD`: Sets the password for root (default: empty)
- `DOLT_ROOT_HOST`: Specifies a host for the root (default: localhost)
- `DOLT_DATABASE` / `MYSQL_DATABASE`: Creates a database with this name if it doesn't exist
- `DOLT_USER` / `MYSQL_USER`: Creates a user with this name if it doesn't exist
- `DOLT_PASSWORD` / `MYSQL_PASSWORD`: Sets the password for the user specified in `DOLT_USER`/`MYSQL_USER`
- `DOLT_USER_HOST` / `MYSQL_USER_HOST`: Specifies a host for the custom user (default: falls back to `DOLT_ROOT_HOST`, then localhost)
- `DOLT_SERVER_TIMEOUT`: Sets the server startup timeout in seconds (default: 300). A value of 0 means no timeout.
The user will be granted all privileges on the database specified by `DOLT_DATABASE`/`MYSQL_DATABASE` if provided.
+13
View File
@@ -0,0 +1,13 @@
if (( $+commands[dolt] )); then
# gen-zsh writes a file to the command line, and does not output the completion script like
# most other cli tools. For this reason, we write the file to the local directory and source it
local completion_path=${0:h}/_dolt
if [[ ! -e "$completion_path" ]]; then
# creates a completion file in the current directory
dolt gen-zsh --file="$completion_path"
fi
source "$completion_path"
compdef _dolt dolt
fi
+1
View File
@@ -0,0 +1 @@
out
+22294
View File
File diff suppressed because it is too large Load Diff
Generated Executable
+16
View File
@@ -0,0 +1,16 @@
#!/bin/bash
set -eo pipefail
script_dir=$(dirname "$0")
cd $script_dir/..
( GOOS=linux GOARCH=amd64 go list -deps -json ./cmd/dolt/. &&
GOOS=linux GOARCH=386 go list -deps -json ./cmd/dolt/. &&
GOOS=linux GOARCH=arm64 go list -deps -json ./cmd/dolt/. &&
GOOS=windows GOARCH=amd64 go list -deps -json ./cmd/dolt/. &&
GOOS=windows GOARCH=arm64 go list -deps -json ./cmd/dolt/. &&
GOOS=darwin GOARCH=amd64 go list -deps -json ./cmd/dolt/. &&
GOOS=darwin GOARCH=arm64 go list -deps -json ./cmd/dolt/.
) \
| go run ./utils/3pdeps/. > ./Godeps/LICENSES
Generated Executable
+16
View File
@@ -0,0 +1,16 @@
#!/bin/bash
set -eo pipefail
script_dir=$(dirname "$0")
cd $script_dir/..
( GOOS=linux GOARCH=amd64 go list -deps -json ./cmd/dolt/. &&
GOOS=linux GOARCH=386 go list -deps -json ./cmd/dolt/. &&
GOOS=linux GOARCH=arm64 go list -deps -json ./cmd/dolt/. &&
GOOS=windows GOARCH=amd64 go list -deps -json ./cmd/dolt/. &&
GOOS=windows GOARCH=arm64 go list -deps -json ./cmd/dolt/. &&
GOOS=darwin GOARCH=amd64 go list -deps -json ./cmd/dolt/. &&
GOOS=darwin GOARCH=arm64 go list -deps -json ./cmd/dolt/.
) \
| go run ./utils/3pdeps/. -verify ./Godeps/LICENSES
+79
View File
@@ -0,0 +1,79 @@
// Copyright 2019 Dolthub, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package cli
import (
"errors"
"os"
"github.com/dolthub/dolt/go/libraries/utils/argparser"
)
var ErrEmptyDefTuple = errors.New("empty definition tuple")
type UsagePrinter func()
// ParseArgs is used for Dolt SQL functions that are run on the server and should not exit
func ParseArgs(ap *argparser.ArgParser, args []string, usagePrinter UsagePrinter) (*argparser.ArgParseResults, error) {
apr, err := ap.Parse(args)
if err != nil {
// --help param
if usagePrinter != nil {
usagePrinter()
}
return nil, err
}
return apr, nil
}
// ParseArgsOrDie is used for CLI command that should exit after erroring.
func ParseArgsOrDie(ap *argparser.ArgParser, args []string, usagePrinter UsagePrinter) *argparser.ArgParseResults {
apr, err := ap.Parse(args)
if err != nil {
if err != argparser.ErrHelp {
PrintErrln(err.Error())
if usagePrinter != nil {
usagePrinter()
}
os.Exit(1)
}
// --help param
if usagePrinter != nil {
usagePrinter()
}
os.Exit(0)
}
return apr
}
func HelpAndUsagePrinters(cmdDoc *CommandDocumentation) (UsagePrinter, UsagePrinter) {
// TODO handle error states
longDesc, _ := cmdDoc.GetLongDesc(CliFormat)
synopsis, _ := cmdDoc.GetSynopsis(CliFormat)
return func() {
PrintHelpText(cmdDoc.CommandStr, cmdDoc.GetShortDesc(), longDesc, synopsis, cmdDoc.ArgParser)
}, func() {
PrintUsage(cmdDoc.CommandStr, synopsis, cmdDoc.ArgParser)
}
}
+88
View File
@@ -0,0 +1,88 @@
// Copyright 2020 Dolthub, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package cli
import (
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/dolthub/dolt/go/libraries/doltcore/dconfig"
)
func TestParseDate(t *testing.T) {
tests := []struct {
dateStr string
expTime time.Time
expErr bool
}{
{"1901/09/30", time.Date(1901, 9, 30, 0, 0, 0, 0, time.UTC), false},
{"2019/01/20", time.Date(2019, 1, 20, 0, 0, 0, 0, time.UTC), false},
{"2019-1-20", time.Date(2019, 1, 20, 0, 0, 0, 0, time.UTC), true},
{"2019.01.20", time.Date(2019, 1, 20, 0, 0, 0, 0, time.UTC), false},
{"2019/01/20T13:49:59", time.Date(2019, 1, 20, 13, 49, 59, 0, time.UTC), false},
{"2019-01-20T13:49:59", time.Date(2019, 1, 20, 13, 49, 59, 0, time.UTC), false},
{"2019.01.20T13:49:59", time.Date(2019, 1, 20, 13, 49, 59, 0, time.UTC), false},
{"2019.01.20T13:49", time.Date(2019, 1, 20, 13, 49, 59, 0, time.UTC), true},
{"2019.01.20T13", time.Date(2019, 1, 20, 13, 49, 59, 0, time.UTC), true},
{"2019.01", time.Date(2019, 1, 20, 13, 49, 59, 0, time.UTC), true},
}
for _, test := range tests {
t.Run(test.dateStr, func(t *testing.T) {
result, err := dconfig.ParseDate(test.dateStr)
if test.expErr {
assert.Error(t, err)
} else {
require.NoError(t, err)
assert.Equal(t, result, test.expTime)
}
})
}
}
func TestParseAuthor(t *testing.T) {
tests := []struct {
authorStr string
expName string
expEmail string
expErr bool
}{
{"Hi <hi@hi.com>", "Hi", "hi@hi.com", false},
{"John Doe <hi@hi.com>", "John Doe", "hi@hi.com", false},
{"John Doe <hi@hi.com", "John Doe", "hi@hi.com", false},
{"John Doe", "", "", true},
{"<hi@hi.com>", "", "", true},
{"", "", "", true},
{"John Doe hi@hi.com", "", "", true},
}
for _, test := range tests {
t.Run(test.authorStr, func(t *testing.T) {
author, email, err := ParseAuthor(test.authorStr)
if test.expErr {
assert.Error(t, err)
} else {
require.NoError(t, err)
assert.Equal(t, author, test.expName)
assert.Equal(t, email, test.expEmail)
}
})
}
}
+489
View File
@@ -0,0 +1,489 @@
// Copyright 2020 Dolthub, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package cli
import (
"errors"
"fmt"
"regexp"
"strings"
"github.com/dolthub/dolt/go/libraries/doltcore/dbfactory"
"github.com/dolthub/dolt/go/libraries/utils/argparser"
)
const VerboseFlag = "verbose"
// Parses the author flag for the commit method.
func ParseAuthor(authorStr string) (string, string, error) {
if len(authorStr) == 0 {
return "", "", errors.New("Option 'author' requires a value")
}
reg := regexp.MustCompile("(?m)([^)]+) \\<([^)]+)") // Regex matches Name <email
matches := reg.FindStringSubmatch(authorStr) // This function places the original string at the beginning of matches
// If name and email are provided
if len(matches) != 3 {
return "", "", errors.New("Author not formatted correctly. Use 'Name <author@example.com>' format")
}
name := matches[1]
email := strings.ReplaceAll(matches[2], ">", "")
return name, email, nil
}
var branchForceFlagDesc = "Reset {{.LessThan}}branchname{{.GreaterThan}} to {{.LessThan}}startpoint{{.GreaterThan}}, even if {{.LessThan}}branchname{{.GreaterThan}} exists already. Without {{.EmphasisLeft}}-f{{.EmphasisRight}}, {{.EmphasisLeft}}dolt branch{{.EmphasisRight}} refuses to change an existing branch. In combination with {{.EmphasisLeft}}-d{{.EmphasisRight}} (or {{.EmphasisLeft}}--delete{{.EmphasisRight}}), allow deleting the branch irrespective of its merged status. In combination with -m (or {{.EmphasisLeft}}--move{{.EmphasisRight}}), allow renaming the branch even if the new branch name already exists, the same applies for {{.EmphasisLeft}}-c{{.EmphasisRight}} (or {{.EmphasisLeft}}--copy{{.EmphasisRight}})."
// CreateCommitArgParser creates the argparser shared dolt commit cli and DOLT_COMMIT.
func CreateCommitArgParser(supportsBranchFlag bool) *argparser.ArgParser {
ap := argparser.NewArgParserWithMaxArgs("commit", 0)
ap.SupportsString(MessageArg, "m", "msg", "Use the given {{.LessThan}}msg{{.GreaterThan}} as the commit message.")
ap.SupportsFlag(AllowEmptyFlag, "", "Allow recording a commit that has the exact same data as its sole parent. This is usually a mistake, so it is disabled by default. This option bypasses that safety. Cannot be used with --skip-empty.")
ap.SupportsFlag(SkipEmptyFlag, "", "Only create a commit if there are staged changes. If no changes are staged, the call to commit is a no-op. Cannot be used with --allow-empty.")
ap.SupportsString(DateParam, "", "date", "Specify the date used in the commit. If not specified the current system time is used.")
ap.SupportsFlag(ForceFlag, "f", "Ignores any foreign key warnings and proceeds with the commit.")
ap.SupportsString(AuthorParam, "", "author", "Specify an explicit author using the standard A U Thor {{.LessThan}}author@example.com{{.GreaterThan}} format.")
ap.SupportsFlag(AllFlag, "a", "Adds all existing, changed tables (but not new tables) in the working set to the staged set.")
ap.SupportsFlag(UpperCaseAllFlag, "A", "Adds all tables and databases (including new tables) in the working set to the staged set.")
ap.SupportsFlag(AmendFlag, "", "Amend previous commit")
ap.SupportsOptionalString(SignFlag, "S", "key-id", "Sign the commit using GPG. If no key-id is provided the key-id is taken from 'user.signingkey' the in the configuration")
ap.SupportsFlag(SkipVerificationFlag, "", "Skip commit verification")
if supportsBranchFlag {
ap.SupportsString(BranchParam, "", "branch", "Commit to the specified branch instead of the current branch.")
}
return ap
}
func CreateConflictsResolveArgParser() *argparser.ArgParser {
ap := argparser.NewArgParserWithVariableArgs("conflicts resolve")
ap.SupportsFlag(OursFlag, "", "For all conflicts, take the version from our branch and resolve the conflict")
ap.SupportsFlag(TheirsFlag, "", "For all conflicts, take the version from their branch and resolve the conflict")
return ap
}
func CreateUpdateTagArgParser() *argparser.ArgParser {
ap := argparser.NewArgParserWithMaxArgs("update-tag", 3)
ap.ArgListHelp = append(ap.ArgListHelp, [2]string{"table", "The name of the table"})
ap.ArgListHelp = append(ap.ArgListHelp, [2]string{"column", "The name of the column"})
ap.ArgListHelp = append(ap.ArgListHelp, [2]string{"tag", "The new tag value"})
return ap
}
func CreateMergeArgParser() *argparser.ArgParser {
ap := argparser.NewArgParserWithMaxArgs("merge", 1)
ap.TooManyArgsErrorFunc = func(receivedArgs []string) error {
return errors.New("Error: Dolt does not support merging from multiple commits. You probably meant to checkout one and then merge from the other.")
}
ap.SupportsFlag(NoFFParam, "", "Create a merge commit even when the merge resolves as a fast-forward.")
ap.SupportsFlag(FFOnlyParam, "", "Refuse to merge unless the current HEAD is already up to date or the merge can be resolved as a fast-forward.")
ap.SupportsFlag(SquashParam, "", "Merge changes to the working set without updating the commit history")
ap.SupportsString(MessageArg, "m", "msg", "Use the given {{.LessThan}}msg{{.GreaterThan}} as the commit message.")
ap.SupportsFlag(AbortParam, "", "Abort the in-progress merge and return the working set to the state before the merge started.")
ap.SupportsFlag(CommitFlag, "", "Perform the merge and commit the result. This is the default option, but can be overridden with the --no-commit flag. Note that this option does not affect fast-forward merges, which don't create a new merge commit, and if any merge conflicts or constraint violations are detected, no commit will be attempted.")
ap.SupportsFlag(NoCommitFlag, "", "Perform the merge and stop just before creating a merge commit. Note this will not prevent a fast-forward merge; use the --no-ff arg together with the --no-commit arg to prevent both fast-forwards and merge commits.")
ap.SupportsFlag(NoEditFlag, "", "Use an auto-generated commit message when creating a merge commit. The default for interactive CLI sessions is to open an editor.")
ap.SupportsString(AuthorParam, "", "author", "Specify an explicit author using the standard A U Thor {{.LessThan}}author@example.com{{.GreaterThan}} format.")
ap.SupportsFlag(SkipVerificationFlag, "", "Skip commit verification before merge")
return ap
}
func CreateStashArgParser() *argparser.ArgParser {
ap := argparser.NewArgParserWithMaxArgs("stash", 3)
ap.SupportsFlag(IncludeUntrackedFlag, "u", "Untracked tables are also stashed.")
ap.SupportsFlag(AllFlag, "a", "All tables are stashed, including untracked and ignored tables.")
return ap
}
func CreateRebaseArgParser() *argparser.ArgParser {
ap := argparser.NewArgParserWithMaxArgs("rebase", 1)
ap.TooManyArgsErrorFunc = func(receivedArgs []string) error {
return errors.New("rebase takes at most one positional argument.")
}
ap.SupportsString(EmptyParam, "", "empty", "How to handle commits that are not empty to start, but which become empty after rebasing. Valid values are: drop (default) or keep")
ap.SupportsFlag(AbortParam, "", "Abort an interactive rebase and return the working set to the pre-rebase state")
ap.SupportsFlag(ContinueFlag, "", "Continue an interactive rebase after adjusting the rebase plan")
ap.SupportsFlag(InteractiveFlag, "i", "Start an interactive rebase")
ap.SupportsFlag(SkipVerificationFlag, "", "Skip commit verification before rebase")
return ap
}
func CreatePushArgParser() *argparser.ArgParser {
ap := argparser.NewArgParserWithVariableArgs("push")
ap.SupportsString(UserFlag, "", "user", "User name to use when authenticating with the remote. Gets password from the environment variable {{.EmphasisLeft}}DOLT_REMOTE_PASSWORD{{.EmphasisRight}}.")
ap.SupportsFlag(SetUpstreamFlag, "u", "For every branch that is up to date or successfully pushed, add upstream (tracking) reference, used by argument-less {{.EmphasisLeft}}dolt pull{{.EmphasisRight}} and other commands.")
ap.SupportsFlag(ForceFlag, "f", "Update the remote with local history, overwriting any conflicting history in the remote.")
ap.SupportsFlag(AllFlag, "", "Push all branches.")
ap.SupportsFlag(SilentFlag, "", "Suppress progress information.")
return ap
}
func CreateAddArgParser(supportsBranchFlag bool) *argparser.ArgParser {
ap := argparser.NewArgParserWithVariableArgs("add")
ap.ArgListHelp = append(ap.ArgListHelp, [2]string{"table", "Working table(s) to add to the list tables staged to be committed. The abbreviation '.' can be used to add all tables."})
ap.SupportsFlag(AllFlag, "A", "Stages any and all changes (adds, deletes, and modifications) except for ignored tables.")
ap.SupportsFlag(ForceFlag, "f", "Allow adding otherwise ignored tables.")
if supportsBranchFlag {
ap.SupportsString(BranchParam, "", "branch", "Add to the specified branch instead of the current branch.")
}
return ap
}
func CreateCloneArgParser() *argparser.ArgParser {
ap := argparser.NewArgParserWithMaxArgs("clone", 2)
ap.SupportsString(RemoteParam, "", "name", "Name of the remote to be added to the cloned database. The default is 'origin'.")
ap.SupportsString(BranchParam, "b", "branch", "The branch to be cloned. If not specified all branches will be cloned.")
ap.SupportsString(DepthFlag, "", "depth", "Clone a single branch and limit history to the given commit depth.")
ap.SupportsString("ref", "", "ref", "Git ref to use as the Dolt data ref for git remotes (default: refs/dolt/data).")
ap.SupportsString(dbfactory.AWSRegionParam, "", "region", "")
ap.SupportsValidatedString(dbfactory.AWSCredsTypeParam, "", "creds-type", "", argparser.ValidatorFromStrList(dbfactory.AWSCredsTypeParam, dbfactory.AWSCredTypes))
ap.SupportsString(dbfactory.AWSCredsFileParam, "", "file", "AWS credentials file.")
ap.SupportsString(dbfactory.AWSCredsProfile, "", "profile", "AWS profile to use.")
ap.SupportsString(dbfactory.OSSCredsFileParam, "", "file", "OSS credentials file.")
ap.SupportsString(dbfactory.OSSCredsProfile, "", "profile", "OSS profile to use.")
ap.SupportsString(UserFlag, "u", "user", "User name to use when authenticating with the remote. Gets password from the environment variable {{.EmphasisLeft}}DOLT_REMOTE_PASSWORD{{.EmphasisRight}}.")
ap.SupportsFlag(SingleBranchFlag, "", "Clone only the history leading to the tip of a single branch, either specified by --branch or the remote's HEAD (default).")
return ap
}
func CreateResetArgParser() *argparser.ArgParser {
ap := argparser.NewArgParserWithVariableArgs("reset")
ap.SupportsFlag(HardResetParam, "", "Resets the working tables and staged tables. Any changes to tracked tables in the working tree since {{.LessThan}}commit{{.GreaterThan}} are discarded.")
ap.SupportsFlag(SoftResetParam, "", "Resets HEAD to the specified revision without touching the index or the working tables.")
return ap
}
func CreateRemoteArgParser() *argparser.ArgParser {
ap := argparser.NewArgParserWithVariableArgs("remote")
ap.SupportsString("ref", "", "ref", "Git ref to use as the Dolt data ref for git remotes (default: refs/dolt/data).")
return ap
}
func CreateCleanArgParser() *argparser.ArgParser {
ap := argparser.NewArgParserWithVariableArgs("clean")
ap.SupportsFlag(DryRunFlag, "", "Tests removing untracked tables without modifying the working set.")
ap.SupportsFlag(ExcludeIgnoreRulesFlag, "x", "Do not respect dolt_ignore; remove untracked tables that match dolt_ignore. dolt_nonlocal_tables is always respected.")
return ap
}
func CreateCheckoutArgParser() *argparser.ArgParser {
ap := argparser.NewArgParserWithVariableArgs("checkout")
ap.SupportsString(CheckoutCreateBranch, "", "branch", "Create a new branch named {{.LessThan}}new_branch{{.GreaterThan}} and start it at {{.LessThan}}start_point{{.GreaterThan}}.")
ap.SupportsString(CreateResetBranch, "", "branch", "Similar to '-b'. Forcibly resets the branch to {{.LessThan}}start_point{{.GreaterThan}} if it exists.")
ap.SupportsFlag(ForceFlag, "f", "If there is any changes in working set, the force flag will wipe out the current changes and checkout the new branch.")
ap.SupportsString(TrackFlag, "t", "", "When creating a new branch, set up 'upstream' configuration.")
ap.SupportsFlag(OverwriteIgnoreFlag, "", "Silently overwrite ignored tables when switching branches (default behavior).")
ap.SupportsFlag(NoOverwriteIgnoreFlag, "", "Abort the operation when ignored tables in the working set would be overwritten by the checkout.")
return ap
}
func CreateCherryPickArgParser() *argparser.ArgParser {
ap := argparser.NewArgParserWithMaxArgs("cherrypick", 1)
ap.SupportsFlag(AbortParam, "", "Abort the current conflict resolution process, and revert all changes from the in-process cherry-pick operation.")
ap.SupportsFlag(ContinueFlag, "", "Continue the current cherry-pick operation after conflicts have been resolved.")
ap.SupportsFlag(AllowEmptyFlag, "", "Allow empty commits to be cherry-picked. "+
"Note that use of this option only keeps commits that were initially empty. "+
"Commits which become empty, due to a previous commit, will cause cherry-pick to fail.")
ap.SupportsFlag(SkipVerificationFlag, "", "Skip commit verification before cherry-pick")
ap.TooManyArgsErrorFunc = func(receivedArgs []string) error {
return errors.New("cherry-picking multiple commits is not supported yet.")
}
return ap
}
func CreateFetchArgParser() *argparser.ArgParser {
ap := argparser.NewArgParserWithVariableArgs("fetch")
ap.SupportsString(UserFlag, "", "user", "User name to use when authenticating with the remote. Gets password from the environment variable {{.EmphasisLeft}}DOLT_REMOTE_PASSWORD{{.EmphasisRight}}.")
ap.SupportsFlag(PruneFlag, "p", "After fetching, remove any remote-tracking references that don't exist on the remote.")
ap.SupportsFlag(SilentFlag, "", "Suppress progress information.")
return ap
}
func CreateRevertArgParser() *argparser.ArgParser {
ap := argparser.NewArgParserWithVariableArgs("revert")
ap.SupportsString(AuthorParam, "", "author", "Specify an explicit author using the standard A U Thor {{.LessThan}}author@example.com{{.GreaterThan}} format.")
ap.SupportsFlag(AbortParam, "", "Abort the current revert operation and return the working set to the pre-revert state.")
ap.SupportsFlag(ContinueFlag, "", "Continue the current revert operation after resolving conflicts.")
ap.ArgListHelp = append(ap.ArgListHelp, [2]string{"revision",
"The commit revisions. If multiple revisions are given, they're applied in the order given."})
return ap
}
func CreatePullArgParser() *argparser.ArgParser {
ap := argparser.NewArgParserWithMaxArgs("pull", 2)
ap.ArgListHelp = append(ap.ArgListHelp, [2]string{"remote", "The name of the remote to pull from."})
ap.ArgListHelp = append(ap.ArgListHelp, [2]string{"remoteBranch", "The name of a branch on the specified remote to be merged into the current working set."})
ap.SupportsFlag(SquashParam, "", "Merge changes to the working set without updating the commit history")
ap.SupportsFlag(NoFFParam, "", "Create a merge commit even when the merge resolves as a fast-forward.")
ap.SupportsFlag(FFOnlyParam, "", "Refuse to merge unless the current HEAD is already up to date or the merge can be resolved as a fast-forward.")
ap.SupportsFlag(ForceFlag, "f", "Update from the remote HEAD even if there are errors.")
ap.SupportsFlag(CommitFlag, "", "Perform the merge and commit the result. This is the default option, but can be overridden with the --no-commit flag. Note that this option does not affect fast-forward merges, which don't create a new merge commit, and if any merge conflicts or constraint violations are detected, no commit will be attempted.")
ap.SupportsFlag(NoCommitFlag, "", "Perform the merge and stop just before creating a merge commit. Note this will not prevent a fast-forward merge; use the --no-ff arg together with the --no-commit arg to prevent both fast-forwards and merge commits.")
ap.SupportsFlag(NoEditFlag, "", "Use an auto-generated commit message when creating a merge commit. The default for interactive CLI sessions is to open an editor.")
ap.SupportsString(UserFlag, "", "user", "User name to use when authenticating with the remote. Gets password from the environment variable {{.EmphasisLeft}}DOLT_REMOTE_PASSWORD{{.EmphasisRight}}.")
ap.SupportsFlag(PruneFlag, "p", "After fetching, remove any remote-tracking references that don't exist on the remote.")
ap.SupportsFlag(RebaseParam, "r", "After fetching, rebase the current branch on top of the upstream branch instead of merging.")
ap.SupportsFlag(SilentFlag, "", "Suppress progress information.")
ap.SupportsFlag(SkipVerificationFlag, "", "Skip commit verification before merge")
return ap
}
func createTracklessBranchArgParser() *argparser.ArgParser {
ap := argparser.NewArgParserWithVariableArgs("branch")
ap.SupportsFlag(ForceFlag, "f", branchForceFlagDesc)
ap.SupportsFlag(CopyFlag, "c", "Create a copy of a branch.")
ap.SupportsFlag(MoveFlag, "m", "Move/rename a branch")
ap.SupportsFlag(DeleteFlag, "d", "Delete a branch. The branch must be fully merged in its upstream branch.")
ap.SupportsFlag(DeleteForceFlag, "", "Shortcut for {{.EmphasisLeft}}--delete --force{{.EmphasisRight}}.")
return ap
}
func CreateBranchArgParser() *argparser.ArgParser {
ap := createTracklessBranchArgParser()
ap.SupportsFlag(TrackFlag, "t", "Set up upstream configuration for a branch. Uses current branch as default")
ap.SupportsString(SetUpstreamToFlag, "u", "", "Set upstream configuration for a branch.")
return ap
}
func CreateTagArgParser() *argparser.ArgParser {
ap := argparser.NewArgParserWithVariableArgs("tag")
ap.ArgListHelp = append(ap.ArgListHelp, [2]string{"ref", "A commit ref that the tag should point at."})
ap.SupportsString(MessageArg, "m", "msg", "Use the given {{.LessThan}}msg{{.GreaterThan}} as the tag message.")
ap.SupportsFlag(VerboseFlag, "v", "list tags along with their metadata.")
ap.SupportsFlag(DeleteFlag, "d", "Delete a tag.")
ap.SupportsString(AuthorParam, "", "author", "Specify an explicit author using the standard A U Thor {{.LessThan}}author@example.com{{.GreaterThan}} format.")
return ap
}
func CreateBackupArgParser() *argparser.ArgParser {
ap := argparser.NewArgParserWithVariableArgs("backup")
ap.ArgListHelp = append(ap.ArgListHelp, [2]string{"region", "cloud provider region associated with this backup."})
ap.ArgListHelp = append(ap.ArgListHelp, [2]string{"creds-type", "credential type. Valid options are role, env, and file. See the help section for additional details."})
ap.ArgListHelp = append(ap.ArgListHelp, [2]string{"profile", "AWS profile to use."})
ap.SupportsFlag(VerboseFlag, "v", "When printing the list of backups adds additional details.")
ap.SupportsFlag(ForceFlag, "f", "When restoring a backup, overwrite the contents of the existing database with the same name.")
ap.SupportsString("ref", "", "ref", "Git ref to use as the Dolt data ref for git remotes (default: refs/dolt/data).")
ap.SupportsString(dbfactory.AWSRegionParam, "", "region", "")
ap.SupportsValidatedString(dbfactory.AWSCredsTypeParam, "", "creds-type", "", argparser.ValidatorFromStrList(dbfactory.AWSCredsTypeParam, dbfactory.AWSCredTypes))
ap.SupportsString(dbfactory.AWSCredsFileParam, "", "file", "AWS credentials file")
ap.SupportsString(dbfactory.AWSCredsProfile, "", "profile", "AWS profile to use")
return ap
}
func CreateVerifyConstraintsArgParser(name string) *argparser.ArgParser {
ap := argparser.NewArgParserWithVariableArgs(name)
ap.SupportsFlag(AllFlag, "a", "Verifies that all rows in the database do not violate constraints instead of just rows modified or inserted in the working set.")
ap.SupportsFlag(OutputOnlyFlag, "o", "Disables writing violated constraints to the constraint violations table.")
ap.ArgListHelp = append(ap.ArgListHelp, [2]string{"table", "The table(s) to check constraints on. If omitted, checks all tables."})
return ap
}
func CreateLogArgParser(isTableFunction bool) *argparser.ArgParser {
ap := argparser.NewArgParserWithVariableArgs("log")
ap.SupportsInt(NumberFlag, "n", "num_commits", "Limit the number of commits to output.")
ap.SupportsInt(MinParentsFlag, "", "parent_count", "The minimum number of parents a commit must have to be included in the log.")
ap.SupportsFlag(MergesFlag, "", "Equivalent to min-parents == 2, this will limit the log to commits with 2 or more parents.")
ap.SupportsFlag(ParentsFlag, "", "Shows all parents of each commit in the log.")
ap.SupportsString(DecorateFlag, "", "decorate_fmt", "Shows refs next to commits. Valid options are short, full, no, and auto")
ap.SupportsStringList(NotFlag, "", "revision", "Excludes commits from revision.")
ap.SupportsFlag(AllFlag, "", "Automatically select every branch in database")
ap.SupportsFlag(ShowSignatureFlag, "", "Shows the signature of each commit.")
if isTableFunction {
ap.SupportsStringList(TablesFlag, "t", "table", "Restricts the log to commits that modified the specified tables.")
} else {
ap.SupportsFlag(OneLineFlag, "", "Shows logs in a compact format.")
ap.SupportsFlag(StatFlag, "", "Shows the diffstat for each commit.")
ap.SupportsFlag(GraphFlag, "", "Shows the commit graph.")
}
return ap
}
// Values accepted by the --decorate flag. DecorateShort trims ref prefixes,
// DecorateFull keeps refs/heads/, refs/remotes/, and refs/tags/, DecorateNo
// produces an empty refs column, and DecorateAuto resolves to DecorateShort
// on a tty and DecorateNo otherwise.
const (
DecorateAuto = "auto"
DecorateShort = "short"
DecorateFull = "full"
DecorateNo = "no"
)
// ValidateDecorateOption returns nil when |value| is accepted by the --decorate flag.
func ValidateDecorateOption(value string) error {
switch value {
case DecorateShort, DecorateFull, DecorateAuto, DecorateNo:
return nil
}
return fmt.Errorf("invalid --%s option: %q", DecorateFlag, value)
}
func CreateDiffArgParser(isTableFunction bool) *argparser.ArgParser {
ap := argparser.NewArgParserWithVariableArgs("diff")
ap.SupportsFlag(SkinnyFlag, "sk", "Shows only primary key columns and any columns with data changes.")
ap.SupportsStringList(IncludeCols, "ic", "columns", "A list of columns to include in the diff.")
if !isTableFunction { // TODO: support for table function
ap.SupportsFlag(DataFlag, "d", "Show only the data changes, do not show the schema changes (Both shown by default).")
ap.SupportsFlag(SchemaFlag, "s", "Show only the schema changes, do not show the data changes (Both shown by default).")
ap.SupportsFlag(StatFlag, "", "Show stats of data changes")
ap.SupportsFlag(SummaryFlag, "", "Show summary of data and schema changes")
ap.SupportsString(FormatFlag, "r", "result output format", "How to format diff output. Valid values are tabular, sql, json. Defaults to tabular.")
ap.SupportsString(WhereParam, "", "column", "filters columns based on values in the diff. See {{.EmphasisLeft}}dolt diff --help{{.EmphasisRight}} for details.")
ap.SupportsInt(LimitParam, "", "record_count", "limits to the first N diffs.")
ap.SupportsString(FilterParam, "", "diff_type", "filters results based on the type of change (added, modified, renamed, dropped). 'removed' is accepted as an alias for 'dropped'.")
ap.SupportsFlag(StagedFlag, "", "Show only the staged data changes.")
ap.SupportsFlag(CachedFlag, "c", "Synonym for --staged")
ap.SupportsFlag(MergeBase, "", "Uses merge base of the first commit and second commit (or HEAD if not supplied) as the first commit")
ap.SupportsString(DiffMode, "", "diff mode", "Determines how to display modified rows with tabular output. Valid values are row, line, in-place, context. Defaults to context.")
ap.SupportsFlag(ReverseFlag, "R", "Reverses the direction of the diff.")
ap.SupportsFlag(NameOnlyFlag, "", "Only shows table names.")
ap.SupportsFlag(SystemFlag, "", "Show system tables in addition to user tables")
}
return ap
}
func CreateGCArgParser() *argparser.ArgParser {
ap := argparser.NewArgParserWithMaxArgs("gc", 0)
ap.SupportsFlag(ShallowFlag, "s", "perform a fast, but incomplete garbage collection pass")
ap.SupportsFlag(FullFlag, "f", "perform a full garbage collection, including the old generation")
ap.SupportsInt(ArchiveLevelParam, "", "archive compression level", "Specify the archive compression level garbage collection results. Default is 1, Disable with 0")
ap.SupportsUint(IncrementalGCFileSize, "", "", "max size in bytes of incremental GC table files")
return ap
}
func CreateCountCommitsArgParser() *argparser.ArgParser {
ap := argparser.NewArgParserWithMaxArgs("gc", 0)
ap.SupportsString("from", "f", "commit id", "commit to start counting from")
ap.SupportsString("to", "t", "commit id", "commit to stop counting at")
return ap
}
func CreateReflogArgParser() *argparser.ArgParser {
ap := argparser.NewArgParserWithMaxArgs("reflog", 1)
ap.SupportsFlag(AllFlag, "", "Show all refs, including hidden refs, such as DoltHub workspace refs")
return ap
}
func CreateRmArgParser() *argparser.ArgParser {
ap := argparser.NewArgParserWithVariableArgs("rm")
ap.ArgListHelp = append(ap.ArgListHelp, [2]string{"table", "table(s) to remove from the list of tables staged to be committed."})
ap.SupportsFlag(CachedFlag, "", "Use this option to unstage and remove tables only from the index. Working tree tables, whether modified or not, will be left alone.") //TODO
return ap
}
func CreateCreateCommitParser() *argparser.ArgParser {
ap := argparser.NewArgParserWithMaxArgs("createchunk commit", 0)
ap.SupportsString(AuthorParam, "", "author", "Specify an explicit author using the standard A U Thor {{.LessThan}}author@example.com{{.GreaterThan}} format.")
ap.SupportsString("desc", "", "commit description", "the description in the commit")
ap.SupportsFlag(ForceFlag, "", "when used alongside --branch, allows overwriting an existing branch")
ap.SupportsRequiredString("root", "", "database root", "the root hash of the database at this commit")
ap.SupportsStringList("parents", "", "parent commits", "a list of the commit hashes of the parent commit")
ap.SupportsString(BranchParam, "", "ref to assign to", "if set, the new commit will be reachable at this ref")
return ap
}
func CreateGlobalArgParser(name string) *argparser.ArgParser {
ap := argparser.NewArgParserWithVariableArgs(name)
if name == "dolt" {
ap.SupportsString("profile", "", "profile", "The name of the profile to use when executing SQL queries. Run `dolt profile --help` for more information.")
}
ap.SupportsString("user", "u", "user", "Defines the local superuser (defaults to `root`). If the specified user exists, will take on permissions of that user.")
ap.SupportsString("password", "p", "password", "Defines the password for the user. Defaults to empty string when the user is `root`.")
ap.SupportsString("host", "", "host", "Defines the host to connect to.")
ap.SupportsString("port", "", "port", "Defines the port to connect to.")
ap.SupportsFlag("no-tls", "", "Disables TLS for the connection to remote databases.")
ap.SupportsString("data-dir", "", "data-dir", "Defines a data directory whose subdirectories should all be dolt data repositories accessible as independent databases. Defaults to the current directory.")
ap.SupportsString("doltcfg-dir", "", "doltcfg-dir", "Defines a directory that contains configuration files for dolt. Defaults to `$data-dir/.doltcfg`. Will only be created if there is a change to configuration settings.")
ap.SupportsString("privilege-file", "", "privilege-file", "Path to a file to load and store users and grants. Defaults to `$doltcfg-dir/privileges.db`. Will only be created if there is a change to privileges.")
ap.SupportsString("branch-control-file", "", "branch-control-file", "Path to a file to load and store branch control permissions. Defaults to `$doltcfg-dir/branch_control.db`. Will only be created if there is a change to branch control permissions.")
ap.SupportsString("use-db", "", "use-db", "The name of the database to use when executing SQL queries. Defaults the database of the root directory, if it exists, and the first alphabetically if not.")
ap.SupportsString("branch", "", "branch", "Name of the branch to be selected")
return ap
}
var AwsParams = []string{dbfactory.AWSRegionParam, dbfactory.AWSCredsTypeParam, dbfactory.AWSCredsFileParam, dbfactory.AWSCredsProfile}
var ossParams = []string{dbfactory.OSSCredsFileParam, dbfactory.OSSCredsProfile}
func AddAWSParams(remoteUrl string, apr *argparser.ArgParseResults, params map[string]string) error {
isAWS := strings.HasPrefix(remoteUrl, "aws")
if !isAWS {
for _, p := range AwsParams {
if _, ok := apr.GetValue(p); ok {
return fmt.Errorf("%s param is only valid for aws cloud remotes in the format aws://dynamo-table:s3-bucket/database", p)
}
}
}
for _, p := range AwsParams {
if val, ok := apr.GetValue(p); ok {
params[p] = val
}
}
return nil
}
func AddOSSParams(remoteUrl string, apr *argparser.ArgParseResults, params map[string]string) error {
isOSS := strings.HasPrefix(remoteUrl, "oss")
if !isOSS {
for _, p := range ossParams {
if _, ok := apr.GetValue(p); ok {
return fmt.Errorf("%s param is only valid for oss cloud remotes in the format oss://oss-bucket/database", p)
}
}
}
for _, p := range ossParams {
if val, ok := apr.GetValue(p); ok {
params[p] = val
}
}
return nil
}
func VerifyNoAwsParams(apr *argparser.ArgParseResults) error {
if awsParams := apr.GetValues(AwsParams...); len(awsParams) > 0 {
awsParamKeys := make([]string, 0, len(awsParams))
for k := range awsParams {
awsParamKeys = append(awsParamKeys, k)
}
keysStr := strings.Join(awsParamKeys, ",")
return fmt.Errorf("The parameters %s, are only valid for aws remotes", keysStr)
}
return nil
}
// VerifyCommitArgs validates the arguments in |apr| for `dolt commit` and returns an error
// if any validation problems were encountered.
func VerifyCommitArgs(apr *argparser.ArgParseResults) error {
if apr.Contains(AllowEmptyFlag) && apr.Contains(SkipEmptyFlag) {
return errors.New("error: cannot use both --allow-empty and --skip-empty")
}
return nil
}
+166
View File
@@ -0,0 +1,166 @@
// Copyright 2023 Dolthub, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package cli
import (
"context"
"errors"
"github.com/dolthub/go-mysql-server/sql"
"github.com/dolthub/dolt/go/cmd/dolt/errhand"
"github.com/dolthub/dolt/go/libraries/doltcore/env"
"github.com/dolthub/dolt/go/libraries/utils/argparser"
"github.com/dolthub/dolt/go/libraries/utils/filesys"
)
type LateBindQueryistResult struct {
Queryist Queryist
Context *sql.Context
IsRemote bool
Closer func()
}
type LateBindQueryistConfig struct {
EnableAutoGC bool
}
type LateBindQueryistOption func(*LateBindQueryistConfig)
// LateBindQueryist is a function that will be called the first time Queryist is needed for use. Input is a context which
// is appropriate for the call to commence. Output is a LateBindQueryistResult, which includes a Queryist, a sql.Context, and
// a closer function. It can also result in an error.
//
// The Closer function should be called when the Queryist is no longer needed. If the result is cached and returned to
// multiple callers, it should be called after the cached result itself is no longer needed.
//
// A LateBindqueryistResult includes enough information for a caller to know if it is connecting to a remote Dolt instance
// or if it running the SqlEngine locally in-process. The CliContext uses this, in addition to its own local state, to
// let a caller know if they are connected to a remote and if this is the first QueryEngine fetch of the process lifecycle.
// This is reflected in |IsRemote| and, in the case of QueryEngineResult, |IsFirstUse|.
//
// This state is useful for determining whether a command making use of the CliContext is being run within the context of
// another command. This is particularly interesting when running a \checkout in a dolt sql session. It makes sense to do
// so in the context of `dolt sql`, but not in the context of `dolt checkout` when connected to a remote server.
type LateBindQueryist func(ctx context.Context, opts ...LateBindQueryistOption) (LateBindQueryistResult, error)
// CliContexct is used to pass top level command information down to subcommands.
type CliContext interface {
// GlobalArgs returns the arguments passed before the subcommand.
GlobalArgs() *argparser.ArgParseResults
WorkingDir() filesys.Filesys
Config() *env.DoltCliConfig
QueryEngine(ctx context.Context, opts ...LateBindQueryistOption) (QueryEngineResult, error)
// Release resources associated with the CliContext, including
// any QueryEngines which were provisioned over the lifetime
// of the CliContext.
Close()
}
// NewCliContext creates a new CliContext instance. Arguments must not be nil.
func NewCliContext(args *argparser.ArgParseResults, config *env.DoltCliConfig, cwd filesys.Filesys, latebind LateBindQueryist) (CliContext, errhand.VerboseError) {
if args == nil || config == nil || cwd == nil || latebind == nil {
return nil, errhand.VerboseErrorFromError(errors.New("Invariant violated. args, config, cwd, and latebind must be non nil."))
}
return LateBindCliContext{
globalArgs: args,
config: config,
cwd: cwd,
activeContext: &QueryistContext{},
bind: latebind,
}, nil
}
type QueryistContext struct {
sqlCtx *sql.Context
qryist *Queryist
isRemote bool
close func()
}
// LateBindCliContext is a struct that implements CliContext. Its primary purpose is to wrap the global arguments and
// provide an implementation of the QueryEngine function. This instance is stateful to ensure that the Queryist is only
// created once.
type LateBindCliContext struct {
globalArgs *argparser.ArgParseResults
cwd filesys.Filesys
config *env.DoltCliConfig
activeContext *QueryistContext
bind LateBindQueryist
}
type QueryEngineResult struct {
Queryist Queryist
Context *sql.Context
// |true| if this is the first time the CliContext is returning a QueryEngineResult.
// Otherwise it will be |false|, which means this CliContext has already been used
// to retrieve a Queryist, and the Queryist coming back is the cached result.
IsFirstResult bool
IsRemote bool
}
// GlobalArgs returns the arguments passed before the subcommand.
func (lbc LateBindCliContext) GlobalArgs() *argparser.ArgParseResults {
return lbc.globalArgs
}
// QueryEngine returns a Queryist, a sql.Context, a closer function, and an error. It ensures that only one call to the
// LateBindQueryist is made, and caches the result. Note that if this is called twice, the closer function returns will
// be nil, callers should check if is nil.
func (lbc LateBindCliContext) QueryEngine(ctx context.Context, opts ...LateBindQueryistOption) (res QueryEngineResult, err error) {
if lbc.activeContext != nil && lbc.activeContext.qryist != nil && lbc.activeContext.sqlCtx != nil {
res.Queryist = *lbc.activeContext.qryist
res.Context = lbc.activeContext.sqlCtx
res.IsRemote = lbc.activeContext.isRemote
// Returning a cached result.
res.IsFirstResult = false
return res, nil
}
bindRes, err := lbc.bind(ctx, opts...)
if err != nil {
return res, err
}
lbc.activeContext.qryist = &bindRes.Queryist
lbc.activeContext.sqlCtx = bindRes.Context
lbc.activeContext.close = bindRes.Closer
lbc.activeContext.isRemote = bindRes.IsRemote
res.Queryist = bindRes.Queryist
res.Context = bindRes.Context
res.IsRemote = bindRes.IsRemote
res.IsFirstResult = true
return res, nil
}
func (lbc LateBindCliContext) Close() {
if lbc.activeContext != nil && lbc.activeContext.close != nil {
lbc.activeContext.close()
}
}
func (lbc LateBindCliContext) WorkingDir() filesys.Filesys {
return lbc.cwd
}
// Config returns the dolt config stored in CliContext
func (lbc LateBindCliContext) Config() *env.DoltCliConfig {
return lbc.config
}
var _ CliContext = LateBindCliContext{}

Some files were not shown because too many files have changed in this diff Show More