Exemple #1
0
def determine_release_tag(ctx: TagContext) -> None:
    click.secho("> Determining what the release tag should be.", fg="cyan")
    head_ref = ctx.release_pr["head"]["ref"]
    match = re.match(r"release-.+-(v\d+\.\d+\.\d+)", head_ref)

    if match is not None:
        ctx.release_tag = match.group(1)
    else:
        click.secho(
            "I couldn't determine what the release tag should be from the PR's"
            f"head ref {head_ref}.",
            fg="red",
        )
        ctx.release_tag = click.prompt(
            "What should the release tag be (for example, storage-1.2.3)?"
        )

    click.secho(f"Release tag is {ctx.release_tag}.")
Exemple #2
0
def tag(ctx: TagContext = None) -> TagContext:
    if not ctx:
        ctx = TagContext()

    if ctx.interactive:
        click.secho(
            f"o/ Hey, {getpass.getuser()}, let's tag a Ruby release!", fg="magenta"
        )

    if ctx.github is None:
        releasetool.commands.common.setup_github_context(ctx)

    if ctx.release_pr is None:
        determine_release_pr(ctx)

    determine_release_tag(ctx)
    determine_package_name_and_version(ctx)

    # If the release already exists, don't do anything
    if releasetool.commands.common.release_exists(ctx):
        click.secho(f"{ctx.release_tag} already exists.", fg="magenta")
        return ctx

    get_release_notes(ctx)

    create_release(ctx)
    ctx.kokoro_job_name = kokoro_job_name(ctx.upstream_repo, ctx.package_name)

    releasetool.commands.common.publish_via_kokoro(ctx)

    if ctx.interactive:
        click.secho("\\o/ All done!", fg="magenta")

    branch = ctx.release_pr["head"]["ref"]

    try:
        ctx.github.delete_branch(repository=ctx.upstream_repo, branch=branch)
        click.secho(f"Deleted branch {branch}")
    # If user has already deleted the branch, this will fail.
    except HTTPError as exc:
        if exc.response.status_code != 422:
            click.secho(f"{exc!r}")

    return ctx
Exemple #3
0
def get_release_notes(ctx: TagContext) -> None:
    click.secho("> Grabbing the release notes.", fg="cyan")
    changelog = ctx.github.get_contents(
        ctx.upstream_repo,
        f"{ctx.package_name}/CHANGELOG.md",
        ref=ctx.release_pr["merge_commit_sha"],
    ).decode("utf-8")

    match = re.search(
        rf"^### {ctx.release_version} \/ \d\d\d\d-\d\d-\d\d\n(?P<notes>.+?)(\n###\s|\Z)",
        changelog,
        re.DOTALL | re.MULTILINE,
    )
    if match is not None:
        ctx.release_notes = match.group("notes").strip()
    else:
        ctx.release_notes = ""

    click.secho(f"Here's the release notes:\n\n{ctx.release_notes}\n")
Exemple #4
0
def test_new_style_release_notes_patch():
    """
    In the conventional-commits template (see: https://github.com/conventional-changelog/conventional-changelog),
    patches are an H3 header and are linked to the underlying issue that created the release.
    """
    expected = """### Bug Fixes

* include 'x-goog-request-params' header in requests ([#167](https://www.github.com/googleapis/nodejs-os-login/issues/167)) ([074051d](https://www.github.com/googleapis/nodejs-os-login/commit/074051d))"""
    ctx = TagContext(release_version="v0.3.3")
    _get_latest_release_notes(ctx, fixture_new_and_old_style_changelog)
    assert ctx.release_notes == expected
Exemple #5
0
def test_old_style_release_notes():
    """
    Our old CHANGELOG template does not make the version header a link and
    always uses H2 headers.
    """
    expected = """03-13-2019 16:30 PDT

### Bug Fixes
- fix: throw on invalid credentials ([#281](https://github.com/googleapis/nodejs-dialogflow/pull/281))"""
    ctx = TagContext(release_version="v0.8.2")
    _get_latest_release_notes(ctx, fixture_old_style_changelog)
    assert ctx.release_notes == expected
Exemple #6
0
def get_release_notes(ctx: TagContext) -> None:
    click.secho("> Grabbing the release notes.")
    if "google-cloud-python" in ctx.upstream_repo:
        changelog_path = f"{ctx.package_name}/CHANGELOG.md"
    else:
        changelog_path = "CHANGELOG.md"
    changelog = ctx.github.get_contents(
        ctx.upstream_repo,
        changelog_path,
        ref=ctx.release_pr["merge_commit_sha"]).decode("utf-8")

    match = re.search(
        r"#{2,3}[\s\W]+?" + ctx.release_version +
        r"*?\n(?P<notes>.+?)(\Z|\n#{2,3}\W*?\d)",
        changelog,
        re.DOTALL | re.MULTILINE,
    )
    if match is not None:
        ctx.release_notes = match.group("notes").strip()
    else:
        ctx.release_notes = ""
Exemple #7
0
def tag(ctx: TagContext = None) -> TagContext:
    if not ctx:
        ctx = TagContext()

    if ctx.interactive:
        click.secho(f"o/ Hey, {getpass.getuser()}, let's tag a release!", fg="magenta")

    if ctx.github is None:
        releasetool.commands.common.setup_github_context(ctx)

    # delegate releaase tagging to release-please
    default_branch = ctx.release_pr["base"]["ref"]
    repo = ctx.release_pr["base"]["repo"]["full_name"]

    with tempfile.NamedTemporaryFile("w+t", delete=False) as fp:
        fp.write(ctx.token)
        token_file = fp.name

    output = subprocess.check_output(
        [
            "npx",
            "release-please",
            "github-release",
            f"--token={token_file}",
            f"--default-branch={default_branch}",
            "--release-type=java-yoshi",
            "--bump-minor-pre-major=true",
            f"--repo-url={repo}",
            "--package-name=",
            "--debug",
        ]
    )

    ctx.release_tag = _parse_release_tag(output.decode("utf-8"))
    ctx.kokoro_job_name = kokoro_job_name(ctx.upstream_repo, ctx.package_name)

    if ctx.interactive:
        click.secho("\\o/ All done!", fg="magenta")

    return ctx
Exemple #8
0
def tag(ctx: TagContext = None) -> TagContext:
    if not ctx:
        ctx = TagContext()

    if ctx.interactive:
        click.secho(f"o/ Hey, {getpass.getuser()}, let's tag a release!", fg="magenta")

    if ctx.github is None:
        releasetool.commands.common.setup_github_context(ctx)

    if ctx.release_pr is None:
        determine_release_pr(ctx)

    determine_release_tag(ctx)
    determine_package_name_and_version(ctx)

    # If the release already exists, don't do anything
    if releasetool.commands.common.release_exists(ctx):
        click.secho(f"{ctx.release_tag} already exists.", fg="magenta")
        return ctx

    get_release_notes(ctx)
    create_release(ctx)

    # Only enable release job triggering on google-auth-library-java for now.
    if ctx.upstream_repo == "googleapis/google-auth-library-java":
        ctx.kokoro_job_name = (
            "cloud-devrel/client-libraries/java/google-auth-library-java/release/stage"
        )
        # TODO: Move to create_release once autorelease is enabled for all
        # java repositories
        ctx.github.update_pull_labels(
            ctx.release_pr, add=["autorelease: tagged"], remove=["autorelease: pending"]
        )
        releasetool.commands.common.publish_via_kokoro(ctx)

    if ctx.interactive:
        click.secho(f"\\o/ All done!", fg="magenta")

    return ctx
Exemple #9
0
def run_releasetool_tag(lang: str, gh: github.GitHub, pull: dict) -> TagContext:
    """Runs releasetool tag using external config."""
    language_module = importlib.import_module(f"releasetool.commands.tag.{lang}")
    ctx = TagContext()
    ctx.interactive = False
    # TODO(busunkim): Use proxy once KMS setup is complete.
    ctx.github = releasetool.github.GitHub(gh.token, use_proxy=False)
    ctx.token = gh.token
    ctx.upstream_repo = pull["base"]["repo"]["full_name"]
    ctx.release_pr = pull
    return language_module.tag(ctx)
Exemple #10
0
def create_releases(ctx: TagContext) -> None:
    click.secho("> Creating the release.")

    commitish = ctx.release_pr["merge_commit_sha"]
    lines = ctx.release_pr["body"].splitlines()
    pr_comment = ""
    for line in lines:
        match = re.search(RELEASE_LINE_PATTERN, line)
        if match is not None:
            package = match.group(1)
            version = match.group(2)
            tag = package + "-" + version
            ctx.github.create_release(
                repository=ctx.upstream_repo,
                tag_name=tag,
                target_commitish=commitish,
                name=tag,
                body=f"Package {package} version {version}",
                # Versions like "1.0.0-beta01" or "0.9.0" are prerelease
                prerelease="-" in version or version.startswith("0."),
            )
            click.secho(f"Created release for {tag}")
            pr_comment = pr_comment + f"- Created release for {tag}\n"

    if pr_comment == "":
        raise ValueError("No releases found within pull request")

    ctx.github.create_pull_request_comment(ctx.upstream_repo,
                                           ctx.release_pr["number"],
                                           pr_comment)

    # This isn't a tag, but that's okay - it just needs to be a commitish for
    # Kokoro to build against.
    ctx.release_tag = commitish
    ctx.kokoro_job_name = f"cloud-sharp/google-cloud-dotnet/gcp_windows/autorelease"
    ctx.github.update_pull_labels(ctx.release_pr,
                                  add=["autorelease: tagged"],
                                  remove=["autorelease: pending"])
    releasetool.commands.common.publish_via_kokoro(ctx)
