abapgit-agent 1.13.6 → 1.13.7

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/abap/CLAUDE.md CHANGED
@@ -211,6 +211,21 @@ abapgit-agent pull --files src/<intf_name>.intf.abap,src/<class_name>.clas.abap
211
211
 
212
212
  → See `guidelines/object-creation.md` — run: `abapgit-agent ref --topic object-creation`
213
213
 
214
+ **XML metadata when adding test classes:**
215
+
216
+ ```
217
+ Adding .clas.testclasses.abap to an existing class?
218
+ └── Update the .clas.xml → set WITH_UNIT_TESTS flag:
219
+ <clas:abapClassProperties ... abpUnitTestable="true" ... />
220
+ WITHOUT this flag, abapGit will not push/activate the test include.
221
+
222
+ Adding .clas.locals_def.abap (local type definitions)?
223
+ └── Update the .clas.xml → set CLSCCINCL flag:
224
+ <CLSCCINCL>X</CLSCCINCL>
225
+ ```
226
+
227
+ → For exact XML flag placement: `abapgit-agent ref --topic abapgit` (search "WITH_UNIT_TESTS")
228
+
214
229
  ---
215
230
 
216
231
  ### 6. Use `guide`, `ref`, `view` and `where` Commands to Learn About Unknown Classes/Methods
@@ -299,7 +314,47 @@ Use `CL_CDS_TEST_ENVIRONMENT` for unit tests that read CDS views.
299
314
 
300
315
  ---
301
316
 
302
- ### 8. Use `unit` Command for Unit Tests
317
+ ### 8. Writing and Running Unit Tests
318
+
319
+ #### Writing tests — use ABAP Test Double Framework by default
320
+
321
+ ```
322
+ ❌ WRONG: Write a manual test double class (ltd_mock_xxx) when the framework can do it
323
+ ✅ CORRECT: Use cl_abap_testdouble=>create / configure_call for all interface mocking
324
+ ```
325
+
326
+ **Decision — which double pattern to use:**
327
+
328
+ ```
329
+ Does the mock need stateful behaviour (e.g. count calls, vary results per call, complex logic)?
330
+ └── YES → manual test double class (ltd_mock_xxx DEFINITION FOR TESTING)
331
+ └── NO → ABAP Test Double Framework (cl_abap_testdouble=>create / configure_call)
332
+ This covers 90 %+ of cases — simple return value / exception mocking
333
+ ```
334
+
335
+ **ABAP Test Double Framework — quick pattern:**
336
+
337
+ ```abap
338
+ " 1. Create double (declare with interface type)
339
+ DATA lo_agent TYPE REF TO zif_abgagt_agent.
340
+ lo_agent ?= cl_abap_testdouble=>create( 'ZIF_ABGAGT_AGENT' ).
341
+
342
+ " 2. Configure return value
343
+ cl_abap_testdouble=>configure_call( lo_agent )->returning( ls_result ).
344
+ lo_agent->pull( iv_url = 'https://...' ). " registers config for these params
345
+
346
+ " 3. Inject and call
347
+ DATA(lo_cut) = NEW zcl_my_class( io_agent = lo_agent ).
348
+ DATA(ls_actual) = lo_cut->execute( ).
349
+ ```
350
+
351
+ → Full API reference (EXPORT params, exceptions, inherited methods, common mistakes):
352
+ `abapgit-agent ref --topic unit-testable-code`
353
+
354
+ → For class design rules (constructor injection, interfaces for dependencies):
355
+ `abapgit-agent ref --topic unit-testable-code`
356
+
357
+ #### Running tests — use `unit` command
303
358
 
304
359
  **Use `abapgit-agent unit` to run ABAP unit tests (AUnit).**
305
360
 
@@ -399,6 +454,56 @@ abapgit-agent debug step --type continue --json # 4. release
399
454
 
400
455
  ---
401
456
 
457
+ ### 12. abaplint — Static Analysis (Optional, Project-Controlled)
458
+
459
+ abaplint is **optional**. Only run it if `.abaplint.json` exists in the project root.
460
+ Each project defines its own rules — never assume which rules are active.
461
+
462
+ **Detection:**
463
+ ```bash
464
+ # Check whether this project uses abaplint
465
+ ls .abaplint.json 2>/dev/null && echo "abaplint enabled" || echo "no abaplint"
466
+ ```
467
+
468
+ **When to run:**
469
+
470
+ Run abaplint as step 4b — after `syntax`, before `git commit`:
471
+
472
+ ```bash
473
+ # Only if .abaplint.json exists
474
+ npx @abaplint/cli .abaplint.json
475
+ ```
476
+
477
+ Fix any reported issues, then commit.
478
+
479
+ **Before applying any quickfix:**
480
+
481
+ ```
482
+ ❌ WRONG: Accept abaplint quickfixes without checking
483
+ ✅ CORRECT: Run abapgit-agent ref --topic abaplint FIRST, then decide
484
+ ```
485
+
486
+ The `prefer_inline` quickfix is known to introduce a **silent type truncation bug**
487
+ when applied to variables that are later extended with `&&`. Read the guidelines
488
+ before applying it.
489
+
490
+ **When abaplint flags an issue you don't understand:**
491
+ ```bash
492
+ abapgit-agent ref --topic abaplint # bundled rule guidance
493
+ abapgit-agent ref "prefer_inline" # search for specific rule
494
+ abapgit-agent ref "no_inline" # search by keyword
495
+ ```
496
+
497
+ **Project-specific rule guidance:**
498
+
499
+ Projects can add their own abaplint notes to `guidelines/abaplint-local.md` in the
500
+ project repository. After running `abapgit-agent ref export`, the `ref` command
501
+ surfaces both bundled and project-specific guidance together.
502
+
503
+ → See `guidelines/abaplint.md` — run: `abapgit-agent ref --topic abaplint`
504
+
505
+ ---
506
+
402
507
  ## Development Workflow
403
508
 
404
509
  This project's workflow mode is configured in `.abapGitAgent` under `workflow.mode`.
@@ -535,14 +640,17 @@ abapgit-agent pull --files src/<name>.clas.abap --sync-xml
535
640
  Modified ABAP files?
536
641
  ├─ CLAS/INTF/PROG/DDLS files?
537
642
  │ ├─ Independent files (no cross-dependencies)?
538
- │ │ └─ ✅ Use: syntax → commit → push → pull --sync-xml
643
+ │ │ └─ ✅ Use: syntax → [abaplint] → commit → push → pull --sync-xml
539
644
  │ └─ Dependent files (interface + class, class uses class)?
540
- │ └─ ✅ Use: skip syntax → commit → push → pull --sync-xml
645
+ │ └─ ✅ Use: skip syntax → [abaplint] → commit → push → pull --sync-xml
541
646
  └─ Other types (FUGR, TABL, STRU, DTEL, TTYP, etc.)?
542
647
  ├─ XML-only objects (TABL, STRU, DTEL, TTYP)?
543
- │ └─ ✅ Use: skip syntax → commit → push → pull --files abap/ztable.tabl.xml --sync-xml
648
+ │ └─ ✅ Use: skip syntax → [abaplint] → commit → push → pull --files abap/ztable.tabl.xml --sync-xml
544
649
  └─ FUGR and other complex objects?
