Skip to content

Commit a77bff0

Browse files
committed
chore(dev/release): add changelog generator
Fixes #2452.
1 parent 74a09a3 commit a77bff0

File tree

10 files changed

+493
-29
lines changed

10 files changed

+493
-29
lines changed

.github/workflows/dev_adbc.yml

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
# Licensed to the Apache Software Foundation (ASF) under one
2+
# or more contributor license agreements. See the NOTICE file
3+
# distributed with this work for additional information
4+
# regarding copyright ownership. The ASF licenses this file
5+
# to you under the Apache License, Version 2.0 (the
6+
# "License"); you may not use this file except in compliance
7+
# with the License. You may obtain a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing,
12+
# software distributed under the License is distributed on an
13+
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
# KIND, either express or implied. See the License for the
15+
# specific language governing permissions and limitations
16+
# under the License.
17+
18+
name: Dev ADBC
19+
20+
on:
21+
pull_request:
22+
branches:
23+
- main
24+
paths:
25+
- "dev/**"
26+
- ".github/workflows/dev_adbc.yml"
27+
push:
28+
paths:
29+
- "dev/**"
30+
- ".github/workflows/dev_adbc.yml"
31+
32+
concurrency:
33+
group: ${{ github.repository }}-${{ github.ref }}-${{ github.workflow }}
34+
cancel-in-progress: true
35+
36+
permissions:
37+
contents: read
38+
39+
defaults:
40+
run:
41+
# 'bash' will expand to -eo pipefail
42+
shell: bash
43+
44+
jobs:
45+
pre-commit:
46+
name: "pre-commit"
47+
runs-on: ubuntu-latest
48+
steps:
49+
- uses: actions/checkout@v4
50+
with:
51+
fetch-depth: 0
52+
persist-credentials: false
53+
54+
- name: Cache Conda
55+
uses: actions/cache@v4
56+
with:
57+
path: ~/conda_pkgs_dir
58+
key: conda-${{ runner.os }}-${{ steps.get-date.outputs.today }}-${{ env.CACHE_NUMBER }}-${{ hashFiles('ci/**') }}
59+
- uses: conda-incubator/setup-miniconda@v3
60+
with:
61+
miniforge-version: latest
62+
use-only-tar-bz2: false
63+
use-mamba: true
64+
65+
- name: Install Dependencies
66+
run: |
67+
mamba install -c conda-forge \
68+
--file ci/conda_env_dev.txt
69+
70+
- name: Test
71+
run: |
72+
pytest -vv dev/adbc_dev/

.github/workflows/dev_pr.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ jobs:
6363
env:
6464
PR_TITLE: ${{ github.event.pull_request.title }}
6565
run: |
66-
python .github/workflows/dev_pr/title_check.py $(pwd)/pr_checkout "$PR_TITLE"
66+
python dev/adbc_dev/title_check.py $(pwd)/pr_checkout "$PR_TITLE"
6767
6868
# Pings make it into the commit message where they annoy the user every
6969
# time the commit gets pushed somewhere

ci/conda_env_dev.txt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,10 @@
1515
# specific language governing permissions and limitations
1616
# under the License.
1717

18-
commitizen
1918
gh>=2.32.0
2019
jq
2120
pre-commit
21+
pygit2
22+
python
23+
python-dotenv
2224
twine

dev/adbc_dev/__init__.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# Licensed to the Apache Software Foundation (ASF) under one
2+
# or more contributor license agreements. See the NOTICE file
3+
# distributed with this work for additional information
4+
# regarding copyright ownership. The ASF licenses this file
5+
# to you under the Apache License, Version 2.0 (the
6+
# "License"); you may not use this file except in compliance
7+
# with the License. You may obtain a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing,
12+
# software distributed under the License is distributed on an
13+
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
# KIND, either express or implied. See the License for the
15+
# specific language governing permissions and limitations
16+
# under the License.

