@@ -919,18 +919,30 @@ type graphQLActor struct {
919919 ID string `json:"id,omitempty"`
920920}
921921
922- // isBotFromGraphQL determines if an actor is a bot.
923- func isBotFromGraphQL (actor graphQLActor ) bool {
922+ // isBot determines if an actor is a bot.
923+ func isBot (actor graphQLActor ) bool {
924924 if actor .Login == "" {
925925 return false
926926 }
927- // Check for bot patterns in login
927+ // Check for bot patterns in login (case-insensitive for better detection)
928928 login := actor .Login
929+ lowerLogin := strings .ToLower (login )
930+
931+ // Check for common bot suffixes
929932 if strings .HasSuffix (login , "[bot]" ) ||
930- strings .HasSuffix (login , "-bot" ) ||
931- strings .HasSuffix (login , "-robot" ) {
933+ strings .HasSuffix (lowerLogin , "-bot" ) ||
934+ strings .HasSuffix (lowerLogin , "_bot" ) ||
935+ strings .HasSuffix (lowerLogin , "-robot" ) ||
936+ strings .HasPrefix (lowerLogin , "bot-" ) {
937+ return true
938+ }
939+
940+ // Check for GitHub bot account patterns
941+ // Many bots end with "bot" without separator (e.g., "dependabot", "renovatebot")
942+ if strings .HasSuffix (lowerLogin , "bot" ) && len (login ) > 3 {
932943 return true
933944 }
945+
934946 // In GraphQL, bots have different IDs than users
935947 // Bot IDs typically start with "BOT_" or have specific patterns
936948 // This is a heuristic that may need adjustment
@@ -1013,9 +1025,10 @@ func (c *Client) convertGraphQLToPullRequest(ctx context.Context, data *graphQLP
10131025 pr .MergeableState = strings .ToLower (data .MergeStateStatus )
10141026 }
10151027
1016- // Author write access
1028+ // Author write access and bot detection
10171029 if data .Author .Login != "" {
10181030 pr .AuthorWriteAccess = c .writeAccessFromAssociation (ctx , owner , repo , data .Author .Login , data .AuthorAssociation )
1031+ pr .AuthorBot = isBot (data .Author )
10191032 }
10201033
10211034 // Assignees (initialize to empty slice if none)
@@ -1089,7 +1102,7 @@ func (c *Client) convertGraphQLToEventsComplete(ctx context.Context, data *graph
10891102 Timestamp : data .CreatedAt ,
10901103 Actor : data .Author .Login ,
10911104 Body : truncate (data .Body ),
1092- Bot : isBotFromGraphQL (data .Author ),
1105+ Bot : isBot (data .Author ),
10931106 WriteAccess : c .writeAccessFromAssociation (ctx , owner , repo , data .Author .Login , data .AuthorAssociation ),
10941107 })
10951108
@@ -1102,7 +1115,7 @@ func (c *Client) convertGraphQLToEventsComplete(ctx context.Context, data *graph
11021115 }
11031116 if node .Commit .Author .User != nil {
11041117 event .Actor = node .Commit .Author .User .Login
1105- event .Bot = isBotFromGraphQL (* node .Commit .Author .User )
1118+ event .Bot = isBot (* node .Commit .Author .User )
11061119 } else {
11071120 event .Actor = node .Commit .Author .Name
11081121 }
@@ -1126,7 +1139,7 @@ func (c *Client) convertGraphQLToEventsComplete(ctx context.Context, data *graph
11261139 Body : truncate (review .Body ),
11271140 Outcome : strings .ToLower (review .State ),
11281141 Question : containsQuestion (review .Body ),
1129- Bot : isBotFromGraphQL (review .Author ),
1142+ Bot : isBot (review .Author ),
11301143 WriteAccess : c .writeAccessFromAssociation (ctx , owner , repo , review .Author .Login , review .AuthorAssociation ),
11311144 }
11321145 events = append (events , event )
@@ -1141,7 +1154,7 @@ func (c *Client) convertGraphQLToEventsComplete(ctx context.Context, data *graph
11411154 Actor : comment .Author .Login ,
11421155 Body : truncate (comment .Body ),
11431156 Question : containsQuestion (comment .Body ),
1144- Bot : isBotFromGraphQL (comment .Author ),
1157+ Bot : isBot (comment .Author ),
11451158 WriteAccess : c .writeAccessFromAssociation (ctx , owner , repo , comment .Author .Login , comment .AuthorAssociation ),
11461159 }
11471160 events = append (events , event )
@@ -1156,7 +1169,7 @@ func (c *Client) convertGraphQLToEventsComplete(ctx context.Context, data *graph
11561169 Actor : comment .Author .Login ,
11571170 Body : truncate (comment .Body ),
11581171 Question : containsQuestion (comment .Body ),
1159- Bot : isBotFromGraphQL (comment .Author ),
1172+ Bot : isBot (comment .Author ),
11601173 WriteAccess : c .writeAccessFromAssociation (ctx , owner , repo , comment .Author .Login , comment .AuthorAssociation ),
11611174 }
11621175 events = append (events , event )
@@ -1217,7 +1230,7 @@ func (c *Client) convertGraphQLToEventsComplete(ctx context.Context, data *graph
12171230 }
12181231 if node .Creator != nil {
12191232 event .Actor = node .Creator .Login
1220- event .Bot = isBotFromGraphQL (* node .Creator )
1233+ event .Bot = isBot (* node .Creator )
12211234 }
12221235 events = append (events , event )
12231236 default :
@@ -1243,6 +1256,7 @@ func (c *Client) convertGraphQLToEventsComplete(ctx context.Context, data *graph
12431256 if data .MergedBy != nil {
12441257 event .Actor = data .MergedBy .Login
12451258 event .Kind = "pr_merged"
1259+ event .Bot = isBot (* data .MergedBy )
12461260 }
12471261 events = append (events , event )
12481262 }
@@ -1279,6 +1293,21 @@ func (*Client) parseGraphQLTimelineEvent(_ /* ctx */ context.Context, item map[s
12791293 return "unknown"
12801294 }
12811295
1296+ // Helper to check if actor is a bot
1297+ isActorBot := func () bool {
1298+ if actor , ok := item ["actor" ].(map [string ]any ); ok {
1299+ var actorObj graphQLActor
1300+ if login , ok := actor ["login" ].(string ); ok {
1301+ actorObj .Login = login
1302+ }
1303+ if id , ok := actor ["id" ].(string ); ok {
1304+ actorObj .ID = id
1305+ }
1306+ return isBot (actorObj )
1307+ }
1308+ return false
1309+ }
1310+
12821311 createdAt := getTime ("createdAt" )
12831312 if createdAt == nil {
12841313 return nil
@@ -1287,6 +1316,7 @@ func (*Client) parseGraphQLTimelineEvent(_ /* ctx */ context.Context, item map[s
12871316 event := & Event {
12881317 Timestamp : * createdAt ,
12891318 Actor : getActor (),
1319+ Bot : isActorBot (),
12901320 }
12911321
12921322 switch typename {
0 commit comments