From 09ab0bfe937eb8788befb7cd1ecfd491a2e1217f Mon Sep 17 00:00:00 2001 From: Louis Garman <75728+leg100@users.noreply.github.com> Date: Fri, 4 Oct 2019 15:05:06 +0100 Subject: [PATCH] Ability to template path of published badge --- README.md | 30 ++++++++++++++++++++++++++++-- main.py | 12 +++++++++--- tests/test_func.py | 33 +++++++++++++++++++++++++-------- 3 files changed, 62 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 75148d4..9bf504d 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,10 @@ A Cloud Function that generates Cloud Build badges. +## Summary + +The function subscribes to events published by Cloud Build. The events contain information on the status of the progress and completion of a build. The function copies a badge reflecting that status to a known URL, which can be hard-coded in a repository `README` (as seen above). + ## Installation ### Upload Badges @@ -43,9 +47,19 @@ Grant permissions to read and write to the bucket: gsutil iam ch serviceAccount:cloud-build-badge@${GOOGLE_CLOUD_PROJECT}.iam.gserviceaccount.com:legacyBucketReader,legacyObjectReader,legacyBucketWriter gs://${GOOGLE_CLOUD_PROJECT}-badges/ ``` +# Customise Path + +You can customise the path in the bucket at which the badge gets published, using a template string. The default is: + +`builds/${repo}/branches/${branch}.svg` + +Where `${repo}` and `${branch}` refer to the name of the repository and branch that triggered the build. Only these two variables are available. + +Set the environment variable `TEMPLATE_PATH` accordingly when deploying the function in the next step. + ## Deploy -Deploy the function: +Deploy the function. Note you can customise the path at which the badge gets produced, using a template string, ```bash gcloud functions deploy cloud-build-badge \ @@ -54,9 +68,21 @@ gcloud functions deploy cloud-build-badge \ --entry-point build_badge \ --service-account cloud-build-badge@${GOOGLE_CLOUD_PROJECT}.iam.gserviceaccount.com \ --trigger-topic=cloud-builds \ - --set-env-vars BADGES_BUCKET=${GOOGLE_CLOUD_PROJECT}-badges + --set-env-vars BADGES_BUCKET=${GOOGLE_CLOUD_PROJECT}-badges,TEMPLATE_PATH='builds/${repo}/branches/${branch}.svg' ``` +## Use + +Embed the badge in your README, replacing `${repo}` and `${branch}` with the name of your repository and the branch you want to show the latest status for: + +``` +![Cloud Build](https://storage.googleapis.com/${GOOGLE_CLOUD_PROJECT}-badges/builds/${repo}/branches/${branch}) +``` + +If you've customised the path using `TEMPLATE_PATH`, ensure it is reflected in the URL above. + +Now trigger a Cloud Build build (e.g. by pushing a commit, or directly via the Google Cloud console). You should see the badge update to reflect the build status. + ## Test There is a `make` task for running integration tests against the deployed function: diff --git a/main.py b/main.py index 78a063b..e1daa80 100644 --- a/main.py +++ b/main.py @@ -4,6 +4,7 @@ import json import os import re +from string import Template def copy_badge(bucket_name, obj, new_obj): @@ -32,8 +33,11 @@ def build_badge(event, context): decoded = base64.b64decode(event['data']).decode('utf-8') data = json.loads(decoded) + bucket = os.environ['BADGES_BUCKET'] + try: repo = data['source']['repoSource']['repoName'] + branch = data['source']['repoSource']['branchName'] if repo.startswith('github_') or repo.startswith('bitbucket_'): # mirrored repo format: (github|bitbucket)__ @@ -41,11 +45,13 @@ def build_badge(event, context): except KeyError: # github app repo = data['substitutions']['REPO_NAME'] + branch = data['substitutions']['BRANCH_NAME'] finally: - src = 'badges/{}.svg'.format(data['status'].lower()) - dest = 'builds/{}.svg'.format(repo) + tmpl = os.environ.get('TEMPLATE_PATH', + 'builds/${repo}/branches/${branch}.svg') - bucket = os.environ['BADGES_BUCKET'] + src = 'badges/{}.svg'.format(data['status'].lower()) + dest = Template(tmpl).substitute(repo=repo, branch=branch) copy_badge(bucket, src, dest) diff --git a/tests/test_func.py b/tests/test_func.py index f8d2cc8..f25f2e0 100644 --- a/tests/test_func.py +++ b/tests/test_func.py @@ -50,43 +50,60 @@ def github_app(): return { "status": "SUCCESS", "substitutions": { - "REPO_NAME": "webapp" + "REPO_NAME": "webapp", + "BRANCH_NAME": "feature/fish" } } @pytest.fixture -def env_vars(monkeypatch): +def badges_bucket(monkeypatch): monkeypatch.setenv('BADGES_BUCKET', 'my-badges-bucket') +@pytest.fixture +def custom_template_path(monkeypatch): + monkeypatch.setenv('TEMPLATE_PATH', 'builds/${repo}-${branch}.svg') + + @pytest.fixture def patches(mocker): mocker.patch('main.copy_badge') -def test_mirrored_repo(mirrored_repo, env_vars, patches): +def test_mirrored_repo(mirrored_repo, badges_bucket, patches): main.build_badge(mirrored_repo, None) main.copy_badge.assert_called_once_with( 'my-badges-bucket', 'badges/success.svg', - 'builds/webapp.svg') + 'builds/webapp/branches/feature/fish.svg') -def test_github_app(github_app, env_vars, patches): +def test_github_app(github_app, badges_bucket, patches): main.build_badge(github_app, None) main.copy_badge.assert_called_once_with( 'my-badges-bucket', 'badges/success.svg', - 'builds/webapp.svg') + 'builds/webapp/branches/feature/fish.svg') + + +def test_cloud_source_repo(cloud_source_repo, badges_bucket, patches): + main.build_badge(cloud_source_repo, None) + + main.copy_badge.assert_called_once_with( + 'my-badges-bucket', + 'badges/working.svg', + 'builds/webapp/branches/master.svg') + +def test_custom_template_path(cloud_source_repo, badges_bucket, + custom_template_path, patches): -def test_cloud_source_repo(cloud_source_repo, env_vars, patches): main.build_badge(cloud_source_repo, None) main.copy_badge.assert_called_once_with( 'my-badges-bucket', 'badges/working.svg', - 'builds/webapp.svg') + 'builds/webapp-master.svg')