From 7924f506ca815e7b8c3d7964f9806d37f7ad794e Mon Sep 17 00:00:00 2001 From: Serene-Arc <33189705+Serene-Arc@users.noreply.github.com> Date: Mon, 16 Oct 2023 13:56:37 +1000 Subject: [PATCH 1/7] Add release workflow --- .github/workflows/make_release.yaml | 74 +++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) create mode 100644 .github/workflows/make_release.yaml diff --git a/.github/workflows/make_release.yaml b/.github/workflows/make_release.yaml new file mode 100644 index 0000000000..96350643f7 --- /dev/null +++ b/.github/workflows/make_release.yaml @@ -0,0 +1,74 @@ +name: Make a Beets Release + +on: + workflow_dispatch: + inputs: + version: + description: 'Version of the new release' + required: true + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Set up Python + uses: actions/setup-python@v4 + with: + python-version: "3.x" + - name: Install pypa/build + run: >- + python3 -m + pip install + build + --user + - name: Build a binary wheel and a source tarball + run: python3 -m build + - name: Store the distribution packages + uses: actions/upload-artifact@v3 + with: + name: python-package-distributions + path: dist/ + + make_github_release: + runs-on: ubuntu-latest + needs: build + steps: + - uses: actions/checkout@v2 + - name: Bump version and push tag + id: tag_version + uses: mathieudutour/github-tag-action@v6.1 + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + custom_tag: ${{ inputs.version }} + - name: Download all the dists + uses: actions/download-artifact@v3 + with: + name: python-package-distributions + path: dist/ + - name: Create a GitHub release + uses: ncipollo/release-action@v1 + with: + tag: ${{ steps.tag_version.outputs.new_tag }} + name: Release ${{ steps.tag_version.outputs.new_tag }} + body: ${{ steps.tag_version.outputs.changelog }} + artifacts: dist/ + + publish_to_pypi: + runs-on: ubuntu-latest + needs: build + environment: + name: pypi + url: https://pypi.org/p/beets + permissions: + id-token: write + steps: + - name: Download all the dists + uses: actions/download-artifact@v3 + with: + name: python-package-distributions + path: dist/ + - name: Publish distribution 📦 to PyPI + uses: pypa/gh-action-pypi-publish@release/v1 + + \ No newline at end of file From 860f096fcd06f636337e51d1792ef0bef4fb7bb4 Mon Sep 17 00:00:00 2001 From: Serene-Arc <33189705+Serene-Arc@users.noreply.github.com> Date: Mon, 16 Oct 2023 14:15:17 +1000 Subject: [PATCH 2/7] Fix build bug in workflow --- .github/workflows/make_release.yaml | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/.github/workflows/make_release.yaml b/.github/workflows/make_release.yaml index 96350643f7..7157eb236a 100644 --- a/.github/workflows/make_release.yaml +++ b/.github/workflows/make_release.yaml @@ -15,14 +15,11 @@ jobs: - name: Set up Python uses: actions/setup-python@v4 with: - python-version: "3.x" - - name: Install pypa/build - run: >- - python3 -m - pip install - build - --user + python-version: "3.9" + - run: pip install build wheel sphinx - name: Build a binary wheel and a source tarball + env: + TZ: UTC run: python3 -m build - name: Store the distribution packages uses: actions/upload-artifact@v3 From 3c4c586fb1968c77e9bba39549555e73e07124b3 Mon Sep 17 00:00:00 2001 From: Serene-Arc <33189705+Serene-Arc@users.noreply.github.com> Date: Mon, 16 Oct 2023 14:23:02 +1000 Subject: [PATCH 3/7] Fix action version --- .github/workflows/make_release.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/make_release.yaml b/.github/workflows/make_release.yaml index 7157eb236a..cce706b3e2 100644 --- a/.github/workflows/make_release.yaml +++ b/.github/workflows/make_release.yaml @@ -31,7 +31,7 @@ jobs: runs-on: ubuntu-latest needs: build steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Bump version and push tag id: tag_version uses: mathieudutour/github-tag-action@v6.1 From 308f9f5f1c6fc9ec8b4c0c79cec16b9cd3866ea9 Mon Sep 17 00:00:00 2001 From: Serene-Arc <33189705+Serene-Arc@users.noreply.github.com> Date: Sat, 21 Oct 2023 20:05:54 +1000 Subject: [PATCH 4/7] Update script markdown export --- extra/release.py | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/extra/release.py b/extra/release.py index c3142268fb..5e08b0449c 100755 --- a/extra/release.py +++ b/extra/release.py @@ -117,16 +117,11 @@ def bump_version(version): with open(filename, "w") as f: f.write("".join(out_lines)) - # Generate bits to insert into changelog. - header_line = f"{version} (in development)" - header = "\n\n" + header_line + "\n" + "-" * len(header_line) + "\n\n" - header += "Changelog goes here!\n" - # Insert into the right place. with open(CHANGELOG) as f: contents = f.read() location = contents.find("\n\n") # First blank line. - contents = contents[:location] + header + contents[location:] + contents = contents[:location] + contents[location:] # Write back. with open(CHANGELOG, "w") as f: @@ -158,7 +153,7 @@ def get_latest_changelog(): elif started: lines.append(line) - return "".join(lines).strip() + return "".join(lines[2:]).strip() def rst2md(text): From 77b5179207fd2f62ab91abb67a6b9d6dc33af009 Mon Sep 17 00:00:00 2001 From: Serene-Arc <33189705+Serene-Arc@users.noreply.github.com> Date: Sat, 21 Oct 2023 20:19:23 +1000 Subject: [PATCH 5/7] Update release --- .github/workflows/make_release.yaml | 35 +++++++++++++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-) diff --git a/.github/workflows/make_release.yaml b/.github/workflows/make_release.yaml index cce706b3e2..7464352431 100644 --- a/.github/workflows/make_release.yaml +++ b/.github/workflows/make_release.yaml @@ -8,8 +8,34 @@ on: required: true jobs: + increment_version: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Install pandoc + run: sudo apt update && sudo apt install pandoc -y + - name: Set up Python + uses: actions/setup-python@v4 + with: + python-version: "3.9" + - name: Run version script + id: script + run: | + python extra/release.py "${{ inputs.version }}" >> changelog.txt + - name: Store the changelog + uses: actions/upload-artifact@v3 + with: + name: changelog + path: changelog.txt + - run: rm changelog.txt + - uses: EndBug/add-and-commit@v9 + name: Commit the changes + with: + message: 'Increment version numbers to ${{ inputs.version }}' + build: runs-on: ubuntu-latest + needs: increment_version steps: - uses: actions/checkout@v4 - name: Set up Python @@ -43,13 +69,18 @@ jobs: with: name: python-package-distributions path: dist/ + - name: Download the changelog + uses: actions/download-artifact@v3 + with: + name: changelog + path: changelog.txt - name: Create a GitHub release uses: ncipollo/release-action@v1 with: tag: ${{ steps.tag_version.outputs.new_tag }} name: Release ${{ steps.tag_version.outputs.new_tag }} - body: ${{ steps.tag_version.outputs.changelog }} - artifacts: dist/ + bodyFile: ./changelog.txt + artifacts: dist/* publish_to_pypi: runs-on: ubuntu-latest From 380059304653e9690e6a0538c6c5805a45bc2810 Mon Sep 17 00:00:00 2001 From: Serene-Arc <33189705+Serene-Arc@users.noreply.github.com> Date: Sat, 21 Oct 2023 21:57:30 +1000 Subject: [PATCH 6/7] Remove changelog --- .github/workflows/make_release.yaml | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/.github/workflows/make_release.yaml b/.github/workflows/make_release.yaml index 7464352431..9e24e1b9cc 100644 --- a/.github/workflows/make_release.yaml +++ b/.github/workflows/make_release.yaml @@ -21,13 +21,7 @@ jobs: - name: Run version script id: script run: | - python extra/release.py "${{ inputs.version }}" >> changelog.txt - - name: Store the changelog - uses: actions/upload-artifact@v3 - with: - name: changelog - path: changelog.txt - - run: rm changelog.txt + python extra/release.py "${{ inputs.version }}" - uses: EndBug/add-and-commit@v9 name: Commit the changes with: @@ -69,17 +63,12 @@ jobs: with: name: python-package-distributions path: dist/ - - name: Download the changelog - uses: actions/download-artifact@v3 - with: - name: changelog - path: changelog.txt - name: Create a GitHub release uses: ncipollo/release-action@v1 with: tag: ${{ steps.tag_version.outputs.new_tag }} name: Release ${{ steps.tag_version.outputs.new_tag }} - bodyFile: ./changelog.txt + body: "Check [here](https://beets.readthedocs.io/en/stable/changelog.html) for the latest changes." artifacts: dist/* publish_to_pypi: From 8c898ce52457fffaa44fafe705a6486fb2aef62c Mon Sep 17 00:00:00 2001 From: Serene-Arc <33189705+Serene-Arc@users.noreply.github.com> Date: Fri, 27 Oct 2023 17:58:47 +1000 Subject: [PATCH 7/7] Fix script for changelog --- extra/release.py | 258 ++++++----------------------------------------- 1 file changed, 31 insertions(+), 227 deletions(-) diff --git a/extra/release.py b/extra/release.py index 5e08b0449c..8ad63cfe93 100755 --- a/extra/release.py +++ b/extra/release.py @@ -2,31 +2,15 @@ """A utility script for automating the beets release process. """ +import argparse import datetime import os import re -import subprocess -from contextlib import contextmanager - -import click BASE = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) CHANGELOG = os.path.join(BASE, "docs", "changelog.rst") - - -@contextmanager -def chdir(d): - """A context manager that temporary changes the working directory.""" - olddir = os.getcwd() - os.chdir(d) - yield - os.chdir(olddir) - - -@click.group() -def release(): - pass - +parser = argparse.ArgumentParser() +parser.add_argument("version", type=str) # Locations (filenames and patterns) of the version number. VERSION_LOCS = [ @@ -67,7 +51,7 @@ def release(): GITHUB_REPO = "beets" -def bump_version(version): +def bump_version(version: str): """Update the version number in setup.py, docs config, changelog, and root module. """ @@ -105,129 +89,45 @@ def bump_version(version): found = True break - else: # Normal line. out_lines.append(line) - if not found: print(f"No pattern found in {filename}") - # Write the file back. with open(filename, "w") as f: f.write("".join(out_lines)) - # Insert into the right place. - with open(CHANGELOG) as f: - contents = f.read() - location = contents.find("\n\n") # First blank line. - contents = contents[:location] + contents[location:] - - # Write back. - with open(CHANGELOG, "w") as f: - f.write(contents) - - -@release.command() -@click.argument("version") -def bump(version): - """Bump the version number.""" - bump_version(version) + update_changelog(version) -def get_latest_changelog(): - """Extract the first section of the changelog.""" - started = False - lines = [] - with open(CHANGELOG) as f: - for line in f: - if re.match(r"^--+$", line.strip()): - # Section boundary. Start or end. - if started: - # Remove last line, which is the header of the next - # section. - del lines[-1] - break - else: - started = True - - elif started: - lines.append(line) - return "".join(lines[2:]).strip() - - -def rst2md(text): - """Use Pandoc to convert text from ReST to Markdown.""" - pandoc = subprocess.Popen( - ["pandoc", "--from=rst", "--to=markdown", "--wrap=none"], - stdin=subprocess.PIPE, - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, +def update_changelog(version: str): + # Generate bits to insert into changelog. + header_line = f"{version} (in development)" + header = "\n\n" + header_line + "\n" + "-" * len(header_line) + "\n\n" + header += ( + "Changelog goes here! Please add your entry to the bottom of" + " one of the lists below!\n" ) - stdout, _ = pandoc.communicate(text.encode("utf-8")) - md = stdout.decode("utf-8").strip() - - # Fix up odd spacing in lists. - return re.sub(r"^- ", "- ", md, flags=re.M) - - -def changelog_as_markdown(): - """Get the latest changelog entry as hacked up Markdown.""" - rst = get_latest_changelog() - - # Replace plugin links with plugin names. - rst = re.sub(r":doc:`/plugins/(\w+)`", r"``\1``", rst) - - # References with text. - rst = re.sub(r":ref:`([^<]+)(<[^>]+>)`", r"\1", rst) - - # Other backslashes with verbatim ranges. - rst = re.sub(r"(\s)`([^`]+)`([^_])", r"\1``\2``\3", rst) - - # Command links with command names. - rst = re.sub(r":ref:`(\w+)-cmd`", r"``\1``", rst) - - # Bug numbers. - rst = re.sub(r":bug:`(\d+)`", r"#\1", rst) - - # Users. - rst = re.sub(r":user:`(\w+)`", r"@\1", rst) - - # Convert with Pandoc. - md = rst2md(rst) - - # Restore escaped issue numbers. - md = re.sub(r"\\#(\d+)\b", r"#\1", md) - - return md - - -@release.command() -def changelog(): - """Get the most recent version's changelog as Markdown.""" - print(changelog_as_markdown()) - - -def get_version(index=0): - """Read the current version from the changelog.""" + # Insert into the right place. with open(CHANGELOG) as f: - cur_index = 0 - for line in f: - match = re.search(r"^\d+\.\d+\.\d+", line) - if match: - if cur_index == index: - return match.group(0) - else: - cur_index += 1 + contents = f.readlines() + contents = [ + line + for line in contents + if not re.match(r"Changelog goes here!.*", line) + ] + contents = "".join(contents) + contents = re.sub("\n{3,}", "\n\n", contents) -@release.command() -def version(): - """Display the current version.""" - print(get_version()) + location = contents.find("\n\n") # First blank line. + contents = contents[:location] + header + contents[location:] + # Write back. + with open(CHANGELOG, "w") as f: + f.write(contents) -@release.command() def datestamp(): """Enter today's date as the release date in the changelog.""" dt = datetime.datetime.now() @@ -255,108 +155,12 @@ def datestamp(): f.write(line) -@release.command() -def prep(): - """Run all steps to prepare a release. - - - Tag the commit. - - Build the sdist package. - - Generate the Markdown changelog to ``changelog.md``. - - Bump the version number to the next version. - """ - cur_version = get_version() - - # Tag. - subprocess.check_call(["git", "tag", f"v{cur_version}"]) - - # Build. - with chdir(BASE): - subprocess.check_call(["python", "setup.py", "sdist"]) - - # Generate Markdown changelog. - cl = changelog_as_markdown() - with open(os.path.join(BASE, "changelog.md"), "w") as f: - f.write(cl) - +def prep(args: argparse.Namespace): # Version number bump. - # FIXME It should be possible to specify this as an argument. - version_parts = [int(n) for n in cur_version.split(".")] - version_parts[-1] += 1 - next_version = ".".join(map(str, version_parts)) - bump_version(next_version) - - -@release.command() -def publish(): - """Unleash a release unto the world. - - - Push the tag to GitHub. - - Upload to PyPI. - """ - version = get_version(1) - - # Push to GitHub. - with chdir(BASE): - subprocess.check_call(["git", "push"]) - subprocess.check_call(["git", "push", "--tags"]) - - # Upload to PyPI. - path = os.path.join(BASE, "dist", f"beets-{version}.tar.gz") - subprocess.check_call(["twine", "upload", path]) - - -@release.command() -def ghrelease(): - """Create a GitHub release using the `github-release` command-line - tool. - - Reads the changelog to upload from `changelog.md`. Uploads the - tarball from the `dist` directory. - """ - version = get_version(1) - tag = "v" + version - - # Load the changelog. - with open(os.path.join(BASE, "changelog.md")) as f: - cl_md = f.read() - - # Create the release. - subprocess.check_call( - [ - "github-release", - "release", - "-u", - GITHUB_USER, - "-r", - GITHUB_REPO, - "--tag", - tag, - "--name", - f"{GITHUB_REPO} {version}", - "--description", - cl_md, - ] - ) - - # Attach the release tarball. - tarball = os.path.join(BASE, "dist", f"beets-{version}.tar.gz") - subprocess.check_call( - [ - "github-release", - "upload", - "-u", - GITHUB_USER, - "-r", - GITHUB_REPO, - "--tag", - tag, - "--name", - os.path.basename(tarball), - "--file", - tarball, - ] - ) + datestamp() + bump_version(args.version) if __name__ == "__main__": - release() + args = parser.parse_args() + prep(args)