From 3a95caef41ab6732512f00a3896fa54d2a64715d Mon Sep 17 00:00:00 2001 From: Timothy Jones Date: Wed, 15 Mar 2023 15:19:45 +1100 Subject: [PATCH 01/14] ci: Remove Ruby version update trigger --- .github/workflows/update.yml | 21 --------------------- 1 file changed, 21 deletions(-) delete mode 100644 .github/workflows/update.yml diff --git a/.github/workflows/update.yml b/.github/workflows/update.yml deleted file mode 100644 index 7cff5781..00000000 --- a/.github/workflows/update.yml +++ /dev/null @@ -1,21 +0,0 @@ -name: Update Pact Ruby Standalone - -on: - repository_dispatch: - types: - - pact-ruby-standalone-released - -jobs: - update: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - - run: | - git config --global user.email "${GITHUB_ACTOR}@users.noreply.github.com" - git config --global user.name "${GITHUB_ACTOR}" - git config pull.ff only - - - run: script/create-pr-to-update-pact-ruby-standalone.sh ${{ github.event.client_payload.version }} - env: - GITHUB_TOKEN: '${{ secrets.GITHUB_TOKEN }}' From 8e4f735c3628d7155b4451d7254a801b86b19d8a Mon Sep 17 00:00:00 2001 From: Timothy Jones Date: Wed, 15 Mar 2023 16:06:41 +1100 Subject: [PATCH 02/14] feat!: Remove the Ruby verifier and the associated CLI stubs (pact-broker, pact-message, pact-mock-service, pact-provider-verifier, pact-stub-service, pact, and pactflow). These have moved to @pact-foundation/pact-cli --- bin/pact-broker.ts | 13 ---- bin/pact-message.ts | 13 ---- bin/pact-mock-service.ts | 11 ---- bin/pact-provider-verifier.ts | 13 ---- bin/pact-stub-service.ts | 13 ---- bin/pact.ts | 13 ---- bin/pactflow.ts | 13 ---- package-lock.json | 28 ++++---- package.json | 18 ++--- ...reate-pr-to-update-pact-ruby-standalone.sh | 27 -------- script/download-libs.sh | 3 +- script/lib/download-standalone.sh | 60 ----------------- script/lib/export-binary-versions.sh | 1 - standalone/__fixtures__/.keep | 0 standalone/install.ts | 66 ------------------- 15 files changed, 20 insertions(+), 272 deletions(-) delete mode 100644 bin/pact-broker.ts delete mode 100644 bin/pact-message.ts delete mode 100644 bin/pact-mock-service.ts delete mode 100644 bin/pact-provider-verifier.ts delete mode 100644 bin/pact-stub-service.ts delete mode 100644 bin/pact.ts delete mode 100644 bin/pactflow.ts delete mode 100755 script/create-pr-to-update-pact-ruby-standalone.sh delete mode 100755 script/lib/download-standalone.sh delete mode 100644 standalone/__fixtures__/.keep delete mode 100644 standalone/install.ts diff --git a/bin/pact-broker.ts b/bin/pact-broker.ts deleted file mode 100644 index aa7bed46..00000000 --- a/bin/pact-broker.ts +++ /dev/null @@ -1,13 +0,0 @@ -#!/usr/bin/env node - -import childProcess = require('child_process'); -import rubyStandalone from '../src/pact-standalone'; - -const { status } = childProcess.spawnSync( - rubyStandalone.brokerFullPath, - process.argv.slice(2), - { - stdio: 'inherit', - } -); -process.exit(status as number); diff --git a/bin/pact-message.ts b/bin/pact-message.ts deleted file mode 100644 index c31a54ec..00000000 --- a/bin/pact-message.ts +++ /dev/null @@ -1,13 +0,0 @@ -#!/usr/bin/env node - -import childProcess = require('child_process'); -import rubyStandalone from '../src/pact-standalone'; - -const { status } = childProcess.spawnSync( - rubyStandalone.messageFullPath, - process.argv.slice(2), - { - stdio: 'inherit', - } -); -process.exit(status as number); diff --git a/bin/pact-mock-service.ts b/bin/pact-mock-service.ts deleted file mode 100644 index 15e279e0..00000000 --- a/bin/pact-mock-service.ts +++ /dev/null @@ -1,11 +0,0 @@ -#!/usr/bin/env node - -import childProcess = require('child_process'); -import rubyStandalone from '../src/pact-standalone'; - -const { status } = childProcess.spawnSync( - rubyStandalone.mockServiceFullPath, - process.argv.slice(2), - { stdio: 'inherit' } -); -process.exit(status as number); diff --git a/bin/pact-provider-verifier.ts b/bin/pact-provider-verifier.ts deleted file mode 100644 index 3d4b7dab..00000000 --- a/bin/pact-provider-verifier.ts +++ /dev/null @@ -1,13 +0,0 @@ -#!/usr/bin/env node - -import childProcess = require('child_process'); -import rubyStandalone from '../src/pact-standalone'; - -const { status } = childProcess.spawnSync( - rubyStandalone.verifierFullPath, - process.argv.slice(2), - { - stdio: 'inherit', - } -); -process.exit(status as number); diff --git a/bin/pact-stub-service.ts b/bin/pact-stub-service.ts deleted file mode 100644 index c565efae..00000000 --- a/bin/pact-stub-service.ts +++ /dev/null @@ -1,13 +0,0 @@ -#!/usr/bin/env node - -import childProcess = require('child_process'); -import rubyStandalone from '../src/pact-standalone'; - -const { status } = childProcess.spawnSync( - rubyStandalone.stubFullPath, - process.argv.slice(2), - { - stdio: 'inherit', - } -); -process.exit(status as number); diff --git a/bin/pact.ts b/bin/pact.ts deleted file mode 100644 index 34e5553f..00000000 --- a/bin/pact.ts +++ /dev/null @@ -1,13 +0,0 @@ -#!/usr/bin/env node - -import childProcess = require('child_process'); -import rubyStandalone from '../src/pact-standalone'; - -const { status } = childProcess.spawnSync( - rubyStandalone.pactFullPath, - process.argv.slice(2), - { - stdio: 'inherit', - } -); -process.exit(status as number); diff --git a/bin/pactflow.ts b/bin/pactflow.ts deleted file mode 100644 index 707158b6..00000000 --- a/bin/pactflow.ts +++ /dev/null @@ -1,13 +0,0 @@ -#!/usr/bin/env node - -import childProcess = require('child_process'); -import rubyStandalone from '../src/pact-standalone'; - -const { status } = childProcess.spawnSync( - rubyStandalone.pactflowFullPath, - process.argv.slice(2), - { - stdio: 'inherit', - } -); -process.exit(status as number); diff --git a/package-lock.json b/package-lock.json index 77cb0ca8..4d20e361 100644 --- a/package-lock.json +++ b/package-lock.json @@ -22,7 +22,6 @@ "dependencies": { "@types/needle": "2.5.2", "bindings": "^1.5.0", - "chalk": "4.1.2", "check-types": "7.3.0", "cross-spawn": "7.0.3", "mkdirp": "1.0.0", @@ -35,15 +34,6 @@ "underscore": "1.12.1", "unixify": "1.0.0" }, - "bin": { - "pact": "bin/pact.js", - "pact-broker": "bin/pact-broker.js", - "pact-message": "bin/pact-message.js", - "pact-mock-service": "bin/pact-mock-service.js", - "pact-provider-verifier": "bin/pact-provider-verifier.js", - "pact-stub-service": "bin/pact-stub-service.js", - "pactflow": "bin/pactflow.js" - }, "devDependencies": { "@grpc/grpc-js": "^1.8.0", "@grpc/proto-loader": "^0.7.3", @@ -1248,6 +1238,7 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, "dependencies": { "color-convert": "^2.0.1" }, @@ -1641,6 +1632,7 @@ "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -1717,6 +1709,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, "dependencies": { "color-name": "~1.1.4" }, @@ -1727,7 +1720,8 @@ "node_modules/color-name": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true }, "node_modules/colorette": { "version": "2.0.19", @@ -4005,6 +3999,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, "engines": { "node": ">=8" } @@ -7014,6 +7009,7 @@ "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, "dependencies": { "has-flag": "^4.0.0" }, @@ -8566,6 +8562,7 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, "requires": { "color-convert": "^2.0.1" } @@ -8864,6 +8861,7 @@ "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, "requires": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -8919,6 +8917,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, "requires": { "color-name": "~1.1.4" } @@ -8926,7 +8925,8 @@ "color-name": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true }, "colorette": { "version": "2.0.19", @@ -10663,7 +10663,8 @@ "has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true }, "has-property-descriptors": { "version": "1.0.0", @@ -12908,6 +12909,7 @@ "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, "requires": { "has-flag": "^4.0.0" } diff --git a/package.json b/package.json index ae0b99ba..b8e62007 100644 --- a/package.json +++ b/package.json @@ -5,15 +5,6 @@ "main": "src/index.js", "homepage": "https://github.com/pact-foundation/pact-js-core#readme", "types": "src/index.d.ts", - "bin": { - "pact": "bin/pact.js", - "pact-broker": "bin/pact-broker.js", - "pact-mock-service": "bin/pact-mock-service.js", - "pact-stub-service": "bin/pact-stub-service.js", - "pact-provider-verifier": "bin/pact-provider-verifier.js", - "pact-message": "bin/pact-message.js", - "pactflow": "bin/pactflow.js" - }, "os": [ "darwin", "linux", @@ -54,7 +45,6 @@ "dependencies": { "@types/needle": "2.5.2", "bindings": "^1.5.0", - "chalk": "4.1.2", "check-types": "7.3.0", "cross-spawn": "7.0.3", "mkdirp": "1.0.0", @@ -123,18 +113,18 @@ "typescript": "4.7.4" }, "scripts": { - "clean": "rimraf '{src,test,bin,standalone}/**/*.{js,map,d.ts}' 'package.zip' '.tmp' 'tmp'", + "clean": "rimraf '{src,test}/**/*.{js,map,d.ts}' 'package.zip' '.tmp' 'tmp'", "lint": "eslint . --ext .ts --config .eslintrc", "lint:fix": "npm run lint -- --fix", "prebuild": "npm run clean && bash script/download-libs.sh", "build": "tsc --project tsconfig.build.json", "prerelease": "npm run snyk-protect", "release": "standard-version", - "test": "cross-env LOGLEVEL=debug PACT_DO_NOT_TRACK=true mocha \"{src,test,bin,standalone}/**/*.spec.ts\"", + "test": "cross-env LOGLEVEL=debug PACT_DO_NOT_TRACK=true mocha \"{src,bin}/**/*.spec.ts\"", "snyk-protect": "snyk protect", "format:base": "prettier --parser typescript", - "format:check": "npm run format:base -- --list-different \"{src,standalone,bin,test}/**/*.{ts,tsx}\"", - "format:fix": "npm run format:base -- --write \"{src,standalone,bin,test}/**/*.{ts,tsx}\"", + "format:check": "npm run format:base -- --list-different \"{src,test}/**/*.{ts,tsx}\"", + "format:fix": "npm run format:base -- --write \"{src,test}/**/*.{ts,tsx}\"", "postinstall": "npm run native", "native": "node-gyp rebuild -v" }, diff --git a/script/create-pr-to-update-pact-ruby-standalone.sh b/script/create-pr-to-update-pact-ruby-standalone.sh deleted file mode 100755 index 50341b91..00000000 --- a/script/create-pr-to-update-pact-ruby-standalone.sh +++ /dev/null @@ -1,27 +0,0 @@ -#!/bin/sh - -set -e - -: "${1?Please supply the pact-ruby-standalone version to upgrade to}" - -STANDALONE_VERSION=$1 -TYPE=${2:-fix} -DASHERISED_VERSION=$(echo "${STANDALONE_VERSION}" | sed 's/\./\-/g') -BRANCH_NAME="chore/upgrade-to-pact-ruby-standalone-${DASHERISED_VERSION}" - -git checkout master -git checkout standalone/install.ts -git pull origin master - -git checkout -b ${BRANCH_NAME} - -cat standalone/install.ts | sed "s/export const PACT_STANDALONE_VERSION.*/export const PACT_STANDALONE_VERSION = '${STANDALONE_VERSION}';/" > tmp-install -mv tmp-install standalone/install.ts - -git add standalone/install.ts -git commit -m "${TYPE}: update standalone to ${STANDALONE_VERSION}" -git push --set-upstream origin ${BRANCH_NAME} - -hub pull-request --message "${TYPE}: update standalone to ${STANDALONE_VERSION}" - -git checkout master diff --git a/script/download-libs.sh b/script/download-libs.sh index a94f09b5..d37ebd2c 100755 --- a/script/download-libs.sh +++ b/script/download-libs.sh @@ -2,5 +2,4 @@ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")"; pwd)" # Figure out where the script is running . "${SCRIPT_DIR}/lib/export-binary-versions.sh" -"${SCRIPT_DIR}/lib/download-ffi.sh" -"${SCRIPT_DIR}/lib/download-standalone.sh" \ No newline at end of file +"${SCRIPT_DIR}/lib/download-ffi.sh" \ No newline at end of file diff --git a/script/lib/download-standalone.sh b/script/lib/download-standalone.sh deleted file mode 100755 index aa81df37..00000000 --- a/script/lib/download-standalone.sh +++ /dev/null @@ -1,60 +0,0 @@ -#!/bin/bash -eu -LIB_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")"; pwd)" # Figure out where the script is running -. "${LIB_DIR}/robust-bash.sh" -. "${LIB_DIR}/download-file.sh" - -require_binary curl -require_binary unzip -require_env_var STANDALONE_VERSION - -BASEURL=https://github.com/pact-foundation/pact-ruby-standalone/releases/download -STANDALONE_DIR="${LIB_DIR}/../../standalone" - -function download_standalone { - if [ -z "${1:-}" ]; then - error "${FUNCNAME[0]} requires the filename to download from" - exit 1 - fi - - if [ -z "${2:-}" ]; then - error "${FUNCNAME[0]} requires the filename to save the download in" - exit 1 - fi - STANDALONE_FILENAME="$2" - - URL="${BASEURL}/v${STANDALONE_VERSION}/${1}" - DOWNLOAD_LOCATION="$STANDALONE_DIR/${STANDALONE_FILENAME}" - - - log "Downloading standalone version $STANDALONE_VERSION to $DOWNLOAD_LOCATION" - download_to "$URL" "$DOWNLOAD_LOCATION" - if [ "${STANDALONE_FILENAME%zip}" != "${STANDALONE_FILENAME}" ]; then - unzip -qo "$DOWNLOAD_LOCATION" -d "${DOWNLOAD_LOCATION%.*}" - rm "${DOWNLOAD_LOCATION}" - else - mkdir -p "${DOWNLOAD_LOCATION%.tar.gz}" - tar -xf "$DOWNLOAD_LOCATION" -C "${DOWNLOAD_LOCATION%.tar.gz}" - rm "${DOWNLOAD_LOCATION}" - fi -} - -log "Downloading Ruby standalone ${STANDALONE_VERSION}" - -if [[ $(find "${STANDALONE_DIR}" -name "*${STANDALONE_VERSION}") ]]; then - log "Skipping download of Ruby standalone, as it exists" - exit 0 -fi - -download_standalone "pact-${STANDALONE_VERSION}-win32.zip" "win32-${STANDALONE_VERSION}.zip" - -if [ -z "${ONLY_DOWNLOAD_PACT_FOR_WINDOWS:-}" ]; then - download_standalone "pact-${STANDALONE_VERSION}-osx.tar.gz" "darwin-${STANDALONE_VERSION}.tar.gz" - download_standalone "pact-${STANDALONE_VERSION}-linux-x86_64.tar.gz" "linux-x64-${STANDALONE_VERSION}.tar.gz" -fi - -# Write readme in the ffi folder -cat << EOF > "$STANDALONE_DIR/README.md" -# Standalone binaries - -This folder is automatically populated during build by /script/download-standalone.sh -EOF diff --git a/script/lib/export-binary-versions.sh b/script/lib/export-binary-versions.sh index 066d2464..9cc2b95f 100644 --- a/script/lib/export-binary-versions.sh +++ b/script/lib/export-binary-versions.sh @@ -2,5 +2,4 @@ LIB_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")"; pwd)" # Figure out where the script is running PROJECT_DIR="${LIB_DIR}"/../../ -export STANDALONE_VERSION=$(grep "PACT_STANDALONE_VERSION = '" "$PROJECT_DIR"/standalone/install.ts | grep -E -o "'(.*)'" | cut -d"'" -f2) export FFI_VERSION=v$(grep "PACT_FFI_VERSION = '" "$PROJECT_DIR"/src/ffi/index.ts | grep -E -o "'(.*)'" | cut -d"'" -f2) \ No newline at end of file diff --git a/standalone/__fixtures__/.keep b/standalone/__fixtures__/.keep deleted file mode 100644 index e69de29b..00000000 diff --git a/standalone/install.ts b/standalone/install.ts deleted file mode 100644 index 78bee06a..00000000 --- a/standalone/install.ts +++ /dev/null @@ -1,66 +0,0 @@ -import chalk = require('chalk'); - -// Get latest version from https://github.com/pact-foundation/pact-ruby-standalone/releases -export const PACT_STANDALONE_VERSION = '1.91.0'; - -function makeError(msg: string): Error { - return new Error(chalk.red(`Error while locating pact binary: ${msg}`)); -} - -export function createConfig(): Config { - const CHECKSUM_SUFFIX = '.checksum'; - - return { - binaries: [ - { - platform: 'win32', - binary: `pact-${PACT_STANDALONE_VERSION}-win32.zip`, - binaryChecksum: `pact-${PACT_STANDALONE_VERSION}-win32.zip${CHECKSUM_SUFFIX}`, - folderName: `win32-${PACT_STANDALONE_VERSION}`, - }, - { - platform: 'darwin', - binary: `pact-${PACT_STANDALONE_VERSION}-osx.tar.gz`, - binaryChecksum: `pact-${PACT_STANDALONE_VERSION}-osx.tar.gz${CHECKSUM_SUFFIX}`, - folderName: `darwin-${PACT_STANDALONE_VERSION}`, - }, - { - platform: 'linux', - arch: 'x64', - binary: `pact-${PACT_STANDALONE_VERSION}-linux-x86_64.tar.gz`, - binaryChecksum: `pact-${PACT_STANDALONE_VERSION}-linux-x86_64.tar.gz${CHECKSUM_SUFFIX}`, - folderName: `linux-x64-${PACT_STANDALONE_VERSION}`, - }, - ], - }; -} - -const CONFIG = createConfig(); - -export function getBinaryEntry( - platform: string = process.platform, - arch: string = process.arch -): BinaryEntry { - const found = CONFIG.binaries.find( - (value) => - value.platform === platform && (value.arch ? value.arch === arch : true) - ); - if (found === undefined) { - throw makeError( - `Cannot find binary for platform '${platform}' with architecture '${arch}'.` - ); - } - return found; -} - -export interface Config { - binaries: BinaryEntry[]; -} - -export interface BinaryEntry { - platform: string; - arch?: string; - binary: string; - binaryChecksum: string; - folderName: string; -} From e7778dacf5428282080ba7b3feaf5447a4968fb3 Mon Sep 17 00:00:00 2001 From: Timothy Jones Date: Wed, 15 Mar 2023 16:08:37 +1100 Subject: [PATCH 03/14] fix: Remove check for windows long paths as it was only relevant to the Ruby binaries --- src/pact.ts | 20 -------------------- 1 file changed, 20 deletions(-) diff --git a/src/pact.ts b/src/pact.ts index 2c6da4dc..b5e7a19b 100644 --- a/src/pact.ts +++ b/src/pact.ts @@ -1,7 +1,4 @@ -import * as path from 'path'; import * as _ from 'underscore'; -import mkdirp = require('mkdirp'); -import rimraf = require('rimraf'); import serverFactory, { Server, ServerOptions } from './server'; import stubFactory, { Stub, StubOptions } from './stub'; import verifierFactory from './verifier'; @@ -9,7 +6,6 @@ import { VerifierOptions } from './verifier/types'; import messageFactory from './message'; import publisherFactory from './publisher'; import canDeployFactory from './can-deploy'; -import pactEnvironment from './pact-environment'; import logger, { setLogLevel } from './logger'; import { LogLevel } from './logger/types'; import { MessageOptions, PublisherOptions } from './types'; @@ -23,22 +19,6 @@ export class Pact { constructor() { // Check to see if we hit into Windows Long Path issue - if (pactEnvironment.isWindows()) { - try { - // Trying to trigger windows error by creating path that's over 260 characters long - const name = - 'Jctyo0NXwbPN6Y1o8p2TkicKma2kfqmXwVLw6ypBX47uktBPX9FM9kbPraQXsAUZuT6BvenTbnWczXzuN4js0KB9e7P5cccxvmXPYcFhJnBvPSKGH1FlTqEOsjl8djk3md'; - const dir = mkdirp.sync(path.resolve(__dirname, name, name)); - if (dir) { - rimraf.sync(dir); - } - } catch { - logger.warn( - 'WARNING: Windows Long Paths is not enabled and might cause Pact to crash if the path is too long. ' + - 'To fix this issue, please consult https://github.com/pact-foundation/pact-js-core#enable-long-paths`' - ); - } - } // Listen for Node exiting or someone killing the process // Must remove all the instances of Pact mock service From e9f569b5a72279b522a21ad18809279acfe54be1 Mon Sep 17 00:00:00 2001 From: Timothy Jones Date: Wed, 15 Mar 2023 16:25:48 +1100 Subject: [PATCH 04/14] feat!: Remove all classes that were backed by the Ruby implementation (Publisher; Message; Server; AbstractService; Stub; CanDeploy; CannotDeployError). Also remove the Pact() methods that called them (createServer; listServer; removeAllServers; createStub; listStub; createMessage; publishPacts). If you need these features, please use @pact-foundation/pact-cli --- package.json | 2 +- src/can-deploy/CannotDeployError.ts | 11 - src/can-deploy/can-deploy.spec.ts | 270 -------------------- src/can-deploy/can-deploy.ts | 169 ------------- src/can-deploy/index.ts | 6 - src/can-deploy/types.ts | 29 --- src/index.spec.ts | 2 - src/index.ts | 9 - src/message.spec.ts | 142 ----------- src/message.ts | 110 --------- src/pact-standalone.spec.ts | 234 ------------------ src/pact-standalone.ts | 70 ------ src/pact.spec.ts | 228 ----------------- src/pact.ts | 144 ----------- src/publisher.spec.ts | 134 ---------- src/publisher.ts | 151 ------------ src/server.spec.ts | 370 ---------------------------- src/server.ts | 111 --------- src/service.ts | 347 -------------------------- src/spawn/arguments.spec.ts | 168 ------------- src/spawn/arguments.ts | 77 ------ src/spawn/index.ts | 5 - src/spawn/spawn.ts | 87 ------- src/stub.spec.ts | 230 ----------------- src/stub.ts | 50 ---- src/types.ts | 37 --- test/publisher.integration.spec.ts | 179 -------------- 27 files changed, 1 insertion(+), 3371 deletions(-) delete mode 100644 src/can-deploy/CannotDeployError.ts delete mode 100644 src/can-deploy/can-deploy.spec.ts delete mode 100644 src/can-deploy/can-deploy.ts delete mode 100644 src/can-deploy/index.ts delete mode 100644 src/can-deploy/types.ts delete mode 100644 src/message.spec.ts delete mode 100644 src/message.ts delete mode 100644 src/pact-standalone.spec.ts delete mode 100644 src/pact-standalone.ts delete mode 100644 src/publisher.spec.ts delete mode 100644 src/publisher.ts delete mode 100644 src/server.spec.ts delete mode 100644 src/server.ts delete mode 100644 src/service.ts delete mode 100644 src/spawn/arguments.spec.ts delete mode 100644 src/spawn/arguments.ts delete mode 100644 src/spawn/index.ts delete mode 100644 src/spawn/spawn.ts delete mode 100644 src/stub.spec.ts delete mode 100644 src/stub.ts delete mode 100644 test/publisher.integration.spec.ts diff --git a/package.json b/package.json index b8e62007..93a6b95f 100644 --- a/package.json +++ b/package.json @@ -120,7 +120,7 @@ "build": "tsc --project tsconfig.build.json", "prerelease": "npm run snyk-protect", "release": "standard-version", - "test": "cross-env LOGLEVEL=debug PACT_DO_NOT_TRACK=true mocha \"{src,bin}/**/*.spec.ts\"", + "test": "cross-env LOGLEVEL=debug PACT_DO_NOT_TRACK=true mocha \"{src,test}/**/*.spec.ts\"", "snyk-protect": "snyk protect", "format:base": "prettier --parser typescript", "format:check": "npm run format:base -- --list-different \"{src,test}/**/*.{ts,tsx}\"", diff --git a/src/can-deploy/CannotDeployError.ts b/src/can-deploy/CannotDeployError.ts deleted file mode 100644 index 6d8ff64b..00000000 --- a/src/can-deploy/CannotDeployError.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { CanDeployResponse } from './types'; - -export class CannotDeployError extends Error { - output: CanDeployResponse | string; - - constructor(output: CanDeployResponse | string) { - super('can-i-deploy result: it is not safe to deploy'); - this.name = 'CannotDeployError'; - this.output = output; - } -} diff --git a/src/can-deploy/can-deploy.spec.ts b/src/can-deploy/can-deploy.spec.ts deleted file mode 100644 index 3659c961..00000000 --- a/src/can-deploy/can-deploy.spec.ts +++ /dev/null @@ -1,270 +0,0 @@ -import * as path from 'path'; -import * as fs from 'fs'; -import * as chai from 'chai'; -import chaiAsPromised from 'chai-as-promised'; -import * as http from 'http'; -import * as rimraf from 'rimraf'; -import * as mkdirp from 'mkdirp'; - -import canDeployFactory, { CanDeploy } from './can-deploy'; -import { CanDeployOptions } from './types'; -import logger from '../logger'; -import brokerMock from '../../test/integration/broker-mock'; - -const { expect } = chai; -chai.use(chaiAsPromised); - -describe('CanDeploy Spec', () => { - const PORT = Math.floor(Math.random() * 999) + 9000; - let server: http.Server; - let absolutePath: string; - let relativePath: string; - - before(() => - brokerMock(PORT).then((s) => { - logger.debug(`Pact Broker Mock listening on port: ${PORT}`); - server = s; - }) - ); - - after(() => server.close()); - - beforeEach(() => { - relativePath = `.tmp/${Math.floor(Math.random() * 1000)}`; - absolutePath = path.resolve(__dirname, '..', relativePath); - mkdirp.sync(absolutePath); - }); - - afterEach(() => { - if (fs.existsSync(absolutePath)) { - rimraf.sync(absolutePath); - } - }); - - describe('convertForSpawnBinary helper function', () => { - it('produces an array of SpawnArguments', () => { - const value = { pactBroker: 'some broker', pacticipants: [] }; - const result = CanDeploy.convertForSpawnBinary(value); - expect(result).to.be.an('array'); - expect(result.length).to.be.equal(1); - expect(result).to.be.deep.equal([{ pactBroker: 'some broker' }]); - }); - - it('has version and participant in the right order', () => { - const result = CanDeploy.convertForSpawnBinary({ - pacticipants: [{ version: 'v2', name: 'one' }], - pactBroker: 'some broker', - pactBrokerUsername: 'username', - pactBrokerPassword: 'password', - }); - - expect(result).to.eql([ - { - pactBroker: 'some broker', - pactBrokerUsername: 'username', - pactBrokerPassword: 'password', - }, - { name: 'one' }, - { version: 'v2' }, - ]); - }); - - it('has latest tag and participant in the right order', () => { - const result = CanDeploy.convertForSpawnBinary({ - pacticipants: [{ name: 'two', latest: 'SOME_TAG' }], - pactBroker: 'some broker', - }); - - expect(result).to.eql([ - { - pactBroker: 'some broker', - }, - { name: 'two' }, - { latest: 'SOME_TAG' }, - ]); - }); - - it("understands 'true' for latest", () => { - const result = CanDeploy.convertForSpawnBinary({ - pacticipants: [{ name: 'two', latest: true }], - pactBroker: 'some broker', - }); - - expect(result).to.eql([ - { - pactBroker: 'some broker', - }, - { name: 'two' }, - { latest: 'PACT_NODE_NO_VALUE' }, - ]); - }); - }); - - context('when invalid options are set', () => { - it('should fail with an Error when not given pactBroker', () => { - expect(() => canDeployFactory({} as CanDeployOptions)).to.throw(Error); - }); - - it('should fail with an error when there are no paticipants', () => { - expect(() => - canDeployFactory({ - pactBroker: 'http://localhost', - pacticipants: [], - }) - ).to.throw(Error); - }); - }); - - context('when valid options are set', () => { - it('should return a CanDeploy object when given the correct arguments', () => { - const c = canDeployFactory({ - pactBroker: 'http://localhost', - pacticipants: [{ name: 'two', version: '2' }], - }); - expect(c).to.be.ok; - expect(c.canDeploy).to.be.a('function'); - }); - }); - - context('candeploy function', () => { - it('should return success with a table result deployable true', (done) => { - const opts: CanDeployOptions = { - pactBroker: `http://localhost:${PORT}`, - pacticipants: [{ name: 'Foo', version: '4' }], - }; - const ding = canDeployFactory(opts); - - ding.canDeploy().then((results) => { - expect(results).not.to.be.null; - done(); - }); - }); - - context('with latest true', () => { - it('should return success with a table result deployable true', (done) => { - const opts: CanDeployOptions = { - pactBroker: `http://localhost:${PORT}`, - pacticipants: [{ name: 'Foo', latest: true }], - }; - const ding = canDeployFactory(opts); - - ding.canDeploy().then((results) => { - expect(results).not.to.be.null; - done(); - }); - }); - - it('should throw an error with a table result deployable false', () => { - const opts: CanDeployOptions = { - pactBroker: `http://localhost:${PORT}`, - pacticipants: [{ name: 'FooFail', latest: true }], - }; - const ding = canDeployFactory(opts); - - return ding - .canDeploy() - .then(() => expect.fail()) - .catch((message) => expect(message).not.be.null); - }); - }); - - context('with latest a string', () => { - it('should return success with a table result deployable true', (done) => { - const opts: CanDeployOptions = { - pactBroker: `http://localhost:${PORT}`, - pacticipants: [{ name: 'Foo', latest: 'tag' }], - }; - const ding = canDeployFactory(opts); - - ding.canDeploy().then((results) => { - expect(results).not.to.be.null; - done(); - }); - }); - - it('should throw an error with a table result deployable false', () => { - const opts: CanDeployOptions = { - pactBroker: `http://localhost:${PORT}`, - pacticipants: [{ name: 'FooFail', latest: 'tag' }], - }; - const ding = canDeployFactory(opts); - - return ding - .canDeploy() - .then(() => expect.fail()) - .catch((message) => expect(message).not.be.null); - }); - }); - - context('with latest a string, and a to', () => { - it('should return success with a table result deployable true', (done) => { - const opts: CanDeployOptions = { - pactBroker: `http://localhost:${PORT}`, - pacticipants: [{ name: 'Foo', latest: 'tag' }], - to: 'prod', - }; - const ding = canDeployFactory(opts); - - ding.canDeploy().then((results) => { - expect(results).not.to.be.null; - done(); - }); - }); - - it('should throw an error with a table result deployable false', () => { - const opts: CanDeployOptions = { - pactBroker: `http://localhost:${PORT}`, - pacticipants: [{ name: 'FooFail', latest: 'tag' }], - to: 'prod', - }; - const ding = canDeployFactory(opts); - - return ding - .canDeploy() - .then(() => expect.fail()) - .catch((message) => expect(message).not.be.null); - }); - }); - - it('should throw an error with a table result deployable false', () => { - const opts: CanDeployOptions = { - pactBroker: `http://localhost:${PORT}`, - pacticipants: [{ name: 'FooFail', version: '4' }], - }; - const ding = canDeployFactory(opts); - - return ding - .canDeploy() - .then(() => expect.fail()) - .catch((message) => expect(message).not.be.null); - }); - - it('should return success with a json result deployable true', (done) => { - const opts: CanDeployOptions = { - pactBroker: `http://localhost:${PORT}`, - pacticipants: [{ name: 'Foo', version: '4' }], - output: 'json', - }; - const ding = canDeployFactory(opts); - - ding.canDeploy().then((results) => { - expect(results).not.to.be.null; - done(); - }); - }); - - it('should throw an error with a json result deployable false', () => { - const opts: CanDeployOptions = { - pactBroker: `http://localhost:${PORT}`, - pacticipants: [{ name: 'FooFail', version: '4' }], - output: 'json', - }; - const ding = canDeployFactory(opts); - - return ding - .canDeploy() - .then(() => expect.fail()) - .catch((message) => expect(message).not.be.null); - }); - }); -}); diff --git a/src/can-deploy/can-deploy.ts b/src/can-deploy/can-deploy.ts deleted file mode 100644 index 32643020..00000000 --- a/src/can-deploy/can-deploy.ts +++ /dev/null @@ -1,169 +0,0 @@ -import { timeout, TimeoutError } from 'promise-timeout'; -import * as _ from 'underscore'; -import checkTypes = require('check-types'); - -import { CanDeployOptions, CanDeployResponse } from './types'; -import logger, { verboseIsImplied } from '../logger'; -import pactStandalone from '../pact-standalone'; -import spawn, { PACT_NODE_NO_VALUE } from '../spawn'; -import { CannotDeployError } from './CannotDeployError'; - -export class CanDeploy { - public static convertForSpawnBinary( - options: CanDeployOptions - ): CanDeployOptions[] { - return _.flatten( - [_.omit(options, 'pacticipants')].concat( - options.pacticipants.map(({ name, latest, version }) => [ - { name }, - version - ? { version } - : { - latest: latest === true ? PACT_NODE_NO_VALUE : latest, - }, - ]) - ) - ); - } - - public readonly options: CanDeployOptions; - - private readonly __argMapping = { - name: '--pacticipant', - version: '--version', - latest: '--latest', - to: '--to', - pactBroker: '--broker-base-url', - pactBrokerToken: '--broker-token', - pactBrokerUsername: '--broker-username', - pactBrokerPassword: '--broker-password', - output: '--output', - verbose: '--verbose', - retryWhileUnknown: '--retry-while-unknown', - retryInterval: '--retry-interval', - }; - - constructor(passedOptions: CanDeployOptions) { - const options = { ...passedOptions }; - // Setting defaults - options.timeout = options.timeout || 60000; - if (!options.output) { - options.output = 'json'; - } - - checkTypes.assert.nonEmptyArray( - options.pacticipants, - 'Must provide at least one pacticipant' - ); - - checkTypes.assert.nonEmptyString( - options.pactBroker, - 'Must provide the pactBroker argument' - ); - - if (options.pactBrokerToken !== undefined) { - checkTypes.assert.nonEmptyString(options.pactBrokerToken); - } - if (options.pactBrokerUsername !== undefined) { - checkTypes.assert.string(options.pactBrokerUsername); - } - if (options.pactBrokerPassword !== undefined) { - checkTypes.assert.string(options.pactBrokerPassword); - } - if (options.verbose === undefined && verboseIsImplied()) { - options.verbose = true; - } - - if ( - (options.pactBrokerUsername && !options.pactBrokerPassword) || - (options.pactBrokerPassword && !options.pactBrokerUsername) - ) { - throw new Error( - 'Must provide both Pact Broker username and password. None needed if authentication on Broker is disabled.' - ); - } - - this.options = options; - } - - public canDeploy(): Promise { - logger.info( - `Asking broker at ${this.options.pactBroker} if it is possible to deploy` - ); - const canDeployPromise = new Promise( - (resolve, reject) => { - const instance = spawn.spawnBinary( - pactStandalone.brokerFullPath, - [ - { cliVerb: 'can-i-deploy' }, - ...CanDeploy.convertForSpawnBinary(this.options), - ], - this.__argMapping - ); - const output: Array = []; - if (instance.stdout && instance.stderr) { - instance.stdout.on('data', (l) => output.push(l)); - instance.stderr.on('data', (l) => output.push(l)); - } - instance.once('close', (code) => { - const result: string = output.join('\n'); - - if (this.options.output === 'json') { - try { - const startIndex = output.findIndex((l: string | Buffer) => - l.toString().startsWith('{') - ); - if (startIndex === -1) { - logger.error( - `can-i-deploy produced no json output:\n${result}` - ); - return reject(new Error(result)); - } - if (startIndex !== 0) { - logger.warn( - `can-i-deploy produced additional output: \n${output.slice( - 0, - startIndex - )}` - ); - } - const jsonPart = output.slice(startIndex).join('\n'); - - const parsed = JSON.parse(jsonPart) as CanDeployResponse; - if (code === 0 && parsed.summary.deployable) { - return resolve(parsed); - } - return reject(new CannotDeployError(parsed)); - } catch (e) { - logger.error(`can-i-deploy produced non-json output:\n${result}`); - return reject(new Error(result)); - } - } - - if (code === 0) { - logger.info(result); - return resolve(result); - } - - logger.error( - `can-i-deploy did not return success message:\n${result}` - ); - return reject(new CannotDeployError(result)); - }); - } - ); - - return timeout(canDeployPromise, this.options.timeout as number).catch( - (err: Error) => { - if (err instanceof TimeoutError) { - throw new Error( - `Timeout waiting for publication process to complete` - ); - } - throw err; - } - ); - } -} - -export default (options: CanDeployOptions): CanDeploy => new CanDeploy(options); diff --git a/src/can-deploy/index.ts b/src/can-deploy/index.ts deleted file mode 100644 index 93cb37ab..00000000 --- a/src/can-deploy/index.ts +++ /dev/null @@ -1,6 +0,0 @@ -import factory from './can-deploy'; - -export * from './can-deploy'; -export * from './CannotDeployError'; - -export default factory; diff --git a/src/can-deploy/types.ts b/src/can-deploy/types.ts deleted file mode 100644 index 6288594b..00000000 --- a/src/can-deploy/types.ts +++ /dev/null @@ -1,29 +0,0 @@ -export interface CanDeployPacticipant { - name: string; - version?: string; - latest?: string | boolean; -} - -export interface CanDeployOptions { - pacticipants: CanDeployPacticipant[]; - pactBroker: string; - pactBrokerToken?: string; - pactBrokerUsername?: string; - pactBrokerPassword?: string; - output?: 'json' | 'table'; - verbose?: boolean; - to?: string; - retryWhileUnknown?: number; - retryInterval?: number; - timeout?: number; -} - -export interface CanDeployResponse { - summary: { deployable: boolean; reason: string; unknown: number }; - matrix: Array<{ - consumer: CanDeployPacticipant; - provider: CanDeployPacticipant; - verificationResult: { verifiedAt: string; success: boolean }; - pact: { createdAt: string }; - }>; -} diff --git a/src/index.spec.ts b/src/index.spec.ts index 29d9a00b..30185d71 100644 --- a/src/index.spec.ts +++ b/src/index.spec.ts @@ -6,7 +6,5 @@ const { expect } = chai; describe('Index Spec', () => { it('Typescript import should work', () => { expect(index).to.be.ok; - expect(index.createServer).to.be.ok; - expect(index.createServer).to.be.a('function'); }); }); diff --git a/src/index.ts b/src/index.ts index 971334e9..748a2586 100644 --- a/src/index.ts +++ b/src/index.ts @@ -8,18 +8,9 @@ export default pact; export * from './verifier'; export * from './verifier/types'; -export * from './server'; - -export * from './publisher'; - export * from './logger'; export * from './logger/types'; -export * from './stub'; - -export * from './can-deploy'; -export * from './can-deploy/types'; - export * from './consumer'; export * from './consumer/types'; diff --git a/src/message.spec.ts b/src/message.spec.ts deleted file mode 100644 index 59b6d9e4..00000000 --- a/src/message.spec.ts +++ /dev/null @@ -1,142 +0,0 @@ -import chai = require('chai'); -import path = require('path'); -import chaiAsPromised = require('chai-as-promised'); -import fs = require('fs'); -import mkdirp = require('mkdirp'); -import rimraf = require('rimraf'); -import messageFactory from './message'; - -const { expect } = chai; -chai.use(chaiAsPromised); - -describe('Message Spec', () => { - const validJSON = `{ "description": "a test mesage", "content": { "name": "Mary" } }`; - - let absolutePath: string; - let relativePath: string; - beforeEach(() => { - relativePath = `.tmp/${Math.floor(Math.random() * 1000)}`; - absolutePath = path.resolve(__dirname, '..', relativePath); - mkdirp.sync(absolutePath); - }); - - afterEach(() => { - if (fs.existsSync(absolutePath)) { - rimraf.sync(absolutePath); - } - }); - - context('when invalid options are set', () => { - it('should throw an Error when not given any message content', () => { - expect(() => - messageFactory({ - consumer: 'a-consumer', - dir: absolutePath, - }) - ).to.throw(Error); - }); - - it('should throw an Error when not given a consumer', () => { - expect(() => - messageFactory({ - provider: 'a-provider', - dir: absolutePath, - content: validJSON, - }) - ).to.throw(Error); - }); - - it('should throw an Error when not given a provider', () => { - expect(() => - messageFactory({ - consumer: 'a-provider', - dir: absolutePath, - content: validJSON, - }) - ).to.throw(Error); - }); - - it('should throw an Error when given an invalid JSON document', () => { - expect(() => - messageFactory({ - consumer: 'some-consumer', - provider: 'a-provider', - dir: absolutePath, - content: `{ "unparseable" }`, - }) - ).to.throw(Error); - }); - - it('should throw an Error when not given a pact dir', () => { - expect(() => - messageFactory({ - consumer: 'a-consumer', - content: validJSON, - }) - ).to.throw(Error); - }); - }); - - context('when valid options are set', () => { - it('should return a message object when given the correct arguments', () => { - const message = messageFactory({ - consumer: 'some-consumer', - provider: 'a-provider', - dir: absolutePath, - content: validJSON, - }); - expect(message).to.be.a('object'); - expect(message).to.respondTo('createMessage'); - }); - - it('should return a promise when calling createMessage', () => { - const promise = messageFactory({ - consumer: 'some-consumer', - provider: 'a-provider', - dir: absolutePath, - content: validJSON, - }).createMessage(); - expect(promise).to.ok; - return expect(promise).to.eventually.be.fulfilled; - }); - - it("should create a new directory if the directory specified doesn't exist yet", () => { - const dir = path.resolve(absolutePath, 'create'); - return messageFactory({ - consumer: 'some-consumer', - provider: 'a-provider', - dir, - content: validJSON, - }) - .createMessage() - .then(() => expect(fs.existsSync(dir)).to.be.true); - }); - - it('should return an absolute path when a relative one is given', () => { - const dir = path.join(relativePath, 'create'); - expect( - messageFactory({ - consumer: 'some-consumer', - provider: 'a-provider', - dir, - content: validJSON, - }).options.dir - ).to.equal(path.resolve(__dirname, '..', dir)); - }); - - it('should create a new directory with a relative path', () => { - const dir = path.join(relativePath, 'create'); - return messageFactory({ - consumer: 'some-consumer', - provider: 'a-provider', - dir, - content: validJSON, - }) - .createMessage() - .then( - () => - expect(fs.existsSync(path.resolve(__dirname, '..', dir))).to.be.true - ); - }); - }); -}); diff --git a/src/message.ts b/src/message.ts deleted file mode 100644 index 6565d2ce..00000000 --- a/src/message.ts +++ /dev/null @@ -1,110 +0,0 @@ -import fs = require('fs'); -import path = require('path'); -import mkdirp = require('mkdirp'); -import checkTypes = require('check-types'); -import logger from './logger'; -import spawn, { DEFAULT_ARG } from './spawn'; -import pactStandalone from './pact-standalone'; -import { MessageOptions } from './types'; - -export class Message { - public readonly options: MessageOptions; - - private readonly __argMapping = { - pactFileWriteMode: DEFAULT_ARG, - dir: '--pact_dir', - consumer: '--consumer', - provider: '--provider', - spec: '--pact_specification_version', - }; - - constructor(passedOptions: MessageOptions = {}) { - const options = { ...passedOptions }; - options.pactFileWriteMode = options.pactFileWriteMode || 'update'; - options.spec = options.spec || 3; - - checkTypes.assert.nonEmptyString( - options.consumer || '', - 'Must provide the consumer name' - ); - checkTypes.assert.nonEmptyString( - options.provider || '', - 'Must provide the provider name' - ); - checkTypes.assert.nonEmptyString( - options.content || '', - 'Must provide message content' - ); - checkTypes.assert.nonEmptyString( - options.dir || '', - 'Must provide pact output dir' - ); - - if (options.spec) { - checkTypes.assert.number(options.spec); - checkTypes.assert.integer(options.spec); - checkTypes.assert.positive(options.spec); - } - - if (options.dir) { - options.dir = path.resolve(options.dir); - try { - fs.statSync(options.dir).isDirectory(); - } catch (e) { - mkdirp.sync(options.dir); - } - } - - if (options.content) { - try { - JSON.parse(options.content); - } catch (e) { - throw new Error( - 'Unable to parse message content to JSON, invalid json supplied' - ); - } - } - - if (options.consumer) { - checkTypes.assert.string(options.consumer); - } - - if (options.provider) { - checkTypes.assert.string(options.provider); - } - - this.options = options; - } - - public createMessage(): Promise { - logger.info(`Creating message pact`); - - return new Promise((resolve, reject) => { - const { pactFileWriteMode, content, ...restOptions } = this.options; - - const instance = spawn.spawnBinary( - pactStandalone.messageFullPath, - [{ pactFileWriteMode }, restOptions], - this.__argMapping - ); - const output: Array = []; - if (instance.stdout && instance.stderr && instance.stdin) { - instance.stdout.on('data', (l) => output.push(l)); - instance.stderr.on('data', (l) => output.push(l)); - instance.stdin.write(content); - instance.stdin.end(); - } - instance.once('close', (code) => { - const o = output.join('\n'); - logger.info(o); - - if (code === 0) { - return resolve(o); - } - return reject(o); - }); - }); - } -} - -export default (options: MessageOptions): Message => new Message(options); diff --git a/src/pact-standalone.spec.ts b/src/pact-standalone.spec.ts deleted file mode 100644 index 4d46437f..00000000 --- a/src/pact-standalone.spec.ts +++ /dev/null @@ -1,234 +0,0 @@ -import * as fs from 'fs'; -import * as path from 'path'; -import * as chai from 'chai'; -import pactEnvironment from './pact-environment'; -import { PactStandalone, standalone } from './pact-standalone'; - -const { expect } = chai; -const basePath = pactEnvironment.cwd; - -// Needs to stay a function and not an arrow function to access mocha 'this' context -describe('Pact Standalone', function forMocha() { - // Set timeout to 10 minutes because downloading binaries might take a while. - this.timeout(600000); - - let pact: PactStandalone; - - it('should return an object with cwd, file and fullPath properties that is platform specific', () => { - pact = standalone(); - expect(pact).to.be.an('object'); - expect(pact.cwd).to.be.ok; - expect(pact.brokerPath).to.contain('pact-broker'); - expect(pact.brokerFullPath).to.contain('pact-broker'); - expect(pact.mockServicePath).to.contain('pact-mock-service'); - expect(pact.mockServiceFullPath).to.contain('pact-mock-service'); - expect(pact.stubPath).to.contain('pact-stub-service'); - expect(pact.stubFullPath).to.contain('pact-stub-service'); - expect(pact.verifierPath).to.contain('pact-provider-verifier'); - expect(pact.verifierFullPath).to.contain('pact-provider-verifier'); - expect(pact.pactPath).to.contain('pact'); - expect(pact.pactFullPath).to.contain('pact'); - expect(pact.pactflowPath).to.contain('pactflow'); - expect(pact.pactflowFullPath).to.contain('pactflow'); - }); - - it("should return the base directory of the project with 'cwd' (where the package.json file is)", () => { - expect(fs.existsSync(path.resolve(pact.cwd, 'package.json'))).to.be.true; - }); - - describe('Check if OS specific files are there', () => { - if (!process.env['ONLY_DOWNLOAD_PACT_FOR_WINDOWS']) { - describe('OSX', () => { - beforeEach(() => { - pact = standalone('darwin'); - }); - - it('broker relative path', () => { - expect(fs.existsSync(path.resolve(basePath, pact.brokerPath))).to.be - .true; - }); - - it('broker full path', () => { - expect(fs.existsSync(pact.brokerFullPath)).to.be.true; - }); - - it('mock service relative path', () => { - expect(fs.existsSync(path.resolve(basePath, pact.mockServicePath))).to - .be.true; - }); - - it('mock service full path', () => { - expect(fs.existsSync(pact.mockServiceFullPath)).to.be.true; - }); - - it('stub relative path', () => { - expect(fs.existsSync(path.resolve(basePath, pact.stubPath))).to.be - .true; - }); - - it('stub full path', () => { - expect(fs.existsSync(pact.stubFullPath)).to.be.true; - }); - - it('provider verifier relative path', () => { - expect(fs.existsSync(path.resolve(basePath, pact.verifierPath))).to.be - .true; - }); - - it('provider verifier full path', () => { - expect(fs.existsSync(pact.verifierFullPath)).to.be.true; - }); - - it('pact relative path', () => { - expect(fs.existsSync(path.resolve(basePath, pact.pactPath))).to.be - .true; - }); - - it('pact full path', () => { - expect(fs.existsSync(pact.pactFullPath)).to.be.true; - }); - it('pactflow relative path', () => { - expect(fs.existsSync(path.resolve(basePath, pact.pactflowPath))).to.be - .true; - }); - - it('pactflow full path', () => { - expect(fs.existsSync(pact.pactflowFullPath)).to.be.true; - }); - }); - - describe('Linux X64', () => { - beforeEach(() => { - pact = standalone('linux', 'x64'); - }); - - it('broker relative path', () => { - expect(fs.existsSync(path.resolve(basePath, pact.brokerPath))).to.be - .true; - }); - - it('broker full path', () => { - expect(fs.existsSync(pact.brokerFullPath)).to.be.true; - }); - - it('mock service relative path', () => { - expect(fs.existsSync(path.resolve(basePath, pact.mockServicePath))).to - .be.true; - }); - - it('mock service full path', () => { - expect(fs.existsSync(pact.mockServiceFullPath)).to.be.true; - }); - - it('stub relative path', () => { - expect(fs.existsSync(path.resolve(basePath, pact.stubPath))).to.be - .true; - }); - - it('stub full path', () => { - expect(fs.existsSync(pact.stubFullPath)).to.be.true; - }); - - it('provider verifier relative path', () => { - expect(fs.existsSync(path.resolve(basePath, pact.verifierPath))).to.be - .true; - }); - - it('provider verifier full path', () => { - expect(fs.existsSync(pact.verifierFullPath)).to.be.true; - }); - - it('pact relative path', () => { - expect(fs.existsSync(path.resolve(basePath, pact.pactPath))).to.be - .true; - }); - - it('pact full path', () => { - expect(fs.existsSync(pact.pactFullPath)).to.be.true; - }); - - it('pactflow relative path', () => { - expect(fs.existsSync(path.resolve(basePath, pact.pactflowPath))).to.be - .true; - }); - - it('pactflow full path', () => { - expect(fs.existsSync(pact.pactflowFullPath)).to.be.true; - }); - }); - } - - describe('Windows', () => { - beforeEach(() => { - pact = standalone('win32'); - }); - - it("should add '.bat' to the end of the binary names", () => { - expect(pact.brokerPath).to.contain('pact-broker.bat'); - expect(pact.brokerFullPath).to.contain('pact-broker.bat'); - expect(pact.mockServicePath).to.contain('pact-mock-service.bat'); - expect(pact.mockServiceFullPath).to.contain('pact-mock-service.bat'); - expect(pact.stubPath).to.contain('pact-stub-service.bat'); - expect(pact.stubFullPath).to.contain('pact-stub-service.bat'); - expect(pact.verifierPath).to.contain('pact-provider-verifier.bat'); - expect(pact.verifierFullPath).to.contain('pact-provider-verifier.bat'); - expect(pact.pactPath).to.contain('pact.bat'); - expect(pact.pactFullPath).to.contain('pact.bat'); - expect(pact.pactflowPath).to.contain('pactflow.bat'); - expect(pact.pactflowFullPath).to.contain('pactflow.bat'); - }); - - it('broker relative path', () => { - expect(fs.existsSync(path.resolve(basePath, pact.brokerPath))).to.be - .true; - }); - - it('broker full path', () => { - expect(fs.existsSync(pact.brokerFullPath)).to.be.true; - }); - - it('mock service relative path', () => { - expect(fs.existsSync(path.resolve(basePath, pact.mockServicePath))).to - .be.true; - }); - - it('mock service full path', () => { - expect(fs.existsSync(pact.mockServiceFullPath)).to.be.true; - }); - - it('stub relative path', () => { - expect(fs.existsSync(path.resolve(basePath, pact.stubPath))).to.be.true; - }); - - it('stub full path', () => { - expect(fs.existsSync(pact.stubFullPath)).to.be.true; - }); - - it('provider verifier relative path', () => { - expect(fs.existsSync(path.resolve(basePath, pact.verifierPath))).to.be - .true; - }); - - it('provider verifier full path', () => { - expect(fs.existsSync(pact.verifierFullPath)).to.be.true; - }); - - it('pact relative path', () => { - expect(fs.existsSync(path.resolve(basePath, pact.pactPath))).to.be.true; - }); - - it('pact full path', () => { - expect(fs.existsSync(pact.pactFullPath)).to.be.true; - }); - - it('pactflow relative path', () => { - expect(fs.existsSync(path.resolve(basePath, pact.pactflowPath))).to.be - .true; - }); - - it('pactflow full path', () => { - expect(fs.existsSync(pact.pactflowPath)).to.be.true; - }); - }); - }); -}); diff --git a/src/pact-standalone.ts b/src/pact-standalone.ts deleted file mode 100644 index 94a0ccf8..00000000 --- a/src/pact-standalone.ts +++ /dev/null @@ -1,70 +0,0 @@ -import * as path from 'path'; -import { getBinaryEntry } from '../standalone/install'; -import pactEnvironment from './pact-environment'; - -export interface PactStandalone { - cwd: string; - brokerPath: string; - brokerFullPath: string; - mockServicePath: string; - mockServiceFullPath: string; - stubPath: string; - stubFullPath: string; - verifierPath: string; - verifierFullPath: string; - messagePath: string; - messageFullPath: string; - pactPath: string; - pactFullPath: string; - pactflowPath: string; - pactflowFullPath: string; -} - -export const standalone = ( - platform: string = process.platform, - arch: string = process.arch -): PactStandalone => { - const binName = (name: string): string => - `${name}${pactEnvironment.isWindows(platform) ? '.bat' : ''}`; - const mock = binName('pact-mock-service'); - const message = binName('pact-message'); - const verify = binName('pact-provider-verifier'); - const broker = binName('pact-broker'); - const stub = binName('pact-stub-service'); - const pact = binName('pact'); - const pactflow = binName('pactflow'); - const basePath = path.join( - 'standalone', - getBinaryEntry(platform, arch).folderName, - 'pact', - 'bin' - ); - - return { - cwd: pactEnvironment.cwd, - brokerPath: path.join(basePath, broker), - brokerFullPath: path.resolve(pactEnvironment.cwd, basePath, broker).trim(), - messagePath: path.join(basePath, message), - messageFullPath: path - .resolve(pactEnvironment.cwd, basePath, message) - .trim(), - mockServicePath: path.join(basePath, mock), - mockServiceFullPath: path - .resolve(pactEnvironment.cwd, basePath, mock) - .trim(), - stubPath: path.join(basePath, stub), - stubFullPath: path.resolve(pactEnvironment.cwd, basePath, stub).trim(), - pactPath: path.join(basePath, pact), - pactFullPath: path.resolve(pactEnvironment.cwd, basePath, pact).trim(), - pactflowPath: path.join(basePath, pactflow), - pactflowFullPath: path - .resolve(pactEnvironment.cwd, basePath, pactflow) - .trim(), - verifierPath: path.join(basePath, verify), - verifierFullPath: path - .resolve(pactEnvironment.cwd, basePath, verify) - .trim(), - }; -}; - -export default standalone(); diff --git a/src/pact.spec.ts b/src/pact.spec.ts index 9224bfd5..77f42cd2 100644 --- a/src/pact.spec.ts +++ b/src/pact.spec.ts @@ -1,16 +1,10 @@ import * as chai from 'chai'; -import * as path from 'path'; import chaiAsPromised from 'chai-as-promised'; -import * as fs from 'fs'; import pact from './pact'; -import { ServerOptions } from '.'; -const { expect } = chai; chai.use(chaiAsPromised); describe('Pact Spec', () => { - afterEach(() => pact.removeAllServers()); - describe('Set Log Level', () => { let originalLogLevel: any; // Reset log level after the tests @@ -46,226 +40,4 @@ describe('Pact Spec', () => { }); }); }); - - describe('Create serverFactory', () => { - let dirPath: string; - const monkeypatchFile: string = path.resolve( - __dirname, - '../test/monkeypatch.rb' - ); - - beforeEach(() => { - dirPath = path.resolve( - __dirname, - `../.tmp/${Math.floor(Math.random() * 1000)}` - ); - }); - - afterEach(() => { - try { - if (fs.statSync(dirPath).isDirectory()) { - fs.rmdirSync(dirPath); - } - } catch (e) { - /* any errors here are not a failed test */ - } - }); - - context('when no options are set', () => { - it('should use defaults and return serverFactory', () => { - const server = pact.createServer(); - expect(server).to.be.an('object'); - expect(server.options).to.be.an('object'); - expect(server.options).to.contain.all.keys([ - 'cors', - 'ssl', - 'host', - 'dir', - ]); - expect(server.start).to.be.a('function'); - expect(server.stop).to.be.a('function'); - expect(server.delete).to.be.a('function'); - }); - }); - - context('when user specifies valid options', () => { - it('should return serverFactory using specified options', () => { - const options = { - port: 9500, - host: 'localhost', - dir: dirPath, - ssl: true, - cors: true, - log: './log/log.txt', - spec: 1, - consumer: 'consumerName', - provider: 'providerName', - monkeypatch: monkeypatchFile, - }; - const server = pact.createServer(options); - expect(server).to.be.an('object'); - expect(server.options).to.be.an('object'); - expect(server.options.port).to.equal(options.port); - expect(server.options.host).to.equal(options.host); - expect(server.options.dir).to.equal(options.dir); - expect(server.options.ssl).to.equal(options.ssl); - expect(server.options.cors).to.equal(options.cors); - expect(server.options.log).to.equal(path.resolve(options.log)); - expect(server.options.spec).to.equal(options.spec); - expect(server.options.consumer).to.equal(options.consumer); - expect(server.options.provider).to.equal(options.provider); - expect(server.options.monkeypatch).to.equal(options.monkeypatch); - }); - }); - - context('when user specifies invalid port', () => { - it('should return an error on negative port number', () => { - expect(() => pact.createServer({ port: -42 })).to.throw(Error); - }); - - it('should return an error on non-integer', () => { - expect(() => { - pact.createServer({ port: 42.42 }); - }).to.throw(Error); - }); - - it('should return an error on non-number', () => { - expect(() => - pact.createServer({ port: '99' } as unknown as ServerOptions) - ).to.throw(Error); - }); - - it('should return an error on outside port range', () => { - expect(() => { - pact.createServer({ port: 99999 }); - }).to.throw(Error); - }); - }); - - context("when user specifies port that's currently in use", () => { - it('should return a port conflict error', () => { - pact.createServer({ port: 5100 }); - expect(() => pact.createServer({ port: 5100 })).to.throw(Error); - }); - }); - - context('when user specifies invalid host', () => { - it('should return an error on non-string', () => { - expect(() => - pact.createServer({ host: 12 } as unknown as ServerOptions) - ).to.throw(Error); - }); - }); - - context('when user specifies invalid pact directory', () => { - it('should create the directory for us', () => { - pact.createServer({ dir: dirPath }); - expect(fs.statSync(dirPath).isDirectory()).to.be.true; - }); - }); - - context('when user specifies invalid ssl', () => { - it('should return an error on non-boolean', () => { - expect(() => - pact.createServer({ ssl: 1 } as unknown as ServerOptions) - ).to.throw(Error); - }); - }); - - context('when user specifies invalid cors', () => { - it('should return an error on non-boolean', () => { - expect(() => - pact.createServer({ cors: 1 } as unknown as ServerOptions) - ).to.throw(Error); - }); - }); - - context('when user specifies invalid spec', () => { - it('should return an error on non-number', () => { - expect(() => - pact.createServer({ spec: '1' } as unknown as ServerOptions) - ).to.throw(Error); - }); - - it('should return an error on negative number', () => { - expect(() => { - pact.createServer({ spec: -12 }); - }).to.throw(Error); - }); - - it('should return an error on non-integer', () => { - expect(() => { - pact.createServer({ spec: 3.14 }); - }).to.throw(Error); - }); - }); - - context('when user specifies invalid consumer name', () => { - it('should return an error on non-string', () => { - expect(() => - pact.createServer({ consumer: 1234 } as unknown as ServerOptions) - ).to.throw(Error); - }); - }); - - context('when user specifies invalid provider name', () => { - it('should return an error on non-string', () => { - expect(() => - pact.createServer({ provider: 2341 } as unknown as ServerOptions) - ).to.throw(Error); - }); - }); - - context('when user specifies invalid monkeypatch', () => { - it('should return an error on invalid path', () => { - expect(() => { - pact.createServer({ monkeypatch: 'some-ruby-file.rb' }); - }).to.throw(Error); - }); - }); - }); - - describe('List servers', () => { - context('when called and there are no servers', () => { - it('should return an empty list', () => { - expect(pact.listServers()).to.be.empty; - }); - }); - - context('when called and there are servers in list', () => { - it('should return a list of all servers', () => { - pact.createServer({ port: 1234 }); - pact.createServer({ port: 1235 }); - pact.createServer({ port: 1236 }); - expect(pact.listServers()).to.have.length(3); - }); - }); - - context('when server is removed', () => { - it('should update the list', () => { - pact.createServer({ port: 1234 }); - pact.createServer({ port: 1235 }); - return pact - .createServer({ port: 1236 }) - .delete() - .then(() => expect(pact.listServers()).to.have.length(2)); - }); - }); - }); - - describe('Remove all servers', () => { - context( - 'when removeAll() is called and there are servers to remove', - () => { - it('should remove all servers', () => { - pact.createServer({ port: 1234 }); - pact.createServer({ port: 1235 }); - pact.createServer({ port: 1236 }); - return pact - .removeAllServers() - .then(() => expect(pact.listServers()).to.be.empty); - }); - } - ); - }); }); diff --git a/src/pact.ts b/src/pact.ts index b5e7a19b..6ffed0c6 100644 --- a/src/pact.ts +++ b/src/pact.ts @@ -1,162 +1,18 @@ -import * as _ from 'underscore'; -import serverFactory, { Server, ServerOptions } from './server'; -import stubFactory, { Stub, StubOptions } from './stub'; import verifierFactory from './verifier'; import { VerifierOptions } from './verifier/types'; -import messageFactory from './message'; -import publisherFactory from './publisher'; -import canDeployFactory from './can-deploy'; import logger, { setLogLevel } from './logger'; import { LogLevel } from './logger/types'; -import { MessageOptions, PublisherOptions } from './types'; -import { AbstractService } from './service'; -import { CanDeployOptions, CanDeployResponse } from './can-deploy/types'; export class Pact { - private __servers: Server[] = []; - - private __stubs: Stub[] = []; - - constructor() { - // Check to see if we hit into Windows Long Path issue - - // Listen for Node exiting or someone killing the process - // Must remove all the instances of Pact mock service - process.once('exit', () => this.removeAll()); - process.once('SIGINT', () => process.exit()); - } - public logLevel(level?: LogLevel): void { return setLogLevel(level); } - // Creates server with specified options - public createServer(options: ServerOptions = {}): Server { - if ( - options && - options.port && - _.some(this.__servers, (s: Server) => s.options.port === options.port) - ) { - const msg = `Port '${options.port}' is already in use by another process.`; - logger.error(msg); - throw new Error(msg); - } - - const server = serverFactory(options); - this.__servers.push(server); - logger.info( - `Creating Pact Server with options: \n${JSON.stringify(server.options)}` - ); - - // Listen to server delete events, to remove from server list - server.once(AbstractService.Events.DELETE_EVENT, (s: Server) => { - logger.info( - `Deleting Pact Server with options: \n${JSON.stringify(s.options)}` - ); - this.__servers = _.without(this.__servers, s); - }); - - return server; - } - - // Return arrays of all servers - public listServers(): Server[] { - return this.__servers; - } - - // Remove all the servers that have been created - // Return promise of all others - public removeAllServers(): Promise { - if (this.__servers.length === 0) { - return Promise.resolve(this.__servers); - } - - logger.info('Removing all Pact servers.'); - return Promise.all( - _.map(this.__servers, (server: Server) => server.delete()) - ); - } - - // Creates stub with specified options - public createStub(options: StubOptions = {}): Stub { - if ( - options && - options.port && - _.some(this.__stubs, (s: Stub) => s.options.port === options.port) - ) { - const msg = `Port '${options.port}' is already in use by another process.`; - logger.error(msg); - throw new Error(msg); - } - - const stub = stubFactory(options); - this.__stubs.push(stub); - logger.info( - `Creating Pact Stub with options: \n${JSON.stringify(stub.options)}` - ); - - // Listen to stub delete events, to remove from stub list - stub.once(AbstractService.Events.DELETE_EVENT, (s: Stub) => { - logger.info( - `Deleting Pact Stub with options: \n${JSON.stringify(stub.options)}` - ); - this.__stubs = _.without(this.__stubs, s); - }); - - return stub; - } - - // Return arrays of all stubs - public listStubs(): Stub[] { - return this.__stubs; - } - - // Remove all the stubs that have been created - // Return promise of all others - public removeAllStubs(): Promise { - if (this.__stubs.length === 0) { - return Promise.resolve(this.__stubs); - } - - logger.info('Removing all Pact stubs.'); - return Promise.all( - _.map(this.__stubs, (stub: Stub) => stub.delete()) - ); - } - - // Remove all the servers and stubs - public removeAll(): Promise { - return Promise.all( - _.flatten([this.removeAllStubs(), this.removeAllServers()]) - ); - // .tap(endDestination); - } - // Run the Pact Verification process public verifyPacts(options: VerifierOptions): Promise { logger.info('Verifying Pacts.'); return verifierFactory(options).verify(); } - - // Run the Message Pact creation process - public createMessage(options: MessageOptions): Promise { - logger.info('Creating Message'); - return messageFactory(options).createMessage(); - } - - // Publish Pacts to a Pact Broker - public publishPacts(options: PublisherOptions): Promise { - logger.info('Publishing Pacts to Broker'); - return publisherFactory(options).publish(); - } - - // Use can-i-deploy to determine if it is safe to deploy - public canDeploy( - options: CanDeployOptions - ): Promise { - logger.info('Checking if it it possible to deploy'); - return canDeployFactory(options).canDeploy(); - } } export default new Pact(); diff --git a/src/publisher.spec.ts b/src/publisher.spec.ts deleted file mode 100644 index dd1b78ec..00000000 --- a/src/publisher.spec.ts +++ /dev/null @@ -1,134 +0,0 @@ -import path = require('path'); -import fs = require('fs'); -import chai = require('chai'); -import chaiAsPromised = require('chai-as-promised'); -import * as http from 'http'; -import rimraf = require('rimraf'); -import mkdirp = require('mkdirp'); -import publisherFactory from './publisher'; -import logger from './logger'; -import brokerMock from '../test/integration/broker-mock'; -import { PublisherOptions } from './types'; - -const { expect } = chai; -chai.use(chaiAsPromised); - -describe('Publish Spec', () => { - const PORT = Math.floor(Math.random() * 999) + 9000; - const pactFile = path.resolve( - __dirname, - '../test/integration/me-they-success.json' - ); - let server: http.Server; - let absolutePath: string; - let relativePath: string; - - before(() => - brokerMock(PORT).then((s) => { - logger.debug(`Pact Broker Mock listening on port: ${PORT}`); - server = s; - }) - ); - - after(() => server.close()); - - beforeEach(() => { - relativePath = `.tmp/${Math.floor(Math.random() * 1000)}`; - absolutePath = path.resolve(__dirname, '..', relativePath); - mkdirp.sync(absolutePath); - }); - - afterEach(() => { - if (fs.existsSync(absolutePath)) { - rimraf.sync(absolutePath); - } - }); - - context('when invalid options are set', () => { - it('should fail with an Error when not given pactBroker', () => { - expect(() => { - publisherFactory({ - pactFilesOrDirs: [absolutePath], - consumerVersion: '1.0.0', - } as PublisherOptions); - }).to.throw(Error); - }); - - it('should fail with an Error when not given consumerVersion', () => { - expect(() => { - publisherFactory({ - pactBroker: 'http://localhost', - pactFilesOrDirs: [absolutePath], - } as PublisherOptions); - }).to.throw(Error); - }); - - it('should fail with an error when not given pactFilesOrDirs', () => { - expect(() => { - publisherFactory({ - pactBroker: 'http://localhost', - consumerVersion: '1.0.0', - } as PublisherOptions); - }).to.throw(Error); - }); - - it('should fail with an Error when given Pact paths that do not exist', () => { - expect(() => { - publisherFactory({ - pactBroker: 'http://localhost', - pactFilesOrDirs: ['test.json'], - consumerVersion: '1.0.0', - }); - }).to.throw(Error); - }); - }); - - context('when valid options are set', () => { - it('should return an absolute path when a relative one is given', () => { - expect( - publisherFactory({ - pactBroker: 'http://localhost', - pactFilesOrDirs: [relativePath], - consumerVersion: '1.0.0', - }).options.pactFilesOrDirs[0] - ).to.be.equal(path.resolve(__dirname, '..', relativePath)); - }); - - it('should return a Publisher object when given the correct arguments', () => { - const p = publisherFactory({ - pactBroker: 'http://localhost', - pactFilesOrDirs: [pactFile], - consumerVersion: '1.0.0', - }); - expect(p).to.be.ok; - expect(p.publish).to.be.a('function'); - }); - }); - - context('when a bearer token is provided', () => { - context('and specifies a username or password', () => { - it('should fail with an error', () => { - expect(() => - publisherFactory({ - pactBroker: 'http://localhost', - pactFilesOrDirs: [relativePath], - consumerVersion: '1.0.0', - pactBrokerToken: '1234', - pactBrokerUsername: 'username', - pactBrokerPassword: '5678', - }) - ).to.throw(Error); - }); - }); - it('should not fail', () => { - const p = publisherFactory({ - pactBroker: 'http://localhost', - pactFilesOrDirs: [pactFile], - consumerVersion: '1.0.0', - pactBrokerToken: '1234', - }); - expect(p).to.be.ok; - expect(p.publish).to.be.a('function'); - }); - }); -}); diff --git a/src/publisher.ts b/src/publisher.ts deleted file mode 100644 index 08824019..00000000 --- a/src/publisher.ts +++ /dev/null @@ -1,151 +0,0 @@ -import path = require('path'); -import fs = require('fs'); -import { timeout, TimeoutError } from 'promise-timeout'; -import checkTypes = require('check-types'); -import logger, { verboseIsImplied } from './logger'; -import spawn, { DEFAULT_ARG } from './spawn'; -import pactStandalone from './pact-standalone'; -import { PublisherOptions } from './types'; - -export class Publisher { - public readonly options: PublisherOptions; - - private readonly __argMapping = { - pactFilesOrDirs: DEFAULT_ARG, - pactBroker: '--broker-base-url', - pactBrokerUsername: '--broker-username', - pactBrokerPassword: '--broker-password', - pactBrokerToken: '--broker-token', - tags: '--tag', - consumerVersion: '--consumer-app-version', - verbose: '--verbose', - buildUrl: '--build-url', - branch: '--branch', - autoDetectVersionProperties: '--auto-detect-version-properties', - }; - - constructor(passedOptions: PublisherOptions) { - this.options = passedOptions || {}; - // Setting defaults - this.options.tags = this.options.tags || []; - this.options.timeout = this.options.timeout || 60000; - - checkTypes.assert.nonEmptyString( - this.options.pactBroker, - 'Must provide the pactBroker argument' - ); - checkTypes.assert.nonEmptyString( - this.options.consumerVersion, - 'Must provide the consumerVersion argument' - ); - checkTypes.assert.arrayLike( - this.options.pactFilesOrDirs, - 'Must provide the pactFilesOrDirs argument' - ); - checkTypes.assert.nonEmptyArray( - this.options.pactFilesOrDirs, - 'Must provide the pactFilesOrDirs argument with an array' - ); - - if (this.options.pactFilesOrDirs) { - checkTypes.assert.array.of.string(this.options.pactFilesOrDirs); - - // Resolve all paths as absolute paths - this.options.pactFilesOrDirs = this.options.pactFilesOrDirs.map((v) => { - const newPath = path.resolve(v); - if (!fs.existsSync(newPath)) { - throw new Error( - `Path '${v}' given in pactFilesOrDirs does not exists.` - ); - } - return newPath; - }); - } - - if (this.options.pactBroker) { - checkTypes.assert.string(this.options.pactBroker); - } - - if (this.options.pactBrokerUsername) { - checkTypes.assert.string(this.options.pactBrokerUsername); - } - - if (this.options.pactBrokerPassword) { - checkTypes.assert.string(this.options.pactBrokerPassword); - } - - if (this.options.verbose === undefined && verboseIsImplied()) { - this.options.verbose = true; - } - - if ( - (this.options.pactBrokerUsername && !this.options.pactBrokerPassword) || - (this.options.pactBrokerPassword && !this.options.pactBrokerUsername) - ) { - throw new Error( - 'Must provide both Pact Broker username and password. None needed if authentication on Broker is disabled.' - ); - } - - if ( - this.options.pactBrokerToken && - (this.options.pactBrokerUsername || this.options.pactBrokerPassword) - ) { - throw new Error( - 'Must provide pactBrokerToken or pactBrokerUsername/pactBrokerPassword but not both.' - ); - } - - if (this.options.branch) { - checkTypes.assert.string(this.options.branch); - } - - if (this.options.autoDetectVersionProperties) { - checkTypes.assert.boolean(this.options.autoDetectVersionProperties); - } - } - - public publish(): Promise { - logger.info(`Publishing pacts to broker at: ${this.options.pactBroker}`); - - return timeout( - new Promise((resolve, reject) => { - const instance = spawn.spawnBinary( - pactStandalone.brokerFullPath, - [{ cliVerb: 'publish' }, this.options], - this.__argMapping - ); - const output: Array = []; - if (instance.stderr && instance.stdout) { - instance.stdout.on('data', (l) => output.push(l)); - instance.stderr.on('data', (l) => output.push(l)); - } - instance.once('close', (code) => { - const o = output.join('\n'); - const pactUrls = /https?:\/\/.*\/pacts\/.*$/gim.exec(o); - if (code !== 0) { - const message = `Pact publication failed with non-zero exit code. Full output was:\n${o}`; - logger.error(message); - return reject(new Error(message)); - } - if (!pactUrls) { - const message = `Publication appeared to fail, as we did not detect any pact URLs in the following output:\n${o}`; - logger.error(message); - return reject(new Error(message)); - } - - logger.info(o); - return resolve(pactUrls); - }); - }), - this.options.timeout as number - ).catch((err: Error) => { - if (err instanceof TimeoutError) { - throw new Error(`Timeout waiting for publication process to complete`); - } - throw err; - }); - } -} - -export default (options: PublisherOptions): Publisher => new Publisher(options); diff --git a/src/server.spec.ts b/src/server.spec.ts deleted file mode 100644 index 3a6a8d12..00000000 --- a/src/server.spec.ts +++ /dev/null @@ -1,370 +0,0 @@ -import chai = require('chai'); -import chaiAsPromised = require('chai-as-promised'); -import fs = require('fs'); -import util = require('util'); -import path = require('path'); -import mkdirp = require('mkdirp'); -import rimraf = require('rimraf'); -import serverFactory, { ServerOptions } from './server'; - -chai.use(chaiAsPromised); -const { expect } = chai; -const rm = util.promisify(rimraf); - -describe('Server Spec', () => { - let server: any; - const monkeypatchFile: string = path.resolve( - __dirname, - '../test/monkeypatch.rb' - ); - - let absolutePath: string; - let relativePath: string; - - beforeEach(() => { - relativePath = `.tmp/${Math.floor(Math.random() * 1000)}`; - absolutePath = path.resolve(__dirname, '..', relativePath); - mkdirp.sync(absolutePath); - }); - - afterEach(async () => { - if (server) { - await server.delete(); - } - - if (fs.existsSync(absolutePath)) { - await rm(absolutePath); - } - }); - - const relativeSSLCertPath = 'test/ssl/server.crt'; - const absoluteSSLCertPath = path.resolve( - __dirname, - '..', - relativeSSLCertPath - ); - const relativeSSLKeyPath = 'test/ssl/server.key'; - const absoluteSSLKeyPath = path.resolve(__dirname, '..', relativeSSLKeyPath); - - describe('Start server', () => { - context('when no options are set', () => { - it('should start correctly with defaults', () => { - server = serverFactory(); - return expect(server.start()).to.eventually.be.fulfilled; - }); - }); - - context('when invalid options are set', () => { - it('should fail if custom ssl certs do not exist', () => { - expect(() => - serverFactory({ - ssl: true, - sslcert: 'does/not/exist', - sslkey: absoluteSSLKeyPath, - }) - ).to.throw(Error); - }); - - it('should fail if custom ssl keys do not exist', () => { - expect(() => - serverFactory({ - ssl: true, - sslcert: absoluteSSLCertPath, - sslkey: 'does/not/exist', - }) - ).to.throw(Error); - }); - - it("should fail if custom ssl cert is set, but ssl key isn't", () => { - expect(() => - serverFactory({ - ssl: true, - sslcert: absoluteSSLCertPath, - }) - ).to.throw(Error); - }); - - it("should fail if custom ssl key is set, but ssl cert isn't", () => { - expect(() => - serverFactory({ - ssl: true, - sslkey: absoluteSSLKeyPath, - }) - ).to.throw(Error); - }); - }); - - context('when valid options are set', () => { - it('should start correctly when instance is delayed', () => { - server = serverFactory(); - - const waitForServerUp = server.__waitForServiceUp.bind(server); - return expect( - Promise.all([ - waitForServerUp(server.options), - new Promise((resolve) => { - setTimeout(resolve, 5000); - }).then(() => server.start()), - ]) - ).to.eventually.be.fulfilled; - }); - - it('should start correctly with ssl', () => { - server = serverFactory({ ssl: true }); - expect(server.options.ssl).to.equal(true); - return expect(server.start()).to.eventually.be.fulfilled; - }); - - it('should start correctly with custom ssl cert/key', () => { - server = serverFactory({ - ssl: true, - sslcert: absoluteSSLCertPath, - sslkey: absoluteSSLKeyPath, - }); - expect(server.options.ssl).to.equal(true); - return expect(server.start()).to.eventually.be.fulfilled; - }); - - it('should start correctly with custom ssl cert/key but without specifying ssl flag', () => { - server = serverFactory({ - sslcert: absoluteSSLCertPath, - sslkey: absoluteSSLKeyPath, - }); - - expect(server.options.ssl).to.equal(true); - return expect(server.start()).to.eventually.be.fulfilled; - }); - - it('should start correctly with cors', () => { - server = serverFactory({ cors: true }); - expect(server.options.cors).to.equal(true); - return expect(server.start()).to.eventually.be.fulfilled; - }); - - it('should start correctly with port', () => { - const port = Math.floor(Math.random() * 999) + 9000; - server = serverFactory({ port }); - expect(server.options.port).to.equal(port); - return expect(server.start()).to.eventually.be.fulfilled; - }); - - it('should start correctly with host', () => { - const host = 'localhost'; - server = serverFactory({ host }); - expect(server.options.host).to.equal(host); - return expect(server.start()).to.eventually.be.fulfilled; - }); - - it('should start correctly with spec version 1', () => { - server = serverFactory({ spec: 1 }); - expect(server.options.spec).to.equal(1); - return expect(server.start()).to.eventually.be.fulfilled; - }); - - it('should start correctly with spec version 2', () => { - server = serverFactory({ spec: 2 }); - expect(server.options.spec).to.equal(2); - return expect(server.start()).to.eventually.be.fulfilled; - }); - - it('should start correctly with log', () => { - const logPath = path.resolve(absolutePath, 'log.txt'); - server = serverFactory({ log: logPath }); - expect(server.options.log).to.equal(logPath); - - return expect(server.start()).to.eventually.be.fulfilled; - - // return expect(server.start()).to.eventually.be.fulfilled.then( - // () => void rm(logPath), - // ); - }); - - it('should start correctly with consumer name', () => { - const consumerName = 'cName'; - server = serverFactory({ consumer: consumerName }); - expect(server.options.consumer).to.equal(consumerName); - return expect(server.start()).to.eventually.be.fulfilled; - }); - - it('should start correctly with provider name', () => { - const providerName = 'pName'; - server = serverFactory({ provider: providerName }); - expect(server.options.provider).to.equal(providerName); - return expect(server.start()).to.eventually.be.fulfilled; - }); - - it('should start correctly with monkeypatch', () => { - const s = serverFactory({ monkeypatch: monkeypatchFile }); - expect(s.options.monkeypatch).to.equal(monkeypatchFile); - return expect(s.start()).to.eventually.be.fulfilled; - }); - - context('Paths', () => { - it('should start correctly with dir, absolute path', () => { - server = serverFactory({ dir: relativePath }); - expect(server.options.dir).to.equal(absolutePath); - return expect(server.start()).to.eventually.be.fulfilled; - }); - - it('should start correctly with log, relative paths', () => { - const logPath = path.join(relativePath, 'log.txt'); - server = serverFactory({ log: logPath }); - expect(server.options.log).to.equal(path.resolve(logPath)); - return expect(server.start()).to.eventually.be.fulfilled; - }); - - it('should start correctly with custom ssl cert/key, relative paths', () => { - server = serverFactory({ - sslcert: relativeSSLCertPath, - sslkey: relativeSSLKeyPath, - }); - expect(server.options.sslcert).to.equal(absoluteSSLCertPath); - expect(server.options.sslkey).to.equal(absoluteSSLKeyPath); - return expect(server.start()).to.eventually.be.fulfilled; - }); - }); - - context('File Write Mode', () => { - it("should start correctly with 'overwrite'", () => - expect( - serverFactory({ - pactFileWriteMode: 'overwrite', - }).start() - ).to.eventually.be.fulfilled); - - it("should start correctly with 'merge'", () => - expect( - serverFactory({ - pactFileWriteMode: 'merge', - }).start() - ).to.eventually.be.fulfilled); - - it("should start correctly with 'update'", () => - expect( - serverFactory({ - pactFileWriteMode: 'update', - }).start() - ).to.eventually.be.fulfilled); - }); - - context('Log Level', () => { - it("should start correctly with 'debug'", () => - Promise.all([ - expect( - serverFactory({ - logLevel: 'debug', - }).start() - ).to.eventually.be.fulfilled, - - expect( - serverFactory({ - logLevel: 'DEBUG', - } as unknown as ServerOptions).start() - ).to.eventually.be.fulfilled, - ])); - - it("should start correctly with 'info'", () => - Promise.all([ - expect( - serverFactory({ - logLevel: 'info', - }).start() - ).to.eventually.be.fulfilled, - - expect( - serverFactory({ - logLevel: 'INFO', - } as unknown as ServerOptions).start() - ).to.eventually.be.fulfilled, - ])); - - it("should start correctly with 'warn'", () => - Promise.all([ - expect( - serverFactory({ - logLevel: 'warn', - }).start() - ).to.eventually.be.fulfilled, - - expect( - serverFactory({ - logLevel: 'WARN', - } as unknown as ServerOptions).start() - ).to.eventually.be.fulfilled, - ])); - - it("should start correctly with 'error'", () => - Promise.all([ - expect( - serverFactory({ - logLevel: 'error', - }).start() - ).to.eventually.be.fulfilled, - - expect( - serverFactory({ - logLevel: 'ERROR', - } as unknown as ServerOptions).start() - ).to.eventually.be.fulfilled, - ])); - }); - }); - - it('should dispatch event when starting', (done) => { - server = serverFactory(); - server.once('start', () => done()); - server.start(); - }); - - it('should change running state to true', () => { - server = serverFactory(); - return server.start().then(() => expect(server.__running).to.be.true); - }); - }); - - describe('Stop server', () => { - context('when already started', () => { - it('should stop running', () => { - server = serverFactory(); - return server.start().then(() => server.stop()); - }); - - it('should dispatch event when stopping', (done) => { - server = serverFactory(); - server.once('stop', () => done()); - server.start().then(() => server.stop()); - }); - - it('should change running state to false', () => { - server = serverFactory(); - return server - .start() - .then(() => server.stop()) - .then(() => expect(server.__running).to.be.false); - }); - }); - }); - - describe('Delete server', () => { - context('when already running', () => { - it('should stop & delete server', () => { - server = serverFactory(); - return server.start().then(() => server.delete()); - }); - - it('should dispatch event when deleting', (done) => { - server = serverFactory(); - server.once('delete', () => done()); - server.start().then(() => server.delete()); - }); - - it('should change running state to false', () => { - server = serverFactory(); - return server - .start() - .then(() => server.delete()) - .then(() => expect(server.__running).to.be.false); - }); - }); - }); -}); diff --git a/src/server.ts b/src/server.ts deleted file mode 100644 index 0e450e91..00000000 --- a/src/server.ts +++ /dev/null @@ -1,111 +0,0 @@ -import path = require('path'); -import fs = require('fs'); -import mkdirp = require('mkdirp'); -import checkTypes = require('check-types'); -import pact from './pact-standalone'; -import { AbstractService } from './service'; -import { LogLevel } from './logger/types'; - -export class Server extends AbstractService { - public readonly options: ServerOptions; - - constructor(passedOptions: ServerOptions = {}) { - const options = { ...passedOptions }; - options.dir = options.dir ? path.resolve(options.dir) : process.cwd(); // Use directory relative to cwd - options.pactFileWriteMode = options.pactFileWriteMode || 'overwrite'; - - if (options.spec) { - checkTypes.assert.number(options.spec); - checkTypes.assert.integer(options.spec); - checkTypes.assert.positive(options.spec); - } - - if (options.dir) { - const dir = path.resolve(options.dir); - try { - fs.statSync(dir).isDirectory(); - } catch (e) { - mkdirp.sync(dir); - } - } - - if (options.log) { - options.log = path.resolve(options.log); - } - - if (options.sslcert) { - options.sslcert = path.resolve(options.sslcert); - } - - if (options.sslkey) { - options.sslkey = path.resolve(options.sslkey); - } - - if (options.consumer) { - checkTypes.assert.string(options.consumer); - } - - if (options.provider) { - checkTypes.assert.string(options.provider); - } - - if (options.logLevel) { - options.logLevel = options.logLevel.toLowerCase() as LogLevel; - } - - if (options.monkeypatch) { - checkTypes.assert.string(options.monkeypatch); - try { - fs.statSync(path.normalize(options.monkeypatch)).isFile(); - } catch (e) { - throw new Error( - `Monkeypatch ruby file not found at path: ${options.monkeypatch}` - ); - } - } - - super( - pact.mockServiceFullPath, - options, - { - port: '--port', - host: '--host', - log: '--log', - ssl: '--ssl', - sslcert: '--sslcert', - sslkey: '--sslkey', - cors: '--cors', - dir: '--pact_dir', - spec: '--pact_specification_version', - pactFileWriteMode: '--pact-file-write-mode', - consumer: '--consumer', - provider: '--provider', - monkeypatch: '--monkeypatch', - logLevel: '--log-level', - }, - { cliVerb: 'service' } - ); - this.options = options; - } -} - -// Creates a new instance of the pact server with the specified option -export default (options?: ServerOptions): Server => new Server(options); - -export interface ServerOptions { - port?: number; - ssl?: boolean; - cors?: boolean; - dir?: string; - host?: string; - sslcert?: string; - sslkey?: string; - log?: string; - spec?: number; - consumer?: string; - provider?: string; - monkeypatch?: string; - logLevel?: LogLevel; - timeout?: number; - pactFileWriteMode?: 'overwrite' | 'update' | 'merge'; -} diff --git a/src/service.ts b/src/service.ts deleted file mode 100644 index 0304acf1..00000000 --- a/src/service.ts +++ /dev/null @@ -1,347 +0,0 @@ -/* eslint-disable no-param-reassign */ -// TODO - the param reassign behaviour is relied on, and should be fixed -import path = require('path'); -import fs = require('fs'); -import events = require('events'); -import { ChildProcess } from 'child_process'; -import { timeout, TimeoutError } from 'promise-timeout'; -import mkdirp = require('mkdirp'); -import checkTypes = require('check-types'); -import needle = require('needle'); -import spawn, { CliVerbOptions } from './spawn'; -import { LogLevel } from './logger/types'; -import logger, { setLogLevel } from './logger'; -import { HTTPConfig, ServiceOptions } from './types'; - -// Get a reference to the global setTimeout object in case it is mocked by a testing library later -const { setTimeout } = global; - -const RETRY_AMOUNT = 60; - -const getTimeout = (options: ServiceOptions): number => - options.timeout || 30000; - -const getRetryTickTime = (options: ServiceOptions): number => - Math.round(getTimeout(options) / RETRY_AMOUNT); - -interface AbstractServiceEventInterface { - START_EVENT: string; - STOP_EVENT: string; - DELETE_EVENT: string; -} - -export abstract class AbstractService extends events.EventEmitter { - public static get Events(): AbstractServiceEventInterface { - return { - START_EVENT: 'start', - STOP_EVENT: 'stop', - DELETE_EVENT: 'delete', - }; - } - - public readonly options: ServiceOptions; - - protected __argMapping: Record; - - protected __running: boolean; - - protected __instance: ChildProcess | undefined; - - protected __cliVerb?: CliVerbOptions; - - protected __serviceCommand: string; - - protected constructor( - command: string, - options: ServiceOptions, - argMapping: Record, - cliVerb?: CliVerbOptions - ) { - super(); - // Set logger first - if (options.logLevel) { - setLogLevel(options.logLevel); - // Pact-js-core's logger supports fatal and trace, - // but the ruby binary doesn't. So we map those. - if ((options.logLevel as string) === 'fatal') { - options.logLevel = 'error'; - } else if ((options.logLevel as string) === 'trace') { - options.logLevel = 'debug'; - } - - // Then need to uppercase log level for ruby - options.logLevel = options.logLevel.toUpperCase() as LogLevel; - } - // defaults - options.ssl = options.ssl || false; - options.cors = options.cors || false; - options.host = options.host || 'localhost'; - - // port checking - if (options.port) { - checkTypes.assert.number(options.port); - checkTypes.assert.integer(options.port); - checkTypes.assert.positive(options.port); - if (!checkTypes.inRange(options.port, 0, 65535)) { - throw new Error( - `Port number ${options.port} is not in the range 0-65535` - ); - } - - if (checkTypes.not.inRange(options.port, 1024, 49151)) { - logger.warn( - 'Like a Boss, you used a port outside of the recommended range (1024 to 49151); I too like to live dangerously.' - ); - } - } - - // ssl check - checkTypes.assert.boolean(options.ssl); - - // Throw error if one ssl option is set, but not the other - if ( - (options.sslcert && !options.sslkey) || - (!options.sslcert && options.sslkey) - ) { - throw new Error( - 'Custom ssl certificate and key must be specified together.' - ); - } - - // check certs/keys exist for SSL - if (options.sslcert) { - try { - fs.statSync(path.normalize(options.sslcert)).isFile(); - } catch (e) { - throw new Error( - `Custom ssl certificate not found at path: ${options.sslcert}` - ); - } - } - - if (options.sslkey) { - try { - fs.statSync(path.normalize(options.sslkey)).isFile(); - } catch (e) { - throw new Error(`Custom ssl key not found at path: ${options.sslkey}`); - } - } - - // If both sslcert and sslkey option has been specified, let's assume the user wants to enable ssl - if (options.sslcert && options.sslkey) { - options.ssl = true; - } - - // cors check - checkTypes.assert.boolean(options.cors); - - // log check - if (options.log) { - const fileObj = path.parse(path.normalize(options.log)); - try { - fs.statSync(fileObj.dir).isDirectory(); - } catch (e) { - // If log path doesn't exist, create it - mkdirp.sync(fileObj.dir); - } - } - - // host check - if (options.host) { - checkTypes.assert.string(options.host); - } - - this.options = options; - this.__running = false; - this.__cliVerb = cliVerb; - this.__serviceCommand = command; - this.__argMapping = argMapping; - } - - public start(): Promise { - if (this.__instance && this.__instance.connected) { - logger.warn( - `You already have a process running with PID: ${this.__instance.pid}` - ); - return Promise.resolve(this); - } - - this.__instance = this.spawnBinary(); - this.__instance.once('close', () => this.stop()); - - if (!this.options.port) { - // if port isn't specified, listen for it when pact runs - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const catchPort = (data: any): void => { - const match = data.match(/port=([0-9]+)/); - if (match && match[1]) { - this.options.port = parseInt(match[1], 10); - if (this?.__instance?.stdout) { - // __instance will never be undefined here because we just - // read the port number from it - this.__instance.stdout.removeListener('data', catchPort); - } - logger.info(`Pact running on port ${this.options.port}`); - } - }; - - if (this?.__instance?.stdout) { - this.__instance.stdout.on('data', catchPort); - } - } - - if (this?.__instance?.stderr) { - this.__instance.stderr.on('data', (data) => - logger.error(`Pact Binary Error: ${data}`) - ); - } - - // check service is available - return timeout(this.__waitForServiceUp(), getTimeout(this.options)) - .then(() => { - this.__running = true; - this.emit(AbstractService.Events.START_EVENT, this); - return this; - }) - .catch((err: Error) => { - if (err instanceof TimeoutError) { - throw new Error( - `Timeout while waiting to start Pact with PID: ${ - this.__instance ? this.__instance.pid : 'No Instance' - }` - ); - } - throw err; - }); - } - - // Stop the instance - public stop(): Promise { - const pid = this.__instance ? this.__instance.pid : -1; - return timeout( - Promise.resolve(this.__instance) - .then(spawn.killBinary) - .then(() => this.__waitForServiceDown()), - getTimeout(this.options) - ) - .catch((err: Error) => { - if (err instanceof TimeoutError) { - throw new Error( - `Timeout while waiting to stop Pact with PID '${pid}'` - ); - } - throw err; - }) - .then(() => { - this.__running = false; - this.emit(AbstractService.Events.STOP_EVENT, this); - return this; - }); - } - - // Deletes this instance and emit an event - public delete(): Promise { - return this.stop().then(() => { - this.emit(AbstractService.Events.DELETE_EVENT, this); - - return this; - }); - } - - // Subclass responsible for spawning the process - protected spawnBinary(): ChildProcess { - return spawn.spawnBinary( - this.__serviceCommand, - this.__cliVerb ? [this.__cliVerb, this.options] : [this.options], - this.__argMapping - ); - } - - // Wait for the service to be initialized and ready - protected __waitForServiceUp(): Promise { - let amount = 0; - - const waitPromise = new Promise((resolve, reject) => { - const retry = (): void => { - if (amount >= RETRY_AMOUNT) { - reject( - new Error( - `Pact startup failed; tried calling service ${RETRY_AMOUNT} times with no result.` - ) - ); - } - // eslint-disable-next-line @typescript-eslint/no-use-before-define - setTimeout(check.bind(this), getRetryTickTime(this.options)); - }; - - const check = (): void => { - amount += 1; - if (this.options.port) { - this.__call(this.options).then(() => resolve(), retry.bind(this)); - } else { - retry(); - } - }; - - check(); // Check first time, start polling - }); - return waitPromise; - } - - protected __waitForServiceDown(): Promise { - let amount = 0; - - const checkPromise = new Promise((resolve, reject) => { - const check = (): void => { - amount += 1; - if (this.options.port) { - this.__call(this.options).then( - () => { - if (amount >= RETRY_AMOUNT) { - reject( - new Error( - `Pact stop failed; tried calling service ${RETRY_AMOUNT} times with no result.` - ) - ); - return; - } - setTimeout(check, getRetryTickTime(this.options)); - }, - () => resolve() - ); - } else { - resolve(); - } - }; - check(); // Check first time, start polling - }); - - return checkPromise; - } - - private __call(options: ServiceOptions): Promise { - const config: HTTPConfig = { - method: 'GET', - headers: { - 'X-Pact-Mock-Service': 'true', - 'Content-Type': 'application/json', - }, - }; - - if (options.ssl) { - process.env['NODE_TLS_REJECT_UNAUTHORIZED'] = '0'; - config.rejectUnauthorized = false; - config.agent = false; - } - - return needle( - 'get', - `http${options.ssl ? 's' : ''}://${options.host}:${options.port}`, - config - ).then((res) => { - if (res.statusCode !== 200) { - throw new Error(`HTTP Error: '${JSON.stringify(res)}'`); - } - }); - } -} diff --git a/src/spawn/arguments.spec.ts b/src/spawn/arguments.spec.ts deleted file mode 100644 index fc606b0f..00000000 --- a/src/spawn/arguments.spec.ts +++ /dev/null @@ -1,168 +0,0 @@ -import chai = require('chai'); -import chaiAsPromised = require('chai-as-promised'); -import argsHelper, { DEFAULT_ARG } from './arguments'; - -const { expect } = chai; - -chai.use(chaiAsPromised); - -describe('Pact Util Spec', () => { - describe('toArgumentsArray', () => { - describe('when called with an object', () => { - it('should return an array of all arguments', () => { - const result = argsHelper.toArgumentsArray( - { providerBaseUrl: 'http://localhost' }, - { providerBaseUrl: '--provider-base-url' } - ); - expect(result).to.be.an('array').that.includes('--provider-base-url'); - expect(result.length).to.be.equal(2); - }); - - it('should wrap its argument values in quotes', () => { - const result = argsHelper.toArgumentsArray( - { - providerBaseUrl: 'http://localhost', - pactUrls: ['http://idontexist'], - }, - { - providerBaseUrl: '--provider-base-url', - pactUrls: '--pact-urls', - } - ); - expect(result).to.include('--provider-base-url'); - expect(result).to.include('http://localhost'); - expect(result).to.include('--pact-urls'); - expect(result).to.include('http://idontexist'); - }); - describe("and the argument's value is also an object", () => { - it('should serialise the argument value to a JSON string', () => { - const result = argsHelper.toArgumentsArray( - { - consumerVersionSelectors: [ - { - latest: true, - tag: 'prod', - }, - { - tag: 'bar', - }, - ], - }, - { consumerVersionSelectors: '--consumer-version-selector' } - ); - - expect(result) - .to.be.an('array') - .that.includes('--consumer-version-selector') - .and.includes('{"latest":true,"tag":"prod"}') - .and.includes('{"tag":"bar"}'); - expect(result.length).to.be.equal(4); - }); - }); - }); - describe('when called with an array', () => { - describe('with one element', () => { - it('should return an array of all arguments', () => { - const result = argsHelper.toArgumentsArray( - [{ providerBaseUrl: 'http://localhost' }], - { - providerBaseUrl: '--provider-base-url', - } - ); - expect(result).to.be.an('array').that.includes('--provider-base-url'); - expect(result.length).to.be.equal(2); - }); - - it('should produce correct arguments array', () => { - const result = argsHelper.toArgumentsArray( - [ - { - providerBaseUrl: 'http://localhost', - pactUrls: ['http://idontexist'], - }, - ], - { - providerBaseUrl: '--provider-base-url', - pactUrls: '--pact-urls', - } - ); - expect(result).to.include('--provider-base-url'); - expect(result).to.include('http://localhost'); - expect(result).to.include('--pact-urls'); - expect(result).to.include('http://idontexist'); - }); - }); - describe('with multiple elements', () => { - it('should produce correct arguments array', () => { - const result = argsHelper.toArgumentsArray( - [ - { participant: 'one' }, - { version: 'v1' }, - { participant: 'two' }, - { version: 'v2' }, - ], - { version: '--version', participant: '--participant' } - ); - - expect(result).to.be.an('array'); - expect(result).to.eql([ - '--participant', - 'one', - '--version', - 'v1', - '--participant', - 'two', - '--version', - 'v2', - ]); - }); - }); - describe("and an argument's value is an object", () => { - it('should serialise the argument value to a JSON string', () => { - const result = argsHelper.toArgumentsArray( - [ - { - consumerVersionSelectors: [ - { - latest: true, - tag: 'prod', - }, - ], - }, - { - consumerVersionSelectors: [ - { - tag: 'foo', - }, - ], - }, - ], - { consumerVersionSelectors: '--consumer-version-selector' } - ); - - expect(result) - .to.be.an('array') - .that.includes('--consumer-version-selector') - .and.includes('{"latest":true,"tag":"prod"}') - .and.includes('{"tag":"foo"}'); - expect(result.length).to.be.equal(4); - }); - }); - }); - - it('should make DEFAULT values first, everything else after', () => { - const result = argsHelper.toArgumentsArray( - { - providerBaseUrl: 'http://localhost', - pactUrls: ['http://idontexist'], - }, - { - providerBaseUrl: '--provider-base-url', - pactUrls: DEFAULT_ARG, - } - ); - expect(result.length).to.be.equal(3); - expect(result[0]).to.be.equal('http://idontexist'); - }); - }); -}); diff --git a/src/spawn/arguments.ts b/src/spawn/arguments.ts deleted file mode 100644 index f27f134c..00000000 --- a/src/spawn/arguments.ts +++ /dev/null @@ -1,77 +0,0 @@ -import _ = require('underscore'); -import checkTypes = require('check-types'); -import { VerifierOptions } from '../verifier/types'; -import { MessageOptions, PublisherOptions, ServiceOptions } from '../types'; -import { CanDeployOptions } from '../can-deploy/types'; - -export type CliVerbOptions = { - cliVerb: string; -}; - -export type SpawnArgument = - | CanDeployOptions - | MessageOptions - | PublisherOptions - | ServiceOptions - | VerifierOptions - | CliVerbOptions - // eslint-disable-next-line @typescript-eslint/ban-types - | {}; // Empty object is allowed to make tests less noisy. We should change this in the future - -export type SpawnArguments = Array | SpawnArgument; - -export const DEFAULT_ARG = 'DEFAULT'; -export const PACT_NODE_NO_VALUE = 'PACT_NODE_NO_VALUE'; - -const valFor = (v: SpawnArgument): Array => { - if (typeof v === 'object') { - return [JSON.stringify(v)]; - } - return v !== PACT_NODE_NO_VALUE ? [`${v}`] : []; -}; - -const mapFor = (mapping: string, v: string): Array => - mapping === DEFAULT_ARG ? valFor(v) : [mapping].concat(valFor(v)); - -const convertValue = ( - mapping: string, - v: SpawnArgument | Array -): Array => { - if (v && mapping) { - return checkTypes.array(v) - ? _.flatten( - (v as Array).map((val: string) => mapFor(mapping, val)) - ) - : mapFor(mapping, v as string); - } - return []; -}; - -export class Arguments { - public toArgumentsArray( - args: SpawnArguments, - mappings: { [id: string]: string } - ): string[] { - return _.chain(args instanceof Array ? args : [args]) - .map((x: SpawnArgument) => this.createArgumentsFromObject(x, mappings)) - .flatten() - .value(); - } - - private createArgumentsFromObject( - args: SpawnArgument, - mappings: { [id: string]: string } - ): string[] { - return _.chain(Object.keys(args)) - .reduce( - (acc: Array, key: string): Array => - mappings[key] === DEFAULT_ARG - ? convertValue(mappings[key], args[key]).concat(acc) - : acc.concat(convertValue(mappings[key], args[key])), - [] - ) - .value(); - } -} - -export default new Arguments(); diff --git a/src/spawn/index.ts b/src/spawn/index.ts deleted file mode 100644 index dab54344..00000000 --- a/src/spawn/index.ts +++ /dev/null @@ -1,5 +0,0 @@ -import spawn from './spawn'; - -export * from './arguments'; - -export default spawn; diff --git a/src/spawn/spawn.ts b/src/spawn/spawn.ts deleted file mode 100644 index 790fbace..00000000 --- a/src/spawn/spawn.ts +++ /dev/null @@ -1,87 +0,0 @@ -import spawn = require('cross-spawn'); -import cp = require('child_process'); -import { ChildProcess, SpawnOptions } from 'child_process'; -import * as path from 'path'; -import logger from '../logger'; -import pactEnvironment from '../pact-environment'; -import argsHelper, { SpawnArguments, DEFAULT_ARG } from './arguments'; - -export class Spawn { - public get cwd(): string { - return path.resolve(__dirname, '..'); - } - - public spawnBinary( - command: string, - args: SpawnArguments = {}, - argMapping: { [id: string]: string } = {} - ): ChildProcess { - const envVars = JSON.parse(JSON.stringify(process.env)); // Create copy of environment variables - - envVars.PACT_EXECUTING_LANGUAGE = 'node.js'; - envVars.PACT_EXECUTING_LANGUAGE_VERSION = process.versions.node; - - // Remove environment variable if there - // This is a hack to prevent some weird Travelling Ruby behaviour with Gems - // https://github.com/pact-foundation/pact-mock-service-npm/issues/16 - delete envVars.RUBYGEMS_GEMDEPS; - - const opts: SpawnOptions = { - cwd: pactEnvironment.cwd, - detached: !pactEnvironment.isWindows(), - env: envVars, - }; - - const spawnArgs: string[] = argsHelper.toArgumentsArray(args, { - cliVerb: DEFAULT_ARG, - ...argMapping, - }); - - logger.debug( - `Starting pact binary '${command}', with arguments [${spawnArgs.join( - ' ' - )}]` - ); - logger.trace(`Environment: ${JSON.stringify(opts)}`); - const instance = spawn(command, spawnArgs, opts); - - if (instance.stderr && instance.stdout) { - instance.stdout.on('data', logger.debug.bind(logger)); - instance.stdout.setEncoding('utf8'); - instance.stderr.setEncoding('utf8'); - instance.stderr.on('data', logger.debug.bind(logger)); - } - instance.on('error', logger.error.bind(logger)); - instance.once('close', (code) => { - if (code !== 0) { - logger.warn(`Pact exited with code ${code}.`); - } - }); - - logger.debug(`Created '${command}' process with PID: ${instance.pid}`); - return instance; - } - - public killBinary(binary?: ChildProcess): boolean { - if (binary) { - const { pid } = binary; - logger.info(`Removing Pact process with PID: ${pid}`); - binary.removeAllListeners(); - // Killing instance, since windows can't send signals, must kill process forcefully - try { - if (pid) { - if (pactEnvironment.isWindows()) { - cp.execSync(`taskkill /f /t /pid ${pid}`); - } else { - process.kill(-pid, 'SIGINT'); - } - } - } catch (e) { - return false; - } - } - return true; - } -} - -export default new Spawn(); diff --git a/src/stub.spec.ts b/src/stub.spec.ts deleted file mode 100644 index dbb52b3e..00000000 --- a/src/stub.spec.ts +++ /dev/null @@ -1,230 +0,0 @@ -import * as chai from 'chai'; -import chaiAsPromised from 'chai-as-promised'; -import * as fs from 'fs'; -import * as path from 'path'; -import stubFactory from './stub'; - -chai.use(chaiAsPromised); -const { expect } = chai; - -describe('Stub Spec', () => { - let stub: any; - const validDefaults = { - pactUrls: [ - path.resolve(__dirname, '../test/integration/me-they-success.json'), - ], - }; - - afterEach(() => - stub - ? stub.delete().then(() => { - stub = null; - return stub; - }) - : null - ); - - describe('Start stub', () => { - context('when invalid options are set', () => { - it('should fail if custom ssl certs do not exist', () => { - expect(() => - stubFactory({ - ssl: true, - sslcert: 'does/not/exist', - sslkey: path.resolve(__dirname, '../test/ssl/server.key'), - }) - ).to.throw(Error); - }); - - it('should fail if custom ssl keys do not exist', () => { - expect(() => - stubFactory({ - ssl: true, - sslcert: path.resolve(__dirname, '../test/ssl/server.crt'), - sslkey: 'does/not/exist', - }) - ).to.throw(Error); - }); - - it("should fail if custom ssl cert is set, but ssl key isn't", () => { - expect(() => - stubFactory({ - ssl: true, - sslcert: path.resolve(__dirname, '../test/ssl/server.crt'), - }) - ).to.throw(Error); - }); - - it("should fail if custom ssl key is set, but ssl cert isn't", () => { - expect(() => - stubFactory({ - ssl: true, - sslkey: path.resolve(__dirname, '../test/ssl/server.key'), - }) - ).to.throw(Error); - }); - }); - - context('when valid options are set', () => { - let dirPath: string; - - beforeEach(() => { - dirPath = path.resolve( - __dirname, - `../.tmp/${Math.floor(Math.random() * 1000)}` - ); - }); - - afterEach(() => { - try { - if (fs.statSync(dirPath).isDirectory()) { - fs.rmdirSync(dirPath); - } - } catch (e) { - /* any errors here are not a failed test */ - } - }); - - it('should start correctly when instance is delayed', () => { - stub = stubFactory(validDefaults); - - const waitForStubUp = stub.__waitForServiceUp.bind(stub); - return Promise.all([ - waitForStubUp(stub.options), - new Promise((resolve) => { - setTimeout(resolve, 5000); - }).then(() => stub.start()), - ]); - }); - - it('should start correctly with valid pact URLs', () => { - stub = stubFactory(validDefaults); - return expect(stub.start()).to.eventually.be.fulfilled; - }); - - it('should start correctly with valid pact URLs with spaces in it', () => { - stub = stubFactory({ - pactUrls: [ - path.resolve( - __dirname, - '../test/integration/me-they-weird path-success.json' - ), - ], - }); - return expect(stub.start()).to.eventually.be.fulfilled; - }); - - it('should start correctly with ssl', () => { - stub = stubFactory({ ...validDefaults, ssl: true }); - expect(stub.options.ssl).to.equal(true); - return expect(stub.start()).to.eventually.be.fulfilled; - }); - - it('should start correctly with custom ssl cert/key', () => { - stub = stubFactory({ - ...validDefaults, - ssl: true, - sslcert: path.resolve(__dirname, '../test/ssl/server.crt'), - sslkey: path.resolve(__dirname, '../test/ssl/server.key'), - }); - expect(stub.options.ssl).to.equal(true); - return expect(stub.start()).to.eventually.be.fulfilled; - }); - - it('should start correctly with custom ssl cert/key but without specifying ssl flag', () => { - stub = stubFactory({ - ...validDefaults, - sslcert: path.resolve(__dirname, '../test/ssl/server.crt'), - sslkey: path.resolve(__dirname, '../test/ssl/server.key'), - }); - - expect(stub.options.ssl).to.equal(true); - return expect(stub.start()).to.eventually.be.fulfilled; - }); - - it('should start correctly with cors', () => { - stub = stubFactory({ ...validDefaults, cors: true }); - expect(stub.options.cors).to.equal(true); - return expect(stub.start()).to.eventually.be.fulfilled; - }); - - it('should start correctly with port', () => { - const port = Math.floor(Math.random() * 999) + 9000; - stub = stubFactory({ ...validDefaults, port }); - expect(stub.options.port).to.equal(port); - return expect(stub.start()).to.eventually.be.fulfilled; - }); - - it('should start correctly with host', () => { - const host = 'localhost'; - stub = stubFactory({ ...validDefaults, host }); - expect(stub.options.host).to.equal(host); - return expect(stub.start()).to.eventually.be.fulfilled; - }); - - it('should start correctly with log', () => { - const logPath = path.resolve(dirPath, 'log.txt'); - stub = stubFactory({ ...validDefaults, log: logPath }); - expect(stub.options.log).to.equal(logPath); - return expect(stub.start()).to.eventually.be.fulfilled; - }); - }); - - it('should dispatch event when starting', (done) => { - stub = stubFactory(validDefaults); - stub.once('start', () => done()); - stub.start(); - }); - - it('should change running state to true', () => { - stub = stubFactory(validDefaults); - return stub.start().then(() => expect(stub.__running).to.be.true); - }); - }); - - describe('Stop stub', () => { - context('when already started', () => { - it('should stop running', () => { - stub = stubFactory(validDefaults); - return stub.start().then(() => stub.stop()); - }); - - it('should dispatch event when stopping', (done) => { - stub = stubFactory(validDefaults); - stub.once('stop', () => done()); - stub.start().then(() => stub.stop()); - }); - - it('should change running state to false', () => { - stub = stubFactory(validDefaults); - return stub - .start() - .then(() => stub.stop()) - .then(() => expect(stub.__running).to.be.false); - }); - }); - }); - - describe('Delete stub', () => { - context('when already running', () => { - it('should stop & delete stub', () => { - stub = stubFactory(validDefaults); - return stub.start().then(() => stub.delete()); - }); - - it('should dispatch event when deleting', (done) => { - stub = stubFactory(validDefaults); - stub.once('delete', () => done()); - stub.start().then(() => stub.delete()); - }); - - it('should change running state to false', () => { - stub = stubFactory(validDefaults); - return stub - .start() - .then(() => stub.delete()) - .then(() => expect(stub.__running).to.be.false); - }); - }); - }); -}); diff --git a/src/stub.ts b/src/stub.ts deleted file mode 100644 index 833382dd..00000000 --- a/src/stub.ts +++ /dev/null @@ -1,50 +0,0 @@ -import checkTypes = require('check-types'); -import { DEFAULT_ARG } from './spawn'; -import { AbstractService } from './service'; - -import pact from './pact-standalone'; -import { LogLevel } from './logger/types'; - -export class Stub extends AbstractService { - public readonly options: StubOptions; - - constructor(passedOptions: StubOptions = {}) { - const options = { ...passedOptions }; - options.pactUrls = options.pactUrls || []; - - if (options.pactUrls) { - checkTypes.assert.array.of.string(options.pactUrls); - } - - checkTypes.assert.not.emptyArray(options.pactUrls); - - super(pact.stubFullPath, options, { - pactUrls: DEFAULT_ARG, - port: '--port', - host: '--host', - log: '--log', - logLevel: '--log-level', - ssl: '--ssl', - sslcert: '--sslcert', - sslkey: '--sslkey', - cors: '--cors', - }); - this.options = options; - } -} - -// Creates a new instance of the pact stub with the specified option -export default (options?: StubOptions): Stub => new Stub(options); - -export interface StubOptions { - pactUrls?: string[]; - port?: number; - ssl?: boolean; - cors?: boolean; - host?: string; - sslcert?: string; - sslkey?: string; - log?: string; - logLevel?: LogLevel; - timeout?: number; -} diff --git a/src/types.ts b/src/types.ts index db4b50af..80061004 100644 --- a/src/types.ts +++ b/src/types.ts @@ -1,41 +1,4 @@ import needle from 'needle'; -import { LogLevel } from './logger/types'; - -export interface MessageOptions { - content?: string; - dir?: string; - consumer?: string; - provider?: string; - pactFileWriteMode?: 'overwrite' | 'update' | 'merge'; - spec?: number; -} - -export interface PublisherOptions { - pactFilesOrDirs: string[]; - pactBroker: string; - consumerVersion: string; - pactBrokerUsername?: string; - pactBrokerPassword?: string; - pactBrokerToken?: string; - tags?: string[]; - verbose?: boolean; - timeout?: number; - buildUrl?: string; - branch?: string; - autoDetectVersionProperties?: boolean; -} - -export interface ServiceOptions { - port?: number; - ssl?: boolean; - cors?: boolean; - host?: string; - sslcert?: string; - sslkey?: string; - log?: string; - logLevel?: LogLevel; - timeout?: number; -} export interface HTTPConfig extends Omit { headers: { diff --git a/test/publisher.integration.spec.ts b/test/publisher.integration.spec.ts deleted file mode 100644 index c9efb13e..00000000 --- a/test/publisher.integration.spec.ts +++ /dev/null @@ -1,179 +0,0 @@ -import path = require('path'); -import chai = require('chai'); -import chaiAsPromised = require('chai-as-promised'); -import * as http from 'http'; -import logger from '../src/logger'; -import publisherFactory from '../src/publisher'; -import brokerMock from './integration/broker-mock'; - -const { expect } = chai; -chai.use(chaiAsPromised); - -describe('Publish Spec', () => { - let server: http.Server; - const PORT = Math.floor(Math.random() * 999) + 9000; - const pactBrokerBaseUrl = `http://localhost:${PORT}`; - const authenticatedPactBrokerBaseUrl = `${pactBrokerBaseUrl}/auth`; - - before(() => - brokerMock(PORT).then((s) => { - logger.debug(`Pact Broker Mock listening on port: ${PORT}`); - server = s; - }) - ); - - after(() => server.close()); - - context('when publishing a to a broker', () => { - context('without authentication', () => { - context('and the Pact contract is valid', () => { - it('should successfully publish all Pacts', () => { - const publisher = publisherFactory({ - pactBroker: pactBrokerBaseUrl, - pactFilesOrDirs: [ - path.resolve( - __dirname, - 'integration/publish/publish-success.json' - ), - ], - consumerVersion: '1.0.0', - buildUrl: 'http://ci/build/1', - }); - - expect(publisher).to.be.a('object'); - expect(publisher).to.respondTo('publish'); - return expect(publisher.publish()).to.eventually.be.fulfilled; - }); - - it('should successfully tag all Pacts with `test` and `latest`', () => { - const publisher = publisherFactory({ - pactBroker: pactBrokerBaseUrl, - pactFilesOrDirs: [ - path.resolve( - __dirname, - 'integration/publish/publish-success.json' - ), - ], - consumerVersion: '1.0.0', - tags: ['test', 'latest'], - }); - - expect(publisher).to.be.a('object'); - expect(publisher).to.respondTo('publish'); - return expect(publisher.publish()).to.eventually.be.fulfilled; - }); - }); - context('and the Pact contract is invalid', () => { - it('should report an unsuccessful push', () => { - const publisher = publisherFactory({ - pactBroker: pactBrokerBaseUrl, - pactFilesOrDirs: [ - path.resolve(__dirname, 'integration/publish/publish-fail.json'), - ], - consumerVersion: '1.0.0', - }); - - expect(publisher).to.be.a('object'); - expect(publisher).to.respondTo('publish'); - return expect(publisher.publish()).to.eventually.be.rejected; - }); - }); - }); - - context('with authentication', () => { - context('and valid credentials', () => { - it('should return a sucessful promise', () => { - const publisher = publisherFactory({ - pactBroker: authenticatedPactBrokerBaseUrl, - pactFilesOrDirs: [ - path.resolve( - __dirname, - 'integration/publish/publish-success.json' - ), - ], - consumerVersion: '1.0.0', - pactBrokerUsername: 'foo', - pactBrokerPassword: 'bar', - }); - - expect(publisher).to.be.a('object'); - expect(publisher).to.respondTo('publish'); - return expect(publisher.publish()).to.eventually.be.fulfilled; - }); - }); - - context('and invalid credentials', () => { - it('should return a rejected promise', () => { - const publisher = publisherFactory({ - pactBroker: authenticatedPactBrokerBaseUrl, - pactFilesOrDirs: [ - path.resolve( - __dirname, - 'integration/publish/publish-success.json' - ), - ], - consumerVersion: '1.0.0', - pactBrokerUsername: 'not', - pactBrokerPassword: 'right', - }); - - expect(publisher).to.be.a('object'); - expect(publisher).to.respondTo('publish'); - return expect(publisher.publish()).to.eventually.be.rejected; - }); - }); - }); - }); - - context('when publishing a directory of Pacts to a Broker', () => { - context('and the directory contains only valid Pact contracts', () => { - it('should asynchronously send all Pacts to the Broker', () => { - const publisher = publisherFactory({ - pactBroker: pactBrokerBaseUrl, - pactFilesOrDirs: [ - path.resolve(__dirname, 'integration/publish/pactDirTests'), - ], - consumerVersion: '1.0.0', - }); - - expect(publisher).to.be.a('object'); - expect(publisher).to.respondTo('publish'); - return expect(publisher.publish()).to.eventually.be.fulfilled; - }); - - it('should successfully tag all Pacts sent with `test` and `latest`', () => { - const publisher = publisherFactory({ - pactBroker: pactBrokerBaseUrl, - pactFilesOrDirs: [ - path.resolve(__dirname, 'integration/publish/pactDirTests'), - ], - consumerVersion: '1.0.0', - tags: ['test', 'latest'], - }); - - expect(publisher).to.be.a('object'); - expect(publisher).to.respondTo('publish'); - return expect(publisher.publish()).to.eventually.be.fulfilled; - }); - }); - - context('and the directory contains Pact and non-Pact contracts', () => { - it('should asynchronously send only the Pact contracts to the broker', () => { - const publisher = publisherFactory({ - pactBroker: pactBrokerBaseUrl, - pactFilesOrDirs: [ - path.resolve( - __dirname, - 'integration/publish/pactDirTestsWithOtherStuff' - ), - ], - consumerVersion: '1.0.0', - }); - - expect(publisher).to.be.a('object'); - expect(publisher).to.respondTo('publish'); - return expect(publisher.publish()).to.eventually.be.fulfilled; - }); - }); - }); -}); From 97d6c0f9978eab4223f97566484309a421c5e66e Mon Sep 17 00:00:00 2001 From: Timothy Jones Date: Wed, 15 Mar 2023 16:36:23 +1100 Subject: [PATCH 05/14] test: Remove integration mocks that are no longer needed --- test/integration/broker-mock.ts | 541 ------------------ .../publish/pactDirTests/publish-success.json | 28 - .../pactDirTests/publish-success2.json | 28 - .../publish-success.json | 28 - .../publish-success2.json | 28 - .../pactDirTestsWithOtherStuff/test.txt | 1 - test/integration/publish/publish-fail.json | 22 - test/integration/publish/publish-success.json | 28 - 8 files changed, 704 deletions(-) delete mode 100644 test/integration/broker-mock.ts delete mode 100644 test/integration/publish/pactDirTests/publish-success.json delete mode 100644 test/integration/publish/pactDirTests/publish-success2.json delete mode 100644 test/integration/publish/pactDirTestsWithOtherStuff/publish-success.json delete mode 100644 test/integration/publish/pactDirTestsWithOtherStuff/publish-success2.json delete mode 100644 test/integration/publish/pactDirTestsWithOtherStuff/test.txt delete mode 100644 test/integration/publish/publish-fail.json delete mode 100644 test/integration/publish/publish-success.json diff --git a/test/integration/broker-mock.ts b/test/integration/broker-mock.ts deleted file mode 100644 index 3f513dcd..00000000 --- a/test/integration/broker-mock.ts +++ /dev/null @@ -1,541 +0,0 @@ -import express = require('express'); -import * as http from 'http'; -import cors = require('cors'); -import _ = require('underscore'); -import bodyParser = require('body-parser'); -import { auth, returnJson } from './data-utils'; - -export default (port: number): Promise => { - const BROKER_HOST = `http://localhost:${port}`; - const server: express.Express = express(); - server.use(cors()); - server.use(bodyParser.json()); - server.use(bodyParser.urlencoded({ extended: true })); - - function pactFunction( - req: express.Request, - res: express.Response - ): express.Response { - if ( - _.isEmpty(req.body) || - // 2. Is there a consumer, provider and version in the request? - _.isEmpty(req.params['consumer']) || - _.isEmpty(req.params['provider']) || - _.isEmpty(req.params['version']) - ) { - return res.sendStatus(400); - } - return res.status(201).json({ - consumer: { name: 'consumer' }, - provider: { name: 'publisher' }, - interactions: [ - { - description: 'Greeting', - request: { method: 'GET', path: '/' }, - response: { status: 200, headers: {}, body: { greeting: 'Hello' } }, - }, - ], - metadata: { pactSpecificationVersion: '2.0.0' }, - createdAt: '2017-11-06T13:06:48+00:00', - _links: { - self: { - title: 'Pact', - name: 'Pact between consumer (v1.0.0) and publisher', - href: `${BROKER_HOST}/pacts/provider/publisher/consumer/consumer/version/1.0.0`, - }, - 'pb:consumer': { - title: 'Consumer', - name: 'consumer', - href: `${BROKER_HOST}/pacticipants/consumer`, - }, - 'pb:consumer-version': { - title: 'Consumer version', - name: '1.0.0', - href: `${BROKER_HOST}/pacticipants/consumer/versions/1.0.0`, - }, - 'pb:provider': { - title: 'Provider', - name: 'publisher', - href: `${BROKER_HOST}/pacticipants/publisher`, - }, - 'pb:latest-pact-version': { - title: 'Latest version of this pact', - href: `${BROKER_HOST}/pacts/provider/publisher/consumer/consumer/latest`, - }, - 'pb:all-pact-versions': { - title: 'All version of this pact', - href: `${BROKER_HOST}/pacts/provider/publisher/consumer/consumer/versions`, - }, - 'pb:latest-untagged-pact-version': { - title: 'Latest untagged version of this pact', - href: `${BROKER_HOST}/pacts/provider/publisher/consumer/consumer/latest-untagged`, - }, - 'pb:latest-tagged-pact-version': { - title: 'Latest tagged version of this pact', - href: `${BROKER_HOST}/pacts/provider/publisher/consumer/consumer/latest/{tag}`, - templated: true, - }, - 'pb:previous-distinct': { - title: 'Previous distinct version of this pact', - href: `${BROKER_HOST}/pacts/provider/publisher/consumer/consumer/version/1.0.0/previous-distinct`, - }, - 'pb:diff-previous-distinct': { - title: 'Diff with previous distinct version of this pact', - href: `${BROKER_HOST}/pacts/provider/publisher/consumer/consumer/version/1.0.0/diff/previous-distinct`, - }, - 'pb:pact-webhooks': { - title: 'Webhooks for the pact between consumer and publisher', - href: `${BROKER_HOST}/webhooks/provider/publisher/consumer/consumer`, - }, - 'pb:tag-prod-version': { - title: - "PUT to this resource to tag this consumer version as 'production'", - href: `${BROKER_HOST}/pacticipants/consumer/versions/1.0.0/tags/prod`, - }, - 'pb:tag-version': { - title: 'PUT to this resource to tag this consumer version', - href: `${BROKER_HOST}/pacticipants/consumer/versions/1.0.0/tags/{tag}`, - }, - 'pb:publish-verification-results': { - title: 'Publish verification results', - href: `${BROKER_HOST}/pacts/provider/publisher/consumer/consumer/pact-version/7c36fc0ded24117ec189db3f54fadffc23a56d68/verification-results`, - }, - curies: [ - { name: 'pb', href: `${BROKER_HOST}/doc/{rel}`, templated: true }, - ], - }, - }); - } - - function tagPactFunction( - req: express.Request, - res: express.Response - ): express.Response { - if ( - _.isEmpty(req.params['consumer']) || - _.isEmpty(req.params['version']) || - _.isEmpty(req.params['tag']) - ) { - return res.sendStatus(400); - } - return res.sendStatus(201); - } - - const rootResponse = () => - returnJson({ - _links: { - self: { - href: BROKER_HOST, - title: 'Index', - templated: false, - }, - 'pb:publish-pact': { - href: `${BROKER_HOST}/pacts/provider/{provider}/consumer/{consumer}/version/{consumerApplicationVersion}`, - title: 'Publish a pact', - templated: true, - }, - 'pb:latest-pact-versions': { - href: `${BROKER_HOST}/pacts/latest`, - title: 'Latest pact version', - templated: false, - }, - 'pb:pacticipants': { - href: `${BROKER_HOST}/pacticipants`, - title: 'Pacticipants', - templated: false, - }, - 'pb:latest-provider-pacts': { - href: `${BROKER_HOST}/pacts/provider/{provider}/latest`, - title: 'Latest pacts by provider', - templated: true, - }, - 'pb:latest-provider-pacts-with-tag': { - href: `${BROKER_HOST}/pacts/provider/{provider}/latest/{tag}`, - title: 'Latest pacts by provider with a specified tag', - templated: true, - }, - 'pb:webhooks': { - href: `${BROKER_HOST}/webhooks`, - title: 'Webhooks', - templated: false, - }, - curies: [ - { - name: 'pb', - href: `${BROKER_HOST}/doc/{rel}`, - templated: true, - }, - ], - }, - }); - - server.get('/somebrokenpact', returnJson({})); - - server.get( - '/somepact', - returnJson({ - consumer: { - name: 'anotherclient', - }, - provider: { - name: 'they', - }, - }) - ); - - // Pretend to be a Pact Broker (https://github.com/bethesque/pact_broker) for integration tests - server.put( - '/pacts/provider/:provider/consumer/:consumer/version/:version', - pactFunction - ); - - // Authenticated calls... - server.put( - '/auth/pacts/provider/:provider/consumer/:consumer/version/:version', - auth, - pactFunction - ); - - // Tagging - server.put( - '/pacticipant/:consumer/version/:version/tags/:tag', - tagPactFunction - ); - server.put( - '/auth/pacticipant/:consumer/version/:version/tags/:tag', - tagPactFunction - ); - - // Matrix - server.get('/matrix', (req: express.Request, res: express.Response) => { - if ( - req && - req.query && - req.query['q'] && - req.query['q'][0].pacticipant === 'Foo' - ) { - return res.json({ - summary: { - deployable: true, - reason: 'some text', - unknown: 1, - }, - matrix: [ - { - consumer: { - name: 'Foo', - version: { - number: '4', - }, - }, - provider: { - name: 'Bar', - version: { - number: '5', - }, - }, - verificationResult: { - verifiedAt: '2017-10-10T12:49:04+11:00', - success: true, - }, - pact: { - createdAt: '2017-10-10T12:49:04+11:00', - }, - }, - ], - }); - } - return res.json({ - summary: { - deployable: false, - reason: 'some text', - unknown: 1, - }, - matrix: [ - { - consumer: { - name: 'FooFail', - version: { - number: '4', - }, - }, - provider: { - name: 'Bar', - version: { - number: '5', - }, - }, - verificationResult: { - verifiedAt: '2017-10-10T12:49:04+11:00', - success: false, - }, - pact: { - createdAt: '2017-10-10T12:49:04+11:00', - }, - }, - ], - }); - }); - - // Get root HAL links - server.get('/', rootResponse()); - server.get('/auth', rootResponse()); - server.get('/noauth', rootResponse()); - - // Get pacts by Provider "notfound" - server.get( - '/pacts/provider/notfound/latest', - (req: express.Request, res: express.Response) => res.sendStatus(404) - ); - - // Get pacts by Provider "nolinks" - server.get( - '/pacts/provider/nolinks/latest', - returnJson({ - _links: { - self: { - href: `${BROKER_HOST}/pacts/provider/nolinks/latest/sit4`, - title: 'Latest pact version for the provider nolinks with tag "sit4"', - }, - provider: { - href: `${BROKER_HOST}/pacticipants/nolinks`, - title: 'bobby', - }, - pacts: [], - }, - }) - ); - - // Get pacts by Provider (all) - server.get( - '/pacts/provider/:provider/latest', - returnJson({ - _links: { - self: { - href: `${BROKER_HOST}/pacts/provider/bobby/latest/sit4`, - title: 'Latest pact version for the provider bobby with tag "sit4"', - }, - provider: { - href: `${BROKER_HOST}/pacticipants/bobby`, - title: 'bobby', - }, - pacts: [ - { - href: `${BROKER_HOST}/pacts/provider/bobby/consumer/billy/version/1.0.0`, - title: 'Pact between billy (v1.0.0) and bobby', - name: 'billy', - }, - { - href: `${BROKER_HOST}/pacts/provider/bobby/consumer/someotherguy/version/1.0.0`, - title: 'Pact between someotherguy (v1.0.0) and bobby', - name: 'someotherguy', - }, - ], - }, - }) - ); - - // Get pacts by Provider and Tag - server.get( - '/pacts/provider/:provider/latest/:tag', - returnJson({ - _links: { - self: { - href: 'https://test.pact.dius.com.au/pacts/provider/notfound/latest', - title: 'Latest pact version for the provider bobby', - }, - provider: { - href: 'https://test.pact.dius.com.au/pacticipant/bobby', - title: 'bobby', - }, - pacts: [ - { - href: 'https://test.pact.dius.com.au/pacts/provider/bobby/consumer/billy/version/1.0.0', - title: 'Pact between billy (v1.0.0) and bobby', - name: 'billy', - }, - { - href: 'https://test.pact.dius.com.au/pacts/provider/bobby/consumer/someotherguy/version/1.0.0', - title: 'Pact between someotherguy (v1.0.0) and bobby', - name: 'someotherguy', - }, - ], - }, - }) - ); - - server.get( - '/noauth/pacts/provider/they/consumer/me/latest', - returnJson({ - consumer: { - name: 'me', - }, - provider: { - name: 'they', - }, - interactions: [ - { - description: 'Provider state success', - providerState: 'There is a greeting', - request: { - method: 'GET', - path: '/somestate', - }, - response: { - status: 200, - headers: {}, - body: { - greeting: 'State data!', - }, - }, - }, - ], - metadata: { - pactSpecificationVersion: '2.0.0', - }, - updatedAt: '2016-05-15T00:09:33+00:00', - createdAt: '2016-05-15T00:09:06+00:00', - _links: { - self: { - title: 'Pact', - name: 'Pact between me (v1.0.0) and they', - href: `${BROKER_HOST}/pacts/provider/they/consumer/me/version/1.0.0`, - }, - 'pb:consumer': { - title: 'Consumer', - name: 'me', - href: `${BROKER_HOST}/pacticipants/me`, - }, - 'pb:provider': { - title: 'Provider', - name: 'they', - href: `${BROKER_HOST}/pacticipants/they`, - }, - 'pb:latest-pact-version': { - title: 'Pact', - name: 'Latest version of this pact', - href: `${BROKER_HOST}/pacts/provider/they/consumer/me/latest`, - }, - 'pb:previous-distinct': { - title: 'Pact', - name: 'Previous distinct version of this pact', - href: `${BROKER_HOST}/pacts/provider/they/consumer/me/version/1.0.0/previous-distinct`, - }, - 'pb:diff-previous-distinct': { - title: 'Diff', - name: 'Diff with previous distinct version of this pact', - href: `${BROKER_HOST}/pacts/provider/they/consumer/me/version/1.0.0/diff/previous-distinct`, - }, - 'pb:pact-webhooks': { - title: 'Webhooks for the pact between me and they', - href: `${BROKER_HOST}/webhooks/provider/they/consumer/me`, - }, - 'pb:tag-prod-version': { - title: 'Tag this version as "production"', - href: `${BROKER_HOST}/pacticipants/me/versions/1.0.0/tags/prod`, - }, - 'pb:tag-version': { - title: 'Tag version', - href: `${BROKER_HOST}/pacticipants/me/versions/1.0.0/tags/{tag}`, - }, - curies: [ - { - name: 'pb', - href: `${BROKER_HOST}/doc/{rel}`, - templated: true, - }, - ], - }, - }) - ); - - server.get( - '/noauth/pacts/provider/they/consumer/anotherclient/latest', - returnJson({ - consumer: { - name: 'anotherclient', - }, - provider: { - name: 'they', - }, - interactions: [ - { - description: 'Provider state success', - providerState: 'There is a greeting', - request: { - method: 'GET', - path: '/somestate', - }, - response: { - status: 200, - headers: {}, - body: { - greeting: 'State data!', - }, - }, - }, - ], - metadata: { - pactSpecificationVersion: '2.0.0', - }, - updatedAt: '2016-05-15T00:09:33+00:00', - createdAt: '2016-05-15T00:09:06+00:00', - _links: { - self: { - title: 'Pact', - name: 'Pact between me (v1.0.0) and they', - href: `${BROKER_HOST}/pacts/provider/they/consumer/me/version/1.0.0`, - }, - 'pb:consumer': { - title: 'Consumer', - name: 'anotherclient', - href: `${BROKER_HOST}/pacticipants/me`, - }, - 'pb:provider': { - title: 'Provider', - name: 'they', - href: `${BROKER_HOST}/pacticipants/they`, - }, - 'pb:latest-pact-version': { - title: 'Pact', - name: 'Latest version of this pact', - href: `${BROKER_HOST}/pacts/provider/they/consumer/me/latest`, - }, - 'pb:previous-distinct': { - title: 'Pact', - name: 'Previous distinct version of this pact', - href: `${BROKER_HOST}/pacts/provider/they/consumer/me/version/1.0.0/previous-distinct`, - }, - 'pb:diff-previous-distinct': { - title: 'Diff', - name: 'Diff with previous distinct version of this pact', - href: `${BROKER_HOST}/pacts/provider/they/consumer/me/version/1.0.0/diff/previous-distinct`, - }, - 'pb:pact-webhooks': { - title: 'Webhooks for the pact between me and they', - href: `${BROKER_HOST}/webhooks/provider/they/consumer/me`, - }, - 'pb:tag-prod-version': { - title: 'Tag this version as "production"', - href: `${BROKER_HOST}/pacticipants/me/versions/1.0.0/tags/prod`, - }, - 'pb:tag-version': { - title: 'Tag version', - href: `${BROKER_HOST}/pacticipants/me/versions/1.0.0/tags/{tag}`, - }, - curies: [ - { - name: 'pb', - href: `${BROKER_HOST}/doc/{rel}`, - templated: true, - }, - ], - }, - }) - ); - - let s: http.Server; - return new Promise((resolve) => { - s = server.listen(port, () => resolve()); - }).then(() => s); -}; diff --git a/test/integration/publish/pactDirTests/publish-success.json b/test/integration/publish/pactDirTests/publish-success.json deleted file mode 100644 index 97f4cd6a..00000000 --- a/test/integration/publish/pactDirTests/publish-success.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "consumer": { - "name": "consumer" - }, - "provider": { - "name": "publisher" - }, - "interactions": [ - { - "description": "Greeting", - "request": { - "method": "GET", - "path": "/" - }, - "response": { - "status": 200, - "headers": { - }, - "body": { - "greeting": "Hello" - } - } - } - ], - "metadata": { - "pactSpecificationVersion": "2.0.0" - } -} diff --git a/test/integration/publish/pactDirTests/publish-success2.json b/test/integration/publish/pactDirTests/publish-success2.json deleted file mode 100644 index 7ce1b6f9..00000000 --- a/test/integration/publish/pactDirTests/publish-success2.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "consumer": { - "name": "consumer" - }, - "provider": { - "name": "publisher2" - }, - "interactions": [ - { - "description": "Greeting", - "request": { - "method": "GET", - "path": "/" - }, - "response": { - "status": 200, - "headers": { - }, - "body": { - "greeting": "Hello" - } - } - } - ], - "metadata": { - "pactSpecificationVersion": "2.0.0" - } -} diff --git a/test/integration/publish/pactDirTestsWithOtherStuff/publish-success.json b/test/integration/publish/pactDirTestsWithOtherStuff/publish-success.json deleted file mode 100644 index 97f4cd6a..00000000 --- a/test/integration/publish/pactDirTestsWithOtherStuff/publish-success.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "consumer": { - "name": "consumer" - }, - "provider": { - "name": "publisher" - }, - "interactions": [ - { - "description": "Greeting", - "request": { - "method": "GET", - "path": "/" - }, - "response": { - "status": 200, - "headers": { - }, - "body": { - "greeting": "Hello" - } - } - } - ], - "metadata": { - "pactSpecificationVersion": "2.0.0" - } -} diff --git a/test/integration/publish/pactDirTestsWithOtherStuff/publish-success2.json b/test/integration/publish/pactDirTestsWithOtherStuff/publish-success2.json deleted file mode 100644 index 7ce1b6f9..00000000 --- a/test/integration/publish/pactDirTestsWithOtherStuff/publish-success2.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "consumer": { - "name": "consumer" - }, - "provider": { - "name": "publisher2" - }, - "interactions": [ - { - "description": "Greeting", - "request": { - "method": "GET", - "path": "/" - }, - "response": { - "status": 200, - "headers": { - }, - "body": { - "greeting": "Hello" - } - } - } - ], - "metadata": { - "pactSpecificationVersion": "2.0.0" - } -} diff --git a/test/integration/publish/pactDirTestsWithOtherStuff/test.txt b/test/integration/publish/pactDirTestsWithOtherStuff/test.txt deleted file mode 100644 index 7ef786aa..00000000 --- a/test/integration/publish/pactDirTestsWithOtherStuff/test.txt +++ /dev/null @@ -1 +0,0 @@ -This is not a Pact file, but should also not break the test suite. diff --git a/test/integration/publish/publish-fail.json b/test/integration/publish/publish-fail.json deleted file mode 100644 index 0707f1bb..00000000 --- a/test/integration/publish/publish-fail.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "interactions": [ - { - "description": "Greeting", - "request": { - "method": "GET", - "path": "/" - }, - "response": { - "status": 200, - "headers": { - }, - "body": { - "greeting": "Hello" - } - } - } - ], - "metadata": { - "pactSpecificationVersion": "2.0.0" - } -} diff --git a/test/integration/publish/publish-success.json b/test/integration/publish/publish-success.json deleted file mode 100644 index 97f4cd6a..00000000 --- a/test/integration/publish/publish-success.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "consumer": { - "name": "consumer" - }, - "provider": { - "name": "publisher" - }, - "interactions": [ - { - "description": "Greeting", - "request": { - "method": "GET", - "path": "/" - }, - "response": { - "status": 200, - "headers": { - }, - "body": { - "greeting": "Hello" - } - } - } - ], - "metadata": { - "pactSpecificationVersion": "2.0.0" - } -} From a52fe415a49c514124347775329f40a27fa114a4 Mon Sep 17 00:00:00 2001 From: Timothy Jones Date: Wed, 15 Mar 2023 16:45:23 +1100 Subject: [PATCH 06/14] build: Move rimraf to devDependencies; remove a number of now unused dependencies --- package.json | 13 ++----------- src/types.ts | 8 -------- 2 files changed, 2 insertions(+), 19 deletions(-) delete mode 100644 src/types.ts diff --git a/package.json b/package.json index 93a6b95f..a5fbb9d1 100644 --- a/package.json +++ b/package.json @@ -43,19 +43,12 @@ "access": "public" }, "dependencies": { - "@types/needle": "2.5.2", "bindings": "^1.5.0", "check-types": "7.3.0", - "cross-spawn": "7.0.3", - "mkdirp": "1.0.0", - "needle": "2.8.0", "node-addon-api": "^4.2.0", "pino": "^8.7.0", "pino-pretty": "^9.1.1", - "promise-timeout": "1.3.0", - "rimraf": "2.6.2", - "underscore": "1.12.1", - "unixify": "1.0.0" + "underscore": "1.12.1" }, "devDependencies": { "@grpc/grpc-js": "^1.8.0", @@ -68,13 +61,10 @@ "@types/chai-as-promised": "7.1.0", "@types/check-types": "^7.3.2", "@types/cors": "^2.8.6", - "@types/cross-spawn": "^6.0.1", "@types/decompress": "^4.2.3", "@types/express": "4.11.1", - "@types/mkdirp": "^0.5.2", "@types/mocha": "9.0.0", "@types/node": "^18.11.10", - "@types/promise-timeout": "^1.3.0", "@types/rimraf": "^2.0.2", "@types/sinon": "^9.0.11", "@types/tar": "^4.0.3", @@ -106,6 +96,7 @@ "nodemon": "^2.0.4", "prettier": "^2.3.0", "protobufjs": "^6.11.2", + "rimraf": "2.6.2", "sinon": "9.2.4", "snyk": "^1.747.0", "standard-version": "^9.1.0", diff --git a/src/types.ts b/src/types.ts deleted file mode 100644 index 80061004..00000000 --- a/src/types.ts +++ /dev/null @@ -1,8 +0,0 @@ -import needle from 'needle'; - -export interface HTTPConfig extends Omit { - headers: { - 'X-Pact-Mock-Service': string; - 'Content-Type': string; - }; -} From 6fc16fa83e30e8037bb81044cb20fff672f60e03 Mon Sep 17 00:00:00 2001 From: Timothy Jones Date: Wed, 15 Mar 2023 16:51:50 +1100 Subject: [PATCH 07/14] docs: Remove documentation for the APIs that were backed by Ruby --- README.md | 327 +----------------------------------------------------- 1 file changed, 1 insertion(+), 326 deletions(-) diff --git a/README.md b/README.md index 80ce41ad..cde018c6 100644 --- a/README.md +++ b/README.md @@ -75,40 +75,10 @@ TL;DR - you almost always want Pact JS. | Node.js | Pact JS | | | Browser testing | Pact Web | You probably still want Pact JS. See [Using Pact in non-Node environments](https://github.com/pact-foundation/pact-js#using-pact-in-non-node-environments) \* | | Isomorphic testing | Pact Web | You probably still want Pact JS. See [Using Pact in non-Node environments](https://github.com/pact-foundation/pact-js#using-pact-in-non-node-environments) \* | -| Publishing to Pact Broker | Pact Node | Included in Pact JS distribution | +| Publishing to Pact Broker | Pact CLI | | \* The "I need to run it in the browser" question comes up occasionally. The question is this - for your JS code to be able to make a call to another API, is this dependent on browser-specific code? In most cases, people use tools like React/Angular which have libraries that work on the server and client side, in which case, these tests don't need to run in a browser and could instead be executed in a Node.js environment. -## Usage - -Simply require the library and call the create function to start the mock service - -```js -var pact = require("@pact-foundation/pact-core"); -var server = pact.createServer({ port: 9999 }); -server.start().then(function() { - // Do your testing/development here -}); -``` - -Or if you're using Typescript instead of plain old Javascript - -```ts -import pact from "@pact-foundation/pact-core"; -const server = pact.createServer({ port: 9999 }); -server.start().then(() => { - // Do your testing/development here -}); -``` - -Or you can also use the CLI - -``` -$# pact mock --port 9999 -``` - -To see the list commands possible with the CLI, simply ask for help `$# pact --help` - ## Documentation ### Set Log Level @@ -118,123 +88,6 @@ var pact = require("@pact-foundation/pact-core"); pact.logLevel("debug"); ``` -### Mock Servers - -Mock servers are used by Pact to record interactions and create pact contracts. - -#### Create Mock Server - -```js -var pact = require('@pact-foundation/pact-core'); -var server = pact.createServer({ - ... -}); -``` - -**Options:** - -| Parameter | Required? | Type | Description | -| ------------------- | --------- | ---------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------ | -| `port` | false | number | Port number that the server runs on, defaults to random available port | -| `host` | false | string | Host on which to bind the server on, defaults to 'localhost'. Supports '0.0.0.0' to bind on all IPv4 addresses on the local machine. | -| `log` | false | string | File to log output on relative to current working directory, defaults to none | -| `logLevel` | false | LogLevel (string) | Log level to pass to the pact core. One of "DEBUG", "ERROR", "WARN", "INFO" | -| `ssl` | false | boolean | Create a self-signed SSL cert to run the server over HTTPS , defaults to `false` | -| `sslcert` | false | string | Path to a custom self-signed SSL cert file, 'ssl' option must be set to true to use this option, defaults to none | -| `sslkey` | false | string | Path a custom key and self-signed SSL cert key file, 'ssl' option must be set to true to use this, defaults to none | -| `cors` | false | boolean | Allow CORS OPTION requests to be accepted, defaults to 'false' | -| `dir` | false | string | Directory to write the pact contracts relative to the current working directory, defaults to none | -| `spec` | false | number | The pact specification version to use when writing pact contracts, defaults to '1' | -| `consumer` | false | string | The name of the consumer to be written to the pact contracts, defaults to none | -| `provider` | false | string | The name of the provider to be written to the pact contracts, defaults to none | -| `pactFileWriteMode` | false | `overwrite` OR `update` OR `merge` | Control how the pact file is created. Defaults to "overwrite" | -| `format` | false | `json` OR `xml` | Format to write the results as, either in JSON or XML, defaults to JSON | -| `out` | false | string | Write output to a file instead of returning it in the promise, defaults to none | -| `timeout` | false | number | How long to wait for the mock server to start up (in milliseconds). Defaults to 30000 (30 seconds) | - -#### List Mock Servers - -If you ever need to see which servers are currently created. - -```js -var pact = require("@pact-foundation/pact-core"); -var servers = pact.listServers(); -console.log(JSON.stringify(servers)); -``` - -#### Remove All Mock Servers - -Remove all servers once you're done with them in one fell swoop. - -```js -var pact = require("@pact-foundation/pact-core"); -pact.removeAllServers(); -``` - -#### Start a Mock Server - -Start the current server. - -```js -var pact = require("@pact-foundation/pact-core"); -pact.createServer() - .start() - .then(function() { - // Do something after it started - }); -``` - -#### Stop a Mock server - -Stop the current server. - -```js -var pact = require("@pact-foundation/pact-core"); -pact.createServer() - .stop() - .then(function() { - // Do something after it stopped - }); -``` - -#### Delete a Mock server - -Stop the current server and deletes it from the list. - -```js -var pact = require("@pact-foundation/pact-core"); -pact.createServer() - .delete() - .then(function() { - // Do something after it was killed - }); -``` - -#### Check if a Mock server is running - -```js -var pact = require("@pact-foundation/pact-core"); -pact.createServer().running; -``` - -#### Mock Server Events - -There's 3 different events available, 'start', 'stop' and 'delete'. They can be listened to the same way as an [EventEmitter](https://nodejs.org/api/events.html). - -```js -var pact = require("@pact-foundation/pact-core"); -var server = pact.createServer(); -server.on("start", function() { - console.log("started"); -}); -server.on("stop", function() { - console.log("stopped"); -}); -server.on("delete", function() { - console.log("deleted"); -}); -``` - ### Provider Verification Read more about [Verify Pacts](https://github.com/realestate-com-au/pact/wiki/Verifying-pacts). @@ -289,184 +142,6 @@ ConsumerVersionSelector { See the [Pact Broker documentation on selectors](https://docs.pact.io/pact_broker/advanced_topics/consumer_version_selectors) for more information. -### Pact Broker Publishing - -```js -var pact = require('@pact-foundation/pact-core'); -var opts = { - ... -}; - -pact.publishPacts(opts).then(function () { - // do something -}); -``` - -**Options**: - -| Parameter | Required? | Type | Description | -| -------------------- | --------- | ------ | ------------------------------------------------------------------- | -| `pactFilesOrDirs` | true | array | Array of local Pact files or directories containing them. Required. | -| `pactBroker` | true | string | URL of the Pact Broker to publish pacts to. Required. | -| `consumerVersion` | true | string | A string containing a semver-style version e.g. 1.0.0. Required. | -| `pactBrokerUsername` | false | string | Username for Pact Broker basic authentication. Optional | -| `pactBrokerPassword` | false | string | Password for Pact Broker basic authentication. Optional | -| `pactBrokerToken` | false | string | Bearer token for Pact Broker authentication. Optional | -| `tags` | false | array | An array of Strings to tag the Pacts being published. Optional | -| `branch` | false | string | The branch to associate with the published pacts. Optional but recommended | -| `autoDetectVersionProperties` | false | boolean | Automatically detect the repository branch from known CI environment variables or git CLI. Supports Buildkite, Circle CI, Travis CI, GitHub Actions, Jenkins, Hudson, AppVeyor, GitLab, CodeShip, Bitbucket and Azure DevOps. Optional | -| `buildUrl` | false | string | The build URL that created the pact. Optional | -| `verbose` | false | boolean | Enables verbose output for underlying pact binary. | - -### Pact Broker Deployment Check - -```js -var pact = require('@pact-foundation/pact-core'); -var opts = { - ... -}; - -pact.canDeploy(opts) - .then(function (result) { - // You can deploy this - // If output is not specified or is json, result describes the result of the check. - // If outout is 'table', it is the human readable string returned by the check - }) - .catch(function(error) { - // You can't deploy this - // if output is not specified, or is json, error will be an object describing - // the result of the check (if the check failed), - // if output is 'table', then the error will be a string describing the output from the binary, - - // In both cases, `error` will be an Error object if something went wrong during the check. - }); -``` - -**Options**: - -| Parameter | Required? | Type | Description | -| -------------------- | --------- | ----------- | ----------------------------------------------------------------------------------- | -| `pacticipants` | true | []objects | An array of version [selectors](docs.pact.io/selectors) in the form `{ name: String, latest?: string | boolean, version?: string }` | -| | | | specify a tag, use the tagname with latest. Specify one of these per pacticipant | -| | | | that you want to deploy | -| `pactBroker` | true | string | URL of the Pact Broker to query about deployment. Required. | -| `pactBrokerUsername` | false | string | Username for Pact Broker basic authentication. Optional | -| `pactBrokerPassword` | false | string | Password for Pact Broker basic authentication. Optional | -| `pactBrokerToken` | false | string | Bearer token for Pact Broker authentication. Optional | -| `output` | false | json,table | Specify output to show, json or table. Optional, Defaults to json. | -| `verbose` | false | boolean | Enables verbose output for underlying pact binary. | -| `retryWhileUnknown` | false | number | The number of times to retry while there is an unknown verification result. Optional| -| `retryInterval` | false | number | The time between retries in seconds, use with retryWhileUnknown. Optional | -| `to` | false | string | The tag that you want to deploy to (eg, 'prod') | - -### Stub Servers - -Stub servers create runnable APIs from existing pact files. - -The interface is comparable to the Mock Server API. - -#### Create Stub Server - -```js -var pact = require('@pact-foundation/pact-core'); -var server = pact.createStub({ - ... -}); -``` - -**Options**: - -| Parameter | Required? | Type | Description | -| --------- | --------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------ | -| pactUrls | true | array | List of local Pact files to create the stub service from | -| port | false | number | Port number that the server runs on, defaults to random available port | -| host | false | string | Host on which to bind the server on, defaults to 'localhost'. Supports '0.0.0.0' to bind on all IPv4 addresses on the local machine. | -| log | false | string | File to log output on relative to current working directory, defaults to none | -| logLevel | false | LogLevel (string) | Log level to pass to the pact core. One of "DEBUG", "ERROR", "WARN", "INFO" | -| ssl | false | boolean | Create a self-signed SSL cert to run the server over HTTPS , defaults to 'false' | -| sslcert | false | string | Path to a custom self-signed SSL cert file, 'ssl' option must be set to true to use this option. Defaults false | to none | -| sslkey | false | string | Path a custom key and self-signed SSL cert key file, 'ssl' option must be set to true to use this option false. Defaults to none | -| cors | false | boolean | Allow CORS OPTION requests to be accepted, defaults to 'false' | -| timeout | false | number | How long to wait for the stub server to start up (in milliseconds). Defaults to 30000 (30 seconds) | - -### Message Pacts - -#### Create Message Pacts - -```js -var pact = require('@pact-foundation/pact-core'); -var message = pact.createMessage({ - ... -}); -``` - -**Options**: - -| Parameter | Required? | Type | Description | -| ------------------- | --------- | ---------------------------------- | ------------------------------------------------------------------------------------------------- | -| `dir` | true | string | Directory to write the pact contracts relative to the current working directory, defaults to none | -| `consumer` | true | string | The name of the consumer to be written to the pact contracts, defaults to none | -| `provider` | true | string | The name of the provider to be written to the pact contracts, defaults to none | -| `pactFileWriteMode` | false | `"overwrite" | "update" | "merge"` | Control how the pact file is created. Defaults to "update" | - -##### Example - -```js -const messageFactory = messageFactory({ - consumer: "consumer", - provider: "provider", - dir: dirname(`${__filename}/pacts`), - content: `{ - "description": "a test mesage", - "content": { - "name": "Mary" - } - }` -}); - -messageFactory.createMessage(); -``` - -## CLI Tools - -This package also comes with the [Pact Standalone Tools](https://github.com/pact-foundation/pact-ruby-standalone/releases) available as linked binaries in the [standard](https://docs.npmjs.com/files/folders#executables) NPM installation directory (e..g. `./node_modules/.bin`). - -This means you may call them direct from scripts in your package json, for example: - -``` -"scripts": { - "pactPublish": "pact-broker publish ./pacts --consumer-app-version=$\(git describe\) --broker-base-url=$BROKER_BASE_URL --broker-username=$BROKER_USERNAME --broker-password=BROKER_PASSWORD"` -} -These are available in circumstances where `pact-core` has not yet implemented a feature or access via JavaScript APIs is not desirable. To run the binaries is as simple as the following: - -*Example can-i-deploy check*: -```sh -./node_modules/.bin/pact-broker can-i-deploy --pacticipant "Banana Service" --broker-base-url https://test.pact.dius.com.au --latest --broker-username dXfltyFMgNOFZAxr8io9wJ37iUpY42M --broker-password O5AIZWxelWbLvqMd8PkAVycBJh2Psyg1 - -Computer says no ¯\_(ツ)_/¯ - -CONSUMER | C.VERSION | PROVIDER | P.VERSION | SUCCESS? ----------------|-----------|----------------|-----------|--------- -Banana Service | 1.0.0 | Fofana Service | 1.0.0 | false - -The verification between the latest version of Banana Service (1.0.0) and version 1.0.0 of Fofana Service failed -``` - -The following are the binaries currently made available: - -- `pact-mock-service` -- `pact-broker` -- `pact-stub-service` -- `pact-message` -- `pact-provider-verifier` -- `pact` - -## Windows Issues - -### Enable Long Paths - -[Windows has a default path length limit of 260](https://docs.microsoft.com/en-us/windows/desktop/fileio/naming-a-file#maximum-path-length-limitation) causing issues with projects that are nested deep inside several directory and with how npm handles node_modules directory structures. To fix this issue, please enable Windows Long Paths in the registry by running `regedit.exe`, find the key `HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\FileSystem\LongPathsEnabled` and change the value from `0` to `1`, then reboot your computer. Pact should now work as it should, if not, please [raise an issue on github](https://github.com/pact-foundation/pact-js-core/issues). - ## Contributing To develop this project, simply install the dependencies with `npm install --ignore-scripts`, and run `npm run watch` to for continual development, linting and testing when a source file changes. From 5de47204fc3be1054c1b69fdb1dcf989c5571b88 Mon Sep 17 00:00:00 2001 From: Timothy Jones Date: Wed, 15 Mar 2023 16:54:28 +1100 Subject: [PATCH 08/14] chore: Remove export of file that doesn't exist --- src/index.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/index.ts b/src/index.ts index 748a2586..519db4b5 100644 --- a/src/index.ts +++ b/src/index.ts @@ -15,5 +15,3 @@ export * from './consumer'; export * from './consumer/types'; export * from './ffi'; - -export * from './types'; From f2e88d0d21951aaf36c03fd1d70b87eadcea3b55 Mon Sep 17 00:00:00 2001 From: Timothy Jones Date: Wed, 15 Mar 2023 16:58:26 +1100 Subject: [PATCH 09/14] chore: Remove unused test files --- docker-compose.yml | 24 ------------------------ download-checksums.js | 1 - test/ssl/server.crt | 13 ------------- test/ssl/server.key | 15 --------------- 4 files changed, 53 deletions(-) delete mode 100644 docker-compose.yml delete mode 100644 download-checksums.js delete mode 100644 test/ssl/server.crt delete mode 100644 test/ssl/server.key diff --git a/docker-compose.yml b/docker-compose.yml deleted file mode 100644 index b0571222..00000000 --- a/docker-compose.yml +++ /dev/null @@ -1,24 +0,0 @@ -version: '3' - -services: - postgres: - image: postgres - ports: - - "5432" - environment: - POSTGRES_USER: postgres - POSTGRES_PASSWORD: password - POSTGRES_DB: postgres - - broker_app: - image: dius/pact-broker - ports: - - "80" - links: - - postgres - environment: - PACT_BROKER_DATABASE_USERNAME: postgres - PACT_BROKER_DATABASE_PASSWORD: password - PACT_BROKER_DATABASE_HOST: postgres - PACT_BROKER_DATABASE_NAME: postgres - PASSENGER_COMPILE_NATIVE_SUPPORT_BINARY: 0 diff --git a/download-checksums.js b/download-checksums.js deleted file mode 100644 index 8a7e98c0..00000000 --- a/download-checksums.js +++ /dev/null @@ -1 +0,0 @@ -require('./standalone/install').downloadChecksums(); diff --git a/test/ssl/server.crt b/test/ssl/server.crt deleted file mode 100644 index 766e15f9..00000000 --- a/test/ssl/server.crt +++ /dev/null @@ -1,13 +0,0 @@ ------BEGIN CERTIFICATE----- -MIICATCCAWoCCQDwiTCB86+wIDANBgkqhkiG9w0BAQUFADBFMQswCQYDVQQGEwJB -VTETMBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50ZXJuZXQgV2lkZ2l0 -cyBQdHkgTHRkMB4XDTE3MDEyMTEwNDUxNVoXDTE4MDEyMTEwNDUxNVowRTELMAkG -A1UEBhMCQVUxEzARBgNVBAgTClNvbWUtU3RhdGUxITAfBgNVBAoTGEludGVybmV0 -IFdpZGdpdHMgUHR5IEx0ZDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAqo26 -Be/QVIrdPoRwJoCxHWJXc2hbqWF3kHbRO3hfBgy+Zz+yzY7b08pgCUWul9n5ROlD -IlZ6VvFMWVq2GK87VB1qyzTY8SpdCBgocDby91U+qUWQKVJPALmLtMjZcUJaFZkt -0gKS6teDmAgs+ZusEGNJYZp7g9j7YRgQvi/aIu8CAwEAATANBgkqhkiG9w0BAQUF -AAOBgQAINA5mw2DUJ5DYZ5C6nzLlp0NrdjpLF2yVHV/k4DvtwLzO8VnS9yELJiSz -E0cPHEQ55WWvpEdhARZffRYfp2zGbCgQStUDfOkn8HX+xaRRfbmOlN4v1H1w3otM -XMcbeTx4PqVmwJ80qgy7Mt/SJb/OTRpSqOyqYyqSxsxZ2rfdEg== ------END CERTIFICATE----- diff --git a/test/ssl/server.key b/test/ssl/server.key deleted file mode 100644 index 91cdd60b..00000000 --- a/test/ssl/server.key +++ /dev/null @@ -1,15 +0,0 @@ ------BEGIN RSA PRIVATE KEY----- -MIICXQIBAAKBgQCqjboF79BUit0+hHAmgLEdYldzaFupYXeQdtE7eF8GDL5nP7LN -jtvTymAJRa6X2flE6UMiVnpW8UxZWrYYrztUHWrLNNjxKl0IGChwNvL3VT6pRZAp -Uk8AuYu0yNlxQloVmS3SApLq14OYCCz5m6wQY0lhmnuD2PthGBC+L9oi7wIDAQAB -AoGAN8ulz8tknEPRnWI2TmJLjxFdCqRZWFBKjThRuuLmM1R39c8g756My/yo7l+d -fpAQvDqTe+hOnaLTF2hVqj2papIEwLjWElDIWGy13Jk/WcqL8+WpS1BtpsKQT30X -3TojqFnXsL4wGdEBXbX/9ig1Z++qpODa5jLiDMXKUlkCgAECQQDjCMCayFpRx901 -8+LjFNa78OFcf6t/9UKV6x1gSZ0386Y2YDvEtHw0Ls3cd1O3918dPpQ8bGMD8vXI -FCkeF1HvAkEAwFA91KJqD0kFkcu/lUDcd/5TKavMm2nlTP/l9XcPbn89voEK5lw8 -MGE5FG4NVpOj1wOt5hXr8HHhSNVSKfc/AQJBAJStWKSEbFF+F2mLq5uWPAGb/5l5 -qjADx3UyIWy7CJBpqQGXB80LfQMXW4zzQAoLn2ghYSYovLcLVtWODlc8YlUCQC6A -eKL87tZpWs5pTRcjCux889EEuMHvtkGLMyjKtFGMtPpmq6MONIOiTrIQ9mqz4o8w -VZFoRZfrgYUiB+8b2QECQQCytA8TfzS8gcDI1IQMUPW5ADjpA83qMfZgWKouj/Xa -wMF+w2cVyyshrYSGbsZmBj8uXoot2CuefYuNgyaXT9/D ------END RSA PRIVATE KEY----- From ca178a85ce281b056c09120652948b17d3334dcc Mon Sep 17 00:00:00 2001 From: Timothy Jones Date: Wed, 15 Mar 2023 17:28:10 +1100 Subject: [PATCH 10/14] build: Unzip the binaries anyway, even if they already exist --- script/lib/download-ffi.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/script/lib/download-ffi.sh b/script/lib/download-ffi.sh index f4bc48a3..6788a3dd 100755 --- a/script/lib/download-ffi.sh +++ b/script/lib/download-ffi.sh @@ -52,7 +52,7 @@ function download_ffi { download_ffi_file "${PREFIX}pact_ffi-$SUFFIX" "${OUTPUT_FILENAME}" debug_log " ... unzipping '$DOWNLOAD_LOCATION'" - gunzip "$DOWNLOAD_LOCATION" + gunzip -f "$DOWNLOAD_LOCATION" } if [ -z "${ONLY_DOWNLOAD_PACT_FOR_WINDOWS:-}" ]; then From 0f76ad2f38c88c454789aa0455ddd27d55270a81 Mon Sep 17 00:00:00 2001 From: Yousaf Nabi Date: Sun, 9 Jun 2024 01:08:05 +0100 Subject: [PATCH 11/14] chore: remove more bits of ruby standalone code --- .github/workflows/build-and-test.yml | 20 +- .gitignore | 10 - DEVELOPER.md | 2 - README.md | 2 +- package-lock.json | 277 ++++------------------ package.json | 3 +- script/ci/download-standalone-and-test.sh | 9 - script/ci/release.sh | 2 +- script/ci/unpack-and-test.sh | 2 +- script/download-standalone.sh | 5 - script/trigger-update.sh | 30 --- 11 files changed, 64 insertions(+), 298 deletions(-) delete mode 100755 script/ci/download-standalone-and-test.sh delete mode 100755 script/download-standalone.sh delete mode 100755 script/trigger-update.sh diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index b6de64b9..46a2132c 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -103,17 +103,15 @@ jobs: - run: LOG_LEVEL=debug ./script/ci/unpack-and-test.sh - # Linux aarch64 tests are skipped as QEMU fails when executing the ruby binaries - # Related comment: https://github.com/phusion/passenger/issues/2288#issuecomment-1387625121 - # - name: Set up QEMU - # if: runner.os == 'Linux' - # uses: docker/setup-qemu-action@v3 - # - name: Set up Docker Buildx - # if: runner.os == 'Linux' - # uses: docker/setup-buildx-action@v3 - # - if: runner.os == 'Linux' - # name: test arm64 - # run: docker run -v $PWD:/home --platform linux/arm64 --rm node:20 bin/bash -c 'cd /home && /home/script/ci/unpack-and-test.sh' + - name: Set up QEMU + if: runner.os == 'Linux' + uses: docker/setup-qemu-action@v3 + - name: Set up Docker Buildx + if: runner.os == 'Linux' + uses: docker/setup-buildx-action@v3 + - if: runner.os == 'Linux' + name: test arm64 + run: docker run -v $PWD:/home --platform linux/arm64 --rm node:20 bin/bash -c 'cd /home && /home/script/ci/unpack-and-test.sh' release_dry_run: runs-on: ubuntu-latest diff --git a/.gitignore b/.gitignore index a3d54657..b428edab 100644 --- a/.gitignore +++ b/.gitignore @@ -54,16 +54,6 @@ bin/**/**.js # ts-node cache ts-node-* -# pact standalone binaries -# standalone/* -standalone/darwin* -standalone/linux* -standalone/windows* -standalone/*.d.ts -standalone/*.js -standalone/*.checksum -standalone/*.gz -standalone/README.md # FFI native bindings *.so *.dll* diff --git a/DEVELOPER.md b/DEVELOPER.md index 55b54af5..4a90971f 100644 --- a/DEVELOPER.md +++ b/DEVELOPER.md @@ -18,12 +18,10 @@ As a developer, you need to run `bash script/ci/prebuild.sh` to - download the FFI libraries to `ffi` folder - prebuilds the binaries and outputs to `prebuilds` - cleans up `ffi` and `build` -- downloads the `pact-ruby-standalone` bindings to `standalone` For end users, the following is provided as part of the packaging and release step in CI. - the `prebuilds` folder containing built `ffi` bindings -- the `standalone` folder containing the pact ruby standalone bindings is populated, - the `binding.gyp` file is removed from the npm package, so `npm install` doesn't attempt to build the `ffi` buildings, that are prebuilt. If you have a `binding.gyp` file, and have created `prebuilds` you will want to perform `npm ci` or `npm install` with `--ignore-scripts` set, to avoid building the `ffi` which is prebuilt. diff --git a/README.md b/README.md index 513bacad..400fbdc2 100644 --- a/README.md +++ b/README.md @@ -36,7 +36,7 @@ # Pact-JS Core -A wrapper for the [Pact](http://pact.io) [CLI Tools](https://github.com/pact-foundation/pact-ruby-standalone). +A wrapper for the [Pact](http://pact.io) [Reference Core Library](https://github.com/pact-foundation/pact-reference). diff --git a/package-lock.json b/package-lock.json index bb78ee0a..1af85b67 100644 --- a/package-lock.json +++ b/package-lock.json @@ -19,18 +19,11 @@ "win32" ], "dependencies": { - "chalk": "4.1.2", "check-types": "7.3.0", - "cross-spawn": "7.0.3", - "mkdirp": "1.0.0", - "needle": "^3.2.0", "node-gyp-build": "^4.6.0", "pino": "^8.7.0", "pino-pretty": "^9.1.1", - "promise-timeout": "1.3.0", - "rimraf": "2.6.2", - "underscore": "1.12.1", - "unixify": "1.0.0" + "underscore": "1.12.1" }, "devDependencies": { "@grpc/grpc-js": "^1.8.0", @@ -43,14 +36,11 @@ "@types/chai-as-promised": "7.1.0", "@types/check-types": "^7.3.2", "@types/cors": "^2.8.6", - "@types/cross-spawn": "^6.0.1", "@types/decompress": "^4.2.3", "@types/express": "4.11.1", - "@types/mkdirp": "^0.5.2", "@types/mocha": "9.0.0", "@types/needle": "2.5.2", "@types/node": "^18.11.10", - "@types/promise-timeout": "^1.3.0", "@types/rimraf": "^2.0.2", "@types/sinon": "^9.0.11", "@types/tar": "^4.0.3", @@ -84,6 +74,7 @@ "nodemon": "^2.0.4", "prettier": "^2.3.0", "protobufjs": "^7.2.4", + "rimraf": "2.7.1", "sinon": "9.2.4", "ts-node": "10.9.1", "typescript": "4.7.4" @@ -628,15 +619,6 @@ "@types/node": "*" } }, - "node_modules/@types/cross-spawn": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/@types/cross-spawn/-/cross-spawn-6.0.2.tgz", - "integrity": "sha512-KuwNhp3eza+Rhu8IFI5HUXRP0LIhqH5cAjubUvGXXthh4YYBuP2ntwEX+Cz8GJoZUHlKo247wPWOfA9LYEq4cw==", - "dev": true, - "dependencies": { - "@types/node": "*" - } - }, "node_modules/@types/decompress": { "version": "4.2.4", "resolved": "https://registry.npmjs.org/@types/decompress/-/decompress-4.2.4.tgz", @@ -731,15 +713,6 @@ "minipass": "*" } }, - "node_modules/@types/mkdirp": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/@types/mkdirp/-/mkdirp-0.5.2.tgz", - "integrity": "sha512-U5icWpv7YnZYGsN4/cmh3WD2onMY0aJIiTE6+51TwJCttdHvtCYmkBNOobHlXwrJRL0nkH9jH4kD+1FAdMN4Tg==", - "dev": true, - "dependencies": { - "@types/node": "*" - } - }, "node_modules/@types/mocha": { "version": "9.0.0", "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-9.0.0.tgz", @@ -767,12 +740,6 @@ "integrity": "sha512-Gj7cI7z+98M282Tqmp2K5EIsoouUEzbBJhQQzDE3jSIRk6r9gsz0oUokqIUR4u1R3dMHo0pDHM7sNOHyhulypw==", "dev": true }, - "node_modules/@types/promise-timeout": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@types/promise-timeout/-/promise-timeout-1.3.0.tgz", - "integrity": "sha512-AtVKSZUtpBoZ4SshXJk5JcTXJllinHKKx615lsRNJUsbbFlI0AI8drlnoiQ+PNvjkeoF9Y8fJUh6UO2khsIBZw==", - "dev": true - }, "node_modules/@types/qs": { "version": "6.9.7", "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz", @@ -1452,6 +1419,7 @@ "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -1834,7 +1802,8 @@ "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true }, "node_modules/concat-stream": { "version": "2.0.0", @@ -2352,6 +2321,7 @@ "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", @@ -3956,6 +3926,7 @@ "version": "7.2.0", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", + "dev": true, "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -4790,7 +4761,8 @@ "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true }, "node_modules/joycon": { "version": "3.1.1", @@ -5325,6 +5297,7 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, "dependencies": { "brace-expansion": "^1.1.7" }, @@ -5363,17 +5336,6 @@ "node": ">=16 || 14 >=14.17" } }, - "node_modules/mkdirp": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.0.tgz", - "integrity": "sha512-4Pb+8NJ5DdvaWD797hKOM28wMXsObb4HppQdIwKUHFiB69ICZ4wktOE+qsGGBy7GtwgYNizp0R9KEy4zKYBLMg==", - "bin": { - "mkdirp": "bin/cmd.js" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/mocha": { "version": "9.2.2", "resolved": "https://registry.npmjs.org/mocha/-/mocha-9.2.2.tgz", @@ -5523,7 +5485,8 @@ "node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true }, "node_modules/nanoid": { "version": "3.3.1", @@ -5549,41 +5512,6 @@ "integrity": "sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==", "dev": true }, - "node_modules/needle": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/needle/-/needle-3.2.0.tgz", - "integrity": "sha512-oUvzXnyLiVyVGoianLijF9O/RecZUf7TkBfimjGrLM4eQhXyeJwM6GeAWccwfQ9aa4gMCZKqhAOuLaMIcQxajQ==", - "dependencies": { - "debug": "^3.2.6", - "iconv-lite": "^0.6.3", - "sax": "^1.2.4" - }, - "bin": { - "needle": "bin/needle" - }, - "engines": { - "node": ">= 4.4.x" - } - }, - "node_modules/needle/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dependencies": { - "ms": "^2.1.1" - } - }, - "node_modules/needle/node_modules/iconv-lite": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", - "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/negotiator": { "version": "0.6.3", "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", @@ -6010,6 +5938,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, "engines": { "node": ">=0.10.0" } @@ -6018,6 +5947,7 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, "engines": { "node": ">=8" } @@ -6225,11 +6155,6 @@ "resolved": "https://registry.npmjs.org/process-warning/-/process-warning-2.2.0.tgz", "integrity": "sha512-/1WZ8+VQjR6avWOgHeEPd7SDQmFQ1B5mC1eRXsCm5TarlNmx/wCsa5GEaxGm05BORRtyG/Ex/3xq3TuRvq57qg==" }, - "node_modules/promise-timeout": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/promise-timeout/-/promise-timeout-1.3.0.tgz", - "integrity": "sha512-5yANTE0tmi5++POym6OgtFmwfDvOXABD9oj/jLQr5GPEyuNEb7jH4wbbANJceJid49jwhi1RddxnhnEAb/doqg==" - }, "node_modules/protobufjs": { "version": "7.2.5", "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.2.5.tgz", @@ -6597,11 +6522,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/remove-trailing-separator": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", - "integrity": "sha512-/hS+Y0u3aOfIETiaiirUFwDBDzmXPvO+jAfKTitUngIPzdKc6Z0LoFjM/CK5PL4C+eKwHohlHAb6H0VFfmmUsw==" - }, "node_modules/require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", @@ -6657,11 +6577,13 @@ } }, "node_modules/rimraf": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz", - "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==", + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "dev": true, "dependencies": { - "glob": "^7.0.5" + "glob": "^7.1.3" }, "bin": { "rimraf": "bin.js" @@ -6825,12 +6747,8 @@ "node_modules/safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" - }, - "node_modules/sax": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", - "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true }, "node_modules/secure-json-parse": { "version": "2.7.0", @@ -6931,6 +6849,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, "dependencies": { "shebang-regex": "^3.0.0" }, @@ -6942,6 +6861,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, "engines": { "node": ">=8" } @@ -7585,28 +7505,6 @@ "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.12.1.tgz", "integrity": "sha512-hEQt0+ZLDVUMhebKxL4x1BTtDY7bavVofhZ9KZ4aI26X9SRaE+Y3m83XUL1UP2jn8ynjndwCCpEHdUG+9pP1Tw==" }, - "node_modules/unixify": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unixify/-/unixify-1.0.0.tgz", - "integrity": "sha512-6bc58dPYhCMHHuwxldQxO3RRNZ4eCogZ/st++0+fcC1nr0jiGUtAdBJ2qzmLQWSxbtz42pWt4QQMiZ9HvZf5cg==", - "dependencies": { - "normalize-path": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/unixify/node_modules/normalize-path": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", - "integrity": "sha512-3pKJwH184Xo/lnH6oyP1q2pMd7HcypqqmRs91/6/i2CGtWwIKGCkOOMTm/zXbgTEWHw1uNpNi/igc3ePOYHb6w==", - "dependencies": { - "remove-trailing-separator": "^1.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/unpipe": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", @@ -7677,6 +7575,7 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, "dependencies": { "isexe": "^2.0.0" }, @@ -8338,15 +8237,6 @@ "@types/node": "*" } }, - "@types/cross-spawn": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/@types/cross-spawn/-/cross-spawn-6.0.2.tgz", - "integrity": "sha512-KuwNhp3eza+Rhu8IFI5HUXRP0LIhqH5cAjubUvGXXthh4YYBuP2ntwEX+Cz8GJoZUHlKo247wPWOfA9LYEq4cw==", - "dev": true, - "requires": { - "@types/node": "*" - } - }, "@types/decompress": { "version": "4.2.4", "resolved": "https://registry.npmjs.org/@types/decompress/-/decompress-4.2.4.tgz", @@ -8440,15 +8330,6 @@ "minipass": "*" } }, - "@types/mkdirp": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/@types/mkdirp/-/mkdirp-0.5.2.tgz", - "integrity": "sha512-U5icWpv7YnZYGsN4/cmh3WD2onMY0aJIiTE6+51TwJCttdHvtCYmkBNOobHlXwrJRL0nkH9jH4kD+1FAdMN4Tg==", - "dev": true, - "requires": { - "@types/node": "*" - } - }, "@types/mocha": { "version": "9.0.0", "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-9.0.0.tgz", @@ -8476,12 +8357,6 @@ "integrity": "sha512-Gj7cI7z+98M282Tqmp2K5EIsoouUEzbBJhQQzDE3jSIRk6r9gsz0oUokqIUR4u1R3dMHo0pDHM7sNOHyhulypw==", "dev": true }, - "@types/promise-timeout": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@types/promise-timeout/-/promise-timeout-1.3.0.tgz", - "integrity": "sha512-AtVKSZUtpBoZ4SshXJk5JcTXJllinHKKx615lsRNJUsbbFlI0AI8drlnoiQ+PNvjkeoF9Y8fJUh6UO2khsIBZw==", - "dev": true - }, "@types/qs": { "version": "6.9.7", "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz", @@ -8969,6 +8844,7 @@ "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -9255,7 +9131,8 @@ "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true }, "concat-stream": { "version": "2.0.0", @@ -9648,6 +9525,7 @@ "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, "requires": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", @@ -10851,6 +10729,7 @@ "version": "7.2.0", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", + "dev": true, "requires": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -11418,7 +11297,8 @@ "isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true }, "joycon": { "version": "3.1.1", @@ -11829,6 +11709,7 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, "requires": { "brace-expansion": "^1.1.7" } @@ -11855,11 +11736,6 @@ "integrity": "sha512-MzWSV5nYVT7mVyWCwn2o7JH13w2TBRmmSqSRCKzTw+lmft9X4z+3wjvs06Tzijo5z4W/kahUCDpRXTF+ZrmF/w==", "dev": true }, - "mkdirp": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.0.tgz", - "integrity": "sha512-4Pb+8NJ5DdvaWD797hKOM28wMXsObb4HppQdIwKUHFiB69ICZ4wktOE+qsGGBy7GtwgYNizp0R9KEy4zKYBLMg==" - }, "mocha": { "version": "9.2.2", "resolved": "https://registry.npmjs.org/mocha/-/mocha-9.2.2.tgz", @@ -11976,7 +11852,8 @@ "ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true }, "nanoid": { "version": "3.3.1", @@ -11996,34 +11873,6 @@ "integrity": "sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==", "dev": true }, - "needle": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/needle/-/needle-3.2.0.tgz", - "integrity": "sha512-oUvzXnyLiVyVGoianLijF9O/RecZUf7TkBfimjGrLM4eQhXyeJwM6GeAWccwfQ9aa4gMCZKqhAOuLaMIcQxajQ==", - "requires": { - "debug": "^3.2.6", - "iconv-lite": "^0.6.3", - "sax": "^1.2.4" - }, - "dependencies": { - "debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "requires": { - "ms": "^2.1.1" - } - }, - "iconv-lite": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", - "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", - "requires": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - } - } - } - }, "negotiator": { "version": "0.6.3", "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", @@ -12338,12 +12187,14 @@ "path-is-absolute": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==" + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true }, "path-key": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==" + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true }, "path-parse": { "version": "1.0.7", @@ -12504,11 +12355,6 @@ "resolved": "https://registry.npmjs.org/process-warning/-/process-warning-2.2.0.tgz", "integrity": "sha512-/1WZ8+VQjR6avWOgHeEPd7SDQmFQ1B5mC1eRXsCm5TarlNmx/wCsa5GEaxGm05BORRtyG/Ex/3xq3TuRvq57qg==" }, - "promise-timeout": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/promise-timeout/-/promise-timeout-1.3.0.tgz", - "integrity": "sha512-5yANTE0tmi5++POym6OgtFmwfDvOXABD9oj/jLQr5GPEyuNEb7jH4wbbANJceJid49jwhi1RddxnhnEAb/doqg==" - }, "protobufjs": { "version": "7.2.5", "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.2.5.tgz", @@ -12791,11 +12637,6 @@ "functions-have-names": "^1.2.3" } }, - "remove-trailing-separator": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", - "integrity": "sha512-/hS+Y0u3aOfIETiaiirUFwDBDzmXPvO+jAfKTitUngIPzdKc6Z0LoFjM/CK5PL4C+eKwHohlHAb6H0VFfmmUsw==" - }, "require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", @@ -12832,11 +12673,12 @@ "dev": true }, "rimraf": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz", - "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==", + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "dev": true, "requires": { - "glob": "^7.0.5" + "glob": "^7.1.3" } }, "run-applescript": { @@ -12943,12 +12785,8 @@ "safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" - }, - "sax": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", - "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true }, "secure-json-parse": { "version": "2.7.0", @@ -13041,6 +12879,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, "requires": { "shebang-regex": "^3.0.0" } @@ -13048,7 +12887,8 @@ "shebang-regex": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==" + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true }, "side-channel": { "version": "1.0.4", @@ -13518,24 +13358,6 @@ "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.12.1.tgz", "integrity": "sha512-hEQt0+ZLDVUMhebKxL4x1BTtDY7bavVofhZ9KZ4aI26X9SRaE+Y3m83XUL1UP2jn8ynjndwCCpEHdUG+9pP1Tw==" }, - "unixify": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unixify/-/unixify-1.0.0.tgz", - "integrity": "sha512-6bc58dPYhCMHHuwxldQxO3RRNZ4eCogZ/st++0+fcC1nr0jiGUtAdBJ2qzmLQWSxbtz42pWt4QQMiZ9HvZf5cg==", - "requires": { - "normalize-path": "^2.1.1" - }, - "dependencies": { - "normalize-path": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", - "integrity": "sha512-3pKJwH184Xo/lnH6oyP1q2pMd7HcypqqmRs91/6/i2CGtWwIKGCkOOMTm/zXbgTEWHw1uNpNi/igc3ePOYHb6w==", - "requires": { - "remove-trailing-separator": "^1.0.1" - } - } - } - }, "unpipe": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", @@ -13594,6 +13416,7 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, "requires": { "isexe": "^2.0.0" } diff --git a/package.json b/package.json index a199368f..89bce53f 100644 --- a/package.json +++ b/package.json @@ -43,6 +43,7 @@ "access": "public" }, "dependencies": { + "check-types": "7.3.0", "node-gyp-build": "^4.6.0", "pino": "^8.7.0", "pino-pretty": "^9.1.1", @@ -111,7 +112,7 @@ "lint:fix": "npm run lint -- --fix", "prebuild": "npm run clean", "download-libs": "npm run clean && bash script/download-libs.sh", - "clean-libs": "rimraf standalone/*.{js,map,d.ts} standalone/{windows**,linux**,darwin**} 'ffi'", + "clean-libs": "rimraf 'ffi'", "build": "tsc --project tsconfig.build.json", "prerelease": "npm run snyk-protect", "release": "commit-and-tag-version", diff --git a/script/ci/download-standalone-and-test.sh b/script/ci/download-standalone-and-test.sh deleted file mode 100755 index 65639d43..00000000 --- a/script/ci/download-standalone-and-test.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/bash -eu -set -e # This needs to be here for windows bash, which doesn't read the #! line above -set -u - -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")"; pwd)" # Figure out where the script is running -. "$SCRIPT_DIR"/../lib/robust-bash.sh - -./script/download-standalone.sh -./script/ci/build-and-test.sh \ No newline at end of file diff --git a/script/ci/release.sh b/script/ci/release.sh index 2038eda8..7ddba128 100755 --- a/script/ci/release.sh +++ b/script/ci/release.sh @@ -79,7 +79,7 @@ if [ ! -z "${ONLY_DOWNLOAD_PACT_FOR_WINDOWS:-}" ]; then fi FETCH_ASSETS=true ./script/ci/check-release-libs.sh --fetch-assets -t "${NEXT_TAG}" -"$SCRIPT_DIR"/download-standalone-and-test.sh +"$SCRIPT_DIR"/build-and-test.sh if [[ ${DRY_RUN:-} == 'true' ]]; then VERSION=$NEXT_VERSION diff --git a/script/ci/unpack-and-test.sh b/script/ci/unpack-and-test.sh index 1f7fdd1b..23b28453 100755 --- a/script/ci/unpack-and-test.sh +++ b/script/ci/unpack-and-test.sh @@ -10,4 +10,4 @@ ls -1 artifact mkdir -p prebuilds mv artifact*/*.tar.gz . || echo "no mac prebuilds" ls *.gz |xargs -n1 tar -xzf -./script/ci/download-standalone-and-test.sh \ No newline at end of file +"$SCRIPT_DIR"/build-and-test.sh \ No newline at end of file diff --git a/script/download-standalone.sh b/script/download-standalone.sh deleted file mode 100755 index 44dff19b..00000000 --- a/script/download-standalone.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/bash -eu -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")"; pwd)" # Figure out where the script is running - -. "${SCRIPT_DIR}/lib/export-binary-versions.sh" -"${SCRIPT_DIR}/lib/download-standalone.sh" \ No newline at end of file diff --git a/script/trigger-update.sh b/script/trigger-update.sh deleted file mode 100755 index 569b6434..00000000 --- a/script/trigger-update.sh +++ /dev/null @@ -1,30 +0,0 @@ -#!/bin/sh - -# Script to trigger release of gem via the pact-foundation/release-gem action -# Requires a Github API token with repo scope stored in the -# environment variable GITHUB_ACCESS_TOKEN_FOR_PF_RELEASES - -: "${GITHUB_ACCESS_TOKEN_FOR_PF_RELEASES:?Please set environment variable GITHUB_ACCESS_TOKEN_FOR_PF_RELEASES}" - -if [ -n "$1" ]; then - version="\"${1}\"" -else - version="null" -fi - -repository_slug=$(git remote get-url $(git remote show) | cut -d':' -f2 | sed 's/\.git//') - -output=$(curl -v -X POST https://api.github.com/repos/${repository_slug}/dispatches \ - -H 'Accept: application/vnd.github.everest-preview+json' \ - -H "Authorization: Bearer $GITHUB_ACCESS_TOKEN_FOR_PF_RELEASES" \ - -d "{\"event_type\": \"pact-ruby-standalone-released\", \"client_payload\": {\"version\": ${version}}}" 2>&1) - -if ! echo "${output}" | grep "HTTP\/.* 204" > /dev/null; then - echo "$output" | sed "s/${GITHUB_ACCESS_TOKEN_FOR_PF_RELEASES}/********/g" - echo "Failed to trigger release" - exit 1 -else - echo "Release workflow triggered" -fi - -echo "https://github.com/${repository_slug}/actions?query=workflow%3A%22Update+Pact+Ruby+Standalone%22" From c6c8b253339ff071bf11d4a86049a2f89fce2119 Mon Sep 17 00:00:00 2001 From: Yousaf Nabi Date: Sun, 9 Jun 2024 01:10:48 +0100 Subject: [PATCH 12/14] chore(ci): exclude windows due to broken gha agent --- .github/workflows/build-and-test.yml | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 46a2132c..da97529d 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -29,7 +29,12 @@ jobs: fail-fast: false matrix: node-version: [20] - os: [macos-14,macos-12,ubuntu-latest,windows-latest] + os: [ + macos-14, + macos-12, + ubuntu-latest, + # windows-latest + ] env: NODE_VERSION: ${{ matrix.node-version }} @@ -79,8 +84,12 @@ jobs: fail-fast: false matrix: node-version: [16,18,20] - os: [macos-14, macos-12, ubuntu-latest,windows-latest] - + os: [ + macos-14, + macos-12, + ubuntu-latest, + # windows-latest + ] env: NODE_VERSION: ${{ matrix.node-version }} LOG_LEVEL: debug From 13cf384b1ab7983f6d0996a89f985bf2dda8e1c5 Mon Sep 17 00:00:00 2001 From: Yousaf Nabi Date: Sun, 9 Jun 2024 01:32:24 +0100 Subject: [PATCH 13/14] chore(ci): remove linux arm64 check as shared-mime-info is installed in container --- .github/workflows/build-and-test.yml | 2 +- test/consumer.integration.spec.ts | 2 -- test/message.integration.spec.ts | 4 +--- 3 files changed, 2 insertions(+), 6 deletions(-) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index da97529d..a9dbfef5 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -120,7 +120,7 @@ jobs: uses: docker/setup-buildx-action@v3 - if: runner.os == 'Linux' name: test arm64 - run: docker run -v $PWD:/home --platform linux/arm64 --rm node:20 bin/bash -c 'cd /home && /home/script/ci/unpack-and-test.sh' + run: docker run -v $PWD:/home --platform linux/arm64 --rm node:20 bin/bash -c 'cd /home && npm test' release_dry_run: runs-on: ubuntu-latest diff --git a/test/consumer.integration.spec.ts b/test/consumer.integration.spec.ts index 059d33f0..9f1e3caf 100644 --- a/test/consumer.integration.spec.ts +++ b/test/consumer.integration.spec.ts @@ -24,10 +24,8 @@ const isWin = process.platform === 'win32'; const isLinux = process.platform === 'linux'; const isDarwinArm64 = process.platform === 'darwin' && process.arch === 'arm64'; const isDarwinX64 = process.platform === 'darwin' && process.arch === 'x64'; -const isLinuxArm64 = process.platform === 'linux' && process.arch === 'arm64'; const isCirrusCi = process.env['CIRRUS_CI'] === 'true'; const usesOctetStream = - isLinuxArm64 || isWin || isDarwinArm64 || (isCirrusCi && isLinux) || diff --git a/test/message.integration.spec.ts b/test/message.integration.spec.ts index 484d3607..27c0f2d8 100644 --- a/test/message.integration.spec.ts +++ b/test/message.integration.spec.ts @@ -16,10 +16,8 @@ const { expect } = chai; const isWin = process.platform === 'win32'; const isLinux = process.platform === 'linux'; const isDarwinArm64 = process.platform === 'darwin' && process.arch === 'arm64'; -const isLinuxArm64 = process.platform === 'linux' && process.arch === 'arm64'; const isCirrusCi = process.env['CIRRUS_CI'] === 'true'; -const usesOctetStream = - isLinuxArm64 || isWin || isDarwinArm64 || (isCirrusCi && isLinux); +const usesOctetStream = isWin || isDarwinArm64 || (isCirrusCi && isLinux); const getFeature = async (address: string, protoFile: string) => { const def = await load(protoFile); From c6e93df6e4a27f9a9d9c15c3bb0af35cafe43aa4 Mon Sep 17 00:00:00 2001 From: Yousaf Nabi Date: Sun, 9 Jun 2024 03:41:57 +0100 Subject: [PATCH 14/14] ci(win): workaround for broken curl 8.8.0 --write-out opt in latest win runner update --- .github/workflows/build-and-test.yml | 4 ++-- script/lib/download-file.sh | 14 +++++++++++++- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index a9dbfef5..49d4bb18 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -33,7 +33,7 @@ jobs: macos-14, macos-12, ubuntu-latest, - # windows-latest + windows-latest ] env: @@ -88,7 +88,7 @@ jobs: macos-14, macos-12, ubuntu-latest, - # windows-latest + windows-latest ] env: NODE_VERSION: ${{ matrix.node-version }} diff --git a/script/lib/download-file.sh b/script/lib/download-file.sh index 0640a0ea..87110c34 100644 --- a/script/lib/download-file.sh +++ b/script/lib/download-file.sh @@ -16,7 +16,19 @@ function download_to { OUTPUT_FILE="$2" debug_log "doing curl of: '$URL', saving in $OUTPUT_FILE" - HTTP_CODE="$(curl --silent --output "$OUTPUT_FILE" --write-out "%{http_code}" --location "$URL")" + if [[ "$(uname -m)" == "Darwin" ]] || [[ "$(uname -m)" == "Linux" ]]; then + HTTP_CODE="$(curl --silent --output "$OUTPUT_FILE" --write-out "%{http_code}" --location "$URL")" + else + # temp workaround for curl 8.8.x error on windows gha runners + # https://github.com/curl/curl/issues/13845 + curl --silent --output "$OUTPUT_FILE" --location "$URL" + if [ $? -ne 0 ]; then + error "Unable to download file at url ${URL}" + exit 1 + else + HTTP_CODE=200 + fi + fi debug_log "did curl, http code was '${HTTP_CODE}'" if [[ "${HTTP_CODE}" -lt 200 || "${HTTP_CODE}" -gt 299 ]] ; then error "Unable to download file at url ${URL}"