def get_transformed_webhook_payload(gh_payload, default_branch=None, lookup_user=None): """ Returns the GitHub webhook JSON payload transformed into our own payload format. If the gh_payload is not valid, returns None. """ try: validate(gh_payload, GITHUB_WEBHOOK_PAYLOAD_SCHEMA) except Exception as exc: raise InvalidPayloadException(exc.message) payload = JSONPathDict(gh_payload) if payload["head_commit"] is None: raise SkipRequestException config = SafeDictSetter() config["commit"] = payload["head_commit.id"] config["ref"] = payload["ref"] config["default_branch"] = payload[ "repository.default_branch"] or default_branch config["git_url"] = payload["repository.ssh_url"] config["commit_info.url"] = payload["head_commit.url"] config["commit_info.message"] = payload["head_commit.message"] config["commit_info.date"] = payload["head_commit.timestamp"] config["commit_info.author.username"] = payload[ "head_commit.author.username"] config["commit_info.author.url"] = payload.get( "head_commit.author.html_url") config["commit_info.author.avatar_url"] = payload.get( "head_commit.author.avatar_url") config["commit_info.committer.username"] = payload.get( "head_commit.committer.username") config["commit_info.committer.url"] = payload.get( "head_commit.committer.html_url") config["commit_info.committer.avatar_url"] = payload.get( "head_commit.committer.avatar_url") # Note: GitHub doesn't always return the extra information for users, so we do the lookup # manually if possible. if (lookup_user and not payload.get("head_commit.author.html_url") and payload.get("head_commit.author.username")): author_info = lookup_user(payload["head_commit.author.username"]) if author_info: config["commit_info.author.url"] = author_info["html_url"] config["commit_info.author.avatar_url"] = author_info["avatar_url"] if (lookup_user and payload.get("head_commit.committer.username") and not payload.get("head_commit.committer.html_url")): committer_info = lookup_user(payload["head_commit.committer.username"]) if committer_info: config["commit_info.committer.url"] = committer_info["html_url"] config["commit_info.committer.avatar_url"] = committer_info[ "avatar_url"] return config.dict_value()
def build_manifest(tag, manifest, synthetic_image_id): """ Builds an ACI manifest of an existing repository image. """ docker_layer_data = JSONPathDict( json.loads(manifest.leaf_layer.raw_v1_metadata)) config = docker_layer_data["config"] or JSONPathDict({}) namespace = tag.repository.namespace_name repo_name = tag.repository.name source_url = "%s://%s/%s/%s:%s" % ( app.config["PREFERRED_URL_SCHEME"], app.config["SERVER_HOSTNAME"], namespace, repo_name, tag.name, ) # ACI requires that the execution command be absolutely referenced. Therefore, if we find # a relative command, we give it as an argument to /bin/sh to resolve and execute for us. entrypoint = config["Entrypoint"] or [] exec_path = entrypoint + (config["Cmd"] or []) if exec_path and not exec_path[0].startswith("/"): exec_path = ["/bin/sh", "-c", '""%s""' % " ".join(exec_path)] # TODO: ACI doesn't support : in the name, so remove any ports. hostname = app.config["SERVER_HOSTNAME"] hostname = hostname.split(":", 1)[0] # Calculate the environment variables. docker_env_vars = config.get("Env") or [] env_vars = [] for var in docker_env_vars: pieces = var.split("=") if len(pieces) != 2: continue env_vars.append(pieces) manifest = { "acKind": "ImageManifest", "acVersion": "0.6.1", "name": "%s/%s/%s" % (hostname.lower(), namespace.lower(), repo_name.lower()), "labels": [ { "name": "version", "value": tag.name, }, { "name": "arch", "value": docker_layer_data.get("architecture") or "amd64" }, { "name": "os", "value": docker_layer_data.get("os") or "linux" }, ], "app": { "exec": exec_path, # Below, `or 'root'` is required to replace empty string from Dockerfiles. "user": config.get("User") or "root", "group": config.get("Group") or "root", "eventHandlers": [], "workingDirectory": config.get("WorkingDir") or "/", "environment": [{ "name": key, "value": value } for (key, value) in env_vars], "isolators": DockerV1ToACIManifestTranslator._build_isolators(config), "mountPoints": DockerV1ToACIManifestTranslator._build_volumes(config), "ports": DockerV1ToACIManifestTranslator._build_ports(config), "annotations": [ { "name": "created", "value": docker_layer_data.get("created") or "" }, { "name": "homepage", "value": source_url }, { "name": "quay.io/derived-image", "value": synthetic_image_id }, ], }, } return manifest