Skip to content

Refactor required approvals workflow to use custom script.#5134

Closed
RishabhAgarwal-2001 wants to merge 1 commit intomainfrom
fix-required-approval-action
Closed

Refactor required approvals workflow to use custom script.#5134
RishabhAgarwal-2001 wants to merge 1 commit intomainfrom
fix-required-approval-action

Conversation

@RishabhAgarwal-2001
Copy link
Copy Markdown
Contributor

No description provided.

@gemini-code-assist
Copy link
Copy Markdown
Contributor

Summary of Changes

Hello @RishabhAgarwal-2001, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request refactors the existing required approvals workflow by introducing a new custom Go script. This script automates the process of verifying that all necessary approvals, as defined in the CODEOWNERS file, have been obtained for a pull request. It integrates with the GitHub CLI to retrieve PR data and the GitHub API to resolve team memberships, providing a robust and flexible solution for approval enforcement.

Highlights

  • Custom Approval Script: Introduced a new Go-based custom script (tools/check_approvals/main.go) to manage and enforce required pull request approvals based on CODEOWNERS rules.
  • GitHub Integration: Implemented logic to fetch PR file changes and review states using the GitHub CLI, and developed functionality to fetch GitHub team members via the GitHub API for team-based approvals.
  • CODEOWNERS Parsing: Developed functionality to parse .github/CODEOWNERS files, interpret patterns, and determine required individual or team approvals for changed files.
  • Comprehensive Testing: Included comprehensive unit tests (tools/check_approvals/main_test.go) to ensure the correctness and robustness of the approval logic under various scenarios.
Changelog
  • tools/check_approvals/main.go
    • Added a new Go program to implement custom PR approval logic, including fetching PR data, parsing CODEOWNERS, and validating approvals.
  • tools/check_approvals/main_test.go
    • Added unit tests for the check_approvals Go program, covering various approval scenarios and edge cases.
Ignored Files
  • Ignored by pattern: .github/workflows/** (3)
    • .github/workflows/required_approvals.yml
    • .github/workflows/test_approval_logic.py
    • .github/workflows/test_pr_logic.py
Activity
  • No specific activity (comments, reviews, or progress updates) has been recorded for this pull request.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@OpenConfigBot
Copy link
Copy Markdown

Pull Request Functional Test Report for #5134 / 2299079

No tests identified for validation.

Help

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces a new Go script to automate checking for required approvals based on the CODEOWNERS file. The implementation is well-structured and includes a good set of unit tests.

My review has identified a critical issue in error handling that could cause the script to silently fail to enforce all ownership rules. I also found a high-severity issue regarding an incomplete implementation of the CODEOWNERS pattern matching syntax, which could lead to incorrect owner resolution. Additionally, I've provided a couple of medium-severity suggestions to improve code maintainability and readability. Addressing these points will make the script more robust and reliable.

Comment on lines +269 to +271
if err != nil {
log.Printf("CODEOWNERS not found or error reading: %v", err)
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

critical

If parsing the CODEOWNERS file fails, the error is logged, but the program continues with an empty set of rules. This means the script will only check for the hardcoded default approvers and may incorrectly report success for a PR that is missing required approvals from other code owners.

Failure to read the CODEOWNERS file should be a fatal error to prevent the check from passing with incomplete information.

if err != nil {
		log.Fatalf("CODEOWNERS not found or error reading, cannot reliably check approvals: %v", err)
	}

Comment on lines +129 to +152
func matchOwners(filePath string, rules []Rule) []string {
var matchedOwners []string
for _, rule := range rules {
pattern := rule.Pattern
owners := rule.Owners
isMatch := false

if strings.HasPrefix(pattern, "/") && strings.HasSuffix(pattern, "/") {
prefix := pattern[1:]
if strings.HasPrefix(filePath, prefix) {
isMatch = true
}
} else if pattern == "*" {
isMatch = true
} else if strings.HasPrefix(pattern, "/") && filePath == pattern[1:] {
isMatch = true
}

if isMatch {
matchedOwners = owners
}
}
return matchedOwners
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

high

The matchOwners function provides a very limited implementation of CODEOWNERS pattern matching. It currently supports *, exact file paths from the root (e.g., /path/to/file), and directory prefixes (e.g., /path/).

However, it does not support other standard gitignore-style patterns that CODEOWNERS files use, such as:

  • File extensions (*.go)
  • Directory wildcards (docs/**)
  • Matching directories by name anywhere in the path (foo/)

This limitation could lead to incorrect owner resolution if the CODEOWNERS file uses more complex patterns, potentially bypassing required reviews. Consider using a library that properly implements .gitignore pattern matching, such as github.com/sabhiram/go-gitignore, to ensure full compatibility.

Comment on lines +31 to +44
type prFiles struct {
Files []struct {
Path string `json:"path"`
} `json:"files"`
}

// review represents a single review on a PR.
type review struct {
Author struct {
Login string `json:"login"`
} `json:"author"`
State string `json:"state"`
SubmittedAt string `json:"submittedAt"`
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

The prFiles and review structs use anonymous structs for nested data (Files and Author). Using named structs (e.g., fileInfo, authorInfo) would make the code cleaner, more readable, and simplify test data creation in main_test.go.

type prFiles struct {
	Files []fileInfo `json:"files"`
}

type fileInfo struct {
	Path string `json:"path"`
}

// review represents a single review on a PR.
type review struct {
	Author      authorInfo `json:"author"`
	State       string `json:"state"`
	SubmittedAt string `json:"submittedAt"`
}

type authorInfo struct {
	Login string `json:"login"`
}

Comment on lines +201 to +203
if owner != "@openconfig/featureprofiles-approvers" {
requiredTeams[owner] = true
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

The logic to populate requiredTeams can be simplified. The if condition to skip adding @openconfig/featureprofiles-approvers is redundant because this team is already added to the map, and maps inherently handle duplicate keys. Removing the condition would make the code's intent clearer and more maintainable.

requiredTeams[owner] = true

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.

3 participants