Exemple #11
0
def determine_release_tag(ctx: TagContext) -> None:
    click.secho("> Determining what the release tag should be.", fg="cyan")
    head_ref = ctx.release_pr["head"]["ref"]

    # try release-please v13 pull requests
    title = ctx.release_pr["title"]
    match = re.match("chore\\(.*\\): release (\\d+\\.\\d+\\.\\d+.*)", title)
    if match is not None:
        ctx.release_tag = f"v{match.group(1)}"
        return

    match = re.match("release-(.+)", head_ref)

    if match is not None:
        ctx.release_tag = match.group(1)
    else:
        print(
            "I couldn't determine what the release tag should be from the PR's"
            f"head ref {head_ref}.")
        ctx.release_tag = click.prompt(
            "What should the release tag be (for example, v1.2.3)?")

    click.secho(f"Release tag is {ctx.release_tag}.")
Exemple #12
0
def determine_release_pr(ctx: TagContext) -> None:
    click.secho(
        "> Let's figure out which pull request corresponds to your release.", fg="cyan"
    )

    pulls = ctx.github.list_pull_requests(ctx.upstream_repo, state="closed")
    pulls = [pull for pull in pulls if "release" in pull["title"].lower()][:30]

    click.secho("> Please pick one of the following PRs:\n")
    for n, pull in enumerate(pulls, 1):
        print(f"\t{n}: {pull['title']} ({pull['number']})")

    pull_idx = click.prompt("\nWhich one do you want to tag and release?", type=int)
    ctx.release_pr = pulls[pull_idx - 1]
Exemple #13
0
def determine_release_tag(ctx: TagContext) -> None:
    click.secho("> Determining the release tag.", fg="cyan")
    head_ref = ctx.release_pr["head"]["ref"]
    click.secho(f"PR head ref is {head_ref}")
    match = re.match(r"release-(.+)-v(\d+\.\d+\.\d+)", head_ref)

    if match is not None:
        ctx.package_name = match.group(1)
        ctx.release_version = match.group(2)
        ctx.release_tag = f"{ctx.package_name}/v{ctx.release_version}"
    else:
        click.secho(
            "I couldn't determine what the release tag should be from the PR's"
            f"head ref {head_ref}.",
            fg="red",
        )
        ctx.release_tag = click.prompt(
            "What should the release tag be (for example, google-cloud-storage/v1.2.3)?"
        )

    click.secho(f"Package name is {ctx.package_name}")
    click.secho(f"Package version is {ctx.release_version}")
    click.secho(f"Release tag is {ctx.release_tag}")
Exemple #14
0
def tag(ctx: TagContext = None) -> TagContext:
    if not ctx:
        ctx = TagContext()

    if ctx.interactive:
        click.secho(f"o/ Hey, {getpass.getuser()}, let's tag a release!",
                    fg="magenta")

    if ctx.github is None:
        releasetool.commands.common.setup_github_context(ctx)

    if ctx.release_pr is None:
        determine_release_pr(ctx)

    # If using manifest release, the manifest releaser determines
    # release tag, version, and release notes:
    if ctx.upstream_repo not in manifest_release:
        determine_release_tag(ctx)
        determine_package_version(ctx)
        # If the release already exists, don't do anything
        if releasetool.commands.common.release_exists(ctx):
            click.secho(f"{ctx.release_tag} already exists.", fg="magenta")
            return ctx
        get_release_notes(ctx)
    else:
        # If using mono-release strategy, fallback to using sha from
        # time of merge:
        ctx.release_tag = ctx.release_pr["merge_commit_sha"]

    create_release(ctx)
    ctx.kokoro_job_name = kokoro_job_name(ctx.upstream_repo, ctx.package_name)
    releasetool.commands.common.publish_via_kokoro(ctx)

    if ctx.interactive:
        click.secho("\\o/ All done!", fg="magenta")

    return ctx
Exemple #15
0
def tag(ctx: TagContext = None) -> TagContext:
    if not ctx:
        ctx = TagContext()

    if ctx.interactive:
        click.secho(f"o/ Hey, {getpass.getuser()}, let's tag a release!",
                    fg="magenta")

    if ctx.github is None:
        releasetool.commands.common.setup_github_context(ctx)

    if ctx.release_pr is None:
        determine_release_pr(ctx)

    determine_release_tag(ctx)
    determine_package_name_and_version(ctx)

    # If the release already exists, don't do anything
    if releasetool.commands.common.release_exists(ctx):
        click.secho(f"{ctx.release_tag} already exists.", fg="magenta")
        return ctx

    get_release_notes(ctx)

    create_release(ctx)
    if "google-cloud-python" in ctx.upstream_repo:
        ctx.kokoro_job_name = f"cloud-devrel/client-libraries/google-cloud-python/release/{ctx.package_name}"
    else:
        ctx.kokoro_job_name = (
            f"cloud-devrel/client-libraries/python/{ctx.upstream_repo}/release/release"
        )
    releasetool.commands.common.publish_via_kokoro(ctx)

    if ctx.interactive:
        click.secho(f"\\o/ All done!", fg="magenta")

    return ctx
def test_extracts_appropriate_release_notes_when_prior_release_is_patch():
    """
    see: https://github.com/googleapis/release-please/issues/140
    """
    ctx = TagContext(release_version="v5.0.0")
    _get_latest_release_notes(ctx, fixture_new_style_patch)
    expected = """### ⚠ BREAKING CHANGES

* temp directory now defaults to setting for report directory

### Features

* default temp directory to report directory ([#102](https://www.github.com/bcoe/c8/issues/102)) ([8602f4a](https://www.github.com/bcoe/c8/commit/8602f4a))
* load .nycrc/.nycrc.json to simplify migration ([#100](https://www.github.com/bcoe/c8/issues/100)) ([bd7484f](https://www.github.com/bcoe/c8/commit/bd7484f))"""
    assert ctx.release_notes == expected
Exemple #17
0
def tag(ctx: TagContext = None) -> TagContext:
    if not ctx:
        ctx = TagContext()

    if ctx.interactive:
        click.secho(f"o/ Hey, {getpass.getuser()}, let's tag a release!", fg="magenta")

    if ctx.github is None:
        releasetool.commands.common.setup_github_context(ctx)

    if ctx.release_pr is None:
        determine_release_pr(ctx)

    create_releases(ctx)

    return ctx
Exemple #18
0
def tag() -> None:
    ctx = TagContext()

    click.secho(f"o/ Hey, {getpass.getuser()}, let's tag a release!", fg="magenta")

    releasetool.commands.common.setup_github_context(ctx)

    determine_release_pr(ctx)
    determine_release_tag(ctx)
    determine_package_name_and_version(ctx)
    get_release_notes(ctx)

    create_release(ctx)
    wait_on_circle(ctx)

    click.secho(f"\\o/ All done!", fg="magenta")
Exemple #19
0
def create_release(ctx: TagContext) -> None:
    click.secho("> Creating the release.")

    ctx.github_release = ctx.github.create_release(
        repository=ctx.upstream_repo,
        tag_name=ctx.release_tag,
        target_commitish=ctx.release_pr["merge_commit_sha"],
        name=ctx.release_tag,
        body=ctx.release_notes,
    )

    release_location_string = f"Release is at {ctx.github_release['html_url']}"
    click.secho(release_location_string)

    ctx.github.create_pull_request_comment(
        ctx.upstream_repo, ctx.release_pr["number"], release_location_string
    )
Exemple #20
0
def test_new_style_release_notes_breaking():
    """
    in the conventional-commits template, features/breaking-changes use an H2 header.
    """
    expected = """### Features

* added the most amazing feature ever ([42f90e2](https://www.github.com/bcoe/examples-conventional-commits/commit/42f90e2))
* adds a fancy new feature ([c46bfa3](https://www.github.com/bcoe/examples-conventional-commits/commit/c46bfa3))


### BREAKING CHANGES

* this fancy new feature breaks things
* disclaimer breaks everything"""
    ctx = TagContext(release_version="v2.0.0")
    _get_latest_release_notes(ctx, fixture_new_style_changelog)
    assert ctx.release_notes == expected
