Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enhanced changelog validation #7942

Merged
merged 6 commits into from
Nov 25, 2024

Conversation

cbbayburt
Copy link
Contributor

@cbbayburt cbbayburt commented Nov 22, 2023

A complete overhaul of the changelog validation workflow, introducing many enhancements over the existing GitHub action.

Features

  • Validation is done by a standalone script (.github/workflows/changelogs/changelogs.py)
  • Checks if the changelog is added to the correct package
  • Performs basic checks against typos, spacing, capitalization, whitespace, and line length issues
  • Ensures correct spelling of tracker IDs (bsc#, jira-#, etc.) mentioned in the changelogs
  • Matches mentioned tracker IDs against the PR title and commit messages
  • Verifies that a bug exists and belongs to "SUSE Manager" in bugzilla.suse.com
  • Pinpoints the exact location of an issue in a changelog file
  • Recognizes every type of tracker as defined by OBS/IBS (see: .github/workflows/changelogs/trackers.xml)
  • Inline reporting of issues in the GitHub UI (see GUI diff)
  • Can also be executed locally by executing changelogs.py directly (See "How to run locally" below)

Bugzilla access and tracker information

To enable tracker validation through Bugzilla, we need a Bugzilla API key as a repository secret in uyuni-project/uyuni. The code uses python-bugzilla client and requests a bug via its ID to retrieve its product name.

If the API key is not set up in Github, the Bugzilla checks are skipped.

Tracker information is provided with the trackers.xml file included in the PR. This file is retrieved from the OBS API endpoint /issue_trackers.

GUI Diff

Console output

Screenshot from 2023-11-22 20-55-51

Inline reporting in GUI

Screenshot from 2023-11-22 20-57-36

How to run locally

Note: To run the script, you need to have the gh (GitHub CLI tool) and the python-bugzilla-3.2.0 library installed.

Basic functionality

Once you finish working on your feature and add the necessary changelog entries, execute the following command from your Uyuni repository root, providing all your modified files including the changelog files as positional arguments:

python .github/workflows/changelogs/changelogs.py $(git diff --name-only <pr_base_rev>..<pr_head_ref>)

Since no PR or tracker information is provided, PR and tracker validation will be skipped.

Full validation (PR, trackers, Bugzilla, etc.)

If you have any trackers (bsc#xxx, etc.) mentioned in your changelogs, PR title, and/or commit messages, you should enable the additional checks as well. To do that, add a PR number and a tracker file to the command using the corresponding arguments:

# Get XML tracker definition data from OBS and save it to a file
osc api /issue_trackers > trackers.xml

# Set the required environment variables (for PR and Bugzilla validation)
export GH_TOKEN=<your GitHub access token>
export BZ_TOKEN=<your Bugzilla API key>

python .github/workflows/changelogs/changelogs.py --tracker-file ./trackers.xml --pr-number <your_pr_no> \
    $(git diff --name-only <pr_base_rev>..<pr_head_ref>)

If you want to validate a PR in a different fork, you can specify any Uyuni fork using the --git-repo argument.

Below is a full list of available arguments, their usages, and default values:

python .github/workflows/changelogs/changelogs.py --help
usage: changelogs.py [-h] [-v] [-l LINE_LENGTH] [-t TRACKER_FILE] [-d SPACEWALK_DIR] [-p PR_NUMBER]
                     [-r GIT_REPO] [-b BUGZILLA_URI]
                     [FILE ...]

Validate changelog entries for Uyuni PRs

positional arguments:
  FILE                  the list of modified files in the pull request

options:
  -h, --help            show this help message and exit
  -v, --verbose         enable verbose output
  -l LINE_LENGTH, --line-length LINE_LENGTH
                        maximum line length allowed in changelog files (default: 67)
  -t TRACKER_FILE, --tracker-file TRACKER_FILE
                        tracker definitions XML document retrieved from the OBS/IBS API. Bypass tracker
                        validation if not provided.
  -d SPACEWALK_DIR, --spacewalk-dir SPACEWALK_DIR
                        path to the local git repository root (default: current directory)
  -p PR_NUMBER, --pr-number PR_NUMBER
                        the ID of the pull request to be validated. Bypass PR validation if not provided.
  -r GIT_REPO, --git-repo GIT_REPO
                        the Uyuni repository to validate the PR against (default: 'uyuni-project/uyuni')
  -b BUGZILLA_URI, --bugzilla-uri BUGZILLA_URI
                        the URI to the Bugzilla host to verify bug trackers (default: 'bugzilla.suse.com')

Uyuni project: <https://github.com/uyuni-project/uyuni>

More information

Check out the Python docstrings for more information.

How to review

Unit tests cover every validation rule extensively and provide a good understanding of what rules exist and how each one is enforced (test_validate_chlog_file_rules test method is a good start). Also, feel free to checkout the branch and run the script in your local copy of the Uyuni repository.

Documentation

  • Documentation included (docstrings and --help command)

Test coverage

  • Unit tests were added (pytest)

Links

Fixes https://github.com/SUSE/spacewalk/issues/2734

Changelogs

Make sure the changelogs entries you are adding are compliant with https://github.com/uyuni-project/uyuni/wiki/Contributing#changelogs and https://github.com/uyuni-project/uyuni/wiki/Contributing#uyuni-projectuyuni-repository

If you don't need a changelog check, please mark this checkbox:

  • No changelog needed (how ironic 🤔)

If you uncheck the checkbox after the PR is created, you will need to re-run changelog_test (see below)

Re-run a test

If you need to re-run a test, please mark the related checkbox, it will be unchecked automatically once it has re-run:

  • Re-run test "changelog_test"
  • Re-run test "backend_unittests_pgsql"
  • Re-run test "java_pgsql_tests"
  • Re-run test "schema_migration_test_pgsql"
  • Re-run test "susemanager_unittests"
  • Re-run test "javascript_lint"
  • Re-run test "spacecmd_unittests"

Copy link
Member

@agraul agraul left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks a lot for the work, this looks nice already! You've done a great job with the test suite to show the different validations!

I left a few comments in line, most of them are just informational (about Python). Other than that, I have a general remark:

Can we move the user documentation from the PR description to its own file? It'll be easier to reference it in the future (e.g. when running the code locally). BTW, python3 .github/workflows/changelogs/changelogs.py $(git diff --name-only origin/master...HEAD) can be used to pass all files to the script (assuming a. the remote is called origin and b. you want to merge into master).

.github/workflows/changelogs/changelogs.py Show resolved Hide resolved
.github/workflows/changelogs/changelogs.py Show resolved Hide resolved
.github/workflows/changelogs/changelogs.py Outdated Show resolved Hide resolved
.github/workflows/changelogs/changelogs.py Outdated Show resolved Hide resolved
.github/workflows/changelogs/changelogs.py Outdated Show resolved Hide resolved
.github/workflows/changelogs/changelogs.py Show resolved Hide resolved
.github/workflows/changelogs/changelogs.py Outdated Show resolved Hide resolved
.github/workflows/changelogs/changelogs.py Show resolved Hide resolved
Comment on lines +534 to +532
if not files["files"]:
# Changelog added but no file is modified
issues.append(Issue(IssueType.WRONG_CHLOG, package=pkg))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could this happen intentionally? E.g. when we forgot a (second) tracker and want to add it afterwards

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, but I think it's better fixed with an explicit approval from rel-eng. The test itself should fail anyway.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree. in general we should not edit old changelogs. if this happen it should be only for good reasons. and if we add additional bsc we (releng) need to also be sure that the related patchinfo will also include that reference in a different way from a standard fixed bsc.
@juliogonzalez / @raulillo82 what's your take?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, makes sense.

.github/workflows/changelogs/test_changelogs.py Outdated Show resolved Hide resolved
@cbosdo
Copy link
Contributor

cbosdo commented Nov 27, 2023

Note that mkchglog has been extracted to: https://github.com/uyuni-project/uyuni-releng-tools

Copy link
Contributor

@deneb-alpha deneb-alpha left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@cbbayburt I left a comment about the available trackers.

bug = self.bzapi.getbug(bug_id)
logging.debug(f"Bug #{bug_id} belongs to product '{bug.product}'")

if not bug.product.startswith("SUSE Manager"):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, for security the product is called
SUSE Security Incidents

.github/workflows/changelogs/changelogs.py Show resolved Hide resolved
Comment on lines +566 to +563
parser.add_argument("-t", "--tracker-file",
help="tracker definitions XML document retrieved from the OBS/IBS API. Bypass tracker validation if not provided.")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please, keep in mind that we have some trackers in IBS not available in OBS.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I compared them, and it seems there are only minor differences in between. Which one should we use? OBS for Uyuni, and IBS for SUSE Manager? or something else?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I compared them, and it seems there are only minor differences in between. Which one should we use? OBS for Uyuni, and IBS for SUSE Manager? or something else?

the easy way it could also be to switch between Uyuni / OBS and SUMA / IBS

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

...but it's true that for using IBS we will need authentication. 🤔

in any case, IBS has all the trackers available in OBS, if the parsed tracker is valid in OBS it'svalid in IBS too. let's start easy

Copy link
Contributor Author

@cbbayburt cbbayburt Dec 4, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OBS also requires authentication 🤷🏻‍♂️

So we either create an account and store credentials in GitHub, or we update the file manually whenever needed.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

before uploading that list we need to check why also this endpoint requires authentication :(

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's nothing risky in the data so my guess is it's just the default way the API is designed. But let's ask and make sure of course.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@deneb-alpha thanks for opening the OBS issue. IIUC from this comment, it's ok to upload it to our public repo.

@cbbayburt
Copy link
Contributor Author

Thanks, @agraul for the review and all the tips. I'll address them all separately.

Can we move the user documentation from the PR description to its own file? It'll be easier to reference it in the future (e.g. when running the code locally). BTW, python3 .github/workflows/changelogs/changelogs.py $(git diff --name-only origin/master...HEAD) can be used to pass all files to the script (assuming a. the remote is called origin and b. you want to merge into master).

Good idea, I'll add it in a README in the directory.

Copy link
Contributor

@deneb-alpha deneb-alpha left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

left few more comments

bug = self.bzapi.getbug(bug_id)
logging.debug(f"Bug #{bug_id} belongs to product '{bug.product}'")

if not bug.product.startswith("SUSE Manager"):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it could also be that a bsc under SUSE Security Incidents could also be restricted. I think we could start checking only for SUMA and enhance this later

Comment on lines +534 to +532
if not files["files"]:
# Changelog added but no file is modified
issues.append(Issue(IssueType.WRONG_CHLOG, package=pkg))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree. in general we should not edit old changelogs. if this happen it should be only for good reasons. and if we add additional bsc we (releng) need to also be sure that the related patchinfo will also include that reference in a different way from a standard fixed bsc.
@juliogonzalez / @raulillo82 what's your take?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

how often we will refresh this xml file?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the current state, it needs to be manually uploaded. I don't think this data gets updated often so it shouldn't be much of a problem.

I was also thinking about requesting it from the action itself and caching it, but it seems that the /issue_trackers endpoint needs authentication, so for that, we need to set up an OBS account and store the credentials as additional secrets in Github. All this seems like more work than just manually uploading it. Also, since IBS is not reachable from here, we can only do this for OBS.

deneb-alpha
deneb-alpha previously approved these changes Dec 4, 2023
Copy link
Contributor

@deneb-alpha deneb-alpha left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@cbbayburt from my side +1.
but let's also check with the team if they have issues with what will be marked as failure and what only as warning.

Comment on lines +566 to +563
parser.add_argument("-t", "--tracker-file",
help="tracker definitions XML document retrieved from the OBS/IBS API. Bypass tracker validation if not provided.")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

...but it's true that for using IBS we will need authentication. 🤔

in any case, IBS has all the trackers available in OBS, if the parsed tracker is valid in OBS it'svalid in IBS too. let's start easy

runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 1
fetch-depth: 2
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just out of curiousity, why 2?

Copy link
Member

@juliogonzalez juliogonzalez left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One comment about the credentials.

if: steps.changelogs.conclusion == 'success' && steps.changelogs.outputs.added_modified == ''
- name: Test changelog entries
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this won't work on forks, as the credentials won't be present there, so we'll have the same problem we had for SonarQube? @cbosdo, am I right about this one?

Copy link
Contributor

This PR is stale because it has been open 60 days with no activity. Remove stale label or comment or this will be closed in 10 days.

@github-actions github-actions bot added the Stale label Mar 26, 2024
@cbbayburt cbbayburt removed the Stale label Mar 26, 2024
Copy link
Contributor

This PR is stale because it has been open 60 days with no activity. Remove stale label or comment or this will be closed in 10 days.

@github-actions github-actions bot added the Stale label May 26, 2024
@cbbayburt cbbayburt removed the Stale label May 27, 2024
Copy link
Contributor

This PR is stale because it has been open 60 days with no activity. Remove stale label or comment or this will be closed in 10 days.

@github-actions github-actions bot added the Stale label Jul 27, 2024
@cbbayburt cbbayburt removed the Stale label Jul 27, 2024
raulillo82
raulillo82 previously approved these changes Nov 8, 2024
@cbbayburt cbbayburt force-pushed the changelog-action branch 19 times, most recently from a9b7b94 to ab0d518 Compare November 25, 2024 14:21
deneb-alpha
deneb-alpha previously approved these changes Nov 25, 2024
Copy link
Contributor

@deneb-alpha deneb-alpha left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@cbbayburt for now I think it LGTM

 * Use 'dataclasses'
 * Use python3 shebang
 * Use re.match to match beginning
 * Remove 'type' keyword usages
 * Use 'setdefault'
 * Remove 'wrong capitalization after colon' test
 * Rename 'spacewalk_dir' to 'uyuni_dir'
 * Use 'enumerate' in main loop
 * Fix line numbers off-by-one issue
 * Simplify runner code
@cbbayburt cbbayburt merged commit 762eca4 into uyuni-project:master Nov 25, 2024
17 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants