Skip to content

Commit 522a47b

Browse files
authored
Merge pull request #2055 from Kobzol/team-cache
Add team API client and cache team API calls
2 parents 80c55b1 + f8f2056 commit 522a47b

18 files changed

+265
-165
lines changed

src/actions.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ use serde::{Deserialize, Serialize};
77
use tera::{Context, Tera};
88

99
use crate::github::{self, GithubClient, Repository};
10+
use crate::team_data::TeamClient;
1011

1112
#[async_trait]
1213
pub trait Action {
@@ -106,6 +107,7 @@ impl<'a> Action for Step<'a> {
106107
async fn call(&self) -> anyhow::Result<String> {
107108
let mut gh = GithubClient::new_from_env();
108109
gh.set_retry_rate_limit(true);
110+
let team_api = TeamClient::new_from_env();
109111

110112
let mut context = Context::new();
111113
let mut results = HashMap::new();
@@ -130,6 +132,7 @@ impl<'a> Action for Step<'a> {
130132
let kind = *kind;
131133
let repository = repository.clone();
132134
let gh = gh.clone();
135+
let team_api = team_api.clone();
133136
let query = query.clone();
134137
handles.push(tokio::task::spawn(async move {
135138
let _permit = semaphore.acquire().await?;
@@ -148,6 +151,7 @@ impl<'a> Action for Step<'a> {
148151
mcps_groups.contains(&name.as_str())
149152
&& repository.full_name.contains("rust-lang/compiler-team"),
150153
&gh,
154+
&team_api,
151155
)
152156
.await?;
153157
Ok((name, kind, issues))

src/bin/project_goals.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use clap::Parser;
2+
use triagebot::team_data::TeamClient;
23
use triagebot::zulip::client::ZulipClient;
34
use triagebot::{github::GithubClient, handlers::project_goals};
45

@@ -24,9 +25,11 @@ async fn main() -> anyhow::Result<()> {
2425
let opt = Opt::parse();
2526
let gh = GithubClient::new_from_env();
2627
let zulip = ZulipClient::new_from_env();
28+
let team_api = TeamClient::new_from_env();
2729
project_goals::ping_project_goals_owners(
2830
&gh,
2931
&zulip,
32+
&team_api,
3033
opt.dry_run,
3134
opt.days_threshold,
3235
&opt.next_meeting_date,

src/github.rs

Lines changed: 13 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use crate::team_data::TeamClient;
12
use anyhow::{anyhow, Context};
23
use async_trait::async_trait;
34
use bytes::Bytes;
@@ -240,9 +241,9 @@ impl User {
240241
.await
241242
}
242243

243-
pub async fn is_team_member<'a>(&'a self, client: &'a GithubClient) -> anyhow::Result<bool> {
244+
pub async fn is_team_member<'a>(&'a self, client: &'a TeamClient) -> anyhow::Result<bool> {
244245
log::trace!("Getting team membership for {:?}", self.login);
245-
let permission = crate::team_data::teams(client).await?;
246+
let permission = client.teams().await?;
246247
let map = permission.teams;
247248
let is_triager = map
248249
.get("wg-triage")
@@ -262,49 +263,6 @@ impl User {
262263
}
263264
}
264265

265-
// Returns the ID of the given user, if the user is in the `all` team.
266-
pub async fn get_id_for_username(
267-
client: &GithubClient,
268-
login: &str,
269-
) -> anyhow::Result<Option<u64>> {
270-
let permission = crate::team_data::teams(client).await?;
271-
let map = permission.teams;
272-
let login = login.to_lowercase();
273-
Ok(map["all"]
274-
.members
275-
.iter()
276-
.find(|g| g.github.to_lowercase() == login)
277-
.map(|u| u.github_id))
278-
}
279-
280-
pub async fn get_team(
281-
client: &GithubClient,
282-
team: &str,
283-
) -> anyhow::Result<Option<rust_team_data::v1::Team>> {
284-
let permission = crate::team_data::teams(client).await?;
285-
let mut map = permission.teams;
286-
Ok(map.swap_remove(team))
287-
}
288-
289-
/// Fetches a Rust team via its GitHub team name.
290-
pub async fn get_team_by_github_name(
291-
client: &GithubClient,
292-
org: &str,
293-
team: &str,
294-
) -> anyhow::Result<Option<rust_team_data::v1::Team>> {
295-
let teams = crate::team_data::teams(client).await?;
296-
for rust_team in teams.teams.into_values() {
297-
if let Some(github) = &rust_team.github {
298-
for gh_team in &github.teams {
299-
if gh_team.org == org && gh_team.name == team {
300-
return Ok(Some(rust_team));
301-
}
302-
}
303-
}
304-
}
305-
Ok(None)
306-
}
307-
308266
#[derive(PartialEq, Eq, Debug, Clone, serde::Deserialize)]
309267
pub struct Label {
310268
pub name: String,
@@ -2055,10 +2013,11 @@ impl<'q> IssuesQuery for Query<'q> {
20552013
repo: &'a Repository,
20562014
include_fcp_details: bool,
20572015
include_mcp_details: bool,
2058-
client: &'a GithubClient,
2016+
gh_client: &'a GithubClient,
2017+
team_client: &'a TeamClient,
20592018
) -> anyhow::Result<Vec<crate::actions::IssueDecorator>> {
20602019
let issues = repo
2061-
.get_issues(&client, self)
2020+
.get_issues(&gh_client, self)
20622021
.await
20632022
.with_context(|| "Unable to get issues.")?;
20642023

@@ -2071,7 +2030,7 @@ impl<'q> IssuesQuery for Query<'q> {
20712030
};
20722031

20732032
let zulip_map = if include_fcp_details {
2074-
Some(crate::team_data::zulip_map(client).await?)
2033+
Some(team_client.zulip_map().await?)
20752034
} else {
20762035
None
20772036
};
@@ -2101,7 +2060,7 @@ impl<'q> IssuesQuery for Query<'q> {
21012060
let fk_initiating_comment = fcp.fcp.fk_initiating_comment;
21022061
let (initiating_comment_html_url, initiating_comment_content) = {
21032062
let comment = issue
2104-
.get_comment(&client, fk_initiating_comment)
2063+
.get_comment(gh_client, fk_initiating_comment)
21052064
.await
21062065
.with_context(|| {
21072066
format!(
@@ -2166,7 +2125,7 @@ impl<'q> IssuesQuery for Query<'q> {
21662125
};
21672126

21682127
let mcp_details = if include_mcp_details {
2169-
let first100_comments = issue.get_first100_comments(&client).await?;
2128+
let first100_comments = issue.get_first100_comments(&gh_client).await?;
21702129
let (zulip_link, concerns) = if !first100_comments.is_empty() {
21712130
let split = re_zulip_link
21722131
.split(&first100_comments[0].body)
@@ -2881,7 +2840,8 @@ pub trait IssuesQuery {
28812840
repo: &'a Repository,
28822841
include_fcp_details: bool,
28832842
include_mcp_details: bool,
2884-
client: &'a GithubClient,
2843+
gh_client: &'a GithubClient,
2844+
team_client: &'a TeamClient,
28852845
) -> anyhow::Result<Vec<crate::actions::IssueDecorator>>;
28862846
}
28872847

@@ -2894,6 +2854,7 @@ impl IssuesQuery for LeastRecentlyReviewedPullRequests {
28942854
_include_fcp_details: bool,
28952855
_include_mcp_details: bool,
28962856
client: &'a GithubClient,
2857+
_team_client: &'a TeamClient,
28972858
) -> anyhow::Result<Vec<crate::actions::IssueDecorator>> {
28982859
use cynic::QueryBuilder;
28992860
use github_graphql::queries;
@@ -3112,6 +3073,7 @@ impl IssuesQuery for DesignMeetings {
31123073
_include_fcp_details: bool,
31133074
_include_mcp_details: bool,
31143075
client: &'a GithubClient,
3076+
_team_client: &'a TeamClient,
31153077
) -> anyhow::Result<Vec<crate::actions::IssueDecorator>> {
31163078
use github_graphql::project_items::ProjectV2ItemContent;
31173079

src/handlers.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use crate::config::{self, Config, ConfigurationError};
22
use crate::github::{Event, GithubClient, IssueCommentAction, IssuesAction, IssuesEvent};
33
use crate::handlers::pr_tracking::ReviewerWorkqueue;
4+
use crate::team_data::TeamClient;
45
use crate::zulip::client::ZulipClient;
56
use octocrab::Octocrab;
67
use parser::command::{assign::AssignCommand, Command, Input};
@@ -374,6 +375,7 @@ command_handlers! {
374375
pub struct Context {
375376
pub github: GithubClient,
376377
pub zulip: ZulipClient,
378+
pub team: TeamClient,
377379
pub db: crate::db::ClientPool,
378380
pub username: String,
379381
pub octocrab: Octocrab,

src/handlers/assign.rs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -331,7 +331,7 @@ async fn determine_assignee(
331331
diff: &[FileDiff],
332332
) -> anyhow::Result<(Option<ReviewerSelection>, bool)> {
333333
let mut db_client = ctx.db.get().await;
334-
let teams = crate::team_data::teams(&ctx.github).await?;
334+
let teams = &ctx.team.teams().await?;
335335
if let Some(name) = assign_command {
336336
// User included `r?` in the opening PR body.
337337
match find_reviewer_from_names(
@@ -510,8 +510,7 @@ pub(super) async fn handle_command(
510510
event: &Event,
511511
cmd: AssignCommand,
512512
) -> anyhow::Result<()> {
513-
let is_team_member = if let Err(_) | Ok(false) = event.user().is_team_member(&ctx.github).await
514-
{
513+
let is_team_member = if let Err(_) | Ok(false) = event.user().is_team_member(&ctx.team).await {
515514
false
516515
} else {
517516
true
@@ -545,7 +544,7 @@ pub(super) async fn handle_command(
545544
return Ok(());
546545
}
547546

548-
let teams = crate::team_data::teams(&ctx.github).await?;
547+
let teams = ctx.team.teams().await?;
549548

550549
let assignee = match cmd {
551550
AssignCommand::Claim => event.user().login.clone(),

src/handlers/close.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ pub(super) async fn handle_command(
1212
let issue = event.issue().unwrap();
1313
let is_team_member = event
1414
.user()
15-
.is_team_member(&ctx.github)
15+
.is_team_member(&ctx.team)
1616
.await
1717
.unwrap_or(false);
1818
if !is_team_member {

src/handlers/major_change.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -256,7 +256,7 @@ pub(super) async fn handle_command(
256256

257257
let is_team_member = event
258258
.user()
259-
.is_team_member(&ctx.github)
259+
.is_team_member(&ctx.team)
260260
.await
261261
.ok()
262262
.unwrap_or(false);

src/handlers/nominate.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,7 @@ pub(super) async fn handle_command(
1414
event: &Event,
1515
cmd: NominateCommand,
1616
) -> anyhow::Result<()> {
17-
let is_team_member = if let Err(_) | Ok(false) = event.user().is_team_member(&ctx.github).await
18-
{
17+
let is_team_member = if let Err(_) | Ok(false) = event.user().is_team_member(&ctx.team).await {
1918
false
2019
} else {
2120
true

src/handlers/notification.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
//! Parsing is done in the `parser::command::ping` module.
66
77
use crate::db::{notifications, users};
8-
use crate::github::get_id_for_username;
98
use crate::{
109
github::{self, Event},
1110
handlers::Context,
@@ -69,7 +68,7 @@ pub(super) async fn handle(ctx: &Context, event: &Event) -> anyhow::Result<()> {
6968
//
7069
// If the user intended to ping themselves, they can add the GitHub comment
7170
// via the Zulip interface.
72-
match get_id_for_username(&ctx.github, &event.user().login).await {
71+
match ctx.team.get_gh_id_from_username(&event.user().login).await {
7372
Ok(Some(id)) => {
7473
users_notified.insert(id.try_into().unwrap());
7574
}
@@ -136,7 +135,7 @@ async fn id_from_user(
136135
//
137136
// We may also want to be able to categorize into these buckets
138137
// *after* the ping occurs and is initially processed.
139-
let team = match github::get_team_by_github_name(&ctx.github, org, team).await {
138+
let team = match ctx.team.get_team_by_github_name(org, team).await {
140139
Ok(Some(team)) => team,
141140
Ok(None) => {
142141
// If the team is in rust-lang*, then this is probably an error (potentially user
@@ -170,7 +169,9 @@ async fn id_from_user(
170169
Some(team.name),
171170
)))
172171
} else {
173-
let id = get_id_for_username(&ctx.github, login)
172+
let id = ctx
173+
.team
174+
.get_gh_id_from_username(login)
174175
.await
175176
.with_context(|| format!("failed to get user {} ID", login))?;
176177
let Some(id) = id else {

src/handlers/ping.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,7 @@ pub(super) async fn handle_command(
1818
event: &Event,
1919
team_name: PingCommand,
2020
) -> anyhow::Result<()> {
21-
let is_team_member = if let Err(_) | Ok(false) = event.user().is_team_member(&ctx.github).await
22-
{
21+
let is_team_member = if let Err(_) | Ok(false) = event.user().is_team_member(&ctx.team).await {
2322
false
2423
} else {
2524
true
@@ -49,7 +48,7 @@ pub(super) async fn handle_command(
4948
return Ok(());
5049
}
5150
};
52-
let team = github::get_team(&ctx.github, &gh_team).await?;
51+
let team = ctx.team.get_team(&gh_team).await?;
5352
let team = match team {
5453
Some(team) => team,
5554
None => {

0 commit comments

Comments
 (0)