Exemple #21
0
def create_release(ctx: TagContext) -> None:
    click.secho("> Creating the release.")

    if ctx.upstream_repo in manifest_release:
        # delegate releaase tagging to release-please
        default_branch = ctx.release_pr["base"]["ref"]
        repo = ctx.release_pr["base"]["repo"]["full_name"]

        with tempfile.NamedTemporaryFile("w+t", delete=False) as fp:
            fp.write(ctx.token)
            token_file = fp.name

        subprocess.check_output([
            # TODO(sofisl): remove pinning to a specific version
            # once we've tested:
            "npx",
            "release-please",
            "manifest-release",
            f"--token={token_file}",
            f"--default-branch={default_branch}",
            f"--repo-url={repo}",
            "--debug",
        ])
    else:
        # TODO(sofisl): move the non-manifest release to release-please too
        # for consistency:
        ctx.github_release = ctx.github.create_release(
            repository=ctx.upstream_repo,
            tag_name=ctx.release_version,
            target_commitish=ctx.release_pr["merge_commit_sha"],
            name=f"{ctx.release_version}",
            body=ctx.release_notes,
        )

        release_location_string = f"Release is at {ctx.github_release['html_url']}"
        click.secho(release_location_string)
        click.secho("CI will handle publishing the package to npm.")

        ctx.github.create_pull_request_comment(ctx.upstream_repo,
                                               ctx.release_pr["number"],
                                               release_location_string)

        ctx.github.update_pull_labels(ctx.release_pr,
                                      add=["autorelease: tagged"],
                                      remove=["autorelease: pending"])
Exemple #22
0
def create_release(ctx: TagContext) -> None:
    click.secho("> Creating the release.")

    ctx.github_release = ctx.github.create_release(
        repository=ctx.upstream_repo,
        tag_name=ctx.release_tag,
        target_committish=ctx.release_pr["merge_commit_sha"],
        name=f"google-cloud-{ctx.package_name} {ctx.release_version}",
        body=ctx.release_notes,
    )

    release_location_string = f"Release is at {ctx.github_release['html_url']}"
    click.secho(release_location_string)
    click.secho("CI will handle publishing the package to PyPI.")

    ctx.github.create_pull_request_comment(
        ctx.upstream_repo, ctx.release_pr["number"], release_location_string
    )
def create_release(ctx: TagContext) -> None:
    click.secho("> Creating the release.")

    ctx.github_release = ctx.github.create_release(
        repository=ctx.upstream_repo,
        tag_name=ctx.release_tag,
        target_commitish=ctx.release_pr["merge_commit_sha"],
        name=f"{ctx.package_name} {ctx.release_version}",
        body=ctx.release_notes,
    )

    release_location_string = f"Release is at {ctx.github_release['html_url']}"
    click.secho(release_location_string)

    ctx.github.create_pull_request_comment(ctx.upstream_repo,
                                           ctx.release_pr["number"],
                                           release_location_string)

    ctx.github.update_pull_labels(ctx.release_pr,
                                  add=["autorelease: tagged"],
                                  remove=["autorelease: pending"])
Exemple #24
0
def determine_package_version(ctx: TagContext) -> None:
    click.secho("> Determining the package version.", fg="cyan")
    match = re.match(r"(?P<version>v?\d+\.\d+\.\d+)", ctx.release_tag)
    ctx.release_version = match.group("version")
    click.secho(f"package version: {ctx.release_version}.")
Exemple #25
0
def determine_package_name_and_version(ctx: TagContext) -> None:
    click.secho("> Determining the release version.", fg="cyan")
    match = re.match(r"v(\d+\.\d+\.\d+)", ctx.release_tag)
    ctx.release_version = match.group(1)
    click.secho(f"Package version: {ctx.release_version}.")
Exemple #26
0
def determine_package_version(ctx: TagContext) -> None:
    click.secho("> Determining the package version.", fg="cyan")
    # strip the leading 'v' from the tag
    ctx.release_version = re.sub(r"^v", "", ctx.release_tag)
    click.secho(f"Package version: {ctx.release_version}.")
Exemple #27
0
def get_release_notes(ctx: TagContext) -> None:
    click.secho("> Grabbing the release notes.", fg="cyan")
    ctx.release_notes = _parse_release_notes(ctx.release_pr["body"])
    click.secho(f"Release notes:\n{ctx.release_notes}")
Exemple #28
0
def determine_kokoro_job_name(ctx: TagContext) -> None:
    ctx.kokoro_job_name = (
        f"cloud-devrel/client-libraries/nodejs/release/{ctx.upstream_repo}/publish"
    )