Skip to content

feat(init): add metadata flags for non-interactive project setup#2231

Open
atulya-singh wants to merge 1 commit into
microsoft:mainfrom
atulya-singh:feat/2146-init-metadata-flags
Open

feat(init): add metadata flags for non-interactive project setup#2231
atulya-singh wants to merge 1 commit into
microsoft:mainfrom
atulya-singh:feat/2146-init-metadata-flags

Conversation

@atulya-singh

Copy link
Copy Markdown
Contributor

Closes #2146.

Problem

apm init's interactive mode collects name, version, description and author, but its non-interactive mode exposes no flag for any of them. Scripted / CI / --yes init is therefore pinned to boilerplate and has to hand-edit apm.yml afterwards. The description -- the field an interactive user is most likely to customize -- is the one a non-interactive user cannot set at all.

$ apm init myproj --yes --description "My cool project"
Error: No such option: --description

Change

Adds --name, --description, --version and --author to apm init, following the apm marketplace init --name/--owner precedent already in the CLI.

The overrides are applied at the point where the interactive and --yes paths converge on the config dict, rather than inside _get_default_config() -- that helper has a second caller in commands/install.py which must stay unaffected. The new _perform_init() parameters are keyword-only and default to None, so apm plugin init (the other caller) is unchanged.

The issue's exact invocation now works:

$ apm init myproj --yes --description "My cool project" --version 0.1.0 --author "Jane Dev"
$ cat myproj/apm.yml
name: myproj
version: 0.1.0
description: My cool project
author: Jane Dev

--name boundary

Per the triage panel's note, the positional argument keeps its contract. It does two jobs -- naming the project and mkdir + chdir -- so it takes precedence over --name, which only labels the manifest. --name covers the in-place case interactive init already allowed:

$ apm init --yes --name custom-name     # names the manifest, creates no subdirectory

Passing both reports the ignored flag rather than dropping it silently:

$ apm init myproj --yes --name ignored-name
[!] --name 'ignored-name' ignored: positional project name 'myproj' takes precedence.

--name also gets the same _validate_project_name check the interactive prompt already enforces, so --name ../evil exits 1.

Two findings from tracing the path

  • Plugin-mode version clobber. _perform_init overwrote config["version"] with 0.1.0 after the config was built (if plugin and yes). That would have silently discarded an explicit --version. It is now gated on version is None, preserving the existing default while honoring the flag. Covered by test_explicit_version_survives_plugin_default.
  • The issue's non-TTY claim is inaccurate. It states non-interactive is "--yes or non-TTY stdin", but the metadata branch keys purely on yes; _stdin_is_tty() only guards the target prompt. Rather than have flags silently ignored outside --yes, they seed the matching prompt defaults, so an empty answer still yields the flag value. This keeps the change consistent with the project's stance against silent field loss. Covered by test_flags_seed_interactive_prompts.

Tests

11 new tests in tests/unit/test_init_command.py::TestInitMetadataFlags, all verified to fail on unmodified main before the fix:

Test Contract
test_description_flag_overrides_boilerplate --description beats auto-detected boilerplate
test_version_flag_overrides_default --version replaces hardcoded 1.0.0
test_author_flag_overrides_git_detection --author beats git config user.name
test_all_metadata_flags_together the issue's full invocation writes exact values
test_name_flag_names_project_in_place --name labels manifest, creates no subdirectory
test_name_flag_applies_with_explicit_dot apm init . --name x is the in-place case
test_positional_arg_wins_over_name_flag_with_warning positional wins; --name reported, not dropped
test_name_flag_rejects_path_separators --name ../evil exits 1
test_flags_seed_interactive_prompts flags honored outside --yes
test_plugin_init_unaffected_by_new_params apm plugin init keeps its 0.1.0 default
test_explicit_version_survives_plugin_default --version survives plugin mode

tests/unit/test_init_command.py: 69 passed (58 pre-existing + 11 new). Wider run across init/plugin/install/helpers/cli: 5152 passed. Three failures there (test_mcp_integrator_install_flow, test_mcp_integrator_install_phase3, test_helpers::test_is_tool_available) were confirmed pre-existing by stashing the change and re-running on clean main. ruff check and ruff format --check clean.

CHANGELOG entry added under [Unreleased] / Added.

`apm init` collected name, version, description and author interactively
but exposed no flag for any of them, so scripted and CI init was pinned to
boilerplate and had to hand-edit apm.yml afterwards. The description --
the field an interactive user is most likely to customize -- was the one a
non-interactive user could not set at all.

Add --name, --description, --version and --author. The overrides are
applied where the interactive and --yes paths converge on the config dict,
so _get_default_config() stays untouched for its other caller in
commands/install.py. The new _perform_init() parameters are keyword-only
and default to None, leaving `apm plugin init` unchanged.

Two details worth noting:

- The positional project name also creates and enters a directory, so it
  keeps precedence over --name, which only labels the manifest. Passing
  both reports the ignored flag rather than dropping it silently. --name
  gets the same validation the interactive prompt already enforces.
- Plugin mode overwrote config["version"] with 0.1.0 after the config was
  built, which would have clobbered an explicit --version. It now applies
  only when no version was given.

Outside --yes the flags seed the matching prompt defaults, so a flag is
never silently discarded.

Closes microsoft#2146

Copilot AI left a comment

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.

Pull request overview

Adds non-interactive metadata flags to apm init so scripted/CI initialization can set name, description, version, and author without post-editing apm.yml, while preserving the existing positional-argument directory-creation contract.

Changes:

  • Added --name, --description, --version, and --author options to apm init, applying overrides in the shared init path and seeding interactive prompt defaults when --yes is not used.
  • Added unit tests covering the new flag behavior (including precedence, validation, and plugin-mode version defaulting).
  • Added a CHANGELOG entry under [Unreleased].

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.

File Description
src/apm_cli/commands/init.py Introduces metadata flags, precedence/validation, and prompt seeding for apm init.
tests/unit/test_init_command.py Adds a new test class validating metadata flag behavior across --yes, interactive, and plugin paths.
CHANGELOG.md Documents the new apm init metadata flags under Unreleased/Added.

Comment on lines +453 to +455
auto_author = author or _auto_detect_author()
auto_description = description or _auto_detect_description(default_name)
auto_version = version or "1.0.0"
Comment on lines +89 to +96
@click.option(
"--name",
default=None,
help="Project name written to apm.yml. Ignored when a positional project name is given.",
)
@click.option("--description", default=None, help="Project description (default: auto-detected)")
@click.option("--version", default=None, help="Project version (default: 1.0.0)")
@click.option("--author", default=None, help="Project author (default: git config user.name)")
Comment thread CHANGELOG.md
Comment on lines +54 to +59
- `apm init` now accepts `--name`, `--description`, `--version`, and `--author`,
so scripted and CI init can write a finished `apm.yml` without hand-editing it
afterwards. `--name` labels the manifest in place and is reported as ignored
when a positional project name is given; outside `--yes` the flags seed the
matching prompt defaults instead of being discarded. (closes #2146)
-- by @atulya-singh
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.

[FEATURE] Non-interactive flags for apm init project metadata (name, description, version, author)

2 participants