mega_snake 0.1.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.
Files changed (111) hide show
  1. mega_snake-0.1.0/.devcontainer/devcontainer.json +71 -0
  2. mega_snake-0.1.0/.github/copilot-instructions.md +432 -0
  3. mega_snake-0.1.0/.github/workflows/copilot-setup-steps.yml +44 -0
  4. mega_snake-0.1.0/.github/workflows/pr-validation.yml +37 -0
  5. mega_snake-0.1.0/.gitignore +18 -0
  6. mega_snake-0.1.0/LICENSE +201 -0
  7. mega_snake-0.1.0/PKG-INFO +258 -0
  8. mega_snake-0.1.0/README.md +227 -0
  9. mega_snake-0.1.0/build.gradle +0 -0
  10. mega_snake-0.1.0/offproject/mega_snake/gcloud/__init__.py +1 -0
  11. mega_snake-0.1.0/offproject/mega_snake/gcloud/module.py +33 -0
  12. mega_snake-0.1.0/offproject/mega_snake/gcloud/parse_instances_deployment_id.py +42 -0
  13. mega_snake-0.1.0/offproject/mega_snake/gcloud/parse_json_logs.py +55 -0
  14. mega_snake-0.1.0/offproject/mega_snake/gcloud/sign.py +130 -0
  15. mega_snake-0.1.0/offproject/tests/gcloud/test_gcloud_module.py +46 -0
  16. mega_snake-0.1.0/offproject/tests/gcloud/test_parse_instances_deployment_id.py +139 -0
  17. mega_snake-0.1.0/offproject/tests/gcloud/test_sign.py +387 -0
  18. mega_snake-0.1.0/out/jq.pyi +58 -0
  19. mega_snake-0.1.0/pyproject.toml +106 -0
  20. mega_snake-0.1.0/src/mega_snake/__init__.py +1 -0
  21. mega_snake-0.1.0/src/mega_snake/__main__.py +107 -0
  22. mega_snake-0.1.0/src/mega_snake/config.properties +11 -0
  23. mega_snake-0.1.0/src/mega_snake/config_environment/__init__.py +1 -0
  24. mega_snake-0.1.0/src/mega_snake/config_environment/create_working_env.py +437 -0
  25. mega_snake-0.1.0/src/mega_snake/config_environment/gradle_set.py +209 -0
  26. mega_snake-0.1.0/src/mega_snake/config_environment/graphql_schema.py +79 -0
  27. mega_snake-0.1.0/src/mega_snake/config_environment/java_set.py +292 -0
  28. mega_snake-0.1.0/src/mega_snake/config_environment/local_config.py +72 -0
  29. mega_snake-0.1.0/src/mega_snake/config_environment/maven_set.py +330 -0
  30. mega_snake-0.1.0/src/mega_snake/config_environment/models/github_queries.py +78 -0
  31. mega_snake-0.1.0/src/mega_snake/config_environment/models/log_viewer_watcher.py +70 -0
  32. mega_snake-0.1.0/src/mega_snake/config_environment/models/tools_version.py +204 -0
  33. mega_snake-0.1.0/src/mega_snake/config_environment/models/vscode_input.py +117 -0
  34. mega_snake-0.1.0/src/mega_snake/config_environment/models/vscode_launch.py +140 -0
  35. mega_snake-0.1.0/src/mega_snake/config_environment/models/vscode_task.py +266 -0
  36. mega_snake-0.1.0/src/mega_snake/config_environment/module.py +33 -0
  37. mega_snake-0.1.0/src/mega_snake/config_environment/util.py +61 -0
  38. mega_snake-0.1.0/src/mega_snake/config_setup.ps1 +44 -0
  39. mega_snake-0.1.0/src/mega_snake/config_setup.sh +48 -0
  40. mega_snake-0.1.0/src/mega_snake/constants.py +60 -0
  41. mega_snake-0.1.0/src/mega_snake/diff_tree/__init__.py +1 -0
  42. mega_snake-0.1.0/src/mega_snake/diff_tree/file_type.py +81 -0
  43. mega_snake-0.1.0/src/mega_snake/diff_tree/module.py +154 -0
  44. mega_snake-0.1.0/src/mega_snake/light_weight/__init__.py +1 -0
  45. mega_snake-0.1.0/src/mega_snake/light_weight/create_release.py +105 -0
  46. mega_snake-0.1.0/src/mega_snake/light_weight/echo.py +81 -0
  47. mega_snake-0.1.0/src/mega_snake/light_weight/jks_expired_certs.py +105 -0
  48. mega_snake-0.1.0/src/mega_snake/light_weight/module.py +30 -0
  49. mega_snake-0.1.0/src/mega_snake/light_weight/release.py +132 -0
  50. mega_snake-0.1.0/src/mega_snake/light_weight/release_handler.py +76 -0
  51. mega_snake-0.1.0/src/mega_snake/light_weight/shell_init.py +76 -0
  52. mega_snake-0.1.0/src/mega_snake/remote_branches/__init__.py +1 -0
  53. mega_snake-0.1.0/src/mega_snake/remote_branches/cleanup_remote_branches.py +63 -0
  54. mega_snake-0.1.0/src/mega_snake/remote_branches/details_remote_branches.py +101 -0
  55. mega_snake-0.1.0/src/mega_snake/remote_branches/module.py +24 -0
  56. mega_snake-0.1.0/src/mega_snake/remote_branches/parse_remote_branches.py +73 -0
  57. mega_snake-0.1.0/src/mega_snake/remote_branches/remote_branch.py +161 -0
  58. mega_snake-0.1.0/src/mega_snake/resources/java-formatter.xml +337 -0
  59. mega_snake-0.1.0/src/mega_snake/util/__init__.py +1 -0
  60. mega_snake-0.1.0/src/mega_snake/util/cli_group.py +71 -0
  61. mega_snake-0.1.0/src/mega_snake/util/formatting.py +234 -0
  62. mega_snake-0.1.0/src/mega_snake/util/props.py +384 -0
  63. mega_snake-0.1.0/src/mega_snake/util/util.py +247 -0
  64. mega_snake-0.1.0/src/tests/config.properties +9 -0
  65. mega_snake-0.1.0/src/tests/config_environment/models/test_github_queries.py +109 -0
  66. mega_snake-0.1.0/src/tests/config_environment/models/test_log_viewer_watcher.py +119 -0
  67. mega_snake-0.1.0/src/tests/config_environment/models/test_tools_version.py +353 -0
  68. mega_snake-0.1.0/src/tests/config_environment/models/test_vscode_input.py +129 -0
  69. mega_snake-0.1.0/src/tests/config_environment/models/test_vscode_launch.py +147 -0
  70. mega_snake-0.1.0/src/tests/config_environment/models/test_vscode_task.py +128 -0
  71. mega_snake-0.1.0/src/tests/config_environment/test_ce_util.py +89 -0
  72. mega_snake-0.1.0/src/tests/config_environment/test_config_environment_module.py +20 -0
  73. mega_snake-0.1.0/src/tests/config_environment/test_create_working_env.py +886 -0
  74. mega_snake-0.1.0/src/tests/config_environment/test_gradle_set.py +449 -0
  75. mega_snake-0.1.0/src/tests/config_environment/test_graphql_schema.py +249 -0
  76. mega_snake-0.1.0/src/tests/config_environment/test_java_set.py +790 -0
  77. mega_snake-0.1.0/src/tests/config_environment/test_local_config.py +169 -0
  78. mega_snake-0.1.0/src/tests/config_environment/test_maven_set.py +844 -0
  79. mega_snake-0.1.0/src/tests/gradle/bash_local_file.sh +14 -0
  80. mega_snake-0.1.0/src/tests/gradle/darwin.code-workspace +457 -0
  81. mega_snake-0.1.0/src/tests/gradle/empty.code-workspace +15 -0
  82. mega_snake-0.1.0/src/tests/gradle/empty_local_file.sh +14 -0
  83. mega_snake-0.1.0/src/tests/light_weight/test_light_weight_helpers.py +114 -0
  84. mega_snake-0.1.0/src/tests/light_weight/test_light_weight_module.py +11 -0
  85. mega_snake-0.1.0/src/tests/light_weight/test_release_handler.py +61 -0
  86. mega_snake-0.1.0/src/tests/light_weight/test_shell_init.py +54 -0
  87. mega_snake-0.1.0/src/tests/maven/bash_local_file.sh +14 -0
  88. mega_snake-0.1.0/src/tests/maven/darwin.code-workspace +150 -0
  89. mega_snake-0.1.0/src/tests/maven/empty.code-workspace +15 -0
  90. mega_snake-0.1.0/src/tests/maven/empty_local_file.sh +14 -0
  91. mega_snake-0.1.0/src/tests/maven/pom.xml +26 -0
  92. mega_snake-0.1.0/src/tests/remote_branches/test_remote_branch_helpers.py +129 -0
  93. mega_snake-0.1.0/src/tests/remote_branches/test_remote_branches_module.py +11 -0
  94. mega_snake-0.1.0/src/tests/resources/graphql/extended-types.graphql +75 -0
  95. mega_snake-0.1.0/src/tests/resources/graphql/mutations.graphql +42 -0
  96. mega_snake-0.1.0/src/tests/resources/graphql/queries.graphql +37 -0
  97. mega_snake-0.1.0/src/tests/resources/graphql/specialized-types.graphql +57 -0
  98. mega_snake-0.1.0/src/tests/resources/graphql/types.graphql +31 -0
  99. mega_snake-0.1.0/src/tests/test.code-workspace +9 -0
  100. mega_snake-0.1.0/src/tests/test_cli_commands_aliases.py +31 -0
  101. mega_snake-0.1.0/src/tests/test_cli_entrypoint.py +97 -0
  102. mega_snake-0.1.0/src/tests/test_main_and_diff_tree.py +93 -0
  103. mega_snake-0.1.0/src/tests/test_resources/test_resources +1 -0
  104. mega_snake-0.1.0/src/tests/test_util/side_effect_wrapper.py +30 -0
  105. mega_snake-0.1.0/src/tests/test_util/util_test.py +52 -0
  106. mega_snake-0.1.0/src/tests/util/test_cli_group.py +140 -0
  107. mega_snake-0.1.0/src/tests/util/test_formatting.py +271 -0
  108. mega_snake-0.1.0/src/tests/util/test_props_helpers.py +93 -0
  109. mega_snake-0.1.0/src/tests/util/test_util.py +366 -0
  110. mega_snake-0.1.0/stuff.code-workspace +656 -0
  111. mega_snake-0.1.0/uv.lock +614 -0
