예제 #1
0
    def resolve(self):
        """Resolve a github source into a specific commit.

        The spec must include:
        - github: the URL of the github repository

        The spec may include one of:
        - commit: a commit hash
        - ref: a git ref
        - branch: a git branch
        - tag: a git tag
        - release: "latest" | "previous" | "latest_beta"

        If none of these are specified, CumulusCI will look for the latest release.
        If there is no release, it will use the default branch.
        """
        ref = None
        if "commit" in self.spec:
            self.commit = self.description = self.spec["commit"]
            return
        elif "ref" in self.spec:
            ref = self.spec["ref"]
        elif "tag" in self.spec:
            ref = "tags/" + self.spec["tag"]
        elif "branch" in self.spec:
            ref = "heads/" + self.spec["branch"]
        elif "release" in self.spec:
            release_spec = self.spec["release"]
            if release_spec == "latest":
                release = find_latest_release(self.repo, include_beta=False)
            elif release_spec == "latest_beta":
                release = find_latest_release(self.repo, include_beta=True)
            elif release_spec == "previous":
                release = find_previous_release(self.repo)
            else:
                raise DependencyResolutionError(
                    f"Unknown release: {release_spec}")
            if release is None:
                raise DependencyResolutionError(
                    f"Could not find release: {release_spec}")
            ref = "tags/" + release.tag_name
        if ref is None:
            release = find_latest_release(self.repo, include_beta=False)
            if release:
                ref = "tags/" + release.tag_name
            else:
                ref = "heads/" + self.repo.default_branch
        self.description = ref[6:] if ref.startswith("heads/") else ref
        self.commit = self.repo.ref(ref).object.sha
예제 #2
0
    def resolve(self):
        """Resolve a github source into a specific commit.

        The spec must include:
        - github: the URL of the github repository

        The spec may include one of:
        - commit: a commit hash
        - ref: a git ref
        - branch: a git branch
        - tag: a git tag

        If none of these are specified, CumulusCI will look for the latest release.
        If there is no release, it will use the default branch.
        """
        ref = None
        if "commit" in self.spec:
            self.commit = self.description = self.spec["commit"]
            return
        elif "ref" in self.spec:
            ref = self.spec["ref"]
        elif "tag" in self.spec:
            ref = "tags/" + self.spec["tag"]
        elif "branch" in self.spec:
            ref = "heads/" + self.spec["branch"]
        if ref is None:
            release = find_latest_release(self.repo, include_beta=False)
            if release:
                ref = "tags/" + release.tag_name
            else:
                ref = "heads/" + self.repo.default_branch
        self.description = ref[6:] if ref.startswith("heads/") else ref
        self.commit = self.repo.ref(ref).object.sha
예제 #3
0
    def get_ref_for_dependency(self, repo, dependency, include_beta=None):
        release = None
        if "ref" in dependency:
            ref = dependency["ref"]
        else:
            if "tag" in dependency:
                try:
                    # Find the github release corresponding to this tag.
                    release = repo.release_from_tag(dependency["tag"])
                except NotFoundError:
                    raise DependencyResolutionError(
                        f"No release found for tag {dependency['tag']}"
                    )
            else:
                release = find_latest_release(repo, include_beta)
            if release:
                ref = repo.tag(
                    repo.ref("tags/" + release.tag_name).object.sha
                ).object.sha
            else:
                self.logger.info(
                    f"No release found; using the latest commit from the {repo.default_branch} branch."
                )
                ref = repo.branch(repo.default_branch).commit.sha

        return (release, ref)
