collab: Fix GitHub user retrieval in seed script (#18296)

This PR fixes the GitHub user retrieval in the database seed script.

The users returned from the [list
users](https://docs.github.com/en/rest/users/users?apiVersion=2022-11-28#list-users)
endpoint don't have a `created_at` timestamp, so we need to fetch them
individually.

I want to rework this further at a later date, this is just a bandaid to
get things working again.

Release Notes:

- N/A
This commit is contained in:
Marshall Bowers 2024-09-24 15:44:55 -04:00 committed by GitHub
parent 87ac4cff60
commit 692590bff4
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 44 additions and 5 deletions

View file

@ -298,6 +298,12 @@ impl Database {
result
}
/// Returns all feature flags.
pub async fn list_feature_flags(&self) -> Result<Vec<feature_flag::Model>> {
self.transaction(|tx| async move { Ok(feature_flag::Entity::find().all(&*tx).await?) })
.await
}
/// Creates a new feature flag.
pub async fn create_user_flag(&self, flag: &str, enabled_for_all: bool) -> Result<FlagId> {
self.transaction(|tx| async move {

View file

@ -16,13 +16,23 @@ struct GithubUser {
created_at: DateTime<Utc>,
}
/// A GitHub user returned from the [List users](https://docs.github.com/en/rest/users/users?apiVersion=2022-11-28#list-users) endpoint.
///
/// Notably, this data type does not have the `created_at` field.
#[derive(Debug, Deserialize)]
struct ListGithubUser {
id: i32,
login: String,
email: Option<String>,
}
#[derive(Deserialize)]
struct SeedConfig {
// Which users to create as admins.
/// Which users to create as admins.
admins: Vec<String>,
// Which channels to create (all admins are invited to all channels)
/// Which channels to create (all admins are invited to all channels).
channels: Vec<String>,
// Number of random users to create from the Github API
/// Number of random users to create from the Github API.
number_of_users: Option<usize>,
}
@ -47,11 +57,21 @@ pub async fn seed(config: &Config, db: &Database, force: bool) -> anyhow::Result
let flag_names = ["remoting", "language-models"];
let mut flags = Vec::new();
let existing_feature_flags = db.list_feature_flags().await?;
for flag_name in flag_names {
if existing_feature_flags
.iter()
.any(|flag| flag.flag == flag_name)
{
log::info!("Flag {flag_name:?} already exists");
continue;
}
let flag = db
.create_user_flag(flag_name, false)
.await
.unwrap_or_else(|_| panic!("failed to create flag: '{flag_name}'"));
.unwrap_or_else(|err| panic!("failed to create flag: '{flag_name}': {err}"));
flags.push(flag);
}
@ -121,9 +141,19 @@ pub async fn seed(config: &Config, db: &Database, force: bool) -> anyhow::Result
if let Some(last_user_id) = last_user_id {
write!(&mut uri, "&since={}", last_user_id).unwrap();
}
let users = fetch_github::<Vec<GithubUser>>(&client, &uri).await;
let users = fetch_github::<Vec<ListGithubUser>>(&client, &uri).await;
for github_user in users {
log::info!("Seeding {:?} from GitHub", github_user.login);
// Fetch the user to get their `created_at` timestamp, since it
// isn't on the list response.
let github_user: GithubUser = fetch_github(
&client,
&format!("https://api.github.com/user/{}", github_user.id),
)
.await;
last_user_id = Some(github_user.id);
user_count += 1;
let user = db
@ -143,6 +173,9 @@ pub async fn seed(config: &Config, db: &Database, force: bool) -> anyhow::Result
flag, user.id
))?;
}
// Sleep to avoid getting rate-limited by GitHub.
tokio::time::sleep(std::time::Duration::from_millis(250)).await;
}
}
}