Skip to content
Open
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
2 changes: 1 addition & 1 deletion .flake8
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@
# https://github.com/psf/black/blob/master/docs/the_black_code_style.md#line-length
[flake8]
# black wraps at 88
max-line-length = 90
max-line-length = 120
extend-ignore = E203
18 changes: 11 additions & 7 deletions examples/buildkite-trigger.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,34 +3,38 @@
# my-pipeline change-commit //depot/... "python %//depot/scripts/buildkite-trigger.py% <pipeline> %changelist% %user%"
import sys
import subprocess

try:
from urllib.request import urlopen, Request
except ImportError:
from urllib2 import urlopen, Request
import json

__BUILDKITE_TOKEN__ = "<your_token>"

__ORG_SLUG__ = "<your_org>"
pipeline_slug = sys.argv[1]
changelist = sys.argv[2]
user = sys.argv[3]

description = subprocess.check_output(["p4", "-Ztag", "-F", "%desc%", "describe", changelist])
description = subprocess.check_output(
["p4", "-Ztag", "-F", "%desc%", "describe", changelist]
)

headers = {
'Content-Type': 'application/json',
'Authorization': 'Bearer %s' % __BUILDKITE_TOKEN__
'Authorization': 'Bearer %s' % __BUILDKITE_TOKEN__,
}
payload = {
'commit': '@' + changelist,
'branch': 'master',
'message': description,
'author': {
'name': user
}
'author': {'name': user},
}
url = "https://api.buildkite.com/v2/organizations/%s/pipelines/%s/builds" % (__ORG_SLUG__, pipeline_slug)
url = "https://api.buildkite.com/v2/organizations/%s/pipelines/%s/builds" % (
__ORG_SLUG__,
pipeline_slug,
)

params = json.dumps(payload).encode('utf8')
req = Request(url, data=params, headers=headers)
Expand Down
18 changes: 13 additions & 5 deletions examples/cleanup-unused-workspaces.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,16 +27,24 @@

# Filter by basic prefix matching.
# May want to include filtering by user and other fields to avoid false positives.
bk_clients = [client for client in clients
if client.get('client', '').startswith('bk-p4-')]
bk_clients = [
client for client in clients if client.get('client', '').startswith('bk-p4-')
]

now = datetime.now()
n_days_ago = (now - timedelta(days=__days_unused__)).timestamp()
unused_clients = [client for client in bk_clients
if int(client.get('Access')) < n_days_ago]
unused_clients = [
client for client in bk_clients if int(client.get('Access')) < n_days_ago
]

pprint(unused_clients)
proceed = input("Will delete %d/%d Buildkite clients. Continue? (y/n) " % (len(unused_clients),len(bk_clients))).lower() == 'y'
proceed = (
input(
"Will delete %d/%d Buildkite clients. Continue? (y/n) "
% (len(unused_clients), len(bk_clients))
).lower()
== 'y'
)

if proceed:
for client in unused_clients:
Expand Down
50 changes: 35 additions & 15 deletions python/buildkite.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,24 +12,26 @@
__LOCAL_RUN__ = os.environ['BUILDKITE_AGENT_NAME'] == 'local'

__REVISION_METADATA__ = 'buildkite-perforce-revision'
__REVISION_METADATA_DEPRECATED__ = 'buildkite:perforce:revision' # old metadata key, incompatible with `bk local run`
__REVISION_METADATA_DEPRECATED__ = (
'buildkite:perforce:revision' # old metadata key, incompatible with `bk local run`
)


def get_env():
"""Get env vars passed in via plugin config"""
env = {
'P4PORT': os.environ.get('P4PORT') or os.environ.get('BUILDKITE_REPO')
}
env = {'P4PORT': os.environ.get('P4PORT') or os.environ.get('BUILDKITE_REPO')}
for p4var in ['P4PORT', 'P4USER', 'P4TICKETS', 'P4TRUST']:
plugin_value = os.environ.get('BUILDKITE_PLUGIN_PERFORCE_%s' % p4var)
if plugin_value:
env[p4var] = plugin_value
return env


def list_from_env_array(var):
"""Read list of values from either VAR or VAR_0, VAR_1 etc"""
result = os.environ.get(var, [])
if result:
return [result] # convert single value to list
return [result] # convert single value to list

i = 0
while True:
Expand All @@ -41,6 +43,7 @@ def list_from_env_array(var):

return result


def get_config():
"""Get configuration which will be passed directly to perforce.P4Repo as kwargs"""
conf = {}
Expand All @@ -54,7 +57,9 @@ def get_config():

