Beispiel #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
Beispiel #2
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)
Beispiel #3
0
    def _get_repo_dependencies(self,
                               dependencies=None,
                               include_beta=None,
                               visited_repos=None):
        """Return a list of Package objects representing all of the GitHub repositories
        in this project's dependency tree. Ignore all non-GitHub dependencies."""
        deps = []
        visited = visited_repos or set()

        for dependency in dependencies:
            if "github" in dependency:
                repo = self.project_config.get_repo_from_url(
                    dependency["github"])
                if repo is None:
                    raise DependencyResolutionError(
                        f"Github repository {dependency['github']} not found or not authorized."
                    )
                _, ref = self.project_config.get_ref_for_dependency(
                    repo, dependency, include_beta)

                contents = repo.file_contents("cumulusci.yml", ref=ref)
                cumulusci_yml = cci_safe_load(
                    io.StringIO(contents.decoded.decode("utf-8")))
                project = cumulusci_yml.get("project", {})
                namespace = project.get("package", {}).get("namespace", "")
                if namespace:
                    namespace = f"{namespace}__"
                else:
                    namespace = ""

                if f"{repo.owner}/{repo.name}" in visited:
                    continue

                deps.append(
                    Package(
                        repo,
                        project.get("package",
                                    {}).get("name",
                                            f"{repo.owner}/{repo.name}"),
                        namespace,
                        project.get("git", {}).get("prefix_release",
                                                   "release/"),
                    ))
                visited.add(f"{repo.owner}/{repo.name}")

                deps.extend(
                    self._get_repo_dependencies(
                        cumulusci_yml.get("project",
                                          {}).get("dependencies", []),
                        visited_repos=visited,
                    ))

        return deps
Beispiel #4
0
    def resolve_04t_dependencies(self, dependencies):
        """Look up 04t SubscriberPackageVersion ids for 1gp project dependencies"""
        new_dependencies = []
        for dependency in dependencies:
            dependency = {**dependency}

            if "namespace" in dependency:
                # get the SubscriberPackageVersion id
                key = f"{dependency['namespace']}@{dependency['version']}"
                version_info = self.installed_packages.get(key)
                if version_info:
                    dependency["version_id"] = version_info[0].id
                else:
                    raise DependencyResolutionError(
                        f"Could not find 04t id for package {key} in org {self.name}"
                    )

            # recurse
            if "dependencies" in dependency:
                dependency["dependencies"] = self.resolve_04t_dependencies(
                    dependency["dependencies"])

            new_dependencies.append(dependency)
        return new_dependencies
