@@ -9,6 +9,8 @@ mod schema;
9
9
mod static_api;
10
10
mod validate;
11
11
12
+ const AVAILABLE_SERVICES : & [ & str ] = & [ "github" , "mailgun" , "zulip" ] ;
13
+
12
14
const USER_AGENT : & str = "https://github.com/rust-lang/team (infra@rust-lang.org)" ;
13
15
14
16
use api:: zulip:: ZulipApi ;
@@ -23,6 +25,8 @@ use clap::Parser;
23
25
use log:: { error, info, warn} ;
24
26
use std:: collections:: { BTreeMap , HashMap } ;
25
27
use std:: path:: PathBuf ;
28
+ use sync_team:: run_sync_team;
29
+ use sync_team:: team_api:: TeamApi ;
26
30
27
31
#[ derive( clap:: ValueEnum , Clone , Debug ) ]
28
32
enum DumpIndividualAccessGroupBy {
@@ -83,6 +87,15 @@ enum Cli {
83
87
/// CI scripts
84
88
#[ clap( subcommand) ]
85
89
Ci ( CiOpts ) ,
90
+ /// Perform synchronization of the local data to live services.
91
+ /// Environment variables:
92
+ /// - GITHUB_TOKEN Authentication token with GitHub
93
+ /// - MAILGUN_API_TOKEN Authentication token with Mailgun
94
+ /// - EMAIL_ENCRYPTION_KEY Key used to decrypt encrypted emails in the team repo
95
+ /// - ZULIP_USERNAME Username of the Zulip bot
96
+ /// - ZULIP_API_TOKEN Authentication token of the Zulip bot
97
+ #[ clap( verbatim_doc_comment) ]
98
+ Sync ( SyncOpts ) ,
86
99
}
87
100
88
101
#[ derive( clap:: Parser , Debug ) ]
@@ -93,11 +106,42 @@ enum CiOpts {
93
106
CheckCodeowners ,
94
107
}
95
108
109
+ #[ derive( clap:: Parser , Debug ) ]
110
+ struct SyncOpts {
111
+ /// Comma-separated list of available services
112
+ #[ clap( long, global( true ) , value_parser = clap:: builder:: PossibleValuesParser :: new(
113
+ AVAILABLE_SERVICES
114
+ ) , value_delimiter = ',' ) ]
115
+ services : Vec < String > ,
116
+
117
+ /// Path to a checkout of `rust-lang/team`.
118
+ #[ clap( long, global( true ) , conflicts_with = "team_json" ) ]
119
+ team_repo : Option < PathBuf > ,
120
+
121
+ /// Path to a directory with prebuilt JSON data from the `team` repository.
122
+ #[ clap( long, global( true ) ) ]
123
+ team_json : Option < PathBuf > ,
124
+
125
+ #[ clap( subcommand) ]
126
+ command : Option < SyncCommand > ,
127
+ }
128
+
129
+ #[ derive( clap:: Parser , Debug ) ]
130
+ enum SyncCommand {
131
+ /// Try to apply changes, but do not send any outgoing API requests.
132
+ DryRun ,
133
+ /// Only print a diff of what would be changed.
134
+ PrintPlan ,
135
+ /// Apply the changes to the specified services.
136
+ Apply ,
137
+ }
138
+
96
139
fn main ( ) {
97
140
let mut env = env_logger:: Builder :: new ( ) ;
98
141
env. format_timestamp ( None ) ;
99
142
env. format_module_path ( false ) ;
100
143
env. filter_module ( "rust_team" , log:: LevelFilter :: Info ) ;
144
+ env. filter_module ( "sync_team" , log:: LevelFilter :: Info ) ;
101
145
if std:: env:: var ( "RUST_TEAM_FORCE_COLORS" ) . is_ok ( ) {
102
146
env. write_style ( env_logger:: WriteStyle :: Always ) ;
103
147
}
@@ -406,6 +450,16 @@ fn run() -> Result<(), Error> {
406
450
CiOpts :: GenerateCodeowners => generate_codeowners_file ( data) ?,
407
451
CiOpts :: CheckCodeowners => check_codeowners ( data) ?,
408
452
} ,
453
+ Cli :: Sync ( opts) => {
454
+ if let Err ( err) = perform_sync ( opts) {
455
+ // Display shows just the first element of the chain.
456
+ error ! ( "failed: {}" , err) ;
457
+ for cause in err. chain ( ) . skip ( 1 ) {
458
+ error ! ( "caused by: {}" , cause) ;
459
+ }
460
+ std:: process:: exit ( 1 ) ;
461
+ }
462
+ }
409
463
}
410
464
411
465
Ok ( ( ) )
@@ -437,3 +491,27 @@ fn dump_team_members(
437
491
}
438
492
Ok ( ( ) )
439
493
}
494
+
495
+ fn perform_sync ( opts : SyncOpts ) -> anyhow:: Result < ( ) > {
496
+ let team_api = if let Some ( path) = opts. team_repo {
497
+ TeamApi :: Checkout ( path)
498
+ } else if let Some ( path) = opts. team_json {
499
+ TeamApi :: Prebuilt ( path)
500
+ } else {
501
+ TeamApi :: Production
502
+ } ;
503
+
504
+ let mut services = opts. services ;
505
+ if services. is_empty ( ) {
506
+ info ! ( "no service to synchronize specified, defaulting to all services" ) ;
507
+ services = AVAILABLE_SERVICES
508
+ . iter ( )
509
+ . map ( |s| ( * s) . to_string ( ) )
510
+ . collect ( ) ;
511
+ }
512
+
513
+ let subcmd = opts. command . unwrap_or ( SyncCommand :: DryRun ) ;
514
+ let only_print_plan = matches ! ( subcmd, SyncCommand :: PrintPlan ) ;
515
+ let dry_run = only_print_plan || matches ! ( subcmd, SyncCommand :: DryRun ) ;
516
+ run_sync_team ( team_api, & services, dry_run, only_print_plan)
517
+ }
0 commit comments