From a600a4f91f0e7d9b60f694b2ae63036d22ab5ff9 Mon Sep 17 00:00:00 2001 From: Yousaf Nabi Date: Fri, 6 Sep 2024 12:47:05 +0100 Subject: [PATCH] !feat: create os/arch specific npm optional deps for pact-ruby-standalone --- .github/workflows/build-and-test.yml | 1 + .github/workflows/update.yml | 2 +- .gitignore | 2 +- .npmignore | 7 ++ Makefile | 83 +++++++++++++++++++++++ package.json | 8 ++- package.json.tmpl | 18 +++++ script/ci/build-and-test.sh | 5 +- script/ci/download-standalone-and-test.sh | 3 +- script/ci/lib/publish.sh | 8 +++ src/pact-standalone.spec.ts | 18 ++--- src/pact-standalone.ts | 48 +++++++++---- 12 files changed, 169 insertions(+), 34 deletions(-) create mode 100644 Makefile create mode 100644 package.json.tmpl diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 2944ecf..19af64d 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -30,6 +30,7 @@ jobs: with: node-version: ${{ matrix.node-version }} - run: script/ci/download-standalone-and-test.sh + shell: bash if: runner.os != 'Windows' env: NODE_VERSION: ${{ matrix.node-version }} diff --git a/.github/workflows/update.yml b/.github/workflows/update.yml index 7cff578..df3d221 100644 --- a/.github/workflows/update.yml +++ b/.github/workflows/update.yml @@ -9,7 +9,7 @@ jobs: update: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - run: | git config --global user.email "${GITHUB_ACTOR}@users.noreply.github.com" diff --git a/.gitignore b/.gitignore index 902b29c..27ec2ee 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,7 @@ # Logs logs npm-debug.log - +@pact-foundation/* # Runtime data pids *.pid diff --git a/.npmignore b/.npmignore index 8b9d5be..2e92c58 100644 --- a/.npmignore +++ b/.npmignore @@ -1,3 +1,10 @@ +# Standalone Binaries - Published as seperate packages +@pact-foundation/ + +# Cross packaging files +Makefile +package.json.tmpl + # Logs logs npm-debug.log diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..404fa62 --- /dev/null +++ b/Makefile @@ -0,0 +1,83 @@ +SHELL:=/bin/bash +export bin=@pact-foundation/pact-cli +export pkg_version=$(shell cat package.json | jq -r .version) +supported_platforms = "linux-x64" "linux-arm64" "darwin-x64" "darwin-arm64" "windows-x64" +export STANDALONE_VERSION=$(shell grep "PACT_STANDALONE_VERSION = '" standalone/install.ts | grep -E -o "'(.*)'" | cut -d"'" -f2) + +# https://github.com/npm/npm/issues/17722 +# https://github.com/npm/cli/issues/4828 +# https://github.com/orhun/packaging-rust-for-npm +# https://blog.orhun.dev/packaging-rust-for-npm/ + +clean: + rm -rf @pact-foundation + +libs: clean + bash script/download-libs.sh + +all: libs + for supported_platform in $(supported_platforms); do \ + IFS='-' read -r node_os node_arch <<< "$$supported_platform"; \ + export node_os=$$node_os; \ + export node_arch=$$node_arch; \ + export node_pkg=$(bin)-$$node_os-$$node_arch; \ + export standalone_package=standalone/$$node_os-$$node_arch-$(STANDALONE_VERSION); \ + if [ "$$node_os" = "windows" ]; then \ + export node_os="win32"; \ + fi; \ + echo "Building for $$node_os-$$node_arch"; \ + echo "Building $$node_pkg"; \ + mkdir -p "$$node_pkg/standalone"; \ + mv "$$standalone_package" "$$node_pkg/standalone"; \ + envsubst < package.json.tmpl > "$$node_pkg/package.json"; \ + (cd $$node_pkg && npm publish --access public --dry-run;)\ + done + +update_opt_deps: + @for supported_platform in $(supported_platforms); do \ + IFS='-' read -r node_os node_arch <<< "$$supported_platform"; \ + export node_pkg=$(bin)-$$node_os-$$node_arch; \ + jq '.optionalDependencies."'$$node_pkg'" = "$(pkg_version)"' package.json > package-new.json; \ + mv package-new.json package.json; \ + done + +dry_run: all + set -eu; for supported_platform in $(supported_platforms); do \ + IFS='-' read -r node_os node_arch <<< "$$supported_platform"; \ + export node_os=$$node_os; \ + export node_pkg=$(bin)-$$node_os-$$node_arch; \ + export node_arch=$$node_arch; \ + export standalone_package=standalone/$$node_os-$$node_arch-$(STANDALONE_VERSION); \ + if [ "$$node_os" = "windows" ]; then \ + export node_os="win32"; \ + fi; \ + echo "Building $$node_pkg for $$node_os-$$node_arch (dry-run)"; \ + (cd $$node_pkg && npm publish --access public --dry-run;)\ + done +publish: all + set -eu; for supported_platform in $(supported_platforms); do \ + IFS='-' read -r node_os node_arch <<< "$$supported_platform"; \ + export node_os=$$node_os; \ + export node_arch=$$node_arch; \ + export node_pkg=$(bin)-$$node_os-$$node_arch; \ + export standalone_package=standalone/$$node_os-$$node_arch-$(STANDALONE_VERSION); \ + if [ "$$node_os" = "windows" ]; then \ + export node_os="win32"; \ + fi; \ + echo "Building for $$node_os-$$node_arch"; \ + echo "Building $$node_pkg for $$node_os-$$node_arch"; \ + (cd $$node_pkg && npm publish --access public;)\ + done +link: + set -eu; for supported_platform in $(supported_platforms); do \ + IFS='-' read -r node_os node_arch <<< "$$supported_platform"; \ + export node_os=$$node_os; \ + export node_arch=$$node_arch; \ + export node_pkg=$(bin)-$$node_os-$$node_arch; \ + (cd $$node_pkg && npm link || echo "cannot link for platform";);\ + npm link $$node_pkg || echo "cannot link for platform";\ + done + + +vers: + @echo $(STANDALONE_VERSION) \ No newline at end of file diff --git a/package.json b/package.json index d775d43..84ccf21 100644 --- a/package.json +++ b/package.json @@ -21,7 +21,6 @@ ], "cpu": [ "x64", - "ia32", "arm64" ], "engines": { @@ -52,6 +51,13 @@ "publishConfig": { "access": "public" }, + "optionalDependencies": { + "@pact-foundation/pact-cli-darwin-arm64": "15.0.3", + "@pact-foundation/pact-cli-darwin-x64": "15.0.3", + "@pact-foundation/pact-cli-windows-x64": "15.0.3", + "@pact-foundation/pact-cli-linux-x64": "15.0.3", + "@pact-foundation/pact-cli-linux-arm64": "15.0.3" + }, "dependencies": { "chalk": "4.1.2", "check-types": "7.4.0", diff --git a/package.json.tmpl b/package.json.tmpl new file mode 100644 index 0000000..0481842 --- /dev/null +++ b/package.json.tmpl @@ -0,0 +1,18 @@ +{ + "name": "${node_pkg}", + "version": "${pkg_version}", + "description": "TEST - Platform Specific Broker CLI for @pact-foundation/pact ${node_os}-${node_arch}", + "repository": { + "type": "git", + "url": "git://github.com/pact-foundation/pact-js-cli.git" + }, + "scripts": {}, + "author": "Yousaf Nabi ", + "homepage": "https://github.com/pact-foundation/pact-js-cli#readme", + "os": [ + "${node_os}" + ], + "cpu": [ + "${node_arch}" + ] +} diff --git a/script/ci/build-and-test.sh b/script/ci/build-and-test.sh index ce49fdf..9e866e6 100755 --- a/script/ci/build-and-test.sh +++ b/script/ci/build-and-test.sh @@ -21,7 +21,10 @@ node --version npm --version npm ci - +# Link os/arch specific npm package, for running os/arch system +make link +# Update main package.json optional dependencies versions, with those created earlier +make update_opt_deps npm run format:check npm run lint npm run build diff --git a/script/ci/download-standalone-and-test.sh b/script/ci/download-standalone-and-test.sh index 65639d4..6db0d73 100755 --- a/script/ci/download-standalone-and-test.sh +++ b/script/ci/download-standalone-and-test.sh @@ -5,5 +5,6 @@ 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 +# Make os/arch specific npm packages, with newly created prebuilds +make all ./script/ci/build-and-test.sh \ No newline at end of file diff --git a/script/ci/lib/publish.sh b/script/ci/lib/publish.sh index dbe86ce..a1819ba 100755 --- a/script/ci/lib/publish.sh +++ b/script/ci/lib/publish.sh @@ -14,10 +14,18 @@ echo "--> Releasing artifacts" echo " Publishing pact-cli@${VERSION}..." if [[ ${DRY_RUN:-} == 'true' ]]; then echo "publishing in dry run mode" + # Dry-run Publish os/arch specific npm packages + make dry_run + # Update main package.json optional dependencies versions, with those created earlier + make update_opt_deps npm publish --access-public --dry-run else echo "--> Preparing npmrc file" "$SCRIPT_DIR"/create_npmrc_file.sh + # Publish os/arch specific npm packages + make publish + # Update main package.json optional dependencies versions, with those created earlier + make update_opt_deps npm publish --access public --tag latest fi echo " done!" diff --git a/src/pact-standalone.spec.ts b/src/pact-standalone.spec.ts index 9cee72e..4eed364 100644 --- a/src/pact-standalone.spec.ts +++ b/src/pact-standalone.spec.ts @@ -1,11 +1,11 @@ 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'; +import os from 'os'; +import { getExePath, PactStandalone, standalone } from './pact-standalone'; const { expect } = chai; -const basePath = pactEnvironment.cwd; +const basePath = getExePath(); // Needs to stay a function and not an arrow function to access mocha 'this' context describe('Pact Standalone', function forMocha() { @@ -37,17 +37,7 @@ describe('Pact Standalone', function forMocha() { }); describe('Check if OS specific files are there', () => { - const tests = [ - ['darwin', 'arm64'], - ['darwin', 'x64'], - ['linux', 'arm64'], - ['linux', 'x64'], - ['win32', 'x64'], - ].filter(([platform]) => - process.env['ONLY_DOWNLOAD_PACT_FOR_WINDOWS'] - ? platform === 'win32' - : true - ); + const tests = [[os.platform(), os.arch()]]; tests.forEach(([platform, arch]) => { describe(`${platform} ${arch}`, () => { diff --git a/src/pact-standalone.ts b/src/pact-standalone.ts index 3dc1163..53838ff 100644 --- a/src/pact-standalone.ts +++ b/src/pact-standalone.ts @@ -2,6 +2,32 @@ import * as path from 'path'; import { getBinaryEntry } from '../standalone/install'; import pactEnvironment from './pact-environment'; +/** + * Returns the executable path which is located inside `node_modules` + * The naming convention is app-${os}-${arch} + * @see https://nodejs.org/api/os.html#osarch + * @see https://nodejs.org/api/os.html#osplatform + * @example "x/xx/node_modules/app-darwin-arm64" + */ +export function getExePath(): string { + const { arch } = process; + let os = process.platform as string; + if (['win32', 'cygwin'].includes(process.platform)) { + os = 'windows'; + } + const packageName = `@pact-foundation/pact-cli`; + + const platformArchSpecificPackage = `${packageName}-${os}-${arch}`; + try { + const lib = require.resolve(`${platformArchSpecificPackage}/package.json`); + return lib.replace('package.json', ''); + } catch (e) { + throw new Error( + `Couldn't find application binary for ${os}-${arch}:\n 💡 check if ${platformArchSpecificPackage} has been downloaded in your node_modules` + ); + } +} + export interface PactStandalone { cwd: string; brokerPath: string; @@ -43,27 +69,19 @@ export const standalone = ( return { cwd: pactEnvironment.cwd, brokerPath: path.join(basePath, broker), - brokerFullPath: path.resolve(pactEnvironment.cwd, basePath, broker).trim(), + brokerFullPath: path.resolve(getExePath(), basePath, broker).trim(), messagePath: path.join(basePath, message), - messageFullPath: path - .resolve(pactEnvironment.cwd, basePath, message) - .trim(), + messageFullPath: path.resolve(getExePath(), basePath, message).trim(), mockServicePath: path.join(basePath, mock), - mockServiceFullPath: path - .resolve(pactEnvironment.cwd, basePath, mock) - .trim(), + mockServiceFullPath: path.resolve(getExePath(), basePath, mock).trim(), stubPath: path.join(basePath, stub), - stubFullPath: path.resolve(pactEnvironment.cwd, basePath, stub).trim(), + stubFullPath: path.resolve(getExePath(), basePath, stub).trim(), pactPath: path.join(basePath, pact), - pactFullPath: path.resolve(pactEnvironment.cwd, basePath, pact).trim(), + pactFullPath: path.resolve(getExePath(), basePath, pact).trim(), pactflowPath: path.join(basePath, pactflow), - pactflowFullPath: path - .resolve(pactEnvironment.cwd, basePath, pactflow) - .trim(), + pactflowFullPath: path.resolve(getExePath(), basePath, pactflow).trim(), verifierPath: path.join(basePath, verify), - verifierFullPath: path - .resolve(pactEnvironment.cwd, basePath, verify) - .trim(), + verifierFullPath: path.resolve(getExePath(), basePath, verify).trim(), }; };