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 +114 -5
- package/abap/guidelines/abaplint-local.md +111 -0
- package/abap/guidelines/abaplint.md +173 -0
- package/abap/guidelines/cds-testing.md +1 -1
- package/abap/guidelines/common-errors.md +31 -0
- package/abap/guidelines/index.md +1 -0
- package/abap/guidelines/probe-poc.md +1 -1
- package/abap/guidelines/run-probe-classes.md +1 -1
- package/abap/guidelines/unit-testable-code.md +28 -24
- package/abap/guidelines/workflow-detailed.md +26 -9
- package/package.json +1 -1
- package/src/utils/git-utils.js +12 -1
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.
|
|
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
|
|
@@ -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
|
package/abap/guidelines/index.md
CHANGED
|
@@ -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
|
|
|
@@ -257,31 +257,11 @@ ENDMETHOD.
|
|
|
257
257
|
|
|
258
258
|
## Test Double Patterns
|
|
259
259
|
|
|
260
|
-
|
|
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
|
-
|
|
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
|
-
└─►
|
|
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
|
|
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
package/src/utils/git-utils.js
CHANGED
|
@@ -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
|
-
|
|
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
|
/**
|