#!/usr/bin/env python """ Script responsible for deploying both snowplow-tracker-core and snowplow-tracker Need to be executed in Travis CI environment by tag (core/x.y.z OR x.y.z) Publish core locally, build tracker using locally publiched core and then publish altogether """ from contextlib import contextmanager import os import sys import subprocess # Initial setup if 'TRAVIS_TAG' in os.environ: TRAVIS_TAG = os.environ.get('TRAVIS_TAG') else: sys.exit("Environment variable TRAVIS_TAG is unavailable") if 'TRAVIS_BUILD_DIR' in os.environ: TRAVIS_BUILD_DIR = os.environ.get('TRAVIS_BUILD_DIR') else: sys.exit("Environment variable TRAVIS_BUILD_DIR is unavailable") if 'NPM_AUTH_TOKEN' in os.environ: NPM_AUTH_TOKEN = os.environ.get('NPM_AUTH_TOKEN') else: sys.exit("Environment variable NPM_AUTH_TOKEN is unavailable") if TRAVIS_TAG.startswith('core/'): PROJECT = 'core' VERSION = TRAVIS_TAG[5:] else: PROJECT = 'tracker' VERSION = TRAVIS_TAG if 'AWS_ACCESS_KEY' in os.environ: AWS_ACCESS_KEY = os.environ.get('AWS_ACCESS_KEY') else: sys.exit("Environment variable AWS_ACCESS_KEY is unavailable (required for tracker publishing)") if 'AWS_SECRET_KEY' in os.environ: AWS_SECRET_KEY = os.environ.get('AWS_SECRET_KEY') else: sys.exit("Environment variable AWS_SECRET_KEY is unavailable (required for tracker publishing)") if 'AWS_S3_BUCKET' in os.environ: AWS_S3_BUCKET = os.environ.get('AWS_S3_BUCKET') else: sys.exit("Environment variable AWS_S3_BUCKET is unavailable (required for tracker publishing)") if 'AWS_REGION' in os.environ: AWS_REGION = os.environ.get('AWS_REGION') else: sys.exit("Environment variable AWS_REGION is unavailable (required for tracker publishing)") if 'AWS_CF_DISTRIBUTION' in os.environ: AWS_CF_DISTRIBUTION = os.environ.get('AWS_CF_DISTRIBUTION') else: sys.exit("Environment variable AWS_CF_DISTRIBUTION is unavailable (required for tracker publishing)") # Helper functions def output_if_error(sbt_output): """Callback to print stderr and fail deploy if exit status not successful""" (stdout, stderr) = sbt_output.communicate() if sbt_output.returncode != 0: print("Process has been failed.\n" + stdout) sys.exit(stderr) def execute(command, callback=output_if_error): """Execute shell command with optional callback""" formatted_command = " ".join(command) if (type(command) == list) else command print("Executing [{0}]".format(formatted_command)) output = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE) if hasattr(callback, '__call__'): return callback(output) else: return output def check_version(): """Fail deploy if tag version doesn't match SBT version""" if PROJECT == 'core': get_version = """var fs=require('fs'); fs.readFile('./core/package.json', 'utf8', function(e,d) { console.log(JSON.parse(d)['version']) });""" elif PROJECT == 'tracker': get_version = """var fs=require('fs'); fs.readFile('./package.json', 'utf8', function(e,d) { console.log(JSON.parse(d)['version']) });""" else: sys.exit("Unknown project " + str(PROJECT)) node_output = execute(['node', '-e', get_version], None) print(node_output.stderr.read()) for line in node_output.stdout.read().split("\n"): print(line) if line: if line != VERSION: sys.exit("Version extracted from TRAVIS_TAG [{0}] doesn't conform declared in package.json [{1}]".format(VERSION, line)) else: return sys.exit("Cannot find version in core output:\n" + str(node_output)) @contextmanager def npm_credentials(): """Context manager allowing to use different credentials and delete them after use""" npmrc = os.path.expanduser("~/.npmrc") if os.path.isfile(npmrc): os.remove(npmrc) print("WARNING! ~/.npmrc already exists. It should be deleted after each use") print("Overwriting existing ~/.npmrc") else: print("Creating ~/.npmrc") with open(npmrc, 'a') as f: f.write("registry=https://registry.npmjs.org/\n//registry.npmjs.org/:_authToken=" + NPM_AUTH_TOKEN) yield print("Deleting ~/.npmrc") os.remove(npmrc) @contextmanager def aws_credentials(): """Context manager allowing to use different credentials and delete them after use""" awsjson = os.path.join(TRAVIS_BUILD_DIR, "aws.json") if os.path.isfile(awsjson): sys.exit("aws.json already exists. It should be deleted after each use") else: print("Creating aws.json") with open(awsjson, 'a') as f: f.write( '{"key":"%(key)s","secret":"%(secret)s","bucket":"%(bucket)s","region":"%(region)s", "distribution":"%(distribution)s"}' % \ {'key': AWS_ACCESS_KEY, 'secret': AWS_SECRET_KEY, 'bucket': AWS_S3_BUCKET, 'distribution': AWS_CF_DISTRIBUTION, 'region': AWS_REGION} ) yield print("Deleting aws.json") os.remove(awsjson) def publish_core(): os.chdir(os.path.join(TRAVIS_BUILD_DIR, "core")) with npm_credentials(): execute(['npm', 'publish']) def publish_tracker(): os.chdir(TRAVIS_BUILD_DIR) with aws_credentials(): execute(['grunt', 'publish']) def publish(): if PROJECT == 'core': publish_core() elif PROJECT == 'tracker': publish_tracker() else: sys.exit("Unknown project " + str(PROJECT)) if __name__ == "__main__": # Publish locally all dependencies check_version() publish()