Repository: mitmproxy/mitmproxy

Issue:
Release filenames are inconsistent
##### Steps to reproduce the problem:

1. Roll a new release
2. Some releases have a "v4.0.0" version spec, others have a "4.0.0" version spec: https://snapshots.mitmproxy.org/v4.0.1/
3. v4.0.0 is unexpected and breaks the Linux download link on mitmproxy.org.



Discussion:

Resolving patch:
diff --git a/mitmproxy/version.py b/mitmproxy/version.py
--- a/mitmproxy/version.py
+++ b/mitmproxy/version.py
@@ -3,7 +3,7 @@
 
 # The actual version string. For precompiled binaries, this will be changed to include the build
 # tag, e.g. "3.0.0.dev0042-0xcafeabc"
-VERSION = "4.0.0"
+VERSION = "5.0.0"
 PATHOD = "pathod " + VERSION
 MITMPROXY = "mitmproxy " + VERSION
 
diff --git a/release/ci.py b/release/ci.py
--- a/release/ci.py
+++ b/release/ci.py
@@ -1,5 +1,7 @@
 #!/usr/bin/env python3
 
+import glob
+import re
 import contextlib
 import os
 import platform
@@ -10,7 +12,6 @@
 import zipfile
 from os.path import join, abspath, dirname, exists, basename
 
-import cryptography.fernet
 import click
 
 # https://virtualenv.pypa.io/en/latest/userguide.html#windows-notes
@@ -73,17 +74,17 @@ def Archive(name):
 TAG = os.environ.get("TRAVIS_TAG", os.environ.get("APPVEYOR_REPO_TAG_NAME", None))
 BRANCH = os.environ.get("TRAVIS_BRANCH", os.environ.get("APPVEYOR_REPO_BRANCH", None))
 if TAG:
-    VERSION = TAG
+    VERSION = re.sub('^v', '', TAG)
     UPLOAD_DIR = VERSION
 elif BRANCH:
-    VERSION = BRANCH
+    VERSION = re.sub('^v', '', BRANCH)
     UPLOAD_DIR = "branches/%s" % VERSION
 else:
     print("Could not establish build name - exiting." % BRANCH)
     sys.exit(0)
 
-
 print("BUILD VERSION=%s" % VERSION)
+print("BUILD UPLOAD_DIR=%s" % UPLOAD_DIR)
 
 
 def archive_name(bdist: str) -> str:
@@ -99,23 +100,6 @@ def archive_name(bdist: str) -> str:
     )
 
 
-def wheel_name() -> str:
-    return "mitmproxy-{version}-py3-none-any.whl".format(version=VERSION)
-
-
-def installer_name() -> str:
-    ext = {
-        "Windows": "exe",
-        "Darwin": "dmg",
-        "Linux": "run"
-    }[platform.system()]
-    return "mitmproxy-{version}-{platform}-installer.{ext}".format(
-        version=VERSION,
-        platform=PLATFORM_TAG,
-        ext=ext,
-    )
-
-
 @contextlib.contextmanager
 def chdir(path: str):
     old_dir = os.getcwd()
@@ -134,7 +118,7 @@ def cli():
 
 @cli.command("info")
 def info():
-    print("Version: %s" % VERSION)
+    click.echo("Version: %s" % VERSION)
 
 
 @cli.command("build")
@@ -142,23 +126,41 @@ def build():
     """
     Build a binary distribution
     """
+    os.makedirs(DIST_DIR, exist_ok=True)
+    if "WHEEL" in os.environ:
+        build_wheel()
+    else:
+        click.echo("Not building wheels.")
+    build_pyinstaller()
+
+
+def build_wheel():
+    click.echo("Building wheel...")
+    subprocess.check_call([
+        "python",
+        "setup.py",
+        "-q",
+        "bdist_wheel",
+        "--dist-dir", DIST_DIR,
+    ])
+
+    whl = glob.glob(join(DIST_DIR, 'mitmproxy-*-py3-none-any.whl'))[0]
+    click.echo("Found wheel package: {}".format(whl))
+
+    subprocess.check_call([
+        "tox",
+        "-e", "wheeltest",
+        "--",
+        whl
+    ])
+
+
+def build_pyinstaller():
     if exists(PYINSTALLER_TEMP):
         shutil.rmtree(PYINSTALLER_TEMP)
     if exists(PYINSTALLER_DIST):
         shutil.rmtree(PYINSTALLER_DIST)
 
-    os.makedirs(DIST_DIR, exist_ok=True)
-
-    if "WHEEL" in os.environ:
-        print("Building wheel...")
-        subprocess.check_call(
-            [
-                "python",
-                "setup.py", "-q", "bdist_wheel",
-                "--dist-dir", "release/dist",
-            ]
-        )
-
     for bdist, tools in sorted(BDISTS.items()):
         with Archive(join(DIST_DIR, archive_name(bdist))) as archive:
             for tool in tools:
@@ -168,7 +170,7 @@ def build():
                 # This is PyInstaller, so it messes up paths.
                 # We need to make sure that we are in the spec folder.
                 with chdir(PYINSTALLER_SPEC):
-                    print("Building %s binary..." % tool)
+                    click.echo("Building %s binary..." % tool)
                     excludes = []
                     if tool != "mitmweb":
                         excludes.append("mitmproxy.tools.web")
@@ -209,11 +211,11 @@ def build():
                     )
                     executable = executable.replace("_main", "")
 
-                print("> %s --version" % executable)
-                print(subprocess.check_output([executable, "--version"]).decode())
+                click.echo("> %s --version" % executable)
+                click.echo(subprocess.check_output([executable, "--version"]).decode())
 
                 archive.add(executable, basename(executable))
