minitest-cli 0.34.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.34.0 → minitest_cli-0.36.0}/AGENTS.md +1 -1
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/PKG-INFO +25 -20
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/README.md +24 -19
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/pyproject.toml +1 -1
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/src/minitest_cli/api/client.py +1 -2
- minitest_cli-0.36.0/src/minitest_cli/commands/app_network_helpers.py +114 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/app_skill_helpers.py +10 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/app_skill_write.py +38 -2
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/apps.py +9 -2
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/build.py +2 -0
- {minitest_cli-0.34.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.34.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.36.0/src/minitest_cli/commands/private_network.py +143 -0
- minitest_cli-0.36.0/src/minitest_cli/commands/private_network_helpers.py +93 -0
- minitest_cli-0.36.0/src/minitest_cli/commands/residential_proxy.py +121 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/test_profile.py +5 -1
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/test_profile_helpers.py +9 -1
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/test_profile_list.py +3 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/test_profile_update.py +2 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/src/minitest_cli/main.py +0 -2
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/src/minitest_cli/models/build.py +4 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/src/minitest_cli/models/issues.py +5 -0
- minitest_cli-0.36.0/tests/_network_settings_server.py +106 -0
- {minitest_cli-0.34.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.36.0/tests/test_private_network_commands.py +118 -0
- minitest_cli-0.36.0/tests/test_residential_proxy_commands.py +89 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/tests/test_test_profile_commands.py +25 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/uv.lock +1 -1
- minitest_cli-0.34.0/src/minitest_cli/commands/maintenance.py +0 -130
- minitest_cli-0.34.0/src/minitest_cli/commands/maintenance_callbacks.py +0 -86
- minitest_cli-0.34.0/src/minitest_cli/commands/maintenance_helpers.py +0 -132
- minitest_cli-0.34.0/src/minitest_cli/commands/maintenance_state.py +0 -56
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/.env.example +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/.github/workflows/ci.yml +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/.github/workflows/install-scripts.yml +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/.github/workflows/release.yml +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/.gitignore +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/.opencode/skill/release/SKILL.md +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/RELEASE.md +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/install.ps1 +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/install.sh +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/pyrightconfig.json +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/renovate.json +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/src/minitest_cli/__init__.py +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/src/minitest_cli/api/__init__.py +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/src/minitest_cli/api/apps_manager_client.py +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/src/minitest_cli/api/errors.py +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/src/minitest_cli/assets/__init__.py +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/src/minitest_cli/assets/callback.html +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/__init__.py +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/_response_errors.py +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/app_knowledge.py +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/app_knowledge_helpers.py +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/app_skill.py +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/app_skill_secret.py +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/apps_dependencies.py +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/apps_get.py +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/apps_helpers.py +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/apps_table.py +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/auth.py +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/auth_api_key.py +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/batch.py +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/batch_helpers.py +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/batch_warnings.py +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/build_commit.py +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/build_helpers.py +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/capabilities.py +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/commit_helpers.py +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/deprecated_alias.py +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/draft_feature.py +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/draft_feature_apply.py +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/draft_feature_conflicts.py +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/draft_feature_helpers.py +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/draft_feature_show.py +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/env.py +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/env_helpers.py +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/flow_types.py +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/flow_types_helpers.py +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/flow_types_write.py +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/init.py +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/init_helpers.py +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/init_playbook.py +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/issues_fix.py +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/issues_helpers.py +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/issues_projection.py +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/issues_service.py +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/recording_timeline.py +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/run.py +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/run_cancel.py +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/run_commit.py +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/run_commit_helpers.py +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/run_display.py +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/run_feedback.py +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/run_helpers.py +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/run_recording.py +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/run_recording_helpers.py +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/run_tagged.py +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/run_targets.py +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/screens.py +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/screens_detail.py +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/screens_format.py +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/screens_helpers.py +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/screens_tree.py +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/skill.py +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/tags.py +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/tags_helpers.py +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/test_file.py +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/test_file_helpers.py +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/test_file_list.py +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/test_profile_card.py +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/test_profile_default.py +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/upgrade.py +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/user_story.py +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/user_story_app_skills.py +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/user_story_bindings.py +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/user_story_camera.py +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/user_story_create.py +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/user_story_criteria.py +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/user_story_criterion_edits.py +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/user_story_delete.py +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/user_story_device_count.py +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/user_story_helpers.py +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/user_story_modify.py +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/user_story_overrides.py +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/user_story_profiles.py +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/user_story_setup_commit.py +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/user_story_update.py +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/verdicts.py +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/verdicts_helpers.py +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/src/minitest_cli/commands/verdicts_projection.py +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/src/minitest_cli/core/__init__.py +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/src/minitest_cli/core/app_context.py +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/src/minitest_cli/core/auth.py +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/src/minitest_cli/core/config.py +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/src/minitest_cli/core/credentials.py +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/src/minitest_cli/core/oauth.py +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/src/minitest_cli/core/tenants.py +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/src/minitest_cli/core/token_exchange.py +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/src/minitest_cli/models/__init__.py +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/src/minitest_cli/models/app.py +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/src/minitest_cli/models/app_env_vars.py +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/src/minitest_cli/models/app_failure.py +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/src/minitest_cli/models/app_screen.py +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/src/minitest_cli/models/base.py +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/src/minitest_cli/models/batch.py +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/src/minitest_cli/models/commit_build.py +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/src/minitest_cli/models/draft_feature.py +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/src/minitest_cli/models/flow_type.py +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/src/minitest_cli/models/recording.py +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/src/minitest_cli/models/story_run.py +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/src/minitest_cli/models/tag.py +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/src/minitest_cli/models/targets.py +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/src/minitest_cli/models/user_story.py +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/src/minitest_cli/utils/__init__.py +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/src/minitest_cli/utils/confirm.py +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/src/minitest_cli/utils/dependency_sim.py +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/src/minitest_cli/utils/mermaid.py +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/src/minitest_cli/utils/output.py +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/src/minitest_cli/utils/skill_refresh.py +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/src/minitest_cli/utils/update_check.py +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/src/minitest_cli/utils/video_frames.py +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/tests/__init__.py +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/tests/_commit_transport.py +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/tests/conftest.py +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/tests/test_api_client_auth.py +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/tests/test_app_knowledge_commands.py +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/tests/test_apps_commands.py +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/tests/test_apps_dependencies.py +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/tests/test_auth.py +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/tests/test_auth_api_key.py +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/tests/test_auth_commands.py +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/tests/test_batch_commands.py +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/tests/test_build_commands.py +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/tests/test_build_fix_prompts.py +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/tests/test_capabilities_command.py +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/tests/test_channel_header.py +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/tests/test_code_quality.py +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/tests/test_commit_commands.py +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/tests/test_deprecated_commands.py +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/tests/test_deprecated_flags.py +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/tests/test_draft_feature_commands.py +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/tests/test_env.py +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/tests/test_flow_types_commands.py +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/tests/test_init_command.py +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/tests/test_issues.py +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/tests/test_issues_commands.py +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/tests/test_mermaid.py +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/tests/test_native_device_types.py +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/tests/test_network_errors.py +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/tests/test_recording_timeline.py +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/tests/test_response_errors.py +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/tests/test_run_cancel.py +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/tests/test_run_commands.py +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/tests/test_run_frames_command.py +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/tests/test_screens_commands.py +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/tests/test_skill_command.py +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/tests/test_suite_change_provenance.py +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/tests/test_tags_commands.py +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/tests/test_test_file_commands.py +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/tests/test_upgrade_command.py +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/tests/test_user_story_bindings_commands.py +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/tests/test_user_story_commands.py +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/tests/test_user_story_setup_commit.py +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/tests/test_verdicts.py +0 -0
- {minitest_cli-0.34.0 → minitest_cli-0.36.0}/tests/test_verdicts_actionable.py +0 -0
- {minitest_cli-0.34.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
|
|
@@ -166,7 +166,7 @@ app defaults.
|
|
|
166
166
|
| Command | Description |
|
|
167
167
|
| ---------------- | ------------------------- |
|
|
168
168
|
| `minitest auth` | Authentication management |
|
|
169
|
-
| `minitest apps` | List, inspect, and create apps |
|
|
169
|
+
| `minitest apps` | List, inspect, and create apps; residential proxy and private network settings |
|
|
170
170
|
| `minitest scenario` | Create, update, list and delete scenarios |
|
|
171
171
|
| `minitest scenario-binding` | Bind test accounts, test files or app skills to scenarios |
|
|
172
172
|
| `minitest draft` | Drafts — branches of the test suite |
|
|
@@ -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
|
|
@@ -198,28 +197,34 @@ stderr and leave `--json` stdout unchanged. Switch to the new names.
|
|
|
198
197
|
| `run cancel --srp`, `run recording --srp` | `--target-id` |
|
|
199
198
|
| `--type` on `scenario create/update/list` | `--tag` |
|
|
200
199
|
|
|
201
|
-
##
|
|
200
|
+
## App network settings
|
|
202
201
|
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
202
|
+
Two per-app settings decide how test devices reach the network. Anyone on the
|
|
203
|
+
app can read them; only workspace **owners and admins** can change them (other
|
|
204
|
+
roles get `Only workspace owners and admins can change this setting`, exit 2).
|
|
205
|
+
`set` reads the current settings first and changes only what you pass.
|
|
206
|
+
Domains are an exact host (`api.stg.example.com`) or `*.example.com`, which
|
|
207
|
+
matches subdomains only, not `example.com` itself.
|
|
206
208
|
|
|
207
209
|
```bash
|
|
208
|
-
#
|
|
209
|
-
minitest
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
minitest
|
|
215
|
-
minitest
|
|
216
|
-
minitest
|
|
217
|
-
|
|
218
|
-
# Apply proposed edits now, or open the web review queue
|
|
219
|
-
minitest maintenance apply
|
|
220
|
-
minitest maintenance apply --review
|
|
210
|
+
# Residential proxy: reach the listed domains from a residential IP in one country
|
|
211
|
+
minitest --app <app-id> apps residential-proxy show
|
|
212
|
+
minitest --app <app-id> apps residential-proxy set [--enable|--disable] [--country tr] \
|
|
213
|
+
[--domain ipinfo.io ...] [--remove-domain <d> ...] [--clear-domains]
|
|
214
|
+
|
|
215
|
+
# Private network: reach internal domains through a connector running in your network
|
|
216
|
+
minitest --app <app-id> apps private-network show
|
|
217
|
+
minitest --app <app-id> apps private-network connectors
|
|
218
|
+
minitest --app <app-id> apps private-network set [--enable|--disable] [--connector <name-or-id>] \
|
|
219
|
+
[--domain api.stg.corp.internal ...] [--remove-domain <d> ...] [--clear-domains] [--port 443 ...]
|
|
221
220
|
```
|
|
222
221
|
|
|
222
|
+
`--clear-domains --domain a --domain b` replaces the list; `--port` replaces the
|
|
223
|
+
ports (default 443). Turning the private network on needs a connector and at
|
|
224
|
+
least one domain. Connectors cannot be created from the CLI: a workspace owner
|
|
225
|
+
or admin creates them in the webapp, under **Workspace settings → Private
|
|
226
|
+
network**.
|
|
227
|
+
|
|
223
228
|
## Exit Codes
|
|
224
229
|
|
|
225
230
|
| Code | Meaning |
|
|
@@ -133,7 +133,7 @@ app defaults.
|
|
|
133
133
|
| Command | Description |
|
|
134
134
|
| ---------------- | ------------------------- |
|
|
135
135
|
| `minitest auth` | Authentication management |
|
|
136
|
-
| `minitest apps` | List, inspect, and create apps |
|
|
136
|
+
| `minitest apps` | List, inspect, and create apps; residential proxy and private network settings |
|
|
137
137
|
| `minitest scenario` | Create, update, list and delete scenarios |
|
|
138
138
|
| `minitest scenario-binding` | Bind test accounts, test files or app skills to scenarios |
|
|
139
139
|
| `minitest draft` | Drafts — branches of the test suite |
|
|
@@ -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
|
|
@@ -165,28 +164,34 @@ stderr and leave `--json` stdout unchanged. Switch to the new names.
|
|
|
165
164
|
| `run cancel --srp`, `run recording --srp` | `--target-id` |
|
|
166
165
|
| `--type` on `scenario create/update/list` | `--tag` |
|
|
167
166
|
|
|
168
|
-
##
|
|
167
|
+
## App network settings
|
|
169
168
|
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
169
|
+
Two per-app settings decide how test devices reach the network. Anyone on the
|
|
170
|
+
app can read them; only workspace **owners and admins** can change them (other
|
|
171
|
+
roles get `Only workspace owners and admins can change this setting`, exit 2).
|
|
172
|
+
`set` reads the current settings first and changes only what you pass.
|
|
173
|
+
Domains are an exact host (`api.stg.example.com`) or `*.example.com`, which
|
|
174
|
+
matches subdomains only, not `example.com` itself.
|
|
173
175
|
|
|
174
176
|
```bash
|
|
175
|
-
#
|
|
176
|
-
minitest
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
minitest
|
|
182
|
-
minitest
|
|
183
|
-
minitest
|
|
184
|
-
|
|
185
|
-
# Apply proposed edits now, or open the web review queue
|
|
186
|
-
minitest maintenance apply
|
|
187
|
-
minitest maintenance apply --review
|
|
177
|
+
# Residential proxy: reach the listed domains from a residential IP in one country
|
|
178
|
+
minitest --app <app-id> apps residential-proxy show
|
|
179
|
+
minitest --app <app-id> apps residential-proxy set [--enable|--disable] [--country tr] \
|
|
180
|
+
[--domain ipinfo.io ...] [--remove-domain <d> ...] [--clear-domains]
|
|
181
|
+
|
|
182
|
+
# Private network: reach internal domains through a connector running in your network
|
|
183
|
+
minitest --app <app-id> apps private-network show
|
|
184
|
+
minitest --app <app-id> apps private-network connectors
|
|
185
|
+
minitest --app <app-id> apps private-network set [--enable|--disable] [--connector <name-or-id>] \
|
|
186
|
+
[--domain api.stg.corp.internal ...] [--remove-domain <d> ...] [--clear-domains] [--port 443 ...]
|
|
188
187
|
```
|
|
189
188
|
|
|
189
|
+
`--clear-domains --domain a --domain b` replaces the list; `--port` replaces the
|
|
190
|
+
ports (default 443). Turning the private network on needs a connector and at
|
|
191
|
+
least one domain. Connectors cannot be created from the CLI: a workspace owner
|
|
192
|
+
or admin creates them in the webapp, under **Workspace settings → Private
|
|
193
|
+
network**.
|
|
194
|
+
|
|
190
195
|
## Exit Codes
|
|
191
196
|
|
|
192
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
|
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
"""Shared plumbing for the per-app network settings (residential proxy, private network)."""
|
|
2
|
+
|
|
3
|
+
import asyncio
|
|
4
|
+
import re
|
|
5
|
+
from typing import Any
|
|
6
|
+
|
|
7
|
+
import httpx
|
|
8
|
+
import typer
|
|
9
|
+
|
|
10
|
+
from minitest_cli.api.client import ApiClient
|
|
11
|
+
from minitest_cli.api.errors import format_network_error
|
|
12
|
+
from minitest_cli.commands._response_errors import extract_detail
|
|
13
|
+
from minitest_cli.core.app_context import resolve_app_id
|
|
14
|
+
from minitest_cli.core.auth import require_auth
|
|
15
|
+
from minitest_cli.core.config import Settings
|
|
16
|
+
from minitest_cli.utils.output import print_error
|
|
17
|
+
|
|
18
|
+
EXIT_GENERAL_ERROR = 1
|
|
19
|
+
EXIT_AUTH_ERROR = 2
|
|
20
|
+
EXIT_NETWORK_ERROR = 3
|
|
21
|
+
EXIT_NOT_FOUND = 4
|
|
22
|
+
|
|
23
|
+
ADMIN_ONLY_MESSAGE = "Only workspace owners and admins can change this setting."
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def is_json_mode() -> bool:
|
|
27
|
+
return typer.Context.json_mode # type: ignore[attr-defined]
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def resolve_target() -> tuple[Settings, str]:
|
|
31
|
+
settings: Settings = typer.Context.settings # type: ignore[attr-defined]
|
|
32
|
+
require_auth(settings)
|
|
33
|
+
return settings, resolve_app_id(settings, typer.Context.app_flag) # type: ignore[attr-defined]
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def fail(message: str, code: int = EXIT_GENERAL_ERROR) -> typer.Exit:
|
|
37
|
+
print_error(message)
|
|
38
|
+
return typer.Exit(code=code)
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def _raise_for_status(resp: httpx.Response) -> None:
|
|
42
|
+
if resp.status_code < 400:
|
|
43
|
+
return
|
|
44
|
+
detail = extract_detail(resp)
|
|
45
|
+
if resp.status_code == 403:
|
|
46
|
+
raise fail(f"{ADMIN_ONLY_MESSAGE} ({detail})", EXIT_AUTH_ERROR)
|
|
47
|
+
if resp.status_code == 401:
|
|
48
|
+
raise fail(f"Authentication failed: {detail}", EXIT_AUTH_ERROR)
|
|
49
|
+
if resp.status_code == 404:
|
|
50
|
+
raise fail(f"Not found: {detail}", EXIT_NOT_FOUND)
|
|
51
|
+
if resp.status_code in (400, 409, 422):
|
|
52
|
+
raise fail(f"Rejected by the server ({resp.status_code}): {detail}")
|
|
53
|
+
raise fail(f"API error ({resp.status_code}): {detail}", EXIT_NETWORK_ERROR)
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def call_api(
|
|
57
|
+
settings: Settings, method: str, path: str, body: dict[str, Any] | None = None
|
|
58
|
+
) -> dict[str, Any]:
|
|
59
|
+
async def _run() -> dict[str, Any]:
|
|
60
|
+
async with ApiClient(settings) as client:
|
|
61
|
+
resp = await client.request(method, path, json=body)
|
|
62
|
+
_raise_for_status(resp)
|
|
63
|
+
try:
|
|
64
|
+
return resp.json()
|
|
65
|
+
except ValueError as exc:
|
|
66
|
+
raise fail(
|
|
67
|
+
f"Unexpected non-JSON response ({resp.status_code}): {resp.text[:200]}",
|
|
68
|
+
EXIT_NETWORK_ERROR,
|
|
69
|
+
) from exc
|
|
70
|
+
|
|
71
|
+
try:
|
|
72
|
+
return asyncio.run(_run())
|
|
73
|
+
except httpx.HTTPError as exc:
|
|
74
|
+
raise fail(format_network_error(exc), EXIT_NETWORK_ERROR) from exc
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def merge_domains(
|
|
78
|
+
current: list[str],
|
|
79
|
+
*,
|
|
80
|
+
add: list[str] | None,
|
|
81
|
+
remove: list[str] | None,
|
|
82
|
+
clear: bool,
|
|
83
|
+
pattern: str,
|
|
84
|
+
max_domains: int,
|
|
85
|
+
) -> list[str]:
|
|
86
|
+
"""Apply ``--clear-domains``, ``--remove-domain`` then ``--domain`` and validate the result."""
|
|
87
|
+
added = [_normalize(d) for d in add or []]
|
|
88
|
+
invalid = [d for d in added if not re.fullmatch(pattern, d)]
|
|
89
|
+
if invalid:
|
|
90
|
+
raise fail(
|
|
91
|
+
f"Invalid domain(s): {', '.join(invalid)}. Use a lowercase host like api.example.com, "
|
|
92
|
+
"or *.example.com to match its subdomains (not example.com itself)."
|
|
93
|
+
)
|
|
94
|
+
removed = {_normalize(d) for d in remove or []}
|
|
95
|
+
unknown = sorted(removed - set(current))
|
|
96
|
+
if unknown:
|
|
97
|
+
raise fail(f"Not in the current domain list: {', '.join(unknown)}.")
|
|
98
|
+
base = [] if clear else [d for d in current if d not in removed]
|
|
99
|
+
merged = list(dict.fromkeys([*base, *added]))
|
|
100
|
+
if len(merged) > max_domains:
|
|
101
|
+
raise fail(f"Too many domains: {len(merged)} (max {max_domains}).")
|
|
102
|
+
return merged
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
def _normalize(domain: str) -> str:
|
|
106
|
+
return domain.strip().lower().rstrip(".")
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
def on_off(value: bool) -> str:
|
|
110
|
+
return "on" if value else "off"
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
def domain_list(domains: list[str]) -> str:
|
|
114
|
+
return ", ".join(domains) if domains else "-"
|
|
@@ -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(
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"""App management commands: list, get, create, dependencies."""
|
|
1
|
+
"""App management commands: list, get, create, dependencies, network settings."""
|
|
2
2
|
|
|
3
3
|
import asyncio
|
|
4
4
|
from pathlib import Path
|
|
@@ -10,7 +10,12 @@ import typer
|
|
|
10
10
|
from minitest_cli.api.apps_manager_client import AppsManagerClient # noqa: F401 re-exported for tests
|
|
11
11
|
from minitest_cli.api.client import ApiClient
|
|
12
12
|
from minitest_cli.api.errors import format_network_error
|
|
13
|
-
from minitest_cli.commands import
|
|
13
|
+
from minitest_cli.commands import (
|
|
14
|
+
apps_dependencies,
|
|
15
|
+
apps_get,
|
|
16
|
+
private_network,
|
|
17
|
+
residential_proxy,
|
|
18
|
+
)
|
|
14
19
|
from minitest_cli.commands.apps_helpers import create_app_request
|
|
15
20
|
from minitest_cli.commands.apps_table import APP_TABLE_HEADERS, app_row
|
|
16
21
|
from minitest_cli.core.auth import require_auth
|
|
@@ -30,6 +35,8 @@ EXIT_NETWORK_ERROR = 3
|
|
|
30
35
|
app = typer.Typer(name="apps", help="App management.")
|
|
31
36
|
app.command(name="dependencies")(apps_dependencies.dependencies)
|
|
32
37
|
app.command(name="get")(apps_get.get_app)
|
|
38
|
+
app.add_typer(residential_proxy.app)
|
|
39
|
+
app.add_typer(private_network.app)
|
|
33
40
|
|
|
34
41
|
|
|
35
42
|
@app.callback()
|
|
@@ -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)))
|