Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 6 additions & 3 deletions crates/forge/src/admin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,19 +103,22 @@ pub fn repo_set_pull_floor(data_dir: &Path, owner: &str, name: &str, floor: i64)
Ok(())
}

/// `admin org create`.
pub fn org_create(data_dir: &Path, name: &str, owner: &str) -> Result<()> {
/// `admin org create`, with Gitea's visibility values (`public`, `limited`, `private`).
pub fn org_create(data_dir: &Path, name: &str, owner: &str, visibility: &str) -> Result<()> {
if names::check(name).is_err() {
bail!("invalid or reserved organization name {name:?}");
}
if !crate::api::valid_visibility(visibility) {
bail!("invalid visibility {visibility:?}: use public, limited or private");
}
let mut conn = db::open_for_admin(data_dir)?;
let owner = store::find_by_login(&conn, owner)?
.filter(|u| !u.is_org)
.ok_or_else(|| anyhow!("owner does not exist [name: {owner}]"))?;
let acct = NewAccount {
login: name.into(),
is_org: true,
visibility: "public".into(),
visibility: visibility.into(),
..Default::default()
};
match store::create_org(&mut conn, &acct, owner.id, now()) {
Expand Down
6 changes: 5 additions & 1 deletion crates/forge/src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,9 @@ enum OrgCmd {
name: String,
#[arg(long)]
owner: String,
/// `public`, `limited` or `private`, as in Gitea.
#[arg(long, default_value = "public")]
visibility: String,
#[arg(long)]
data_dir: PathBuf,
},
Expand Down Expand Up @@ -272,10 +275,11 @@ fn run_admin(cmd: AdminCmd) -> Result<()> {
OrgCmd::Create {
name,
owner,
visibility,
data_dir,
},
} => {
admin::org_create(&data_dir, &name, &owner)?;
admin::org_create(&data_dir, &name, &owner, &visibility)?;
println!("Organization '{name}' has been successfully created!");
}
AdminCmd::Repo {
Expand Down
3 changes: 2 additions & 1 deletion crates/forge/src/protection.rs
Original file line number Diff line number Diff line change
Expand Up @@ -159,8 +159,9 @@ fn is_default(v: &Value) -> bool {
}
}

/// Does `s` use Gitea's glob syntax (its compiler gives `* ? [ { \\` a meaning)?
fn has_glob(s: &str) -> bool {
s.contains(['*', '?', '['])
s.contains(['*', '?', '[', '{', '\\'])
}

fn contexts_of(v: &Value) -> Result<Option<Vec<String>>, String> {
Expand Down
6 changes: 5 additions & 1 deletion crates/forge/tests/e2e_a.rs
Original file line number Diff line number Diff line change
Expand Up @@ -650,8 +650,12 @@ fn admin_cli_changes_are_visible_to_the_running_server() {
.status,
201
);
scl_forge::admin::org_create(&s.dir, "cliorg", "carol").unwrap();
scl_forge::admin::org_create(&s.dir, "cliorg", "carol", "public").unwrap();
assert_eq!(s.get("/api/v1/orgs/cliorg", &token(&s.admin)).status, 200);
scl_forge::admin::org_create(&s.dir, "hidden", "carol", "private").unwrap();
let r = s.get("/api/v1/orgs/hidden", &token(&s.admin));
assert_eq!(r.json()["visibility"], "private");
assert!(scl_forge::admin::org_create(&s.dir, "odd", "carol", "secret").is_err());
assert!(scl_forge::admin::user_create(
&s.dir,
"carol",
Expand Down
6 changes: 6 additions & 0 deletions crates/forge/tests/e2e_protection.rs
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,12 @@ fn rule_crud_validation_and_the_branch_object() {
422,
"patterns are not supported",
),
(
"brace glob",
json!({"branch_name": "{main,release}"}),
422,
"patterns are not supported",
),
(
"approvals",
json!({"branch_name": "x", "required_approvals": 2}),
Expand Down
2 changes: 1 addition & 1 deletion docs/superpowers/specs/2026-10-22-p38-forge-design.md
Original file line number Diff line number Diff line change
Expand Up @@ -510,7 +510,7 @@ sc-forge serve --data-dir DIR --listen ADDR --public-url URL [--behind-proxy|--a
sc-forge admin user create --username U --password P --email E [--admin] [--must-change-password=false]
sc-forge admin user change-password --username U --password P [--must-change-password=false]
sc-forge admin user generate-access-token --username U [--token-name N] [--scopes S,…] [--raw]
sc-forge admin org create --name O --owner U
sc-forge admin org create --name O --owner U [--visibility public|limited|private]
sc-forge hook pre-receive|post-receive # internal
```

Expand Down
Loading