diff --git a/cmd/disttown/project.go b/cmd/disttown/project.go index a2e2411..5334458 100644 --- a/cmd/disttown/project.go +++ b/cmd/disttown/project.go @@ -57,6 +57,60 @@ var cmdProject = &cli.Command{ return nil }, }, + { + Name: "set", + Usage: "update a project's optional fields (only the flags you pass change)", + ArgsUsage: "", + Flags: []cli.Flag{ + &cli.StringFlag{Name: "display-name", Usage: "human-facing name"}, + &cli.StringFlag{Name: "description", Usage: "brief description"}, + &cli.StringFlag{Name: "source", Usage: "source repository: an at:// record uri (e.g. your sh.tangled.repo — same-DID sources are self-authenticated) or an https:// forge URL"}, + &cli.StringFlag{Name: "website", Usage: "project homepage, distinct from source"}, + }, + Action: func(c *cli.Context) error { + if c.Args().Len() != 1 { + return fmt.Errorf("usage: disttown project set --source ...") + } + name := canon.NormalizeName(c.Args().First()) + if err := canon.ValidateName(name); err != nil { + return err + } + if !c.IsSet("display-name") && !c.IsSet("description") && !c.IsSet("source") && !c.IsSet("website") { + return fmt.Errorf("nothing to change: pass at least one of --display-name, --description, --source, --website") + } + s, err := atsession.Get(c.Context) + if err != nil { + return err + } + out, err := atproto.RepoGetRecord(c.Context, s.Client, "", canon.NSIDProject, s.DID, name) + if err != nil { + return fmt.Errorf("reading project %q: %w", name, err) + } + rec, ok := out.Value.Val.(*gen.Project) + if !ok { + return fmt.Errorf("record %q is not a project", name) + } + set := func(flag string, field **string) { + if c.IsSet(flag) { + if v := c.String(flag); v == "" { + *field = nil // explicit empty clears the field + } else { + *field = &v + } + } + } + set("display-name", &rec.DisplayName) + set("description", &rec.Description) + set("source", &rec.Source) + set("website", &rec.Website) + w := updateElem(canon.NSIDProject, name, rec) + if err := applyWrites(c.Context, s, []*atproto.RepoApplyWrites_Input_Writes_Elem{w}); err != nil { + return err + } + fmt.Printf("updated project %s\n %s\n", name, atURI(s.DID, canon.NSIDProject, name)) + return nil + }, + }, { Name: "rename", Usage: "rename a project: a successor record is created and the old record persists as a permanent alias", diff --git a/web/src/routes/docs/cli/+page.md b/web/src/routes/docs/cli/+page.md index c309a16..98d118b 100644 --- a/web/src/routes/docs/cli/+page.md +++ b/web/src/routes/docs/cli/+page.md @@ -131,6 +131,19 @@ Create a bare project record (e.g. an umbrella; publish creates leaf projects on - `--display-name ` — human-facing name - `--description ` — brief description +### project set + +```sh +disttown project set +``` + +Update a project's optional fields (only the flags you pass change) + +- `--display-name ` — human-facing name +- `--description ` — brief description +- `--source ` — source repository: an at:// record uri (e.g. your sh.tangled.repo — same-DID sources are self-authenticated) or an https:// forge URL +- `--website ` — project homepage, distinct from source + ### project rename ```sh