diff --git a/native/provider.cc b/native/provider.cc index 2ac6bc18..ad779f44 100644 --- a/native/provider.cc +++ b/native/provider.cc @@ -413,14 +413,14 @@ Napi::Value PactffiVerifierSetPublishOptions(const Napi::CallbackInfo& info) { std::string providerVersion = info[1].As().Utf8Value(); std::string buildUrl = info[2].As().Utf8Value(); Napi::Array providerTagsRaw = info[3].As(); - std::string providerBranch = info[4].As().Utf8Value(); + std::string providerVersionBranch = info[4].As().Utf8Value(); pactffi_verifier_set_publish_options(handles[handleId], providerVersion.c_str(), buildUrl.c_str(), &NapiArrayToCStringVector(providerTagsRaw)[0], providerTagsRaw.Length(), - providerBranch.c_str()); + providerVersionBranch.c_str()); return info.Env().Undefined(); } @@ -788,7 +788,7 @@ Napi::Value PactffiVerifierBrokerSourceWithSelectors(const Napi::CallbackInfo& i bool enablePending = info[5].As().Value(); std::string includeWipPactsSince = info[6].As().Utf8Value(); Napi::Array providerTags = info[7].As(); - std::string providerBranch = info[8].As().Utf8Value(); + std::string providerVersionBranch = info[8].As().Utf8Value(); Napi::Array consumerVersionSelectors = info[9].As(); Napi::Array consumerVersionTags = info[10].As(); @@ -805,7 +805,7 @@ Napi::Value PactffiVerifierBrokerSourceWithSelectors(const Napi::CallbackInfo& i includeWipPactsSince.c_str(), &cProviderTags[0], providerTags.Length(), - providerBranch.c_str(), + providerVersionBranch.c_str(), &cConsumerVersionSelectors[0], consumerVersionSelectors.Length(), &cConsumerVersionTags[0], diff --git a/src/ffi/types.ts b/src/ffi/types.ts index 313adf43..f8aa737f 100644 --- a/src/ffi/types.ts +++ b/src/ffi/types.ts @@ -319,7 +319,7 @@ export type FfiVerificationFunctions = { providerVersion: string, buildUrl: string, providerTags: string[], - providerBranch: string + providerVersionBranch: string ): void; pactffiVerifierSetConsumerFilters( handle: FfiVerifierHandle, @@ -342,7 +342,6 @@ export type FfiVerificationFunctions = { password: string, token: string ): void; - // pactffiVerifierBrokerSource(handle: FfiVerifierHandle): void; pactffiVerifierBrokerSourceWithSelectors( handle: FfiVerifierHandle, url: string, @@ -352,7 +351,7 @@ export type FfiVerificationFunctions = { enablePending: boolean, includeWipPactsSince: string, providerTags: string[], - providerBranch: string, + providerVersionBranch: string, consumerVersionSelectors: string[], consumerVersionTags: string[] ): void; diff --git a/src/verifier/argumentMapper/arguments.ts b/src/verifier/argumentMapper/arguments.ts index c7b2d58a..e4821081 100644 --- a/src/verifier/argumentMapper/arguments.ts +++ b/src/verifier/argumentMapper/arguments.ts @@ -35,14 +35,33 @@ export const ffiFnMapping: FnMapping< > = { pactffiVerifierAddCustomHeader: { validateAndExecute(ffi, handle, options) { + const messages: string[] = []; + if (options.customProviderHeaders) { - if (options.customProviderHeaders) { - Object.entries(options.customProviderHeaders).forEach( - ([key, value]) => { - ffi.pactffiVerifierAddCustomHeader(handle, key, value); + if (Array.isArray(options.customProviderHeaders)) { + options.customProviderHeaders.forEach((item) => { + const parts = item.split(':'); + if (parts.length !== 2) { + messages.push( + `${item} is not a valid custom header. Must be in the format 'Header-Name: Value'` + ); + } else { + ffi.pactffiVerifierAddCustomHeader(handle, parts[0], parts[1]); } - ); + }); + } else { + if (options.customProviderHeaders) { + Object.entries(options.customProviderHeaders).forEach( + ([key, value]) => { + ffi.pactffiVerifierAddCustomHeader(handle, key, value); + } + ); + } + } + if (messages.length > 0) { + return { status: FnValidationStatus.FAIL }; } + return { status: FnValidationStatus.SUCCESS }; } @@ -118,7 +137,7 @@ export const ffiFnMapping: FnMapping< opts.enablePending || false, opts.includeWipPactsSince || '', opts.providerVersionTags || [], - opts.providerBranch || '', + opts.providerVersionBranch || opts.providerBranch || '', opts.consumerVersionSelectors ? objArrayToStringArray(opts.consumerVersionSelectors) : [], @@ -139,7 +158,7 @@ export const ffiFnMapping: FnMapping< }, }, pactffiVerifierSetFilterInfo: { - validateAndExecute(ffi, handle, options) { + validateAndExecute(ffi, handle) { if ( process.env.PACT_DESCRIPTION || process.env.PACT_PROVIDER_STATE || @@ -201,7 +220,7 @@ export const ffiFnMapping: FnMapping< options.providerVersion, options.buildUrl || '', options.providerVersionTags || [], - options.providerBranch || '' + options.providerVersionBranch || options.providerBranch || '' ); return { status: FnValidationStatus.SUCCESS }; } diff --git a/src/verifier/argumentMapper/types.ts b/src/verifier/argumentMapper/types.ts index 72920394..b27bd0aa 100644 --- a/src/verifier/argumentMapper/types.ts +++ b/src/verifier/argumentMapper/types.ts @@ -12,7 +12,7 @@ export type FnObject = { }; export type FnMapping = { - [Key in keyof T]: FnArgumentMapping; + [Key in keyof T]: FnArgumentMapping; }; export enum FnValidationStatus { @@ -26,7 +26,7 @@ export type FnValidationResult = { messages?: string[]; }; -export type FnArgumentMapping = { +export type FnArgumentMapping = { validateAndExecute: ( ffi: Ffi, handle: FfiHandle, diff --git a/src/verifier/types.ts b/src/verifier/types.ts index f77c4807..3ae94626 100644 --- a/src/verifier/types.ts +++ b/src/verifier/types.ts @@ -28,7 +28,7 @@ export interface VerifierOptions { pactBrokerToken?: string; consumerVersionTags?: string[]; providerVersionTags?: string[]; - providerBranch?: string; + providerVersionBranch?: string; providerStatesSetupUrl?: string; providerStatesSetupTeardown?: boolean; providerStatesSetupBody?: boolean; @@ -41,8 +41,12 @@ export interface VerifierOptions { logLevel?: LogLevel; disableSslVerification?: boolean; buildUrl?: string; - customProviderHeaders?: CustomHeaders; + customProviderHeaders?: CustomHeaders | string[]; consumerFilters?: string[]; + /** + * @deprecated use providerVersionBranch instead + */ + providerBranch?: string; } /** These are the deprecated verifier options, removed prior to this verison, diff --git a/src/verifier/validateOptions.spec.ts b/src/verifier/validateOptions.spec.ts index db94a410..c0683910 100644 --- a/src/verifier/validateOptions.spec.ts +++ b/src/verifier/validateOptions.spec.ts @@ -351,12 +351,47 @@ describe('Verifier argument validator', () => { }); }); - context('when given customProviderHeaders that are defined', () => { - it('should pass through to the Pact Verifier', () => { + context('when given customProviderHeaders', () => { + context('using the object notation', () => { + it('should pass through to the Pact Verifier', () => { + expect(() => + validateOptions({ + providerBaseUrl: 'http://localhost', + customProviderHeaders: { my: 'header' }, + }) + ).to.not.throw(Error); + }); + }); + + context('using the legacy array notation', () => { + it('should pass through to the Pact Verifier', () => { + expect(() => + validateOptions({ + providerBaseUrl: 'http://localhost', + customProviderHeaders: ['My: Header'], + }) + ).to.not.throw(Error); + }); + + context('and the format is incorrect', () => { + it('should throw an error', () => { + expect(() => + validateOptions({ + providerBaseUrl: 'http://localhost', + customProviderHeaders: [1 as unknown as string], + }) + ).to.throw(Error); + }); + }); + }); + }); + + context('when given providerBranch', () => { + it('should not throw an error', () => { expect(() => validateOptions({ providerBaseUrl: 'http://localhost', - customProviderHeaders: { my: 'header' }, + providerVersionBranch: 'blah', }) ).to.not.throw(Error); }); diff --git a/src/verifier/validateOptions.ts b/src/verifier/validateOptions.ts index 763aabeb..43b75e3a 100644 --- a/src/verifier/validateOptions.ts +++ b/src/verifier/validateOptions.ts @@ -9,13 +9,22 @@ import { } from './types'; export const deprecatedFunction = - (_: InternalPactVerifierOptions) => + () => (_: any, property: string): boolean => { logger.warn(`${property} is deprecated and no longer has any effect`); return true; }; +export const deprecatedBy = + (preferredOption: string) => + () => + (_: any, property: string): boolean => { + logger.warn(`${property} is deprecated, use ${preferredOption} instead`); + + return true; + }; + export const incompatibleWith = (keys: (keyof InternalPactVerifierOptions)[]) => (options: InternalPactVerifierOptions) => @@ -70,15 +79,12 @@ export const requiresOneOf = export type AssertFunction = (a: any, ...args: any) => boolean; -export const wrapCheckType = - (fn: AssertFunction) => - (_: InternalPactVerifierOptions): AssertFunction => - fn; +export const wrapCheckType = (fn: AssertFunction) => (): AssertFunction => fn; const LogLevels: LogLevel[] = ['debug', 'error', 'info', 'trace', 'warn']; const logLevelValidator = - (_: InternalPactVerifierOptions) => + () => (l: LogLevel): boolean => { if (LogLevels.includes(l.toLowerCase() as LogLevel)) { l = l.toLowerCase() as LogLevel; @@ -93,8 +99,7 @@ const logLevelValidator = }; const consumerVersionSelectorValidator = - (options: InternalPactVerifierOptions) => - (l: LogLevel): boolean => { + (options: InternalPactVerifierOptions) => (): boolean => { if ( options.consumerVersionSelectors && Array.isArray(options.consumerVersionSelectors) @@ -139,8 +144,7 @@ const consumerVersionSelectorValidator = }; const consumerVersionTagsValidator = - (options: InternalPactVerifierOptions) => - (l: LogLevel): boolean => { + (options: InternalPactVerifierOptions) => (): boolean => { if (options.consumerVersionTags) { if ( !checkTypes.string(options.consumerVersionTags) && @@ -165,6 +169,19 @@ const consumerVersionTagsValidator = return true; }; +const customProviderHeadersValidator = + (options: InternalPactVerifierOptions) => (): boolean => { + if (options.customProviderHeaders) { + if (Array.isArray(options.customProviderHeaders)) { + checkTypes.assert.array.of.string(options.customProviderHeaders); + } else { + checkTypes.assert.nonEmptyObject(options.customProviderHeaders); + } + } + + return true; + }; + export type ArgumentValidationRules = { [Key in keyof T]-?: ((options: T) => AssertFunction)[]; }; @@ -175,7 +192,7 @@ export const validationRules: ArgumentValidationRules