예제 #4
0
    def process_github_dependency(  # noqa: C901
            self, dependency, indent=None, include_beta=None):
        if not indent:
            indent = ""

        self.logger.info(
            f"{indent}Processing dependencies from Github repo {dependency['github']}"
        )

        skip = dependency.get("skip")
        if not isinstance(skip, list):
            skip = [skip]

        # Initialize github3.py API against repo
        repo_owner, repo_name = dependency["github"].split("/")[3:5]
        if repo_name.endswith(".git"):
            repo_name = repo_name[:-4]
        gh = self.get_github_api(repo_owner, repo_name)
        repo = gh.repository(repo_owner, repo_name)
        if repo is None:
            raise DependencyResolutionError(
                f"{indent}Github repository {dependency['github']} not found or not authorized."
            )

        # Determine the commit
        release = None
        if "ref" in dependency:
            ref = dependency["ref"]
        else:
            if "tag" in dependency:
                try:
                    # Find the github release corresponding to this tag.
                    release = repo.release_from_tag(dependency["tag"])
                except NotFoundError:
                    raise DependencyResolutionError(
                        f"{indent}No release found for tag {dependency['tag']}"
                    )
            else:
                release = find_latest_release(repo, include_beta)
            if release:
                ref = repo.tag(
                    repo.ref("tags/" + release.tag_name).object.sha).object.sha
            else:
                self.logger.info(
                    f"{indent}No release found; using the latest commit from the {repo.default_branch} branch."
                )
                ref = repo.branch(repo.default_branch).commit.sha

        # Get the cumulusci.yml file
        contents = repo.file_contents("cumulusci.yml", ref=ref)
        cumulusci_yml = cci_safe_load(
            io.StringIO(contents.decoded.decode("utf-8")))

        # Get the namespace from the cumulusci.yml if set
        package_config = cumulusci_yml.get("project", {}).get("package", {})
        namespace = package_config.get("namespace")
        package_name = (package_config.get("name_managed")
                        or package_config.get("name") or namespace)

        # Check for unmanaged flag on a namespaced package
        unmanaged = namespace and dependency.get("unmanaged") is True

        # Look for subfolders under unpackaged/pre
        unpackaged_pre = []
        try:
            contents = repo.directory_contents("unpackaged/pre",
                                               return_as=dict,
                                               ref=ref)
        except NotFoundError:
            contents = None
        if contents:
            for dirname in list(contents.keys()):
                subfolder = f"unpackaged/pre/{dirname}"
                if subfolder in skip:
                    continue
                name = f"Deploy {subfolder}"

                unpackaged_pre.append({
                    "name":
                    name,
                    "repo_owner":
                    repo_owner,
                    "repo_name":
                    repo_name,
                    "ref":
                    ref,
                    "subfolder":
                    subfolder,
                    "unmanaged":
                    dependency.get("unmanaged"),
                    "namespace_tokenize":
                    dependency.get("namespace_tokenize"),
                    "namespace_inject":
                    dependency.get("namespace_inject"),
                    "namespace_strip":
                    dependency.get("namespace_strip"),
                })

        # Look for metadata under src (deployed if no namespace)
        unmanaged_src = None
        if unmanaged or not namespace:
            contents = repo.directory_contents("src", ref=ref)
            if contents:
                subfolder = "src"

                unmanaged_src = {
                    "name": f"Deploy {package_name or repo_name}",
                    "repo_owner": repo_owner,
                    "repo_name": repo_name,
                    "ref": ref,
                    "subfolder": subfolder,
                    "unmanaged": dependency.get("unmanaged"),
                    "namespace_tokenize": dependency.get("namespace_tokenize"),
                    "namespace_inject": dependency.get("namespace_inject"),
                    "namespace_strip": dependency.get("namespace_strip"),
                }

        # Look for subfolders under unpackaged/post
        unpackaged_post = []
        try:
            contents = repo.directory_contents("unpackaged/post",
                                               return_as=dict,
                                               ref=ref)
        except NotFoundError:
            contents = None
        if contents:
            for dirname in list(contents.keys()):
                subfolder = f"unpackaged/post/{dirname}"
                if subfolder in skip:
                    continue
                name = f"Deploy {subfolder}"

                dependency = {
                    "name": name,
                    "repo_owner": repo_owner,
                    "repo_name": repo_name,
                    "ref": ref,
                    "subfolder": subfolder,
                    "unmanaged": dependency.get("unmanaged"),
                    "namespace_tokenize": dependency.get("namespace_tokenize"),
                    "namespace_inject": dependency.get("namespace_inject"),
                    "namespace_strip": dependency.get("namespace_strip"),
                }
                # By default, we always inject the project's namespace into
                # unpackaged/post metadata
                if namespace and not dependency.get("namespace_inject"):
                    dependency["namespace_inject"] = namespace
                    dependency["unmanaged"] = unmanaged
                unpackaged_post.append(dependency)

        # Parse values from the repo's cumulusci.yml
        project = cumulusci_yml.get("project", {})
        dependencies = project.get("dependencies")
        if dependencies:
            dependencies = self.get_static_dependencies(
                dependencies, include_beta=include_beta)

        # Create the final ordered list of all parsed dependencies
        repo_dependencies = []

        # unpackaged/pre/*
        if unpackaged_pre:
            repo_dependencies.extend(unpackaged_pre)

        if namespace and not unmanaged:
            if release is None:
                raise DependencyResolutionError(
                    f"{indent}Could not find latest release for {namespace}")
            version = release.name
            # If a latest prod version was found, make the dependencies a
            # child of that install
            dependency = {
                "name": f"Install {package_name or namespace} {version}",
                "namespace": namespace,
                "version": version,
            }
            if dependencies:
                dependency["dependencies"] = dependencies
            repo_dependencies.append(dependency)

        # Unmanaged metadata from src (if referenced repo doesn't have a
        # namespace)
        else:
            if dependencies:
                repo_dependencies.extend(dependencies)
            if unmanaged_src:
                repo_dependencies.append(unmanaged_src)

        # unpackaged/post/*
        if unpackaged_post:
            repo_dependencies.extend(unpackaged_post)

        return repo_dependencies