Skip to content

Commit

Permalink
Add capability to gather the git commit log since the last release (#357
Browse files Browse the repository at this point in the history
)

Add capability to gather the commit log since the last release and use that to start the release notes.

Warning: This is experimental.

- Add a git toolchain
  - It gets the path to the git binary and the path to your source tree
  - therefore it can only be used locally.
  - Fixes #257
- Add a `git_changelog()` rule that will run git to get the change log.
  - Advances #228
- Change print_relnotes to accept a changelog file, instead of running git locally.

Next steps:
- Add the capability to reduce the change log from everything to only
  the commits that have RELNOTES sections.
  • Loading branch information
aiuto authored Jul 6, 2021
1 parent 70757da commit 486107d
Show file tree
Hide file tree
Showing 12 changed files with 475 additions and 8 deletions.
1 change: 1 addition & 0 deletions pkg/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ constraint_setting(name = "not_compatible_setting")
constraint_value(
name = "not_compatible",
constraint_setting = ":not_compatible_setting",
visibility = ["//visibility:public"],
)

filegroup(
Expand Down
8 changes: 8 additions & 0 deletions pkg/WORKSPACE
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,14 @@ find_system_rpmbuild(
verbose = True,
)

# Needed for making our release notes
load("@rules_pkg//toolchains/git:git_configure.bzl", "experimental_find_system_git")

experimental_find_system_git(
name = "rules_pkg_git",
verbose = True,
)

http_archive(
name = "bazel_stardoc",
sha256 = "36b8d6c2260068b9ff82faea2f7add164bf3436eac9ba3ec14809f335346d66a",
Expand Down
7 changes: 7 additions & 0 deletions pkg/distro/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
load("//:pkg.bzl", "pkg_tar")
load("//:version.bzl", "version")
load("//releasing:defs.bzl", "print_rel_notes")
load("//releasing:git.bzl", "git_changelog")
load("@bazel_skylib//:bzl_library.bzl", "bzl_library")
load("@bazel_stardoc//stardoc:stardoc.bzl", "stardoc")
load("@rules_python//python:defs.bzl", "py_test")
Expand Down Expand Up @@ -59,13 +60,19 @@ genrule(
print_rel_notes(
name = "relnotes",
outs = ["relnotes.txt"],
changelog = ":changelog",
deps_method = "rules_pkg_dependencies",
mirror_host = "mirror.bazel.build",
org = "bazelbuild",
repo = "rules_pkg",
version = version,
)

git_changelog(
name = "changelog",
out = "changelog.txt",
)

py_test(
name = "packaging_test",
size = "large",
Expand Down
14 changes: 13 additions & 1 deletion pkg/releasing/BUILD
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
load("@rules_python//python:defs.bzl", "py_binary", "py_library", "py_test")
load("git.bzl", "git_changelog")

licenses(["notice"])

package(
default_visibility = ["//visibility:public"],
)

# WARNING: 2019-08-05. This is experimental and subject to change.
# WARNING: 2021-06-28. This is experimental and subject to change.

# Sample usage:
# load("@rules_pkg//releasing:defs.bzl", "print_rel_notes")
Expand Down Expand Up @@ -55,3 +56,14 @@ py_test(
":release_utils",
],
)

# This is an internal tool. Use at your own risk.
py_binary(
name = "git_changelog_private",
srcs = [
"git_changelog_private.py",
],
srcs_version = "PY3",
# TODO(https://github.com/bazelbuild/bazel/issues/7377): Make this private.
visibility = ["//visibility:public"],
)
18 changes: 13 additions & 5 deletions pkg/releasing/defs.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ def print_rel_notes(
deps_method = "",
toolchains_method = "",
org = "bazelbuild",
changelog = None,
mirror_host = None):
tarball_name = ":%s-%s.tar.gz" % (repo, version)
cmd = [
Expand All @@ -16,23 +17,30 @@ def print_rel_notes(
"--version=%s" % version,
"--tarball=$(location %s)" % tarball_name,
]
tools = ["//releasing:print_rel_notes"]
if setup_file:
cmd.append("--setup_file=%s" % setup_file)
if deps_method:
cmd.append("--deps_method=%s" % deps_method)
if toolchains_method:
cmd.append("--toolchains_method=%s" % toolchains_method)
if changelog:
cmd.append("--changelog=$(location %s)" % changelog)
# We should depend on a changelog as a tool so that it is always built
# for the host configuration. If the changelog is generated on the fly,
# then we would have to run commands against our revision control
# system. That only makes sense locally on the host, because the
# revision history is never exported to a remote build system.
tools.append(changelog)
if mirror_host:
cmd.append("--mirror_host=%s" % mirror_host)
cmd.append(">$@")
native.genrule(
name = "relnotes",
name = name,
srcs = [
tarball_name,
],
outs = outs or ["relnotes.txt"],
outs = outs or [name + ".txt"],
cmd = " ".join(cmd),
tools = [
"//releasing:print_rel_notes",
],
tools = tools,
)
96 changes: 96 additions & 0 deletions pkg/releasing/git.bzl
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
# Copyright 2021 The Bazel Authors. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""A rule to extract the git changelog."""

def _git_changelog_impl(ctx):
"""Implements to git_changelog rule."""

args = ctx.actions.args()
tools = []

toolchain = ctx.toolchains["@rules_pkg//toolchains/git:git_toolchain_type"].git
if not toolchain.valid:
fail("The git_toolchain is not properly configured: " +
toolchain.name)
if toolchain.path:
args.add("--git_path", toolchain.path)
else:
executable = toolchain.label.files_to_run.executable
tools.append(executable)
tools.append(toolchain.label.default_runfiles.files.to_list())
args.add("--git_path", executable.path)
args.add("--git_root", toolchain.client_top)
args.add("--from_ref", ctx.attr.from_ref)
args.add("--to_ref", ctx.attr.to_ref)
args.add("--out", ctx.outputs.out.path)
if ctx.attr.verbose:
args.add("--verbose")

ctx.actions.run(
mnemonic = "GitChangelog",
executable = ctx.executable._git_changelog,
use_default_shell_env = True,
arguments = [args],
outputs = [ctx.outputs.out],
env = {
"LANG": "en_US.UTF-8",
"LC_CTYPE": "UTF-8",
"PYTHONIOENCODING": "UTF-8",
"PYTHONUTF8": "1",
},
execution_requirements = {
"local": "1",
},
tools = tools,
)

# Define the rule.
_git_changelog = rule(
doc = "Extracts the git changelog between two refs.",
attrs = {
"from_ref": attr.string(
doc = "lower commit ref. The default is to use the latest tag",
default = "_LATEST_TAG_",
),
"to_ref": attr.string(
doc = "upper commit ref. The default is HEAD",
default = "HEAD",
),
"out": attr.output(mandatory = True),
"verbose": attr.bool(
doc = "Be verbose",
default = False,
),
"_git_changelog": attr.label(
default = Label("//releasing:git_changelog_private"),
cfg = "exec",
executable = True,
allow_files = True,
),
},
implementation = _git_changelog_impl,
toolchains = ["@rules_pkg//toolchains/git:git_toolchain_type"],
)


def git_changelog(name, **kwargs):
_git_changelog(
name = name,
# This requires bazel 4.x
target_compatible_with = select({
"//toolchains/git:have_git": [],
"//conditions:default": ["//:not_compatible"],
}),
**kwargs,
)
72 changes: 72 additions & 0 deletions pkg/releasing/git_changelog_private.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
# Copyright 2021 The Bazel Authors. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Utilities to extract git commit descriptions in useful ways."""

import argparse
import os
import subprocess
import sys


def guess_previous_release_tag(git_path, pattern=None):
assert git_path
most_recent = None
cmd = [git_path, 'tag']
if pattern:
cmd.extend(['--list', pattern])
# We are doing something dumb here for now. Grab the list of tags, and pick
# the last one.
with subprocess.Popen(cmd, stdout=subprocess.PIPE) as proc:
most_recent = proc.stdout.read().decode('utf-8')
most_recent = most_recent.strip().replace('\n\n', '\n').split('\n')[-1]
return most_recent


def git_changelog(from_ref, to_ref='HEAD', git_path=None):
assert from_ref
assert to_ref
assert git_path
cmd = [git_path, 'log', '%s..%s' % (from_ref, to_ref)]
with subprocess.Popen(cmd, stdout=subprocess.PIPE) as proc:
return proc.stdout.read().decode('utf-8')


def main():
parser = argparse.ArgumentParser(
description='Helper for extracting git changelog',
fromfile_prefix_chars='@')
parser.add_argument('--git_path', required=True, help='path to git binary')
parser.add_argument('--git_root', required=True, help='path to git client')
parser.add_argument('--out', required=True, help='output path')
parser.add_argument('--from_ref', help='from REF')
parser.add_argument('--to_ref', help='to REF')
parser.add_argument('--verbose', action='store_true')

options = parser.parse_args()

with open(options.out, 'w', encoding='utf-8') as out:
os.chdir(options.git_root)
from_ref = options.from_ref
if not from_ref or from_ref == '_LATEST_TAG_':
from_ref = guess_previous_release_tag(options.git_path)
to_ref = options.to_ref or 'HEAD'
if options.verbose:
print('Getting changelog from %s to %s' % (from_ref, to_ref))
changelog = git_changelog(
from_ref=from_ref, to_ref=to_ref, git_path=options.git_path)
out.write(changelog)
return 0

if __name__ == '__main__':
main()
19 changes: 17 additions & 2 deletions pkg/releasing/print_rel_notes.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@


def print_notes(org, repo, version, tarball_path, mirror_host=None,
deps_method=None, setup_file=None, toolchains_method=None):
deps_method=None, setup_file=None, toolchains_method=None,
changelog=''):
file_name = release_tools.package_basename(repo, version)
sha256 = release_tools.get_package_sha256(tarball_path)

Expand All @@ -42,6 +43,9 @@ def print_notes(org, repo, version, tarball_path, mirror_host=None,
**Incompatible Changes**
**Change Log**
${changelog}
**WORKSPACE setup**
```
Expand All @@ -55,6 +59,7 @@ def print_notes(org, repo, version, tarball_path, mirror_host=None,
""").strip())
print(relnotes_template.substitute({
'changelog': changelog,
'org': org,
'repo': repo,
'version': version,
Expand Down Expand Up @@ -100,7 +105,7 @@ def main():
required=True, help='path to release tarball')
parser.add_argument(
'--mirror_host', default=None,
help='If provider, the hostname of a mirror for the download url.')
help='If provider, the hostname of a mirror for the download url')
parser.add_argument(
'--setup_file', default=None,
help='Alternate name for setup file. Default: deps.bzl')
Expand All @@ -110,10 +115,20 @@ def main():
parser.add_argument(
'--toolchains_method', default=None,
help='Alternate name for toolchains method. Default: {repo}_toolchains')
parser.add_argument(
'--changelog', default=None,
help='Pre-fill release notes with changes from this file')

options = parser.parse_args()
if options.changelog:
with open(options.changelog, 'r', encoding='utf-8') as f:
changelog = f.read()
else:
changelog = 'TBD'

print_notes(options.org, options.repo, options.version, options.tarball_path,
deps_method=options.deps_method,
changelog=changelog,
mirror_host=options.mirror_host,
setup_file=options.setup_file,
toolchains_method=options.toolchains_method)
Expand Down
Loading

0 comments on commit 486107d

Please sign in to comment.