Skip to content

Commit d5b438b

Browse files
authored
Merge pull request #1696 from Kobzol/codeowners
Add CODEOWNERS
2 parents c467c7d + ab668ac commit d5b438b

File tree

4 files changed

+129
-0
lines changed

4 files changed

+129
-0
lines changed

.github/CODEOWNERS

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# This is an automatically generated file
2+
# Run `cargo run ci generate-codeowners` to regenerate it.
3+
4+
/.github/ @Mark-Simulacrum @pietroalbini @jdno @marcoieni
5+
/src/ @Mark-Simulacrum @pietroalbini @jdno @marcoieni
6+
/rust_team_data/ @Mark-Simulacrum @pietroalbini @jdno @marcoieni
7+
/repos/rust-lang/team.toml @Mark-Simulacrum @pietroalbini @jdno @marcoieni
8+
/repos/rust-lang/sync-team.toml @Mark-Simulacrum @pietroalbini @jdno @marcoieni
9+
/teams/infra-admins.toml @Mark-Simulacrum @pietroalbini @jdno @marcoieni
10+
/teams/team-repo-admins.toml @Mark-Simulacrum @pietroalbini @jdno @marcoieni
11+
.cargo @Mark-Simulacrum @pietroalbini @jdno @marcoieni
12+
target @Mark-Simulacrum @pietroalbini @jdno @marcoieni
13+
Cargo.lock @Mark-Simulacrum @pietroalbini @jdno @marcoieni
14+
Cargo.toml @Mark-Simulacrum @pietroalbini @jdno @marcoieni
15+
config.toml @Mark-Simulacrum @pietroalbini @jdno @marcoieni
16+
/people/Mark-Simulacrum.toml @Mark-Simulacrum @pietroalbini @jdno @marcoieni
17+
/people/pietroalbini.toml @Mark-Simulacrum @pietroalbini @jdno @marcoieni
18+
/people/jdno.toml @Mark-Simulacrum @pietroalbini @jdno @marcoieni
19+
/people/marcoieni.toml @Mark-Simulacrum @pietroalbini @jdno @marcoieni

.github/workflows/main.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,9 @@ jobs:
3838
- name: Run tests
3939
run: cargo test --workspace --all-features
4040

41+
- name: Check CODEOWNERS
42+
run: cargo run ci check-codeowners
43+
4144
- name: Build the contents of the static API
4245
run: |
4346
cargo run -- static-api build

src/ci.rs

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
use crate::schema::Team;
2+
use anyhow::Context;
3+
use std::path::{Path, PathBuf};
4+
5+
/// Generates the contents of `.github/CODEOWNERS`, based on
6+
/// the infra admins in `infra-admins.toml`.
7+
pub fn generate_codeowners_file() -> anyhow::Result<()> {
8+
let admins = load_infra_admins()?;
9+
let codeowners_content = generate_codeowners_content(admins);
10+
std::fs::write(codeowners_path(), codeowners_content).context("cannot write CODEOWNERS")?;
11+
Ok(())
12+
}
13+
14+
/// Check if `.github/CODEOWNERS` are up-to-date, based on the
15+
/// `infra-admins.toml` file.
16+
pub fn check_codeowners() -> anyhow::Result<()> {
17+
let admins = load_infra_admins()?;
18+
let expected_codeowners = generate_codeowners_content(admins);
19+
let actual_codeowners =
20+
std::fs::read_to_string(codeowners_path()).context("cannot read CODEOWNERS")?;
21+
if expected_codeowners != actual_codeowners {
22+
return Err(anyhow::anyhow!("CODEOWNERS content is not up-to-date. Regenerate it using `cargo run ci generate-codeowners`."));
23+
}
24+
25+
Ok(())
26+
}
27+
28+
fn generate_codeowners_content(admins: Vec<String>) -> String {
29+
use std::fmt::Write;
30+
31+
let mut output = String::new();
32+
writeln!(
33+
output,
34+
r#"# This is an automatically generated file
35+
# Run `cargo run ci generate-codeowners` to regenerate it.
36+
"#
37+
)
38+
.unwrap();
39+
40+
let admin_list = admins
41+
.iter()
42+
.map(|admin| format!("@{admin}"))
43+
.collect::<Vec<_>>()
44+
.join(" ");
45+
46+
// Set of paths that should only be modifiable by infra-admins
47+
let mut secure_paths = vec![
48+
"/.github/".to_string(),
49+
"/src/".to_string(),
50+
"/rust_team_data/".to_string(),
51+
"/repos/rust-lang/team.toml".to_string(),
52+
"/repos/rust-lang/sync-team.toml".to_string(),
53+
"/teams/infra-admins.toml".to_string(),
54+
"/teams/team-repo-admins.toml".to_string(),
55+
".cargo".to_string(),
56+
"target".to_string(),
57+
"Cargo.lock".to_string(),
58+
"Cargo.toml".to_string(),
59+
"config.toml".to_string(),
60+
];
61+
for admin in admins {
62+
secure_paths.push(format!("/people/{admin}.toml"));
63+
}
64+
65+
for path in secure_paths {
66+
writeln!(output, "{path} {admin_list}").unwrap();
67+
}
68+
output
69+
}
70+
71+
fn codeowners_path() -> PathBuf {
72+
Path::new(&env!("CARGO_MANIFEST_DIR"))
73+
.join(".github")
74+
.join("CODEOWNERS")
75+
}
76+
77+
fn load_infra_admins() -> anyhow::Result<Vec<String>> {
78+
let admins = std::fs::read_to_string(
79+
Path::new(&env!("CARGO_MANIFEST_DIR"))
80+
.join("teams")
81+
.join("infra-admins.toml"),
82+
)
83+
.context("cannot load infra-admins.toml")?;
84+
let team: Team = toml::from_str(&admins).context("cannot deserialize infra-admins")?;
85+
Ok(team
86+
.raw_people()
87+
.members
88+
.iter()
89+
.map(|member| member.github.clone())
90+
.collect())
91+
}

src/main.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
mod data;
44
#[macro_use]
55
mod permissions;
6+
mod ci;
67
mod github;
78
mod schema;
89
mod static_api;
@@ -15,6 +16,7 @@ use data::Data;
1516
use schema::{Email, Team, TeamKind};
1617
use zulip::ZulipApi;
1718

19+
use crate::ci::{check_codeowners, generate_codeowners_file};
1820
use crate::schema::RepoPermission;
1921
use anyhow::{bail, format_err, Error};
2022
use log::{error, info, warn};
@@ -111,6 +113,16 @@ enum Cli {
111113
EncryptEmail,
112114
#[structopt(name = "decrypt-email", help = "decrypt an email address")]
113115
DecryptEmail,
116+
#[structopt(name = "ci", help = "CI scripts")]
117+
Ci(CiOpts),
118+
}
119+
120+
#[derive(structopt::StructOpt)]
121+
enum CiOpts {
122+
#[structopt(help = "Generate the .github/CODEOWNERS file")]
123+
GenerateCodeowners,
124+
#[structopt(help = "Check if the .github/CODEOWNERS file is up-to-date")]
125+
CheckCodeowners,
114126
}
115127

116128
fn main() {
@@ -422,6 +434,10 @@ fn run() -> Result<(), Error> {
422434
rust_team_data::email_encryption::try_decrypt(&key, &encrypted)?
423435
);
424436
}
437+
Cli::Ci(opts) => match opts {
438+
CiOpts::GenerateCodeowners => generate_codeowners_file()?,
439+
CiOpts::CheckCodeowners => check_codeowners()?,
440+
},
425441
}
426442

427443
Ok(())

0 commit comments

Comments
 (0)