Add workflow to automate changelog updates#790
Conversation
Reviewer's GuideAdds a reusable GitHub Actions workflow that generates and optionally PRs Debian changelog updates based on commit titles since the last changelog change, with configurable versioning, maintainer metadata, base branch, and distribution. Flow diagram for the new changelog update GitHub Actions workflowflowchart TD
trigger[[Workflow_dispatch_or_workflow_call_inputs]]
job[update_changelog_job]
checkout[Checkout_base_branch]
tools[Install_devscripts]
prepare[Prepare_changelog_data\nget_current_version / bump_version / commit_titles_since_changelog]
generate[Generate_changelog_with_dch]
decision{inputs.create_pr}
appToken[Create_GitHub_App_token]
showDiff[Show_changelog_diff]
upload[Upload_generated_changelog_artifact]
createPR[Create_pull_request]
showResult[Show_pull_request_result]
trigger --> job
job --> checkout --> tools --> prepare --> generate --> decision
decision -->|false| showDiff --> upload
decision -->|true| appToken --> createPR --> showResult
File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
There was a problem hiding this comment.
Hey - I've found 1 issue, and left some high level feedback:
- The
Create GitHub App tokenstep is conditioned only oninputs.create_pr, butAPP_ID/APP_PRIVATE_KEYare optional; consider either making these secrets required whenevercreate_pris true or adding an additionalifguard/fallback so the workflow can still create a PR usinggithub.tokenwhen app credentials are not provided. - In the
Prepare changelog datastep, the workflow assumes theGITHUB_TOKENcan always access the compare and commits APIs; you may want to add explicit error messages or handling for common API failure cases (e.g., rate limiting or permission issues) to make debugging failed runs easier.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- The `Create GitHub App token` step is conditioned only on `inputs.create_pr`, but `APP_ID`/`APP_PRIVATE_KEY` are optional; consider either making these secrets required whenever `create_pr` is true or adding an additional `if` guard/fallback so the workflow can still create a PR using `github.token` when app credentials are not provided.
- In the `Prepare changelog data` step, the workflow assumes the `GITHUB_TOKEN` can always access the compare and commits APIs; you may want to add explicit error messages or handling for common API failure cases (e.g., rate limiting or permission issues) to make debugging failed runs easier.
## Individual Comments
### Comment 1
<location path=".github/workflows/update-changelog.yml" line_range="157-166" />
<code_context>
+ parts[-1] = str(int(parts[-1]) + 1)
+ return epoch + ".".join(parts)
+
+ def github_get(url):
+ headers = {
+ "Accept": "application/vnd.github+json",
+ "X-GitHub-Api-Version": "2022-11-28",
+ "User-Agent": "deepin-autopack-update-changelog",
+ "Authorization": f"Bearer {os.environ['GITHUB_TOKEN']}",
+ }
+ req = urllib.request.Request(url, headers=headers)
+ with urllib.request.urlopen(req, timeout=30) as resp:
+ body = resp.read().decode("utf-8")
+ data = json.loads(body) if body else None
+ resp_headers = {k.lower(): v for k, v in resp.headers.items()}
+ return data, resp_headers
+
+ def parse_link_header(value):
</code_context>
<issue_to_address>
**suggestion:** Lack of explicit error handling for GitHub API responses can make failures opaque and harder to debug.
Since failures will surface only as a generic `urllib.error.HTTPError`, consider wrapping the call in a `try/except` for `HTTPError` and re-raising a `RuntimeError` that includes the status code, URL, and a truncated response body. That will make CI failures easier to diagnose (e.g., rate limits vs auth/permission issues).
Suggested implementation:
```
def github_get(url):
headers = {
"Accept": "application/vnd.github+json",
"X-GitHub-Api-Version": "2022-11-28",
"User-Agent": "deepin-autopack-update-changelog",
"Authorization": f"Bearer {os.environ['GITHUB_TOKEN']}",
}
req = urllib.request.Request(url, headers=headers)
try:
with urllib.request.urlopen(req, timeout=30) as resp:
body = resp.read().decode("utf-8")
data = json.loads(body) if body else None
resp_headers = {k.lower(): v for k, v in resp.headers.items()}
return data, resp_headers
except urllib.error.HTTPError as e:
# Read and safely decode error body (may be helpful for diagnosing rate limits, auth issues, etc.)
error_body_bytes = getattr(e, "fp", None).read() if getattr(e, "fp", None) is not None else b""
error_body = error_body_bytes.decode("utf-8", errors="replace") if error_body_bytes else ""
max_len = 500
truncated_body = (error_body[:max_len] + "...") if len(error_body) > max_len else error_body
raise RuntimeError(
f"GitHub API request failed (status {e.code}) for {url}: {truncated_body}"
) from e
```
To make this work you also need to ensure `urllib.error` (or specifically `HTTPError`) is imported in the Python section of the workflow. If you currently have `import urllib.request` only, either add `import urllib.error` or change it to `import urllib.request, urllib.error`. The exact edit will depend on where and how imports are declared in the existing script.
</issue_to_address>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
BLumia
left a comment
There was a problem hiding this comment.
sourceryai 的 review 可以瞅瞅,另外可以让 cicd 组那边也看看
98dbbe2 to
da0140f
Compare
ok AI的建议有必要,我已经增加错误处理 |
This workflow automates the process of updating the changelog based on commits since the last changelog entry. It includes options for versioning, maintainer details, and creating a pull request for the updated changelog. Log: add changelog-update changelog
deepin pr auto review★ 总体评分:60分■ 【总体评价】
■ 【详细分析】
■ 【改进建议代码示例】 # 修复 Generate changelog 步骤中的 Changelog 格式注入漏洞
import json
import os
import re
import subprocess
def sanitize_changelog_input(value: str) -> str:
"""移除换行符及控制字符,防止 Changelog 格式注入"""
if not value:
return value
# 移除 \r, \n 及其他 ASCII 控制字符
return re.sub(r'[\r\n\x00-\x1f\x7f]', '', value)
version = sanitize_changelog_input(os.environ["VERSION"].strip())
distribution = sanitize_changelog_input(os.environ["DISTRIBUTION"].strip() or "unstable")
# 对维护者信息同样进行清洗
os.environ["DEBFULLNAME"] = sanitize_changelog_input(os.environ.get("DEBFULLNAME", ""))
os.environ["DEBEMAIL"] = sanitize_changelog_input(os.environ.get("DEBEMAIL", ""))
titles = json.loads(os.environ["TITLES_JSON"])
if not titles:
titles = [f"Release {version}"]
# 使用列表形式传参,防止 Shell 注入
subprocess.run(
["dch", "-v", version, "-D", distribution, titles[0]],
check=True,
)
for title in titles[1:]:
# commit message 来源相对可信,但为防御性编程也可做清洗
safe_title = sanitize_changelog_input(title)
subprocess.run(["dch", "-a", safe_title], check=True) |
触发 action是需要有权限用户才可以的,通常是项目maintainer,另外生成的PR是需要maintainer审核的,不能直接合入。所以可以忽略这种注入 |
|
[APPROVALNOTIFIER] This PR is NOT APPROVED This pull-request has been approved by: BLumia, hudeng-go, mhduiy The full list of commands accepted by this bot can be found here. DetailsNeeds approval from an approver in each of these files:Approvers can indicate their approval by writing |
This workflow automates the process of updating the changelog based on commits since the last changelog entry. It includes options for versioning, maintainer details, and creating a pull request for the updated changelog.
这个可复用 workflow 用于自动更新 Debian
debian/changelog。它会在目标基础分支上查找最近一次修改
debian/changelog的提交,收集该提交之后的提交标题,并使用dch生成新的 changelog 条目。目标版本号可以通过version输入手动指定。如果没有指定version,workflow 会尝试自动递增简单的数字版本号,例如1.2.3、1:1.2.3或1.2.3-1。对于
1.2.3~rc1、1.2.3a、1.2.3+deepin这类复杂 Debian 版本号,workflow 不会猜测下一个版本号,而是会给出明确错误,并要求调用方显式传入version。主要功能:
暂时只给 dde 和 treeland维护的项目增加这个workflow
自动提升版本号的功能没有办法覆盖所有情况,一定要仔细甄别PR的版本号是否合理
Summary by Sourcery
Add a reusable GitHub Actions workflow to automatically update the Debian changelog from recent commit titles and optionally open a pull request with the changes.
New Features:
Enhancements: