From 5095d836c00ccfd66ceb4f7e38c3e25b9636fd27 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=BB=9B=E4=BA=BD?= <83791825+Soltus@users.noreply.github.com> Date: Tue, 7 May 2024 22:13:59 +0800 Subject: [PATCH] =?UTF-8?q?=F0=9F=8E=A8=20=E6=9B=B4=E6=96=B0=20parse-chang?= =?UTF-8?q?elog=20=E5=B7=A5=E4=BD=9C=E6=B5=81=20(#11289)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/cd.yml | 10 +++-- .gitignore | 3 ++ scripts/_pkg/Const.py | 19 ++++++++ scripts/_pkg/Utils.py | 61 +++++++++++++++++++++++++ scripts/_pkg/__init__.py | 8 ++++ scripts/parse-changelog-HEAD.py | 29 ++++++++++++ scripts/parse-changelog.py | 79 ++++----------------------------- 7 files changed, 135 insertions(+), 74 deletions(-) create mode 100644 scripts/_pkg/Const.py create mode 100644 scripts/_pkg/Utils.py create mode 100644 scripts/_pkg/__init__.py create mode 100644 scripts/parse-changelog-HEAD.py diff --git a/.github/workflows/cd.yml b/.github/workflows/cd.yml index 3f2c8afeb..7626ebfd4 100644 --- a/.github/workflows/cd.yml +++ b/.github/workflows/cd.yml @@ -29,10 +29,10 @@ jobs: - name: Setup Python uses: actions/setup-python@v5 with: - python-version: "3.10" + python-version: "3.11" - run: pip install PyGithub - - - id: thislatestR + + - id: thisLatestRelease uses: pozetroninc/github-action-get-latest-release@master with: # owner: siyuan-note @@ -46,9 +46,11 @@ jobs: run: | echo "release_title=$(git show --format=%s --no-patch | head -1)" >> $GITHUB_OUTPUT echo "release_version=$(TZ=Asia/Shanghai date +'v%Y%m%d%H%M')" >> $GITHUB_OUTPUT - changelog=$(python scripts/parse-changelog.py -t ${{ github.ref }} -b ${{ steps.thislatestR.outputs.release }} ${{ env.repo_owner }}/${{ env.repo_name }}) + changelog_header=$(python scripts/parse-changelog-HEAD.py -t ${{ github.ref }} -b ${{ steps.thisLatestRelease.outputs.release }} ${{ env.repo_owner }}/${{ env.repo_name }}) + changelog=$(python scripts/parse-changelog.py -t ${{ github.ref }} ${{ env.repo_owner }}/${{ env.repo_name }}) EOF=$(dd if=/dev/urandom bs=15 count=1 status=none | base64) echo "release_body<<$EOF" >> $GITHUB_ENV + echo "$changelog_header" >> $GITHUB_ENV echo "$changelog" >> $GITHUB_ENV echo "$EOF" >> $GITHUB_ENV env: diff --git a/.gitignore b/.gitignore index beff8f1d9..7352184b3 100644 --- a/.gitignore +++ b/.gitignore @@ -38,3 +38,6 @@ lerna-debug.log* # NPM Package package-lock.json yarn.lock + +# workflows +**/__pycache__ diff --git a/scripts/_pkg/Const.py b/scripts/_pkg/Const.py new file mode 100644 index 000000000..81806a78c --- /dev/null +++ b/scripts/_pkg/Const.py @@ -0,0 +1,19 @@ +docmap_siyuan = { + "Feature": "Feature", + "Enhancement": "Enhancement", + "Bug": "Bugfix", + "Document": "Document", + "Refactor": "Refactor", + "Abolishment": "Abolishment", + "Development": "Development", +} + +repo_siyuan = "siyuan-note/siyuan" +hostname = "api.github.com" + +HEADER_siyuan = ''' +''' + +HEADER = { + "siyuan-note/siyuan": HEADER_siyuan, +} diff --git a/scripts/_pkg/Utils.py b/scripts/_pkg/Utils.py new file mode 100644 index 000000000..ad34b4dd8 --- /dev/null +++ b/scripts/_pkg/Utils.py @@ -0,0 +1,61 @@ +import re + +def find_milestone(repo, title, len=0): + """Find the milestone in a repository that is similar to milestone title + + Args: + repo (github.repository.Repository): The repository to search + title (str): the title to match + len: 版本号长度限制,默认 0 不限制 + + Returns: + The milestone which title matches the given argument. + If no milestone matches, it will return None + """ + thisRelease = title.split("/")[-1] + pat = re.search("v([0-9.]+)", thisRelease) + if not pat: + return None + if len > 0: + version = ".".join(pat.group(1).split(".")[:len]) + else: + version = ".".join(pat.group(1).split(".")[:]) + + # REF https://docs.github.com/en/rest/issues/milestones?apiVersion=2022-11-28#list-milestones + for milestone in repo.get_milestones(state="all"): + if version in milestone.title: + return milestone + +def generate_msg(desc_mapping, docmap): + """Print changelogs from direction.""" + print() + for header in docmap: + if not desc_mapping[header]: + continue + print(f"#### {docmap[header]}\n") + for item in desc_mapping[header]: + print(f"* [{item['title']}]({item['url']})") + print() + +def get_issue_first_label(issue, docmap): + """Get the first label from issue, if no labels, return empty string.""" + for label in issue.get_labels(): + if label.name in docmap: + return label.name + return "" + +def generate_header_from_repo(repo_name, tag_name, lastestRelease, action_file, HEADER=''): + thisRelease = tag_name.split("/")[-1] + pat = re.search("v([0-9.]+)", thisRelease) + if not pat: + return None + + return f''' +--- +
+ +{HEADER}''' diff --git a/scripts/_pkg/__init__.py b/scripts/_pkg/__init__.py new file mode 100644 index 000000000..ac8f810c8 --- /dev/null +++ b/scripts/_pkg/__init__.py @@ -0,0 +1,8 @@ +import os,sys +if os.path.abspath(os.path.dirname(__file__)) not in sys.path: + sys.path.append(os.path.abspath(os.path.dirname(__file__))) +PY_DIR = os.path.abspath(os.path.dirname(sys.executable)) +PYSPP = os.path.abspath(os.path.join(PY_DIR,'Lib', 'site-packages')) +if PY_DIR not in sys.path: + sys.path.append(PY_DIR) + sys.path.append(PYSPP) diff --git a/scripts/parse-changelog-HEAD.py b/scripts/parse-changelog-HEAD.py new file mode 100644 index 000000000..f22ad4f8e --- /dev/null +++ b/scripts/parse-changelog-HEAD.py @@ -0,0 +1,29 @@ +import os +import re +from argparse import ArgumentParser +from _pkg import Const as C +from _pkg import Utils as U + +def generate_msg_from_repo(repo_name, tag_name, lastestRelease): + thisRelease = tag_name.split("/")[-1] + pat = re.search("v([0-9.]+)", thisRelease) + if not pat: + return None + + action_file = "cd.yml" + print(U.generate_header_from_repo(repo_name, tag_name, lastestRelease, action_file, C.HEADER[repo_name])) + + +if __name__ == "__main__": + parser = ArgumentParser( + description="Automaticly generate information from issues by tag." + ) + parser.add_argument("-t", "--tag", help="the tag to filter issues.") + parser.add_argument("-b", "--lastestRelease", help="lastest Release") + parser.add_argument("repo", help="The repository name") + args = parser.parse_args() + + try: + generate_msg_from_repo(args.repo, args.tag, args.lastestRelease) + except AssertionError: + print(args.tag) diff --git a/scripts/parse-changelog.py b/scripts/parse-changelog.py index 40d6e4fda..d793b60a2 100644 --- a/scripts/parse-changelog.py +++ b/scripts/parse-changelog.py @@ -2,21 +2,11 @@ import os import re from argparse import ArgumentParser from collections import defaultdict +from _pkg import Const as C +from _pkg import Utils as U +import github # type: ignore # pip install PyGithub -import github # pip install PyGithub -# ensure the milestone is open before run this -docmap = { - "Feature": "Feature", - "Enhancement": "Enhancement", - "Bug": "Bugfix", - "Document": "Document", - "Refactor": "Refactor", - "Abolishment": "Abolishment", - "Development": "Development", -} - - -def generate_msg_from_repo(repo_name, tag_name, lastestRelease): +def generate_msg_from_repo(repo_name, tag_name): """Generate changelog messages from repository and tag name. Envs: @@ -27,81 +17,30 @@ def generate_msg_from_repo(repo_name, tag_name, lastestRelease): repo_name (str): The repository name tag_name (str): the tag name """ - hostname = os.getenv("GITHUB_HOST") or "api.github.com" + hostname = os.getenv("GITHUB_HOST") or C.hostname token = os.getenv("GITHUB_TOKEN") desc_mapping = defaultdict(list) gh = github.Github(token, base_url=f"https://{hostname}") repo = gh.get_repo(repo_name) - milestone = find_milestone(repo, tag_name, lastestRelease) + milestone = U.find_milestone(repo, tag_name) for issue in repo.get_issues(state="closed", milestone=milestone): # type: ignore # REF https://pygithub.readthedocs.io/en/latest/github_objects/Issue.html#github.Issue.Issue - desc_mapping[get_issue_first_label(issue)].append( + desc_mapping[U.get_issue_first_label(issue, C.docmap_siyuan)].append( {"title": issue.title, "url": issue.html_url} ) - generate_msg(desc_mapping) - - -def find_milestone(repo, title, lastestRelease): - """Find the milestone in a repository that is similar to milestone title - - Args: - repo (github.repository.Repository): The repository to search - title (str): the title to match - - Returns: - The milestone which title matches the given argument. - If no milestone matches, it will return None - """ - pat = re.search("v([0-9.]+)", title) - thisRelease = title.split("/")[-1] - if not pat: - return None - version = pat.group(1) - print(f''' - - -''') - for milestone in repo.get_milestones(): - if version in milestone.title: - return milestone - - -def get_issue_first_label(issue): - """Get the first label from issue, if no labels, return empty string.""" - for label in issue.get_labels(): - if label.name in docmap: - return label.name - return "" - - -def generate_msg(desc_mapping): - """Print changelogs from direction.""" - print() - for header in docmap: - if not desc_mapping[header]: - continue - print(f"### {docmap[header]}\n") - for item in desc_mapping[header]: - print(f"* [{item['title']}]({item['url']})") - print() - + U.generate_msg(desc_mapping, C.docmap_siyuan) if __name__ == "__main__": parser = ArgumentParser( description="Automaticly generate information from issues by tag." ) parser.add_argument("-t", "--tag", help="the tag to filter issues.") - parser.add_argument("-b", "--lastestRelease", help="lastest Release") parser.add_argument("repo", help="The repository name") args = parser.parse_args() try: - generate_msg_from_repo(args.repo, args.tag, args.lastestRelease) + generate_msg_from_repo(args.repo, args.tag) except AssertionError: print(args.tag)