abapgit-agent 1.11.0 → 1.11.2
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.
- package/.abapGitAgent.example +1 -0
- package/abap/.github/copilot-instructions.md +9 -9
- package/abap/CLAUDE.md +48 -539
- package/abap/guidelines/{08_abapgit.md → abapgit.md} +1 -1
- package/abap/guidelines/branch-workflow.md +137 -0
- package/abap/guidelines/cds-testing.md +25 -0
- package/abap/guidelines/{04_cds.md → cds.md} +4 -4
- package/abap/guidelines/{10_common_errors.md → common-errors.md} +3 -3
- package/abap/guidelines/debug-dump.md +33 -0
- package/abap/guidelines/debug-session.md +280 -0
- package/abap/guidelines/index.md +50 -0
- package/abap/guidelines/object-creation.md +51 -0
- package/abap/guidelines/{06_objects.md → objects.md} +2 -2
- package/abap/guidelines/{01_sql.md → sql.md} +2 -2
- package/abap/guidelines/{03_testing.md → testing.md} +3 -3
- package/abap/guidelines/workflow-detailed.md +255 -0
- package/package.json +1 -1
- package/src/commands/debug.js +54 -20
- package/src/commands/inspect.js +5 -3
- package/src/commands/pull.js +4 -1
- package/src/commands/transport.js +3 -1
- package/src/commands/unit.js +10 -10
- package/src/commands/view.js +238 -1
- package/src/config.js +4 -2
- package/src/utils/abap-http.js +11 -6
- package/src/utils/abap-reference.js +4 -4
- package/src/utils/adt-http.js +13 -8
- package/src/utils/format-error.js +89 -0
- package/src/utils/version-check.js +4 -3
- package/abap/guidelines/00_index.md +0 -44
- /package/abap/guidelines/{05_classes.md → classes.md} +0 -0
- /package/abap/guidelines/{02_exceptions.md → exceptions.md} +0 -0
- /package/abap/guidelines/{07_json.md → json.md} +0 -0
- /package/abap/guidelines/{09_unit_testable_code.md → unit-testable-code.md} +0 -0
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
---
|
|
2
|
+
layout: default
|
|
3
|
+
title: Development Workflow (Detailed)
|
|
4
|
+
nav_order: 15
|
|
5
|
+
parent: ABAP Coding Guidelines
|
|
6
|
+
grand_parent: ABAP Development
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Development Workflow (Detailed)
|
|
10
|
+
|
|
11
|
+
```
|
|
12
|
+
1. Read .abapGitAgent → get folder value AND workflow.mode
|
|
13
|
+
│
|
|
14
|
+
▼
|
|
15
|
+
2. Research → use ref command for unfamiliar topics
|
|
16
|
+
│
|
|
17
|
+
▼
|
|
18
|
+
3. Write code → place in correct folder (e.g., src/zcl_*.clas.abap)
|
|
19
|
+
│
|
|
20
|
+
▼
|
|
21
|
+
4. Syntax check (for CLAS, INTF, PROG, DDLS only)
|
|
22
|
+
│
|
|
23
|
+
├─► CLAS/INTF/PROG/DDLS → abapgit-agent syntax --files <file>
|
|
24
|
+
│ │
|
|
25
|
+
│ ├─► Errors? → Fix locally (no commit needed), re-run syntax
|
|
26
|
+
│ │
|
|
27
|
+
│ └─► Clean ✅ → Proceed to commit
|
|
28
|
+
│
|
|
29
|
+
└─► Other types (FUGR, TABL, etc.) → Skip syntax, go to commit
|
|
30
|
+
│
|
|
31
|
+
▼
|
|
32
|
+
5. Commit and push → git add . && git commit && git push
|
|
33
|
+
│
|
|
34
|
+
▼
|
|
35
|
+
6. Activate → abapgit-agent pull --files src/file.clas.abap
|
|
36
|
+
│ (behaviour depends on .abapgit-agent.json — see AI Tool Guidelines)
|
|
37
|
+
│
|
|
38
|
+
▼
|
|
39
|
+
7. Verify → Check pull output
|
|
40
|
+
- **"Error updating where-used list"** → SYNTAX ERROR (use inspect for details)
|
|
41
|
+
- Objects in "Failed Objects Log" → Syntax error (use inspect)
|
|
42
|
+
- Objects NOT appearing at all → XML metadata issue (check abapgit.md)
|
|
43
|
+
│
|
|
44
|
+
▼
|
|
45
|
+
8. (Optional) Run unit tests → abapgit-agent unit --files <testclass> (AFTER successful pull)
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
**Syntax Command - Supported Object Types:**
|
|
49
|
+
|
|
50
|
+
| Object Type | Syntax Command | What to Do |
|
|
51
|
+
|-------------|----------------|------------|
|
|
52
|
+
| CLAS (classes) | ✅ Supported | Run `syntax` before commit |
|
|
53
|
+
| CLAS (test classes: .testclasses.abap) | ✅ Supported | Run `syntax` before commit |
|
|
54
|
+
| INTF (interfaces) | ✅ Supported | Run `syntax` before commit |
|
|
55
|
+
| PROG (programs) | ✅ Supported | Run `syntax` before commit |
|
|
56
|
+
| DDLS (CDS views) | ✅ Supported | Run `syntax` before commit (requires annotations) |
|
|
57
|
+
| FUGR (function groups) | ❌ Not supported | Skip syntax, use `pull` then `inspect` |
|
|
58
|
+
| TABL/DTEL/DOMA/MSAG/SHLP | ❌ Not supported | Skip syntax, just `pull` |
|
|
59
|
+
| All other types | ❌ Not supported | Skip syntax, just `pull` |
|
|
60
|
+
|
|
61
|
+
**IMPORTANT**:
|
|
62
|
+
- **Use `syntax` BEFORE commit** for CLAS/INTF/PROG/DDLS - catches errors early, no git pollution
|
|
63
|
+
- **Syntax checks files INDEPENDENTLY** - syntax checker doesn't have access to uncommitted files
|
|
64
|
+
- **For dependent files** (interface + class): Create/activate underlying object FIRST, then dependent object (see workflow below)
|
|
65
|
+
- **DDLS requires proper annotations** - CDS views need `@AbapCatalog.sqlViewName`, view entities don't
|
|
66
|
+
- **ALWAYS push to git BEFORE running pull** - abapGit reads from git
|
|
67
|
+
- **Use `inspect` AFTER pull** for unsupported types or if pull fails
|
|
68
|
+
|
|
69
|
+
**Working with dependent objects (RECOMMENDED APPROACH):**
|
|
70
|
+
|
|
71
|
+
When creating objects with dependencies (e.g., interface → class), create and activate the underlying object FIRST:
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
# Step 1: Create interface, syntax check, commit, activate
|
|
75
|
+
vim src/zif_my_interface.intf.abap
|
|
76
|
+
abapgit-agent syntax --files src/zif_my_interface.intf.abap # ✅ Works (no dependencies)
|
|
77
|
+
git add src/zif_my_interface.intf.abap src/zif_my_interface.intf.xml
|
|
78
|
+
git commit -m "feat: add interface"
|
|
79
|
+
git push
|
|
80
|
+
abapgit-agent pull --files src/zif_my_interface.intf.abap # Interface now activated
|
|
81
|
+
|
|
82
|
+
# Step 2: Create class, syntax check, commit, activate
|
|
83
|
+
vim src/zcl_my_class.clas.abap
|
|
84
|
+
abapgit-agent syntax --files src/zcl_my_class.clas.abap # ✅ Works (interface already activated)
|
|
85
|
+
git add src/zcl_my_class.clas.abap src/zcl_my_class.clas.xml
|
|
86
|
+
git commit -m "feat: add class implementing interface"
|
|
87
|
+
git push
|
|
88
|
+
abapgit-agent pull --files src/zcl_my_class.clas.abap
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
**Benefits:**
|
|
92
|
+
- ✅ Syntax checking works for both objects
|
|
93
|
+
- ✅ Each step is validated independently
|
|
94
|
+
- ✅ Easier to debug if something fails
|
|
95
|
+
- ✅ Cleaner workflow
|
|
96
|
+
|
|
97
|
+
**Alternative approach (when interface design is uncertain):**
|
|
98
|
+
|
|
99
|
+
If the interface might need changes while implementing the class, commit both together:
|
|
100
|
+
|
|
101
|
+
```bash
|
|
102
|
+
# Create both files
|
|
103
|
+
vim src/zif_my_interface.intf.abap
|
|
104
|
+
vim src/zcl_my_class.clas.abap
|
|
105
|
+
|
|
106
|
+
# Skip syntax (files depend on each other), commit together
|
|
107
|
+
git add src/zif_my_interface.intf.abap src/zif_my_interface.intf.xml
|
|
108
|
+
git add src/zcl_my_class.clas.abap src/zcl_my_class.clas.xml
|
|
109
|
+
git commit -m "feat: add interface and implementing class"
|
|
110
|
+
git push
|
|
111
|
+
|
|
112
|
+
# Pull both together
|
|
113
|
+
abapgit-agent pull --files src/zif_my_interface.intf.abap,src/zcl_my_class.clas.abap
|
|
114
|
+
|
|
115
|
+
# Use inspect if errors occur
|
|
116
|
+
abapgit-agent inspect --files src/zcl_my_class.clas.abap
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
**Use this approach when:**
|
|
120
|
+
- ❌ Interface design is still evolving
|
|
121
|
+
- ❌ Multiple iterations expected
|
|
122
|
+
|
|
123
|
+
**Working with mixed file types:**
|
|
124
|
+
When modifying multiple files of different types (e.g., 1 class + 1 CDS view):
|
|
125
|
+
1. Run `syntax` on independent supported files (CLAS, INTF, PROG, DDLS)
|
|
126
|
+
2. Commit ALL files together (including unsupported types)
|
|
127
|
+
3. Push and pull ALL files together
|
|
128
|
+
|
|
129
|
+
Example:
|
|
130
|
+
```bash
|
|
131
|
+
# Check syntax on independent files only
|
|
132
|
+
abapgit-agent syntax --files src/zcl_my_class.clas.abap,src/zc_my_view.ddls.asddls
|
|
133
|
+
|
|
134
|
+
# Commit and push all files
|
|
135
|
+
git add src/zcl_my_class.clas.abap src/zc_my_view.ddls.asddls
|
|
136
|
+
git commit -m "feat: add class and CDS view"
|
|
137
|
+
git push
|
|
138
|
+
|
|
139
|
+
# Pull all files together
|
|
140
|
+
abapgit-agent pull --files src/zcl_my_class.clas.abap,src/zc_my_view.ddls.asddls
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
**When to use syntax vs inspect vs view**:
|
|
144
|
+
- **syntax**: Check LOCAL code BEFORE commit (CLAS, INTF, PROG, DDLS)
|
|
145
|
+
- **inspect**: Check ACTIVATED code AFTER pull (all types, runs Code Inspector)
|
|
146
|
+
- **view**: Understand object STRUCTURE (not for debugging errors)
|
|
147
|
+
|
|
148
|
+
### Quick Decision Tree for AI
|
|
149
|
+
|
|
150
|
+
**When user asks to modify/create ABAP code:**
|
|
151
|
+
|
|
152
|
+
```
|
|
153
|
+
1. Identify file extension(s) AND dependencies
|
|
154
|
+
├─ .clas.abap or .clas.testclasses.abap → CLAS ✅ syntax supported
|
|
155
|
+
├─ .intf.abap → INTF ✅ syntax supported
|
|
156
|
+
├─ .prog.abap → PROG ✅ syntax supported
|
|
157
|
+
├─ .ddls.asddls → DDLS ✅ syntax supported (requires proper annotations)
|
|
158
|
+
└─ All other extensions → ❌ syntax not supported
|
|
159
|
+
|
|
160
|
+
2. Check for dependencies:
|
|
161
|
+
├─ Interface + implementing class? → DEPENDENT (interface is underlying)
|
|
162
|
+
├─ Class A uses class B? → DEPENDENT (class B is underlying)
|
|
163
|
+
├─ CDS view uses table? → INDEPENDENT (table already exists)
|
|
164
|
+
└─ Unrelated bug fixes across files? → INDEPENDENT
|
|
165
|
+
|
|
166
|
+
3. For SUPPORTED types (CLAS/INTF/PROG/DDLS):
|
|
167
|
+
├─ INDEPENDENT files → Run syntax → Fix errors → Commit → Push → Pull
|
|
168
|
+
│
|
|
169
|
+
└─ DEPENDENT files (NEW objects):
|
|
170
|
+
├─ RECOMMENDED: Create underlying object first (interface, base class, etc.)
|
|
171
|
+
│ 1. Create underlying object → Syntax → Commit → Push → Pull
|
|
172
|
+
│ 2. Create dependent object → Syntax (works!) → Commit → Push → Pull
|
|
173
|
+
│ ✅ Benefits: Both syntax checks work, cleaner workflow
|
|
174
|
+
│
|
|
175
|
+
└─ ALTERNATIVE: If interface design uncertain, commit both together
|
|
176
|
+
→ Skip syntax → Commit both → Push → Pull → (if errors: inspect)
|
|
177
|
+
|
|
178
|
+
4. For UNSUPPORTED types (FUGR, TABL, etc.):
|
|
179
|
+
Write code → Skip syntax → Commit → Push → Pull → (if errors: inspect)
|
|
180
|
+
|
|
181
|
+
5. For MIXED types (some supported + some unsupported):
|
|
182
|
+
Write all code → Run syntax on independent supported files ONLY → Commit ALL → Push → Pull ALL
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
**Example workflows:**
|
|
186
|
+
|
|
187
|
+
**Scenario 1: Interface + Class (RECOMMENDED)**
|
|
188
|
+
```bash
|
|
189
|
+
# Step 1: Interface first
|
|
190
|
+
vim src/zif_calculator.intf.abap
|
|
191
|
+
abapgit-agent syntax --files src/zif_calculator.intf.abap # ✅ Works
|
|
192
|
+
git commit -am "feat: add calculator interface" && git push
|
|
193
|
+
abapgit-agent pull --files src/zif_calculator.intf.abap # Interface activated
|
|
194
|
+
|
|
195
|
+
# Step 2: Class next
|
|
196
|
+
vim src/zcl_calculator.clas.abap
|
|
197
|
+
abapgit-agent syntax --files src/zcl_calculator.clas.abap # ✅ Works (interface exists!)
|
|
198
|
+
git commit -am "feat: implement calculator" && git push
|
|
199
|
+
abapgit-agent pull --files src/zcl_calculator.clas.abap
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
**Scenario 2: Multiple independent classes**
|
|
203
|
+
```bash
|
|
204
|
+
# All syntax checks work (no dependencies)
|
|
205
|
+
vim src/zcl_class1.clas.abap src/zcl_class2.clas.abap
|
|
206
|
+
abapgit-agent syntax --files src/zcl_class1.clas.abap,src/zcl_class2.clas.abap
|
|
207
|
+
git commit -am "feat: add utility classes" && git push
|
|
208
|
+
abapgit-agent pull --files src/zcl_class1.clas.abap,src/zcl_class2.clas.abap
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
**Error indicators after pull:**
|
|
212
|
+
- ❌ **"Error updating where-used list"** → SYNTAX ERROR - run `inspect` for details
|
|
213
|
+
- ❌ **Objects in "Failed Objects Log"** → SYNTAX ERROR - run `inspect`
|
|
214
|
+
- ❌ **Objects NOT appearing at all** → XML metadata issue (check `ref --topic abapgit`)
|
|
215
|
+
- ⚠️ **"Activated with warnings"** → Code Inspector warnings - run `inspect` to see details
|
|
216
|
+
|
|
217
|
+
### Commands
|
|
218
|
+
|
|
219
|
+
```bash
|
|
220
|
+
# 1. Syntax check LOCAL code BEFORE commit (CLAS, INTF, PROG, DDLS)
|
|
221
|
+
abapgit-agent syntax --files src/zcl_my_class.clas.abap
|
|
222
|
+
abapgit-agent syntax --files src/zc_my_view.ddls.asddls
|
|
223
|
+
abapgit-agent syntax --files src/zcl_class1.clas.abap,src/zif_intf1.intf.abap,src/zc_view.ddls.asddls
|
|
224
|
+
|
|
225
|
+
# 2. Pull/activate AFTER pushing to git
|
|
226
|
+
abapgit-agent pull --files src/zcl_class1.clas.abap,src/zcl_class2.clas.abap
|
|
227
|
+
|
|
228
|
+
# Override conflict detection for a single pull (e.g. deliberate branch switch)
|
|
229
|
+
abapgit-agent pull --files src/zcl_class1.clas.abap --conflict-mode ignore
|
|
230
|
+
|
|
231
|
+
# 3. Inspect AFTER pull (for errors or unsupported types)
|
|
232
|
+
abapgit-agent inspect --files src/zcl_class1.clas.abap
|
|
233
|
+
|
|
234
|
+
# Run unit tests (after successful pull)
|
|
235
|
+
abapgit-agent unit --files src/zcl_test1.clas.testclasses.abap,src/zcl_test2.clas.testclasses.abap
|
|
236
|
+
|
|
237
|
+
# View object definitions (multiple objects)
|
|
238
|
+
abapgit-agent view --objects ZCL_CLASS1,ZCL_CLASS2,ZIF_INTERFACE
|
|
239
|
+
|
|
240
|
+
# Preview table data (multiple tables/views)
|
|
241
|
+
abapgit-agent preview --objects ZTABLE1,ZTABLE2
|
|
242
|
+
|
|
243
|
+
# Explore table structures
|
|
244
|
+
abapgit-agent view --objects ZTABLE --type TABL
|
|
245
|
+
|
|
246
|
+
# Display package tree
|
|
247
|
+
abapgit-agent tree --package \$MY_PACKAGE
|
|
248
|
+
|
|
249
|
+
# Investigate runtime errors (ST22 short dumps)
|
|
250
|
+
abapgit-agent dump # Last 7 days
|
|
251
|
+
abapgit-agent dump --user DEVELOPER --date TODAY # Today's dumps for a user
|
|
252
|
+
abapgit-agent dump --program ZMY_PROGRAM # Dumps from a specific program
|
|
253
|
+
abapgit-agent dump --error TIME_OUT # Dumps by error type
|
|
254
|
+
abapgit-agent dump --user DEVELOPER --detail 1 # Full detail of first result
|
|
255
|
+
```
|
package/package.json
CHANGED
package/src/commands/debug.js
CHANGED
|
@@ -34,6 +34,7 @@ const { spawn } = require('child_process');
|
|
|
34
34
|
const { AdtHttp } = require('../utils/adt-http');
|
|
35
35
|
const { DebugSession } = require('../utils/debug-session');
|
|
36
36
|
const debugStateModule = require('../utils/debug-state');
|
|
37
|
+
const { printHttpError } = require('../utils/format-error');
|
|
37
38
|
const {
|
|
38
39
|
saveActiveSession,
|
|
39
40
|
loadActiveSession,
|
|
@@ -60,11 +61,16 @@ function hasFlag(args, flag) {
|
|
|
60
61
|
}
|
|
61
62
|
|
|
62
63
|
/**
|
|
63
|
-
* Determine ADT object URI from object name (class/interface vs program).
|
|
64
|
+
* Determine ADT object URI from object name (class/interface vs program vs include).
|
|
64
65
|
* Must use /source/main suffix for classes — verified by live testing: ADT
|
|
65
66
|
* rejects breakpoints set on the class root URI but accepts /source/main.
|
|
66
67
|
* classes → /sap/bc/adt/oo/classes/<name_lowercase>/source/main
|
|
68
|
+
* includes → /sap/bc/adt/programs/includes/<name_lowercase>
|
|
67
69
|
* programs → /sap/bc/adt/programs/programs/<name_lowercase>
|
|
70
|
+
*
|
|
71
|
+
* Class method includes are named <ClassName padded to 30 chars with '='>CM<suffix>
|
|
72
|
+
* e.g. ZCL_ABGAGT_AGENT=============CM00D
|
|
73
|
+
* These must be routed to the programs/includes ADT endpoint.
|
|
68
74
|
*/
|
|
69
75
|
function objectUri(name) {
|
|
70
76
|
const upper = (name || '').toUpperCase();
|
|
@@ -325,17 +331,16 @@ async function cmdSet(args, config, adt) {
|
|
|
325
331
|
return;
|
|
326
332
|
}
|
|
327
333
|
|
|
328
|
-
await adt.fetchCsrfToken();
|
|
329
|
-
const body = buildBreakpointsXml(config.user, updated);
|
|
330
|
-
|
|
331
334
|
let resp;
|
|
332
335
|
try {
|
|
336
|
+
await adt.fetchCsrfToken();
|
|
337
|
+
const body = buildBreakpointsXml(config.user, updated);
|
|
333
338
|
resp = await adt.post('/sap/bc/adt/debugger/breakpoints', body, {
|
|
334
339
|
contentType: 'application/xml',
|
|
335
340
|
headers: { Accept: 'application/xml' }
|
|
336
341
|
});
|
|
337
342
|
} catch (err) {
|
|
338
|
-
|
|
343
|
+
printHttpError(err, { prefix: ' Error' });
|
|
339
344
|
process.exit(1);
|
|
340
345
|
}
|
|
341
346
|
|
|
@@ -357,6 +362,35 @@ async function cmdSet(args, config, adt) {
|
|
|
357
362
|
});
|
|
358
363
|
if (_saveBpState) _saveBpState(config, updatedWithServerIds);
|
|
359
364
|
|
|
365
|
+
// Immediately re-validate the newly added breakpoints: ADT accepts the POST
|
|
366
|
+
// with HTTP 200 even for invalid positions (e.g. comment lines), but then
|
|
367
|
+
// silently drops them. Re-validating here gives immediate feedback instead
|
|
368
|
+
// of only discovering the failure on the next "debug list".
|
|
369
|
+
const addedBps = updatedWithServerIds.filter(bp =>
|
|
370
|
+
added.some(a => a.uri === bp.uri && a.line === bp.line)
|
|
371
|
+
);
|
|
372
|
+
const { stale: newlyStale } = await refreshBreakpoints(config, adt, addedBps);
|
|
373
|
+
if (newlyStale.length > 0) {
|
|
374
|
+
// Remove stale from state
|
|
375
|
+
const stillValid = updatedWithServerIds.filter(bp =>
|
|
376
|
+
!newlyStale.some(s => s.uri === bp.uri && s.line === bp.line)
|
|
377
|
+
);
|
|
378
|
+
if (_saveBpState) _saveBpState(config, stillValid);
|
|
379
|
+
|
|
380
|
+
if (jsonOutput) {
|
|
381
|
+
console.log(JSON.stringify({ error: 'Breakpoint not accepted by server', stale: newlyStale.map(b => ({ object: b.object, line: b.line, error: b.error })) }));
|
|
382
|
+
} else {
|
|
383
|
+
newlyStale.forEach(({ object, line, error }) => {
|
|
384
|
+
console.error(`\n ❌ Breakpoint not accepted: ${object} line ${line}`);
|
|
385
|
+
console.error(` Reason: ${error || 'Not registered on server'}`);
|
|
386
|
+
console.error(` Tip: line must be an executable statement — not a comment, blank line,`);
|
|
387
|
+
console.error(` DATA declaration, or continuation line of a multi-line call.\n`);
|
|
388
|
+
});
|
|
389
|
+
process.exit(1);
|
|
390
|
+
}
|
|
391
|
+
return;
|
|
392
|
+
}
|
|
393
|
+
|
|
360
394
|
if (jsonOutput) {
|
|
361
395
|
const out = added.map(a => {
|
|
362
396
|
const sr = serverResults.find(r => r.uri === a.uri && r.line === a.line);
|
|
@@ -461,7 +495,7 @@ async function cmdDelete(args, config, adt) {
|
|
|
461
495
|
try {
|
|
462
496
|
await adt.delete(`/sap/bc/adt/debugger/breakpoints/${encodeURIComponent(bpId)}`);
|
|
463
497
|
} catch (err) {
|
|
464
|
-
|
|
498
|
+
printHttpError(err, { prefix: ' Error' });
|
|
465
499
|
process.exit(1);
|
|
466
500
|
}
|
|
467
501
|
if (jsonOutput) {
|
|
@@ -488,11 +522,11 @@ async function cmdDelete(args, config, adt) {
|
|
|
488
522
|
try {
|
|
489
523
|
await adt.delete(`/sap/bc/adt/debugger/breakpoints?clientId=${encodeURIComponent(ADT_CLIENT_ID)}`);
|
|
490
524
|
} catch (err2) {
|
|
491
|
-
|
|
525
|
+
printHttpError(err2, { prefix: ' Error' });
|
|
492
526
|
process.exit(1);
|
|
493
527
|
}
|
|
494
528
|
} else {
|
|
495
|
-
|
|
529
|
+
printHttpError(err, { prefix: ' Error' });
|
|
496
530
|
process.exit(1);
|
|
497
531
|
}
|
|
498
532
|
}
|
|
@@ -622,7 +656,7 @@ async function cmdAttach(args, config, adt) {
|
|
|
622
656
|
);
|
|
623
657
|
process.exit(1);
|
|
624
658
|
}
|
|
625
|
-
|
|
659
|
+
printHttpError(err, { prefix: ' Error from ADT listener' });
|
|
626
660
|
process.exit(1);
|
|
627
661
|
}
|
|
628
662
|
|
|
@@ -708,7 +742,7 @@ async function cmdAttach(args, config, adt) {
|
|
|
708
742
|
try {
|
|
709
743
|
await session.attach(sessionId, (config.user || '').toUpperCase());
|
|
710
744
|
} catch (e) {
|
|
711
|
-
|
|
745
|
+
printHttpError(e, { prefix: ' Error during attach' });
|
|
712
746
|
if (e.body) console.error(' Response body:', e.body.substring(0, 400));
|
|
713
747
|
process.exit(1);
|
|
714
748
|
}
|
|
@@ -802,7 +836,7 @@ async function cmdStep(args, config, adt) {
|
|
|
802
836
|
try {
|
|
803
837
|
resp = await sendDaemonCommand(socketPath, { cmd: 'step', type }, 60000);
|
|
804
838
|
} catch (err) {
|
|
805
|
-
|
|
839
|
+
printHttpError(err, { prefix: ' Error' });
|
|
806
840
|
process.exit(1);
|
|
807
841
|
}
|
|
808
842
|
if (!resp.ok) {
|
|
@@ -846,7 +880,7 @@ async function cmdStep(args, config, adt) {
|
|
|
846
880
|
);
|
|
847
881
|
process.exit(1);
|
|
848
882
|
}
|
|
849
|
-
|
|
883
|
+
printHttpError(err, { prefix: ' Error' });
|
|
850
884
|
process.exit(1);
|
|
851
885
|
}
|
|
852
886
|
|
|
@@ -892,7 +926,7 @@ async function cmdVars(args, config, adt) {
|
|
|
892
926
|
try {
|
|
893
927
|
resp = await sendDaemonCommand(socketPath, { cmd: 'vars', name: nameFilter }, 60000);
|
|
894
928
|
} catch (err) {
|
|
895
|
-
|
|
929
|
+
printHttpError(err, { prefix: ' Error' });
|
|
896
930
|
process.exit(1);
|
|
897
931
|
}
|
|
898
932
|
if (!resp.ok) {
|
|
@@ -923,7 +957,7 @@ async function cmdVars(args, config, adt) {
|
|
|
923
957
|
);
|
|
924
958
|
process.exit(1);
|
|
925
959
|
}
|
|
926
|
-
|
|
960
|
+
printHttpError(err, { prefix: ' Error' });
|
|
927
961
|
process.exit(1);
|
|
928
962
|
}
|
|
929
963
|
|
|
@@ -962,7 +996,7 @@ async function cmdExpand(expandName, sessionId, socketPath, config, adt, jsonOut
|
|
|
962
996
|
try {
|
|
963
997
|
result = await session.expandPath(pathParts);
|
|
964
998
|
} catch (err) {
|
|
965
|
-
|
|
999
|
+
printHttpError(err, { prefix: ' Error' });
|
|
966
1000
|
process.exit(1);
|
|
967
1001
|
}
|
|
968
1002
|
const { variable: target, children } = result;
|
|
@@ -977,7 +1011,7 @@ async function cmdExpand(expandName, sessionId, socketPath, config, adt, jsonOut
|
|
|
977
1011
|
try {
|
|
978
1012
|
resp = await sendDaemonCommand(socketPath, { cmd: 'vars', name: null }, 60000);
|
|
979
1013
|
} catch (err) {
|
|
980
|
-
|
|
1014
|
+
printHttpError(err, { prefix: ' Error' });
|
|
981
1015
|
process.exit(1);
|
|
982
1016
|
}
|
|
983
1017
|
if (!resp.ok) {
|
|
@@ -1009,7 +1043,7 @@ async function cmdExpand(expandName, sessionId, socketPath, config, adt, jsonOut
|
|
|
1009
1043
|
try {
|
|
1010
1044
|
resp = await sendDaemonCommand(socketPath, { cmd: 'expand', id: target.id, meta }, 60000);
|
|
1011
1045
|
} catch (err) {
|
|
1012
|
-
|
|
1046
|
+
printHttpError(err, { prefix: ' Error' });
|
|
1013
1047
|
process.exit(1);
|
|
1014
1048
|
}
|
|
1015
1049
|
if (!resp.ok) {
|
|
@@ -1070,7 +1104,7 @@ async function cmdStack(args, config, adt) {
|
|
|
1070
1104
|
try {
|
|
1071
1105
|
resp = await sendDaemonCommand(socketPath, { cmd: 'stack' }, 60000);
|
|
1072
1106
|
} catch (err) {
|
|
1073
|
-
|
|
1107
|
+
printHttpError(err, { prefix: ' Error' });
|
|
1074
1108
|
process.exit(1);
|
|
1075
1109
|
}
|
|
1076
1110
|
if (!resp.ok) {
|
|
@@ -1101,7 +1135,7 @@ async function cmdStack(args, config, adt) {
|
|
|
1101
1135
|
);
|
|
1102
1136
|
process.exit(1);
|
|
1103
1137
|
}
|
|
1104
|
-
|
|
1138
|
+
printHttpError(err, { prefix: ' Error' });
|
|
1105
1139
|
process.exit(1);
|
|
1106
1140
|
}
|
|
1107
1141
|
|
|
@@ -1164,7 +1198,7 @@ async function cmdTerminate(args, config, adt) {
|
|
|
1164
1198
|
);
|
|
1165
1199
|
process.exit(1);
|
|
1166
1200
|
}
|
|
1167
|
-
|
|
1201
|
+
printHttpError(err, { prefix: ' Error' });
|
|
1168
1202
|
process.exit(1);
|
|
1169
1203
|
}
|
|
1170
1204
|
|
package/src/commands/inspect.js
CHANGED
|
@@ -3,11 +3,12 @@
|
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
const pathModule = require('path');
|
|
6
|
+
const { printHttpError } = require('../utils/format-error');
|
|
6
7
|
|
|
7
8
|
/**
|
|
8
9
|
* Inspect all files in one request
|
|
9
10
|
*/
|
|
10
|
-
async function inspectAllFiles(files, csrfToken, config, variant, http) {
|
|
11
|
+
async function inspectAllFiles(files, csrfToken, config, variant, http, verbose = false) {
|
|
11
12
|
// Convert files to uppercase names
|
|
12
13
|
const fileNames = files.map(f => {
|
|
13
14
|
const baseName = pathModule.basename(f).toUpperCase();
|
|
@@ -45,7 +46,7 @@ async function inspectAllFiles(files, csrfToken, config, variant, http) {
|
|
|
45
46
|
|
|
46
47
|
return results;
|
|
47
48
|
} catch (error) {
|
|
48
|
-
|
|
49
|
+
printHttpError(error, { verbose });
|
|
49
50
|
process.exit(1);
|
|
50
51
|
}
|
|
51
52
|
}
|
|
@@ -149,6 +150,7 @@ module.exports = {
|
|
|
149
150
|
const { loadConfig, AbapHttp } = context;
|
|
150
151
|
|
|
151
152
|
const jsonOutput = args.includes('--json');
|
|
153
|
+
const verbose = args.includes('--verbose');
|
|
152
154
|
const filesArgIndex = args.indexOf('--files');
|
|
153
155
|
if (filesArgIndex === -1 || filesArgIndex + 1 >= args.length) {
|
|
154
156
|
console.error('Error: --files parameter required');
|
|
@@ -178,7 +180,7 @@ module.exports = {
|
|
|
178
180
|
const csrfToken = await http.fetchCsrfToken();
|
|
179
181
|
|
|
180
182
|
// Send all files in one request
|
|
181
|
-
const results = await inspectAllFiles(filesSyntaxCheck, csrfToken, config, variant, http);
|
|
183
|
+
const results = await inspectAllFiles(filesSyntaxCheck, csrfToken, config, variant, http, verbose);
|
|
182
184
|
|
|
183
185
|
// JSON output mode
|
|
184
186
|
if (jsonOutput) {
|
package/src/commands/pull.js
CHANGED
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
* Pull command - Pull and activate ABAP objects from git repository
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
+
const { printHttpError } = require('../utils/format-error');
|
|
6
|
+
|
|
5
7
|
module.exports = {
|
|
6
8
|
name: 'pull',
|
|
7
9
|
description: 'Pull and activate ABAP objects from git repository',
|
|
@@ -10,6 +12,7 @@ module.exports = {
|
|
|
10
12
|
|
|
11
13
|
async execute(args, context) {
|
|
12
14
|
const { loadConfig, AbapHttp, gitUtils, getTransport, getSafeguards, getConflictSettings, getTransportSettings } = context;
|
|
15
|
+
const verbose = args.includes('--verbose');
|
|
13
16
|
|
|
14
17
|
// Check project-level safeguards
|
|
15
18
|
const safeguards = getSafeguards();
|
|
@@ -404,7 +407,7 @@ module.exports = {
|
|
|
404
407
|
if (error._isPullError) {
|
|
405
408
|
throw error;
|
|
406
409
|
}
|
|
407
|
-
|
|
410
|
+
printHttpError(error, { verbose });
|
|
408
411
|
process.exit(1);
|
|
409
412
|
}
|
|
410
413
|
}
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
const VALID_SCOPES = ['mine', 'task', 'all'];
|
|
6
6
|
const VALID_SUBCOMMANDS = ['list', 'create', 'check', 'release'];
|
|
7
7
|
const VALID_TYPES = ['workbench', 'customizing'];
|
|
8
|
+
const { printHttpError } = require('../utils/format-error');
|
|
8
9
|
|
|
9
10
|
module.exports = {
|
|
10
11
|
name: 'transport',
|
|
@@ -16,6 +17,7 @@ module.exports = {
|
|
|
16
17
|
const { loadConfig, AbapHttp, getTransportSettings } = context;
|
|
17
18
|
|
|
18
19
|
const jsonOutput = args.includes('--json');
|
|
20
|
+
const verbose = args.includes('--verbose');
|
|
19
21
|
|
|
20
22
|
// Determine subcommand (first positional arg, default to 'list')
|
|
21
23
|
const subcommand = args[0] && !args[0].startsWith('-') ? args[0] : 'list';
|
|
@@ -65,7 +67,7 @@ module.exports = {
|
|
|
65
67
|
break;
|
|
66
68
|
}
|
|
67
69
|
} catch (error) {
|
|
68
|
-
|
|
70
|
+
printHttpError(error, { verbose });
|
|
69
71
|
process.exit(1);
|
|
70
72
|
}
|
|
71
73
|
},
|
package/src/commands/unit.js
CHANGED
|
@@ -4,11 +4,12 @@
|
|
|
4
4
|
|
|
5
5
|
const pathModule = require('path');
|
|
6
6
|
const fs = require('fs');
|
|
7
|
+
const { formatHttpError } = require('../utils/format-error');
|
|
7
8
|
|
|
8
9
|
/**
|
|
9
10
|
* Run unit test for a single file
|
|
10
11
|
*/
|
|
11
|
-
async function runUnitTestForFile(sourceFile, csrfToken, config, coverage, http, jsonOutput = false) {
|
|
12
|
+
async function runUnitTestForFile(sourceFile, csrfToken, config, coverage, http, jsonOutput = false, verbose = false) {
|
|
12
13
|
if (!jsonOutput) {
|
|
13
14
|
console.log(` Running unit test for: ${sourceFile}`);
|
|
14
15
|
}
|
|
@@ -123,14 +124,12 @@ async function runUnitTestForFile(sourceFile, csrfToken, config, coverage, http,
|
|
|
123
124
|
}
|
|
124
125
|
|
|
125
126
|
if (!jsonOutput) {
|
|
126
|
-
console.error(`\n ❌ Error: ${error
|
|
127
|
-
if (error.
|
|
128
|
-
console.error(
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
const preview = error.body.substring(0, 500);
|
|
133
|
-
console.error(` Response: ${preview}${error.body.length > 500 ? '...' : ''}`);
|
|
127
|
+
console.error(`\n ❌ Error: ${formatHttpError(error)}`);
|
|
128
|
+
if (verbose && error.body) {
|
|
129
|
+
console.error('\n--- Raw response body ---');
|
|
130
|
+
const raw = typeof error.body === 'object' ? JSON.stringify(error.body, null, 2) : String(error.body);
|
|
131
|
+
console.error(raw);
|
|
132
|
+
console.error('--- End of response body ---');
|
|
134
133
|
}
|
|
135
134
|
}
|
|
136
135
|
|
|
@@ -148,6 +147,7 @@ module.exports = {
|
|
|
148
147
|
const { loadConfig, AbapHttp } = context;
|
|
149
148
|
|
|
150
149
|
const jsonOutput = args.includes('--json');
|
|
150
|
+
const verbose = args.includes('--verbose');
|
|
151
151
|
const filesArgIndex = args.indexOf('--files');
|
|
152
152
|
if (filesArgIndex === -1 || filesArgIndex + 1 >= args.length) {
|
|
153
153
|
console.error('Error: --files parameter required');
|
|
@@ -177,7 +177,7 @@ module.exports = {
|
|
|
177
177
|
let hasErrors = false;
|
|
178
178
|
|
|
179
179
|
for (const sourceFile of files) {
|
|
180
|
-
const result = await runUnitTestForFile(sourceFile, csrfToken, config, coverage, http, jsonOutput);
|
|
180
|
+
const result = await runUnitTestForFile(sourceFile, csrfToken, config, coverage, http, jsonOutput, verbose);
|
|
181
181
|
if (result) {
|
|
182
182
|
results.push(result);
|
|
183
183
|
|