@@ -16,13 +16,23 @@ struct GithubUser {
16
16
created_at : DateTime < Utc > ,
17
17
}
18
18
19
+ /// A GitHub user returned from the [List users](https://docs.github.com/en/rest/users/users?apiVersion=2022-11-28#list-users) endpoint.
20
+ ///
21
+ /// Notably, this data type does not have the `created_at` field.
22
+ #[ derive( Debug , Deserialize ) ]
23
+ struct ListGithubUser {
24
+ id : i32 ,
25
+ login : String ,
26
+ email : Option < String > ,
27
+ }
28
+
19
29
#[ derive( Deserialize ) ]
20
30
struct SeedConfig {
21
- // Which users to create as admins.
31
+ /// Which users to create as admins.
22
32
admins : Vec < String > ,
23
- // Which channels to create (all admins are invited to all channels)
33
+ /// Which channels to create (all admins are invited to all channels).
24
34
channels : Vec < String > ,
25
- // Number of random users to create from the Github API
35
+ /// Number of random users to create from the Github API.
26
36
number_of_users : Option < usize > ,
27
37
}
28
38
@@ -47,11 +57,21 @@ pub async fn seed(config: &Config, db: &Database, force: bool) -> anyhow::Result
47
57
let flag_names = [ "remoting" , "language-models" ] ;
48
58
let mut flags = Vec :: new ( ) ;
49
59
60
+ let existing_feature_flags = db. list_feature_flags ( ) . await ?;
61
+
50
62
for flag_name in flag_names {
63
+ if existing_feature_flags
64
+ . iter ( )
65
+ . any ( |flag| flag. flag == flag_name)
66
+ {
67
+ log:: info!( "Flag {flag_name:?} already exists" ) ;
68
+ continue ;
69
+ }
70
+
51
71
let flag = db
52
72
. create_user_flag ( flag_name, false )
53
73
. await
54
- . unwrap_or_else ( |_ | panic ! ( "failed to create flag: '{flag_name}'" ) ) ;
74
+ . unwrap_or_else ( |err | panic ! ( "failed to create flag: '{flag_name}': {err} " ) ) ;
55
75
flags. push ( flag) ;
56
76
}
57
77
@@ -121,9 +141,19 @@ pub async fn seed(config: &Config, db: &Database, force: bool) -> anyhow::Result
121
141
if let Some ( last_user_id) = last_user_id {
122
142
write ! ( & mut uri, "&since={}" , last_user_id) . unwrap ( ) ;
123
143
}
124
- let users = fetch_github :: < Vec < GithubUser > > ( & client, & uri) . await ;
144
+ let users = fetch_github :: < Vec < ListGithubUser > > ( & client, & uri) . await ;
125
145
126
146
for github_user in users {
147
+ log:: info!( "Seeding {:?} from GitHub" , github_user. login) ;
148
+
149
+ // Fetch the user to get their `created_at` timestamp, since it
150
+ // isn't on the list response.
151
+ let github_user: GithubUser = fetch_github (
152
+ & client,
153
+ & format ! ( "https://api.github.com/user/{}" , github_user. id) ,
154
+ )
155
+ . await ;
156
+
127
157
last_user_id = Some ( github_user. id ) ;
128
158
user_count += 1 ;
129
159
let user = db
@@ -143,6 +173,9 @@ pub async fn seed(config: &Config, db: &Database, force: bool) -> anyhow::Result
143
173
flag, user. id
144
174
) ) ?;
145
175
}
176
+
177
+ // Sleep to avoid getting rate-limited by GitHub.
178
+ tokio:: time:: sleep ( std:: time:: Duration :: from_millis ( 250 ) ) . await ;
146
179
}
147
180
}
148
181
}
0 commit comments