-        print("Packed {}.".format(archive_name(bdist)))
+        click.echo("Packed {}.".format(archive_name(bdist)))
 
 
 def is_pr():
@@ -229,34 +231,40 @@ def is_pr():
 @cli.command("upload")
 def upload():
     """
-        Upload snapshot to snapshot server
+        Upload build artifacts to snapshot server and
+        upload wheel package to PyPi
     """
     # This requires some explanation. The AWS access keys are only exposed to
     # privileged builds - that is, they are not available to PRs from forks.
     # However, they ARE exposed to PRs from a branch within the main repo. This
     # check catches that corner case, and prevents an inadvertent upload.
     if is_pr():
-        print("Refusing to upload a pull request")
+        click.echo("Refusing to upload a pull request")
         return
+
     if "AWS_ACCESS_KEY_ID" in os.environ:
-        subprocess.check_call(
-            [
-                "aws", "s3", "cp",
-                "--acl", "public-read",
-                DIST_DIR + "/",
-                "s3://snapshots.mitmproxy.org/%s/" % UPLOAD_DIR,
-                "--recursive",
-            ]
-        )
-
-
-@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):
-    f = cryptography.fernet.Fernet(key.encode())
-    outfile.write(f.decrypt(infile.read()))
+        subprocess.check_call([
+            "aws", "s3", "cp",
+            "--acl", "public-read",
+            DIST_DIR + "/",
+            "s3://snapshots.mitmproxy.org/%s/" % UPLOAD_DIR,
+            "--recursive",
+        ])
+
+    upload_pypi = (
+        TAG and
+        "WHEEL" in os.environ and
+        "TWINE_USERNAME" in os.environ and
+        "TWINE_PASSWORD" in os.environ
+    )
+    if upload_pypi:
+        filename = "mitmproxy-{version}-py3-none-any.whl".format(version=VERSION)
+        click.echo("Uploading {} to PyPi...".format(filename))
+        subprocess.check_call([
+            "twine",
+            "upload",
+            join(DIST_DIR, filename)
+        ])
 
 
 if __name__ == "__main__":
diff --git a/release/rtool.py b/release/rtool.py
deleted file mode 100755
--- a/release/rtool.py
+++ /dev/null
@@ -1,114 +0,0 @@
-#!/usr/bin/env python3
-
-import contextlib
-import os
-import sys
-import platform
-import runpy
-import shlex
-import subprocess
-from os.path import join, abspath, dirname
-
-import cryptography.fernet
-import click
-
-
-ROOT_DIR = abspath(join(dirname(__file__), ".."))
-RELEASE_DIR = join(ROOT_DIR, "release")
-DIST_DIR = join(RELEASE_DIR, "dist")
-VERSION_FILE = join(ROOT_DIR, "mitmproxy", "version.py")
-
-
-def git(args: str) -> str:
-    with chdir(ROOT_DIR):
-        return subprocess.check_output(["git"] + shlex.split(args)).decode()
-
-
-def get_version(dev: bool = False, build: bool = False) -> str:
-    x = runpy.run_path(VERSION_FILE)
-    return x["get_version"](dev, build, True)
-
-
-def wheel_name() -> str:
-    return "mitmproxy-{version}-py3-none-any.whl".format(
-        version=get_version(True),
-    )
-
-
-@contextlib.contextmanager
-def chdir(path: str):
-    old_dir = os.getcwd()
-    os.chdir(path)
-    yield
-    os.chdir(old_dir)
-
-
-@click.group(chain=True)
-def cli():
-    """
-    mitmproxy build tool
-    """
-    pass
-
-
-@cli.command("contributors")
-def contributors():
-    """
-    Update CONTRIBUTORS.md
-    """
-    with chdir(ROOT_DIR):
-        print("Updating CONTRIBUTORS...")
-        contributors_data = git("shortlog -n -s")
-        with open("CONTRIBUTORS", "wb") as f:
-            f.write(contributors_data.encode())
-
-
-@cli.command("upload-release")
-@click.option('--username', prompt=True)
-@click.password_option(confirmation_prompt=False)
-@click.option('--repository', default="pypi")
-def upload_release(username, password, repository):
-    """
-    Upload wheels to PyPI
-    """
-    filename = wheel_name()
-    print("Uploading {} to {}...".format(filename, repository))
-    subprocess.check_call([
-        "twine",
-        "upload",
-        "-u", username,
-        "-p", password,
-        "-r", repository,
-        join(DIST_DIR, filename)
-    ])
-
-
-@cli.command("homebrew-pr")
-def homebrew_pr():
-    """
-    Create a new Homebrew PR
-    """
-    if platform.system() != "Darwin":
-        print("You need to run this on macOS to create a new Homebrew PR. Sorry.")
-        sys.exit(1)
-
-    print("Creating a new PR with Homebrew...")
-    subprocess.check_call([
-        "brew",
-        "bump-formula-pr",
-        "--url", "https://github.com/mitmproxy/mitmproxy/archive/v{}".format(get_version()),
-        "mitmproxy",
-    ])
-
-
-@cli.command("encrypt")
-@click.argument('infile', type=click.File('rb'))
-@click.argument('outfile', type=click.File('wb'))
-@click.argument('key', envvar='RTOOL_KEY')
-def encrypt(infile, outfile, key):
-    f = cryptography.fernet.Fernet(key.encode())
-    outfile.write(f.encrypt(infile.read()))
-
-
-if __name__ == "__main__":
-    cli()


Test patch: