Skip to content

Add App Install Command#157

Closed
kivlor wants to merge 1 commit into
runtipi:developfrom
kivlor:feat/add-install-command
Closed

Add App Install Command#157
kivlor wants to merge 1 commit into
runtipi:developfrom
kivlor:feat/add-install-command

Conversation

@kivlor
Copy link
Copy Markdown

@kivlor kivlor commented Jun 7, 2026

Summary by CodeRabbit

Release Notes

  • New Features
    • Added app install subcommand to install applications with configurable options including port, backup limits, domain, visibility, and authentication settings
    • Support for custom installation parameters via --set flag for advanced configuration

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Jun 7, 2026

Review Change Stack

Walkthrough

This PR adds support for an app install subcommand to the runtipi-cli tool. It defines new types to hold install parameters, implements CLI flag handling and validation, wires the subcommand into the Cobra command tree, and updates the service layer to marshal install options into a JSON API request.

Changes

App install subcommand

Layer / File(s) Summary
Install command types and constants
internal/types/args.go
AppArgs gains InstallOptions map[string]any, a new AppInstallFlags struct holds install CLI parameters (port, domain, backups, auth/visibility toggles, and --set overrides), and AppCommandInstall constant is added.
Install flag building and binding
internal/flags/app.go
BuildAppInstallOptions maps changed CLI flags to an options map and validates --set key=value entries; BindAppInstallFlags registers all install flags on a Cobra command, binding them into AppInstallFlags struct fields.
CLI command registration and wiring
cmd/runtipi/main.go
Imports flags package, adds appInstallArgs variable, defines appInstallCmd that requires [app-urn] argument, binds flags, builds options map, and calls commands.RunApp(appArgs); registers command with appCmd.
Install request handling in service
internal/commands/app.go
RunApp handles AppCommandInstall case by JSON-marshaling args.InstallOptions with error handling, then POSTing the payload to the install endpoint.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • runtipi/cli#111: Both extend commands.RunApp(appArgs) with new app subcommand handling; this PR adds install-specific payload marshaling on top of existing logic.
  • runtipi/cli#112: Both modify RunApp in internal/commands/app.go; this PR updates install request handling while the other adjusts base URL construction.
  • runtipi/cli#120: Both extend app command wiring and RunApp switch to handle new AppCommand subcommands (this: install; other: backup/restore/list/delete).

Suggested labels

size/L

Suggested reviewers

  • nicotsx
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The pull request title 'Add App Install Command' directly and clearly summarizes the main change: introducing a new app install subcommand to the CLI.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@internal/flags/app.go`:
- Around line 56-62: The --set parsing loop (iterating args.SetOptions and
writing into options) can overwrite built-in-flag-typed fields (e.g., --port)
with strings; update the logic in the block that processes args.SetOptions to
detect conflicts with existing built-in flags/keys (inspect the options map or
the canonical flag names like "port") and either reject the --set entry with a
clear error or coerce the string to the built-in type before writing; ensure you
reference and check the same keys used by built-in flags (e.g., "port") so a
--set of a built-in flag does not silently replace an int with a string.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 2ac8042b-ab2d-4b9b-9c0c-5e925f044457

📥 Commits

Reviewing files that changed from the base of the PR and between febb939 and a23f924.

📒 Files selected for processing (5)
  • cmd/runtipi/main.go
  • internal/commands/app.go
  • internal/flags/app.go
  • internal/types/args.go
  • mise.toml

Comment thread internal/flags/app.go
Comment on lines +56 to +62
for _, option := range args.SetOptions {
key, value, ok := strings.Cut(option, "=")
if !ok || key == "" {
return nil, fmt.Errorf("invalid --set value %q. Expected key=value", option)
}
options[key] = value
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Type inconsistency: --set values can overwrite built-in flags with strings instead of typed values.

When a user provides --set port=8080, the code stores "8080" (string) in options["port"], but the built-in --port flag stores an int. This creates two problems:

  1. Type mismatch: The API receives mixed types for the same field depending on which flag was used.
  2. Silent overwrite: If both --port 8080 and --set port=9090 are specified, the --set silently overwrites the typed int with the string "9090".

This could cause the API to reject the request or misinterpret the value.

🛡️ Proposed fix: detect and prevent conflicts

Add validation before processing --set options to detect conflicts with built-in flags:

+	// Known built-in option keys
+	knownOptions := map[string]bool{
+		"port": true, "maxBackups": true, "domain": true, "localSubdomain": true,
+		"exposed": true, "exposedLocal": true, "openPort": true,
+		"isVisibleOnGuestDashboard": true, "enableAuth": true,
+		"skipEnv": true, "skipPull": true, "skipRun": true, "forcePull": true,
+	}
+
 	for _, option := range args.SetOptions {
 		key, value, ok := strings.Cut(option, "=")
 		if !ok || key == "" {
 			return nil, fmt.Errorf("invalid --set value %q. Expected key=value", option)
 		}
+		if knownOptions[key] {
+			return nil, fmt.Errorf("--set key %q conflicts with built-in flag --%s. Use the built-in flag instead", key, flagNameFromKey(key))
+		}
 		options[key] = value
 	}

Alternatively, document that --set is only for custom app-specific fields, not built-in options.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/flags/app.go` around lines 56 - 62, The --set parsing loop
(iterating args.SetOptions and writing into options) can overwrite
built-in-flag-typed fields (e.g., --port) with strings; update the logic in the
block that processes args.SetOptions to detect conflicts with existing built-in
flags/keys (inspect the options map or the canonical flag names like "port") and
either reject the --set entry with a clear error or coerce the string to the
built-in type before writing; ensure you reference and check the same keys used
by built-in flags (e.g., "port") so a --set of a built-in flag does not silently
replace an int with a string.

@kivlor
Copy link
Copy Markdown
Author

kivlor commented Jun 7, 2026

Sorry, this PR was opened by a local Clanker 🤖

@kivlor kivlor closed this Jun 7, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant