diff --git a/.github/workflows/dependabot_changelog.yml b/.github/workflows/dependabot_changelog.yml deleted file mode 100644 index df47e3dcba43..000000000000 --- a/.github/workflows/dependabot_changelog.yml +++ /dev/null @@ -1,49 +0,0 @@ -name: Write changelog for dependabot PR -on: - pull_request: - types: - - opened - - reopened # For debugging! - -permissions: - # Needed to be able to push the commit. See - # https://docs.github.com/en/code-security/dependabot/working-with-dependabot/automating-dependabot-with-github-actions#enable-auto-merge-on-a-pull-request - # for a similar example - contents: write - -jobs: - add-changelog: - runs-on: 'ubuntu-latest' - if: ${{ github.actor == 'dependabot[bot]' }} - steps: - - uses: actions/checkout@v3 - with: - ref: ${{ github.event.pull_request.head.ref }} - - name: Write, commit and push changelog - env: - PR_TITLE: ${{ github.event.pull_request.title }} - PR_NUMBER: ${{ github.event.pull_request.number }} - run: | - echo "${PR_TITLE}." > "changelog.d/${PR_NUMBER}".misc - git add changelog.d - git config user.email "github-actions[bot]@users.noreply.github.com" - git config user.name "GitHub Actions" - git commit -m "Changelog" - git push - shell: bash - # The `git push` above does not trigger CI on the dependabot PR. - # - # By default, workflows can't trigger other workflows when they're just using the - # default `GITHUB_TOKEN` access token. (This is intended to stop you from writing - # recursive workflow loops by accident, because that'll get very expensive very - # quickly.) Instead, you have to manually call out to another workflow, or else - # make your changes (i.e. the `git push` above) using a personal access token. - # See - # https://docs.github.com/en/actions/using-workflows/triggering-a-workflow#triggering-a-workflow-from-a-workflow - # - # I have tried and failed to find a way to trigger CI on the "merge ref" of the PR. - # See git commit history for previous attempts. If anyone desperately wants to try - # again in the future, make a matrix-bot account and use its access token to git push. - - # THIS WORKFLOW HAS WRITE PERMISSIONS---do not add other jobs here unless they - # are sufficiently locked down to dependabot only as above. diff --git a/changelog.d/15481.misc b/changelog.d/15481.misc new file mode 100644 index 000000000000..a6e088c16493 --- /dev/null +++ b/changelog.d/15481.misc @@ -0,0 +1 @@ +Create dependabot changelogs at release time. diff --git a/docs/development/dependencies.md b/docs/development/dependencies.md index c4449c51f780..b5926d96ffb7 100644 --- a/docs/development/dependencies.md +++ b/docs/development/dependencies.md @@ -260,15 +260,17 @@ doesn't require poetry. (It's what we use in CI too). However, you could try ## ...handle a Dependabot pull request? -Synapse uses Dependabot to keep the `poetry.lock` file up-to-date. When it -creates a pull request a GitHub Action will run to automatically create a changelog -file. Ensure that: +Synapse uses Dependabot to keep the `poetry.lock` and `Cargo.lock` file +up-to-date with the latest releases of our dependencies. The changelog check is +omitted for Dependabot PRs; the release script will include them in the +changelog. + +When reviewing a dependabot PR, ensure that: * the lockfile changes look reasonable; * the upstream changelog file (linked in the description) doesn't include any breaking changes; -* continuous integration passes (due to permissions, the GitHub Actions run on - the changelog commit will fail, look at the initial commit of the pull request); +* continuous integration passes. In particular, any updates to the type hints (usually packages which start with `types-`) should be safe to merge if linting passes. diff --git a/scripts-dev/release.py b/scripts-dev/release.py index ec92a59bb8be..257d1e9ebd29 100755 --- a/scripts-dev/release.py +++ b/scripts-dev/release.py @@ -27,7 +27,7 @@ import urllib.request from os import path from tempfile import TemporaryDirectory -from typing import Any, List, Optional +from typing import Any, List, Match, Optional, Union import attr import click @@ -233,7 +233,7 @@ def _prepare() -> None: subprocess.check_output(["poetry", "version", new_version]) # Generate changelogs. - generate_and_write_changelog(current_version, new_version) + generate_and_write_changelog(synapse_repo, current_version, new_version) # Generate debian changelogs if parsed_new_version.pre is not None: @@ -814,7 +814,7 @@ class VersionSection: def generate_and_write_changelog( - current_version: version.Version, new_version: str + repo: Repo, current_version: version.Version, new_version: str ) -> None: # We do this by getting a draft so that we can edit it before writing to the # changelog. @@ -827,6 +827,10 @@ def generate_and_write_changelog( new_changes = new_changes.replace( "No significant changes.", f"No significant changes since {current_version}." ) + new_changes += build_dependabot_changelog( + repo, + current_version, + ) # Prepend changes to changelog with open("CHANGES.md", "r+") as f: @@ -841,5 +845,47 @@ def generate_and_write_changelog( os.remove(filename) +def build_dependabot_changelog(repo: Repo, current_version: version.Version) -> str: + """Summarise dependabot commits between `current_version` and `release_branch`. + + Returns an empty string if there have been no such commits; otherwise outputs a + third-level markdown header followed by an unordered list.""" + last_release_commit = repo.tag("v" + str(current_version)).commit + rev_spec = f"{last_release_commit.hexsha}.." + commits = list(git.objects.Commit.iter_items(repo, rev_spec)) + messages = [] + for commit in reversed(commits): + if commit.author.name == "dependabot[bot]": + message: Union[str, bytes] = commit.message + if isinstance(message, bytes): + message = message.decode("utf-8") + messages.append(message.split("\n", maxsplit=1)[0]) + + if not messages: + print(f"No dependabot commits in range {rev_spec}", file=sys.stderr) + return "" + + messages.sort() + + def replacer(match: Match[str]) -> str: + desc = match.group(1) + number = match.group(2) + return f"* {desc}. ([\\#{number}](https://github.com/matrix-org/synapse/issues/{number}))" + + for i, message in enumerate(messages): + messages[i] = re.sub(r"(.*) \(#(\d+)\)$", replacer, message) + messages.insert(0, "### Updates to locked dependencies\n") + return "\n".join(messages) + + +@cli.command() +@click.argument("since") +def test_dependabot_changelog(since: str) -> None: + """Test building the dependabot changelog. + + Summarises all dependabot commits between the SINCE tag and the current git HEAD.""" + print(build_dependabot_changelog(git.Repo("."), version.Version(since))) + + if __name__ == "__main__": cli()