@@ -0,0 +1,71 @@
1
+ {
2
+ "name": "MegaSnake CLI - Java 21 + Python 3.13",
3
+ "image": "mcr.microsoft.com/devcontainers/java:21-bullseye",
4
+ "features": {
5
+ "ghcr.io/devcontainers/features/java:1": {
6
+ "version": "21",
7
+ "installMaven": false,
8
+ "installGradle": true
9
+ },
10
+ "ghcr.io/devcontainers/features/python:1": {
11
+ "version": "3.13"
12
+ },
13
+ "ghcr.io/devcontainers/features/git:1": {}
14
+ },
15
+ "containerEnv": {
16
+ "PYTHONPATH": "${containerWorkspaceFolder}",
17
+ "JAVA_HOME": "/usr/local/sdkman/candidates/java/current",
18
+ "GRADLE_HOME": "/opt/gradle/gradle-8.11"
19
+ },
20
+ "remoteEnv": {
21
+ "PYTHONPATH": "${containerWorkspaceFolder}"
22
+ },
23
+ "postCreateCommand": "pip install --upgrade pip && pip install poetry",
24
+ "customizations": {
25
+ "vscode": {
26
+ "extensions": [
27
+ "ms-python.python",
28
+ "ms-python.vscode-pylance",
29
+ "ms-python.debugpy",
30
+ "vscjava.vscode-java-pack",
31
+ "vscjava.vscode-gradle",
32
+ "vscjava.vscode-java-debug",
33
+ "redhat.java",
34
+ "github.vscode-github-actions",
35
+ "github.vscode-pull-request-github",
36
+ "graphql.vscode-graphql-syntax",
37
+ "graphql.vscode-graphql"
38
+ ],
39
+ "settings": {
40
+ "python.defaultInterpreterPath": "/usr/local/bin/python3.13",
41
+ "python.analysis.extraPaths": [
42
+ "${containerWorkspaceFolder}"
43
+ ],
44
+ "python.linting.enabled": true,
45
+ "python.linting.pylintEnabled": true,
46
+ "python.linting.pylintPath": "/usr/local/bin/pylint",
47
+ "[python]": {
48
+ "editor.defaultFormatter": "ms-python.python",
49
+ "editor.formatOnSave": true
50
+ }
51
+ }
52
+ }
53
+ },
54
+ "mounts": [
55
+ "source=${localEnv:HOME}${localEnv:USERPROFILE}/.ssh,target=/home/vscode/.ssh,type=bind,consistency=cached"
56
+ ],
57
+ "forwardPorts": [
58
+ 5005,
59
+ 8080
60
+ ],
61
+ "portsAttributes": {
62
+ "5005": {
63
+ "label": "Java Debug",
64
+ "onAutoForward": "notify"
65
+ },
66
+ "8080": {
67
+ "label": "Application",
68
+ "onAutoForward": "notify"
69
+ }
70
+ }
71
+ }
@@ -0,0 +1,432 @@
1
+ # GitHub Copilot Instructions for `unix-scripts` (Mega Snake)
2
+
3
+ ## 1. Project Overview & Philosophy
4
+
5
+ `mega_snake` is a robust Python 3.13+ CLI tool designed to standardize the local development lifecycle. It acts as a "Swiss Army Knife" for developers, primarily automating the complex configuration of VS Code environments for Java/Gradle, but extending into Git management, Release orchestration context, and Google Cloud observability.
6
+
7
+ **Core Philosophy:**
8
+ - **Zero Config Start**: A developer should be able to run `mgsnake working-env` and have a fully functional IDE state immediately.
9
+ - **Idempotency**: Commands should be safe to run multiple times without destructive side effects unless explicitly requested.
10
+ - **System Integration**: The tool deeply integrates with the OS shell (Bash/Zsh/PowerShell) and external tools (Git, Java, Gradle).
11
+
12
+ **Tech Stack:**
13
+ - **Runtime**: Python 3.13+
14
+ - **CLI Framework**: `click` (Command composition), `rich-click` (Beautiful help text/formatting)
15
+ - **UI/Output**: `colorama` (Terminal colors), `rich` (Tables/Trees)
16
+ - **Dependency Management**: `uv`
17
+ - **Shell Interop**: Custom shell scripts (`config_setup.sh/ps1`) that wrap the python execution.
18
+
19
+ ---
20
+
21
+ ## 2. Architecture & Patterns
22
+
23
+ ### 2.1 Entry Point & CLI Orchestration (`src/mega_snake/__main__.py`)
24
+
25
+ The application uses a `click.Group` with a custom `CliGroup` class to support command aliases. The entry point `cli()` function initializes global application properties before any command runs.
26
+
27
+ **Critical Pattern: Initialization & Light-weight Mode**
28
+ The CLI checks for a `skip` flag in command metadata. If present, it bypasses heavy environment checks (like requiring a valid workspace folder), allowing "light-weight" commands (e.g., `create-release`) to run anywhere.
29
+
30
+ ```python
31
+ # src/mega_snake/__main__.py
32
+ @click.pass_context
33
+ def cli(ctx: click.Context, log_level: str, shell: str) -> None:
34
+ # ...
35
+ # Access metadata to check for 'skip' flag
36
+ metadata = getattr(cmd.callback, "flags", {})
37
+ if flags and "skip" in flags:
38
+ # Light-weight mode: minimal initialization
39
+ init_app_properties(log_level, shell, light_weight=True)
40
+ ```
41
+
42
+ ### 2.2 Command Registration & Aliases (`src/mega_snake/util/cli_group.py`)
43
+
44
+ We do not standard `click` alias implementation. We use `CliGroup` to register commands with multiple names.
45
+
46
+ **Usage:**
47
+ ```python
48
+ # Registration in __main__.py
49
+ from .diff_tree.module import main as diff_tree
50
+ # Registers 'diff-tree' command accessible via 'dt' and 'tree' aliases
51
+ cli.add_command_with_alias(diff_tree, ["dt", "tree"])
52
+ ```
53
+
54
+ ### 2.3 The Wrapper Pattern (`module.py` files)
55
+
56
+ Each functional module (e.g., `config_environment`) exposes an `add_wrapper` decorator. This allows module-specific checks to run before the command execution, keeping the core logic clean.
57
+
58
+ **Example from `src/mega_snake/config_environment/module.py`:**
59
+ ```python
60
+ def wrapper(_ctx: click.Context, *_args, **_kwargs) -> None:
61
+ # Pre-flight check: verify we're in a valid workspace
62
+ if not get_workspace_folder():
63
+ raise RuntimeError("Not in a valid workspace.")
64
+
65
+ add_wrapper = wrapper_decorator(wrapper)
66
+
67
+ # Usage in __main__.py
68
+ for command in config_environment.commands.values():
69
+ # Wraps every command in the module with the pre-flight check
70
+ cli.add_command(config_environment_result_callback(command))
71
+ ```
72
+
73
+ **Educational Logic:**
74
+ This implements the **Decorator Pattern**. Instead of repeating validation logic in every command, we define it once in the wrapper. The `__main__.py` entry point applies this wrapper dynamically when registering commands, ensuring checks only run when a relevant command is invoked.
75
+
76
+ ---
77
+
78
+ ## 3. Core Functional Modules
79
+
80
+ ### 3.1 Environment Configuration (`src/mega_snake/config_environment/`)
81
+
82
+ This is the most complex module, responsible for generating `.code-workspace` files. It configures the "settings" section of the workspace file directly, avoiding reliance on `.vscode/settings.json`.
83
+
84
+ #### `working-env`
85
+ - **Logic**:
86
+ 1. Validates Git repository status.
87
+ 2. Loads local developer overrides (`initial_load`).
88
+ 3. Configures Java (`set-java`) and Gradle (`set-gradle`).
89
+ 4. Generates VS Code tasks, launch configurations, and recommendations.
90
+
91
+ #### `set-java` (`java_set.py`)
92
+ Manages the `java.configuration.runtimes` and `terminal.integrated.env` settings in VS Code.
93
+
94
+ **Key Logic:**
95
+ - It parses the `.code-workspace` file (as JSON with comments).
96
+ - It queries the OS for installed JDKs.
97
+ - It updates the `settings` structure inside the workspace file to point `JAVA_HOME` to the selected version.
98
+
99
+ ```python
100
+ # src/mega_snake/config_environment/java_set.py
101
+ ENV_VARIABLE = f"terminal.integrated.env.{OS_MAP[OS]}"
102
+ JAVA_JQ_QUERY = f'.settings["{ENV_VARIABLE}"].JAVA_HOME'
103
+
104
+ # It uses python logic to traverse the JSON structure similar to JQ
105
+ # to find and replace the Java path.
106
+ ```
107
+
108
+ #### `set-gradle` (`gradle_set.py`)
109
+ Like `set-java`, this configures the Gradle version for the workspace.
110
+
111
+ **Key Logic:**
112
+ - It identifies installed Gradle versions via `ToolVersion` abstraction.
113
+ - It updates `java.import.gradle.home` and `terminal.integrated.env` settings.
114
+ - It ensures consistency between the terminal environment and the IDE's internal Gradle wrapper.
115
+
116
+ **Technical Note: JSON with Comments**
117
+ Both `set-java` and `set-gradle` modify the `.code-workspace` file which contains comments. The standard python `json` library fails on comments. We use a custom `load_json_with_comments` utility to handle VS Code's configuration format safely without stripping comments, which are vital for developers understanding the config.
118
+
119
+ #### `init-local-config` (`local_config.py`)
120
+ Creates a local developer-specific configuration file that is **ignored by Git**.
121
+
122
+ **Why?**
123
+ Developers often have machine-specific tokens, paths, or aliases that shouldn't be committed to the repo. `init-local-config` generates a shell-specific file (`.sh` or `.ps1` logic embedded) that is sourced by the main environment. This pattern allows the tool to support "Convention over Configuration" while still allowing for "Configuration" when necessary.
124
+
125
+ ### 3.2 Git Utilities (`src/mega_snake/diff_tree/`)
126
+
127
+ #### `diff-tree` (`dt`)
128
+ Generates a visual tree representation of changed files.
129
+
130
+ **Implementation Details:**
131
+ - Uses `git diff-tree -r {main_branch} {current_branch}` to get raw file lists.
132
+ - categorizes files using `FileType.from_symbol(symbol)`.
133
+ - Reconstructs a dummy directory structure in `workspace_temp/diff_tree_dummy_repo`.
134
+ - Uses `directory_tree` library to generating the visual text tree.
135
+
136
+ ```python
137
+ # src/mega_snake/diff_tree/module.py
138
+ for diff in diff_str.split("\n"):
139
+ columns: list[str] = diff.split("\t")
140
+ symbol = columns[0].split(" ")[4] # M, A, D, etc.
141
+ path: str = columns[1]
142
+ # builds tree structure...
143
+ ```
144
+
145
+ ### 3.3 Remote Branch Management (`src/mega_snake/remote_branches/`)
146
+
147
+ #### `remote-branches-details`
148
+ Analyzes remote branches to suggest cleanup candidates.
149
+
150
+ **Filtering Logic (`-f` flag):**
151
+ - **'M' (Merged)**: Branches that have been merged into `master`.
152
+ - **'U' (Unmerged)**: Branches with unique commits not in `master`.
153
+ - **'A' (All)**: Both.
154
+
155
+ It creates `workspace_temp/remote_branches.txt` containing detailed metadata (author, last commit date, ahead/behind count) for every branch.
156
+
157
+ #### `remote-branches-cleanup`
158
+ An interactive tool that consumes the output of `remote-branches-details`.
159
+
160
+ **Logic:**
161
+ 1. Allows re-running `remote-branches-details` to refresh data.
162
+ 2. Reads `workspace_temp/remote_branches.txt`.
163
+ 3. Presents an interactive list to the user to select branches for deletion.
164
+ 4. Performs `git push origin --delete <branch>` and prunes local references.
165
+
166
+ **Design Pattern: Pipeline via Files**
167
+ Instead of passing complex objects between commands in memory, we use the filesystem (`remote_branches.txt`) as an intermediate buffer. This allows the user to inspect (and potentially edit) the list of candidates before running the destructive cleanup command.
168
+
169
+ ### 3.4 Release Management (`src/mega_snake/light_weight/create_release.py`)
170
+
171
+ Automates GitHub releases, creating tags and proper GitHub Release entries.
172
+
173
+ **Arguments:**
174
+ - `tag_suffix`: e.g., `v1.0.0-{suffix}`
175
+ - `release_type`:
176
+ - `p`: Prerelease (`--prerelease`)
177
+ - `l`: Latest (`--latest`)
178
+ - `r`: Replace Latest (Updates the `latest` tag to point to a new commit)
179
+
180
+ **Logic:**
181
+ It fetches the current tags, calculates the new tag based on the suffix, and relies on the `gh` CLI to publish the release.
182
+
183
+ **Technical Note: Why use the `gh` wrapper?**
184
+ We use the `gh` (GitHub CLI) tool because it leverages the user's existing authentication state, avoiding the need to manage complex API tokens within the Python code.
185
+
186
+ ```python
187
+ # src/mega_snake/light_weight/release_handler.py
188
+ cwd: str = (
189
+ f'gh release create {tag_name} {release_type} --target "{release_branch}" '
190
+ f'--title "{tag_name}" {release_notes} --generate-notes'
191
+ )
192
+ ```
193
+
194
+ **Educational Logic:**
195
+ Instead of re-implementing the GitHub API client (which requires managing OAuth tokens, permissions, etc.), we delegate the heavy lifting to the `gh` binary. This is a common "shell wrapper" pattern where Python manages the *control flow* and *validation*, but the shell executes the *remote action*.
196
+
197
+ ### 3.5 Other Utilities
198
+
199
+ #### `graphql-schema` (`graphql_schema.py`)
200
+ Compiles multiple `.graphql` files into a single schema and generates introspection JSON.
201
+
202
+ **Why introspection?**
203
+ Frontend tools (like Apollo) and IDE plugins often require a full introspection result (`schema.json`) to provide autocompletion and type checking, not just the raw SDL string.
204
+
205
+ #### `expired-certs-jks` (`jks_expired_certs.py`)
206
+ Audits Java KeyStore (JKS) files for expired certificates using `keytool`.
207
+
208
+ **Technical Challenge:**
209
+ Parsing the output of `keytool -v -list` is non-trivial because the date format depends on the system locale and standard Java output formats. The tool attempts to parse these formats to warn developers before their local dev environments break due to expired SSL certs.
210
+
211
+ #### `msg` (`echo.py`)
212
+ Exposes the internal logging mechanism to the shell. Used by `config_setup.sh` to print consistent success/error messages from shell scripts.
213
+
214
+ ---
215
+
216
+ ## 4. Utilities & Helpers
217
+
218
+ ### 4.1 Output Formatting (`src/mega_snake/util/formatting.py`)
219
+
220
+ ** STRICT RULE**: NEVER use `print()`. Always use valid logging/formatting functions.
221
+
222
+ - `ws_info(msg)`: ℹ️ Blue info message.
223
+ - `ws_success(msg)`: ✅ Green success message.
224
+ - `ws_warning(msg)`: ⚠️ Yellow warning.
225
+ - `ws_error(msg)`: ❌ Red error.
226
+ - `ws_advice(msg)`: 💡 Helpful tip/advice.
227
+
228
+ ### 4.2 Property Management (`src/mega_snake/util/props.py`)
229
+
230
+ Configuration is layered:
231
+ 1. **Hardcoded Defaults**
232
+ 2. **`src/config.properties`**: Static project config (versions, default paths).
233
+ 3. **Local Overrides**: A local file (usually ignored by git) that overrides specific keys for a specific developer machine.
234
+
235
+ Access properties via `get_property(key)`.
236
+
237
+ ### 4.3 Shell Execution (`src/mega_snake/util/util.py`)
238
+
239
+ Use `run_operation` for ALL shell commands. It handles logging, error capturing, and return codes.
240
+
241
+ ```python
242
+ result = run_operation(
243
+ command="git fetch --all",
244
+ message="Fetching remotes" # This is logged to console/file
245
+ )
246
+ if result.returncode != 0:
247
+ # handle error...
248
+ ```
249
+
250
+ ---
251
+
252
+ ## 5. Shell Integration & Deployment
253
+
254
+ ### User Installation Flow
255
+
256
+ When end-users install `mega_snake` via `uv tool install` or `pipx install`:
257
+
258
+ 1. The package is installed in an isolated virtual environment.
259
+ 2. The `mgsnake` command becomes available globally.
260
+ 3. Users add initialization code to their shell profile:
261
+ - **Bash/Zsh**: `. "$(mgsnake shell-path bash)"` → outputs the path to `config_setup.sh`
262
+ - **PowerShell**: `. (mgsnake shell-path pwsh)` → outputs the path to `config_setup.ps1`
263
+ 4. The initialization script (`config_setup.sh` or `config_setup.ps1`) is sourced, which:
264
+ - Sets `MEGA_SNAKE_SHELL` environment variable
265
+ - Defines `mgsnake_reload` to (re)load the local config file (if present)
266
+ - Calls `mgsnake_reload` once so the local config is applied immediately
267
+ **Why this approach?**
268
+ - Allows the tool to run anywhere without polluting the user's active Python environment
269
+ - Users don't need to manually activate/deactivate virtual environments
270
+ - The `mgsnake` console script runs from its isolated `uv tool`/`pipx` environment
271
+ - Sourcing the shell setup only configures shell integration (`MEGA_SNAKE_SHELL` and `mgsnake_reload`) per session
272
+
273
+ ### Local Development Setup
274
+
275
+ **Prerequisites:**
276
+ - Python 3.13+
277
+ - `uv` package manager
278
+
279
+ **Setup Steps:**
280
+
281
+ 1. Clone the repository and navigate to the root:
282
+ ```bash
283
+ git clone <repo-url>
284
+ cd unix-scripts
285
+ ```
286
+
287
+ 2. Install dependencies (including dev dependencies):
288
+ ```bash
289
+ uv sync --all-extras
290
+ ```
291
+
292
+ 3. Build the wheel:
293
+ ```bash
294
+ uv build
295
+ ```
296
+
297
+ 4. Install locally for testing:
298
+ ```bash
299
+ uv tool install dist/*.whl --force-reinstall
300
+ ```
301
+
302
+ 5. Add the initialization script to your shell profile (same as end-users do):
303
+ - **Bash/Zsh**: Add `. "$(mgsnake shell-path bash)"` to `~/.bashrc` or `~/.zshrc`
304
+ - **PowerShell**: Add `. (mgsnake shell-path pwsh)` to your PowerShell profile
305
+
306
+ 6. Restart your terminal and verify:
307
+ ```bash
308
+ mgsnake --help
309
+ ```
310
+
311
+ ---
312
+
313
+ ## 6. Development Rules
314
+
315
+ ### 6.1 Code Quality Standards
316
+
317
+ **ALL code must follow these standards without exception:**
318
+
319
+ 1. **Type Hinting - MANDATORY for all functions and parameters:**
320
+ - **All function parameters** must have explicit type annotations (e.g., `name: str`, `count: int`)
321
+ - **All function return types** must be explicitly declared (e.g., `-> str`, `-> None`, `-> list[str]`)
322
+ - **Use `Optional[T]`** for optional types instead of `T | None` (e.g., `Optional[str]` not `str | None`)
323
+ - Example:
324
+ ```python
325
+ def process_data(items: list[str], timeout: Optional[int] = None) -> dict[str, int]:
326
+ """Process items with optional timeout."""
327
+ pass
328
+ ```
329
+
330
+ 2. **Docstrings - MANDATORY for all modules, classes, and functions:**
331
+ - **Module-level docstring**: Must be at the top of every `.py` file
332
+ - **Class docstring**: Required for all class definitions
333
+ - **Function/method docstring**: Required for every function and method (including `__init__`, `__str__`, etc.)
334
+ - **Format**: Use the following structure for methods:
335
+ ```python
336
+ """Brief description of what the method does.
337
+
338
+ Parameters:
339
+ param_name: Description of parameter.
340
+ another_param: Description of another parameter.
341
+
342
+ Raises:
343
+ ValueError: Description of when this exception is raised.
344
+ RuntimeError: Description of when this exception is raised.
345
+
346
+ Returns:
347
+ str: Description of the return value.
348
+ """
349
+ ```
350
+ - **Note**: If there are no parameters, raises, or returns, explicitly state `None` in those sections.
351
+ - Example:
352
+ ```python
353
+ def validate_path(path: str) -> bool:
354
+ """Check if the given path is valid and accessible.
355
+
356
+ Parameters:
357
+ path: The file system path to validate.
358
+
359
+ Raises:
360
+ ValueError: If path is None or empty string.
361
+
362
+ Returns:
363
+ bool: True if the path is valid, False otherwise.
364
+ """
365
+ pass
366
+ ```
367
+
368
+ 3. **Imports**: Group imports in this order:
369
+ - Standard Library
370
+ - Third Party
371
+ - Local Application
372
+ - Each group separated by a blank line
373
+
374
+ 4. **Error Handling**:
375
+ - Raise `ValueError` for invalid user input
376
+ - Raise `click.ClickException` for expected CLI errors
377
+ - Let unexpected errors bubble up to `__main__.py` to be caught by the global handler
378
+
379
+ 5. **Paths**: Always use `pathlib.Path` or `os.path` joins. Never use string concatenation for paths.
380
+
381
+ ### 6.2 Testing & Coverage Requirements (CRITICAL)
382
+
383
+ **MANDATORY: Any file created, modified, or deleted must have corresponding tests created, updated, or removed respectively.**
384
+
385
+ #### Core Principles
386
+
387
+ - **Do not simplify, remove, weaken, or rewrite existing passing tests** unless strictly necessary to fix a defect.
388
+ - **Do not exclude files, modules, classes, or functions from the pytest test suite** to artificially increase coverage.
389
+ - **Do not modify source code solely to make testing easier** or to reduce the number of required tests.
390
+ - **New tests must validate real application behavior**, not be written solely to inflate coverage metrics.
391
+ - **Reuse existing fixtures, helpers, and testing patterns** whenever possible to maintain consistency.
392
+ - **Preserve the current project structure and testing conventions** throughout all changes.
393
+
394
+ #### Coverage Requirements
395
+
396
+ - **Overall project coverage**: Minimum 95%
397
+ - **All new or modified source code**: Minimum 98% coverage
398
+ - **All tests must pass** before any PR is submitted
399
+
400
+ #### Testing Workflow
401
+
402
+ 1. **New Source Code**: Create comprehensive tests in `src/tests/{module}/` directory. Ensure 98% coverage.
403
+ 2. **Modified Source Code**: Update existing tests to reflect changes. Add new tests for new behavior. Maintain 98% coverage.
404
+ 3. **Deleted Source Code**: Remove or update corresponding tests in `src/tests/{module}/` directory.
405
+ 4. **Run Tests**: Execute `pytest` to verify all tests pass and coverage goals are met.
406
+
407
+ ```bash
408
+ # Run full test suite with coverage reporting
409
+ pytest
410
+
411
+ # This generates:
412
+ # - report.html: HTML report of test results
413
+ # - coverage_html/index.html: Detailed coverage breakdown by file
414
+ # - Fails if coverage < 95% overall or < 98% for new code
415
+ ```
416
+
417
+ #### Example: What This Means
418
+
419
+ **If you modify `config_environment/java_set.py`:**
420
+ - Update tests in `src/tests/config_environment/test_java_set.py`
421
+ - Add tests for any new functions or branches
422
+ - Ensure the modified functions have 98% coverage
423
+ - Verify overall project coverage remains ≥ 95%
424
+
425
+ **If you create `util/new_helper.py`:**
426
+ - Create `src/tests/util/test_new_helper.py` with comprehensive tests
427
+ - All functions must have 98% coverage
428
+ - Tests must validate real behavior, not just code paths
429
+
430
+ **If you delete a module:**
431
+ - Remove its corresponding test file or test class
432
+ - Verify overall coverage still meets 95% threshold
@@ -0,0 +1,44 @@
1
+ name: Copilot Setup Steps
2
+
3
+ on:
4
+ workflow_dispatch:
5
+ push:
6
+ paths:
7
+ - .github/workflows/copilot-setup-steps.yml
8
+
9
+ jobs:
10
+ copilot-setup-steps: # This name is mandatory
11
+ runs-on: ubuntu-latest
12
+ permissions:
13
+ contents: read # This is mandatory to allow the action to read the repository contents
14
+ steps:
15
+ - name: Checkout code
16
+ uses: actions/checkout@v4
17
+
18
+ - name: Set up Python 3.13
19
+ uses: actions/setup-python@v5
20
+ with:
21
+ python-version: '3.13'
22
+
23
+ - name: Upgrade pip
24
+ run: |
25
+ python -m pip install --upgrade pip setuptools wheel
26
+
27
+ - name: Install uv
28
+ uses: astral-sh/setup-uv@v6
29
+
30
+ - name: Install Rust toolchain
31
+ uses: dtolnay/rust-toolchain@stable
32
+
33
+ - name: Verify toolchain
34
+ run: |
35
+ python --version
36
+ pip --version
37
+ uv --version
38
+ rustc --version
39
+ cargo --version
40
+
41
+ # Opcional: crea un .venv para que Copilot lo tenga listo
42
+ - name: Create virtual environment
43
+ run: |
44
+ uv venv
@@ -0,0 +1,37 @@
1
+ name: PR Validation
2
+
3
+ on:
4
+ pull_request:
5
+ types: [ opened, ready_for_review, reopened, synchronize ]
6
+
7
+ jobs:
8
+ test:
9
+ runs-on: ubuntu-latest
10
+
11
+ steps:
12
+ - uses: actions/checkout@v4
13
+
14
+ - name: Set up Python
15
+ uses: actions/setup-python@v4
16
+ with:
17
+ python-version: '3.13'
18
+
19
+ - name: Install uv
20
+ run: |
21
+ pip install uv
22
+
23
+ - name: Install dependencies
24
+ run: |
25
+ uv sync --all-extras
26
+
27
+ - name: Run pytest
28
+ run: |
29
+ uv run pytest
30
+
31
+ - name: Run ruff check
32
+ run: |
33
+ uv run ruff check src/mega_snake --output-format=concise
34
+
35
+ - name: Run mypy
36
+ run: |
37
+ uv run mypy --show-column-numbers --no-error-summary src/mega_snake
@@ -0,0 +1,18 @@
1
+ .DS_Store
2
+ mega_snake/**/__pycache__
3
+ tests/**/__pycache__
4
+ mega_snake/lib
5
+ mega_snake/bin
6
+ mega_snake/include
7
+ pyvenv.cfg
8
+ poetry.lock
9
+ .gradle
10
+ build/
11
+ .vscode
12
+ coverage_html
13
+ .coverage
14
+ report.html
15
+ assets/
16
+ **/__pycache__
17
+ src/tests/util/test_props.py
18
+ workspace_temp