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

Fix #5499: Include in pip's User-Agent whether it looks like pip is in CI #6273

Merged
merged 2 commits into from
Feb 24, 2019
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
2 changes: 2 additions & 0 deletions news/5499.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Include in pip's User-Agent string whether it looks like pip is running
under CI.
31 changes: 31 additions & 0 deletions src/pip/_internal/download.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,31 @@
logger = logging.getLogger(__name__)


# These are environment variables present when running under various
# CI systems. For each variable, some CI systems that use the variable
# are indicated. The collection was chosen so that for each of a number
# of popular systems, at least one of the environment variables is used.
# This list is used to provide some indication of and lower bound for
# CI traffic to PyPI. Thus, it is okay if the list is not comprehensive.
# For more background, see: https://github.com/pypa/pip/issues/5499
CI_ENVIRONMENT_VARIABLES = [
pradyunsg marked this conversation as resolved.
Show resolved Hide resolved
# Azure Pipelines
'BUILD_BUILDID',
# Jenkins
'BUILD_ID',
# AppVeyor, CircleCI, Codeship, Gitlab CI, Shippable, Travis CI
'CI',
]


def looks_like_ci():
# type: () -> bool
"""
Return whether it looks like pip is running under CI.
"""
return any(name in os.environ for name in CI_ENVIRONMENT_VARIABLES)


def user_agent():
"""
Return a string representing the user agent.
Expand Down Expand Up @@ -135,6 +160,12 @@ def user_agent():
if setuptools_version is not None:
data["setuptools_version"] = setuptools_version

# Use None rather than False so as not to give the impression that
# pip knows it is not being run under CI. Rather, it is a null or
# inconclusive result. Also, we include some value rather than no
# value to make it easier to know that the check has been run.
data["ci"] = True if looks_like_ci() else None

return "{data[installer][name]}/{data[installer][version]} {json}".format(
data=data,
json=json.dumps(data, separators=(",", ":"), sort_keys=True),
Expand Down
22 changes: 21 additions & 1 deletion tests/unit/test_download.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,27 @@ def _fake_session_get(*args, **kwargs):


def test_user_agent():
PipSession().headers["User-Agent"].startswith("pip/%s" % pip.__version__)
user_agent = PipSession().headers["User-Agent"]

assert user_agent.startswith("pip/%s" % pip.__version__)


@pytest.mark.parametrize('name, expected_like_ci', [
('BUILD', False),
pradyunsg marked this conversation as resolved.
Show resolved Hide resolved
('BUILD_BUILDID', True),
('BUILD_ID', True),
('CI', True),
])
def test_user_agent__ci(monkeypatch, name, expected_like_ci):
# Clear existing names since we can be running under an actual CI.
for ci_name in ('BUILD_BUILDID', 'BUILD_ID', 'CI'):
pradyunsg marked this conversation as resolved.
Show resolved Hide resolved
monkeypatch.delenv(ci_name, raising=False)

monkeypatch.setenv(name, 'true')
user_agent = PipSession().headers["User-Agent"]

assert ('"ci":true' in user_agent) == expected_like_ci
assert ('"ci":null' in user_agent) == (not expected_like_ci)


class FakeStream(object):
Expand Down