@@ -12,6 +12,7 @@ environment: | |||||
- PYTHON: "C:\\Python36" | - PYTHON: "C:\\Python36" | ||||
TOXENV: "py36" | TOXENV: "py36" | ||||
PYINSTALLER: "1" | PYINSTALLER: "1" | ||||
WININSTALLER: "1" | |||||
install: | install: | ||||
- "SET PATH=%PYTHON%;%PYTHON%\\Scripts;%PATH%" | - "SET PATH=%PYTHON%;%PYTHON%\\Scripts;%PATH%" | ||||
@@ -19,41 +20,17 @@ install: | |||||
- "pip install -U tox" | - "pip install -U tox" | ||||
test_script: | test_script: | ||||
- ps: "tox -- --verbose --cov-report=term" | |||||
- ps: | | - ps: | | ||||
$Env:VERSION = $(python -m mitmproxy.version) | |||||
tox -e cibuild -- build | |||||
- ps: | | |||||
if($Env:RTOOL_KEY) { | |||||
$ibVersion = "18.2.0" | |||||
$ibSetup = "C:\projects\mitmproxy\release\installbuilder-installer.exe" | |||||
$ibCli = "C:\Program Files (x86)\BitRock InstallBuilder Enterprise $ibVersion\bin\builder-cli.exe" | |||||
if (!(Test-Path $ibSetup)) { | |||||
echo "Download InstallBuilder..." | |||||
(New-Object System.Net.WebClient).DownloadFile( | |||||
"https://installbuilder.bitrock.com/installbuilder-enterprise-$ibVersion-windows-installer.exe", | |||||
$ibSetup | |||||
) | |||||
} | |||||
echo "Install InstallBuilder..." | |||||
Start-Process $ibSetup "--mode unattended --unattendedmodeui none" -PassThru -NoNewWindow -Wait | |||||
echo "Decrypt license..." | |||||
tox -e cibuild -- decrypt release\installbuilder\license.xml.enc release\installbuilder\license.xml | |||||
echo "Run InstallBuilder..." | |||||
&$ibCli ` | |||||
build ` | |||||
.\release\installbuilder\mitmproxy.xml ` | |||||
windows ` | |||||
--license .\release\installbuilder\license.xml ` | |||||
--setvars project.version=$Env:VERSION ` | |||||
--verbose | |||||
while (!(Test-Path C:\projects\mitmproxy\release\dist\mitmproxy-*-windows-installer.exe)) { Start-Sleep 0.1 } | |||||
echo "Installer build completed." | |||||
if ($env:APPVEYOR_REPO_COMMIT_MESSAGE.Contains("[notest]")) { | |||||
echo "!!!! Skipping tests." | |||||
} else { | |||||
tox -- --verbose --cov-report=term | |||||
} | } | ||||
- ps: tox -e cibuild -- build | |||||
deploy_script: | deploy_script: | ||||
ps: tox -e cibuild -- upload | ps: tox -e cibuild -- upload | ||||
cache: | cache: | ||||
- C:\projects\mitmproxy\release\installbuilder-installer.exe -> .appveyor.yml | |||||
- C:\projects\mitmproxy\release\installbuilder\setup -> .appveyor.yml | |||||
- C:\Users\appveyor\AppData\Local\pip\cache | - C:\Users\appveyor\AppData\Local\pip\cache |
@@ -74,7 +74,13 @@ script: | |||||
# Using the after_success block DOES NOT capture errors. | # Using the after_success block DOES NOT capture errors. | ||||
# Pull requests might break our build - we need to check this. | # Pull requests might break our build - we need to check this. | ||||
# Pull requests are not allowed to upload build artifacts - enforced by cibuild script. | # Pull requests are not allowed to upload build artifacts - enforced by cibuild script. | ||||
- tox -- --verbose --cov-report=term | |||||
- | | |||||
if [[ $TRAVIS_COMMIT_MESSAGE = *"[notest]"* ]]; then | |||||
echo "!!!! Skipping tests." | |||||
else | |||||
tox -- --verbose --cov-report=term | |||||
fi | |||||
- | | - | | ||||
if [[ $CIBUILD == "1" ]] | if [[ $CIBUILD == "1" ]] | ||||
then | then | ||||
@@ -1,7 +1,6 @@ | |||||
import gc | import gc | ||||
import os | import os | ||||
import platform | import platform | ||||
import re | |||||
import signal | import signal | ||||
import sys | import sys | ||||
import threading | import threading | ||||
@@ -13,21 +12,10 @@ from mitmproxy import version | |||||
def dump_system_info(): | def dump_system_info(): | ||||
mitmproxy_version = version.get_version(True, True) | |||||
mitmproxy_version = re.sub( | |||||
r"-0x([0-9a-f]+)", | |||||
r" (commit \1)", | |||||
mitmproxy_version | |||||
) | |||||
# PyInstaller builds indicator, if using precompiled binary | |||||
if getattr(sys, 'frozen', False): | |||||
bin_indicator = "binary" | |||||
else: | |||||
bin_indicator = "" | |||||
mitmproxy_version = version.get_dev_version() | |||||
data = [ | data = [ | ||||
"Mitmproxy: {} {}".format(mitmproxy_version, bin_indicator), | |||||
"Mitmproxy: {}".format(mitmproxy_version), | |||||
"Python: {}".format(platform.python_version()), | "Python: {}".format(platform.python_version()), | ||||
"OpenSSL: {}".format(SSL.SSLeay_version(SSL.SSLEAY_VERSION).decode()), | "OpenSSL: {}".format(SSL.SSLeay_version(SSL.SSLEAY_VERSION).decode()), | ||||
"Platform: {}".format(platform.platform()), | "Platform: {}".format(platform.platform()), | ||||
@@ -1,9 +1,8 @@ | |||||
import os | import os | ||||
import subprocess | import subprocess | ||||
import sys | |||||
# The actual version string. For precompiled binaries, this will be changed to include the build | |||||
# tag, e.g. "3.0.0.dev0042-0xcafeabc" | |||||
VERSION = "5.0.0" | |||||
VERSION = "5.0.0.dev" | |||||
PATHOD = "pathod " + VERSION | PATHOD = "pathod " + VERSION | ||||
MITMPROXY = "mitmproxy " + VERSION | MITMPROXY = "mitmproxy " + VERSION | ||||
@@ -12,50 +11,33 @@ MITMPROXY = "mitmproxy " + VERSION | |||||
FLOW_FORMAT_VERSION = 7 | FLOW_FORMAT_VERSION = 7 | ||||
def get_version(dev: bool = False, build: bool = False, refresh: bool = False) -> str: | |||||
def get_dev_version() -> str: | |||||
""" | """ | ||||
Return a detailed version string, sourced either from a hardcoded VERSION constant | |||||
or obtained dynamically using git. | |||||
Args: | |||||
dev: If True, non-tagged releases will include a ".devXXXX" suffix, where XXXX is the number | |||||
of commits since the last tagged release. | |||||
build: If True, non-tagged releases will include a "-0xXXXXXXX" suffix, where XXXXXXX are | |||||
the first seven digits of the commit hash. | |||||
refresh: If True, always try to use git instead of a potentially hardcoded constant. | |||||
Return a detailed version string, sourced either from VERSION or obtained dynamically using git. | |||||
""" | """ | ||||
mitmproxy_version = VERSION | mitmproxy_version = VERSION | ||||
if "dev" in VERSION and not refresh: | |||||
pass # There is a hardcoded build tag, so we just use what's there. | |||||
elif dev or build: | |||||
here = os.path.abspath(os.path.join(os.path.dirname(__file__), "..")) | |||||
try: | |||||
git_describe = subprocess.check_output( | |||||
['git', 'describe', '--long'], | |||||
stderr=subprocess.STDOUT, | |||||
cwd=here, | |||||
) | |||||
last_tag, tag_dist, commit = git_describe.decode().strip().rsplit("-", 2) | |||||
commit = commit.lstrip("g")[:7] | |||||
tag_dist = int(tag_dist) | |||||
except Exception: | |||||
pass | |||||
else: | |||||
# Remove current suffix | |||||
mitmproxy_version = mitmproxy_version.split(".dev")[0] | |||||
# Add suffix for non-tagged releases | |||||
if tag_dist > 0: | |||||
mitmproxy_version += ".dev{tag_dist}".format(tag_dist=tag_dist) | |||||
# The wheel build tag (we use the commit) must start with a digit, so we include "0x" | |||||
mitmproxy_version += "-0x{commit}".format(commit=commit) | |||||
if not dev: | |||||
mitmproxy_version = mitmproxy_version.split(".dev")[0] | |||||
elif not build: | |||||
mitmproxy_version = mitmproxy_version.split("-0x")[0] | |||||
here = os.path.abspath(os.path.join(os.path.dirname(__file__), "..")) | |||||
try: | |||||
git_describe = subprocess.check_output( | |||||
['git', 'describe', '--long'], | |||||
stderr=subprocess.STDOUT, | |||||
cwd=here, | |||||
) | |||||
last_tag, tag_dist, commit = git_describe.decode().strip().rsplit("-", 2) | |||||
commit = commit.lstrip("g")[:7] | |||||
tag_dist = int(tag_dist) | |||||
except Exception: | |||||
pass | |||||
else: | |||||
# Add commit info for non-tagged releases | |||||
if tag_dist > 0: | |||||
mitmproxy_version += f" (+{tag_dist}, commit {commit})" | |||||
# PyInstaller build indicator, if using precompiled binary | |||||
if getattr(sys, 'frozen', False): | |||||
mitmproxy_version += " binary" | |||||
return mitmproxy_version | return mitmproxy_version | ||||
@@ -1,14 +1,16 @@ | |||||
#!/usr/bin/env python3 | #!/usr/bin/env python3 | ||||
import glob | |||||
import re | |||||
import contextlib | import contextlib | ||||
import glob | |||||
import os | import os | ||||
import pathlib | |||||
import platform | import platform | ||||
import sys | |||||
import re | |||||
import shutil | import shutil | ||||
import subprocess | import subprocess | ||||
import sys | |||||
import tarfile | import tarfile | ||||
import urllib.request | |||||
import zipfile | import zipfile | ||||
import click | import click | ||||
@@ -38,26 +40,23 @@ class BuildEnviron: | |||||
def __init__( | def __init__( | ||||
self, | self, | ||||
*, | *, | ||||
system = "", | |||||
root_dir = "", | |||||
travis_tag = "", | |||||
travis_branch = "", | |||||
travis_pull_request = "", | |||||
appveyor_repo_tag_name = "", | |||||
appveyor_repo_branch = "", | |||||
appveyor_pull_request_number = "", | |||||
should_build_wheel = False, | |||||
should_build_docker = False, | |||||
should_build_pyinstaller = False, | |||||
has_aws_creds = False, | |||||
has_twine_creds = False, | |||||
docker_username = "", | |||||
docker_password = "", | |||||
system="", | |||||
root_dir="", | |||||
travis_tag="", | |||||
travis_branch="", | |||||
travis_pull_request="", | |||||
appveyor_repo_tag_name="", | |||||
appveyor_repo_branch="", | |||||
appveyor_pull_request_number="", | |||||
should_build_wheel=False, | |||||
should_build_docker=False, | |||||
should_build_pyinstaller=False, | |||||
should_build_wininstaller=False, | |||||
has_aws_creds=False, | |||||
has_twine_creds=False, | |||||
docker_username="", | |||||
docker_password="", | |||||
rtool_key="", | |||||
): | ): | ||||
self.system = system | self.system = system | ||||
self.root_dir = root_dir | self.root_dir = root_dir | ||||
@@ -69,6 +68,7 @@ class BuildEnviron: | |||||
self.should_build_wheel = should_build_wheel | self.should_build_wheel = should_build_wheel | ||||
self.should_build_docker = should_build_docker | self.should_build_docker = should_build_docker | ||||
self.should_build_pyinstaller = should_build_pyinstaller | self.should_build_pyinstaller = should_build_pyinstaller | ||||
self.should_build_wininstaller = should_build_wininstaller | |||||
self.appveyor_repo_tag_name = appveyor_repo_tag_name | self.appveyor_repo_tag_name = appveyor_repo_tag_name | ||||
self.appveyor_repo_branch = appveyor_repo_branch | self.appveyor_repo_branch = appveyor_repo_branch | ||||
@@ -78,33 +78,31 @@ class BuildEnviron: | |||||
self.has_twine_creds = has_twine_creds | self.has_twine_creds = has_twine_creds | ||||
self.docker_username = docker_username | self.docker_username = docker_username | ||||
self.docker_password = docker_password | self.docker_password = docker_password | ||||
self.rtool_key = rtool_key | |||||
@classmethod | @classmethod | ||||
def from_env(klass): | |||||
return klass( | |||||
system = platform.system(), | |||||
root_dir = os.path.normpath(os.path.join(os.path.dirname(__file__), "..")), | |||||
travis_tag = os.environ.get("TRAVIS_TAG", ""), | |||||
travis_branch = os.environ.get("TRAVIS_BRANCH", ""), | |||||
travis_pull_request = os.environ.get("TRAVIS_PULL_REQUEST"), | |||||
appveyor_repo_tag_name = os.environ.get("APPVEYOR_REPO_TAG_NAME", ""), | |||||
appveyor_repo_branch = os.environ.get("APPVEYOR_REPO_BRANCH", ""), | |||||
appveyor_pull_request_number = os.environ.get("APPVEYOR_PULL_REQUEST_NUMBER"), | |||||
should_build_wheel = "WHEEL" in os.environ, | |||||
should_build_pyinstaller = "PYINSTALLER" in os.environ, | |||||
should_build_docker = "DOCKER" in os.environ, | |||||
has_aws_creds = "AWS_ACCESS_KEY_ID" in os.environ, | |||||
has_twine_creds= ( | |||||
def from_env(cls): | |||||
return cls( | |||||
system=platform.system(), | |||||
root_dir=os.path.normpath(os.path.join(os.path.dirname(__file__), "..")), | |||||
travis_tag=os.environ.get("TRAVIS_TAG", ""), | |||||
travis_branch=os.environ.get("TRAVIS_BRANCH", ""), | |||||
travis_pull_request=os.environ.get("TRAVIS_PULL_REQUEST"), | |||||
appveyor_repo_tag_name=os.environ.get("APPVEYOR_REPO_TAG_NAME", ""), | |||||
appveyor_repo_branch=os.environ.get("APPVEYOR_REPO_BRANCH", ""), | |||||
appveyor_pull_request_number=os.environ.get("APPVEYOR_PULL_REQUEST_NUMBER"), | |||||
should_build_wheel="WHEEL" in os.environ, | |||||
should_build_pyinstaller="PYINSTALLER" in os.environ, | |||||
should_build_wininstaller="WININSTALLER" in os.environ, | |||||
should_build_docker="DOCKER" in os.environ, | |||||
has_aws_creds="AWS_ACCESS_KEY_ID" in os.environ, | |||||
has_twine_creds=( | |||||
"TWINE_USERNAME" in os.environ and | "TWINE_USERNAME" in os.environ and | ||||
"TWINE_PASSWORD" in os.environ | "TWINE_PASSWORD" in os.environ | ||||
), | ), | ||||
docker_username = os.environ.get("DOCKER_USERNAME"), | |||||
docker_password = os.environ.get("DOCKER_PASSWORD"), | |||||
docker_username=os.environ.get("DOCKER_USERNAME"), | |||||
docker_password=os.environ.get("DOCKER_PASSWORD"), | |||||
rtool_key=os.environ.get("RTOOL_KEY"), | |||||
) | ) | ||||
def archive(self, path): | def archive(self, path): | ||||
@@ -177,16 +175,45 @@ class BuildEnviron: | |||||
"should_upload_pypi", | "should_upload_pypi", | ||||
] | ] | ||||
for attr in lst: | for attr in lst: | ||||
print("cibuild.%s=%s" % (attr, getattr(self, attr)), file=fp) | |||||
print(f"cibuild.{attr}={getattr(self, attr)}", file=fp) | |||||
def check_version(self) -> None: | |||||
""" | |||||
Check that version numbers match our conventions. | |||||
Raises a ValueError if there is a mismatch. | |||||
""" | |||||
with open(pathlib.Path(self.root_dir) / "mitmproxy" / "version.py") as f: | |||||
contents = f.read() | |||||
version = re.search(r'^VERSION = "(.+?)"', contents, re.M).group(1) | |||||
if self.tag: | |||||
# For (tagged) releases, we are strict: | |||||
# 1. The tagname must match the version in mitmproxy/version.py | |||||
# 2. The version info must be in canonical form (as recommended in PEP 440). | |||||
if version != self.tag: | |||||
raise ValueError(f"Tag is {self.tag}, but mitmproxy/version.py is {version}.") | |||||
try: | |||||
parver.Version.parse(version, strict=True) | |||||
except parver.ParseError as e: | |||||
raise ValueError(str(e)) from e | |||||
else: | |||||
# For snapshots, we only ensure that mitmproxy/version.py contains a dev release. | |||||
version_info = parver.Version.parse(version) | |||||
if not version_info.is_devrelease: | |||||
raise ValueError("Releases must be tagged.") | |||||
@property | @property | ||||
def has_docker_creds(self) -> bool: | def has_docker_creds(self) -> bool: | ||||
return self.docker_username and self.docker_password | |||||
return bool(self.docker_username and self.docker_password) | |||||
@property | @property | ||||
def is_prod_release(self) -> bool: | def is_prod_release(self) -> bool: | ||||
if not self.tag: | |||||
return False | |||||
try: | try: | ||||
v = parver.Version.parse(self.version) | |||||
v = parver.Version.parse(self.version, strict=True) | |||||
except (parver.ParseError, BuildError): | except (parver.ParseError, BuildError): | ||||
return False | return False | ||||
return not v.is_prerelease | return not v.is_prerelease | ||||
@@ -212,7 +239,7 @@ class BuildEnviron: | |||||
@property | @property | ||||
def should_upload_docker(self) -> bool: | def should_upload_docker(self) -> bool: | ||||
return all([ | return all([ | ||||
(self.tag or self.branch == "master"), | |||||
(self.is_prod_release or self.branch == "master"), | |||||
self.should_build_docker, | self.should_build_docker, | ||||
self.has_docker_creds, | self.has_docker_creds, | ||||
]) | ]) | ||||
@@ -220,7 +247,6 @@ class BuildEnviron: | |||||
@property | @property | ||||
def should_upload_pypi(self) -> bool: | def should_upload_pypi(self) -> bool: | ||||
return all([ | return all([ | ||||
self.tag, | |||||
self.is_prod_release, | self.is_prod_release, | ||||
self.should_build_wheel, | self.should_build_wheel, | ||||
self.has_twine_creds, | self.has_twine_creds, | ||||
@@ -242,7 +268,7 @@ class BuildEnviron: | |||||
name = self.tag or self.branch | name = self.tag or self.branch | ||||
if not name: | if not name: | ||||
raise BuildError("We're on neither a tag nor a branch - could not establish version") | raise BuildError("We're on neither a tag nor a branch - could not establish version") | ||||
return re.sub('^v', "", name) | |||||
return name | |||||
def build_wheel(be: BuildEnviron): # pragma: no cover | def build_wheel(be: BuildEnviron): # pragma: no cover | ||||
@@ -354,6 +380,56 @@ def build_pyinstaller(be: BuildEnviron): # pragma: no cover | |||||
click.echo("Packed {}.".format(be.archive_name(bdist))) | click.echo("Packed {}.".format(be.archive_name(bdist))) | ||||
def build_wininstaller(be: BuildEnviron): # pragma: no cover | |||||
click.echo("Building wininstaller package...") | |||||
IB_VERSION = "18.5.2" | |||||
IB_DIR = pathlib.Path(be.release_dir) / "installbuilder" | |||||
IB_SETUP = IB_DIR / "setup" / f"{IB_VERSION}-installer.exe" | |||||
IB_CLI = fr"C:\Program Files (x86)\BitRock InstallBuilder Enterprise {IB_VERSION}\bin\builder-cli.exe" | |||||
IB_LICENSE = IB_DIR / "license.xml" | |||||
if True or not os.path.isfile(IB_CLI): | |||||
if not os.path.isfile(IB_SETUP): | |||||
click.echo("Downloading InstallBuilder...") | |||||
def report(block, blocksize, total): | |||||
done = block * blocksize | |||||
if round(100 * done / total) != round(100 * (done - blocksize) / total): | |||||
click.secho(f"Downloading... {round(100*done/total)}%") | |||||
urllib.request.urlretrieve( | |||||
f"https://installbuilder.bitrock.com/installbuilder-enterprise-{IB_VERSION}-windows-installer.exe", | |||||
IB_SETUP.with_suffix(".tmp"), | |||||
reporthook=report | |||||
) | |||||
shutil.move(IB_SETUP.with_suffix(".tmp"), IB_SETUP) | |||||
click.echo("Install InstallBuilder...") | |||||
subprocess.run([str(IB_SETUP), "--mode", "unattended", "--unattendedmodeui", "none"], | |||||
check=True) | |||||
assert os.path.isfile(IB_CLI) | |||||
click.echo("Decrypt InstallBuilder license...") | |||||
f = cryptography.fernet.Fernet(be.rtool_key.encode()) | |||||
with open(IB_LICENSE.with_suffix(".xml.enc"), "rb") as infile, open(IB_LICENSE, | |||||
"wb") as outfile: | |||||
outfile.write(f.decrypt(infile.read())) | |||||
click.echo("Run InstallBuilder...") | |||||
subprocess.run([ | |||||
IB_CLI, | |||||
"build", | |||||
str(IB_DIR / "mitmproxy.xml"), | |||||
"windows", | |||||
"--license", str(IB_LICENSE), | |||||
"--setvars", f"project.version={be.version}", | |||||
"--verbose" | |||||
], check=True) | |||||
assert os.path.isfile( | |||||
os.path.join(be.dist_dir, f"mitmproxy-{be.version}-windows-installer.exe")) | |||||
@click.group(chain=True) | @click.group(chain=True) | ||||
def cli(): # pragma: no cover | def cli(): # pragma: no cover | ||||
""" | """ | ||||
@@ -370,6 +446,7 @@ def build(): # pragma: no cover | |||||
be = BuildEnviron.from_env() | be = BuildEnviron.from_env() | ||||
be.dump_info() | be.dump_info() | ||||
be.check_version() | |||||
os.makedirs(be.dist_dir, exist_ok=True) | os.makedirs(be.dist_dir, exist_ok=True) | ||||
if be.should_build_wheel: | if be.should_build_wheel: | ||||
@@ -379,6 +456,8 @@ def build(): # pragma: no cover | |||||
build_docker_image(be, whl) | build_docker_image(be, whl) | ||||
if be.should_build_pyinstaller: | if be.should_build_pyinstaller: | ||||
build_pyinstaller(be) | build_pyinstaller(be) | ||||
if be.should_build_wininstaller and be.rtool_key: | |||||
build_wininstaller(be) | |||||
@cli.command("upload") | @cli.command("upload") | ||||
@@ -421,14 +500,5 @@ def upload(): # pragma: no cover | |||||
subprocess.check_call(["docker", "push", be.docker_tag]) | subprocess.check_call(["docker", "push", be.docker_tag]) | ||||
@cli.command("decrypt") | |||||
@click.argument('infile', type=click.File('rb')) | |||||
@click.argument('outfile', type=click.File('wb')) | |||||
@click.argument('key', envvar='RTOOL_KEY') | |||||
def decrypt(infile, outfile, key): # pragma: no cover | |||||
f = cryptography.fernet.Fernet(key.encode()) | |||||
outfile.write(f.decrypt(infile.read())) | |||||
if __name__ == "__main__": # pragma: no cover | if __name__ == "__main__": # pragma: no cover | ||||
cli() | cli() |
@@ -1,2 +1,2 @@ | |||||
license.xml | license.xml | ||||
*.xml.backup | |||||
*.xml.backup |
@@ -0,0 +1,2 @@ | |||||
* | |||||
!.gitignore |
@@ -13,7 +13,7 @@ with open(os.path.join(here, 'README.rst'), encoding='utf-8') as f: | |||||
long_description = f.read() | long_description = f.read() | ||||
with open(os.path.join(here, "mitmproxy", "version.py")) as f: | with open(os.path.join(here, "mitmproxy", "version.py")) as f: | ||||
VERSION = re.search(r'VERSION = "(.+?)(?:-0x|")', f.read()).group(1) | |||||
VERSION = re.search(r'VERSION = "(.+?)"', f.read()).group(1) | |||||
setup( | setup( | ||||
name="mitmproxy", | name="mitmproxy", | ||||
@@ -1,6 +1,7 @@ | |||||
import pathlib | import pathlib | ||||
import runpy | import runpy | ||||
import subprocess | import subprocess | ||||
import sys | |||||
from unittest import mock | from unittest import mock | ||||
from mitmproxy import version | from mitmproxy import version | ||||
@@ -15,22 +16,19 @@ def test_version(capsys): | |||||
assert stdout.strip() == version.VERSION | assert stdout.strip() == version.VERSION | ||||
def test_get_version_hardcoded(): | |||||
version.VERSION = "3.0.0.dev123-0xcafebabe" | |||||
assert version.get_version() == "3.0.0" | |||||
assert version.get_version(True) == "3.0.0.dev123" | |||||
assert version.get_version(True, True) == "3.0.0.dev123-0xcafebabe" | |||||
def test_get_version(): | def test_get_version(): | ||||
version.VERSION = "3.0.0" | |||||
version.VERSION = "3.0.0rc2" | |||||
with mock.patch('subprocess.check_output') as m: | with mock.patch('subprocess.check_output') as m: | ||||
m.return_value = b"tag-0-cafecafe" | m.return_value = b"tag-0-cafecafe" | ||||
assert version.get_version(True, True) == "3.0.0" | |||||
assert version.get_dev_version() == "3.0.0rc2" | |||||
sys.frozen = True | |||||
assert version.get_dev_version() == "3.0.0rc2 binary" | |||||
sys.frozen = False | |||||
m.return_value = b"tag-2-cafecafe" | m.return_value = b"tag-2-cafecafe" | ||||
assert version.get_version(True, True) == "3.0.0.dev2-0xcafecaf" | |||||
assert version.get_dev_version() == "3.0.0rc2 (+2, commit cafecaf)" | |||||
m.side_effect = subprocess.CalledProcessError(-1, 'git describe --long') | m.side_effect = subprocess.CalledProcessError(-1, 'git describe --long') | ||||
assert version.get_version(True, True) == "3.0.0" | |||||
assert version.get_dev_version() == "3.0.0rc2" |
@@ -1,5 +1,5 @@ | |||||
import os | |||||
import io | import io | ||||
import os | |||||
import pytest | import pytest | ||||
@@ -13,11 +13,9 @@ def test_buildenviron_live(): | |||||
def test_buildenviron_common(): | def test_buildenviron_common(): | ||||
be = cibuild.BuildEnviron( | be = cibuild.BuildEnviron( | ||||
system = "Linux", | |||||
root_dir = "/foo", | |||||
travis_tag = "v0.0.1", | |||||
travis_branch = "v0.x", | |||||
system="Linux", | |||||
root_dir="/foo", | |||||
travis_branch="master", | |||||
) | ) | ||||
assert be.release_dir == os.path.join(be.root_dir, "release") | assert be.release_dir == os.path.join(be.root_dir, "release") | ||||
assert be.dist_dir == os.path.join(be.root_dir, "release", "dist") | assert be.dist_dir == os.path.join(be.root_dir, "release", "dist") | ||||
@@ -30,8 +28,8 @@ def test_buildenviron_common(): | |||||
assert cs.getvalue() | assert cs.getvalue() | ||||
be = cibuild.BuildEnviron( | be = cibuild.BuildEnviron( | ||||
system = "Unknown", | |||||
root_dir = "/foo", | |||||
system="Unknown", | |||||
root_dir="/foo", | |||||
) | ) | ||||
with pytest.raises(cibuild.BuildError): | with pytest.raises(cibuild.BuildError): | ||||
be.version | be.version | ||||
@@ -43,19 +41,18 @@ def test_buildenviron_pr(): | |||||
# Simulates a PR. We build everything, but don't have access to secret | # Simulates a PR. We build everything, but don't have access to secret | ||||
# credential env variables. | # credential env variables. | ||||
be = cibuild.BuildEnviron( | be = cibuild.BuildEnviron( | ||||
travis_tag = "", | |||||
travis_branch = "master", | |||||
travis_pull_request = "true", | |||||
should_build_wheel = True, | |||||
should_build_pyinstaller = True, | |||||
should_build_docker = True, | |||||
travis_tag="", | |||||
travis_branch="master", | |||||
travis_pull_request="true", | |||||
should_build_wheel=True, | |||||
should_build_pyinstaller=True, | |||||
should_build_docker=True, | |||||
) | ) | ||||
assert be.is_pull_request | assert be.is_pull_request | ||||
# Mini test for appveyor | # Mini test for appveyor | ||||
be = cibuild.BuildEnviron( | be = cibuild.BuildEnviron( | ||||
appveyor_pull_request_number = "xxxx", | |||||
appveyor_pull_request_number="xxxx", | |||||
) | ) | ||||
assert be.is_pull_request | assert be.is_pull_request | ||||
assert not be.is_prod_release | assert not be.is_prod_release | ||||
@@ -64,15 +61,14 @@ def test_buildenviron_pr(): | |||||
def test_buildenviron_commit(): | def test_buildenviron_commit(): | ||||
# Simulates an ordinary commit on the master branch. | # Simulates an ordinary commit on the master branch. | ||||
be = cibuild.BuildEnviron( | be = cibuild.BuildEnviron( | ||||
travis_tag = "", | |||||
travis_branch = "master", | |||||
travis_pull_request = "false", | |||||
should_build_wheel = True, | |||||
should_build_pyinstaller = True, | |||||
should_build_docker = True, | |||||
docker_username = "foo", | |||||
docker_password = "bar", | |||||
travis_tag="", | |||||
travis_branch="master", | |||||
travis_pull_request="false", | |||||
should_build_wheel=True, | |||||
should_build_pyinstaller=True, | |||||
should_build_docker=True, | |||||
docker_username="foo", | |||||
docker_password="bar", | |||||
) | ) | ||||
assert be.docker_tag == "mitmproxy/mitmproxy:dev" | assert be.docker_tag == "mitmproxy/mitmproxy:dev" | ||||
assert be.should_upload_docker | assert be.should_upload_docker | ||||
@@ -81,23 +77,21 @@ def test_buildenviron_commit(): | |||||
assert not be.is_prod_release | assert not be.is_prod_release | ||||
def test_buildenviron_rleasetag(): | |||||
def test_buildenviron_releasetag(): | |||||
# Simulates a tagged release on a release branch. | # Simulates a tagged release on a release branch. | ||||
be = cibuild.BuildEnviron( | be = cibuild.BuildEnviron( | ||||
system = "Linux", | |||||
root_dir = "/foo", | |||||
travis_tag = "v0.0.1", | |||||
travis_branch = "v0.x", | |||||
should_build_wheel = True, | |||||
should_build_docker = True, | |||||
should_build_pyinstaller = True, | |||||
has_twine_creds = True, | |||||
docker_username = "foo", | |||||
docker_password = "bar", | |||||
system="Linux", | |||||
root_dir="/foo", | |||||
travis_tag="0.0.1", | |||||
travis_branch="v0.x", | |||||
should_build_wheel=True, | |||||
should_build_docker=True, | |||||
should_build_pyinstaller=True, | |||||
has_twine_creds=True, | |||||
docker_username="foo", | |||||
docker_password="bar", | |||||
) | ) | ||||
assert be.tag == "v0.0.1" | |||||
assert be.tag == "0.0.1" | |||||
assert be.branch == "v0.x" | assert be.branch == "v0.x" | ||||
assert be.version == "0.0.1" | assert be.version == "0.0.1" | ||||
assert be.upload_dir == "0.0.1" | assert be.upload_dir == "0.0.1" | ||||
@@ -110,18 +104,16 @@ def test_buildenviron_rleasetag(): | |||||
def test_buildenviron_branch(): | def test_buildenviron_branch(): | ||||
# Simulates a development branch on the main repo | # Simulates a development branch on the main repo | ||||
be = cibuild.BuildEnviron( | be = cibuild.BuildEnviron( | ||||
system = "Linux", | |||||
root_dir = "/foo", | |||||
travis_tag = "", | |||||
travis_branch = "mybranch", | |||||
should_build_wheel = True, | |||||
should_build_docker = True, | |||||
should_build_pyinstaller = True, | |||||
has_twine_creds = True, | |||||
docker_username = "foo", | |||||
docker_password = "bar", | |||||
system="Linux", | |||||
root_dir="/foo", | |||||
travis_tag="", | |||||
travis_branch="mybranch", | |||||
should_build_wheel=True, | |||||
should_build_docker=True, | |||||
should_build_pyinstaller=True, | |||||
has_twine_creds=True, | |||||
docker_username="foo", | |||||
docker_password="bar", | |||||
) | ) | ||||
assert be.tag == "" | assert be.tag == "" | ||||
assert be.branch == "mybranch" | assert be.branch == "mybranch" | ||||
@@ -133,11 +125,10 @@ def test_buildenviron_branch(): | |||||
def test_buildenviron_osx(tmpdir): | def test_buildenviron_osx(tmpdir): | ||||
be = cibuild.BuildEnviron( | be = cibuild.BuildEnviron( | ||||
system = "Darwin", | |||||
root_dir = "/foo", | |||||
travis_tag = "v0.0.1", | |||||
travis_branch = "v0.x", | |||||
system="Darwin", | |||||
root_dir="/foo", | |||||
travis_tag="0.0.1", | |||||
travis_branch="v0.x", | |||||
) | ) | ||||
assert be.platform_tag == "osx" | assert be.platform_tag == "osx" | ||||
assert be.bdists == { | assert be.bdists == { | ||||
@@ -153,11 +144,10 @@ def test_buildenviron_osx(tmpdir): | |||||
def test_buildenviron_windows(tmpdir): | def test_buildenviron_windows(tmpdir): | ||||
be = cibuild.BuildEnviron( | be = cibuild.BuildEnviron( | ||||
system = "Windows", | |||||
root_dir = "/foo", | |||||
travis_tag = "v0.0.1", | |||||
travis_branch = "v0.x", | |||||
system="Windows", | |||||
root_dir="/foo", | |||||
travis_tag="0.0.1", | |||||
travis_branch="v0.x", | |||||
) | ) | ||||
assert be.platform_tag == "windows" | assert be.platform_tag == "windows" | ||||
assert be.bdists == { | assert be.bdists == { | ||||
@@ -168,4 +158,26 @@ def test_buildenviron_windows(tmpdir): | |||||
a = be.archive(os.path.join(tmpdir, "arch")) | a = be.archive(os.path.join(tmpdir, "arch")) | ||||
assert a | assert a | ||||
a.close() | |||||
a.close() | |||||
@pytest.mark.parametrize("version, tag, ok", [ | |||||
("3.0.0.dev", "", True), # regular snapshot | |||||
("3.0.0.dev", "3.0.0", False), # forgot to remove ".dev" on bump | |||||
("3.0.0", "", False), # forgot to re-add ".dev" | |||||
("3.0.0", "4.0.0", False), # version mismatch | |||||
("3.0.0", "3.0.0", True), # regular release | |||||
("3.0.0.rc1", "3.0.0.rc1", False), # non-canonical. | |||||
]) | |||||
def test_buildenviron_check_version(version, tag, ok, tmpdir): | |||||
tmpdir.mkdir("mitmproxy").join("version.py").write(f'VERSION = "{version}"') | |||||
be = cibuild.BuildEnviron( | |||||
root_dir=tmpdir, | |||||
travis_tag=tag | |||||
) | |||||
if ok: | |||||
be.check_version() | |||||
else: | |||||
with pytest.raises(ValueError): | |||||
be.check_version() |
@@ -33,7 +33,7 @@ commands = | |||||
python ./test/individual_coverage.py | python ./test/individual_coverage.py | ||||
[testenv:cibuild] | [testenv:cibuild] | ||||
passenv = TRAVIS_* APPVEYOR_* AWS_* TWINE_* DOCKER_* RTOOL_KEY WHEEL DOCKER PYINSTALLER | |||||
passenv = TRAVIS_* APPVEYOR_* AWS_* TWINE_* DOCKER_* RTOOL_KEY WHEEL DOCKER PYINSTALLER WININSTALLER | |||||
deps = | deps = | ||||
-rrequirements.txt | -rrequirements.txt | ||||
pyinstaller==3.3.1 | pyinstaller==3.3.1 | ||||