mirror of
https://github.com/certbot/certbot.git
synced 2025-08-06 16:42:41 +03:00
Break lockstep between our packages (#5655)
Fixes #5490. There's a lot of possibilities discussed in #5490, but I'll try and explain what I actually did here as succinctly as I can. Unfortunately, there's a fair bit to explain. My goal was to break lockstep and give us tests to ensure the minimum specified versions are correct without taking the time now to refactor our whole test setup. To handle specifying each package's minimum acme/certbot version, I added a requirements file to each package. This won't actually be included in the shipped package (because it's not in the MANIFEST). After creating these files and modifying tools/pip_install.sh to use them, I created a separate tox env for most packages (I kept the DNS plugins together for convenience). The reason this is necessary is because we currently use a single environment for each plugin, but if we used this approach for these tests we'd hit issues due to different installed plugins requiring different versions of acme/certbot. There's a lot more discussion about this in #5490 if you're interested in this piece. I unfortunately wasted a lot of time trying to remove the boilerplate this approach causes in tox.ini, but to do this I think we need negations described at complex factor conditions which hasn't made it into a tox release yet. The biggest missing piece here is how to make sure the oldest versions that are currently pinned to master get updated. Currently, they'll stay pinned that way without manual intervention and won't be properly testing the oldest version. I think we should solve this during the larger test/repo refactoring after the release because the tests are using the correct values now and I don't see a simple way around the problem. Once this lands, I'm planning on updating the test-everything tests to do integration tests with the "oldest" versions here. * break lockstep between packages * Use per package requirements files * add local oldest requirements files * update tox.ini * work with dev0 versions * Install requirements in separate step. * don't error when we don't have requirements * install latest packages in editable mode * Update .travis.yml * Add reminder comments * move dev to requirements * request acme[dev] * Update pip_install documentation
This commit is contained in:
@@ -30,7 +30,7 @@ matrix:
|
|||||||
- python: "2.7"
|
- python: "2.7"
|
||||||
env: TOXENV=lint
|
env: TOXENV=lint
|
||||||
- python: "2.7"
|
- python: "2.7"
|
||||||
env: TOXENV=py27-oldest
|
env: TOXENV='py27-{acme,apache,certbot,dns,nginx}-oldest'
|
||||||
sudo: required
|
sudo: required
|
||||||
services: docker
|
services: docker
|
||||||
- python: "3.4"
|
- python: "3.4"
|
||||||
|
2
certbot-apache/local-oldest-requirements.txt
Normal file
2
certbot-apache/local-oldest-requirements.txt
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
acme[dev]==0.21.1
|
||||||
|
certbot[dev]==0.21.1
|
@@ -6,10 +6,11 @@ from setuptools import find_packages
|
|||||||
|
|
||||||
version = '0.22.0.dev0'
|
version = '0.22.0.dev0'
|
||||||
|
|
||||||
# Please update tox.ini when modifying dependency version requirements
|
# Remember to update local-oldest-requirements.txt when changing the minimum
|
||||||
|
# acme/certbot version.
|
||||||
install_requires = [
|
install_requires = [
|
||||||
'acme=={0}'.format(version),
|
'acme>=0.21.1',
|
||||||
'certbot=={0}'.format(version),
|
'certbot>=0.21.1',
|
||||||
'mock',
|
'mock',
|
||||||
'python-augeas',
|
'python-augeas',
|
||||||
'setuptools',
|
'setuptools',
|
||||||
|
2
certbot-dns-cloudflare/local-oldest-requirements.txt
Normal file
2
certbot-dns-cloudflare/local-oldest-requirements.txt
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
acme[dev]==0.21.1
|
||||||
|
certbot[dev]==0.21.1
|
@@ -6,10 +6,11 @@ from setuptools import find_packages
|
|||||||
|
|
||||||
version = '0.22.0.dev0'
|
version = '0.22.0.dev0'
|
||||||
|
|
||||||
# Please update tox.ini when modifying dependency version requirements
|
# Remember to update local-oldest-requirements.txt when changing the minimum
|
||||||
|
# acme/certbot version.
|
||||||
install_requires = [
|
install_requires = [
|
||||||
'acme=={0}'.format(version),
|
'acme>=0.21.1',
|
||||||
'certbot=={0}'.format(version),
|
'certbot>=0.21.1',
|
||||||
'cloudflare>=1.5.1',
|
'cloudflare>=1.5.1',
|
||||||
'mock',
|
'mock',
|
||||||
'setuptools',
|
'setuptools',
|
||||||
|
2
certbot-dns-cloudxns/local-oldest-requirements.txt
Normal file
2
certbot-dns-cloudxns/local-oldest-requirements.txt
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
acme[dev]==0.21.1
|
||||||
|
certbot[dev]==0.21.1
|
@@ -6,10 +6,11 @@ from setuptools import find_packages
|
|||||||
|
|
||||||
version = '0.22.0.dev0'
|
version = '0.22.0.dev0'
|
||||||
|
|
||||||
# Please update tox.ini when modifying dependency version requirements
|
# Remember to update local-oldest-requirements.txt when changing the minimum
|
||||||
|
# acme/certbot version.
|
||||||
install_requires = [
|
install_requires = [
|
||||||
'acme=={0}'.format(version),
|
'acme>=0.21.1',
|
||||||
'certbot=={0}'.format(version),
|
'certbot>=0.21.1',
|
||||||
'dns-lexicon',
|
'dns-lexicon',
|
||||||
'mock',
|
'mock',
|
||||||
'setuptools',
|
'setuptools',
|
||||||
|
2
certbot-dns-digitalocean/local-oldest-requirements.txt
Normal file
2
certbot-dns-digitalocean/local-oldest-requirements.txt
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
acme[dev]==0.21.1
|
||||||
|
certbot[dev]==0.21.1
|
@@ -6,10 +6,11 @@ from setuptools import find_packages
|
|||||||
|
|
||||||
version = '0.22.0.dev0'
|
version = '0.22.0.dev0'
|
||||||
|
|
||||||
# Please update tox.ini when modifying dependency version requirements
|
# Remember to update local-oldest-requirements.txt when changing the minimum
|
||||||
|
# acme/certbot version.
|
||||||
install_requires = [
|
install_requires = [
|
||||||
'acme=={0}'.format(version),
|
'acme>=0.21.1',
|
||||||
'certbot=={0}'.format(version),
|
'certbot>=0.21.1',
|
||||||
'mock',
|
'mock',
|
||||||
'python-digitalocean>=1.11',
|
'python-digitalocean>=1.11',
|
||||||
'setuptools',
|
'setuptools',
|
||||||
|
2
certbot-dns-dnsimple/local-oldest-requirements.txt
Normal file
2
certbot-dns-dnsimple/local-oldest-requirements.txt
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
acme[dev]==0.21.1
|
||||||
|
certbot[dev]==0.21.1
|
@@ -6,10 +6,11 @@ from setuptools import find_packages
|
|||||||
|
|
||||||
version = '0.22.0.dev0'
|
version = '0.22.0.dev0'
|
||||||
|
|
||||||
# Please update tox.ini when modifying dependency version requirements
|
# Remember to update local-oldest-requirements.txt when changing the minimum
|
||||||
|
# acme/certbot version.
|
||||||
install_requires = [
|
install_requires = [
|
||||||
'acme=={0}'.format(version),
|
'acme>=0.21.1',
|
||||||
'certbot=={0}'.format(version),
|
'certbot>=0.21.1',
|
||||||
'dns-lexicon',
|
'dns-lexicon',
|
||||||
'mock',
|
'mock',
|
||||||
'setuptools',
|
'setuptools',
|
||||||
|
2
certbot-dns-dnsmadeeasy/local-oldest-requirements.txt
Normal file
2
certbot-dns-dnsmadeeasy/local-oldest-requirements.txt
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
acme[dev]==0.21.1
|
||||||
|
certbot[dev]==0.21.1
|
@@ -6,10 +6,11 @@ from setuptools import find_packages
|
|||||||
|
|
||||||
version = '0.22.0.dev0'
|
version = '0.22.0.dev0'
|
||||||
|
|
||||||
# Please update tox.ini when modifying dependency version requirements
|
# Remember to update local-oldest-requirements.txt when changing the minimum
|
||||||
|
# acme/certbot version.
|
||||||
install_requires = [
|
install_requires = [
|
||||||
'acme=={0}'.format(version),
|
'acme>=0.21.1',
|
||||||
'certbot=={0}'.format(version),
|
'certbot>=0.21.1',
|
||||||
'dns-lexicon',
|
'dns-lexicon',
|
||||||
'mock',
|
'mock',
|
||||||
'setuptools',
|
'setuptools',
|
||||||
|
2
certbot-dns-google/local-oldest-requirements.txt
Normal file
2
certbot-dns-google/local-oldest-requirements.txt
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
acme[dev]==0.21.1
|
||||||
|
certbot[dev]==0.21.1
|
@@ -6,10 +6,11 @@ from setuptools import find_packages
|
|||||||
|
|
||||||
version = '0.22.0.dev0'
|
version = '0.22.0.dev0'
|
||||||
|
|
||||||
# Please update tox.ini when modifying dependency version requirements
|
# Remember to update local-oldest-requirements.txt when changing the minimum
|
||||||
|
# acme/certbot version.
|
||||||
install_requires = [
|
install_requires = [
|
||||||
'acme=={0}'.format(version),
|
'acme>=0.21.1',
|
||||||
'certbot=={0}'.format(version),
|
'certbot>=0.21.1',
|
||||||
# 1.5 is the first version that supports oauth2client>=2.0
|
# 1.5 is the first version that supports oauth2client>=2.0
|
||||||
'google-api-python-client>=1.5',
|
'google-api-python-client>=1.5',
|
||||||
'mock',
|
'mock',
|
||||||
|
2
certbot-dns-luadns/local-oldest-requirements.txt
Normal file
2
certbot-dns-luadns/local-oldest-requirements.txt
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
acme[dev]==0.21.1
|
||||||
|
certbot[dev]==0.21.1
|
@@ -6,10 +6,11 @@ from setuptools import find_packages
|
|||||||
|
|
||||||
version = '0.22.0.dev0'
|
version = '0.22.0.dev0'
|
||||||
|
|
||||||
# Please update tox.ini when modifying dependency version requirements
|
# Remember to update local-oldest-requirements.txt when changing the minimum
|
||||||
|
# acme/certbot version.
|
||||||
install_requires = [
|
install_requires = [
|
||||||
'acme=={0}'.format(version),
|
'acme>=0.21.1',
|
||||||
'certbot=={0}'.format(version),
|
'certbot>=0.21.1',
|
||||||
'dns-lexicon',
|
'dns-lexicon',
|
||||||
'mock',
|
'mock',
|
||||||
'setuptools',
|
'setuptools',
|
||||||
|
2
certbot-dns-nsone/local-oldest-requirements.txt
Normal file
2
certbot-dns-nsone/local-oldest-requirements.txt
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
acme[dev]==0.21.1
|
||||||
|
certbot[dev]==0.21.1
|
@@ -6,10 +6,11 @@ from setuptools import find_packages
|
|||||||
|
|
||||||
version = '0.22.0.dev0'
|
version = '0.22.0.dev0'
|
||||||
|
|
||||||
# Please update tox.ini when modifying dependency version requirements
|
# Remember to update local-oldest-requirements.txt when changing the minimum
|
||||||
|
# acme/certbot version.
|
||||||
install_requires = [
|
install_requires = [
|
||||||
'acme=={0}'.format(version),
|
'acme>=0.21.1',
|
||||||
'certbot=={0}'.format(version),
|
'certbot>=0.21.1',
|
||||||
'dns-lexicon',
|
'dns-lexicon',
|
||||||
'mock',
|
'mock',
|
||||||
'setuptools',
|
'setuptools',
|
||||||
|
2
certbot-dns-rfc2136/local-oldest-requirements.txt
Normal file
2
certbot-dns-rfc2136/local-oldest-requirements.txt
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
acme[dev]==0.21.1
|
||||||
|
certbot[dev]==0.21.1
|
@@ -6,10 +6,11 @@ from setuptools import find_packages
|
|||||||
|
|
||||||
version = '0.22.0.dev0'
|
version = '0.22.0.dev0'
|
||||||
|
|
||||||
# Please update tox.ini when modifying dependency version requirements
|
# Remember to update local-oldest-requirements.txt when changing the minimum
|
||||||
|
# acme/certbot version.
|
||||||
install_requires = [
|
install_requires = [
|
||||||
'acme=={0}'.format(version),
|
'acme>=0.21.1',
|
||||||
'certbot=={0}'.format(version),
|
'certbot>=0.21.1',
|
||||||
'dnspython',
|
'dnspython',
|
||||||
'mock',
|
'mock',
|
||||||
'setuptools',
|
'setuptools',
|
||||||
|
2
certbot-dns-route53/local-oldest-requirements.txt
Normal file
2
certbot-dns-route53/local-oldest-requirements.txt
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
acme[dev]==0.21.1
|
||||||
|
certbot[dev]==0.21.1
|
@@ -5,9 +5,11 @@ from setuptools import find_packages
|
|||||||
|
|
||||||
version = '0.22.0.dev0'
|
version = '0.22.0.dev0'
|
||||||
|
|
||||||
|
# Remember to update local-oldest-requirements.txt when changing the minimum
|
||||||
|
# acme/certbot version.
|
||||||
install_requires = [
|
install_requires = [
|
||||||
'acme=={0}'.format(version),
|
'acme>=0.21.1',
|
||||||
'certbot=={0}'.format(version),
|
'certbot>=0.21.1',
|
||||||
'boto3',
|
'boto3',
|
||||||
'mock',
|
'mock',
|
||||||
'setuptools',
|
'setuptools',
|
||||||
|
2
certbot-nginx/local-oldest-requirements.txt
Normal file
2
certbot-nginx/local-oldest-requirements.txt
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
-e acme[dev]
|
||||||
|
-e .[dev]
|
@@ -6,10 +6,14 @@ from setuptools import find_packages
|
|||||||
|
|
||||||
version = '0.22.0.dev0'
|
version = '0.22.0.dev0'
|
||||||
|
|
||||||
# Please update tox.ini when modifying dependency version requirements
|
# Remember to update local-oldest-requirements.txt when changing the minimum
|
||||||
|
# acme/certbot version.
|
||||||
install_requires = [
|
install_requires = [
|
||||||
'acme=={0}'.format(version),
|
# This plugin works with an older version of acme, but Certbot does not.
|
||||||
'certbot=={0}'.format(version),
|
# 0.22.0 is specified here to work around
|
||||||
|
# https://github.com/pypa/pip/issues/988.
|
||||||
|
'acme>0.21.1',
|
||||||
|
'certbot>0.21.1',
|
||||||
'mock',
|
'mock',
|
||||||
'PyOpenSSL',
|
'PyOpenSSL',
|
||||||
'pyparsing>=1.5.5', # Python3 support; perhaps unnecessary?
|
'pyparsing>=1.5.5', # Python3 support; perhaps unnecessary?
|
||||||
|
1
local-oldest-requirements.txt
Normal file
1
local-oldest-requirements.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
-e acme[dev]
|
4
setup.py
4
setup.py
@@ -34,7 +34,9 @@ version = meta['version']
|
|||||||
# specified here to avoid masking the more specific request requirements in
|
# specified here to avoid masking the more specific request requirements in
|
||||||
# acme. See https://github.com/pypa/pip/issues/988 for more info.
|
# acme. See https://github.com/pypa/pip/issues/988 for more info.
|
||||||
install_requires = [
|
install_requires = [
|
||||||
'acme=={0}'.format(version),
|
# Remember to update local-oldest-requirements.txt when changing the
|
||||||
|
# minimum acme version.
|
||||||
|
'acme>0.21.1',
|
||||||
# We technically need ConfigArgParse 0.10.0 for Python 2.6 support, but
|
# We technically need ConfigArgParse 0.10.0 for Python 2.6 support, but
|
||||||
# saying so here causes a runtime error against our temporary fork of 0.9.3
|
# saying so here causes a runtime error against our temporary fork of 0.9.3
|
||||||
# in which we added 2.6 support (see #2243), so we relax the requirement.
|
# in which we added 2.6 support (see #2243), so we relax the requirement.
|
||||||
|
@@ -1,18 +1,30 @@
|
|||||||
#!/bin/bash -e
|
#!/bin/bash -e
|
||||||
# pip installs packages using pinned package versions. If CERTBOT_OLDEST is set
|
# pip installs packages using pinned package versions. If CERTBOT_OLDEST is set
|
||||||
# to 1, a combination of tools/oldest_constraints.txt and
|
# to 1, a combination of tools/oldest_constraints.txt,
|
||||||
# tools/dev_constraints.txt is used, otherwise, a combination of certbot-auto's
|
# tools/dev_constraints.txt, and local-oldest-requirements.txt contained in the
|
||||||
# requirements file and tools/dev_constraints.txt is used. The other file
|
# top level of the package's directory is used, otherwise, a combination of
|
||||||
# always takes precedence over tools/dev_constraints.txt.
|
# certbot-auto's requirements file and tools/dev_constraints.txt is used. The
|
||||||
|
# other file always takes precedence over tools/dev_constraints.txt. If
|
||||||
|
# CERTBOT_OLDEST is set, this script must be run with `-e <package-name>` and
|
||||||
|
# no other arguments.
|
||||||
|
|
||||||
# get the root of the Certbot repo
|
# get the root of the Certbot repo
|
||||||
tools_dir=$(dirname $("$(dirname $0)/readlink.py" $0))
|
tools_dir=$(dirname $("$(dirname $0)/readlink.py" $0))
|
||||||
dev_constraints="$tools_dir/dev_constraints.txt"
|
all_constraints=$(mktemp)
|
||||||
merge_reqs="$tools_dir/merge_requirements.py"
|
|
||||||
test_constraints=$(mktemp)
|
test_constraints=$(mktemp)
|
||||||
trap "rm -f $test_constraints" EXIT
|
trap "rm -f $all_constraints $test_constraints" EXIT
|
||||||
|
|
||||||
if [ "$CERTBOT_OLDEST" = 1 ]; then
|
if [ "$CERTBOT_OLDEST" = 1 ]; then
|
||||||
|
if [ "$1" != "-e" -o "$#" -ne "2" ]; then
|
||||||
|
echo "When CERTBOT_OLDEST is set, this script must be run with a single -e <path> argument."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
pkg_dir=$(echo $2 | cut -f1 -d\[) # remove any extras such as [dev]
|
||||||
|
requirements="$pkg_dir/local-oldest-requirements.txt"
|
||||||
|
# packages like acme don't have any local oldest requirements
|
||||||
|
if [ ! -f "$requirements" ]; then
|
||||||
|
unset requirements
|
||||||
|
fi
|
||||||
cp "$tools_dir/oldest_constraints.txt" "$test_constraints"
|
cp "$tools_dir/oldest_constraints.txt" "$test_constraints"
|
||||||
else
|
else
|
||||||
repo_root=$(dirname "$tools_dir")
|
repo_root=$(dirname "$tools_dir")
|
||||||
@@ -20,7 +32,13 @@ else
|
|||||||
sed -n -e 's/^\([^[:space:]]*==[^[:space:]]*\).*$/\1/p' "$certbot_requirements" > "$test_constraints"
|
sed -n -e 's/^\([^[:space:]]*==[^[:space:]]*\).*$/\1/p' "$certbot_requirements" > "$test_constraints"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
"$tools_dir/merge_requirements.py" "$tools_dir/dev_constraints.txt" \
|
||||||
|
"$test_constraints" > "$all_constraints"
|
||||||
|
|
||||||
set -x
|
set -x
|
||||||
|
|
||||||
# install the requested packages using the pinned requirements as constraints
|
# install the requested packages using the pinned requirements as constraints
|
||||||
pip install -q --constraint <("$merge_reqs" "$dev_constraints" "$test_constraints") "$@"
|
if [ -n "$requirements" ]; then
|
||||||
|
pip install -q --constraint "$all_constraints" --requirement "$requirements"
|
||||||
|
fi
|
||||||
|
pip install -q --constraint "$all_constraints" "$@"
|
||||||
|
53
tox.ini
53
tox.ini
@@ -14,10 +14,7 @@ pip_install = {toxinidir}/tools/pip_install_editable.sh
|
|||||||
# before the script moves on to the next package. All dependencies are pinned
|
# before the script moves on to the next package. All dependencies are pinned
|
||||||
# to a specific version for increased stability for developers.
|
# to a specific version for increased stability for developers.
|
||||||
install_and_test = {toxinidir}/tools/install_and_test.sh
|
install_and_test = {toxinidir}/tools/install_and_test.sh
|
||||||
all_packages =
|
dns_packages =
|
||||||
acme[dev] \
|
|
||||||
.[dev] \
|
|
||||||
certbot-apache \
|
|
||||||
certbot-dns-cloudflare \
|
certbot-dns-cloudflare \
|
||||||
certbot-dns-cloudxns \
|
certbot-dns-cloudxns \
|
||||||
certbot-dns-digitalocean \
|
certbot-dns-digitalocean \
|
||||||
@@ -27,7 +24,12 @@ all_packages =
|
|||||||
certbot-dns-luadns \
|
certbot-dns-luadns \
|
||||||
certbot-dns-nsone \
|
certbot-dns-nsone \
|
||||||
certbot-dns-rfc2136 \
|
certbot-dns-rfc2136 \
|
||||||
certbot-dns-route53 \
|
certbot-dns-route53
|
||||||
|
all_packages =
|
||||||
|
acme[dev] \
|
||||||
|
.[dev] \
|
||||||
|
certbot-apache \
|
||||||
|
{[base]dns_packages} \
|
||||||
certbot-nginx \
|
certbot-nginx \
|
||||||
letshelp-certbot
|
letshelp-certbot
|
||||||
install_packages =
|
install_packages =
|
||||||
@@ -70,6 +72,47 @@ setenv =
|
|||||||
passenv =
|
passenv =
|
||||||
{[testenv]passenv}
|
{[testenv]passenv}
|
||||||
|
|
||||||
|
[testenv:py27-acme-oldest]
|
||||||
|
commands =
|
||||||
|
{[base]install_and_test} acme[dev]
|
||||||
|
setenv =
|
||||||
|
{[testenv:py27-oldest]setenv}
|
||||||
|
passenv =
|
||||||
|
{[testenv:py27-oldest]passenv}
|
||||||
|
|
||||||
|
[testenv:py27-apache-oldest]
|
||||||
|
commands =
|
||||||
|
{[base]install_and_test} certbot-apache
|
||||||
|
setenv =
|
||||||
|
{[testenv:py27-oldest]setenv}
|
||||||
|
passenv =
|
||||||
|
{[testenv:py27-oldest]passenv}
|
||||||
|
|
||||||
|
[testenv:py27-certbot-oldest]
|
||||||
|
commands =
|
||||||
|
{[base]install_and_test} .[dev]
|
||||||
|
setenv =
|
||||||
|
{[testenv:py27-oldest]setenv}
|
||||||
|
passenv =
|
||||||
|
{[testenv:py27-oldest]passenv}
|
||||||
|
|
||||||
|
[testenv:py27-dns-oldest]
|
||||||
|
commands =
|
||||||
|
{[base]install_and_test} {[base]dns_packages}
|
||||||
|
setenv =
|
||||||
|
{[testenv:py27-oldest]setenv}
|
||||||
|
passenv =
|
||||||
|
{[testenv:py27-oldest]passenv}
|
||||||
|
|
||||||
|
[testenv:py27-nginx-oldest]
|
||||||
|
commands =
|
||||||
|
{[base]install_and_test} certbot-nginx
|
||||||
|
python tests/lock_test.py
|
||||||
|
setenv =
|
||||||
|
{[testenv:py27-oldest]setenv}
|
||||||
|
passenv =
|
||||||
|
{[testenv:py27-oldest]passenv}
|
||||||
|
|
||||||
[testenv:py27_install]
|
[testenv:py27_install]
|
||||||
basepython = python2.7
|
basepython = python2.7
|
||||||
commands =
|
commands =
|
||||||
|
Reference in New Issue
Block a user