545
- └─ ✅ Use: skip syntax → commit → push → pull --sync-xml → (if errors: inspect)
650
+ └─ ✅ Use: skip syntax → [abaplint] → commit → push → pull --sync-xml → (if errors: inspect)
651
+
652
+ [abaplint] = run npx @abaplint/cli .abaplint.json only if .abaplint.json exists in repo root
653
+ before applying any quickfix: run abapgit-agent ref --topic abaplint
546
654
  ```
547
655
 
548
656
  → For creating new objects (what files to write): `abapgit-agent ref --topic object-creation`
@@ -583,6 +691,7 @@ Detailed guidelines are available in the `guidelines/` folder:
583
691
  | `guidelines/workflow-detailed.md` | Development Workflow (Detailed) |
584
692
  | `guidelines/object-creation.md` | Object Creation (XML metadata, local classes) |
585
693
  | `guidelines/cds-testing.md` | CDS Testing (Test Double Framework) |
694
+ | `guidelines/abaplint.md` | abaplint Rule Guidelines (prefer_inline trap, safe patterns) |
586
695
 
587
696
  These guidelines are automatically searched by the `ref` command.
588
697
 
@@ -0,0 +1,111 @@
1
+ ---
2
+ layout: default
3
+ title: abaplint Local Rules
4
+ nav_order: 18
5
+ parent: ABAP Coding Guidelines
6
+ grand_parent: ABAP Development
7
+ ---
8
+
9
+ # abaplint Local Rules — abapgit-agent project
10
+
11
+ **Searchable keywords**: naming, local_variable_names, method_parameter_names,
12
+ prefix, lv, lt, ls, lo, li, lx, iv, it, is, io, rv, rs, rt, ro
13
+
14
+ This project enforces **type-specific Hungarian notation** via `local_variable_names`
15
+ and `method_parameter_names` in `.abaplint.json`.
16
+
17
+ ---
18
+
19
+ ## Variable Naming — Required Prefixes
20
+
21
+ ### Local Variables (inside methods)
22
+
23
+ | Prefix | Type | Example |
24
+ |--------|------|---------|
25
+ | `lv_` | Scalar / value (i, string, char, …) | `lv_count TYPE i` |
26
+ | `lt_` | Internal table | `lt_files TYPE ty_files` |
27
+ | `ls_` | Structure | `ls_result TYPE ty_result` |
28
+ | `lo_` | Object reference | `lo_agent TYPE REF TO zcl_abgagt_agent` |
29
+ | `li_` | Interface reference | `li_repo TYPE REF TO zif_abapgit_repo` |
30
+ | `lx_` | Exception reference | `lx_error TYPE REF TO cx_static_check` |
31
+ | `lr_` | Data reference | `lr_data TYPE REF TO data` |
32
+ | `lc_` | Constant | `lc_max TYPE i VALUE 100` |
33
+
34
+ ### Field-Symbols (inside methods)
35
+
36
+ | Prefix | Example |
37
+ |--------|---------|
38
+ | `<lv_>`, `<lt_>`, `<ls_>`, `<lo_>`, `<li_>` | `FIELD-SYMBOLS <ls_item> TYPE ty_item` |
39
+ | `<comp>` | Allowed for generic component iteration |
40
+
41
+ ### Method Parameters
42
+
43
+ | Direction | Prefix | Type |
44
+ |-----------|--------|------|
45
+ | IMPORTING | `iv_` | scalar |
46
+ | IMPORTING | `it_` | table |
47
+ | IMPORTING | `is_` | structure |
48
+ | IMPORTING | `io_` | object ref |
49
+ | IMPORTING | `ii_` | interface ref |
50
+ | IMPORTING | `ix_` | exception ref |
51
+ | RETURNING | `rv_` | scalar |
52
+ | RETURNING | `rs_` | structure |
53
+ | RETURNING | `rt_` | table |
54
+ | RETURNING | `ro_` | object ref |
55
+ | RETURNING | `ri_` | interface ref |
56
+ | RETURNING | `rr_` | data ref |
57
+ | EXPORTING | `ev_`, `es_`, `et_` | scalar / structure / table |
58
+ | CHANGING | `cv_`, `cs_`, `ct_` | scalar / structure / table |
59
+
60
+ ---
61
+
62
+ ## Quick Reference
63
+
64
+ ```abap
65
+ " Local variables
66
+ DATA lv_name TYPE string.
67
+ DATA lt_files TYPE ty_files.
68
+ DATA ls_result TYPE ty_result.
69
+ DATA lo_agent TYPE REF TO zcl_abgagt_agent.
70
+ DATA li_repo TYPE REF TO zif_abapgit_repo.
71
+ DATA lx_error TYPE REF TO cx_static_check.
72
+ FIELD-SYMBOLS <ls_item> TYPE ty_item.
73
+
74
+ " Method signature
75
+ METHODS process
76
+ IMPORTING
77
+ iv_url TYPE string
78
+ it_files TYPE ty_files
79
+ is_config TYPE ty_config
80
+ io_agent TYPE REF TO zcl_abgagt_agent
81
+ ii_repo TYPE REF TO zif_abapgit_repo
82
+ RETURNING
83
+ VALUE(rv_result) TYPE string.
84
+
85
+ METHODS get_repo
86
+ RETURNING
87
+ VALUE(ro_repo) TYPE REF TO zcl_abgagt_agent.
88
+ ```
89
+
90
+ ---
91
+
92
+ ## Rule: Never Use Generic `lv_` for Objects, Tables, or Structures
93
+
94
+ ```abap
95
+ " WRONG — abaplint will flag these
96
+ DATA lv_repo TYPE REF TO zcl_abgagt_agent. " use lo_
97
+ DATA lv_files TYPE ty_files. " use lt_
98
+ DATA lv_result TYPE ty_result. " use ls_
99
+
100
+ " CORRECT
101
+ DATA lo_repo TYPE REF TO zcl_abgagt_agent.
102
+ DATA lt_files TYPE ty_files.
103
+ DATA ls_result TYPE ty_result.
104
+ ```
105
+
106
+ ---
107
+
108
+ ## See Also
109
+
110
+ - `.abaplint.json` — rule definitions (`local_variable_names`, `method_parameter_names`)
111
+ - `guidelines/abaplint.md` — bundled guidance on `prefer_inline` trap
@@ -0,0 +1,173 @@
1
+ ---
2
+ layout: default
3
+ title: abaplint Rule Guidelines
4
+ nav_order: 17
5
+ parent: ABAP Coding Guidelines
6
+ grand_parent: ABAP Development
7
+ ---
8
+
9
+ # abaplint Rule Guidelines
10
+
11
+ **Searchable keywords**: abaplint, prefer_inline, inline declaration, char literal, string truncation,
12
+ no_inline_in_optional_branches, fully_type_constants, linting, static analysis
13
+
14
+ This file covers rules that have **non-obvious or dangerous implications** — cases where applying
15
+ a rule mechanically (or accepting its quickfix) can introduce subtle bugs.
16
+
17
+ For project-specific rule guidance, add a `guidelines/abaplint-local.md` file to the project
18
+ repository. The `ref` command searches both bundled and project guidelines automatically.
19
+
20
+ ---
21
+
22
+ ## prefer_inline — Inline Declarations
23
+
24
+ ### What the rule does
25
+
26
+ Flags up-front `DATA` declarations and suggests replacing them with inline `DATA(var) = expr`:
27
+
28
+ ```abap
29
+ * Bad (flagged by rule)
30
+ DATA lv_count TYPE i.
31
+ lv_count = lines( lt_table ).
32
+
33
+ * Good (preferred by rule)
34
+ DATA(lv_count) = lines( lt_table ).
35
+ ```
36
+
37
+ This is safe when the RHS expression is a **function call, method call, or constructor
38
+ operator** — because the return type is fully defined.
39
+
40
+ ### The char-literal trap — NEVER apply the quickfix here
41
+
42
+ ```
43
+ ❌ DANGEROUS: DATA(var) = 'literal'.
44
+ ```
45
+
46
+ When the RHS is a quoted string literal, ABAP infers type `C LENGTH N` where N equals
47
+ the exact character count of the literal. Any subsequent `&&` concatenation computes the
48
+ correct longer string but **silently truncates it back to N characters**. The variable
49
+ never grows beyond the length of its initial value.
50
+
51
+ **This is the most dangerous quickfix the rule offers — it changes the runtime type.**
52
+
53
+ ```abap
54
+ * WRONG — produced by prefer_inline quickfix, causes silent truncation
55
+ DATA(lv_response) = '{"success":"X",'. " → TYPE C LENGTH 16
56
+ lv_response = lv_response && '"key":"val"'. " computed correctly, truncated to 16 chars
57
+ " lv_response is STILL '{"success":"X",' — the && had no effect
58
+
59
+ * CORRECT — use a string template to build the full value in one step
60
+ DATA(lv_key) = condense( val = CONV string( li_repo->get_key( ) ) ).
61
+ rv_result = |\{"success":"X","key":"{ lv_key }"\}|.
62
+
63
+ * ALSO CORRECT — explicit TYPE string, safe to concatenate
64
+ DATA lv_response TYPE string.
65
+ lv_response = '{"success":"X",'.
66
+ lv_response = lv_response && '"key":"val"}'.
67
+ ```
68
+
69
+ ### Safe vs unsafe patterns
70
+
71
+ | Pattern | Safe? | Why |
72
+ |---|---|---|
73
+ | `DATA(n) = lines( lt_tab ).` | ✅ | Return type `I` — no truncation risk |
74
+ | `DATA(lo) = NEW zcl_foo( ).` | ✅ | Object reference — fully typed |
75
+ | `DATA(ls) = CORRESPONDING #( ls_src ).` | ✅ | Inherits structure type |
76
+ | `DATA(lv) = lv_other.` | ✅ | Inherits type from source variable |
77
+ | `SELECT ... INTO TABLE @DATA(lt).` | ✅ | Type from DB dictionary |
78
+ | `DATA(lv) = 'literal'.` followed by `&&` | ❌ | Infers `C LENGTH N`, truncates |
79
+ | `DATA(lv) = 'literal'.` used only in `\|{ lv }\|` | ⚠️ | Technically works but misleading — prefer explicit type |
80
+ | `DATA(lv) = 'X'.` used as abap_bool flag | ✅ | `C LENGTH 1` is correct for flags |
81
+
82
+ ### Rule of thumb
83
+
84
+ > If the inline-declared variable will ever appear on the left side of `&&`,
85
+ > or be passed to a parameter typed `TYPE string`, declare it explicitly:
86
+ > `DATA lv_foo TYPE string.`
87
+
88
+ ---
89
+
90
+ ## no_inline_in_optional_branches
91
+
92
+ ### What the rule does
93
+
94
+ Flags inline `DATA(var)` declarations inside `IF`, `CASE/WHEN`, `LOOP`, `WHILE`, `DO`,
95
+ and `SELECT` loops — branches that may not execute, leaving the variable uninitialized
96
+ when code after the branch reads it.
97
+
98
+ ```abap
99
+ * Bad (flagged)
100
+ LOOP AT lt_items INTO DATA(ls_item).
101
+ DATA(lv_key) = ls_item-key. " declared inside LOOP — only set when loop runs
102
+ ENDLOOP.
103
+ WRITE lv_key. " undefined if lt_items was empty
104
+
105
+ * Good
106
+ DATA lv_key TYPE string.
107
+ LOOP AT lt_items INTO DATA(ls_item).
108
+ lv_key = ls_item-key.
109
+ ENDLOOP.
110
+ WRITE lv_key.
111
+ ```
112
+
113
+ **Exception**: `TRY/CATCH/CLEANUP` is explicitly NOT considered an optional branch by
114
+ the rule — inline declarations inside `TRY` are allowed.
115
+
116
+ ### When you see this rule triggered
117
+
118
+ Move the `DATA(var)` declaration out of the branch to the top of the method, giving it
119
+ an explicit type:
120
+
121
+ ```abap
122
+ * Before (flagged)
123
+ IF condition.
124
+ DATA(lv_result) = compute( ).
125
+ ENDIF.
126
+
127
+ * After (clean)
128
+ DATA lv_result TYPE string.
129
+ IF condition.
130
+ lv_result = compute( ).
131
+ ENDIF.
132
+ ```
133
+
134
+ ---
135
+
136
+ ## Project-Specific Rule Overrides
137
+
138
+ Each project can add its own abaplint guidance by creating a file in the `guidelines/`
139
+ folder of the project repository:
140
+
141
+ ```
142
+ guidelines/
143
+ abaplint-local.md ← project-specific rule notes
144
+ ```
145
+
146
+ After creating the file, export it so the `ref` command can find it:
147
+
148
+ ```bash
149
+ abapgit-agent ref export
150
+ ```
151
+
152
+ Then `abapgit-agent ref "prefer_inline"` will surface both this bundled guidance
153
+ and the project-specific notes together.
154
+
155
+ **Example `guidelines/abaplint-local.md`:**
156
+
157
+ ```markdown
158
+ ## prefer_inline — project rules
159
+
160
+ This project's .abaplint.json enables prefer_inline.
161
+
162
+ Additional constraint: never inline-declare response-building variables.
163
+ All JSON response strings must use string templates (| ... |) directly
164
+ on rv_result — no intermediate lv_response variable at all.
165
+ ```
166
+
167
+ ---
168
+
169
+ ## See Also
170
+
171
+ - **common-errors.md** — char-literal truncation listed as a known error pattern
172
+ - **json.md** — safe patterns for building JSON strings in ABAP
173
+ - **workflow-detailed.md** — where abaplint fits in the development workflow
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  layout: default
3
3
  title: CDS Testing
4
- nav_order: 17
4
+ nav_order: 19
5
5
  parent: ABAP Coding Guidelines
6
6
  grand_parent: ABAP Development
7
7
  ---
@@ -89,7 +89,38 @@ Find data elements: `abapgit-agent view --objects <TABLE> --type TABL`
89
89
 
90
90
  ---
91
91
 
92
+ ## Inline Declaration from String Literal — Silent Truncation
93
+
94
+ **Symptom**: A `&&` concatenation has no effect; the variable retains its initial value.
95
+
96
+ **Root cause**: `DATA(var) = 'literal'` infers type `C LENGTH N` (N = literal length).
97
+ Any subsequent `&&` computes the correct longer string but truncates it back to N chars.
98
+ The abaplint `prefer_inline` quickfix can introduce this bug automatically.
99
+
100
+ ```abap
101
+ * WRONG — lv_response stays '{"success":"X",' after && (16 chars, always truncated)
102
+ DATA(lv_response) = '{"success":"X",'.
103
+ lv_response = lv_response && '"key":"value"}'. " no effect!
104
+
105
+ * CORRECT — use string template
106
+ DATA(lv_key) = condense( val = CONV string( li_repo->get_key( ) ) ).
107
+ rv_result = |\{"success":"X","key":"{ lv_key }"\}|.
108
+
109
+ * ALSO CORRECT — explicit TYPE string
110
+ DATA lv_response TYPE string.
111
+ lv_response = '{"success":"X",'.
112
+ lv_response = lv_response && '"key":"value"}'. " works correctly
113
+ ```
114
+
115
+ **Fix**: Replace the inline declaration + `&&` chain with a string template,
116
+ or declare the variable explicitly with `TYPE string`.
117
+
118
+ → See `abaplint.md` for full guidance on the `prefer_inline` rule.
119
+
120
+ ---
121
+
92
122
  ## See Also
