Skip to content
Open
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
38 changes: 35 additions & 3 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ The application follows a command-line interface pattern using the Cobra library
- **main.go**: Core CLI structure with command definitions and configuration management
- **auth.go**: OAuth2 device flow authentication with JWT token handling
- **datasets.go**: Dataset operations (list, download, upload, status) with REST API integration
- **registries.go**: Registry operations (list, config, add, update) with REST API integration
- **registries.go**: Registry operations (list, config, add, update, registrator) with REST API integration
- **packages.go**: Package operations (search, dependency) with REST API primary path (`/packages/info`), GraphQL fallback, and documentation API (`/docs/{registry}/{package}/stable/pkg.json`)
- **projects.go**: Project management using GraphQL API with user filtering
- **user.go**: User information retrieval using GraphQL API and REST API for listing users
Expand Down Expand Up @@ -44,12 +44,16 @@ The application follows a command-line interface pattern using the Cobra library
- `jh dataset`: Dataset operations (list, download, upload, status)
- `jh registry`: Registry operations (list, config — all via REST API)
- `jh registry config`: Show registry JSON config by name; subcommands add/update accept JSON via stdin or `--file`
- `jh registry permission`: Registry permission management (list, set, remove)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like unrelated change

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

was missed in the previous merged pr, if you want i can add in separately

- `jh registry registrator`: Show registrator config by name; subcommand update accepts JSON via stdin or `--file`
- `jh package`: Package search and dependency (REST primary via `/packages/info`, GraphQL fallback; dependency data from `/docs/{registry}/{package}/stable/pkg.json`)
- `jh project`: Project management (list with GraphQL, supports user filtering)
- `jh user`: User information (info with GraphQL)
- `jh admin`: Administrative commands (user management, token management, credential management, landing page)
- `jh user`: User information (info, list via GraphQL `public_users`)
- `jh group`: Group information (list via GraphQL)
- `jh admin`: Administrative commands (user management, token management, group management, credential management, landing page)
- `jh admin user`: User management (list all users with REST API, supports verbose mode)
- `jh admin token`: Token management (list all tokens with REST API, supports verbose mode)
- `jh admin group`: Group management (list all groups via REST API)
- `jh admin credential`: Registry credential management (list, add, update, delete via REST API)
- `jh admin credential list`: List all registry credentials (tokens, SSH keys, GitHub Apps); supports verbose mode
- `jh admin credential add`: Add a credential — subcommands: `token`, `ssh`, `github-app`; accepts JSON argument or stdin
Expand Down Expand Up @@ -141,6 +145,24 @@ go run . registry config add --file registry.json

# Update an existing registry (same JSON schema, same flags)
go run . registry config update --file registry.json

# Show registrator config for a registry
go run . registry registrator MyRegistry

# Update registrator config (JSON via stdin or --file)
echo '{
"enabled": true,
"email": "pkg@example.com",
"authorization": true,
"ssl_verify": true,
"registry_fork_url": null,
"registry_deps": ["General"]
}' | go run . registry registrator update MyRegistry
go run . registry registrator update MyRegistry --file registrator.json

# Get, edit, push back
go run . registry registrator MyRegistry > registrator.json
go run . registry registrator update MyRegistry --file registrator.json
```

### Test project and user operations
Expand Down Expand Up @@ -430,6 +452,10 @@ jh run setup
- Registry add/update commands (`jh registry config add` / `jh registry config update`) use REST API endpoint `/api/v1/registry/config/registry/{name}` (POST); the backend creates or updates based on whether the registry already exists
- Both commands accept the full registry JSON payload via `--file <path>` or stdin; the payload `name` field identifies the registry
- Registry add/update always poll `/api/v1/registry/config/registry/{name}/savestatus` every 3 seconds up to a 2-minute timeout
- Registry registrator command (`jh registry registrator <name>`) uses REST API endpoint `/api/v1/registry/config/registrator/{name}` (GET) and prints the full JSON response
- Registry registrator update command (`jh registry registrator update <name>`) uses REST API endpoint `/api/v1/registry/config/registrator/{name}` (POST); the registry name comes from the positional argument (`RegistratorInfo` has no `name` field)
- Registrator update validates that `"email"` is non-empty when `"enabled"` is true
- GET returns 404 "Registry not found" when no registrator has been configured for that registry yet
- Bundle provider type automatically sets `license_detect: false` in the payload
- Admin token list command (`jh admin token list`) uses REST API endpoint `/app/token/activelist` which requires appropriate permissions
- Token list output is concise by default (Subject, Created By, and Expired status only); use `--verbose` flag for detailed information (signature, creation date, expiration date with estimate indicator)
Expand Down Expand Up @@ -476,6 +502,12 @@ jh run setup
- `submitRegistry` POSTs to `/api/v1/registry/config/registry/{name}` with retry on 500s, then calls `pollRegistrySaveStatus()`
- `pollRegistrySaveStatus` GETs `/api/v1/registry/config/registry/{name}/savestatus` every 3 seconds up to a 2-minute deadline

**`jh registry registrator <name>` / `jh registry registrator update`:**

- `getRegistrator` uses `apiGet` to GET `/api/v1/registry/config/registrator/{name}` and pretty-prints the JSON response
- `setRegistrator(server, name, filePath)` reads `RegistratorInfo` JSON from `--file` or stdin, validates `"email"` is set when `"enabled"` is true, then POSTs to `/api/v1/registry/config/registrator/{name}`
- No polling — the POST response is the final result

### Julia Credentials Management (`run.go`)

The Julia credentials system consists of three main functions:
Expand Down
57 changes: 56 additions & 1 deletion main.go
Original file line number Diff line number Diff line change
Expand Up @@ -1128,6 +1128,57 @@ Exactly one of --user or --group must be provided.`,
},
}

var registryRegistratorCmd = &cobra.Command{
Use: "registrator <name>",
Short: "Show the registrator configuration for a registry",
Example: " jh registry registrator MyRegistry\n jh registry registrator MyRegistry -s nightly.juliahub.dev",
Args: cobra.ExactArgs(1),
Run: func(cmd *cobra.Command, args []string) {
server, err := getServerFromFlagOrConfig(cmd)
if err != nil {
fmt.Printf("Failed to get server config: %v\n", err)
os.Exit(1)
}
if err := getRegistrator(server, args[0]); err != nil {
fmt.Printf("Failed to get registrator config: %v\n", err)
os.Exit(1)
}
},
}

var registryRegistratorUpdateCmd = &cobra.Command{
Use: "update <registry>",
Short: "Update the registrator configuration for a registry",
Long: `Update the registrator configuration for a Julia package registry.

Reads the registrator configuration from a JSON file (--file) or stdin.

REGISTRATOR JSON SCHEMA

{
"enabled": true, // enable/disable registrator
"email": "<email>", // required when enabled
"authorization": true, // allow only package authors to register
"ssl_verify": true, // verify SSL certificates
"registry_fork_url": "<url>", // URL to a forked registry with write access (optional, null to unset)
"registry_deps": ["<registry>", ...] // registries whose packages may be dependencies
}`,
Example: " jh registry registrator update MyRegistry --file registrator.json\n jh registry registrator MyRegistry | jh registry registrator update MyRegistry",
Args: cobra.ExactArgs(1),
Run: func(cmd *cobra.Command, args []string) {
server, err := getServerFromFlagOrConfig(cmd)
if err != nil {
fmt.Printf("Failed to get server config: %v\n", err)
os.Exit(1)
}
filePath, _ := cmd.Flags().GetString("file")
if err := setRegistrator(server, args[0], filePath); err != nil {
fmt.Printf("Failed to update registrator config: %v\n", err)
os.Exit(1)
}
},
}

var projectCmd = &cobra.Command{
Use: "project",
Short: "Project management commands",
Expand Down Expand Up @@ -2200,7 +2251,11 @@ func init() {
registryPermissionRemoveCmd.Flags().String("user", "", "Username to remove permission for")
registryPermissionRemoveCmd.Flags().String("group", "", "Group name to remove permission for")
registryPermissionCmd.AddCommand(registryPermissionListCmd, registryPermissionSetCmd, registryPermissionRemoveCmd)
registryCmd.AddCommand(registryListCmd, registryConfigCmd, registryPermissionCmd)
registryRegistratorCmd.Flags().StringP("server", "s", "", "JuliaHub server")
registryRegistratorUpdateCmd.Flags().StringP("server", "s", "", "JuliaHub server")
registryRegistratorUpdateCmd.Flags().StringP("file", "f", "", "Path to JSON config file (reads from stdin if omitted)")
registryRegistratorCmd.AddCommand(registryRegistratorUpdateCmd)
registryCmd.AddCommand(registryListCmd, registryConfigCmd, registryPermissionCmd, registryRegistratorCmd)
projectCmd.AddCommand(projectListCmd)
userListGQLCmd.Flags().StringP("server", "s", "juliahub.com", "JuliaHub server")
userCmd.AddCommand(userInfoCmd, userListGQLCmd)
Expand Down
Loading