minitest-cli 0.35.0__tar.gz → 0.36.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/AGENTS.md +1 -1
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/PKG-INFO +1 -24
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/README.md +0 -23
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/pyproject.toml +1 -1
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/src/minitest_cli/api/client.py +1 -2
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/app_skill_helpers.py +10 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/app_skill_write.py +38 -2
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/build.py +2 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/build_fix_prompts.py +15 -10
- minitest_cli-0.36.0/src/minitest_cli/commands/build_get.py +50 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/issues.py +2 -0
- minitest_cli-0.36.0/src/minitest_cli/commands/issues_get.py +33 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/test_profile.py +5 -1
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/test_profile_helpers.py +9 -1
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/test_profile_list.py +3 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/test_profile_update.py +2 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/src/minitest_cli/main.py +0 -2
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/src/minitest_cli/models/build.py +4 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/src/minitest_cli/models/issues.py +5 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/tests/test_app_skill_commands.py +50 -0
- minitest_cli-0.36.0/tests/test_build_get_command.py +106 -0
- minitest_cli-0.36.0/tests/test_issues_get_command.py +90 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/tests/test_test_profile_commands.py +25 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/uv.lock +1 -1
- minitest_cli-0.35.0/src/minitest_cli/commands/maintenance.py +0 -130
- minitest_cli-0.35.0/src/minitest_cli/commands/maintenance_callbacks.py +0 -86
- minitest_cli-0.35.0/src/minitest_cli/commands/maintenance_helpers.py +0 -132
- minitest_cli-0.35.0/src/minitest_cli/commands/maintenance_state.py +0 -56
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/.env.example +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/.github/workflows/ci.yml +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/.github/workflows/install-scripts.yml +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/.github/workflows/release.yml +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/.gitignore +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/.opencode/skill/release/SKILL.md +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/RELEASE.md +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/install.ps1 +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/install.sh +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/pyrightconfig.json +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/renovate.json +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/src/minitest_cli/__init__.py +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/src/minitest_cli/api/__init__.py +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/src/minitest_cli/api/apps_manager_client.py +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/src/minitest_cli/api/errors.py +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/src/minitest_cli/assets/__init__.py +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/src/minitest_cli/assets/callback.html +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/__init__.py +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/_response_errors.py +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/app_knowledge.py +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/app_knowledge_helpers.py +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/app_network_helpers.py +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/app_skill.py +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/app_skill_secret.py +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/apps.py +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/apps_dependencies.py +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/apps_get.py +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/apps_helpers.py +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/apps_table.py +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/auth.py +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/auth_api_key.py +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/batch.py +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/batch_helpers.py +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/batch_warnings.py +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/build_commit.py +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/build_helpers.py +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/capabilities.py +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/commit_helpers.py +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/deprecated_alias.py +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/draft_feature.py +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/draft_feature_apply.py +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/draft_feature_conflicts.py +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/draft_feature_helpers.py +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/draft_feature_show.py +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/env.py +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/env_helpers.py +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/flow_types.py +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/flow_types_helpers.py +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/flow_types_write.py +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/init.py +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/init_helpers.py +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/init_playbook.py +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/issues_fix.py +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/issues_helpers.py +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/issues_projection.py +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/issues_service.py +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/private_network.py +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/private_network_helpers.py +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/recording_timeline.py +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/residential_proxy.py +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/run.py +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/run_cancel.py +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/run_commit.py +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/run_commit_helpers.py +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/run_display.py +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/run_feedback.py +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/run_helpers.py +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/run_recording.py +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/run_recording_helpers.py +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/run_tagged.py +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/run_targets.py +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/screens.py +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/screens_detail.py +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/screens_format.py +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/screens_helpers.py +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/screens_tree.py +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/skill.py +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/tags.py +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/tags_helpers.py +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/test_file.py +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/test_file_helpers.py +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/test_file_list.py +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/test_profile_card.py +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/test_profile_default.py +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/upgrade.py +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/user_story.py +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/user_story_app_skills.py +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/user_story_bindings.py +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/user_story_camera.py +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/user_story_create.py +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/user_story_criteria.py +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/user_story_criterion_edits.py +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/user_story_delete.py +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/user_story_device_count.py +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/user_story_helpers.py +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/user_story_modify.py +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/user_story_overrides.py +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/user_story_profiles.py +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/user_story_setup_commit.py +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/user_story_update.py +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/verdicts.py +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/verdicts_helpers.py +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/verdicts_projection.py +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/src/minitest_cli/core/__init__.py +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/src/minitest_cli/core/app_context.py +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/src/minitest_cli/core/auth.py +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/src/minitest_cli/core/config.py +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/src/minitest_cli/core/credentials.py +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/src/minitest_cli/core/oauth.py +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/src/minitest_cli/core/tenants.py +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/src/minitest_cli/core/token_exchange.py +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/src/minitest_cli/models/__init__.py +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/src/minitest_cli/models/app.py +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/src/minitest_cli/models/app_env_vars.py +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/src/minitest_cli/models/app_failure.py +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/src/minitest_cli/models/app_screen.py +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/src/minitest_cli/models/base.py +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/src/minitest_cli/models/batch.py +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/src/minitest_cli/models/commit_build.py +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/src/minitest_cli/models/draft_feature.py +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/src/minitest_cli/models/flow_type.py +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/src/minitest_cli/models/recording.py +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/src/minitest_cli/models/story_run.py +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/src/minitest_cli/models/tag.py +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/src/minitest_cli/models/targets.py +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/src/minitest_cli/models/user_story.py +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/src/minitest_cli/utils/__init__.py +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/src/minitest_cli/utils/confirm.py +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/src/minitest_cli/utils/dependency_sim.py +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/src/minitest_cli/utils/mermaid.py +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/src/minitest_cli/utils/output.py +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/src/minitest_cli/utils/skill_refresh.py +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/src/minitest_cli/utils/update_check.py +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/src/minitest_cli/utils/video_frames.py +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/tests/__init__.py +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/tests/_commit_transport.py +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/tests/_network_settings_server.py +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/tests/conftest.py +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/tests/test_api_client_auth.py +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/tests/test_app_knowledge_commands.py +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/tests/test_apps_commands.py +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/tests/test_apps_dependencies.py +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/tests/test_auth.py +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/tests/test_auth_api_key.py +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/tests/test_auth_commands.py +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/tests/test_batch_commands.py +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/tests/test_build_commands.py +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/tests/test_build_fix_prompts.py +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/tests/test_capabilities_command.py +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/tests/test_channel_header.py +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/tests/test_code_quality.py +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/tests/test_commit_commands.py +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/tests/test_deprecated_commands.py +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/tests/test_deprecated_flags.py +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/tests/test_draft_feature_commands.py +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/tests/test_env.py +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/tests/test_flow_types_commands.py +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/tests/test_init_command.py +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/tests/test_issues.py +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/tests/test_issues_commands.py +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/tests/test_mermaid.py +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/tests/test_native_device_types.py +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/tests/test_network_errors.py +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/tests/test_private_network_commands.py +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/tests/test_recording_timeline.py +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/tests/test_residential_proxy_commands.py +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/tests/test_response_errors.py +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/tests/test_run_cancel.py +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/tests/test_run_commands.py +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/tests/test_run_frames_command.py +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/tests/test_screens_commands.py +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/tests/test_skill_command.py +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/tests/test_suite_change_provenance.py +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/tests/test_tags_commands.py +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/tests/test_test_file_commands.py +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/tests/test_upgrade_command.py +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/tests/test_user_story_bindings_commands.py +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/tests/test_user_story_commands.py +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/tests/test_user_story_setup_commit.py +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/tests/test_verdicts.py +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/tests/test_verdicts_actionable.py +0 -0
- {minitest_cli-0.35.0 → minitest_cli-0.36.0}/tests/test_version.py +0 -0
|
@@ -14,7 +14,7 @@ uv add <package> # Add new dependency (always
|
|
|
14
14
|
## Project Structure
|
|
15
15
|
|
|
16
16
|
- `src/minitest_cli/` - Main package
|
|
17
|
-
- `commands/` - One Typer sub-app per command group (auth, apps, flow, build, run
|
|
17
|
+
- `commands/` - One Typer sub-app per command group (auth, apps, flow, build, run)
|
|
18
18
|
- `core/`
|
|
19
19
|
- `config.py` - pydantic-settings: MINITEST_API_URL, MINITEST_TOKEN, config dir
|
|
20
20
|
- `app_context.py` - --app flag / MINITEST_APP_ID resolution
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: minitest-cli
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.36.0
|
|
4
4
|
Summary: Minitest CLI – command-line interface for the Minitest testing platform
|
|
5
5
|
Project-URL: Homepage, https://minitap.ai/
|
|
6
6
|
Project-URL: Source, https://github.com/minitap-ai/minitest-cli
|
|
@@ -178,7 +178,6 @@ app defaults.
|
|
|
178
178
|
| `minitest run` | Start runs and inspect their scenario runs |
|
|
179
179
|
| `minitest batch` | List, inspect and cancel runs (a batch is a Run in the webapp) |
|
|
180
180
|
| `minitest issues` | Read app issues and their fix prompts, mark them fixed |
|
|
181
|
-
| `minitest maintenance` | CLI-only scenario maintenance against local code |
|
|
182
181
|
| `minitest skill` | Print the CLI skill for your AI coding agent (not app skills) |
|
|
183
182
|
|
|
184
183
|
### Deprecated names
|
|
@@ -226,28 +225,6 @@ least one domain. Connectors cannot be created from the CLI: a workspace owner
|
|
|
226
225
|
or admin creates them in the webapp, under **Workspace settings → Private
|
|
227
226
|
network**.
|
|
228
227
|
|
|
229
|
-
## CLI-only maintenance
|
|
230
|
-
|
|
231
|
-
`minitest maintenance` lets a coding agent keep Minitest scenarios in sync
|
|
232
|
-
without connecting GitHub. Run it from the app repository: the code stays on the
|
|
233
|
-
machine, while the CLI sends only proposed scenario edits and the local HEAD SHA.
|
|
234
|
-
|
|
235
|
-
```bash
|
|
236
|
-
# Print the server-composed maintenance instructions for your coding agent
|
|
237
|
-
minitest maintenance --agent
|
|
238
|
-
|
|
239
|
-
# Agent workflow primitives
|
|
240
|
-
minitest --json maintenance context
|
|
241
|
-
minitest maintenance affected --file affected.json
|
|
242
|
-
minitest maintenance change --file change.json
|
|
243
|
-
minitest maintenance status --phase writing --message "Updating affected scenarios"
|
|
244
|
-
minitest maintenance complete --changed
|
|
245
|
-
|
|
246
|
-
# Apply proposed edits now, or open the web review queue
|
|
247
|
-
minitest maintenance apply
|
|
248
|
-
minitest maintenance apply --review
|
|
249
|
-
```
|
|
250
|
-
|
|
251
228
|
## Exit Codes
|
|
252
229
|
|
|
253
230
|
| Code | Meaning |
|
|
@@ -145,7 +145,6 @@ app defaults.
|
|
|
145
145
|
| `minitest run` | Start runs and inspect their scenario runs |
|
|
146
146
|
| `minitest batch` | List, inspect and cancel runs (a batch is a Run in the webapp) |
|
|
147
147
|
| `minitest issues` | Read app issues and their fix prompts, mark them fixed |
|
|
148
|
-
| `minitest maintenance` | CLI-only scenario maintenance against local code |
|
|
149
148
|
| `minitest skill` | Print the CLI skill for your AI coding agent (not app skills) |
|
|
150
149
|
|
|
151
150
|
### Deprecated names
|
|
@@ -193,28 +192,6 @@ least one domain. Connectors cannot be created from the CLI: a workspace owner
|
|
|
193
192
|
or admin creates them in the webapp, under **Workspace settings → Private
|
|
194
193
|
network**.
|
|
195
194
|
|
|
196
|
-
## CLI-only maintenance
|
|
197
|
-
|
|
198
|
-
`minitest maintenance` lets a coding agent keep Minitest scenarios in sync
|
|
199
|
-
without connecting GitHub. Run it from the app repository: the code stays on the
|
|
200
|
-
machine, while the CLI sends only proposed scenario edits and the local HEAD SHA.
|
|
201
|
-
|
|
202
|
-
```bash
|
|
203
|
-
# Print the server-composed maintenance instructions for your coding agent
|
|
204
|
-
minitest maintenance --agent
|
|
205
|
-
|
|
206
|
-
# Agent workflow primitives
|
|
207
|
-
minitest --json maintenance context
|
|
208
|
-
minitest maintenance affected --file affected.json
|
|
209
|
-
minitest maintenance change --file change.json
|
|
210
|
-
minitest maintenance status --phase writing --message "Updating affected scenarios"
|
|
211
|
-
minitest maintenance complete --changed
|
|
212
|
-
|
|
213
|
-
# Apply proposed edits now, or open the web review queue
|
|
214
|
-
minitest maintenance apply
|
|
215
|
-
minitest maintenance apply --review
|
|
216
|
-
```
|
|
217
|
-
|
|
218
195
|
## Exit Codes
|
|
219
196
|
|
|
220
197
|
| Code | Meaning |
|
|
@@ -13,8 +13,7 @@ CONVERSATION_ID_HEADER = "X-Minitest-Conversation-Id"
|
|
|
13
13
|
CAUSE_HEADER = "X-Minitest-Cause"
|
|
14
14
|
DEFAULT_TIMEOUT = 30.0
|
|
15
15
|
UPLOAD_TIMEOUT = 300.0 # 5 minutes for large file uploads
|
|
16
|
-
# Creating a batch
|
|
17
|
-
# POST is not idempotent — timing out client-side leaves a batch running unseen.
|
|
16
|
+
# Creating a batch is not idempotent — timing out client-side leaves a batch running unseen.
|
|
18
17
|
BATCH_CREATE_TIMEOUT = 180.0
|
|
19
18
|
|
|
20
19
|
|
|
@@ -103,6 +103,16 @@ def read_instructions(instructions: str | None, instructions_file: Path | None)
|
|
|
103
103
|
return instructions
|
|
104
104
|
|
|
105
105
|
|
|
106
|
+
def instruction_edits(
|
|
107
|
+
replace: list[str] | None, replacements: list[str] | None
|
|
108
|
+
) -> list[dict[str, str]]:
|
|
109
|
+
old, new = replace or [], replacements or []
|
|
110
|
+
if len(old) != len(new):
|
|
111
|
+
print_error("Give exactly one --with for each --replace.")
|
|
112
|
+
raise typer.Exit(code=1)
|
|
113
|
+
return [{"oldText": o, "newText": n} for o, n in zip(old, new, strict=True)]
|
|
114
|
+
|
|
115
|
+
|
|
106
116
|
def warn_undefined_secrets(skill: dict[str, Any]) -> None:
|
|
107
117
|
undefined = skill.get("undefinedSecrets") or []
|
|
108
118
|
if undefined:
|
|
@@ -8,11 +8,12 @@ import typer
|
|
|
8
8
|
from minitest_cli.commands.app_skill_helpers import (
|
|
9
9
|
call,
|
|
10
10
|
command_context,
|
|
11
|
+
instruction_edits,
|
|
11
12
|
read_instructions,
|
|
12
13
|
skills_path,
|
|
13
14
|
warn_undefined_secrets,
|
|
14
15
|
)
|
|
15
|
-
from minitest_cli.utils.output import print_error, print_json, print_success
|
|
16
|
+
from minitest_cli.utils.output import print_error, print_info, print_json, print_success
|
|
16
17
|
|
|
17
18
|
Description = Annotated[
|
|
18
19
|
str | None,
|
|
@@ -31,6 +32,24 @@ InstructionsFile = Annotated[
|
|
|
31
32
|
"--instructions-file", exists=True, readable=True, dir_okay=False, help="Markdown file."
|
|
32
33
|
),
|
|
33
34
|
]
|
|
35
|
+
Replace = Annotated[
|
|
36
|
+
list[str] | None,
|
|
37
|
+
typer.Option(
|
|
38
|
+
"--replace",
|
|
39
|
+
help="Exact text of the instructions to replace; pair each with a --with (repeatable).",
|
|
40
|
+
),
|
|
41
|
+
]
|
|
42
|
+
With = Annotated[
|
|
43
|
+
list[str] | None,
|
|
44
|
+
typer.Option("--with", help="Replacement for the matching --replace; empty deletes it."),
|
|
45
|
+
]
|
|
46
|
+
AllowDestructive = Annotated[
|
|
47
|
+
bool,
|
|
48
|
+
typer.Option(
|
|
49
|
+
"--allow-destructive",
|
|
50
|
+
help="Accept a version that removes runnable code or most of the instructions.",
|
|
51
|
+
),
|
|
52
|
+
]
|
|
34
53
|
AllPlatforms = Annotated[
|
|
35
54
|
bool, typer.Option("--all-platforms", help="Make the skill apply to every platform.")
|
|
36
55
|
]
|
|
@@ -94,17 +113,34 @@ def register(app: typer.Typer) -> None:
|
|
|
94
113
|
all_platforms: AllPlatforms = False,
|
|
95
114
|
instructions: Instructions = None,
|
|
96
115
|
instructions_file: InstructionsFile = None,
|
|
116
|
+
replace: Replace = None,
|
|
117
|
+
with_: With = None,
|
|
118
|
+
allow_destructive: AllowDestructive = False,
|
|
97
119
|
) -> None:
|
|
98
|
-
"""Change a skill; every change becomes a new version.
|
|
120
|
+
"""Change a skill; every change becomes a new version.
|
|
121
|
+
|
|
122
|
+
Change part of the instructions with --replace/--with pairs instead of resending them.
|
|
123
|
+
"""
|
|
99
124
|
settings, json_mode, app_id = command_context()
|
|
100
125
|
body = _patch(description, platforms, all_platforms, instructions, instructions_file)
|
|
126
|
+
edits = instruction_edits(replace, with_)
|
|
127
|
+
if edits and "instructions" in body:
|
|
128
|
+
print_error("Use either --replace/--with or --instructions, not both.")
|
|
129
|
+
raise typer.Exit(code=1)
|
|
130
|
+
if edits:
|
|
131
|
+
body["edits"] = edits
|
|
101
132
|
if new_name is not None:
|
|
102
133
|
body["name"] = new_name
|
|
103
134
|
if not body:
|
|
104
135
|
print_error("Nothing to update.")
|
|
105
136
|
raise typer.Exit(code=1)
|
|
137
|
+
if allow_destructive:
|
|
138
|
+
body["allowDestructive"] = True
|
|
106
139
|
skill = call(settings, "PATCH", f"{skills_path(app_id)}/{name}", json=body)
|
|
107
140
|
_report(skill, json_mode, f"Skill {skill['name']} is now v{skill['version']}.")
|
|
141
|
+
if not json_mode:
|
|
142
|
+
for change in skill.get("changes", []):
|
|
143
|
+
print_info(f" {change}")
|
|
108
144
|
|
|
109
145
|
@app.command(name="propose")
|
|
110
146
|
def propose_update(
|
|
@@ -22,6 +22,7 @@ from minitest_cli.commands.build_helpers import (
|
|
|
22
22
|
upload_status_message,
|
|
23
23
|
)
|
|
24
24
|
from minitest_cli.commands.build_commit import from_commit
|
|
25
|
+
from minitest_cli.commands.build_get import get
|
|
25
26
|
from minitest_cli.commands.build_fix_prompts import print_fix_prompts, redacted_payload
|
|
26
27
|
from minitest_cli.models import BuildListResponse, BuildResponse
|
|
27
28
|
from minitest_cli.utils.output import (
|
|
@@ -145,4 +146,5 @@ def list_builds(
|
|
|
145
146
|
print_fix_prompts(result.items)
|
|
146
147
|
|
|
147
148
|
|
|
149
|
+
app.command(name="get")(get)
|
|
148
150
|
app.command(name="from-commit")(from_commit)
|
|
@@ -40,18 +40,23 @@ def build_guidance(build: BuildResponse) -> dict[str, str | None]:
|
|
|
40
40
|
return {"source": "none", "text": None}
|
|
41
41
|
|
|
42
42
|
|
|
43
|
+
def redacted_build(build: BuildResponse) -> dict[str, Any]:
|
|
44
|
+
item = build.model_dump(mode="json", by_alias=True)
|
|
45
|
+
if build.status != FAILED_STATUS:
|
|
46
|
+
item["guidance"] = None
|
|
47
|
+
return item
|
|
48
|
+
item["guidance"] = build_guidance(build)
|
|
49
|
+
if is_withheld(build.error_class):
|
|
50
|
+
item["errorSummary"] = WITHHELD_NOTICE
|
|
51
|
+
item["errorRemediation"] = None
|
|
52
|
+
item["errorFixPrompt"] = None
|
|
53
|
+
item["errorRaw"] = None
|
|
54
|
+
return item
|
|
55
|
+
|
|
56
|
+
|
|
43
57
|
def redacted_payload(result: BuildListResponse) -> dict[str, Any]:
|
|
44
58
|
payload = result.model_dump(mode="json", by_alias=True)
|
|
45
|
-
|
|
46
|
-
if build.status != FAILED_STATUS:
|
|
47
|
-
item["guidance"] = None
|
|
48
|
-
continue
|
|
49
|
-
item["guidance"] = build_guidance(build)
|
|
50
|
-
if is_withheld(build.error_class):
|
|
51
|
-
item["errorSummary"] = WITHHELD_NOTICE
|
|
52
|
-
item["errorRemediation"] = None
|
|
53
|
-
item["errorFixPrompt"] = None
|
|
54
|
-
item["errorRaw"] = None
|
|
59
|
+
payload["items"] = [redacted_build(build) for build in result.items]
|
|
55
60
|
return payload
|
|
56
61
|
|
|
57
62
|
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
"""``minitest build get``: read one build of the active app by id."""
|
|
2
|
+
|
|
3
|
+
from typing import Annotated
|
|
4
|
+
|
|
5
|
+
import typer
|
|
6
|
+
|
|
7
|
+
from minitest_cli.api.client import ApiClient
|
|
8
|
+
from minitest_cli.commands.build_fix_prompts import print_fix_prompts, redacted_build
|
|
9
|
+
from minitest_cli.commands.build_helpers import (
|
|
10
|
+
BUILD_TABLE_HEADERS,
|
|
11
|
+
base_path,
|
|
12
|
+
format_build_row,
|
|
13
|
+
handle_response_error,
|
|
14
|
+
resolve_app,
|
|
15
|
+
run_api_call,
|
|
16
|
+
)
|
|
17
|
+
from minitest_cli.commands.run_helpers import ensure_uuid
|
|
18
|
+
from minitest_cli.models import BuildResponse
|
|
19
|
+
from minitest_cli.utils.output import output, print_table
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def _version_label(build: BuildResponse) -> str | None:
|
|
23
|
+
if build.app_version and build.build_number:
|
|
24
|
+
return f"{build.app_version} ({build.build_number})"
|
|
25
|
+
return build.app_version or build.build_number
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def get(
|
|
29
|
+
build_id: Annotated[str, typer.Argument(help="Build ID (from `minitest build list`).")],
|
|
30
|
+
) -> None:
|
|
31
|
+
"""Show one build of the active app: status, version, commit and failure guidance."""
|
|
32
|
+
ensure_uuid(build_id, kind="build ID")
|
|
33
|
+
settings, app_id, json_mode = resolve_app()
|
|
34
|
+
|
|
35
|
+
async def _run() -> BuildResponse:
|
|
36
|
+
async with ApiClient(settings) as client:
|
|
37
|
+
resp = await client.get(f"{base_path(app_id)}/builds/{build_id}")
|
|
38
|
+
handle_response_error(resp, resource="Build")
|
|
39
|
+
return BuildResponse.model_validate(resp.json())
|
|
40
|
+
|
|
41
|
+
build = run_api_call(_run())
|
|
42
|
+
|
|
43
|
+
if json_mode:
|
|
44
|
+
output(redacted_build(build), json_mode=True)
|
|
45
|
+
return
|
|
46
|
+
|
|
47
|
+
version = _version_label(build)
|
|
48
|
+
title = f"Build {version}" if version else "Build"
|
|
49
|
+
print_table(BUILD_TABLE_HEADERS, [format_build_row(build)], title=title)
|
|
50
|
+
print_fix_prompts([build])
|
|
@@ -6,6 +6,7 @@ from typing import Annotated
|
|
|
6
6
|
import typer
|
|
7
7
|
|
|
8
8
|
from minitest_cli.commands.issues_fix import fix
|
|
9
|
+
from minitest_cli.commands.issues_get import get
|
|
9
10
|
from minitest_cli.commands.issues_service import collect_issues
|
|
10
11
|
from minitest_cli.commands.run_helpers import ensure_uuid, resolve_app, run_api_call
|
|
11
12
|
from minitest_cli.utils.output import print_error, print_json
|
|
@@ -25,6 +26,7 @@ class IssueCriticality(StrEnum):
|
|
|
25
26
|
app = typer.Typer(
|
|
26
27
|
name="issues", help="Read app issues, fix prompts, and mark them fixed.", no_args_is_help=True
|
|
27
28
|
)
|
|
29
|
+
app.command()(get)
|
|
28
30
|
app.command()(fix)
|
|
29
31
|
|
|
30
32
|
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"""``minitest issues get``: read one issue of the active app by id."""
|
|
2
|
+
|
|
3
|
+
from typing import Annotated
|
|
4
|
+
|
|
5
|
+
import typer
|
|
6
|
+
|
|
7
|
+
from minitest_cli.api.client import ApiClient
|
|
8
|
+
from minitest_cli.commands.issues_helpers import fetch_failure, fetch_optional_batch
|
|
9
|
+
from minitest_cli.commands.issues_projection import build_block, issue_item
|
|
10
|
+
from minitest_cli.commands.run_helpers import ensure_uuid, resolve_app, run_api_call
|
|
11
|
+
from minitest_cli.core.config import Settings
|
|
12
|
+
from minitest_cli.models.issues import IssueDetailResponse
|
|
13
|
+
from minitest_cli.utils.output import print_json
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
async def read_issue(settings: Settings, app_id: str, issue_id: str) -> IssueDetailResponse:
|
|
17
|
+
async with ApiClient(settings) as client:
|
|
18
|
+
failure = await fetch_failure(client, app_id, issue_id)
|
|
19
|
+
batch = (
|
|
20
|
+
await fetch_optional_batch(client, app_id, failure.batch_id)
|
|
21
|
+
if failure.batch_id
|
|
22
|
+
else None
|
|
23
|
+
)
|
|
24
|
+
return IssueDetailResponse(issue=issue_item(failure), build=build_block(batch))
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def get(
|
|
28
|
+
issue_id: Annotated[str, typer.Argument(help="Issue ID (the `id` from `issues list`).")],
|
|
29
|
+
) -> None:
|
|
30
|
+
"""Return one issue, whatever its status, with its build provenance and fix prompt as JSON."""
|
|
31
|
+
ensure_uuid(issue_id, kind="issue")
|
|
32
|
+
settings, app_id, _ = resolve_app()
|
|
33
|
+
print_json(run_api_call(read_issue(settings, app_id, issue_id)))
|
|
@@ -20,6 +20,7 @@ from minitest_cli.commands.test_profile_helpers import (
|
|
|
20
20
|
is_json_mode,
|
|
21
21
|
read_stdin_secret,
|
|
22
22
|
run_api_call,
|
|
23
|
+
warn_if_qa_inbox_unreadable,
|
|
23
24
|
)
|
|
24
25
|
from minitest_cli.core.app_context import resolve_app_id
|
|
25
26
|
from minitest_cli.core.auth import require_auth
|
|
@@ -125,6 +126,7 @@ def create_profile(
|
|
|
125
126
|
data = run_api_call(_run())
|
|
126
127
|
if not json_mode:
|
|
127
128
|
print_success(f"Test profile created: {data.get('id', '')}")
|
|
129
|
+
warn_if_qa_inbox_unreadable(data)
|
|
128
130
|
output(data, json_mode=json_mode)
|
|
129
131
|
|
|
130
132
|
|
|
@@ -143,7 +145,9 @@ def get_profile(
|
|
|
143
145
|
handle_profile_response(resp)
|
|
144
146
|
return resp.json()
|
|
145
147
|
|
|
146
|
-
|
|
148
|
+
data = run_api_call(_run())
|
|
149
|
+
warn_if_qa_inbox_unreadable(data)
|
|
150
|
+
output(data, json_mode=json_mode)
|
|
147
151
|
|
|
148
152
|
|
|
149
153
|
@app.command(name="delete")
|
{minitest_cli-0.35.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/test_profile_helpers.py
RENAMED
|
@@ -13,7 +13,7 @@ from minitest_cli.commands.user_story_helpers import (
|
|
|
13
13
|
is_json_mode,
|
|
14
14
|
run_api_call,
|
|
15
15
|
)
|
|
16
|
-
from minitest_cli.utils.output import print_error
|
|
16
|
+
from minitest_cli.utils.output import print_error, print_warning
|
|
17
17
|
|
|
18
18
|
EXIT_NETWORK_ERROR = 3
|
|
19
19
|
EXIT_NOT_FOUND = 4
|
|
@@ -87,3 +87,11 @@ __all__ = [
|
|
|
87
87
|
"read_stdin_secret",
|
|
88
88
|
"run_api_call",
|
|
89
89
|
]
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def warn_if_qa_inbox_unreadable(profile: dict[str, Any]) -> None:
|
|
93
|
+
if profile.get("qaInboxShared"):
|
|
94
|
+
print_warning(
|
|
95
|
+
f"{profile.get('username')} belongs to another workspace, so Mini can't read its "
|
|
96
|
+
"emails (login codes, verification links). Use a different @qa.minitap.ai address."
|
|
97
|
+
)
|
|
@@ -13,6 +13,7 @@ from minitest_cli.commands.test_profile_helpers import (
|
|
|
13
13
|
handle_profile_response,
|
|
14
14
|
is_json_mode,
|
|
15
15
|
run_api_call,
|
|
16
|
+
warn_if_qa_inbox_unreadable,
|
|
16
17
|
)
|
|
17
18
|
from minitest_cli.core.app_context import resolve_app_id
|
|
18
19
|
from minitest_cli.core.auth import require_auth
|
|
@@ -36,6 +37,8 @@ def register(app: typer.Typer) -> None:
|
|
|
36
37
|
|
|
37
38
|
data = run_api_call(_run())
|
|
38
39
|
items = data["items"] if isinstance(data, dict) and "items" in data else data
|
|
40
|
+
for profile in items:
|
|
41
|
+
warn_if_qa_inbox_unreadable(profile)
|
|
39
42
|
if json_mode:
|
|
40
43
|
output(items, json_mode=True)
|
|
41
44
|
return
|
{minitest_cli-0.35.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/test_profile_update.py
RENAMED
|
@@ -20,6 +20,7 @@ from minitest_cli.commands.test_profile_helpers import (
|
|
|
20
20
|
is_json_mode,
|
|
21
21
|
read_stdin_secret,
|
|
22
22
|
run_api_call,
|
|
23
|
+
warn_if_qa_inbox_unreadable,
|
|
23
24
|
)
|
|
24
25
|
from minitest_cli.core.app_context import resolve_app_id
|
|
25
26
|
from minitest_cli.core.auth import require_auth
|
|
@@ -156,4 +157,5 @@ def register(app: typer.Typer) -> None:
|
|
|
156
157
|
data = run_api_call(_run())
|
|
157
158
|
if not json_mode:
|
|
158
159
|
print_success(f"Test profile updated: {profile_id}")
|
|
160
|
+
warn_if_qa_inbox_unreadable(data)
|
|
159
161
|
output(data, json_mode=json_mode)
|
|
@@ -18,7 +18,6 @@ from minitest_cli.commands import (
|
|
|
18
18
|
flow_types,
|
|
19
19
|
init,
|
|
20
20
|
issues,
|
|
21
|
-
maintenance,
|
|
22
21
|
run,
|
|
23
22
|
screens,
|
|
24
23
|
skill,
|
|
@@ -60,7 +59,6 @@ app.add_typer(build.app)
|
|
|
60
59
|
app.add_typer(env.app)
|
|
61
60
|
app.add_typer(run.app)
|
|
62
61
|
app.add_typer(issues.app)
|
|
63
|
-
app.add_typer(maintenance.app)
|
|
64
62
|
app.add_typer(batch.app)
|
|
65
63
|
app.add_typer(skill.app)
|
|
66
64
|
app.add_typer(upgrade.app)
|
|
@@ -17,6 +17,10 @@ class BuildResponse(CamelModel):
|
|
|
17
17
|
size_bytes: int | None = None
|
|
18
18
|
commit_sha: str | None = None
|
|
19
19
|
commit_title: str | None = None
|
|
20
|
+
app_version: str | None = None
|
|
21
|
+
build_number: str | None = None
|
|
22
|
+
verification_status: str | None = None
|
|
23
|
+
verification_reason: str | None = None
|
|
20
24
|
error_class: str | None = None
|
|
21
25
|
error_summary: str | None = None
|
|
22
26
|
error_remediation: str | None = None
|
|
@@ -97,6 +97,56 @@ def test_update_all_platforms_clears_the_platform_filter(tmp_path):
|
|
|
97
97
|
assert recorder.body == {"platforms": []}
|
|
98
98
|
|
|
99
99
|
|
|
100
|
+
def test_update_sends_paired_replacements_and_prints_what_changed(tmp_path):
|
|
101
|
+
changes = ["Changed runnable blocks: fill.sh", "Instructions went from 900 to 940 characters"]
|
|
102
|
+
recorder = Recorder(httpx.Response(200, json=_skill(version=3, changes=changes)))
|
|
103
|
+
|
|
104
|
+
result = _invoke(
|
|
105
|
+
skill_app,
|
|
106
|
+
[
|
|
107
|
+
"update",
|
|
108
|
+
"color-by-number-fill",
|
|
109
|
+
"--replace",
|
|
110
|
+
"retry once",
|
|
111
|
+
"--with",
|
|
112
|
+
"retry three times",
|
|
113
|
+
"--replace",
|
|
114
|
+
"# old check\n",
|
|
115
|
+
"--with",
|
|
116
|
+
"",
|
|
117
|
+
"--allow-destructive",
|
|
118
|
+
],
|
|
119
|
+
recorder,
|
|
120
|
+
tmp_path,
|
|
121
|
+
)
|
|
122
|
+
|
|
123
|
+
assert result.exit_code == 0, result.output
|
|
124
|
+
assert recorder.body == {
|
|
125
|
+
"edits": [
|
|
126
|
+
{"oldText": "retry once", "newText": "retry three times"},
|
|
127
|
+
{"oldText": "# old check\n", "newText": ""},
|
|
128
|
+
],
|
|
129
|
+
"allowDestructive": True,
|
|
130
|
+
}
|
|
131
|
+
assert "Changed runnable blocks: fill.sh" in result.output
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
@pytest.mark.parametrize(
|
|
135
|
+
"args",
|
|
136
|
+
[
|
|
137
|
+
["--replace", "a", "--with", "b", "--replace", "c"],
|
|
138
|
+
["--replace", "a", "--with", "b", "--instructions", "whole"],
|
|
139
|
+
],
|
|
140
|
+
)
|
|
141
|
+
def test_update_refuses_ambiguous_instruction_changes_before_calling_the_api(tmp_path, args):
|
|
142
|
+
recorder = Recorder(httpx.Response(200, json=_skill()))
|
|
143
|
+
|
|
144
|
+
result = _invoke(skill_app, ["update", "color-by-number-fill", *args], recorder, tmp_path)
|
|
145
|
+
|
|
146
|
+
assert result.exit_code == 1
|
|
147
|
+
assert recorder.requests == []
|
|
148
|
+
|
|
149
|
+
|
|
100
150
|
def test_delete_linked_skill_lists_scenarios_and_keeps_the_skill(tmp_path):
|
|
101
151
|
recorder = Recorder(
|
|
102
152
|
httpx.Response(
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
"""Behavior tests for `minitest build get`."""
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
from typing import Any
|
|
6
|
+
from unittest.mock import patch
|
|
7
|
+
|
|
8
|
+
import httpx
|
|
9
|
+
from tests._commit_transport import make_settings, routed
|
|
10
|
+
from typer.testing import CliRunner
|
|
11
|
+
|
|
12
|
+
from minitest_cli.commands.build_fix_prompts import WITHHELD_NOTICE
|
|
13
|
+
from minitest_cli.main import app
|
|
14
|
+
|
|
15
|
+
runner = CliRunner()
|
|
16
|
+
APP_ID = "a0d9820f-5136-4f70-b46b-e5966f56bfb5"
|
|
17
|
+
BUILD_ID = "6f1c2a3b-4d5e-4f60-8a7b-9c0d1e2f3a4b"
|
|
18
|
+
FOREIGN_BUILD_ID = "0b6d1f4e-2c3a-4e5f-9a8b-7c6d5e4f3a2b"
|
|
19
|
+
BUILD = {
|
|
20
|
+
"id": BUILD_ID,
|
|
21
|
+
"appId": APP_ID,
|
|
22
|
+
"kind": "native",
|
|
23
|
+
"platform": "ios",
|
|
24
|
+
"status": "completed",
|
|
25
|
+
"originalName": "Shop.app.zip",
|
|
26
|
+
"sizeBytes": 2048,
|
|
27
|
+
"commitSha": "a1b2c3d4e5f6",
|
|
28
|
+
"commitTitle": "feat: checkout v2",
|
|
29
|
+
"appVersion": "4.2.0",
|
|
30
|
+
"buildNumber": "317",
|
|
31
|
+
"verificationStatus": "verified",
|
|
32
|
+
"createdAt": "2026-10-14T09:30:00Z",
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def _serve(build: dict[str, Any]):
|
|
37
|
+
seen: list[str] = []
|
|
38
|
+
|
|
39
|
+
def handler(request: httpx.Request) -> httpx.Response:
|
|
40
|
+
seen.append(request.url.path)
|
|
41
|
+
if request.url.path == f"/api/v1/apps/{APP_ID}/builds/{BUILD_ID}":
|
|
42
|
+
return httpx.Response(200, json=build)
|
|
43
|
+
return httpx.Response(404, json={"message": "Build not found"})
|
|
44
|
+
|
|
45
|
+
return handler, seen
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def _invoke(tmp_path: Path, build: dict[str, Any], args: list[str]):
|
|
49
|
+
handler, seen = _serve(build)
|
|
50
|
+
with (
|
|
51
|
+
routed(handler),
|
|
52
|
+
patch("minitest_cli.main.get_settings", return_value=make_settings(tmp_path)),
|
|
53
|
+
patch("minitest_cli.main.check_for_updates"),
|
|
54
|
+
):
|
|
55
|
+
return runner.invoke(app, args), seen
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
class TestBuildGet:
|
|
59
|
+
def test_get_returns_the_app_build_as_json(self, tmp_path: Path) -> None:
|
|
60
|
+
result, seen = _invoke(tmp_path, BUILD, ["--json", "build", "get", BUILD_ID])
|
|
61
|
+
|
|
62
|
+
assert result.exit_code == 0
|
|
63
|
+
assert seen == [f"/api/v1/apps/{APP_ID}/builds/{BUILD_ID}"]
|
|
64
|
+
payload = json.loads(result.stdout)
|
|
65
|
+
assert payload["id"] == BUILD_ID
|
|
66
|
+
assert (payload["appVersion"], payload["buildNumber"]) == ("4.2.0", "317")
|
|
67
|
+
assert payload["commitTitle"] == "feat: checkout v2"
|
|
68
|
+
assert payload["verificationStatus"] == "verified"
|
|
69
|
+
assert payload["guidance"] is None
|
|
70
|
+
|
|
71
|
+
def test_get_withholds_infra_failure_details(self, tmp_path: Path) -> None:
|
|
72
|
+
failed = {
|
|
73
|
+
**BUILD,
|
|
74
|
+
"status": "failed",
|
|
75
|
+
"errorClass": "infra",
|
|
76
|
+
"errorSummary": "builder disk full",
|
|
77
|
+
"errorFixPrompt": "ssh into the builder",
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
result, _ = _invoke(tmp_path, failed, ["--json", "build", "get", BUILD_ID])
|
|
81
|
+
|
|
82
|
+
payload = json.loads(result.stdout)
|
|
83
|
+
assert payload["guidance"] == {"source": "withheld", "text": WITHHELD_NOTICE}
|
|
84
|
+
assert payload["errorSummary"] == WITHHELD_NOTICE
|
|
85
|
+
assert payload["errorFixPrompt"] is None
|
|
86
|
+
|
|
87
|
+
def test_get_shows_the_version_in_human_mode(self, tmp_path: Path) -> None:
|
|
88
|
+
result, _ = _invoke(tmp_path, BUILD, ["build", "get", BUILD_ID])
|
|
89
|
+
|
|
90
|
+
assert result.exit_code == 0
|
|
91
|
+
assert "Build 4.2.0 (317)" in result.stdout
|
|
92
|
+
assert "completed" in result.stdout
|
|
93
|
+
|
|
94
|
+
def test_get_a_build_of_another_app_is_not_found(self, tmp_path: Path) -> None:
|
|
95
|
+
result, _ = _invoke(tmp_path, BUILD, ["--json", "build", "get", FOREIGN_BUILD_ID])
|
|
96
|
+
|
|
97
|
+
assert result.exit_code == 4
|
|
98
|
+
assert "Build not found" in result.stderr
|
|
99
|
+
assert result.stdout == ""
|
|
100
|
+
|
|
101
|
+
def test_get_rejects_a_non_uuid_without_calling_the_api(self, tmp_path: Path) -> None:
|
|
102
|
+
result, seen = _invoke(tmp_path, BUILD, ["build", "get", "317"])
|
|
103
|
+
|
|
104
|
+
assert result.exit_code == 1
|
|
105
|
+
assert "not a valid UUID" in result.stderr
|
|
106
|
+
assert seen == []
|