Example #1
0
def update_bundle(bundle_path):
    working_directory = os.path.abspath(os.getcwd())
    os.chdir(bundle_path)
    git.submodule("foreach", "git", "fetch")
    # sh fails to find the subcommand so we use subprocess.
    subprocess.run(shlex.split(
        "git submodule foreach 'git checkout -q `git rev-list --tags --max-count=1`'"
    ),
                   stdout=subprocess.DEVNULL)

    status = StringIO()
    result = git.status("--short", _out=status)
    updates = []
    status = status.getvalue().strip()
    if status:
        for status_line in status.split("\n"):
            action, directory = status_line.split()
            if action != "M" or not directory.startswith("libraries"):
                raise RuntimeError("Unsupported updates")

            # Compute the tag difference.
            diff = StringIO()
            result = git.diff("--submodule=log", directory, _out=diff)
            diff_lines = diff.getvalue().split("\n")
            commit_range = diff_lines[0].split()[2]
            commit_range = commit_range.strip(":").split(".")
            old_commit = commit_to_tag(directory, commit_range[0])
            new_commit = commit_to_tag(directory, commit_range[-1])
            url = repo_remote_url(directory)
            summary = "\n".join(diff_lines[1:-1])
            updates.append((url[:-4], old_commit, new_commit, summary))
    os.chdir(working_directory)
    return updates
Example #2
0
def update_bundle(bundle_path):
    working_directory = os.path.abspath(os.getcwd())
    os.chdir(bundle_path)
    git.submodule("foreach", "git", "fetch")
    # Regular release tags are 'x.x.x'. Exclude tags that are alpha or beta releases.
    # They will contain a '-' in the tag, such as '3.0.0-beta.5'.
    # --exclude must be before --tags.
    # sh fails to find the subcommand so we use subprocess.
    subprocess.run(shlex.split(
        "git submodule foreach 'git checkout -q `git rev-list --exclude='*-*' --tags --max-count=1`'"
    ),
                   stdout=subprocess.DEVNULL)
    status = StringIO()
    result = git.status("--short", _out=status)
    updates = []
    status = status.getvalue().strip()
    if status:
        for status_line in status.split("\n"):
            action, directory = status_line.split()
            if directory.endswith("library_list.md"):
                continue
            if action != "M" or not directory.startswith("libraries"):
                raise RuntimeError("Unsupported updates")

            # Compute the tag difference.
            diff = StringIO()
            result = git.diff("--submodule=log", directory, _out=diff)
            diff_lines = diff.getvalue().split("\n")
            commit_range = diff_lines[0].split()[2]
            commit_range = commit_range.strip(":").split(".")
            old_commit = commit_to_tag(directory, commit_range[0])
            new_commit = commit_to_tag(directory, commit_range[-1])
            url = repo_remote_url(directory)
            summary = "\n".join(diff_lines[1:-1])
            updates.append((url[:-4], old_commit, new_commit, summary))
    os.chdir(working_directory)
    lib_list_updates = check_lib_links_md(bundle_path)
    if lib_list_updates:
        updates.append((
            "https://github.com/adafruit/Adafruit_CircuitPython_Bundle/circuitpython_library_list.md",
            "NA", "NA", "  > Added the following libraries: {}".format(
                ", ".join(lib_list_updates))))

    return updates
Example #3
0
    def get_git_status(self) -> GitStatus:
        """
        Returns Absolute Paths to all files that are staged

        Ignores files that are symlinks to directories
        """
        import gitdb.exc  # type: ignore

        repo = get_git_repo()

        if not repo or self._base_commit is None:
            return GitStatus([], [], [], [])

        try:
            repo.rev_parse(self._base_commit)
        except gitdb.exc.BadName:
            raise ActionFailure(f"Unknown git ref '{self._base_commit}'")

        # Output of git command will be relative to git project root
        status_output = zsplit(
            git.diff(
                "--cached",
                "--name-status",
                "--no-ext-diff",
                "-z",
                "--diff-filter=ACDMRTUXB",
                "--ignore-submodules",
                self._base_commit,
            ).stdout.decode())

        added = []
        modified = []
        removed = []
        unmerged = []
        while status_output:
            code = status_output[0]
            fname = status_output[1]
            trim_size = 2

            if not code.strip():
                continue
            if code == StatusCode.Untracked or code == StatusCode.Ignored:
                continue

            resolved_name = self._fname_to_path(repo, fname)

            # If file is symlink to directory, skip
            absolute_name = Path(repo.working_tree_dir) / fname
            if absolute_name.is_symlink() and resolved_name.is_dir():
                click.echo(
                    f"| Skipping {absolute_name} since it is a symlink to a directory: {resolved_name}",
                    err=True,
                )
            else:
                # The following detection for unmerged codes comes from `man git-status`
                if code == StatusCode.Unmerged:
                    unmerged.append(resolved_name)
                if (code[0] == StatusCode.Renamed
                    ):  # code is RXXX, where XXX is percent similarity
                    removed.append(resolved_name)
                    fname = status_output[2]
                    trim_size += 1
                    added.append(resolved_name)
                if code == StatusCode.Added:
                    added.append(resolved_name)
                if code == StatusCode.Modified:
                    modified.append(resolved_name)
                if code == StatusCode.Deleted:
                    removed.append(resolved_name)

            status_output = status_output[trim_size:]
        debug_echo(
            f"Git status:\nadded: {added}\nmodified: {modified}\nremoved: {removed}\nunmerged: {unmerged}"
        )

        return GitStatus(added, modified, removed, unmerged)