93
123
  - **ABAP SQL** (sql.md) - for SQL syntax rules
94
124
  - **CDS Views** (cds.md) - for CDS selection patterns
95
125
  - **abapGit** (abapgit.md) - for XML metadata templates
126
+ - **abaplint** (abaplint.md) - for abaplint rule guidance and known quickfix traps
@@ -30,6 +30,7 @@ This folder contains detailed ABAP coding guidelines that can be searched using
30
30
  | `workflow-detailed.md` | Development Workflow (Detailed) |
31
31
  | `object-creation.md` | Object Creation (XML metadata, local classes) |
32
32
  | `cds-testing.md` | CDS Testing (Test Double Framework) |
33
+ | `abaplint.md` | abaplint Rule Guidelines (prefer_inline trap, safe patterns) |
33
34
 
34
35
  ## Usage
35
36
 
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  layout: default
3
3
  title: Probe and PoC Guide
4
- nav_order: 19
4
+ nav_order: 21
5
5
  parent: ABAP Coding Guidelines
6
6
  grand_parent: ABAP Development
7
7
  ---
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  layout: default
3
3
  title: run Command Guide
4
- nav_order: 18
4
+ nav_order: 20
5
5
  parent: ABAP Coding Guidelines
6
6
  grand_parent: ABAP Development