Beispiel #5
0
    def process_github_dependency(self, dependency, indent=None):
        if not indent:
            indent = ''

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

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

        # Initialize github3.py API against repo
        gh = self.get_github_api()
        repo_owner, repo_name = dependency['github'].split('/')[3:5]
        if repo_name.endswith('.git'):
            repo_name = repo_name[:-4]
        repo = gh.repository(repo_owner, repo_name)

        # Prepare HTTP auth header for requests calls to Github
        github = self.keychain.get_service('github')
        headers = {'Authorization': 'token {}'.format(github.password)}

        # Determine the ref if specified
        kwargs = {}
        if 'tag' in dependency:
            tag = dependency['tag']
            kwargs['ref'] = tag
        else:
            tag = None

        # Get the cumulusci.yml file
        contents = repo.contents('cumulusci.yml', **kwargs)
        cumulusci_yml = hiyapyco.load(contents.decoded, loglevel='INFO')

        # Get the namespace from the cumulusci.yml if set
        namespace = cumulusci_yml.get('project', {}).get(
            'package', {}).get('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 = []
        contents = repo.contents('unpackaged/pre', **kwargs)
        if contents:
            for dirname in list(contents.keys()):
                if 'unpackaged/pre/{}'.format(dirname) in skip:
                    continue
                subfolder = "{}-{}/unpackaged/pre/{}".format(
                    repo.name, repo.default_branch, dirname)
                zip_url = "{}/archive/{}.zip".format(
                    repo.html_url, repo.default_branch)

                unpackaged_pre.append({
                    'zip_url': zip_url,
                    'subfolder': subfolder,
                    'headers': headers,
                    '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.contents('src', **kwargs)
            if contents:
                zip_url = "{}/archive/{}.zip".format(
                    repo.html_url, repo.default_branch)
                subfolder = "{}-{}/src".format(repo.name, repo.default_branch)

                unmanaged_src = {
                    'zip_url': zip_url,
                    'subfolder': subfolder,
                    'headers': headers,
                    '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 = []
        contents = repo.contents('unpackaged/post', **kwargs)
        if contents:
            for dirname in list(contents.keys()):
                if 'unpackaged/post/{}'.format(dirname) in skip:
                    continue
                zip_url = "{}/archive/{}.zip".format(
                    repo.html_url, repo.default_branch)
                subfolder = "{}-{}/unpackaged/post/{}".format(
                    repo.name, repo.default_branch, dirname)

                dependency = {
                    'zip_url': zip_url,
                    'subfolder': subfolder,
                    'headers': headers,
                    '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', {})
        prefix_beta = project.get('git', {}).get('prefix_beta', 'beta/')
        prefix_release = project.get('git', {}).get('prefix_release', 'release/')
        dependencies = project.get('dependencies')
        if dependencies:
            dependencies = self.get_static_dependencies(dependencies)

        # 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:
            version = None
            if tag:
                version = self.get_version_for_tag(tag, prefix_beta, prefix_release)
            else:
                # github3.py doesn't support the latest release API so we hack
                # it together here
                url = repo._build_url('releases/latest', base_url=repo._api)
                try:
                    version = repo._get(url).json()['name']
                except Exception as e:
                    self.logger.warn('{}{}: {}'.format(
                        indent, e.__class__.__name__, e.message))

            if not version:
                raise DependencyResolutionError(
                    '{}Could not find latest release for {}'.format(indent, namespace)
                )
            # If a latest prod version was found, make the dependencies a
            # child of that install
            dependency = {
                '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
Beispiel #6
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
Beispiel #7
0
    def process_github_dependency(self,
                                  dependency,
                                  indent=None,
                                  include_beta=None):
        if not indent:
            indent = ""

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

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

        # Initialize github3.py API against repo
        gh = self.get_github_api()
        repo_owner, repo_name = dependency["github"].split("/")[3:5]
        if repo_name.endswith(".git"):
            repo_name = repo_name[:-4]
        repo = gh.repository(repo_owner, repo_name)

        # Determine the ref if specified
        kwargs = {}
        if "tag" in dependency:
            tag = dependency["tag"]
            kwargs["ref"] = tag
        else:
            tag = None

        # Get the cumulusci.yml file
        contents = repo.file_contents("cumulusci.yml", **kwargs)
        cumulusci_yml = ordered_yaml_load(contents.decoded)

        # Get the namespace from the cumulusci.yml if set
        namespace = cumulusci_yml.get("project", {}).get("package",
                                                         {}).get("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,
                                               **kwargs)
        except NotFoundError:
            contents = None
        if contents:
            for dirname in list(contents.keys()):
                subfolder = "unpackaged/pre/{}".format(dirname)
                if subfolder in skip:
                    continue

                unpackaged_pre.append({
                    "repo_owner":
                    repo_owner,
                    "repo_name":
                    repo_name,
                    "ref":
                    tag,
                    "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", **kwargs)
            if contents:
                subfolder = "src"

                unmanaged_src = {
                    "repo_owner": repo_owner,
                    "repo_name": repo_name,
                    "ref": tag,
                    "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,
                                               **kwargs)
        except NotFoundError:
            contents = None
        if contents:
            for dirname in list(contents.keys()):
                subfolder = "unpackaged/post/{}".format(dirname)
                if subfolder in skip:
                    continue

                dependency = {
                    "repo_owner": repo_owner,
                    "repo_name": repo_name,
                    "ref": tag,
                    "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", {})
        prefix_beta = project.get("git", {}).get("prefix_beta", "beta/")
        prefix_release = project.get("git", {}).get("prefix_release",
                                                    "release/")
        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:
            version = None
            if tag:
                version = self.get_version_for_tag(tag, prefix_beta,
                                                   prefix_release)
            else:
                version = self._find_release_version(repo, indent,
                                                     include_beta)

            if not version:
                raise DependencyResolutionError(
                    "{}Could not find latest release for {}".format(
                        indent, namespace))
            # If a latest prod version was found, make the dependencies a
            # child of that install
            dependency = {"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
    def process_github_dependency(self, dependency, indent=None):
        if not indent:
            indent = ""

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

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

        # Initialize github3.py API against repo
        gh = self.get_github_api()
        repo_owner, repo_name = dependency["github"].split("/")[3:5]
        if repo_name.endswith(".git"):
            repo_name = repo_name[:-4]
        repo = gh.repository(repo_owner, repo_name)

        # Prepare HTTP auth header for requests calls to Github
        github = self.keychain.get_service("github")
        headers = {"Authorization": "token {}".format(github.password)}

        # Determine the ref if specified
        kwargs = {}
        if "tag" in dependency:
            tag = dependency["tag"]
            kwargs["ref"] = tag
        else:
            tag = None

        # Get the cumulusci.yml file
        contents = repo.contents("cumulusci.yml", **kwargs)
        cumulusci_yml = hiyapyco.load(contents.decoded, loglevel="INFO")

        # Get the namespace from the cumulusci.yml if set
        namespace = cumulusci_yml.get("project", {}).get("package",
                                                         {}).get("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 = []
        contents = repo.contents("unpackaged/pre", **kwargs)
        if contents:
            for dirname in list(contents.keys()):
                if "unpackaged/pre/{}".format(dirname) in skip:
                    continue
                subfolder = "{}-{}/unpackaged/pre/{}".format(
                    repo.name, repo.default_branch, dirname)
                zip_url = "{}/archive/{}.zip".format(repo.html_url,
                                                     repo.default_branch)

                unpackaged_pre.append({
                    "zip_url":
                    zip_url,
                    "subfolder":
                    subfolder,
                    "headers":
                    headers,
                    "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.contents("src", **kwargs)
            if contents:
                zip_url = "{}/archive/{}.zip".format(repo.html_url,
                                                     repo.default_branch)
                subfolder = "{}-{}/src".format(repo.name, repo.default_branch)

                unmanaged_src = {
                    "zip_url": zip_url,
                    "subfolder": subfolder,
                    "headers": headers,
                    "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 = []
        contents = repo.contents("unpackaged/post", **kwargs)
        if contents:
            for dirname in list(contents.keys()):
                if "unpackaged/post/{}".format(dirname) in skip:
                    continue
                zip_url = "{}/archive/{}.zip".format(repo.html_url,
                                                     repo.default_branch)
                subfolder = "{}-{}/unpackaged/post/{}".format(
                    repo.name, repo.default_branch, dirname)

                dependency = {
                    "zip_url": zip_url,
                    "subfolder": subfolder,
                    "headers": headers,
                    "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", {})
        prefix_beta = project.get("git", {}).get("prefix_beta", "beta/")
        prefix_release = project.get("git", {}).get("prefix_release",
                                                    "release/")
        dependencies = project.get("dependencies")
        if dependencies:
            dependencies = self.get_static_dependencies(dependencies)

        # 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:
            version = None
            if tag:
                version = self.get_version_for_tag(tag, prefix_beta,
                                                   prefix_release)
            else:
                # github3.py doesn't support the latest release API so we hack
                # it together here
                url = repo._build_url("releases/latest", base_url=repo._api)
                try:
                    version = repo._get(url).json()["name"]
                except Exception as e:
                    self.logger.warn("{}{}: {}".format(indent,
                                                       e.__class__.__name__,
                                                       e.message))

            if not version:
                raise DependencyResolutionError(
                    "{}Could not find latest release for {}".format(
                        indent, namespace))
            # If a latest prod version was found, make the dependencies a
            # child of that install
            dependency = {"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