Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,17 @@
### 1.4.2
* f2230b6 - chore: Bundle Ruby standalones into dist artifact. (#256) (Taj Pereira, Sun Aug 22 19:53:53 2021 +0930)
* e370786 - chore: Releasing version 1.4.1 (Elliott Murray, Tue Aug 17 18:55:53 2021 +0100)
* 7dc8864 - fix: make uvicorn versions over 0.14 (#255) (Elliott Murray, Tue Aug 17 18:51:52 2021 +0100)
* da49cd7 - chore: Releasing version 1.4.0 (Elliott Murray, Sat Aug 7 10:17:26 2021 +0100)
* 0089937 - fix: issue originating from snyk with requests and urllib (#252) (Elliott Murray, Sat Jul 31 12:46:15 2021 +0100)
* 903371b - feat: added support for message provider (#251) (Fabio Pulvirenti, Sat Jul 31 13:24:19 2021 +0200)
* 2c81029 - chore(snyk): update fastapi (#239) (Elliott Murray, Fri Jun 11 09:12:38 2021 +0100)
### 1.4.1
* 7dc8864 - fix: make uvicorn versions over 0.14 (#255) (Elliott Murray, Tue Aug 17 18:51:52 2021 +0100)
### 1.4.0
* 0089937 - fix: issue originating from snyk with requests and urllib (#252) (Elliott Murray, Sat Jul 31 12:46:15 2021 +0100)
* 903371b - feat: added support for message provider (#251) (Fabio Pulvirenti, Sat Jul 31 13:24:19 2021 +0200)
* 2c81029 - chore(snyk): update fastapi (#239) (Elliott Murray, Fri Jun 11 09:12:38 2021 +0100)
### 1.3.9
* 98d9a4b - chore(ruby): update ruby standalen (#233) (Elliott Murray, Thu May 13 20:21:10 2021 +0100)
* 657e770 - fix: change default from empty string to empty list (#235) (Vasile Tofan, Thu May 13 22:20:47 2021 +0300)
Expand Down
2 changes: 1 addition & 1 deletion MANIFEST.in
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
include LICENSE
include *.txt
include *.md
include pact/bin/*
prune pact/test
prune pact/bin
prune e2e
11 changes: 10 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -437,7 +437,7 @@ To setup a development environment:
1. If you want to run tests for all Python versions, install 2.7, 3.3, 3.4, 3.5, and 3.6 from source or using a tool like [pyenv]
2. Its recommended to create a Python [virtualenv] for the project

The setup the environment, run tests, and package the application, run:
To setup the environment, run tests, and package the application, run:
`make release`

If you are just interested in packaging pact-python so you can install it using pip:
Expand All @@ -449,6 +449,15 @@ From there you can use pip to install it:

`pip install ./dist/pact-python-N.N.N.tar.gz`

## Offline Installation of Standalone Packages

Although all Ruby standalone applications are predownloaded into the wheel artifact, it may be useful, for development, purposes to install custom Ruby binaries. In which case, use the `bin-path` flag.
```
pip install pact-python --bin-path=/absolute/path/to/folder/containing/pact/binaries/for/your/os
```

Pact binaries can be found at [Pact Ruby Releases](https://github.com/pact-foundation/pact-ruby-standalone/releases).

## Testing

This project has unit and end to end tests, which can both be run from make:
Expand Down
2 changes: 1 addition & 1 deletion pact/__version__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
"""Pact version info."""

__version__ = '1.3.9'
__version__ = '1.4.2'
125 changes: 106 additions & 19 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import os
import platform
import shutil
import sys
import tarfile

Expand All @@ -10,18 +11,39 @@
from setuptools import setup
from setuptools.command.develop import develop
from setuptools.command.install import install
from distutils.command.sdist import sdist as sdist_orig


IS_64 = sys.maxsize > 2 ** 32
PACT_STANDALONE_VERSION = '1.88.51'

PACT_STANDALONE_SUFFIXES = ['osx.tar.gz',
'linux-x86_64.tar.gz',
'linux-x86.tar.gz',
'win32.zip']

here = os.path.abspath(os.path.dirname(__file__))

about = {}
with open(os.path.join(here, "pact", "__version__.py")) as f:
exec(f.read(), about)

class sdist(sdist_orig):
"""
Subclass sdist so that we can download all standalone ruby applications
into ./pact/bin so our users receive all the binaries on pip install.
"""
def run(self):
package_bin_path = os.path.join(os.path.dirname(__file__), 'pact', 'bin')

if os.path.exists(package_bin_path):
shutil.rmtree(package_bin_path, ignore_errors=True)
os.mkdir(package_bin_path)

for suffix in PACT_STANDALONE_SUFFIXES:
filename = ('pact-{version}-{suffix}').format(version=PACT_STANDALONE_VERSION, suffix=suffix)
download_ruby_app_binary(package_bin_path, filename, suffix)
super().run()


class PactPythonDevelopCommand(develop):
"""
Expand All @@ -35,11 +57,11 @@ class PactPythonDevelopCommand(develop):
def run(self):
"""Install ruby command."""
develop.run(self)
bin_path = os.path.join(os.path.dirname(__file__), 'pact', 'bin')
if not os.path.exists(bin_path):
os.mkdir(bin_path)
package_bin_path = os.path.join(os.path.dirname(__file__), 'pact', 'bin')
if not os.path.exists(package_bin_path):
os.mkdir(package_bin_path)

install_ruby_app(bin_path)
install_ruby_app(package_bin_path, download_bin_path=None)


class PactPythonInstallCommand(install):
Expand All @@ -48,25 +70,66 @@ class PactPythonInstallCommand(install):

Installs the Python package and unpacks the platform appropriate version
of the Ruby mock service and provider verifier.

User Options:
--bin-path An absolute folder path containing predownloaded pact binaries
that should be used instead of fetching from the internet.
"""

user_options = install.user_options + [('bin-path=', None, None)]

def initialize_options(self):
"""Load our preconfigured options"""
install.initialize_options(self)
self.bin_path = None

def finalize_options(self):
"""Load provided CLI arguments into our options"""
install.finalize_options(self)

def run(self):
"""Install python binary."""
install.run(self)
bin_path = os.path.join(self.install_lib, 'pact', 'bin')
os.mkdir(bin_path)
install_ruby_app(bin_path)
package_bin_path = os.path.join(self.install_lib, 'pact', 'bin')
if not os.path.exists(package_bin_path):
os.mkdir(package_bin_path)
install_ruby_app(package_bin_path, self.bin_path)


def install_ruby_app(bin_path):
def install_ruby_app(package_bin_path, download_bin_path):
"""
Download a Ruby application and install it for use.
Installs the ruby standalone application for this OS.

:param bin_path: The path where binaries should be installed.
:param package_bin_path: The path where we want our pact binaries unarchived.
:param download_bin_path: An optional path containing pre-downloaded pact binaries.
"""

binary = ruby_app_binary()
if download_bin_path is None:
download_bin_path = package_bin_path

path = os.path.join(download_bin_path, binary['filename'])

if os.path.isfile(path) is True:
extract_ruby_app_binary(download_bin_path, package_bin_path, binary['filename'])
else:
if download_bin_path is not None:
if os.path.isfile(path) is not True:
raise RuntimeError('Could not find {} binary.'.format(path))
extract_ruby_app_binary(download_bin_path, package_bin_path, binary['filename'])
else:
download_ruby_app_binary(package_bin_path, binary['filename'], binary['suffix'])
extract_ruby_app_binary(package_bin_path, package_bin_path, binary['filename'])

def ruby_app_binary():
"""
Determines the ruby app binary required for this OS.

:return A dictionary of type {'filename': string, 'version': string, 'suffix': string }
"""
target_platform = platform.platform().lower()
uri = ('https://github.com/pact-foundation/pact-ruby-standalone/releases'
'/download/v{version}/pact-{version}-{suffix}')

binary = ('pact-{version}-{suffix}')

if 'darwin' in target_platform or 'macos' in target_platform:
suffix = 'osx.tar.gz'
Expand All @@ -82,12 +145,26 @@ def install_ruby_app(bin_path):
platform.platform())
raise Exception(msg)

binary = binary.format(version=PACT_STANDALONE_VERSION, suffix=suffix)
return {'filename': binary, 'version': PACT_STANDALONE_VERSION, 'suffix': suffix}

def download_ruby_app_binary(path_to_download_to, filename, suffix):
"""
Downloads `binary` into `path_to_download_to`.

:param path_to_download_to: The path where binaries should be downloaded.
:param filename: The filename that should be installed.
:param suffix: The suffix of the standalone app to install.
"""
uri = ('https://github.com/pact-foundation/pact-ruby-standalone/releases'
'/download/v{version}/pact-{version}-{suffix}')

if sys.version_info.major == 2:
from urllib import urlopen
else:
from urllib.request import urlopen

path = os.path.join(bin_path, suffix)
path = os.path.join(path_to_download_to, filename)
resp = urlopen(uri.format(version=PACT_STANDALONE_VERSION, suffix=suffix))
with open(path, 'wb') as f:
if resp.code == 200:
Expand All @@ -97,12 +174,21 @@ def install_ruby_app(bin_path):
'Received HTTP {} when downloading {}'.format(
resp.code, resp.url))

def extract_ruby_app_binary(source, destination, binary):
"""
Extracts the ruby app binary from `source` into `destination`.

:param source: The location of the binary to unarchive.
:param destination: The location to unarchive to.
:param binary: The binary that needs to be unarchived.
"""
path = os.path.join(source, binary)
if 'windows' in platform.platform().lower():
with ZipFile(path) as f:
f.extractall(bin_path)
f.extractall(destination)
else:
with tarfile.open(path) as f:
f.extractall(bin_path)
f.extractall(destination)


def read(filename):
Expand All @@ -117,16 +203,17 @@ def read(filename):
'psutil>=2.0.0',
'requests>=2.5.0',
'six>=1.9.0',
'fastapi==0.67.0',
'fastapi>=0.67.0',
'urllib3>=1.26.5',
'uvicorn==0.14.0'
'uvicorn>=0.14.0'
]

if __name__ == '__main__':
setup(
cmdclass={
'develop': PactPythonDevelopCommand,
'install': PactPythonInstallCommand},
'install': PactPythonInstallCommand,
'sdist': sdist},
name='pact-python',
version=about['__version__'],
description=(
Expand Down