7
7
  ---
@@ -257,31 +257,11 @@ ENDMETHOD.
257
257
 
258
258
  ## Test Double Patterns
259
259
 
260
- ### Manual Test Double (Local Class)
260
+ **Prefer the ABAP Test Double Framework** (`cl_abap_testdouble`) over manual doubles.
261
+ Use manual doubles only when stateful logic is required (e.g. call-count tracking, results that
262
+ vary per call, or complex setup that configure_call cannot express).
261
263
 
262
- ```abap
263
- " Create test double class
264
- CLASS ltd_mock_reader DEFINITION FOR TESTING.
265
- PUBLIC SECTION.
266
- INTERFACES zif_data_reader PARTIALLY IMPLEMENTED.
267
- METHODS set_result_data
268
- IMPORTING it_data TYPE ANY TABLE.
269
- PRIVATE SECTION.
270
- DATA mt_data TYPE ANY TABLE.
271
- ENDCLASS.
272
-
273
- CLASS ltd_mock_reader IMPLEMENTATION.
274
- METHOD set_result_data.
275
- mt_data = it_data.
276
- ENDMETHOD.
277
-
278
- METHOD zif_data_reader~read_all.
279
- rt_data = mt_data.
280
- ENDMETHOD.
281
- ENDCLASS.
282
- ```
283
-
284
- ### Using ABAP Test Double Framework
264
+ ### Using ABAP Test Double Framework (Recommended)
285
265
 
286
266
  ```abap
287
267
  " Step 1: Declare with correct interface type, then assign
@@ -315,6 +295,30 @@ lo_mock->my_method( ... ).
315
295
  - Use `returning(value = ...)` not `IMPORTING`
316
296
  - Call method after configure_call to register the configuration
317
297
 
298
+ ### Manual Test Double (Local Class — use only when stateful logic is needed)
299
+
300
+ ```abap
301
+ " Create test double class
302
+ CLASS ltd_mock_reader DEFINITION FOR TESTING.
303
+ PUBLIC SECTION.
304
+ INTERFACES zif_data_reader PARTIALLY IMPLEMENTED.
305
+ METHODS set_result_data
306
+ IMPORTING it_data TYPE ANY TABLE.
307
+ PRIVATE SECTION.
308
+ DATA mt_data TYPE ANY TABLE.
309
+ ENDCLASS.
310
+
311
+ CLASS ltd_mock_reader IMPLEMENTATION.
312
+ METHOD set_result_data.
313
+ mt_data = it_data.
314
+ ENDMETHOD.
315
+
316
+ METHOD zif_data_reader~read_all.
317
+ rt_data = mt_data.
318
+ ENDMETHOD.
319
+ ENDCLASS.
320
+ ```
321
+
318
322
  ### Mocking EXPORT Parameters
319
323
 
320
324
  Some methods use EXPORT parameters instead of returning values. Use `set_parameter`:
@@ -24,9 +24,22 @@ grand_parent: ABAP Development
24
24
  │ │
25
25
  │ ├─► Errors? → Fix locally (no commit needed), re-run syntax
26
26
  │ │
27
+ │ └─► Clean ✅ → Proceed to 4b
28
+
29
+ └─► Other types (FUGR, TABL, etc.) → Skip syntax, go to 4b
30
+
31
+
32
+ 4b. abaplint (OPTIONAL — only if .abaplint.json exists in repo root)
33
+
34
+ ├─► .abaplint.json exists → npx @abaplint/cli .abaplint.json
35
+ │ │
36
+ │ ├─► Issues? → Fix locally, re-run abaplint
37
+ │ │ ⚠️ Before applying any quickfix: run abapgit-agent ref --topic abaplint
38
+ │ │ Quickfixes for prefer_inline can introduce silent type truncation bugs.
39
+ │ │
27
40
  │ └─► Clean ✅ → Proceed to commit
28
41
 
29
- └─► Other types (FUGR, TABL, etc.) → Skip syntax, go to commit
42
+ └─► No .abaplint.json → Skip, go to commit
30
43
 
31
44
 
32
45
  5. Commit and push → git add . && git commit && git push
@@ -140,8 +153,9 @@ git push
140
153
  abapgit-agent pull --files src/zcl_my_class.clas.abap,src/zc_my_view.ddls.asddls
141
154
  ```
142
155
 
143
- **When to use syntax vs inspect vs view**:
144
- - **syntax**: Check LOCAL code BEFORE commit (CLAS, INTF, PROG, DDLS)
156
+ **When to use syntax vs abaplint vs inspect vs view**:
157
+ - **syntax**: Check LOCAL ABAP syntax BEFORE commit (CLAS, INTF, PROG, DDLS)
158
+ - **abaplint**: Check LOCAL code style/quality BEFORE commit (only if .abaplint.json present)
145
159
  - **inspect**: Check ACTIVATED code AFTER pull (all types, runs Code Inspector)
146
160
  - **view**: Understand object STRUCTURE (not for debugging errors)
147
161
 
@@ -164,22 +178,25 @@ abapgit-agent pull --files src/zcl_my_class.clas.abap,src/zc_my_view.ddls.asddls
164
178
  └─ Unrelated bug fixes across files? → INDEPENDENT
165
179
 
166
180
  3. For SUPPORTED types (CLAS/INTF/PROG/DDLS):
167
- ├─ INDEPENDENT files → Run syntax → Fix errors → Commit → Push → Pull
181
+ ├─ INDEPENDENT files → Run syntax → [abaplint if enabled] → Fix errors → Commit → Push → Pull
168
182
 
169
183
  └─ DEPENDENT files (NEW objects):
170
184
  ├─ 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
185
+ │ 1. Create underlying object → Syntax → [abaplint] → Commit → Push → Pull
186
+ │ 2. Create dependent object → Syntax (works!) → [abaplint] → Commit → Push → Pull
173
187
  │ ✅ Benefits: Both syntax checks work, cleaner workflow
174
188
 
175
189
  └─ ALTERNATIVE: If interface design uncertain, commit both together
176
- → Skip syntax → Commit both → Push → Pull → (if errors: inspect)
190
+ → Skip syntax → [abaplint] → Commit both → Push → Pull → (if errors: inspect)
177
191
 
178
192
  4. For UNSUPPORTED types (FUGR, TABL, etc.):
179
- Write code → Skip syntax → Commit → Push → Pull → (if errors: inspect)
193
+ Write code → Skip syntax → [abaplint] → Commit → Push → Pull → (if errors: inspect)
180
194
 
181
195
  5. For MIXED types (some supported + some unsupported):
182
- Write all code → Run syntax on independent supported files ONLY → Commit ALL → Push → Pull ALL
196
+ Write all code → Run syntax on independent supported files ONLY → [abaplint] → Commit ALL → Push → Pull ALL
197
+
198
+ [abaplint] = run npx @abaplint/cli .abaplint.json only if .abaplint.json exists in repo root
199
+ before applying any quickfix: run abapgit-agent ref --topic abaplint
183
200
  ```
184
201
 
185
202
  **Example workflows:**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "abapgit-agent",
3
- "version": "1.13.6",
3
+ "version": "1.13.7",
4
4
  "description": "ABAP Git Agent - Pull and activate ABAP code via abapGit from any git repository",
5
5
  "files": [
6
6
  "bin/",
@@ -40,7 +40,18 @@ function getBranch() {
40
40
 
41
41
  const content = fs.readFileSync(headPath, 'utf8').trim();
42
42
  const match = content.match(/ref: refs\/heads\/(.+)/);
43
- return match ? match[1] : 'main';
43
+ if (match) return match[1];
44
+
45
+ // Detached HEAD (e.g. Jenkins checkout) — use Jenkins env vars:
46
+ // CHANGE_BRANCH is set in PR builds (actual head branch name),
47
+ // BRANCH_NAME is set in all builds (branch name or "PR-N" for PRs).
48
+ // For PR builds BRANCH_NAME is "PR-N" so prefer CHANGE_BRANCH first.
49
+ if (process.env.CHANGE_BRANCH) return process.env.CHANGE_BRANCH;
50
+ if (process.env.BRANCH_NAME && !process.env.BRANCH_NAME.startsWith('PR-')) {
51
+ return process.env.BRANCH_NAME;
52
+ }
53
+
54
+ return 'main';
44
55
  }
45
56
 
46
57
  /**