Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat: Prebuildify pact.node for all FFI supported platform/architectures #446

Merged
merged 20 commits into from
Jul 6, 2023

Conversation

YOU54F
Copy link
Member

@YOU54F YOU54F commented May 12, 2023

🗣 Context

Would like Pact to run batteries included for all major platforms and architectures

💬 Narrative

When run npm install @pact-foundation/pact --ignore-scripts on any major platform/architecture, and I am on a supported version of node, I should be able to install Pact

🏗 Design

✅ Acceptance Criteria

GIVEN I have node version 16, 18 or 20 installed

AND I am on one of the following platforms

OS Amd64 Arm64
Linux (glibc)
Mac
Windows
Linux (alpine)

WHEN I run npm install @pact-foundation/pact --ignore-scripts

THEN I should be able to use pact

✅ = installs without build hooks, pre-built native library
❌ = not supported

🚫 Out of Scope

  • Alpine Linux
    • Requires .so file building - will come later
  • Arm64 Windows
    • Requires .dll file building - will come later

📝 Summary of Changes

Changes proposed in this pull request:

  1. use prebuilidfy npx prebuildify --napi to generate bindings for each targeted platform/arch combination
❯tree prebuilds 
prebuilds
└── darwin-arm64
   ├── libpact_ffi.dylib
   └── node.napi.node
  1. Use combination of cirrus-ci / github-actions to test generated napi build against supported LTS versions of node
Release Released Active Support Security Support Latest
20 (Upcoming LTS) 3 weeks and 3 days ago(18 Apr 2023) Ends in 1 year and 5 months(22 Oct 2024) Ends in 2 years and 11 months(30 Apr 2026) 20.1.0(03 May 2023)
19 6 months and 3 weeks ago(18 Oct 2022) Ended 1 month and 1 week ago(01 Apr 2023) Ends in 2 weeks and 6 days(01 Jun 2023) 19.9.0(10 Apr 2023)
18 (LTS) 1 year ago(19 Apr 2022) Ends in 5 months(18 Oct 2023) Ends in 1 year and 11 months(30 Apr 2025) 18.16.0(12 Apr 2023)
17 1 year and 6 months ago(19 Oct 2021) Ended 1 year and 1 month ago(01 Apr 2022) Ended 11 months ago(01 Jun 2022) 17.9.1
16 (LTS) 2 years ago(20 Apr 2021) Ended 6 months and 3 weeks ago(18 Oct 2022) Ends in 4 months(11 Sep 2023) 16.20.0(29 Mar 202

⚠️ Items of Note

Ruby arm64 runtimes

node-addon-api compatability

ABI Matrix

Screenshot 2023-04-21 at 12 43 10

Screenshot 2023-04-21 at 12 42 50

We can see version in NAPI_VERSION=3 here

https://github.com/YOU54F/pact-js-core/blob/master/native/ffi.cc#L1

anything lower and it fails to build.

Looking at the ABI compat matrix, version 8 supports v12 which is EOL, v14 which is going EOL end of the month, but raises minimum compat up to v15.12.0 (for v15 users)

I'm not sure what the implications are of leaving it at the lowest version it will compile with (which is NAPI_VERSION=3).

I also don't understand why that chart isn't updated, to include v17->v20, especially as that matrix for the node-api version matrix is on the node v20 ref docs

This PR seeks to address those concerns, by allowing maintainers to easily add or remove different versions of node for testing, and ensuring the latest LTS versions are tested and covered.

A combination of nvm and nvs is used to manage node versions in .cirrus.yml, as nvs offers a nicer interface for getting x64 builds which you are on arm hardware (testing rosetta on MacOS)

🔨 How To Test

💻 Local Machine

  1. Checkout the branch prebuildify.
  2. Run bash script/download-libs.sh
  • This downloads the FFI libraries for building, end users wont do this
  1. Run npm ci --ignore-scripts
  • This installs our node_modules we only need node-addon-api for now
  1. Run npx prebuildify --napi
  • This run node-gyp-build and outputs a platform specific pact.node in the prebuilds directory
  • This step used to be performed by end users, and required a full python build chain amongst other things with node-gyp
  1. Run rm -rf build ffi
  • This deletes folders we wont distribute in the end binary, and makes sure you are using the prebuilds
  • It would read the prebuild anyway, but I just like to be sure
  1. Run npm run build
  • This transpiles the typescript into javascript
  1. Run npm run test
  • Hopefully all green!

🐱‍💻 Local Machine - GitHub Actions

  1. Download Act
  2. Download Docker (or Podman)

Linux workflows

act --container-architecture linux/amd64 -W .github/workflows/build-and-test.yml --artifact-server-path pkgs

🐱‍💻 Local Machine - Cirrus CLI

  1. Download Cirrus CLI
  2. Download Docker (or Podman)
  3. If on an arm64 mac, download tart.run

Linux workflows

cirrus run --output github-actions "linux_amd64" --artifacts-dir pkgs

MacOS workflows

cirrus run --output github-actions "macos_arm_prebuilder" --artifacts-dir pkgs
cirrus run --output github-actions "macos_x64_prebuilder" --artifacts-dir pkg

Copy link
Contributor

@TimothyJones TimothyJones left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice work! I didn't read the gyp config changes because I don't actually know gyp. A few other comments left inline.

.cirrus.yml Outdated Show resolved Hide resolved
.gitignore Outdated
@@ -58,7 +58,9 @@ standalone/*
!standalone/*.ts
standalone/*.d.ts
ffi/*
!src/ffi
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This doesn't seem right. If the intention is to stop the line above matching in /src/ think it's better to change the line above it to:

/ffi/*

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this actually works as intended, however cirrus cli wasn’t honouring the git ignore excludes so when it mounted my workspace it was sans src/ffi

will remove

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Either way, I think the ffi/* was definitely meant to be /ffi/*

.npmignore Outdated Show resolved Hide resolved
package.json Outdated Show resolved Hide resolved
script/lib/download-standalone.sh Outdated Show resolved Hide resolved
src/ffi/index.ts Outdated Show resolved Hide resolved
src/ffi/index.ts Outdated Show resolved Hide resolved
standalone/install.ts Outdated Show resolved Hide resolved
@YOU54F
Copy link
Member Author

YOU54F commented May 13, 2023

just a note to the reader

i still need to get the generated prebuilds from each of the os arch runs and consolidate them so they can be packaged up for a release.

the github action run will generate the x64 bindings for macos windows and linux. ( via seperate runs ), these are then uploaded as artefacts and downloaded in another job to show the prebuilds working

cirrrus is used to generate the bindings for arm macos and linux.

we can download workflow artefacts from either runs as they upload the packages on each ci run. just needs a bit of thought as to how we pull them together for packaging time.

@YOU54F
Copy link
Member Author

YOU54F commented May 13, 2023

Nice work! I didn't read the gyp config changes because I don't actually know gyp. A few other comments left inline.

main gist of the node gyp changes

  • conditionally copy platform-arch specific binaries ( dll so or dylib ) and with generated node file to prebuilds/platform-arch
  • our code will look here first ( and always find one for our supported platforms )
  • then fall back looking in the usual place as it does today, but this is unnecessary as there are no arch/plats specific in the node gyp file that we won’t have generated pre builds for
  • it also ensures all the node binaries when copied are appropriately linked to the relevant shared lib.

i’m actually wondering if we need node-gyp or node-addon-api in our dependencies, i think the only reason we would use node gyp is to do a platform look up to pick the right binary ( which we could do easily )

node-addon-api appears to be needed when building the pact bindings, but again not sure if it’s a run time dep. will do some investigation :) ( read that as remove things till it breaks 😂 )

@mefellows
Copy link
Member

i’m actually wondering if we need node-gyp or node-addon-api in our dependencies, i think the only reason we would use node gyp is to do a platform look up to pick the right binary ( which we could do easily )

Node Gyp is an install time dependency. It only gets used in the postinstall stage of an npm install, and of course it wouldn't get used if you use the --ignore-scripts option. I don't think it is needed for most users, but in the case a pre-built pact.node isn't available, it could be used as a fallback option to attempt to build against it. This assumes the requisite shared library is in place, but the prebuilt pact.node is not available - which I think is not the case now.

So we could try removing it for the general users (obviously it is needed for other steps in the build process0.

node-addon-api appears to be needed when building the pact bindings, but again not sure if it’s a run time dep. will do some investigation :) ( read that as remove things till it breaks 😂 )

💯

@YOU54F YOU54F marked this pull request as draft May 18, 2023 22:51
@YOU54F
Copy link
Member Author

YOU54F commented May 29, 2023

Hey hey

So just an update on this

I've got a decent workflow worked out for packaging and releasing,

The diff is here master...YOU54F:pact-js-core:master

Published to npm on my fork, you can see the prebuilds and pact.node here in the code tab

https://www.npmjs.com/package/@you54f/pact-core?activeTab=code

One irksome thing I found, is that release versions take that on the commit message only, so if you have a fix, after a feat, you lose the feat version bump. You don't get warned on it, just warned to ensure you have a fix/feat.

That seems odd, it's bitten me in the past.

I would expect to see it computed based on the last release and the delta of commit conventions that go into a changelog.

I added some additional path looks and ways for users to help themselves if they get stuck. I'll write more detail up this week but just thought I'd drop in where I was up to

Build and test workflow

https://github.com/YOU54F/pact-js-core/actions/runs/5099788056

publish workflow

https://github.com/YOU54F/pact-js-core/actions/runs/5099802203

Releases published to GH

https://github.com/YOU54F/pact-js-core/releases/tag/v13.19.0

@TimothyJones
Copy link
Contributor

One irksome thing I found, is that release versions take that on the commit message only, so if you have a fix, after a feat, you lose the feat version bump

This shouldn’t happen. How are you generating releases? They should include all commits (fix, feat, fix!, feat!) since the last tag

@YOU54F
Copy link
Member Author

YOU54F commented May 30, 2023

Ahh its because I was testing the flow out with dry run, so you dont have committed tags.

so

  • 13.13.8
  • feat = 13.14.0
  • feat + fix = 13.14.0

I assume if after + feat, a commit and tag took place, I would get a bump from 13.14.0 -> 13.14.1

It's actually a random by product of the fact I have duplicate version numbers on npm, of the version I was bumping too with a feat was taken, because of previous changes that I had self released.

I wanted to get to something that was 13.14.x but not 13.14.0 because I also have a 13.15.x and other versions released when changes out in the past

@TimothyJones
Copy link
Contributor

The version numbers bump to the highest of all the things: so:

13.13.8 with 3 commits of fix,fix,fix would release 13.13.9

Any combination that includes at least one feat commit would be 13.14.0

Any breaking changes (feat!, fix!, refactor!, etc) would release 14.0.0.

@YOU54F
Copy link
Member Author

YOU54F commented May 30, 2023

Just about to force push some new changes, documented below

📝 Summary of Changes

Changes Implemented in this pull request:

  1. use prebuilidfy to generate bindings for each targeted platform/arch combination
  • Script ./script/ci/prebuild.sh

  • Conditions - github.ref == 'refs/heads/master' then upload binaries to GitHub pre-release

    tree prebuilds
    prebuilds
    ├── darwin-arm64
    │   ├── libpact_ffi.dylib
    │   └── node.napi.node
    ├── darwin-x64
    │   ├── libpact_ffi.dylib
    │   └── node.napi.node
    ├── linux-arm64
    │   ├── libpact_ffi.so
    │   └── node.napi.node
    ├── linux-x64
    │   ├── libpact_ffi.so
    │   └── node.napi.node
    └── win32-x64
        ├── node.napi.node
        └── pact_ffi.dll
    
    6 directories, 10 files
    
  • This removes our dependency on node-addon-api and moves it to a dev-dependency

  1. Use pre-built bindings and run test suite
  • Pre built packages are uploaded on each test run, as build job artefacts
    • Pre built packages are downloaded from the previous build step, this could utilise the latest release bindings to speed up test runs
      • If the ffi version hasn't changed
      • If no changes to the native .c files for our node addon api
  • Script ./script/ci/unpack-and-test.sh
  1. Create a GitHub Pre-release
  • On master, a pre-release draft is created,
    • which allows the node-bindings to be published by each individual runner
  • script GH_CREATE_PRE_RELEASE=true ./script/ci/release.sh
  1. Dry run the release process
  • On master, a dry run of the release process is performed,
    • which checks the node-bindings have been published by each individual runner
    • smoke tests the bindings for linux
    • Informs the user of the next version number
    • runs an npm publish dry run to inform user of published package files
    • Updates the release notes for the pre-release
  • script DRY_RUN=true ./script/ci/release.sh
  1. Run the release process
  • On a release, a run of the release process is performed,
    • which checks the node-bindings have been published by each individual runner
    • smoke tests the bindings for linux
    • Releases to npm
    • Converts pre-release to a release
    • Commits changelog back to repo
  • script ./script/ci/release.sh

⚠️ Items of Note

  • Used node-gyp-build for bindings lookup in prebuilds folder, the import could be async or sync, the package considers this. If we can sort that, we could drop the dependency completely.
  • Additional error messaging is provided when the pact node binding are not found, and inform user how they can proceed
    • provide own path to bindings
    • tell us about path so we can add it to a path resolver
    • tell them how they can build their own pact node
    • should we just exit the process early if this case?
    • allow users to run UNSUPPORTED_PLATFORMS
  • Users can install with --ignore-scripts. If a user does a plain npm install , then node-gyp will automatically pick up the fact there is a binding.gyp and attempt to build the bindings which isn't needed. There is an echo script to prevent this, but is now solved by not publishing the binding.gyp in the npm package.
  • We could move our prebuilds, or just prebuild with the exiting node-gyp rebuild process which means there output would be in the exact place node-gyp expects, and therefore publishing the binding.gyp wouldn't matter, and for other users where the built bindings don't work, they could build it themselves. (I don't forsee this being a case, but computers often predict otherwise)

This change pre-builds the pact node bindings with prebuildify

Supported node versions are node LTS versions 16, 18, 20.

Supported Platforms + Arches are now

* Linux ARM64/X64
* MacOS ARM64/X64
* Windows X64

For the Pact FFI.

This change additional includes the Pact-Ruby-Standalone updated to v2.x

This brings is support for

* Linux/MacOS ARM64

for the pact cli and api

## Requirements

Users are no longer required to

* Install a node-gyp build chain
  - Not limited to
   - Python
   - MSVS for Windows

* Ensure `--ignore-scripts` is not set to true
  - This is because pact-js-core and the npm package pact-core will now come
    batteries included, which means the ffi and standalone come packaged in the
    npm package. This increases size, however all files have to be downloaded currently
    even if all are not used, so we might as well do this once for the user, rather than
    every user needing to, and possibly struggling due to various build system reasons related
    to node-gyp.
.cirrus.yml Outdated
install_script:
- apt update --yes && apt install --yes curl python3 make build-essential g++ unzip zip
<< : *BUILD_TEST_TASK_TEMPLATE
GITHUB_TOKEN: ENCRYPTED[636f316600928de28b5c36027cc39d9796bc0d0eca2a181368f255ad61540f13bb38cdce09b6428774f315bbf45e0ada]
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note - Pact-Foundation Cirrus CI account will need a scoped GITHUB_TOKEN

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is needed here sorry Saf - do we need to bake a new one with scoped permissions instead of (presumably) wider perms here?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hiya,

so currently this is using a PAT under my own user scope, which has been attached to my pact js core fork in cirrus ci.

it creates an encrypted secret

https://cirrus-ci.org/guide/writing-tasks/#encrypted-variables

which is usable at the repo level.

the token can only be encrypted by the associated repo and if the user triggering has suitable perms.

this will mean for merging

  1. will need a scoped PAT creating in pact foundation org, and added to our vault that Beth setup.
  2. will need the scoped PAT linked in pact-js-core cirrus config ( under pact foundation org not my fork )

token is required perms to

  • list releases
  • upload assets to releases

CHANGELOG.md Outdated Show resolved Hide resolved
download-checksums.js Outdated Show resolved Hide resolved
@YOU54F YOU54F marked this pull request as ready for review May 30, 2023 13:08
DEVELOPER.md Outdated Show resolved Hide resolved
@mefellows
Copy link
Member

I tried taking your published package from npm for a spin:

npm init -f
npm i @you54f/pact-core
node -e 'require("@you54f/pact-core")'
[16:42:39.452] INFO (83549): [email protected]: We detected your platform as:

 - darwin-x64

[16:42:39.466] WARN (83549): [email protected]: You have set the environment variable UNSUPPORTED_PLATFORM to undefined, this will override the detected platform of darwin-x64
[16:42:39.470] INFO (83549): [email protected]: Attempting to find pact native module : loading native module from:

 - /private/tmp/js-core-test/node_modules/@you54f/pact-core/prebuilds/darwin-x64
   source: /private/tmp/js-core-test/node_modules/@you54f/pact-core/prebuilds/darwin-x64

 - You can override via PACT_NAPI_NODE_LOCATION

[16:42:41.275] WARN (83549): [email protected]: Failed to load native module from /private/tmp/js-core-test/node_modules/@you54f/pact-core: Error: Native module not found
➜  js-core-test uname -a                                                                                                                                                                                                                     
Darwin SB-AS-G7GM9F7 22.5.0 Darwin Kernel Version 22.5.0: Mon Apr 24 20:52:24 PDT 2023; root:xnu-
➜  js-core-test ll node_modules/@you54f/pact-core/prebuilds/darwin-x64/node.napi.node ll                                                                                                                                                     
➜  js-core-test file /private/tmp/js-core-test/node_modules/@you54f/pact-core/prebuilds/darwin-x64/libpact_ffi.dylib                                                                                                                         
/private/tmp/js-core-test/node_modules/@you54f/pact-core/prebuilds/darwin-x64/libpact_ffi.dylib: Mach-O 64-bit dynamically linked shared library x86_64
➜  js-core-test file /private/tmp/js-core-test/node_modules/@you54f/pact-core/prebuilds/darwin-x64/node.napi.node                                                                                                                            <aws:pactflow-prod-admin>
/private/tmp/js-core-test/node_modules/@you54f/pact-core/prebuilds/darwin-x64/node.napi.node: Mach-O 64-bit bundle x86_64

A few things:

  1. I think we ought to adjust the log levels:
  2. For some reason it couldn't run on my mac, despite the library being in the right place (I think) and linked to the correct runtime

Log Levels

[16:42:39.466] WARN (83549): [email protected]: You have set the environment variable UNSUPPORTED_PLATFORM to undefined, this will override the detected platform of darwin-x64

Is it expected for users to set that? Also the naming is a little confusing relative to the message ("unsupported platform" is the variable which would appear to override the current detected os?). I imagine this should be a DEBUG or something hidden from the user normally.

[16:42:39.470] INFO (83549): [email protected]: Attempting to find pact native module : loading native module from:

  • /private/tmp/js-core-test/node_modules/@you54f/pact-core/prebuilds/darwin-x64
    source: /private/tmp/js-core-test/node_modules/@you54f/pact-core/prebuilds/darwin-x64

  • You can override via PACT_NAPI_NODE_LOCATION

This should be DEBUG.

[16:42:41.275] WARN (83549): [email protected]: Failed to load native module from /private/tmp/js-core-test/node_modules/@you54f/pact-core: Error: Native module not found

This should be ERROR and cause a non-zero exit.

I'll keep digging to see if I can work out why it's failing...

@mefellows
Copy link
Member

So far as I can tell from the PR UNSUPPORTED_PLATFORM is not used outside of logs/warnings. Perhaps it's used in prebuildify or elsewhere? (a grep through the code base/node_modules turns up nothing)

src/ffi/index.ts Outdated
`Attempting to find pact native module ${loadPathMessage(bindingPath)}`
);
ffiLib = bindingsResolver(bindingPath);
if (ffiLib) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah! I think this is why it's failing - should this be:

Suggested change
if (ffiLib) {
if (!ffiLib) {

At the moment, it seems to be finding the package and then throwing an error!

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

whooops 🤦🏾

src/ffi/index.ts Outdated
logger.warn(`Failed to load native module from ${bindingPath}: ${error}`);
}
});
} catch (error) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This section isn't currently being caught, at least in the case that the bindings library can't find the node lib. The reason is that on line 90, the error is caught there and thus is swallowed, both preventing the subsequent log from logging, and a non-zero exit status.

src/ffi/index.ts Outdated
logger.info(detectedMessage);
if (
!supportedPlatforms.includes(platform) &&
process.env['UNSUPPORTED_PLATFORM'] !== platform
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can't see where UNSUPPORTED_PLATFORM is actually used, outside of notices?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It was, but removed, I tried switching to natively looking up the bindings rather than using another package, which would give us finer grained control over the platform/arch combos, but you have to deal with modules with being loaded sync or async and it was a mission, sooo, they can just raise an issue and we can build ffi bindings in pact-reference if possible :)

@@ -39,7 +44,7 @@ describe('FFI integration test for the HTTP Consumer API', () => {
value,
});

describe('with JSON data', () => {
describe.skip('with JSON data', () => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Accident? I'd hope the JSON one works 😬

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes I think so!

@mefellows
Copy link
Member

OK! I got a bit further now and I think it's really close - looks like just a single line was responsible for the package not installing on my machine. Had a few additional minor comments also for looking at after you return from your well-deserved break!

@YOU54F
Copy link
Member Author

YOU54F commented Jul 5, 2023

So far as I can tell from the PR UNSUPPORTED_PLATFORM is not used outside of logs/warnings. Perhaps it's used in prebuildify or elsewhere? (a grep through the code base/node_modules turns up nothing)

yep will remove, I wanted to be able to allow users to set their own platform and arch but can't whilst using node-gyp-build to load the bindings, as it will detect the platform/arch from the users machine, rather than anything we can set I believe

@YOU54F
Copy link
Member Author

YOU54F commented Jul 5, 2023

OK! I got a bit further now and I think it's really close - looks like just a single line was responsible for the package not installing on my machine. Had a few additional minor comments also for looking at after you return from your well-deserved break!

Appreciate the eyes dude!

@YOU54F
Copy link
Member Author

YOU54F commented Jul 5, 2023

  • I think we ought to adjust the log levels:

Yep 110% have removed INFO's and updated that one mentioned to ERROR

@YOU54F
Copy link
Member Author

YOU54F commented Jul 5, 2023

Right this should with any luck be good to go, I've simplified the logic a bit and allowed for

  • LOG_LEVEL env var to be honoured, if set
  • PACT_PREBUILD_LOCATION env var can be set, if the user has the node bindings other than the shipped location of the npm package. This should allow users to set their own path if there are issues (sometimes monorepos etc) and we can add the load lookup path, if they raise an issue.
    • I don't see end users being required to set this, but it might be useful for some in a jam. It's not documented other than in the debug logs.
    • If the user does set their own location, they will be informed
    • If the native binding lookup fails, the user will be informed they can set the env var, to the path if it exists

I've also now added a scoped pat token, against pact-foundation org, scoped to pact-js-core, into cirrus-ci :) it's valid for a year, and I will add it to our vault

@YOU54F YOU54F requested a review from mefellows July 5, 2023 20:45
@mefellows
Copy link
Member

So I'm going to merge this, but I'm not going to squash the commits. There are 3 feat in there that we want to preserve, and the others won't appear in the changelog. They may be helpful to have about if there are issues though).

@mefellows mefellows merged commit 4bbfc28 into pact-foundation:master Jul 6, 2023
@mefellows
Copy link
Member

mefellows commented Jul 6, 2023

The release is failing because it thinks the release notes are empty. I've put some debugging in a branch, and can see a discrepancy between CI and local (which looks correct):

CI

🔵  npx commit-and-tag-version --dry-run:
✔ bumping version in package.json from 13.13.9 to 13.13.[10](https://github.com/pact-foundation/pact-js-core/actions/runs/5472016151/jobs/9963725008#step:4:11)
✔ bumping version in package-lock.json from 13.13.9 to 13.13.10
✔ outputting changes to CHANGELOG.md

---
## 13.13.10 (2023-07-06)
---

✔ committing package-lock.json and package.json and CHANGELOG.md
✔ tagging release v13.13.10
ℹ Run `git push --follow-tags origin chore/release-debug && npm publish` to publish
🔵  RELEASE_NOTES:
🔵  ## 13.13.10 (2023-07-06)
🔵  NEXT_VERSION:
🔵  13.13.10
🔵  NEXT_TAG:
🔵  v13.13.10

Local

✗ npx -y commit-and-tag-version --dry-run
✔ bumping version in package.json from 13.13.9 to 13.14.0
✔ bumping version in package-lock.json from 13.13.9 to 13.14.0
✔ outputting changes to CHANGELOG.md

---
## [13.14.0](https://github.com/pact-foundation/pact-js-core/compare/v13.13.9...v13.14.0) (2023-07-06)


### Features

* allow setting of LOG_LEVEL env var ([7224770](https://github.com/pact-foundation/pact-js-core/commit/72247702e1868286c09988764f93ac4aad68dfdb))
* ARM64 Linux/MacOS Pact Ruby Standalone ([ea9f86f](https://github.com/pact-foundation/pact-js-core/commit/ea9f86f75a287425dfc1aa9b2124b9c892ec7672))
* Prebuild pact_ffi pact.node - ([6a38cf7](https://github.com/pact-foundation/pact-js-core/commit/6a38cf7cf2738e43e84586446fcaa8022d9e2431))
---

✔ committing package-lock.json and package.json and CHANGELOG.md
✔ tagging release v13.14.0
ℹ Run `git push --follow-tags origin chore/release-debug && npm publish` to publish

Continuing to investigate.

@mefellows
Copy link
Member

Thanks to @TimothyJones, spotting the need for fetch-depth: 0: 6a38cf7#diff-551d1fcf87f78cc3bc18a7b332a4dc5d8773a512062df881c5aba28a6f5c48d7L15

From https://github.com/actions/checkout

Only a single commit is fetched by default, for the ref/SHA that triggered the workflow. Set fetch-depth: 0 to fetch all history for all branches and tags. Refer here to learn which commit $GITHUB_SHA points to for different events.

@mefellows
Copy link
Member

There seems to be an issue with the release (tested with Pact JS) so I have deprecated the package (this should mean it won't be pulled in as a transitive dependency). I'll do some more testing locally, hopefully it's something simple (the prebuilds are definitely in the released package)

@YOU54F
Copy link
Member Author

YOU54F commented Jul 6, 2023

Woohoo,

Right two issues

  1. The path lookup is looking at the root of the project folder, and not in the node_modules directory

  2. env var LOG_LEVEL doesn't affect logging of the FFI native module, as that uses DEFAULT_LOG_LEVEL or the user provided instead ofcurrentLogLevel which was modified to take account of the env var LOG_LEVEL

simple test of the standalone and ffi

const pact = require('@pact-foundation/pact-core')
pact.createServer()
 .delete()
 .then(function() {
  console.log('pact ruby standalone server created and deleted')
 });

const consumerPact = pact.makeConsumerPact(
    'foo-consumer',
    'bar-provider',
    4 ,// v3 spec,
    'TRACE'
  );
const interaction = consumerPact.newInteraction('some description');

interaction.uponReceiving('a request to get a dog');
interaction.given('fido exists');
interaction.withRequest('GET', '/dogs/1234');
interaction.withResponseBody(
JSON.stringify({
    name: 'fido',
    age: 23,
    alive: true,
}),
'application/json'
);
interaction.withStatus(200);

port = consumerPact.createMockServer('127.0.0.1');
// port = consumerPact.createMockServer('localhost'); // Error in native callback - JSON.parse(ffi.pactffiMockServerMismatches(port)) 
console.log(port)
consumerPact.mockServerMatchedSuccessfully(port)
const mismatches = consumerPact.mockServerMismatches(port);
console.log(mismatches)

npm install @pact-foundation/pact-core

LOG_LEVEL=debug node test.js

You can see the lookup path is /Users/yousaf.nabi/dev/fooscratch/prebuilds/darwin-arm64 but it should be ` /Users/yousaf.nabi/dev/fooscratch/node_modules/@pact-foundation/pact-core/prebuilds/darwin-arm64

[11:46:08.471] DEBUG (10503): [email protected]: Attempting to find pact native module : loading native module from: 

 - /Users/yousaf.nabi/dev/fooscratch/prebuilds/darwin-arm64 
   source: pact-js-core binding lookup 

 - You can override via PACT_PREBUILD_LOCATION

[11:46:08.473] DEBUG (10503): [email protected]: Supported platforms are: 
 - darwin-arm64
 - darwin-x64
 - linux-arm64
 - linux-x64
 - win32-x64
We detected your platform as: 

 - darwin-arm64

[11:46:08.474] ERROR (10503): [email protected]: Failed to initialise native module for darwin-arm64: Error: No native build was found for platform=darwin arch=arm64 runtime=node abi=93 uv=1 armv=8 libc=glibc node=16.20.0
    loaded from: /Users/yousaf.nabi/dev/fooscratch

[11:46:08.474] DEBUG (10503): [email protected]: {supportedPlatformsMessage}
We detected your platform as: 

 - darwin-arm64


      We looked for a supported build in this location /Users/yousaf.nabi/dev/fooscratch/prebuilds/darwin-arm64

      Tip: check there is a prebuild for darwin-arm64 

      check the prebuild exists at the path: /Users/yousaf.nabi/dev/fooscratch/prebuilds/darwin-arm64

      Wrong Path?: set the load path with PACT_PREBUILD_LOCATION ensuring that $PACT_NODE_NAPI_LOCATION/prebuilds/darwin-arm64 exists

      - Note: You dont need to include the prebuilds/darwin-arm64 part of the path, just the parent directory

      - Let us know: We can add more supported path lookups easily, chat to us on slack or raise an issue on github
[11:46:08.474] INFO (10503): [email protected]: Removing all Pact servers.
/Users/yousaf.nabi/dev/fooscratch/node_modules/@pact-foundation/pact-core/src/ffi/index.js:94
        throw new Error(`Failed to load native module, try setting LOG_LEVEL=debug for more info \n. ${error}`);
        ^

Error: Failed to load native module, try setting LOG_LEVEL=debug for more info 
. TypeError: Cannot read properties of undefined (reading 'pactffiInitWithLogLevel')

LOG_LEVEL=debug PACT_PREBUILD_LOCATION=$PWD/node_modules/@pact-foundation/pact-core node test.js

2023-07-06T10:41:20.317521Z DEBUG ThreadId(01) pactffi_create_mock_server_for_pact{pact=PactHandle { pact_ref: 1 } addr_str=0x16f8e5958 tls=false}: pact_mock_server::mock_server: Started mock server on 127.0.0.1:51574
2023-07-06T10:41:20.317539Z TRACE ThreadId(01) pactffi_create_mock_server_for_pact{pact=PactHandle { pact_ref: 1 } addr_str=0x16f8e5958 tls=false}: pact_ffi::mock_server::handles: with_pact after - ref = 1, inner = RefCell { value: PactHandleInner { pact: V4Pact { consumer: Consumer { name: "foo-consumer" }, provider: Provider { name: "bar-provider" }, interactions: [SynchronousHttp { id: None, key: None, description: "a request to get a dog", provider_states: [ProviderState { name: "fido exists", params: {} }], request: HttpRequest { method: "GET", path: "/dogs/1234", query: None, headers: None, body: Missing, matching_rules: MatchingRules { rules: {PATH: MatchingRuleCategory { name: PATH, rules: {} }} }, generators: Generators { categories: {} } }, response: HttpResponse { status: 200, headers: Some({"Content-Type": ["application/json"]}), body: Present(b"{\"age\":23,\"alive\":true,\"name\":\"fido\"}", Some(ContentType { main_type: "application", sub_type: "json", attributes: {}, suffix: None }), None), matching_rules: MatchingRules { rules: {BODY: MatchingRuleCategory { name: BODY, rules: {} }} }, generators: Generators { categories: {} } }, comments: {}, pending: false, plugin_config: {}, interaction_markup: InteractionMarkup { markup: "", markup_type: "" }, transport: None }], metadata: {"pactRust": Object {"ffi": String("0.4.0")}}, plugin_data: [] }, mock_server_started: true, specification_version: V3 } }
51574
[
  {
    method: 'GET',
    path: '/dogs/1234',
    request: { method: 'GET', path: '/dogs/1234' },
    type: 'missing-request'
  }
]
[11:41:20.320] INFO (10256): [email protected]: Deleting Pact Server with options: 
{"dir":"/Users/yousaf.nabi/dev/fooscratch","pactFileWriteMode":"overwrite","ssl":false,"cors":false,"host":"localhost"}
pact ruby standalone server created and deleted

@YOU54F
Copy link
Member Author

YOU54F commented Jul 6, 2023

found the source of the issue

path.resolve(
path.resolve(__dirname, '..', '..'),
process.env['PACT_PREBUILD_LOCATION']?.toString() ?? path.resolve()
),
];

an extra path.resolve around what should be a list of paths in an array

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants