readystack-jdk25-upgrade-blocker-lint 1.0.3__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.
- readystack_jdk25_upgrade_blocker_lint-1.0.3/LICENSE.txt +16 -0
- readystack_jdk25_upgrade_blocker_lint-1.0.3/PKG-INFO +79 -0
- readystack_jdk25_upgrade_blocker_lint-1.0.3/README.md +60 -0
- readystack_jdk25_upgrade_blocker_lint-1.0.3/pyproject.toml +28 -0
- readystack_jdk25_upgrade_blocker_lint-1.0.3/setup.cfg +4 -0
- readystack_jdk25_upgrade_blocker_lint-1.0.3/src/readystack_jdk25_upgrade_blocker_lint/__init__.py +1 -0
- readystack_jdk25_upgrade_blocker_lint-1.0.3/src/readystack_jdk25_upgrade_blocker_lint/cli.py +135 -0
- readystack_jdk25_upgrade_blocker_lint-1.0.3/src/readystack_jdk25_upgrade_blocker_lint/engine.py +30 -0
- readystack_jdk25_upgrade_blocker_lint-1.0.3/src/readystack_jdk25_upgrade_blocker_lint/license.py +61 -0
- readystack_jdk25_upgrade_blocker_lint-1.0.3/src/readystack_jdk25_upgrade_blocker_lint/rules.json +110 -0
- readystack_jdk25_upgrade_blocker_lint-1.0.3/src/readystack_jdk25_upgrade_blocker_lint/strings.json +10 -0
- readystack_jdk25_upgrade_blocker_lint-1.0.3/src/readystack_jdk25_upgrade_blocker_lint.egg-info/PKG-INFO +79 -0
- readystack_jdk25_upgrade_blocker_lint-1.0.3/src/readystack_jdk25_upgrade_blocker_lint.egg-info/SOURCES.txt +14 -0
- readystack_jdk25_upgrade_blocker_lint-1.0.3/src/readystack_jdk25_upgrade_blocker_lint.egg-info/dependency_links.txt +1 -0
- readystack_jdk25_upgrade_blocker_lint-1.0.3/src/readystack_jdk25_upgrade_blocker_lint.egg-info/entry_points.txt +2 -0
- readystack_jdk25_upgrade_blocker_lint-1.0.3/src/readystack_jdk25_upgrade_blocker_lint.egg-info/top_level.txt +1 -0
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
JDK 25 Upgrade Blocker Lint — Licence
|
|
2
|
+
|
|
3
|
+
Free scope
|
|
4
|
+
Scans every .java file you open or the whole workspace and names each JDK 21/25 blocker on its line with the JEP that removed it and the replacement call. is free for any use, personal or commercial, for as long as you keep the
|
|
5
|
+
extension installed, and the online check at the product page is free without registration.
|
|
6
|
+
|
|
7
|
+
Paid scope
|
|
8
|
+
Exports the whole repository as one dated migration report — every file, blocker, JEP and replacement in Markdown and CSV — to hand to the team or attach to the upgrade ticket, and covers commercial and team-seat use. is the paid part. It asks for a licence key issued at purchase (one seat, one key;
|
|
9
|
+
7-day full refund, no questions). The key is checked against the payment provider and
|
|
10
|
+
cached locally for 30 days so it keeps working offline.
|
|
11
|
+
|
|
12
|
+
Redistribution
|
|
13
|
+
You may not resell, re-host or bundle this extension or its rule set. The rule set and the
|
|
14
|
+
engine are provided as-is; check results are advisory and do not constitute legal advice.
|
|
15
|
+
|
|
16
|
+
(c) ReadyStack — https://getreadystack.com
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: readystack-jdk25-upgrade-blocker-lint
|
|
3
|
+
Version: 1.0.3
|
|
4
|
+
Summary: Finds the Java lines the new LTS removed — 18 rules; 23 findings in one 64-line fixture
|
|
5
|
+
Author-email: ReadyStack <support@getreadystack.com>
|
|
6
|
+
License: Proprietary - see LICENSE.txt
|
|
7
|
+
Project-URL: Homepage, https://getreadystack.com/tools/jdk25-upgrade-blocker-lint?ref=pypi
|
|
8
|
+
Project-URL: Documentation, https://getreadystack.com/tools/jdk25-upgrade-blocker-lint?ref=pypi
|
|
9
|
+
Project-URL: Support, https://getreadystack.com/support
|
|
10
|
+
Keywords: java,jdk,migration,jakarta,linter,upgrade
|
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
|
12
|
+
Classifier: Environment :: Console
|
|
13
|
+
Classifier: Topic :: Software Development :: Quality Assurance
|
|
14
|
+
Classifier: Operating System :: OS Independent
|
|
15
|
+
Requires-Python: >=3.9
|
|
16
|
+
Description-Content-Type: text/markdown
|
|
17
|
+
License-File: LICENSE.txt
|
|
18
|
+
Dynamic: license-file
|
|
19
|
+
|
|
20
|
+
# JDK 25 Upgrade Blocker Lint
|
|
21
|
+
|
|
22
|
+
Finds the Java lines the new LTS removed — 18 rules; 23 findings in one 64-line fixture
|
|
23
|
+
|
|
24
|
+
## Install
|
|
25
|
+
|
|
26
|
+
```
|
|
27
|
+
jdk25-upgrade-blocker-lint file
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Node 18+. The same 18 rules as the VS Code extension, from a terminal or CI.
|
|
31
|
+
|
|
32
|
+
## Free
|
|
33
|
+
|
|
34
|
+
- Lints the .java file you have open with all 18 rules, no key and no cap — the bundled 64-line fixture returns 23 findings, 15 errors and 8 warnings; the fixed copy returns 0.
|
|
35
|
+
- `--rules` lists every rule
|
|
36
|
+
|
|
37
|
+
## With a licence ($29 once)
|
|
38
|
+
|
|
39
|
+
- Sweeps the whole workspace and writes the dated migration report file — every file, blocker, JEP and replacement — for the upgrade ticket; free for the first 7 days, then one key, commercial and CI-seat use included.
|
|
40
|
+
|
|
41
|
+
```
|
|
42
|
+
@readystack/jdk25-upgrade-blocker-lint --dir ./templates --report html --out report.html
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
A Java migration consultant bills $120-$200 an hour; a two-day audit of one repo is over $2,000.
|
|
46
|
+
|
|
47
|
+
## Use from an AI agent (MCP)
|
|
48
|
+
|
|
49
|
+
Claude Code · Cursor · Windsurf · any MCP client - add to your MCP config:
|
|
50
|
+
|
|
51
|
+
```json
|
|
52
|
+
{ "mcpServers": { "jdk25-upgrade-blocker-lint": { "command": "npx", "args": ["-y", "@readystack/jdk25-upgrade-blocker-lint", "--mcp"] } } }
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
Tools: `check_text` and `check_file` (free) · `check_dir` (licence; the full sweep is free for 7 days). The agent gets every finding with the line number.
|
|
56
|
+
|
|
57
|
+
## Use in CI
|
|
58
|
+
|
|
59
|
+
```yaml
|
|
60
|
+
- name: JDK 25 Upgrade Blocker Lint
|
|
61
|
+
run: npx -y @readystack/jdk25-upgrade-blocker-lint --dir . --ci
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
(container: `docker run --rm -v "$PWD:/work" getreadystack/jdk25-upgrade-blocker-lint --dir /work --ci`)
|
|
65
|
+
|
|
66
|
+
Try the full run free for 7 days — no key needed. Then one licence, 7-day refund, no questions. Set `READYSTACK_LICENSE=<key>` or run `--license <key>` once.
|
|
67
|
+
|
|
68
|
+
[Get a licence](https://buy.polar.sh/polar_cl_YK2CXL7Hd4TEoxQ76oOVQpVAsrLK9zUpcK7oV2MKwJs)
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
<!-- jdk25 upgrade blocker lint -->
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
## Install (PyPI)
|
|
75
|
+
|
|
76
|
+
```
|
|
77
|
+
pip install readystack-jdk25-upgrade-blocker-lint
|
|
78
|
+
jdk25-upgrade-blocker-lint --help
|
|
79
|
+
```
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# JDK 25 Upgrade Blocker Lint
|
|
2
|
+
|
|
3
|
+
Finds the Java lines the new LTS removed — 18 rules; 23 findings in one 64-line fixture
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
jdk25-upgrade-blocker-lint file
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Node 18+. The same 18 rules as the VS Code extension, from a terminal or CI.
|
|
12
|
+
|
|
13
|
+
## Free
|
|
14
|
+
|
|
15
|
+
- Lints the .java file you have open with all 18 rules, no key and no cap — the bundled 64-line fixture returns 23 findings, 15 errors and 8 warnings; the fixed copy returns 0.
|
|
16
|
+
- `--rules` lists every rule
|
|
17
|
+
|
|
18
|
+
## With a licence ($29 once)
|
|
19
|
+
|
|
20
|
+
- Sweeps the whole workspace and writes the dated migration report file — every file, blocker, JEP and replacement — for the upgrade ticket; free for the first 7 days, then one key, commercial and CI-seat use included.
|
|
21
|
+
|
|
22
|
+
```
|
|
23
|
+
@readystack/jdk25-upgrade-blocker-lint --dir ./templates --report html --out report.html
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
A Java migration consultant bills $120-$200 an hour; a two-day audit of one repo is over $2,000.
|
|
27
|
+
|
|
28
|
+
## Use from an AI agent (MCP)
|
|
29
|
+
|
|
30
|
+
Claude Code · Cursor · Windsurf · any MCP client - add to your MCP config:
|
|
31
|
+
|
|
32
|
+
```json
|
|
33
|
+
{ "mcpServers": { "jdk25-upgrade-blocker-lint": { "command": "npx", "args": ["-y", "@readystack/jdk25-upgrade-blocker-lint", "--mcp"] } } }
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Tools: `check_text` and `check_file` (free) · `check_dir` (licence; the full sweep is free for 7 days). The agent gets every finding with the line number.
|
|
37
|
+
|
|
38
|
+
## Use in CI
|
|
39
|
+
|
|
40
|
+
```yaml
|
|
41
|
+
- name: JDK 25 Upgrade Blocker Lint
|
|
42
|
+
run: npx -y @readystack/jdk25-upgrade-blocker-lint --dir . --ci
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
(container: `docker run --rm -v "$PWD:/work" getreadystack/jdk25-upgrade-blocker-lint --dir /work --ci`)
|
|
46
|
+
|
|
47
|
+
Try the full run free for 7 days — no key needed. Then one licence, 7-day refund, no questions. Set `READYSTACK_LICENSE=<key>` or run `--license <key>` once.
|
|
48
|
+
|
|
49
|
+
[Get a licence](https://buy.polar.sh/polar_cl_YK2CXL7Hd4TEoxQ76oOVQpVAsrLK9zUpcK7oV2MKwJs)
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
<!-- jdk25 upgrade blocker lint -->
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
## Install (PyPI)
|
|
56
|
+
|
|
57
|
+
```
|
|
58
|
+
pip install readystack-jdk25-upgrade-blocker-lint
|
|
59
|
+
jdk25-upgrade-blocker-lint --help
|
|
60
|
+
```
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=68"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "readystack-jdk25-upgrade-blocker-lint"
|
|
7
|
+
version = "1.0.3"
|
|
8
|
+
description = "Finds the Java lines the new LTS removed \u2014 18 rules; 23 findings in one 64-line fixture"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.9"
|
|
11
|
+
license = {text = "Proprietary - see LICENSE.txt"}
|
|
12
|
+
keywords = ["java", "jdk", "migration", "jakarta", "linter", "upgrade"]
|
|
13
|
+
authors = [{name = "ReadyStack", email = "support@getreadystack.com"}]
|
|
14
|
+
classifiers = ["Programming Language :: Python :: 3", "Environment :: Console", "Topic :: Software Development :: Quality Assurance", "Operating System :: OS Independent"]
|
|
15
|
+
|
|
16
|
+
[project.urls]
|
|
17
|
+
Homepage = "https://getreadystack.com/tools/jdk25-upgrade-blocker-lint?ref=pypi"
|
|
18
|
+
Documentation = "https://getreadystack.com/tools/jdk25-upgrade-blocker-lint?ref=pypi"
|
|
19
|
+
Support = "https://getreadystack.com/support"
|
|
20
|
+
|
|
21
|
+
[project.scripts]
|
|
22
|
+
"jdk25-upgrade-blocker-lint" = "readystack_jdk25_upgrade_blocker_lint.cli:main"
|
|
23
|
+
|
|
24
|
+
[tool.setuptools.packages.find]
|
|
25
|
+
where = ["src"]
|
|
26
|
+
|
|
27
|
+
[tool.setuptools.package-data]
|
|
28
|
+
"readystack_jdk25_upgrade_blocker_lint" = ["rules.json", "strings.json"]
|
readystack_jdk25_upgrade_blocker_lint-1.0.3/src/readystack_jdk25_upgrade_blocker_lint/__init__.py
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = '1.0.3'
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
# cli.py — the same rules as the VS Code extension, from a terminal, a container or an MCP client. Generated by pypi_build.py.
|
|
2
|
+
import json, os, sys, time, datetime
|
|
3
|
+
from . import engine as ENGINE, license as lic
|
|
4
|
+
_HERE = os.path.dirname(os.path.abspath(__file__))
|
|
5
|
+
S = json.load(open(os.path.join(_HERE, 'strings.json'), encoding='utf-8'))
|
|
6
|
+
def scan(text, file=''):
|
|
7
|
+
r = ENGINE.check(str(text), {'today': datetime.date.today().isoformat(), 'path': file})
|
|
8
|
+
return [{'line': int(f.get('line') or 1), 'msg': str(f.get('msg') or f.get('check') or ''), 'fix': f.get('fix'), 'sev': 'error' if str(f.get('sev', 'error')).lower().startswith('err') else 'warn'} for f in r.get('findings', [])]
|
|
9
|
+
def is_text(p):
|
|
10
|
+
try:
|
|
11
|
+
with open(p, 'rb') as h: b = h.read(4096)
|
|
12
|
+
return os.path.getsize(p) <= 2 * 1024 * 1024 and b'\x00' not in b
|
|
13
|
+
except Exception: return False
|
|
14
|
+
def walk(d, exts, out):
|
|
15
|
+
try: ents = list(os.scandir(d))
|
|
16
|
+
except Exception: return out
|
|
17
|
+
for e in ents:
|
|
18
|
+
if e.name in ('node_modules', '.git') or e.name.startswith('.'): continue
|
|
19
|
+
if e.is_dir(): walk(e.path, exts, out)
|
|
20
|
+
elif (not exts or os.path.splitext(e.name)[1].lower() in exts) and is_text(e.path): out.append(e.path)
|
|
21
|
+
return out
|
|
22
|
+
def esc(s): return str(s).replace('&', '&').replace('<', '<').replace('>', '>')
|
|
23
|
+
def csvq(s): return '"' + str('' if s is None else s).replace('"', '""') + '"'
|
|
24
|
+
RULE_N = len(ENGINE.RULES)
|
|
25
|
+
def render(rows, fmt):
|
|
26
|
+
if fmt == 'json': return json.dumps({'tool': S['name'], 'rules': RULE_N, 'files': rows}, indent=1)
|
|
27
|
+
if fmt == 'csv':
|
|
28
|
+
o = ['file,line,severity,message,fix']
|
|
29
|
+
for r in rows:
|
|
30
|
+
for h in r['hits']: o.append(','.join([csvq(r['file']), str(h['line']), h['sev'], csvq(h['msg']), csvq(h['fix'])]))
|
|
31
|
+
return '\n'.join(o)
|
|
32
|
+
if fmt == 'html':
|
|
33
|
+
n = sum(len(r['hits']) for r in rows)
|
|
34
|
+
o = '<!doctype html><meta charset="utf-8"><title>' + esc(S['name']) + ' report</title><style>body{font:14px system-ui;margin:24px}table{border-collapse:collapse}td,th{border:1px solid #ddd;padding:4px 8px}</style>'
|
|
35
|
+
o += '<h1>' + esc(S['name']) + '</h1><p>' + str(len(rows)) + ' files · ' + str(n) + ' findings · ' + str(RULE_N) + ' rules</p><table><tr><th>file</th><th>line</th><th>sev</th><th>message</th><th>fix</th></tr>'
|
|
36
|
+
for r in rows:
|
|
37
|
+
for h in r['hits']: o += '<tr><td><code>' + esc(r['file']) + '</code></td><td>' + str(h['line']) + '</td><td>' + esc(h['sev']) + '</td><td>' + esc(h['msg']) + '</td><td>' + esc(h['fix'] or '') + '</td></tr>'
|
|
38
|
+
return o + '</table>'
|
|
39
|
+
o = ''
|
|
40
|
+
for r in rows:
|
|
41
|
+
o += r['file'] + '\n'
|
|
42
|
+
for h in r['hits']: o += ' ' + str(h['line']).rjust(5) + ' ' + h['sev'].ljust(5) + ' ' + h['msg'] + ('\n -> ' + h['fix'] if h['fix'] else '') + '\n'
|
|
43
|
+
return o
|
|
44
|
+
def trial_state():
|
|
45
|
+
if os.environ.get('READYSTACK_NO_TRIAL'): return {'active': False}
|
|
46
|
+
try:
|
|
47
|
+
p = os.path.join(os.path.dirname(lic.store_path()), S['bin'] + '.trial.json'); t = None
|
|
48
|
+
try: t = json.load(open(p, encoding='utf-8'))
|
|
49
|
+
except Exception: pass
|
|
50
|
+
if not t or not t.get('until'):
|
|
51
|
+
t = {'until': (datetime.date.today() + datetime.timedelta(days=7)).isoformat()}; os.makedirs(os.path.dirname(p), exist_ok=True); json.dump(t, open(p, 'w', encoding='utf-8'))
|
|
52
|
+
return {'active': datetime.date.fromisoformat(t['until']) >= datetime.date.today(), 'until': t['until']}
|
|
53
|
+
except Exception: return {'active': False}
|
|
54
|
+
def mcp_serve():
|
|
55
|
+
os.environ['READYSTACK_MCP'] = '1'
|
|
56
|
+
def send(o): sys.stdout.write(json.dumps(o) + '\n'); sys.stdout.flush()
|
|
57
|
+
tools = [
|
|
58
|
+
{'name': 'check_text', 'description': S['name'] + ' - run all ' + str(RULE_N) + ' checks on a text (free)', 'inputSchema': {'type': 'object', 'properties': {'text': {'type': 'string', 'description': 'file contents'}, 'path': {'type': 'string'}}, 'required': ['text']}},
|
|
59
|
+
{'name': 'check_file', 'description': S['name'] + ' - run all checks on one file by path (free)', 'inputSchema': {'type': 'object', 'properties': {'path': {'type': 'string'}}, 'required': ['path']}},
|
|
60
|
+
{'name': 'check_dir', 'description': S['name'] + ' - sweep a folder and return every finding (licence; the full run is free for 7 days)', 'inputSchema': {'type': 'object', 'properties': {'dir': {'type': 'string'}, 'ext': {'type': 'string'}}, 'required': ['dir']}},
|
|
61
|
+
]
|
|
62
|
+
def result(i, rows): send({'jsonrpc': '2.0', 'id': i, 'result': {'content': [{'type': 'text', 'text': render(rows, 'text')}], 'structuredContent': {'tool': S['name'], 'rules': RULE_N, 'files': rows}}})
|
|
63
|
+
def fail(i, text): send({'jsonrpc': '2.0', 'id': i, 'result': {'content': [{'type': 'text', 'text': text}], 'isError': True}})
|
|
64
|
+
for line in sys.stdin:
|
|
65
|
+
try: m = json.loads(line)
|
|
66
|
+
except Exception: continue
|
|
67
|
+
i, method = m.get('id'), m.get('method')
|
|
68
|
+
if method == 'initialize': send({'jsonrpc': '2.0', 'id': i, 'result': {'protocolVersion': '2025-06-18', 'capabilities': {'tools': {}}, 'serverInfo': {'name': 'readystack-' + S['bin'], 'version': '1.0.3'}}}); continue
|
|
69
|
+
if method in ('notifications/initialized', 'ping'):
|
|
70
|
+
if i is not None: send({'jsonrpc': '2.0', 'id': i, 'result': {}})
|
|
71
|
+
continue
|
|
72
|
+
if method == 'tools/list': send({'jsonrpc': '2.0', 'id': i, 'result': {'tools': tools}}); continue
|
|
73
|
+
if method == 'tools/call':
|
|
74
|
+
name = (m.get('params') or {}).get('name'); args = (m.get('params') or {}).get('arguments') or {}
|
|
75
|
+
try:
|
|
76
|
+
if name == 'check_text': result(i, [{'file': args.get('path') or '(text)', 'hits': scan(str(args.get('text') or ''), args.get('path') or '')}]); continue
|
|
77
|
+
if name == 'check_file': result(i, [{'file': args['path'], 'hits': scan(open(args['path'], encoding='utf-8', errors='replace').read(), args['path'])}]); continue
|
|
78
|
+
if name == 'check_dir':
|
|
79
|
+
r = lic.ensure()
|
|
80
|
+
if not r['ok'] and not trial_state()['active']: fail(i, S['need_key'] + ' Get a licence ($' + str(S['price']) + ', once, 7-day refund): ' + lic.BUY_URL); continue
|
|
81
|
+
files = walk(args['dir'], [args['ext']] if args.get('ext') else (S.get('exts') or []), [])
|
|
82
|
+
rows = []
|
|
83
|
+
for f in files:
|
|
84
|
+
try: rows.append({'file': f, 'hits': scan(open(f, encoding='utf-8', errors='replace').read(), f)})
|
|
85
|
+
except Exception as e: rows.append({'file': f, 'hits': [], 'error': str(e)})
|
|
86
|
+
result(i, rows); continue
|
|
87
|
+
send({'jsonrpc': '2.0', 'id': i, 'error': {'code': -32601, 'message': 'unknown tool ' + str(name)}})
|
|
88
|
+
except Exception as e: fail(i, str(e))
|
|
89
|
+
continue
|
|
90
|
+
if i is not None: send({'jsonrpc': '2.0', 'id': i, 'error': {'code': -32601, 'message': 'method not found: ' + str(method)}})
|
|
91
|
+
def help_text():
|
|
92
|
+
b = S['bin']
|
|
93
|
+
return '\n'.join([S['name'] + ' - ' + S['subtitle'], '', 'Usage: ' + b + ' <file> [more files] check the files you name (free, every rule)',
|
|
94
|
+
' ' + b + ' --dir <folder> [--ext .py] scan a whole folder (licence)',
|
|
95
|
+
' ' + b + ' ... --report csv|json|html [--out file] export a report (licence)',
|
|
96
|
+
' ' + b + ' ... --ci exit 1 when an error-level finding exists (licence)',
|
|
97
|
+
' ' + b + ' --license <key> store your licence key (or set READYSTACK_LICENSE)',
|
|
98
|
+
' ' + b + ' --rules list the ' + str(RULE_N) + ' rules',
|
|
99
|
+
' ' + b + ' --mcp run as an MCP server (stdio) for Claude Code / Cursor / Windsurf - free checks, folder sweep needs a licence', '',
|
|
100
|
+
'Free: ' + S['free'], 'Licence ($' + str(S['price']) + ', once, 7-day refund): ' + S['paid'], 'Get a licence: ' + lic.BUY_URL, ''])
|
|
101
|
+
def main(argv=None):
|
|
102
|
+
a = list(sys.argv[1:] if argv is None else argv)
|
|
103
|
+
try:
|
|
104
|
+
feed = lic.pull_feed()
|
|
105
|
+
if feed and isinstance(feed.get('rules'), list): ENGINE.RULES.extend(feed['rules'])
|
|
106
|
+
except Exception: pass
|
|
107
|
+
def get(k):
|
|
108
|
+
return a[a.index(k) + 1] if k in a and a.index(k) + 1 < len(a) else None
|
|
109
|
+
if '--mcp' in a: mcp_serve(); return 0
|
|
110
|
+
if not a or '--help' in a or '-h' in a: sys.stdout.write(help_text()); return 0
|
|
111
|
+
if '--rules' in a:
|
|
112
|
+
sys.stdout.write('\n'.join(str(i + 1).rjust(3) + ' [' + str(r.get('sev', 'warn')) + '] ' + str(r.get('msg') or r.get('id') or '') for i, r in enumerate(ENGINE.RULES)) + '\n'); return 0
|
|
113
|
+
if '--license' in a:
|
|
114
|
+
r = lic.ensure(get('--license')); sys.stdout.write(('Licence stored: ' + lic.store_path() if r['ok'] else 'Licence not accepted (' + str(r.get('why')) + ')') + '\n'); return 0 if r['ok'] else 1
|
|
115
|
+
d, fmt, out, ci = get('--dir'), get('--report'), get('--out'), '--ci' in a
|
|
116
|
+
exts = [get('--ext')] if '--ext' in a else (S.get('exts') or [])
|
|
117
|
+
if d or fmt or ci:
|
|
118
|
+
r = lic.ensure()
|
|
119
|
+
if not r['ok']:
|
|
120
|
+
t = trial_state()
|
|
121
|
+
if t['active']: sys.stderr.write('Trial: the full run is free until ' + t['until'] + ' - after that $' + str(S['price']) + ' once (7-day refund). Get a licence: ' + lic.BUY_URL + '\n')
|
|
122
|
+
else: sys.stderr.write(S['need_key'] + '\n set READYSTACK_LICENSE=<key> or ' + S['bin'] + ' --license <key>\n Get a licence ($' + str(S['price']) + ', once): ' + lic.BUY_URL + '\n'); return 2
|
|
123
|
+
flags = {'--dir', '--report', '--out', '--ext', '--license'}
|
|
124
|
+
files = walk(d, exts, []) if d else [x for i, x in enumerate(a) if not x.startswith('--') and (i == 0 or a[i - 1] not in flags)]
|
|
125
|
+
if not files: sys.stderr.write('No files. ' + S['bin'] + ' --help\n'); return 2
|
|
126
|
+
rows = []
|
|
127
|
+
for f in files:
|
|
128
|
+
try: rows.append({'file': f, 'hits': scan(open(f, encoding='utf-8', errors='replace').read(), f)})
|
|
129
|
+
except Exception as e: rows.append({'file': f, 'hits': [], 'error': str(e)})
|
|
130
|
+
text = render(rows, fmt or 'text')
|
|
131
|
+
if out: open(out, 'w', encoding='utf-8').write(text)
|
|
132
|
+
else: sys.stdout.write(text if text.endswith('\n') else text + '\n')
|
|
133
|
+
errors = sum(1 for r in rows for h in r['hits'] if h['sev'] == 'error')
|
|
134
|
+
return 1 if (ci and errors) else 0
|
|
135
|
+
if __name__ == '__main__': sys.exit(main())
|
readystack_jdk25_upgrade_blocker_lint-1.0.3/src/readystack_jdk25_upgrade_blocker_lint/engine.py
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# engine.py — same rules as the VS Code extension and the npm CLI (rules.json), pure Python. Generated by pypi_build.py.
|
|
2
|
+
import json, os, re
|
|
3
|
+
_HERE = os.path.dirname(os.path.abspath(__file__))
|
|
4
|
+
RULES = json.load(open(os.path.join(_HERE, 'rules.json'), encoding='utf-8'))
|
|
5
|
+
def _py(p): return re.sub(r'\(\?<(?![=!])', '(?P<', p)
|
|
6
|
+
def _c(r):
|
|
7
|
+
if '_re' not in r:
|
|
8
|
+
r['_re'] = re.compile(_py(r['re'])); r['_ctx'] = re.compile(_py(r['ctx']), re.M) if r.get('ctx') else None
|
|
9
|
+
r['_prev'] = re.compile(_py(r['prev_not'])) if r.get('prev_not') else None; r['_next'] = re.compile(_py(r['next_re'])) if r.get('next_re') else None
|
|
10
|
+
return r
|
|
11
|
+
def _code(s): t = s.strip(); return t != '' and not t.startswith('#')
|
|
12
|
+
def check(text, opts=None):
|
|
13
|
+
opts = opts or {}; src = '' if text is None else str(text); lines = src.split('\n'); lines = [l.rstrip('\r') for l in lines]; out = []
|
|
14
|
+
for r in RULES:
|
|
15
|
+
r = _c(r)
|
|
16
|
+
if r['_ctx'] and not r['_ctx'].search(src): continue
|
|
17
|
+
for n, line in enumerate(lines):
|
|
18
|
+
if not _code(line) or not r['_re'].search(line): continue
|
|
19
|
+
if r['_prev']:
|
|
20
|
+
p = n - 1
|
|
21
|
+
while p >= 0 and lines[p].strip() == '': p -= 1
|
|
22
|
+
if p >= 0 and r['_prev'].search(lines[p]): continue
|
|
23
|
+
if r['_next']:
|
|
24
|
+
q = n + 1
|
|
25
|
+
while q < len(lines) and lines[q].strip() == '': q += 1
|
|
26
|
+
if q >= len(lines) or not r['_next'].search(lines[q]): continue
|
|
27
|
+
out.append({'check': r['id'], 'sev': r.get('sev', 'warn'), 'line': n + 1, 'msg': r.get('msg', ''), 'fix': r.get('fix'), 'text': line.strip()[:160]})
|
|
28
|
+
out.sort(key=lambda f: f['line'])
|
|
29
|
+
return {'findings': out, 'scanned_lines': len(lines), 'rule_count': len(RULES),
|
|
30
|
+
'errors': sum(1 for f in out if f['sev'] == 'error'), 'warnings': sum(1 for f in out if f['sev'] == 'warn'), 'today': opts.get('today', '')}
|
readystack_jdk25_upgrade_blocker_lint-1.0.3/src/readystack_jdk25_upgrade_blocker_lint/license.py
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# license.py — Polar licence check (same contract as license.js). Generated by pypi_build.py.
|
|
2
|
+
import json, os, sys, time, urllib.request
|
|
3
|
+
ORG_ID = 'a5cdf664-d8e7-4f87-8895-056717aaba17'; BENEFIT_ID = 'ecc7be06-5c7b-418a-abf2-9204bdc20568'; BUY_URL = 'https://buy.polar.sh/polar_cl_YK2CXL7Hd4TEoxQ76oOVQpVAsrLK9zUpcK7oV2MKwJs'; ALL_BENEFIT_ID = '22692551-5203-4467-b1a3-e33cdba6589d'; SLUG = 'jdk25-upgrade-blocker-lint'
|
|
4
|
+
GRACE = 30 * 86400; RECHECK = 7 * 86400
|
|
5
|
+
def store_path():
|
|
6
|
+
return os.path.join(os.environ.get('READYSTACK_HOME') or os.path.join(os.path.expanduser('~'), '.config', 'readystack'), SLUG + '.json')
|
|
7
|
+
def load():
|
|
8
|
+
try: return json.load(open(store_path(), encoding='utf-8'))
|
|
9
|
+
except Exception: return {}
|
|
10
|
+
def save(o):
|
|
11
|
+
try:
|
|
12
|
+
os.makedirs(os.path.dirname(store_path()), exist_ok=True); json.dump(o, open(store_path(), 'w', encoding='utf-8'))
|
|
13
|
+
except Exception: pass
|
|
14
|
+
def _post(url, body, headers, timeout):
|
|
15
|
+
req = urllib.request.Request(url, data=json.dumps(body).encode(), headers=dict({'content-type': 'application/json'}, **headers), method='POST')
|
|
16
|
+
return urllib.request.urlopen(req, timeout=timeout)
|
|
17
|
+
def _validate1(key, ben):
|
|
18
|
+
if not ORG_ID: return {'ok': False, 'offline': False}
|
|
19
|
+
body = {'key': key, 'organization_id': ORG_ID}
|
|
20
|
+
if len(ben) == 36: body['benefit_id'] = ben
|
|
21
|
+
try:
|
|
22
|
+
r = _post('https://api.polar.sh/v1/customer-portal/license-keys/validate', body, {'polar-version': '2026-04', 'user-agent': 'readystack-py/' + SLUG}, 8)
|
|
23
|
+
if r.status != 200: return {'ok': False, 'offline': False}
|
|
24
|
+
j = json.loads(r.read().decode() or '{}'); return {'ok': bool(j and (j.get('status') == 'granted' or j.get('valid') is True or j.get('id'))), 'offline': False}
|
|
25
|
+
except urllib.error.HTTPError: return {'ok': False, 'offline': False}
|
|
26
|
+
except Exception: return {'ok': False, 'offline': True}
|
|
27
|
+
def validate(key):
|
|
28
|
+
r = _validate1(key, BENEFIT_ID)
|
|
29
|
+
if r['ok'] or r['offline'] or len(ALL_BENEFIT_ID) != 36: return r
|
|
30
|
+
return _validate1(key, ALL_BENEFIT_ID)
|
|
31
|
+
_pinged = [False]
|
|
32
|
+
def ping_paywall(why):
|
|
33
|
+
try:
|
|
34
|
+
if _pinged[0]: return
|
|
35
|
+
_pinged[0] = True
|
|
36
|
+
if os.environ.get('DO_NOT_TRACK') == '1' or os.environ.get('READYSTACK_NO_TELEMETRY') or os.environ.get('CI'): return
|
|
37
|
+
if not (sys.stdout.isatty() or sys.stdin.isatty() or os.environ.get('READYSTACK_MCP') == '1'): return
|
|
38
|
+
_post('https://getreadystack.com/api/ev', {'t': 'paywall', 'slug': SLUG, 'src': 'mcp' if os.environ.get('READYSTACK_MCP') == '1' else 'cli', 'why': why or 'no_key'}, {'user-agent': 'readystack-py/' + SLUG}, 3).read()
|
|
39
|
+
except Exception: pass
|
|
40
|
+
def ensure(explicit=None):
|
|
41
|
+
st = load(); key = explicit or os.environ.get('READYSTACK_LICENSE') or st.get('key')
|
|
42
|
+
if not key: ping_paywall('no_key'); return {'ok': False, 'why': 'no_key'}
|
|
43
|
+
age = time.time() - (st.get('okAt') or 0)
|
|
44
|
+
if not explicit and st.get('key') == key and age < RECHECK: return {'ok': True, 'cached': True}
|
|
45
|
+
r = validate(str(key).strip())
|
|
46
|
+
if r['ok']: save({'key': str(key).strip(), 'okAt': time.time()}); return {'ok': True}
|
|
47
|
+
if r['offline'] and st.get('key') == key and age < GRACE: return {'ok': True, 'offline': True}
|
|
48
|
+
if not r['offline']: ping_paywall('invalid')
|
|
49
|
+
return {'ok': False, 'why': 'offline' if r['offline'] else 'invalid'}
|
|
50
|
+
def pull_feed():
|
|
51
|
+
st = load(); key = os.environ.get('READYSTACK_LICENSE') or st.get('key'); cached = st.get('feed')
|
|
52
|
+
if not key: return cached
|
|
53
|
+
if cached and time.time() - (st.get('feedAt') or 0) < RECHECK: return cached
|
|
54
|
+
try:
|
|
55
|
+
import urllib.parse
|
|
56
|
+
r = urllib.request.urlopen(urllib.request.Request('https://getreadystack.com/api/rules/' + urllib.parse.quote(SLUG) + '?key=' + urllib.parse.quote(key), headers={'user-agent': 'readystack-py'}), timeout=8)
|
|
57
|
+
if r.status != 200: return cached
|
|
58
|
+
j = json.loads(r.read().decode() or '{}')
|
|
59
|
+
if not isinstance(j, dict) or not isinstance(j.get('rules'), list): return cached
|
|
60
|
+
s2 = load(); s2['feed'] = j; s2['feedAt'] = time.time(); save(s2); return j
|
|
61
|
+
except Exception: return cached
|
readystack_jdk25_upgrade_blocker_lint-1.0.3/src/readystack_jdk25_upgrade_blocker_lint/rules.json
ADDED
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
[
|
|
2
|
+
{
|
|
3
|
+
"id": "security_manager_set",
|
|
4
|
+
"re": "System\\s*\\.\\s*setSecurityManager\\s*\\(",
|
|
5
|
+
"sev": "error",
|
|
6
|
+
"msg": "System.setSecurityManager() throws UnsupportedOperationException on JDK 24 and later — JEP 486 permanently disabled the Security Manager. Delete the call and move the check into your own authorization layer."
|
|
7
|
+
},
|
|
8
|
+
{
|
|
9
|
+
"id": "access_controller",
|
|
10
|
+
"re": "AccessController\\s*\\.\\s*doPrivileged|import\\s+java\\.security\\.AccessController",
|
|
11
|
+
"sev": "error",
|
|
12
|
+
"msg": "AccessController.doPrivileged is terminally deprecated and grants nothing (JEP 486, JDK 24). The privileged block now runs with the caller's own access. Inline the body and drop the wrapper."
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
"id": "security_policy",
|
|
16
|
+
"re": "java\\.security\\.Policy|Policy\\s*\\.\\s*setPolicy\\s*\\(|SecurityManager\\s+[A-Za-z_]",
|
|
17
|
+
"sev": "error",
|
|
18
|
+
"msg": "java.security.Policy and SecurityManager are terminally deprecated with JEP 486 (JDK 24). Your .policy file grants nothing at run time — the permissions in it are no longer enforced."
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
"id": "unsafe_memory",
|
|
22
|
+
"re": "sun\\.misc\\.Unsafe|Unsafe\\s*\\.\\s*getUnsafe\\s*\\(",
|
|
23
|
+
"sev": "error",
|
|
24
|
+
"msg": "sun.misc.Unsafe memory-access methods are deprecated for removal (JEP 471, JDK 23) and warn at run time by default since JDK 24 (JEP 498). Replace with java.lang.invoke.VarHandle, or the FFM API in java.lang.foreign for off-heap memory."
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
"id": "javax_to_jakarta",
|
|
28
|
+
"re": "import\\s+javax\\.(persistence|servlet|ws\\.rs|enterprise|inject|validation|transaction|ejb|jms|mail|annotation\\.(Resource|PostConstruct|PreDestroy))",
|
|
29
|
+
"sev": "error",
|
|
30
|
+
"msg": "Jakarta EE 9 renamed this package to jakarta.*. A Jakarta EE 10/11 runtime (Spring Boot 3, Quarkus 3, Payara 6, WildFly 27+) never scans javax.* here, so the bean or endpoint silently disappears. Rename the import to jakarta.*"
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
"id": "jaxb_removed",
|
|
34
|
+
"re": "javax\\.xml\\.bind|com\\.sun\\.xml\\.bind",
|
|
35
|
+
"sev": "error",
|
|
36
|
+
"msg": "javax.xml.bind (JAXB) was removed from the JDK in Java 11 (JEP 320). On JDK 21/25 this compiles only if you add the jakarta.xml.bind-api and a runtime yourself — and the package is jakarta.xml.bind now."
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
"id": "applet_api",
|
|
40
|
+
"re": "java\\.applet|\\bextends\\s+(J?Applet)\\b",
|
|
41
|
+
"sev": "error",
|
|
42
|
+
"msg": "The Applet API was removed outright in JDK 25 (JEP 504). There is no replacement class — this file cannot compile on the new LTS."
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
"id": "thread_stop",
|
|
46
|
+
"re": "(?:[Tt]hread[A-Za-z0-9_]*|[a-z][A-Za-z0-9_]*Thread)\\s*\\.\\s*(?:stop|suspend|resume)\\s*\\(\\s*\\)",
|
|
47
|
+
"sev": "error",
|
|
48
|
+
"msg": "Thread.stop() throws UnsupportedOperationException since JDK 20, and suspend()/resume() are terminally deprecated and throw on current JDKs. Use interrupt() plus a volatile flag the worker loop reads."
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
"id": "finalize_override",
|
|
52
|
+
"re": "(?:protected|public)\\s+void\\s+finalize\\s*\\(\\s*\\)",
|
|
53
|
+
"sev": "error",
|
|
54
|
+
"msg": "Overriding finalize() is deprecated for removal (JEP 421) and finalization is already disabled by default in some runs via --finalization=disabled — your cleanup may never execute. Move it to try-with-resources or java.lang.ref.Cleaner."
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
"id": "jdk_internal_import",
|
|
58
|
+
"re": "import\\s+(?:sun\\.(?!misc\\.Unsafe)|com\\.sun\\.(?!xml\\.bind)|jdk\\.internal\\.)",
|
|
59
|
+
"sev": "error",
|
|
60
|
+
"msg": "JDK-internal packages are strongly encapsulated since JDK 17 (JEP 403). This import throws IllegalAccessError at run time unless every launch carries a matching --add-exports flag."
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
"id": "run_finalization",
|
|
64
|
+
"re": "(?:System|Runtime\\s*\\.\\s*getRuntime\\s*\\(\\s*\\))\\s*\\.\\s*runFinalization\\s*\\(",
|
|
65
|
+
"sev": "error",
|
|
66
|
+
"msg": "System.runFinalization() and Runtime.runFinalization() are deprecated for removal (JEP 421). They are no-ops once finalization is disabled — the resource you expect to be released is not released."
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
"id": "subject_do_as",
|
|
70
|
+
"re": "Subject\\s*\\.\\s*doAs(?:Privileged)?\\s*\\(",
|
|
71
|
+
"sev": "warn",
|
|
72
|
+
"msg": "Subject.doAs is deprecated for removal together with the Security Manager. Use Subject.callAs, added in JDK 18, which takes a Callable and keeps the Subject on the current thread."
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
"id": "native_access",
|
|
76
|
+
"re": "System\\s*\\.\\s*(?:loadLibrary|load)\\s*\\(|\\bnative\\s+(?:[A-Za-z_$][\\w$<>\\[\\]\\.]*)\\s+[A-Za-z_$]",
|
|
77
|
+
"sev": "warn",
|
|
78
|
+
"msg": "Loading native code prints a warning on JDK 24+ unless the module is named in --enable-native-access (JEP 472), and that warning is planned to become an error. Add the flag or an Enable-Native-Access manifest entry now."
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
"id": "set_accessible",
|
|
82
|
+
"re": "setAccessible\\s*\\(\\s*true\\s*\\)",
|
|
83
|
+
"sev": "warn",
|
|
84
|
+
"msg": "setAccessible(true) against a java.* class throws InaccessibleObjectException under the strong encapsulation of JDK 17+ (JEP 403). Check the target is your own class, or add an explicit --add-opens for the exact package."
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
"id": "url_constructor",
|
|
88
|
+
"re": "new\\s+URL\\s*\\(",
|
|
89
|
+
"sev": "warn",
|
|
90
|
+
"msg": "The java.net.URL constructors are deprecated since JDK 20 because they accept malformed input without validating it. Use URI.create(s).toURL(), which rejects the bad string instead of carrying it."
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
"id": "wrapper_constructor",
|
|
94
|
+
"re": "new\\s+(?:Integer|Long|Double|Float|Short|Byte|Character|Boolean)\\s*\\(",
|
|
95
|
+
"sev": "warn",
|
|
96
|
+
"msg": "Primitive wrapper constructors are deprecated for removal since JDK 9. Use Integer.valueOf(x) or Integer.parseInt(s) — valueOf caches small values, the constructor allocates every time."
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
"id": "class_new_instance",
|
|
100
|
+
"re": "(?:\\.class|getClass\\(\\s*\\)|Class\\.forName\\([^)]*\\))\\s*\\.\\s*newInstance\\s*\\(\\s*\\)",
|
|
101
|
+
"sev": "warn",
|
|
102
|
+
"msg": "Class.newInstance() is deprecated since JDK 9 because it rethrows checked exceptions the compiler cannot see. Use getDeclaredConstructor().newInstance()."
|
|
103
|
+
},
|
|
104
|
+
{
|
|
105
|
+
"id": "locale_constructor",
|
|
106
|
+
"re": "new\\s+Locale\\s*\\(",
|
|
107
|
+
"sev": "warn",
|
|
108
|
+
"msg": "The java.util.Locale constructors are deprecated since JDK 19. Use Locale.of(language, country), which validates and interns the tag."
|
|
109
|
+
}
|
|
110
|
+
]
|
readystack_jdk25_upgrade_blocker_lint-1.0.3/src/readystack_jdk25_upgrade_blocker_lint/strings.json
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "JDK 25 Upgrade Blocker Lint",
|
|
3
|
+
"subtitle": "Finds the Java lines the new LTS removed — 18 rules; 23 findings in one 64-line fixture",
|
|
4
|
+
"bin": "jdk25-upgrade-blocker-lint",
|
|
5
|
+
"price": 29,
|
|
6
|
+
"free": "Lints the .java file you have open with all 18 rules, no key and no cap — the bundled 64-line fixture returns 23 findings, 15 errors and 8 warnings; the fixed copy returns 0.",
|
|
7
|
+
"paid": "Sweeps the whole workspace and writes the dated migration report file — every file, blocker, JEP and replacement — for the upgrade ticket; free for the first 7 days, then one key, commercial and CI-seat use included.",
|
|
8
|
+
"need_key": "This option needs a licence (JDK 25 Upgrade Blocker Lint).",
|
|
9
|
+
"exts": []
|
|
10
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: readystack-jdk25-upgrade-blocker-lint
|
|
3
|
+
Version: 1.0.3
|
|
4
|
+
Summary: Finds the Java lines the new LTS removed — 18 rules; 23 findings in one 64-line fixture
|
|
5
|
+
Author-email: ReadyStack <support@getreadystack.com>
|
|
6
|
+
License: Proprietary - see LICENSE.txt
|
|
7
|
+
Project-URL: Homepage, https://getreadystack.com/tools/jdk25-upgrade-blocker-lint?ref=pypi
|
|
8
|
+
Project-URL: Documentation, https://getreadystack.com/tools/jdk25-upgrade-blocker-lint?ref=pypi
|
|
9
|
+
Project-URL: Support, https://getreadystack.com/support
|
|
10
|
+
Keywords: java,jdk,migration,jakarta,linter,upgrade
|
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
|
12
|
+
Classifier: Environment :: Console
|
|
13
|
+
Classifier: Topic :: Software Development :: Quality Assurance
|
|
14
|
+
Classifier: Operating System :: OS Independent
|
|
15
|
+
Requires-Python: >=3.9
|
|
16
|
+
Description-Content-Type: text/markdown
|
|
17
|
+
License-File: LICENSE.txt
|
|
18
|
+
Dynamic: license-file
|
|
19
|
+
|
|
20
|
+
# JDK 25 Upgrade Blocker Lint
|
|
21
|
+
|
|
22
|
+
Finds the Java lines the new LTS removed — 18 rules; 23 findings in one 64-line fixture
|
|
23
|
+
|
|
24
|
+
## Install
|
|
25
|
+
|
|
26
|
+
```
|
|
27
|
+
jdk25-upgrade-blocker-lint file
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Node 18+. The same 18 rules as the VS Code extension, from a terminal or CI.
|
|
31
|
+
|
|
32
|
+
## Free
|
|
33
|
+
|
|
34
|
+
- Lints the .java file you have open with all 18 rules, no key and no cap — the bundled 64-line fixture returns 23 findings, 15 errors and 8 warnings; the fixed copy returns 0.
|
|
35
|
+
- `--rules` lists every rule
|
|
36
|
+
|
|
37
|
+
## With a licence ($29 once)
|
|
38
|
+
|
|
39
|
+
- Sweeps the whole workspace and writes the dated migration report file — every file, blocker, JEP and replacement — for the upgrade ticket; free for the first 7 days, then one key, commercial and CI-seat use included.
|
|
40
|
+
|
|
41
|
+
```
|
|
42
|
+
@readystack/jdk25-upgrade-blocker-lint --dir ./templates --report html --out report.html
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
A Java migration consultant bills $120-$200 an hour; a two-day audit of one repo is over $2,000.
|
|
46
|
+
|
|
47
|
+
## Use from an AI agent (MCP)
|
|
48
|
+
|
|
49
|
+
Claude Code · Cursor · Windsurf · any MCP client - add to your MCP config:
|
|
50
|
+
|
|
51
|
+
```json
|
|
52
|
+
{ "mcpServers": { "jdk25-upgrade-blocker-lint": { "command": "npx", "args": ["-y", "@readystack/jdk25-upgrade-blocker-lint", "--mcp"] } } }
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
Tools: `check_text` and `check_file` (free) · `check_dir` (licence; the full sweep is free for 7 days). The agent gets every finding with the line number.
|
|
56
|
+
|
|
57
|
+
## Use in CI
|
|
58
|
+
|
|
59
|
+
```yaml
|
|
60
|
+
- name: JDK 25 Upgrade Blocker Lint
|
|
61
|
+
run: npx -y @readystack/jdk25-upgrade-blocker-lint --dir . --ci
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
(container: `docker run --rm -v "$PWD:/work" getreadystack/jdk25-upgrade-blocker-lint --dir /work --ci`)
|
|
65
|
+
|
|
66
|
+
Try the full run free for 7 days — no key needed. Then one licence, 7-day refund, no questions. Set `READYSTACK_LICENSE=<key>` or run `--license <key>` once.
|
|
67
|
+
|
|
68
|
+
[Get a licence](https://buy.polar.sh/polar_cl_YK2CXL7Hd4TEoxQ76oOVQpVAsrLK9zUpcK7oV2MKwJs)
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
<!-- jdk25 upgrade blocker lint -->
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
## Install (PyPI)
|
|
75
|
+
|
|
76
|
+
```
|
|
77
|
+
pip install readystack-jdk25-upgrade-blocker-lint
|
|
78
|
+
jdk25-upgrade-blocker-lint --help
|
|
79
|
+
```
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
LICENSE.txt
|
|
2
|
+
README.md
|
|
3
|
+
pyproject.toml
|
|
4
|
+
src/readystack_jdk25_upgrade_blocker_lint/__init__.py
|
|
5
|
+
src/readystack_jdk25_upgrade_blocker_lint/cli.py
|
|
6
|
+
src/readystack_jdk25_upgrade_blocker_lint/engine.py
|
|
7
|
+
src/readystack_jdk25_upgrade_blocker_lint/license.py
|
|
8
|
+
src/readystack_jdk25_upgrade_blocker_lint/rules.json
|
|
9
|
+
src/readystack_jdk25_upgrade_blocker_lint/strings.json
|
|
10
|
+
src/readystack_jdk25_upgrade_blocker_lint.egg-info/PKG-INFO
|
|
11
|
+
src/readystack_jdk25_upgrade_blocker_lint.egg-info/SOURCES.txt
|
|
12
|
+
src/readystack_jdk25_upgrade_blocker_lint.egg-info/dependency_links.txt
|
|
13
|
+
src/readystack_jdk25_upgrade_blocker_lint.egg-info/entry_points.txt
|
|
14
|
+
src/readystack_jdk25_upgrade_blocker_lint.egg-info/top_level.txt
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
readystack_jdk25_upgrade_blocker_lint
|