mirror of
				https://github.com/esphome/esphome.git
				synced 2025-10-31 07:03:55 +00:00 
			
		
		
		
	[CI] Only mention codeowners once (#9727)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
This commit is contained in:
		
							
								
								
									
										95
									
								
								.github/workflows/codeowner-review-request.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										95
									
								
								.github/workflows/codeowner-review-request.yml
									
									
									
									
										vendored
									
									
								
							| @@ -178,6 +178,51 @@ jobs: | ||||
|                 reviewedUsers.add(review.user.login); | ||||
|               }); | ||||
|  | ||||
|               // Check for previous comments from this workflow to avoid duplicate pings | ||||
|               const { data: comments } = await github.rest.issues.listComments({ | ||||
|                 owner, | ||||
|                 repo, | ||||
|                 issue_number: pr_number | ||||
|               }); | ||||
|  | ||||
|               const previouslyPingedUsers = new Set(); | ||||
|               const previouslyPingedTeams = new Set(); | ||||
|  | ||||
|               // Look for comments from github-actions bot that contain codeowner pings | ||||
|               const workflowComments = comments.filter(comment => | ||||
|                 comment.user.type === 'Bot' && | ||||
|                 comment.user.login === 'github-actions[bot]' && | ||||
|                 comment.body.includes("I've automatically requested reviews from codeowners") | ||||
|               ); | ||||
|  | ||||
|               // Extract previously mentioned users and teams from workflow comments | ||||
|               for (const comment of workflowComments) { | ||||
|                 // Match @username patterns (not team mentions) | ||||
|                 const userMentions = comment.body.match(/@([a-zA-Z0-9_.-]+)(?![/])/g) || []; | ||||
|                 userMentions.forEach(mention => { | ||||
|                   const username = mention.slice(1); // remove @ | ||||
|                   previouslyPingedUsers.add(username); | ||||
|                 }); | ||||
|  | ||||
|                 // Match @org/team patterns | ||||
|                 const teamMentions = comment.body.match(/@[a-zA-Z0-9_.-]+\/([a-zA-Z0-9_.-]+)/g) || []; | ||||
|                 teamMentions.forEach(mention => { | ||||
|                   const teamName = mention.split('/')[1]; | ||||
|                   previouslyPingedTeams.add(teamName); | ||||
|                 }); | ||||
|               } | ||||
|  | ||||
|               console.log(`Found ${previouslyPingedUsers.size} previously pinged users and ${previouslyPingedTeams.size} previously pinged teams`); | ||||
|  | ||||
|               // Remove users who have already been pinged in previous workflow comments | ||||
|               previouslyPingedUsers.forEach(user => { | ||||
|                 matchedOwners.delete(user); | ||||
|               }); | ||||
|  | ||||
|               previouslyPingedTeams.forEach(team => { | ||||
|                 matchedTeams.delete(team); | ||||
|               }); | ||||
|  | ||||
|               // Remove only users who have already submitted reviews (not just requested reviewers) | ||||
|               reviewedUsers.forEach(reviewer => { | ||||
|                 matchedOwners.delete(reviewer); | ||||
| @@ -192,7 +237,7 @@ jobs: | ||||
|               const teamsList = Array.from(matchedTeams); | ||||
|  | ||||
|               if (reviewersList.length === 0 && teamsList.length === 0) { | ||||
|                 console.log('No eligible reviewers found (all may already be requested or reviewed)'); | ||||
|                 console.log('No eligible reviewers found (all may already be requested, reviewed, or previously pinged)'); | ||||
|                 return; | ||||
|               } | ||||
|  | ||||
| @@ -227,31 +272,41 @@ jobs: | ||||
|                   console.log('All codeowners are already requested reviewers or have reviewed'); | ||||
|                 } | ||||
|  | ||||
|                 // Add a comment to the PR mentioning what happened (include all matched codeowners) | ||||
|                 const commentBody = createCommentBody(reviewersList, teamsList, fileMatches.size, true); | ||||
|                 // Only add a comment if there are new codeowners to mention (not previously pinged) | ||||
|                 if (reviewersList.length > 0 || teamsList.length > 0) { | ||||
|                   const commentBody = createCommentBody(reviewersList, teamsList, fileMatches.size, true); | ||||
|  | ||||
|                 await github.rest.issues.createComment({ | ||||
|                   owner, | ||||
|                   repo, | ||||
|                   issue_number: pr_number, | ||||
|                   body: commentBody | ||||
|                 }); | ||||
|                   await github.rest.issues.createComment({ | ||||
|                     owner, | ||||
|                     repo, | ||||
|                     issue_number: pr_number, | ||||
|                     body: commentBody | ||||
|                   }); | ||||
|                   console.log(`Added comment mentioning ${reviewersList.length} users and ${teamsList.length} teams`); | ||||
|                 } else { | ||||
|                   console.log('No new codeowners to mention in comment (all previously pinged)'); | ||||
|                 } | ||||
|               } catch (error) { | ||||
|                 if (error.status === 422) { | ||||
|                   console.log('Some reviewers may already be requested or unavailable:', error.message); | ||||
|  | ||||
|                   // Try to add a comment even if review request failed | ||||
|                   const commentBody = createCommentBody(reviewersList, teamsList, fileMatches.size, false); | ||||
|                   // Only try to add a comment if there are new codeowners to mention | ||||
|                   if (reviewersList.length > 0 || teamsList.length > 0) { | ||||
|                     const commentBody = createCommentBody(reviewersList, teamsList, fileMatches.size, false); | ||||
|  | ||||
|                   try { | ||||
|                     await github.rest.issues.createComment({ | ||||
|                       owner, | ||||
|                       repo, | ||||
|                       issue_number: pr_number, | ||||
|                       body: commentBody | ||||
|                     }); | ||||
|                   } catch (commentError) { | ||||
|                     console.log('Failed to add comment:', commentError.message); | ||||
|                     try { | ||||
|                       await github.rest.issues.createComment({ | ||||
|                         owner, | ||||
|                         repo, | ||||
|                         issue_number: pr_number, | ||||
|                         body: commentBody | ||||
|                       }); | ||||
|                       console.log(`Added fallback comment mentioning ${reviewersList.length} users and ${teamsList.length} teams`); | ||||
|                     } catch (commentError) { | ||||
|                       console.log('Failed to add comment:', commentError.message); | ||||
|                     } | ||||
|                   } else { | ||||
|                     console.log('No new codeowners to mention in fallback comment'); | ||||
|                   } | ||||
|                 } else { | ||||
|                   throw error; | ||||
|   | ||||
							
								
								
									
										45
									
								
								.github/workflows/issue-codeowner-notify.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										45
									
								
								.github/workflows/issue-codeowner-notify.yml
									
									
									
									
										vendored
									
									
								
							| @@ -92,10 +92,49 @@ jobs: | ||||
|                 mention !== `@${issueAuthor}` | ||||
|               ); | ||||
|  | ||||
|               const allMentions = [...filteredUserOwners, ...teamOwners]; | ||||
|               // Check for previous comments from this workflow to avoid duplicate pings | ||||
|               const { data: comments } = await github.rest.issues.listComments({ | ||||
|                 owner, | ||||
|                 repo, | ||||
|                 issue_number: issue_number | ||||
|               }); | ||||
|  | ||||
|               const previouslyPingedUsers = new Set(); | ||||
|               const previouslyPingedTeams = new Set(); | ||||
|  | ||||
|               // Look for comments from github-actions bot that contain codeowner pings for this component | ||||
|               const workflowComments = comments.filter(comment => | ||||
|                 comment.user.type === 'Bot' && | ||||
|                 comment.user.login === 'github-actions[bot]' && | ||||
|                 comment.body.includes(`component: ${componentName}`) && | ||||
|                 comment.body.includes("you've been identified as a codeowner") | ||||
|               ); | ||||
|  | ||||
|               // Extract previously mentioned users and teams from workflow comments | ||||
|               for (const comment of workflowComments) { | ||||
|                 // Match @username patterns (not team mentions) | ||||
|                 const userMentions = comment.body.match(/@([a-zA-Z0-9_.-]+)(?![/])/g) || []; | ||||
|                 userMentions.forEach(mention => { | ||||
|                   previouslyPingedUsers.add(mention); // Keep @ prefix for easy comparison | ||||
|                 }); | ||||
|  | ||||
|                 // Match @org/team patterns | ||||
|                 const teamMentions = comment.body.match(/@[a-zA-Z0-9_.-]+\/[a-zA-Z0-9_.-]+/g) || []; | ||||
|                 teamMentions.forEach(mention => { | ||||
|                   previouslyPingedTeams.add(mention); | ||||
|                 }); | ||||
|               } | ||||
|  | ||||
|               console.log(`Found ${previouslyPingedUsers.size} previously pinged users and ${previouslyPingedTeams.size} previously pinged teams for component ${componentName}`); | ||||
|  | ||||
|               // Remove previously pinged users and teams | ||||
|               const newUserOwners = filteredUserOwners.filter(mention => !previouslyPingedUsers.has(mention)); | ||||
|               const newTeamOwners = teamOwners.filter(mention => !previouslyPingedTeams.has(mention)); | ||||
|  | ||||
|               const allMentions = [...newUserOwners, ...newTeamOwners]; | ||||
|  | ||||
|               if (allMentions.length === 0) { | ||||
|                 console.log('No codeowners to notify (issue author is the only codeowner)'); | ||||
|                 console.log('No new codeowners to notify (all previously pinged or issue author is the only codeowner)'); | ||||
|                 return; | ||||
|               } | ||||
|  | ||||
| @@ -111,7 +150,7 @@ jobs: | ||||
|                 body: commentBody | ||||
|               }); | ||||
|  | ||||
|               console.log(`Successfully notified codeowners: ${mentionString}`); | ||||
|               console.log(`Successfully notified new codeowners: ${mentionString}`); | ||||
|  | ||||
|             } catch (error) { | ||||
|               console.log('Failed to process codeowner notifications:', error.message); | ||||
|   | ||||
		Reference in New Issue
	
	Block a user