kiwiproject / kiwiproject-changelog

Generates change logs
MIT License
1 stars 0 forks source link

Determine the issues and PRs for a release using the GitHub APIs #194

Closed sleberknight closed 1 month ago

sleberknight commented 1 month ago

Use the GitHub REST APIs to get the PRs and issues associated with a release.

This completely replaces the existing logic, which parses git commit messages to determine the issue numbers. However, this has increasingly been causing unrelated issues to be included in the generated change logs, especially when it parses commit messages from dependabot PRS. The dependabot PRs include release notes which usually includes the issue numbers and therefore can confuse the existing logic; it does not and cannot distinguish issue numbers from some other repository's release notes, and therefore includes them.

There are some issues with the GitHub APIs that will need to be handled.

  1. The issues API provides a milestone query parameter, however it is the milestone number (e.g., 42) as opposed to the string (e.g., "2.4.0"). So, the REST endpoints for milestones must be used to find the milestone number, which can then be used to query for issues. Unfortunately, the milestone endpoints don't provide a way to filter on a string, so we need to query for all the open milestones and find the one we want. By limiting to open milestones, we should never need to worry about pagination.
  2. The issues API defaults to finding open issues, but when doing a release, all issues should be closed. We could also use the all state and consider any open issues associated with a release to be an error.
  3. We will need to handle pagination in most if not all requests.
  4. The pull requests API does not provide any way to filter based on milestone, so we need to figure out a way to avoid going through every PR in a repository. For example, we might need to get the date of the previous release, and then paginate through PRs until we see one before that date.
  5. When looking at PRs, we need to filter out ones that are associated with an issue, while retaining "bare" PRs that have the milestone we are releasing for. For example, PRs created by dependabot will not be associated with an issue, but they will have a milestone (which we should have assigned).

When combining the issues and PRs, we'll want to retain the existing behavior of listing from most to least recent, such that issues and PRs are listed in descending order of creation.

Update:

I think I found a much easier way to find issues an PRs for a milestone, which is to use the REST API endpoints for search, and specifically Searching issues and pull requests using Search by milestone.

And to find commit authors, we can use Compare two commits

This supersedes #26.

GitHub API references:

sleberknight commented 1 month ago

Here are some example curls:

$ curl -s -L \
  -H "Accept: application/vnd.github+json" \
  -H "Authorization: Bearer <your-token>" \
  -H "X-GitHub-Api-Version: 2022-11-28" \
  "https://api.github.com/search/issues?q=repo:kiwiproject/kiwiproject-changelog+milestone:0.11.0"

$ curl -s -L \
  -H "Accept: application/vnd.github+json" \
  -H "Authorization: Bearer <your-token>" \
  -H "X-GitHub-Api-Version: 2022-11-28" \
  "https://api.github.com/search/issues?q=repo:kiwiproject/kiwiproject-changelog+milestone:0.12.0"
sleberknight commented 1 month ago

You can pipe the above results into jq to get only the titles:

... | jq '.items[].title'
sleberknight commented 1 month ago

Notes on GitHub issue/PR responses:

sleberknight commented 1 month ago

The structure of the response to a search for issues and PRs for a milestone has the top-level structure:

{
  "total_count": 8,
  "incomplete_results": false,
  "items": [
    { },
    { },
  ]
}
sleberknight commented 1 month ago

Here is example JSON for an issue/PR, with only parts we care about and everything else removed:

    {
      "html_url": "https://github.com/kiwiproject/kiwiproject-changelog/issues/174",
      "number": 174,
      "title": "Provide an \"installation\" script",
      "user": {
        "login": "sleberknight",
        "html_url": "https://github.com/sleberknight",
      },
      "labels": [
        {
          "name": "new feature",
          "default": false,
        }
      ]
    }