if 'BUILDKITE_PLUGIN_PERFORCE_ROOT' in os.environ and not __LOCAL_RUN__:
raise Exception("Custom P4 root is for use in unit tests only")
conf['root'] = os.environ.get('BUILDKITE_PLUGIN_PERFORCE_ROOT') or os.environ.get('BUILDKITE_BUILD_CHECKOUT_PATH')
conf['root'] = os.environ.get('BUILDKITE_PLUGIN_PERFORCE_ROOT') or os.environ.get(
'BUILDKITE_BUILD_CHECKOUT_PATH'
)

# Coerce view into pairs of [depot client] paths
view_parts = conf['view'].split(' ')
Expand All @@ -63,27 +68,35 @@ def get_config():
conf['view'] = ['%s %s' % (v, next(view_iter)) for v in view_iter]
return conf


def get_metadata(key):
"""If it exists, retrieve metadata from buildkite for a given key"""
if not __ACCESS_TOKEN__:
# Cannot get metadata outside of buildkite context
return None

if subprocess.call(['buildkite-agent', 'meta-data', 'exists', key]) == 0:
return subprocess.check_output(['buildkite-agent', 'meta-data', 'get', key]).decode(sys.stdout.encoding)
return subprocess.check_output(
['buildkite-agent', 'meta-data', 'get', key]
).decode(sys.stdout.encoding)


def set_metadata(key, value, overwrite=False):
""" Set metadata in buildkite for a given key. Optionally overwrite existing data.
Returns true if data was written
"""Set metadata in buildkite for a given key. Optionally overwrite existing data.
Returns true if data was written
"""
if not __ACCESS_TOKEN__ or __LOCAL_RUN__:
# Cannot set metadata outside of buildkite context, including `bk local run`
return False

if overwrite or subprocess.call(['buildkite-agent', 'meta-data', 'exists', key]) == 100:
subprocess.call(['buildkite-agent', 'meta-data', 'set', key, value])
if (
overwrite
or subprocess.call(['buildkite-agent', 'meta-data', 'exists', key]) == 100
):
subprocess.call(['buildkite-agent', 'meta-data', 'set', key, value])
return True


def get_users_changelist():
"""Get the shelved changelist supplied by the user, if applicable"""
# Overrides the CL to unshelve via plugin config
Expand All @@ -96,11 +109,14 @@ def get_users_changelist():
if branch.isdigit():
return branch


def get_build_revision():
"""Get a p4 revision for the build from buildkite context"""
revision = get_metadata(__REVISION_METADATA__) or \
get_metadata(__REVISION_METADATA_DEPRECATED__) or \
os.environ['BUILDKITE_COMMIT'] # HEAD, user-defined revision or git-sha
revision = (
get_metadata(__REVISION_METADATA__)
or get_metadata(__REVISION_METADATA_DEPRECATED__)
or os.environ['BUILDKITE_COMMIT']
) # HEAD, user-defined revision or git-sha

# Convert bare changelist number to revision specifier
# Note: Theoretically, its possible for all 40 characters of a git sha to be digits.
Expand All @@ -113,12 +129,16 @@ def get_build_revision():
# Unable to establish a concrete revision for the build
return None


def set_build_revision(revision):
"""Set the p4 revision for following jobs in this build"""
set_metadata(__REVISION_METADATA__, revision)
set_metadata(__REVISION_METADATA_DEPRECATED__, revision)


def set_build_info(revision, description):
"""Set the description and commit number in the UI for this build by mimicking a git repo"""
revision = revision.lstrip('@#') # revision must look like a git sha for buildkite to accept it
revision = revision.lstrip(
'@#'
) # revision must look like a git sha for buildkite to accept it
set_metadata('buildkite:git:commit', 'commit %s\n\n\t%s' % (revision, description))
14 changes: 11 additions & 3 deletions python/checkout.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,15 @@
import subprocess

from perforce import P4Repo
from buildkite import (get_env, get_config, get_build_revision, set_build_revision,
get_users_changelist, set_build_info)
from buildkite import (
get_env,
get_config,
get_build_revision,
set_build_revision,
get_users_changelist,
set_build_info,
)


def main():
"""Main"""
Expand All @@ -29,7 +36,8 @@ def main():

description = repo.description(
# Prefer users change description over latest submitted change
user_changelist or repo.head_at_revision(revision)
user_changelist
or repo.head_at_revision(revision)
)
set_build_info(revision, description)

Expand Down
Loading