dev/adbc_dev/changelog.py

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
#!/usr/bin/env python3
2+
# Licensed to the Apache Software Foundation (ASF) under one
3+
# or more contributor license agreements. See the NOTICE file
4+
# distributed with this work for additional information
5+
# regarding copyright ownership. The ASF licenses this file
6+
# to you under the Apache License, Version 2.0 (the
7+
# "License"); you may not use this file except in compliance
8+
# with the License. You may obtain a copy of the License at
9+
#
10+
# http://www.apache.org/licenses/LICENSE-2.0
11+
#
12+
# Unless required by applicable law or agreed to in writing,
13+
# software distributed under the License is distributed on an
14+
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
# KIND, either express or implied. See the License for the
16+
# specific language governing permissions and limitations
17+
# under the License.
18+
19+
"""Generate a changelog from our commit log."""
20+
21+
import argparse
22+
import datetime
23+
import sys
24+
from pathlib import Path
25+
26+
import dotenv
27+
import pygit2
28+
29+
from . import title_check
30+
31+
32+
def display(*args, **kwargs):
33+
print(*args, file=sys.stderr, **kwargs)
34+
35+
36+
def get_commit(repo: pygit2.Repository, rev: str) -> pygit2.Oid:
37+
try:
38+
return repo.lookup_reference_dwim(rev).target
39+
except KeyError:
40+
return repo[rev].id
41+
42+
43+
def list_commits(
44+
repo: pygit2.Repository, from_rev: str, to_rev: str
45+
) -> list[title_check.Commit]:
46+
root = Path(repo.workdir)
47+
from_commit = get_commit(repo, from_rev)
48+
to_commit = get_commit(repo, to_rev)
49+
walker = repo.walk(to_commit, pygit2.GIT_SORT_TIME)
50+
walker.hide(from_commit)
51+
commits = []
52+
for commit in walker:
53+
title = commit.message.strip().split("\n")[0]
54+
commits.append(title_check.matches_commit_format(root, title))
55+
return commits
56+
57+
58+
def format_commit(commit: title_check.Commit) -> str:
59+
components = ""
60+
warning = ""
61+
if commit.components:
62+
components = f"**{', '.join(commit.components)}**: "
63+
if commit.breaking_change:
64+
warning = "⚠️ "
65+
return f"{warning}{components}{commit.subject}"
66+
67+
68+
def format_section(title: str, commits: list[title_check.Commit]) -> list[str]:
69+
if not commits:
70+
return []
71+
72+
lines = [f"### {title}", ""]
73+
commits.sort(key=lambda commit: (commit.components, commit.subject))
74+
lines.extend(f"- {format_commit(commit)}" for commit in commits)
75+
lines.append("")
76+
return lines
77+
78+
79+
def format_changelog(
80+
title: str, release: dict[str, str], commits: list[title_check.Commit]
81+
) -> str:
82+
date = datetime.date.today().strftime("%Y-%m-%d")
83+
lines = [
84+
f"## {title} ({date})",
85+
"",
86+
"### Versions",
87+
"",
88+
f"- C/C++/GLib/Go/Python/Ruby: {release['VERSION_NATIVE']}",
89+
f"- C#: {release['VERSION_CSHARP']}",
90+
f"- Java: {release['VERSION_JAVA']}",
91+
f"- R: {release['VERSION_R']}",
92+
f"- Rust: {release['VERSION_RUST']}",
93+
"",
94+
]
95+
96+
breaking = [commit for commit in commits if commit.breaking_change]
97+
lines.extend(format_section("Breaking Changes", breaking))
98+
99+
feat = [commit for commit in commits if commit.category == "feat"]
100+
lines.extend(format_section("New Features", feat))
101+
102+
fix = [commit for commit in commits if commit.category == "fix"]
103+
lines.extend(format_section("Bugfixes", fix))
104+
105+
docs = [commit for commit in commits if commit.category == "docs"]
106+
lines.extend(format_section("Documentation Improvements", docs))
107+
108+
perf = [commit for commit in commits if commit.category == "perf"]
109+
lines.extend(format_section("Performance Improvements", perf))
110+
111+
return "\n".join(lines)
112+
113+
114+
def main():
115+
parser = argparse.ArgumentParser(description=__doc__)
116+
parser.add_argument("from_rev", help="The start revision.")
117+
parser.add_argument("to_rev", help="The end revision.")
118+
parser.add_argument("--name", required=True, help="The name of the release.")
119+
120+
args = parser.parse_args()
121+
122+
repo_root = Path(__file__).parent.parent.parent.resolve()
123+
release = dotenv.dotenv_values(repo_root / "dev/release/versions.env")
124+
display("Opening repository at", repo_root)
125+
repo = pygit2.Repository(repo_root)
126+
127+
commits = list_commits(repo, args.from_rev, args.to_rev)
128+
changelog = format_changelog(args.name, release, commits)
129+
print(changelog)
130+
131+
return 0
132+
133+
134+
if __name__ == "__main__":
135+
sys.exit(main())

dev/adbc_dev/tests/__init__.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# Licensed to the Apache Software Foundation (ASF) under one
2+
# or more contributor license agreements. See the NOTICE file
3+
# distributed with this work for additional information
4+
# regarding copyright ownership. The ASF licenses this file
5+
# to you under the Apache License, Version 2.0 (the
6+
# "License"); you may not use this file except in compliance
7+
# with the License. You may obtain a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing,
12+
# software distributed under the License is distributed on an
13+
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
# KIND, either express or implied. See the License for the
15+
# specific language governing permissions and limitations
16+
# under the License.

0 commit comments

Comments
 (0)