def new_release(bundle, bundle_path):
    working_directory = os.path.abspath(os.getcwd())
    os.chdir(bundle_path)
    print(bundle)
    current_release = github.get(
        "/repos/adafruit/{}/releases/latest".format(bundle))
    last_tag = current_release.json()["tag_name"]
    contributors = get_contributors("adafruit/" + bundle, last_tag + "..")
    added_submodules = []
    updated_submodules = []
    repo_links = {}

    output = StringIO()
    git.diff("--submodule=short", last_tag + "..", _out=output)
    output = output.getvalue().strip()
    if not output:
        print("Everything is already released.")
        return
    current_submodule = None
    current_index = None
    for line in output.split("\n"):
        if line.startswith("diff"):
            current_submodule = line.split()[-1][len("b/"):]
            continue
        elif "index" in line:
            current_index = line
            continue
        elif not line.startswith("+Subproject"):
            continue

        # We have a candidate submodule change.
        directory = current_submodule
        commit_range = current_index.split()[1]
        library_name = directory.split("/")[-1]
        if commit_range.startswith("0000000"):
            added_submodules.append(library_name)
            commit_range = commit_range.split(".")[-1]
        elif commit_range.endswith("0000000"):
            # For now, skip documenting deleted modules.
            continue
        else:
            updated_submodules.append(library_name)

        repo_url = repo_remote_url(directory)

        new_commit = commit_range.split(".")[-1]
        release_tag = commit_to_tag(directory, new_commit)
        with Submodule(directory):
            submodule_contributors = get_contributors(repo_name(repo_url),
                                                      commit_range)
            add_contributors(contributors, submodule_contributors)
        repo_links[library_name] = repo_url[:-4] + "/releases/" + release_tag

    release_description = []
    if added_submodules:
        additions = []
        for library in added_submodules:
            additions.append("[{}]({})".format(library, repo_links[library]))
        release_description.append("New libraries: " + ", ".join(additions))

    if updated_submodules:
        updates = []
        for library in updated_submodules:
            updates.append("[{}]({})".format(library, repo_links[library]))
        release_description.append("Updated libraries: " + ", ".join(updates))

    release_description.append("")

    contributors = sorted(contributors, key=contributors.__getitem__, reverse=True)
    contributors = ["@" + x for x in contributors]

    release_description.append("As always, thank you to all of our contributors: " + ", ".join(contributors))

    release_description.append("\n--------------------------\n")

    release_description.append("The libraries in each release are compiled for all recent major versions of CircuitPython. Please download the one that matches the major version of your CircuitPython. For example, if you are running 4.0.0 you should download the `4.x` bundle.\n")

    release_description.append("To install, simply download the matching zip file, unzip it, and selectively copy the libraries you would like to install into the lib folder on your CIRCUITPY drive. This is especially important for non-express boards such as the [Trinket M0](https://www.adafruit.com/product/3500), [Gemma M0](https://www.adafruit.com/product/3501) and [Feather M0 Basic](https://www.adafruit.com/product/2772).")

    release = {
        "tag_name": "{0:%Y%m%d}".format(date.today()),
        "target_commitish": repo_sha(),
        "name": "{0:%B} {0:%d}, {0:%Y} auto-release".format(date.today()),
        "body": "\n".join(release_description),
        "draft": False,
        "prerelease": False}

    print("Releasing {}".format(release["tag_name"]))
    print(release["body"])
    response = github.post("/repos/adafruit/" + bundle + "/releases", json=release)
    if not response.ok:
        print("Failed to create release")
        print(release)
        print(response.request.url)
        print(response.text)

    os.chdir(working_directory)
Example #5
0
    def get_git_status(self) -> GitStatus:
        """
            Returns Absolute Paths to all files that are staged
        """
        import gitdb.exc  # type: ignore

        repo = get_git_repo()

        if not repo or self._base_commit is None:
            return GitStatus([], [], [], [])

        try:
            repo.rev_parse(self._base_commit)
        except gitdb.exc.BadName:
            raise RuntimeError(f"Unknown git ref '{self._base_commit}'")

        # Output of git command will be relative to git project root
        status_output = zsplit(
            git.diff(
                "--name-status",
                "--no-ext-diff",
                "-z",
                "--diff-filter=ACDMRTUXB",
                "--ignore-submodules",
                self._base_commit,
            ).stdout.decode())

        added = []
        modified = []
        removed = []
        unmerged = []
        while status_output:
            code = status_output[0]
            fname = status_output[1]
            trim_size = 2

            if not code.strip():
                continue
            if code == StatusCode.Untracked or code == StatusCode.Ignored:
                continue

            # The following detection for unmerged codes comes from `man git-status`
            if code == StatusCode.Unmerged:
                unmerged.append(self._fname_to_path(repo, fname))
            if (code[0] == StatusCode.Renamed
                ):  # code is RXXX, where XXX is percent similarity
                removed.append(self._fname_to_path(repo, fname))
                fname = status_output[2]
                trim_size += 1
                added.append(self._fname_to_path(repo, fname))
            if code == StatusCode.Added:
                added.append(self._fname_to_path(repo, fname))
            if code == StatusCode.Modified:
                modified.append(self._fname_to_path(repo, fname))
            if code == StatusCode.Deleted:
                removed.append(self._fname_to_path(repo, fname))

            status_output = status_output[trim_size:]
        debug_echo(
            f"Git status:\nadded: {added}\nmodified: {modified}\nremoved: {removed}\nunmerged: {unmerged}"
        )
        return GitStatus(added, modified, removed, unmerged)