mule-discovery 1.0.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 (106) hide show
  1. mule_discovery-1.0.0/.claude/settings.local.json +18 -0
  2. mule_discovery-1.0.0/.github/workflows/tests.yml +27 -0
  3. mule_discovery-1.0.0/.gitignore +35 -0
  4. mule_discovery-1.0.0/Makefile +52 -0
  5. mule_discovery-1.0.0/PKG-INFO +236 -0
  6. mule_discovery-1.0.0/README.md +217 -0
  7. mule_discovery-1.0.0/pyproject.toml +53 -0
  8. mule_discovery-1.0.0/src/mule_discovery/__init__.py +288 -0
  9. mule_discovery-1.0.0/src/mule_discovery/analysis/__init__.py +1 -0
  10. mule_discovery-1.0.0/src/mule_discovery/analysis/classification.py +67 -0
  11. mule_discovery-1.0.0/src/mule_discovery/analysis/complexity.py +98 -0
  12. mule_discovery-1.0.0/src/mule_discovery/analysis/dependencies.py +291 -0
  13. mule_discovery-1.0.0/src/mule_discovery/analysis/patterns.py +27 -0
  14. mule_discovery-1.0.0/src/mule_discovery/analysis/scoring.py +202 -0
  15. mule_discovery-1.0.0/src/mule_discovery/anypoint/__init__.py +1 -0
  16. mule_discovery-1.0.0/src/mule_discovery/anypoint/exchange.py +21 -0
  17. mule_discovery-1.0.0/src/mule_discovery/anypoint/policies.py +14 -0
  18. mule_discovery-1.0.0/src/mule_discovery/cli/__init__.py +1 -0
  19. mule_discovery-1.0.0/src/mule_discovery/cli/discover.py +101 -0
  20. mule_discovery-1.0.0/src/mule_discovery/cli/download_policies.py +46 -0
  21. mule_discovery-1.0.0/src/mule_discovery/cli/scan_policies.py +51 -0
  22. mule_discovery-1.0.0/src/mule_discovery/constants.py +183 -0
  23. mule_discovery-1.0.0/src/mule_discovery/models/__init__.py +64 -0
  24. mule_discovery-1.0.0/src/mule_discovery/models/connectors.py +22 -0
  25. mule_discovery-1.0.0/src/mule_discovery/models/dataweave.py +21 -0
  26. mule_discovery-1.0.0/src/mule_discovery/models/dependencies.py +33 -0
  27. mule_discovery-1.0.0/src/mule_discovery/models/flows.py +216 -0
  28. mule_discovery-1.0.0/src/mule_discovery/models/listeners.py +28 -0
  29. mule_discovery-1.0.0/src/mule_discovery/models/result.py +53 -0
  30. mule_discovery-1.0.0/src/mule_discovery/models/schemas.py +12 -0
  31. mule_discovery-1.0.0/src/mule_discovery/models/scoring.py +40 -0
  32. mule_discovery-1.0.0/src/mule_discovery/output/__init__.py +1 -0
  33. mule_discovery-1.0.0/src/mule_discovery/output/json_output.py +12 -0
  34. mule_discovery-1.0.0/src/mule_discovery/output/text_output.py +35 -0
  35. mule_discovery-1.0.0/src/mule_discovery/output/yaml_output.py +26 -0
  36. mule_discovery-1.0.0/src/mule_discovery/parsers/__init__.py +1 -0
  37. mule_discovery-1.0.0/src/mule_discovery/parsers/aws.py +124 -0
  38. mule_discovery-1.0.0/src/mule_discovery/parsers/dataweave.py +107 -0
  39. mule_discovery-1.0.0/src/mule_discovery/parsers/file_discovery.py +165 -0
  40. mule_discovery-1.0.0/src/mule_discovery/parsers/http_auth.py +158 -0
  41. mule_discovery-1.0.0/src/mule_discovery/parsers/mule_xml.py +810 -0
  42. mule_discovery-1.0.0/src/mule_discovery/parsers/openapi.py +93 -0
  43. mule_discovery-1.0.0/src/mule_discovery/parsers/pom.py +185 -0
  44. mule_discovery-1.0.0/src/mule_discovery/parsers/soap.py +126 -0
  45. mule_discovery-1.0.0/src/mule_discovery/parsers/wsdl.py +58 -0
  46. mule_discovery-1.0.0/src/mule_discovery/xml_helpers.py +213 -0
  47. mule_discovery-1.0.0/tests/__init__.py +0 -0
  48. mule_discovery-1.0.0/tests/conftest.py +106 -0
  49. mule_discovery-1.0.0/tests/fixtures/batch_app/pom.xml +6 -0
  50. mule_discovery-1.0.0/tests/fixtures/batch_app/src/main/mule/batch-job.xml +27 -0
  51. mule_discovery-1.0.0/tests/fixtures/complex_app/pom.xml +31 -0
  52. mule_discovery-1.0.0/tests/fixtures/complex_app/src/main/mule/api.xml +48 -0
  53. mule_discovery-1.0.0/tests/fixtures/complex_app/src/main/mule/globals.xml +10 -0
  54. mule_discovery-1.0.0/tests/fixtures/complex_app/src/main/resources/dwl/complex.dwl +11 -0
  55. mule_discovery-1.0.0/tests/fixtures/complex_app/src/main/resources/dwl/simple.dwl +7 -0
  56. mule_discovery-1.0.0/tests/fixtures/complex_app/src/main/resources/dwl/trivial.dwl +4 -0
  57. mule_discovery-1.0.0/tests/fixtures/event_driven_app/pom.xml +13 -0
  58. mule_discovery-1.0.0/tests/fixtures/event_driven_app/src/main/mule/event-flows.xml +15 -0
  59. mule_discovery-1.0.0/tests/fixtures/mule3_app/pom.xml +9 -0
  60. mule_discovery-1.0.0/tests/fixtures/mule3_app/src/main/app/mule-config.xml +9 -0
  61. mule_discovery-1.0.0/tests/fixtures/simple_api_app/pom.xml +22 -0
  62. mule_discovery-1.0.0/tests/fixtures/simple_api_app/src/main/mule/api.xml +38 -0
  63. mule_discovery-1.0.0/tests/fixtures/simple_api_app/src/main/mule/globals.xml +15 -0
  64. mule_discovery-1.0.0/tests/fixtures/soap_app/pom.xml +13 -0
  65. mule_discovery-1.0.0/tests/fixtures/soap_app/src/main/mule/soap-flows.xml +16 -0
  66. mule_discovery-1.0.0/tests/fixtures/soap_app/src/main/resources/wsdl/service.wsdl +26 -0
  67. mule_discovery-1.0.0/tests/test_analysis/__init__.py +0 -0
  68. mule_discovery-1.0.0/tests/test_analysis/test_classification.py +75 -0
  69. mule_discovery-1.0.0/tests/test_analysis/test_complexity.py +145 -0
  70. mule_discovery-1.0.0/tests/test_analysis/test_dependencies.py +398 -0
  71. mule_discovery-1.0.0/tests/test_analysis/test_patterns.py +39 -0
  72. mule_discovery-1.0.0/tests/test_analysis/test_scoring.py +410 -0
  73. mule_discovery-1.0.0/tests/test_anypoint/__init__.py +0 -0
  74. mule_discovery-1.0.0/tests/test_anypoint/test_exchange.py +21 -0
  75. mule_discovery-1.0.0/tests/test_anypoint/test_policies.py +20 -0
  76. mule_discovery-1.0.0/tests/test_cli/__init__.py +0 -0
  77. mule_discovery-1.0.0/tests/test_cli/test_discover_cli.py +148 -0
  78. mule_discovery-1.0.0/tests/test_cli/test_download_policies_cli.py +76 -0
  79. mule_discovery-1.0.0/tests/test_cli/test_scan_policies_cli.py +113 -0
  80. mule_discovery-1.0.0/tests/test_constants.py +52 -0
  81. mule_discovery-1.0.0/tests/test_discover_mule_app.py +274 -0
  82. mule_discovery-1.0.0/tests/test_models/__init__.py +0 -0
  83. mule_discovery-1.0.0/tests/test_models/test_connectors.py +28 -0
  84. mule_discovery-1.0.0/tests/test_models/test_dataweave.py +23 -0
  85. mule_discovery-1.0.0/tests/test_models/test_dependencies.py +28 -0
  86. mule_discovery-1.0.0/tests/test_models/test_flows.py +146 -0
  87. mule_discovery-1.0.0/tests/test_models/test_listeners.py +23 -0
  88. mule_discovery-1.0.0/tests/test_models/test_result.py +20 -0
  89. mule_discovery-1.0.0/tests/test_models/test_schemas.py +15 -0
  90. mule_discovery-1.0.0/tests/test_models/test_scoring.py +37 -0
  91. mule_discovery-1.0.0/tests/test_output/__init__.py +0 -0
  92. mule_discovery-1.0.0/tests/test_output/test_json_output.py +18 -0
  93. mule_discovery-1.0.0/tests/test_output/test_text_output.py +22 -0
  94. mule_discovery-1.0.0/tests/test_output/test_yaml_output.py +19 -0
  95. mule_discovery-1.0.0/tests/test_parsers/__init__.py +0 -0
  96. mule_discovery-1.0.0/tests/test_parsers/test_aws.py +328 -0
  97. mule_discovery-1.0.0/tests/test_parsers/test_dataweave.py +170 -0
  98. mule_discovery-1.0.0/tests/test_parsers/test_file_discovery.py +231 -0
  99. mule_discovery-1.0.0/tests/test_parsers/test_http_auth.py +291 -0
  100. mule_discovery-1.0.0/tests/test_parsers/test_mule_xml.py +986 -0
  101. mule_discovery-1.0.0/tests/test_parsers/test_openapi.py +103 -0
  102. mule_discovery-1.0.0/tests/test_parsers/test_pom.py +234 -0
  103. mule_discovery-1.0.0/tests/test_parsers/test_soap.py +356 -0
  104. mule_discovery-1.0.0/tests/test_parsers/test_wsdl.py +90 -0
  105. mule_discovery-1.0.0/tests/test_xml_helpers.py +356 -0
  106. mule_discovery-1.0.0/uv.lock +523 -0
@@ -0,0 +1,18 @@
1
+ {
2
+ "permissions": {
3
+ "allow": [
4
+ "Bash(python -m pytest --cov=mule_discovery --cov-report=term-missing --no-header -q)",
5
+ "Bash(/Users/stephen.brown/projects/sandbox-workspaces/mule-discovery-tools/mule-discovery/.venv/bin/python3 -m pytest --cov=mule_discovery --cov-report=term-missing --no-header -q)",
6
+ "Bash(.venv/bin/python -m pytest --co -q)",
7
+ "Bash(.venv/bin/python -m pytest --cov=mule_discovery --cov-report=term-missing --no-header -q 2>&1)",
8
+ "Bash(.venv/bin/python -m pytest --cov=mule_discovery --cov-report=term-missing:skip-covered --no-header -q)",
9
+ "Bash(find /Users/stephen.brown/projects/sandbox-workspaces/single-app-usecase/sys-sap-plants-maintenance-api -name *.wsdl -o -name *.raml -o -name *.swagger*)",
10
+ "Bash(find /Users/stephen.brown/projects/sandbox-workspaces/single-app-usecase/dfi-el-agama -name *.wsdl -o -name *.raml -o -name *.swagger*)",
11
+ "Bash(find /Users/stephen.brown/projects/sandbox-workspaces/single-app-usecase/dfi-el-agama/src/main/resources -type f -name *.dwl)",
12
+ "WebFetch(domain:github.com)",
13
+ "Bash(gh api:*)",
14
+ "Bash(make test:*)",
15
+ "Bash(uv sync:*)"
16
+ ]
17
+ }
18
+ }
@@ -0,0 +1,27 @@
1
+ name: Tests
2
+
3
+ on:
4
+ pull_request:
5
+ branches: [main]
6
+
7
+ jobs:
8
+ test:
9
+ runs-on: ubuntu-latest
10
+ strategy:
11
+ matrix:
12
+ python-version: ["3.10", "3.11", "3.12", "3.13"]
13
+
14
+ steps:
15
+ - uses: actions/checkout@v4
16
+
17
+ - name: Install uv
18
+ uses: astral-sh/setup-uv@v5
19
+
20
+ - name: Set up Python ${{ matrix.python-version }}
21
+ run: uv python install ${{ matrix.python-version }}
22
+
23
+ - name: Install dependencies
24
+ run: uv sync --extra dev
25
+
26
+ - name: Run tests
27
+ run: uv run --extra dev python -m pytest
@@ -0,0 +1,35 @@
1
+ # Python bytecode
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+
6
+ # Distribution / packaging
7
+ dist/
8
+ build/
9
+ *.egg-info/
10
+ *.egg
11
+
12
+ # Virtual environments
13
+ .venv/
14
+ venv/
15
+
16
+ # Testing / coverage
17
+ .pytest_cache/
18
+ .coverage
19
+ htmlcov/
20
+ coverage.xml
21
+
22
+ # IDEs
23
+ .idea/
24
+ .vscode/
25
+ *.swp
26
+ *.swo
27
+ *~
28
+
29
+ # OS files
30
+ .DS_Store
31
+ Thumbs.db
32
+
33
+ # Environment variables
34
+ .env
35
+ .env.*
@@ -0,0 +1,52 @@
1
+ .PHONY: test test-verbose test-cov test-quick install clean build publish publish-test
2
+
3
+ ## Install/sync dependencies
4
+ install:
5
+ uv sync --extra dev
6
+
7
+ ## Run full test suite with coverage
8
+ test:
9
+ uv run --extra dev python -m pytest
10
+
11
+ ## Run tests with verbose output
12
+ test-verbose:
13
+ uv run --extra dev python -m pytest -v
14
+
15
+ ## Run tests without coverage (faster)
16
+ test-quick:
17
+ uv run --extra dev python -m pytest --no-cov
18
+
19
+ ## Run tests and show detailed coverage report
20
+ test-cov:
21
+ uv run --extra dev python -m pytest --cov-report=html
22
+ @echo "HTML report: htmlcov/index.html"
23
+
24
+ ## Run a specific test file (usage: make test-file F=tests/test_parsers/test_pom.py)
25
+ test-file:
26
+ uv run --extra dev python -m pytest $(F) -v --no-cov
27
+
28
+ ## Run tests matching a keyword (usage: make test-k K=scoring)
29
+ test-k:
30
+ uv run --extra dev python -m pytest -k "$(K)" -v --no-cov
31
+
32
+ ## Build distribution packages
33
+ build: clean
34
+ uv build
35
+
36
+ ## Publish to PyPI
37
+ publish: build
38
+ UV_PUBLISH_USERNAME=__token__ \
39
+ UV_PUBLISH_PASSWORD=$$(python3 -c "import configparser; c = configparser.ConfigParser(); c.read('$$HOME/.pypirc'); print(c['pypi']['password'])") \
40
+ uv publish
41
+
42
+ ## Publish to TestPyPI
43
+ publish-test: build
44
+ UV_PUBLISH_USERNAME=__token__ \
45
+ UV_PUBLISH_PASSWORD=$$(python3 -c "import configparser; c = configparser.ConfigParser(); c.read('$$HOME/.pypirc'); print(c['testpypi']['password'])") \
46
+ uv publish --publish-url https://test.pypi.org/legacy/
47
+
48
+ ## Remove build artifacts and caches
49
+ clean:
50
+ rm -rf dist build htmlcov .coverage .pytest_cache
51
+ find . -type d -name __pycache__ -exec rm -rf {} + 2>/dev/null || true
52
+ find . -type d -name "*.egg-info" -exec rm -rf {} + 2>/dev/null || true
@@ -0,0 +1,236 @@
1
+ Metadata-Version: 2.4
2
+ Name: mule-discovery
3
+ Version: 1.0.0
4
+ Summary: Scan Mule applications for migration complexity assessment
5
+ Project-URL: Homepage, https://github.com/KongHQ-CX/mule-discovery
6
+ Author: Stephen Brown
7
+ License-Expression: MIT
8
+ Classifier: License :: OSI Approved :: MIT License
9
+ Classifier: Operating System :: OS Independent
10
+ Classifier: Programming Language :: Python :: 3
11
+ Requires-Python: >=3.10
12
+ Requires-Dist: pyyaml>=6.0
13
+ Provides-Extra: anypoint
14
+ Requires-Dist: anypoint-sdk>=0.2.0; extra == 'anypoint'
15
+ Provides-Extra: dev
16
+ Requires-Dist: pytest-cov>=4.0; extra == 'dev'
17
+ Requires-Dist: pytest>=7.0; extra == 'dev'
18
+ Description-Content-Type: text/markdown
19
+
20
+ # mule-discovery
21
+
22
+ Scan Mule applications for migration complexity assessment.
23
+
24
+ Parses Mule 4 (and 3) XML source files, POM dependencies, DataWeave scripts, and API specifications to produce a structured migration readiness report with complexity scoring.
25
+
26
+ ## Estate Analysis
27
+
28
+ The output produced by `mule-discover` (JSON or YAML) can be fed into the [estate-analyzer](https://github.com/KongHQ-CX/kong-ps-agent-skills/tree/main/mule-analysis/estate-analyzer) agent skill to generate pre-sales migration reports. The estate-analyzer processes discovery output across your entire Mule application estate to produce complexity summaries, connector frequency analysis, PoC candidate recommendations, and migration sizing reports.
29
+
30
+ ## Quick Start (uv)
31
+
32
+ No install required — just run from the project directory:
33
+
34
+ ```bash
35
+ cd mule-discovery
36
+
37
+ # Discover all Mule apps under a directory
38
+ uv run mule-discover /path/to/apps --output-dir ./inventory
39
+
40
+ # JSON output instead of YAML
41
+ uv run mule-discover /path/to/apps --json --output-dir ./inventory
42
+ ```
43
+
44
+ `uv run` reads `pyproject.toml`, resolves dependencies into an ephemeral environment, and runs the command. Nothing is installed globally.
45
+
46
+ ## Installation
47
+
48
+ Install dependencies with uv:
49
+
50
+ ```bash
51
+ uv sync
52
+ ```
53
+
54
+ For development (adds pytest + coverage):
55
+
56
+ ```bash
57
+ uv sync --extra dev
58
+ ```
59
+
60
+ For Anypoint Platform integration (policy scanning):
61
+
62
+ ```bash
63
+ uv sync --extra anypoint
64
+ ```
65
+
66
+ Requires Python 3.10+.
67
+
68
+ ## CLI Tools
69
+
70
+ ### `mule-discover`
71
+
72
+ Recursively find all Mule applications under a directory and produce migration complexity reports for each.
73
+
74
+ ```bash
75
+ # Discover all apps, write YAML inventories (default) to ./inventory
76
+ uv run mule-discover /path/to/apps --output-dir ./inventory
77
+
78
+ # JSON output
79
+ uv run mule-discover /path/to/apps --json --output-dir ./inventory
80
+
81
+ # Suppress progress output
82
+ uv run mule-discover /path/to/apps -o ./inventory -q
83
+
84
+ # Custom complexity thresholds
85
+ uv run mule-discover /path/to/apps --flow-low 8 --flow-medium 18 --flow-high 30
86
+ ```
87
+
88
+ Each per-app report includes:
89
+ - Flow inventory with complexity levels (LOW / MEDIUM / HIGH / VERY_HIGH)
90
+ - DataWeave transformation analysis and classification
91
+ - HTTP listener and scheduled job detection
92
+ - Connector inventory with migration weights
93
+ - API specification detection (OpenAPI, WSDL)
94
+ - External dependency and out-of-scope item tracking
95
+ - AWS service usage (SQS, S3, DynamoDB)
96
+ - SOAP/WSDL service detection
97
+ - Overall migration score (0–100) with recommendation (SIMPLE / MODERATE / COMPLEX / VERY_COMPLEX)
98
+
99
+ ### `mule-scan-policies`
100
+
101
+ Scan Anypoint Platform for API policies on deployed applications. Requires the `anypoint` extra.
102
+
103
+ ```bash
104
+ pip install -e ".[anypoint]"
105
+
106
+ export ANYPOINT_CLIENT_ID=...
107
+ export ANYPOINT_CLIENT_SECRET=...
108
+ export ANYPOINT_ORG_ID=...
109
+ export ANYPOINT_ENV_ID=...
110
+
111
+ uv run mule-scan-policies
112
+ uv run mule-scan-policies --format json
113
+ ```
114
+
115
+ ### `mule-download-policies`
116
+
117
+ Download custom policies from Anypoint Exchange. Requires the `anypoint` extra.
118
+
119
+ ```bash
120
+ export ANYPOINT_CLIENT_ID=...
121
+ export ANYPOINT_CLIENT_SECRET=...
122
+ export ANYPOINT_ORG_ID=...
123
+
124
+ uv run mule-download-policies --output-dir ./custom_policies
125
+ ```
126
+
127
+ ## Complexity Scoring
128
+
129
+ Each application receives a migration score from 0 to 100 (higher = simpler migration):
130
+
131
+ | Score Range | Recommendation | Meaning |
132
+ |---|---|---|
133
+ | 75–100 | SMALL | Straightforward migration |
134
+ | 50–74 | MEDIUM | Some complexity, manageable |
135
+ | 25–49 | LARGE | Significant effort required |
136
+ | 0–24 | XLARGE | Major rework needed |
137
+
138
+ Deductions are applied across eight dimensions:
139
+
140
+ | Dimension | Max Deduction |
141
+ |---|---|
142
+ | Flow complexity | 30 pts |
143
+ | Transform complexity | 15 pts |
144
+ | Risk / out-of-scope items | 20 pts |
145
+ | Connector migration weight | 20 pts |
146
+ | WSDL / SOAP services | 10 pts |
147
+ | Scale (flow + component count) | 20 pts |
148
+ | Pattern complexity (scatter-gather, choices, batch, parallel-foreach, retries) | 15 pts |
149
+ | DataWeave volume | 15 pts |
150
+
151
+ ### Flow Complexity Thresholds
152
+
153
+ Flows are classified by component count (configurable via CLI flags):
154
+
155
+ | Components | Complexity |
156
+ |---|---|
157
+ | ≤ 6 | LOW |
158
+ | 7–14 | MEDIUM |
159
+ | 15–25 | HIGH |
160
+ | > 25 | VERY_HIGH |
161
+
162
+ ### DataWeave Classification
163
+
164
+ DataWeave transformations are classified by line count and function usage:
165
+
166
+ | Classification | Criteria |
167
+ |---|---|
168
+ | simple_mapping | ≤ 5 lines, no complex functions |
169
+ | field_level_logic | 6–20 lines, or uses routine functions (map, filter, pluck, etc.) |
170
+ | business_logic | > 20 lines, or uses complex functions (reduce, groupBy, flatMap, etc.) |
171
+
172
+ ## Package Structure
173
+
174
+ ```
175
+ src/mule_discovery/
176
+ ├── __init__.py # Main discover_mule_app() orchestrator
177
+ ├── constants.py # XML namespaces, element classifications, connector weights
178
+ ├── xml_helpers.py # XML utility functions
179
+ ├── models/ # Data models (dataclasses)
180
+ │ ├── result.py # DiscoveryResult (top-level container)
181
+ │ ├── flows.py # FlowInfo, BatchInfo, ChoiceInfo, ScatterGatherInfo, ...
182
+ │ ├── connectors.py # ConnectorInfo, SpringDependency
183
+ │ ├── dataweave.py # DataWeaveInfo
184
+ │ ├── listeners.py # HttpListenerInfo, ScheduledJobInfo
185
+ │ ├── dependencies.py # ExternalDependencyInfo, SourceFiles, OutOfScopeItem
186
+ │ ├── schemas.py # ApiSpecInfo (OpenAPI, WSDL)
187
+ │ └── scoring.py # ComplexityThresholds, ScoreResult
188
+ ├── parsers/ # File IO → models
189
+ │ ├── file_discovery.py # find_mule_apps(), find_mule_xml_files()
190
+ │ ├── mule_xml.py # Mule XML parsing (flows, listeners, jobs)
191
+ │ ├── pom.py # POM parsing (app name, version, connectors)
192
+ │ ├── http_auth.py # HTTP auth config extraction
193
+ │ ├── dataweave.py # DataWeave script parsing
194
+ │ ├── soap.py # SOAP/WSDL service detection
195
+ │ ├── aws.py # AWS service detection (SQS, S3, DynamoDB)
196
+ │ ├── openapi.py # OpenAPI spec detection
197
+ │ └── wsdl.py # WSDL parsing utilities
198
+ ├── analysis/ # Models → models (pure functions)
199
+ │ ├── classification.py # Flow type and source category constants
200
+ │ ├── complexity.py # Flow and DataWeave complexity assignment
201
+ │ ├── patterns.py # Pattern detection (async, scatter-gather, choice, ...)
202
+ │ ├── scoring.py # Migration score calculation (0–100)
203
+ │ └── dependencies.py # External dependency and out-of-scope extraction
204
+ ├── output/ # Models → formatted strings
205
+ │ ├── yaml_output.py # YAML
206
+ │ ├── json_output.py # JSON
207
+ │ └── text_output.py # Human-readable text summary
208
+ ├── anypoint/ # Anypoint Platform integration (optional)
209
+ │ ├── policies.py # Policy scanning
210
+ │ └── exchange.py # Custom policy download
211
+ └── cli/ # CLI entry points (thin wrappers)
212
+ ├── discover.py # mule-discover
213
+ ├── scan_policies.py # mule-scan-policies
214
+ └── download_policies.py # mule-download-policies
215
+ ```
216
+
217
+ ### Design Principles
218
+
219
+ - **No function does both IO and computation.** Parsers read files → return models. Analysis takes models → returns models. Output takes models → returns strings.
220
+ - **All data models are plain dataclasses** with typed fields — no methods with side effects.
221
+ - **All analysis functions are standalone** — no class methods, no inheritance.
222
+ - **Each output format is a separate module.**
223
+
224
+ ## Testing
225
+
226
+ ```bash
227
+ make test
228
+ ```
229
+
230
+ Or directly:
231
+
232
+ ```bash
233
+ uv run --extra dev python -m pytest
234
+ ```
235
+
236
+ Coverage is enforced at 70% (branch coverage) via `pyproject.toml`.
@@ -0,0 +1,217 @@
1
+ # mule-discovery
2
+
3
+ Scan Mule applications for migration complexity assessment.
4
+
5
+ Parses Mule 4 (and 3) XML source files, POM dependencies, DataWeave scripts, and API specifications to produce a structured migration readiness report with complexity scoring.
6
+
7
+ ## Estate Analysis
8
+
9
+ The output produced by `mule-discover` (JSON or YAML) can be fed into the [estate-analyzer](https://github.com/KongHQ-CX/kong-ps-agent-skills/tree/main/mule-analysis/estate-analyzer) agent skill to generate pre-sales migration reports. The estate-analyzer processes discovery output across your entire Mule application estate to produce complexity summaries, connector frequency analysis, PoC candidate recommendations, and migration sizing reports.
10
+
11
+ ## Quick Start (uv)
12
+
13
+ No install required — just run from the project directory:
14
+
15
+ ```bash
16
+ cd mule-discovery
17
+
18
+ # Discover all Mule apps under a directory
19
+ uv run mule-discover /path/to/apps --output-dir ./inventory
20
+
21
+ # JSON output instead of YAML
22
+ uv run mule-discover /path/to/apps --json --output-dir ./inventory
23
+ ```
24
+
25
+ `uv run` reads `pyproject.toml`, resolves dependencies into an ephemeral environment, and runs the command. Nothing is installed globally.
26
+
27
+ ## Installation
28
+
29
+ Install dependencies with uv:
30
+
31
+ ```bash
32
+ uv sync
33
+ ```
34
+
35
+ For development (adds pytest + coverage):
36
+
37
+ ```bash
38
+ uv sync --extra dev
39
+ ```
40
+
41
+ For Anypoint Platform integration (policy scanning):
42
+
43
+ ```bash
44
+ uv sync --extra anypoint
45
+ ```
46
+
47
+ Requires Python 3.10+.
48
+
49
+ ## CLI Tools
50
+
51
+ ### `mule-discover`
52
+
53
+ Recursively find all Mule applications under a directory and produce migration complexity reports for each.
54
+
55
+ ```bash
56
+ # Discover all apps, write YAML inventories (default) to ./inventory
57
+ uv run mule-discover /path/to/apps --output-dir ./inventory
58
+
59
+ # JSON output
60
+ uv run mule-discover /path/to/apps --json --output-dir ./inventory
61
+
62
+ # Suppress progress output
63
+ uv run mule-discover /path/to/apps -o ./inventory -q
64
+
65
+ # Custom complexity thresholds
66
+ uv run mule-discover /path/to/apps --flow-low 8 --flow-medium 18 --flow-high 30
67
+ ```
68
+
69
+ Each per-app report includes:
70
+ - Flow inventory with complexity levels (LOW / MEDIUM / HIGH / VERY_HIGH)
71
+ - DataWeave transformation analysis and classification
72
+ - HTTP listener and scheduled job detection
73
+ - Connector inventory with migration weights
74
+ - API specification detection (OpenAPI, WSDL)
75
+ - External dependency and out-of-scope item tracking
76
+ - AWS service usage (SQS, S3, DynamoDB)
77
+ - SOAP/WSDL service detection
78
+ - Overall migration score (0–100) with recommendation (SIMPLE / MODERATE / COMPLEX / VERY_COMPLEX)
79
+
80
+ ### `mule-scan-policies`
81
+
82
+ Scan Anypoint Platform for API policies on deployed applications. Requires the `anypoint` extra.
83
+
84
+ ```bash
85
+ pip install -e ".[anypoint]"
86
+
87
+ export ANYPOINT_CLIENT_ID=...
88
+ export ANYPOINT_CLIENT_SECRET=...
89
+ export ANYPOINT_ORG_ID=...
90
+ export ANYPOINT_ENV_ID=...
91
+
92
+ uv run mule-scan-policies
93
+ uv run mule-scan-policies --format json
94
+ ```
95
+
96
+ ### `mule-download-policies`
97
+
98
+ Download custom policies from Anypoint Exchange. Requires the `anypoint` extra.
99
+
100
+ ```bash
101
+ export ANYPOINT_CLIENT_ID=...
102
+ export ANYPOINT_CLIENT_SECRET=...
103
+ export ANYPOINT_ORG_ID=...
104
+
105
+ uv run mule-download-policies --output-dir ./custom_policies
106
+ ```
107
+
108
+ ## Complexity Scoring
109
+
110
+ Each application receives a migration score from 0 to 100 (higher = simpler migration):
111
+
112
+ | Score Range | Recommendation | Meaning |
113
+ |---|---|---|
114
+ | 75–100 | SMALL | Straightforward migration |
115
+ | 50–74 | MEDIUM | Some complexity, manageable |
116
+ | 25–49 | LARGE | Significant effort required |
117
+ | 0–24 | XLARGE | Major rework needed |
118
+
119
+ Deductions are applied across eight dimensions:
120
+
121
+ | Dimension | Max Deduction |
122
+ |---|---|
123
+ | Flow complexity | 30 pts |
124
+ | Transform complexity | 15 pts |
125
+ | Risk / out-of-scope items | 20 pts |
126
+ | Connector migration weight | 20 pts |
127
+ | WSDL / SOAP services | 10 pts |
128
+ | Scale (flow + component count) | 20 pts |
129
+ | Pattern complexity (scatter-gather, choices, batch, parallel-foreach, retries) | 15 pts |
130
+ | DataWeave volume | 15 pts |
131
+
132
+ ### Flow Complexity Thresholds
133
+
134
+ Flows are classified by component count (configurable via CLI flags):
135
+
136
+ | Components | Complexity |
137
+ |---|---|
138
+ | ≤ 6 | LOW |
139
+ | 7–14 | MEDIUM |
140
+ | 15–25 | HIGH |
141
+ | > 25 | VERY_HIGH |
142
+
143
+ ### DataWeave Classification
144
+
145
+ DataWeave transformations are classified by line count and function usage:
146
+
147
+ | Classification | Criteria |
148
+ |---|---|
149
+ | simple_mapping | ≤ 5 lines, no complex functions |
150
+ | field_level_logic | 6–20 lines, or uses routine functions (map, filter, pluck, etc.) |
151
+ | business_logic | > 20 lines, or uses complex functions (reduce, groupBy, flatMap, etc.) |
152
+
153
+ ## Package Structure
154
+
155
+ ```
156
+ src/mule_discovery/
157
+ ├── __init__.py # Main discover_mule_app() orchestrator
158
+ ├── constants.py # XML namespaces, element classifications, connector weights
159
+ ├── xml_helpers.py # XML utility functions
160
+ ├── models/ # Data models (dataclasses)
161
+ │ ├── result.py # DiscoveryResult (top-level container)
162
+ │ ├── flows.py # FlowInfo, BatchInfo, ChoiceInfo, ScatterGatherInfo, ...
163
+ │ ├── connectors.py # ConnectorInfo, SpringDependency
164
+ │ ├── dataweave.py # DataWeaveInfo
165
+ │ ├── listeners.py # HttpListenerInfo, ScheduledJobInfo
166
+ │ ├── dependencies.py # ExternalDependencyInfo, SourceFiles, OutOfScopeItem
167
+ │ ├── schemas.py # ApiSpecInfo (OpenAPI, WSDL)
168
+ │ └── scoring.py # ComplexityThresholds, ScoreResult
169
+ ├── parsers/ # File IO → models
170
+ │ ├── file_discovery.py # find_mule_apps(), find_mule_xml_files()
171
+ │ ├── mule_xml.py # Mule XML parsing (flows, listeners, jobs)
172
+ │ ├── pom.py # POM parsing (app name, version, connectors)
173
+ │ ├── http_auth.py # HTTP auth config extraction
174
+ │ ├── dataweave.py # DataWeave script parsing
175
+ │ ├── soap.py # SOAP/WSDL service detection
176
+ │ ├── aws.py # AWS service detection (SQS, S3, DynamoDB)
177
+ │ ├── openapi.py # OpenAPI spec detection
178
+ │ └── wsdl.py # WSDL parsing utilities
179
+ ├── analysis/ # Models → models (pure functions)
180
+ │ ├── classification.py # Flow type and source category constants
181
+ │ ├── complexity.py # Flow and DataWeave complexity assignment
182
+ │ ├── patterns.py # Pattern detection (async, scatter-gather, choice, ...)
183
+ │ ├── scoring.py # Migration score calculation (0–100)
184
+ │ └── dependencies.py # External dependency and out-of-scope extraction
185
+ ├── output/ # Models → formatted strings
186
+ │ ├── yaml_output.py # YAML
187
+ │ ├── json_output.py # JSON
188
+ │ └── text_output.py # Human-readable text summary
189
+ ├── anypoint/ # Anypoint Platform integration (optional)
190
+ │ ├── policies.py # Policy scanning
191
+ │ └── exchange.py # Custom policy download
192
+ └── cli/ # CLI entry points (thin wrappers)
193
+ ├── discover.py # mule-discover
194
+ ├── scan_policies.py # mule-scan-policies
195
+ └── download_policies.py # mule-download-policies
196
+ ```
197
+
198
+ ### Design Principles
199
+
200
+ - **No function does both IO and computation.** Parsers read files → return models. Analysis takes models → returns models. Output takes models → returns strings.
201
+ - **All data models are plain dataclasses** with typed fields — no methods with side effects.
202
+ - **All analysis functions are standalone** — no class methods, no inheritance.
203
+ - **Each output format is a separate module.**
204
+
205
+ ## Testing
206
+
207
+ ```bash
208
+ make test
209
+ ```
210
+
211
+ Or directly:
212
+
213
+ ```bash
214
+ uv run --extra dev python -m pytest
215
+ ```
216
+
217
+ Coverage is enforced at 70% (branch coverage) via `pyproject.toml`.
@@ -0,0 +1,53 @@
1
+ [project]
2
+ name = "mule-discovery"
3
+ version = "1.0.0"
4
+ description = "Scan Mule applications for migration complexity assessment"
5
+ readme = "README.md"
6
+ license = "MIT"
7
+ requires-python = ">=3.10"
8
+ authors = [{ name = "Stephen Brown" }]
9
+ classifiers = [
10
+ "Programming Language :: Python :: 3",
11
+ "License :: OSI Approved :: MIT License",
12
+ "Operating System :: OS Independent",
13
+ ]
14
+ dependencies = [
15
+ "pyyaml>=6.0",
16
+ ]
17
+
18
+ [project.urls]
19
+ Homepage = "https://github.com/KongHQ-CX/mule-discovery"
20
+
21
+ [project.optional-dependencies]
22
+ anypoint = [
23
+ "anypoint-sdk>=0.2.0",
24
+ ]
25
+ dev = [
26
+ "pytest>=7.0",
27
+ "pytest-cov>=4.0",
28
+ ]
29
+
30
+ [project.scripts]
31
+ mule-discover = "mule_discovery.cli.discover:main"
32
+ mule-scan-policies = "mule_discovery.cli.scan_policies:main"
33
+ mule-download-policies = "mule_discovery.cli.download_policies:main"
34
+
35
+ [build-system]
36
+ requires = ["hatchling"]
37
+ build-backend = "hatchling.build"
38
+
39
+ [tool.pytest.ini_options]
40
+ testpaths = ["tests"]
41
+ addopts = "--cov=mule_discovery --cov-report=term-missing --cov-fail-under=70"
42
+
43
+ [tool.coverage.run]
44
+ source = ["mule_discovery"]
45
+ branch = true
46
+
47
+ [tool.coverage.report]
48
+ fail_under = 70
49
+ show_missing = true
50
+ exclude_lines = [
51
+ "if __name__ == .__main__.",
52
+ "pragma: no cover",
53
+ ]