abapgit-agent 1.13.2 → 1.13.4
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 +131 -26
- package/abap/CLAUDE.slim.md +2 -0
- package/abap/guidelines/abapgit.md +233 -44
- package/abap/guidelines/object-creation.md +20 -11
- package/abap/guidelines/objects.md +60 -49
- package/abap/guidelines/probe-poc.md +146 -0
- package/package.json +3 -1
- package/src/commands/pull.js +87 -10
package/abap/CLAUDE.md
CHANGED
|
@@ -70,24 +70,93 @@ abapgit-agent ref --list-topics
|
|
|
70
70
|
```
|
|
71
71
|
|
|
72
72
|
The folder is configured in `.abapGitAgent` (property: `folder`):
|
|
73
|
-
- If `folder` is `/src/` → files go in `src/`
|
|
74
|
-
- If `folder` is `/abap/` → files go in `abap/`
|
|
73
|
+
- If `folder` is `/src/` → files go in `src/`
|
|
74
|
+
- If `folder` is `/abap/` → files go in `abap/`
|
|
75
75
|
|
|
76
76
|
**Also check naming conventions before creating any new object:**
|
|
77
77
|
|
|
78
78
|
```
|
|
79
|
-
1. Check guidelines/objects.local.md ← project
|
|
80
|
-
2.
|
|
79
|
+
1. Check guidelines/objects.local.md ← this project's actual conventions (if file exists)
|
|
80
|
+
2. No objects.local.md? ← customer namespace project, use Z/Y defaults
|
|
81
81
|
```
|
|
82
82
|
|
|
83
|
-
`objects.local.md` is
|
|
83
|
+
`objects.local.md` is never overwritten by updates. It specifies the production naming
|
|
84
|
+
pattern — which may be customer namespace (`ZCL_*`, `YCL_*`), SAP namespace (`CL_*`),
|
|
85
|
+
or SAP registered namespace (`/NAMESPACE/CL_*` — also SAP namespace, not customer).
|
|
86
|
+
Never assume Z/Y prefix without checking.
|
|
87
|
+
|
|
88
|
+
**SAP namespace vs customer namespace:**
|
|
89
|
+
- **Customer namespace**: `Z*`, `Y*` objects; `Z*`, `Y*`, `$*` packages — owned by the customer
|
|
90
|
+
- **SAP namespace**: everything else (`CL_*`, `IF_*`, `/NAMESPACE/*`) — delivered by SAP
|
|
84
91
|
|
|
85
92
|
---
|
|
86
93
|
|
|
87
|
-
### 3.
|
|
94
|
+
### 3. Creating a New ABAP Object — Files to Write and Package Assignment
|
|
88
95
|
|
|
89
|
-
|
|
90
|
-
|
|
96
|
+
```
|
|
97
|
+
❌ WRONG: Only write the .abap source file
|
|
98
|
+
✅ CORRECT: Every object needs both a source file AND an XML metadata file
|
|
99
|
+
XML-only objects (TABL, STRU, DTEL, TTYP) need ONLY the XML file
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
Use the object name from `objects.local.md` (or `objects.md` as fallback) in place of `<name>`:
|
|
103
|
+
|
|
104
|
+
| Object Type | Source File | XML File |
|
|
105
|
+
|-------------|-------------|----------|
|
|
106
|
+
| Class (CLAS) | `<name>.clas.abap` | `<name>.clas.xml` |
|
|
107
|
+
| Interface (INTF) | `<name>.intf.abap` | `<name>.intf.xml` |
|
|
108
|
+
| Program (PROG) | `<name>.prog.abap` | `<name>.prog.xml` |
|
|
109
|
+
| CDS View (DDLS) | `<name>.ddls.asddls` | `<name>.ddls.xml` |
|
|
110
|
+
| Table (TABL) | *(none)* | `<name>.tabl.xml` |
|
|
111
|
+
| Structure (STRU) | *(none)* | `<name>.stru.xml` |
|
|
112
|
+
| Data Element (DTEL) | *(none)* | `<name>.dtel.xml` |
|
|
113
|
+
| Table Type (TTYP) | *(none)* | `<name>.ttyp.xml` |
|
|
114
|
+
|
|
115
|
+
**Package assignment — determine the package, then follow the confirmation rule below:**
|
|
116
|
+
|
|
117
|
+
```
|
|
118
|
+
1. Check objects.local.md for package rules ← use them directly
|
|
119
|
+
2. No package rules in objects.local.md?
|
|
120
|
+
└── Read .abapGitAgent → get the package property → use as root
|
|
121
|
+
Run: abapgit-agent tree --package <root>
|
|
122
|
+
├── Only one package found → use it directly
|
|
123
|
+
└── Multiple packages found → present options, ask user to choose
|
|
124
|
+
3. No package in .abapGitAgent?
|
|
125
|
+
└── Ask the user for the root package
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
**Confirmation before writing files — depends on namespace:**
|
|
129
|
+
|
|
130
|
+
```
|
|
131
|
+
Object name starts with Z* or Y* AND package starts with Z*, Y*, or $*?
|
|
132
|
+
└── Customer namespace object in customer package
|
|
133
|
+
→ Write files directly. No confirmation needed.
|
|
134
|
+
|
|
135
|
+
Anything else (SAP namespace object, or SAP-delivered package)?
|
|
136
|
+
└── Show a creation summary and wait for explicit confirmation:
|
|
137
|
+
|
|
138
|
+
"I'm going to create the following:
|
|
139
|
+
|
|
140
|
+
Object: <NAME> (<Type>)
|
|
141
|
+
Package: <PACKAGE>
|
|
142
|
+
Files: <folder>/<name>.<ext>.abap
|
|
143
|
+
<folder>/<name>.<ext>.xml
|
|
144
|
+
|
|
145
|
+
Shall I proceed?"
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
```
|
|
149
|
+
❌ WRONG: Write files without showing the summary for SAP namespace objects
|
|
150
|
+
❌ WRONG: Run abapgit-agent tree and pick a package yourself
|
|
151
|
+
✅ CORRECT: Customer namespace → write directly
|
|
152
|
+
✅ CORRECT: SAP namespace → always show summary, wait for confirmation
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
> **Tip for project setup**: Add package rules to `objects.local.md` so Claude never
|
|
156
|
+
> needs to ask. See `guidelines/objects.md` for examples.
|
|
157
|
+
|
|
158
|
+
→ For exact XML templates: `abapgit-agent ref --topic abapgit`
|
|
159
|
+
→ For local helper/test-double class files: `abapgit-agent ref --topic object-creation`
|
|
91
160
|
|
|
92
161
|
---
|
|
93
162
|
|
|
@@ -102,14 +171,15 @@ Each ABAP object needs an XML metadata file. Local helper/test-double classes us
|
|
|
102
171
|
|
|
103
172
|
```bash
|
|
104
173
|
# Check syntax of local code (no commit/push needed)
|
|
105
|
-
|
|
106
|
-
abapgit-agent syntax --files src
|
|
174
|
+
# Use the actual filename from your project (name comes from objects.local.md)
|
|
175
|
+
abapgit-agent syntax --files src/<name>.clas.abap
|
|
176
|
+
abapgit-agent syntax --files src/<name>.ddls.asddls
|
|
107
177
|
|
|
108
178
|
# Check multiple INDEPENDENT files
|
|
109
|
-
abapgit-agent syntax --files src
|
|
179
|
+
abapgit-agent syntax --files src/<name1>.clas.abap,src/<name2>.clas.abap
|
|
110
180
|
```
|
|
111
181
|
|
|
112
|
-
**For other types (
|
|
182
|
+
**For other types (FUGR, TABL, etc.)**: Skip syntax, proceed to commit/push/pull.
|
|
113
183
|
|
|
114
184
|
**Why use syntax command?**
|
|
115
185
|
- Catches syntax errors BEFORE polluting git history with fix commits
|
|
@@ -126,11 +196,11 @@ When checking multiple files, each is validated in isolation:
|
|
|
126
196
|
**For dependent files, skip `syntax` and use `pull` instead:**
|
|
127
197
|
```bash
|
|
128
198
|
# ❌ BAD - Interface and implementing class (may show false errors)
|
|
129
|
-
abapgit-agent syntax --files src
|
|
199
|
+
abapgit-agent syntax --files src/<intf_name>.intf.abap,src/<class_name>.clas.abap
|
|
130
200
|
|
|
131
201
|
# ✅ GOOD - Use pull instead for dependent files
|
|
132
202
|
git add . && git commit && git push
|
|
133
|
-
abapgit-agent pull --files src
|
|
203
|
+
abapgit-agent pull --files src/<intf_name>.intf.abap,src/<class_name>.clas.abap
|
|
134
204
|
```
|
|
135
205
|
|
|
136
206
|
**Note**: `inspect` still runs against ABAP system (requires pull first). Use `syntax` for pre-commit checking.
|
|
@@ -256,11 +326,29 @@ After activating a class, stop and tell the user: `"Class is activated. Run with
|
|
|
256
326
|
|
|
257
327
|
---
|
|
258
328
|
|
|
259
|
-
### 10. Probe
|
|
329
|
+
### 10. Probe and PoC Objects — Always Z/Y, Never in SAP Packages
|
|
330
|
+
|
|
331
|
+
```
|
|
332
|
+
❌ WRONG: Create a probe/PoC object with the project's SAP namespace prefix
|
|
333
|
+
❌ WRONG: Assign a probe/PoC object to an SAP-delivered package
|
|
334
|
+
✅ CORRECT: Probe/PoC objects always use Z* or Y* prefix
|
|
335
|
+
✅ CORRECT: Always assign to a customer namespace package (Z*, Y*, or $*)
|
|
336
|
+
```
|
|
337
|
+
|
|
338
|
+
This rule applies even on projects where production objects use SAP namespace (`CL_*`, `/NAMESPACE/*`).
|
|
339
|
+
|
|
340
|
+
**Trigger — when `objects.local.md` shows a SAP namespace prefix (`CL_*`, `IF_*`, `/NAMESPACE/*`)
|
|
341
|
+
and the user asks to create a new object, always ask first:**
|
|
342
|
+
|
|
343
|
+
```
|
|
344
|
+
"Is this a production object, a PoC (will persist, needs its own package/repo),
|
|
345
|
+
or a probe (throwaway, run once)?"
|
|
346
|
+
```
|
|
260
347
|
|
|
261
|
-
|
|
348
|
+
Never assume — wait for the user's answer before proceeding.
|
|
262
349
|
|
|
263
|
-
→
|
|
350
|
+
→ For full decision flow (how to determine namespace, probe vs PoC, scratchWorkspace,
|
|
351
|
+
pocWorkspace, setup instructions): `abapgit-agent ref --topic probe-poc`
|
|
264
352
|
|
|
265
353
|
---
|
|
266
354
|
|
|
@@ -355,11 +443,11 @@ If workflow mode is `"trunk"` or not set, commit directly to the default branch:
|
|
|
355
443
|
```bash
|
|
356
444
|
git checkout main # or master/develop (auto-detected)
|
|
357
445
|
git pull origin main
|
|
358
|
-
edit
|
|
359
|
-
abapgit-agent syntax --files src
|
|
360
|
-
git add . && git commit -m "feat:
|
|
446
|
+
# edit your ABAP file (name from objects.local.md)
|
|
447
|
+
abapgit-agent syntax --files src/<name>.clas.abap
|
|
448
|
+
git add . && git commit -m "feat: description"
|
|
361
449
|
git push origin main
|
|
362
|
-
abapgit-agent pull --files src
|
|
450
|
+
abapgit-agent pull --files src/<name>.clas.abap --sync-xml
|
|
363
451
|
```
|
|
364
452
|
|
|
365
453
|
### AI Tool Guidelines
|
|
@@ -400,7 +488,14 @@ abapgit-agent pull --files src/zcl_auth_handler.clas.abap
|
|
|
400
488
|
2. ✓ Inform the user that run is disabled for this project
|
|
401
489
|
|
|
402
490
|
**When `safeguards.disableProbeClasses = true`:**
|
|
403
|
-
1. ✗ Do not create probe classes in the current project
|
|
491
|
+
1. ✗ Do not create probe classes in the current project
|
|
492
|
+
2. ✓ If `scratchWorkspace` is configured → create probe class there (see Rule 10)
|
|
493
|
+
3. ✗ If `scratchWorkspace` is NOT configured → refuse, tell user to configure it in `.abapGitAgent`
|
|
494
|
+
|
|
495
|
+
**When user requests a PoC object:**
|
|
496
|
+
1. ✓ Read `pocWorkspace.path` from `.abapGitAgent`
|
|
497
|
+
2. ✓ If configured → read `{path}/.abapGitAgent` for package, show confirmation summary, wait for user
|
|
498
|
+
3. ✗ If NOT configured → refuse, tell user to set up a PoC repo and configure `pocWorkspace.path`
|
|
404
499
|
|
|
405
500
|
**When `conflictDetection.mode = "ignore"` or not set:**
|
|
406
501
|
1. ✓ Run `pull` normally — no conflict flags needed
|
|
@@ -425,6 +520,11 @@ abapgit-agent pull --files src/zcl_auth_handler.clas.abap
|
|
|
425
520
|
1. ✗ Do not run `abapgit-agent transport release`
|
|
426
521
|
2. ✓ Inform the user that transport release is disabled for this project
|
|
427
522
|
|
|
523
|
+
**After every pull that creates or modifies ABAP objects:**
|
|
524
|
+
1. ✓ Always pass `--sync-xml` — rewrites any XML metadata files that differ from the ABAP serializer output, amends the commit, and re-pulls so git and the ABAP system stay in sync
|
|
525
|
+
2. ✓ If pull output shows `⚠️ X XML file(s) differ from serializer output`, re-run immediately with `--sync-xml`
|
|
526
|
+
3. ✗ Never leave a pull without `--sync-xml` when you authored the objects — abapGit will show **M (modified)** permanently otherwise
|
|
527
|
+
|
|
428
528
|
---
|
|
429
529
|
|
|
430
530
|
### Quick Decision Tree for AI
|
|
@@ -435,13 +535,17 @@ abapgit-agent pull --files src/zcl_auth_handler.clas.abap
|
|
|
435
535
|
Modified ABAP files?
|
|
436
536
|
├─ CLAS/INTF/PROG/DDLS files?
|
|
437
537
|
│ ├─ Independent files (no cross-dependencies)?
|
|
438
|
-
│ │ └─ ✅ Use: syntax → commit → push → pull
|
|
538
|
+
│ │ └─ ✅ Use: syntax → commit → push → pull --sync-xml
|
|
439
539
|
│ └─ Dependent files (interface + class, class uses class)?
|
|
440
|
-
│ └─ ✅ Use: skip syntax → commit → push → pull
|
|
441
|
-
└─ Other types (
|
|
442
|
-
|
|
540
|
+
│ └─ ✅ Use: skip syntax → commit → push → pull --sync-xml
|
|
541
|
+
└─ Other types (FUGR, TABL, STRU, DTEL, TTYP, etc.)?
|
|
542
|
+
├─ XML-only objects (TABL, STRU, DTEL, TTYP)?
|
|
543
|
+
│ └─ ✅ Use: skip syntax → commit → push → pull --files abap/ztable.tabl.xml --sync-xml
|
|
544
|
+
└─ FUGR and other complex objects?
|
|
545
|
+
└─ ✅ Use: skip syntax → commit → push → pull --sync-xml → (if errors: inspect)
|
|
443
546
|
```
|
|
444
547
|
|
|
548
|
+
→ For creating new objects (what files to write): `abapgit-agent ref --topic object-creation`
|
|
445
549
|
→ See `guidelines/workflow-detailed.md` — run: `abapgit-agent ref --topic workflow-detailed`
|
|
446
550
|
|
|
447
551
|
---
|
|
@@ -474,6 +578,7 @@ Detailed guidelines are available in the `guidelines/` folder:
|
|
|
474
578
|
| `guidelines/debug-session.md` | Debug Session Guide |
|
|
475
579
|
| `guidelines/debug-dump.md` | Dump Analysis Guide |
|
|
476
580
|
| `guidelines/run-probe-classes.md` | run Command — AI Guidelines (probe classes, scratchWorkspace) |
|
|
581
|
+
| `guidelines/probe-poc.md` | Probe and PoC — Full Decision Flow |
|
|
477
582
|
| `guidelines/branch-workflow.md` | Branch Workflow |
|
|
478
583
|
| `guidelines/workflow-detailed.md` | Development Workflow (Detailed) |
|
|
479
584
|
| `guidelines/object-creation.md` | Object Creation (XML metadata, local classes) |
|
package/abap/CLAUDE.slim.md
CHANGED
|
@@ -10,6 +10,8 @@ Read the full ABAP development guide by running:
|
|
|
10
10
|
abapgit-agent guide
|
|
11
11
|
```
|
|
12
12
|
|
|
13
|
+
**Never pipe `abapgit-agent guide` or `abapgit-agent ref` through `head`, `tail`, or any other truncation command. Always read the full output.**
|
|
14
|
+
|
|
13
15
|
This guide covers: development workflow, ABAP syntax guidelines, object naming, unit testing, and debugging.
|
|
14
16
|
|
|
15
17
|
> **Humans:** Full guide online at https://sylvoscai.github.io/abapgit-agent/pages/abap-coding-guidelines.html
|
|
@@ -19,23 +19,23 @@ Class | zcl_*.clas.abap | zcl_*.clas.xml
|
|
|
19
19
|
Test Class | zcl_*.clas.testclasses.abap | zcl_*.clas.xml
|
|
20
20
|
Interface | zif_*.intf.abap | zif_*.intf.xml
|
|
21
21
|
Program | z*.prog.abap | z*.prog.xml
|
|
22
|
-
Table | z*.tabl.abap | z*.tabl.xml
|
|
23
22
|
CDS View (DDLS) | zc_*.ddls.asddls | zc_*.ddls.xml
|
|
24
|
-
|
|
25
|
-
Structure
|
|
26
|
-
|
|
23
|
+
Table (TABL) | (no .abap file) | z*.tabl.xml
|
|
24
|
+
Structure (STRU) | (no .abap file) | z*.stru.xml
|
|
25
|
+
Data Element (DTEL)| (no .abap file) | z*.dtel.xml
|
|
26
|
+
Table Type (TTYP) | (no .abap file) | z*.ttyp.xml
|
|
27
27
|
```
|
|
28
28
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
29
|
+
> **XML-only objects (TABL, STRU, DTEL, TTYP)** have **no ABAP source file**. abapGit serializes
|
|
30
|
+
> them as XML metadata only. When using `--files`, pass the `.xml` file directly:
|
|
31
|
+
> `abapgit-agent pull --files abap/zmy_table.tabl.xml --sync-xml`
|
|
32
|
+
|
|
33
|
+
> **CRITICAL: Always write XML files with a UTF-8 BOM (`\ufeff`) as the very first character**, before `<?xml ...`.
|
|
34
|
+
> Without the BOM, abapGit shows the object as **"M" (modified)** after every pull because the
|
|
35
|
+
> serializer always produces XML with BOM — and every byte matters.
|
|
36
|
+
|
|
37
|
+
> **CRITICAL: Only include fields that abapGit's serializer actually writes. Never add fields with
|
|
38
|
+
> default values.** Extra fields cause a permanent "M" (modified) diff. Follow the exact templates below.
|
|
39
39
|
|
|
40
40
|
**Searchable keywords**: class xml, interface xml, table xml, cds xml, test class, exposure, serializer, abapgit
|
|
41
41
|
|
|
@@ -46,14 +46,50 @@ abapGit needs XML files to:
|
|
|
46
46
|
- Store object attributes (description, exposure, state, etc.)
|
|
47
47
|
- Handle object-specific configurations
|
|
48
48
|
|
|
49
|
+
## Field Presence Rules (CRITICAL)
|
|
50
|
+
|
|
51
|
+
abapGit's serializer **omits fields that have their default value**. Writing extra fields causes permanent
|
|
52
|
+
"M" (modified) status in abapGit UI. Follow these rules strictly:
|
|
53
|
+
|
|
54
|
+
### CLAS — Field Presence Rules
|
|
55
|
+
|
|
56
|
+
| Field | Include when | Omit when |
|
|
57
|
+
|---|---|---|
|
|
58
|
+
| `CLSNAME` | Always | — |
|
|
59
|
+
| `LANGU` | Always | — |
|
|
60
|
+
| `DESCRIPT` | Always | — |
|
|
61
|
+
| `CATEGORY` | Non-standard class (`40`=exception, `05`=test double) | Standard class (default `00`) — **omit** |
|
|
62
|
+
| `EXPOSURE` | **Never for CLAS** | **Always omit** — public (`2`) is the default and is never written |
|
|
63
|
+
| `STATE` | Always (`1`) | — |
|
|
64
|
+
| `CLSCCINCL` | `.clas.locals_def.abap` file exists | No local class files — **omit** |
|
|
65
|
+
| `FIXPT` | Always (`X`) | — |
|
|
66
|
+
| `UNICODE` | Always (`X`) | — |
|
|
67
|
+
| `WITH_UNIT_TESTS` | `.clas.testclasses.abap` file exists | No test class file — **omit** |
|
|
68
|
+
| `MSG_ID` | Class has a message class | No message class — **omit** |
|
|
69
|
+
|
|
70
|
+
**Field order**: `CLSNAME → LANGU → DESCRIPT → [CATEGORY] → STATE → [CLSCCINCL] → FIXPT → UNICODE → [WITH_UNIT_TESTS] → [MSG_ID]`
|
|
71
|
+
|
|
72
|
+
### INTF — Field Presence Rules
|
|
73
|
+
|
|
74
|
+
| Field | Include when | Omit when |
|
|
75
|
+
|---|---|---|
|
|
76
|
+
| `CLSNAME` | Always | — |
|
|
77
|
+
| `LANGU` | Always | — |
|
|
78
|
+
| `DESCRIPT` | Always | — |
|
|
79
|
+
| `EXPOSURE` | Always (`2`) | — (interfaces always have EXPOSURE, unlike classes) |
|
|
80
|
+
| `STATE` | Always (`1`) | — |
|
|
81
|
+
| `UNICODE` | Always (`X`) | — |
|
|
82
|
+
|
|
49
83
|
## Object Types and XML Templates
|
|
50
84
|
|
|
51
85
|
### Class (CLAS)
|
|
52
86
|
|
|
53
87
|
**Filename**: `src/zcl_my_class.clas.xml`
|
|
54
88
|
|
|
89
|
+
**Standard public class** (no local includes, no test class):
|
|
90
|
+
|
|
55
91
|
```xml
|
|
56
|
-
<?xml version="1.0" encoding="utf-8"?>
|
|
92
|
+
<?xml version="1.0" encoding="utf-8"?>
|
|
57
93
|
<abapGit version="v1.0.0" serializer="LCL_OBJECT_CLAS" serializer_version="v1.0.0">
|
|
58
94
|
<asx:abap xmlns:asx="http://www.sap.com/abapxml" version="1.0">
|
|
59
95
|
<asx:values>
|
|
@@ -61,29 +97,85 @@ abapGit needs XML files to:
|
|
|
61
97
|
<CLSNAME>ZCL_MY_CLASS</CLSNAME>
|
|
62
98
|
<LANGU>E</LANGU>
|
|
63
99
|
<DESCRIPT>Description of the class</DESCRIPT>
|
|
64
|
-
<EXPOSURE>2</EXPOSURE>
|
|
65
100
|
<STATE>1</STATE>
|
|
101
|
+
<FIXPT>X</FIXPT>
|
|
66
102
|
<UNICODE>X</UNICODE>
|
|
103
|
+
</VSEOCLASS>
|
|
104
|
+
</asx:values>
|
|
105
|
+
</asx:abap>
|
|
106
|
+
</abapGit>
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
**Class with test class** (`.clas.testclasses.abap` exists — add `WITH_UNIT_TESTS`):
|
|
110
|
+
|
|
111
|
+
```xml
|
|
112
|
+
<?xml version="1.0" encoding="utf-8"?>
|
|
113
|
+
<abapGit version="v1.0.0" serializer="LCL_OBJECT_CLAS" serializer_version="v1.0.0">
|
|
114
|
+
<asx:abap xmlns:asx="http://www.sap.com/abapxml" version="1.0">
|
|
115
|
+
<asx:values>
|
|
116
|
+
<VSEOCLASS>
|
|
117
|
+
<CLSNAME>ZCL_MY_CLASS</CLSNAME>
|
|
118
|
+
<LANGU>E</LANGU>
|
|
119
|
+
<DESCRIPT>Description of the class</DESCRIPT>
|
|
120
|
+
<STATE>1</STATE>
|
|
67
121
|
<FIXPT>X</FIXPT>
|
|
122
|
+
<UNICODE>X</UNICODE>
|
|
123
|
+
<WITH_UNIT_TESTS>X</WITH_UNIT_TESTS>
|
|
68
124
|
</VSEOCLASS>
|
|
69
125
|
</asx:values>
|
|
70
126
|
</asx:abap>
|
|
71
127
|
</abapGit>
|
|
72
128
|
```
|
|
73
129
|
|
|
74
|
-
**
|
|
75
|
-
- `CLSNAME`: Class name (must match filename)
|
|
76
|
-
- `DESCRIPT`: Class description
|
|
77
|
-
- `EXPOSURE`: Exposure (2 = Public, 3 = Protected, 4 = Private)
|
|
78
|
-
- `STATE`: State (1 = Active)
|
|
79
|
-
- `UNICODE`: Unicode encoding (X = Yes)
|
|
80
|
-
- `FIXPT`: Fixed-point arithmetic (X = Yes) - **Always include for correct decimal arithmetic**
|
|
130
|
+
**Class with local includes** (`.clas.locals_def.abap` exists — add `CLSCCINCL` before `FIXPT`):
|
|
81
131
|
|
|
82
|
-
|
|
132
|
+
```xml
|
|
133
|
+
<?xml version="1.0" encoding="utf-8"?>
|
|
134
|
+
<abapGit version="v1.0.0" serializer="LCL_OBJECT_CLAS" serializer_version="v1.0.0">
|
|
135
|
+
<asx:abap xmlns:asx="http://www.sap.com/abapxml" version="1.0">
|
|
136
|
+
<asx:values>
|
|
137
|
+
<VSEOCLASS>
|
|
138
|
+
<CLSNAME>ZCL_MY_CLASS</CLSNAME>
|
|
139
|
+
<LANGU>E</LANGU>
|
|
140
|
+
<DESCRIPT>Description of the class</DESCRIPT>
|
|
141
|
+
<STATE>1</STATE>
|
|
142
|
+
<CLSCCINCL>X</CLSCCINCL>
|
|
143
|
+
<FIXPT>X</FIXPT>
|
|
144
|
+
<UNICODE>X</UNICODE>
|
|
145
|
+
<WITH_UNIT_TESTS>X</WITH_UNIT_TESTS>
|
|
146
|
+
</VSEOCLASS>
|
|
147
|
+
</asx:values>
|
|
148
|
+
</asx:abap>
|
|
149
|
+
</abapGit>
|
|
150
|
+
```
|
|
83
151
|
|
|
84
|
-
**
|
|
85
|
-
|
|
86
|
-
|
|
152
|
+
**Exception class** (`CATEGORY>40` — add `CATEGORY` after `DESCRIPT`):
|
|
153
|
+
|
|
154
|
+
```xml
|
|
155
|
+
<?xml version="1.0" encoding="utf-8"?>
|
|
156
|
+
<abapGit version="v1.0.0" serializer="LCL_OBJECT_CLAS" serializer_version="v1.0.0">
|
|
157
|
+
<asx:abap xmlns:asx="http://www.sap.com/abapxml" version="1.0">
|
|
158
|
+
<asx:values>
|
|
159
|
+
<VSEOCLASS>
|
|
160
|
+
<CLSNAME>ZCX_MY_EXCEPTION</CLSNAME>
|
|
161
|
+
<LANGU>E</LANGU>
|
|
162
|
+
<DESCRIPT>My exception</DESCRIPT>
|
|
163
|
+
<CATEGORY>40</CATEGORY>
|
|
164
|
+
<STATE>1</STATE>
|
|
165
|
+
<CLSCCINCL>X</CLSCCINCL>
|
|
166
|
+
<FIXPT>X</FIXPT>
|
|
167
|
+
<UNICODE>X</UNICODE>
|
|
168
|
+
</VSEOCLASS>
|
|
169
|
+
</asx:values>
|
|
170
|
+
</asx:abap>
|
|
171
|
+
</abapGit>
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
**Key rules**:
|
|
175
|
+
- ❌ **Never include `<EXPOSURE>`** in a CLAS XML — public (2) is the default and abapGit omits it
|
|
176
|
+
- ✅ Always include `<FIXPT>X</FIXPT>` and `<UNICODE>X</UNICODE>`
|
|
177
|
+
- ✅ Add `<WITH_UNIT_TESTS>X</WITH_UNIT_TESTS>` only when `.clas.testclasses.abap` exists
|
|
178
|
+
- ✅ Add `<CLSCCINCL>X</CLSCCINCL>` only when `.clas.locals_def.abap` exists
|
|
87
179
|
|
|
88
180
|
**Local Class Files**:
|
|
89
181
|
| File | Purpose |
|
|
@@ -98,7 +190,7 @@ abapGit needs XML files to:
|
|
|
98
190
|
**Filename**: `src/zif_my_interface.intf.xml`
|
|
99
191
|
|
|
100
192
|
```xml
|
|
101
|
-
<?xml version="1.0" encoding="utf-8"?>
|
|
193
|
+
<?xml version="1.0" encoding="utf-8"?>
|
|
102
194
|
<abapGit version="v1.0.0" serializer="LCL_OBJECT_INTF" serializer_version="v1.0.0">
|
|
103
195
|
<asx:abap xmlns:asx="http://www.sap.com/abapxml" version="1.0">
|
|
104
196
|
<asx:values>
|
|
@@ -115,6 +207,9 @@ abapGit needs XML files to:
|
|
|
115
207
|
</abapGit>
|
|
116
208
|
```
|
|
117
209
|
|
|
210
|
+
**Key rules**:
|
|
211
|
+
- ✅ `<EXPOSURE>2</EXPOSURE>` is **always present** for interfaces (unlike classes where it is omitted)
|
|
212
|
+
|
|
118
213
|
---
|
|
119
214
|
|
|
120
215
|
### Program (PROG)
|
|
@@ -122,13 +217,13 @@ abapGit needs XML files to:
|
|
|
122
217
|
**Filename**: `src/zmy_program.prog.xml`
|
|
123
218
|
|
|
124
219
|
```xml
|
|
125
|
-
<?xml version="1.0" encoding="utf-8"?>
|
|
220
|
+
<?xml version="1.0" encoding="utf-8"?>
|
|
126
221
|
<abapGit version="v1.0.0" serializer="LCL_OBJECT_PROG" serializer_version="v1.0.0">
|
|
127
222
|
<asx:abap xmlns:asx="http://www.sap.com/abapxml" version="1.0">
|
|
128
223
|
<asx:values>
|
|
129
224
|
<PROGDIR>
|
|
130
225
|
<NAME>ZMY_PROGRAM</NAME>
|
|
131
|
-
<SUBC>
|
|
226
|
+
<SUBC>1</SUBC>
|
|
132
227
|
<RLOAD>E</RLOAD>
|
|
133
228
|
<FIXPT>X</FIXPT>
|
|
134
229
|
<UCCHECK>X</UCCHECK>
|
|
@@ -140,8 +235,12 @@ abapGit needs XML files to:
|
|
|
140
235
|
|
|
141
236
|
**Key Fields**:
|
|
142
237
|
- `NAME`: Program name
|
|
143
|
-
- `SUBC`:
|
|
144
|
-
- `RLOAD`:
|
|
238
|
+
- `SUBC`: Program type (`1`=Executable, `I`=Include, `F`=Function Group, `M`=Module Pool, `S`=Subroutine Pool)
|
|
239
|
+
- `RLOAD`: `E`=External
|
|
240
|
+
- `FIXPT`: Fixed-point arithmetic (`X`=Yes) — include for executables
|
|
241
|
+
- `UCCHECK`: Unicode checks active (`X`=Yes)
|
|
242
|
+
|
|
243
|
+
**Note**: The serializer may also write a `<TPOOL>` section after `<PROGDIR>` if the program has a title text. You do not need to write this when creating new programs — abapGit will add it on the next pull if needed.
|
|
145
244
|
|
|
146
245
|
---
|
|
147
246
|
|
|
@@ -149,8 +248,10 @@ abapGit needs XML files to:
|
|
|
149
248
|
|
|
150
249
|
**Filename**: `src/zmy_table.tabl.xml`
|
|
151
250
|
|
|
251
|
+
> **XML-only object** — no `.abap` source file. Pull with: `pull --files src/zmy_table.tabl.xml`
|
|
252
|
+
|
|
152
253
|
```xml
|
|
153
|
-
<?xml version="1.0" encoding="utf-8"?>
|
|
254
|
+
<?xml version="1.0" encoding="utf-8"?>
|
|
154
255
|
<abapGit version="v1.0.0" serializer="LCL_OBJECT_TABL" serializer_version="v1.0.0">
|
|
155
256
|
<asx:abap xmlns:asx="http://www.sap.com/abapxml" version="1.0">
|
|
156
257
|
<asx:values>
|
|
@@ -168,9 +269,20 @@ abapGit needs XML files to:
|
|
|
168
269
|
|
|
169
270
|
**Key Fields**:
|
|
170
271
|
- `TABNAME`: Table name
|
|
171
|
-
- `DDTEXT`: Description (
|
|
172
|
-
- `TABCLASS`:
|
|
173
|
-
- `CONTFLAG`: Delivery class
|
|
272
|
+
- `DDTEXT`: Description (**not** `DESCRIPT`)
|
|
273
|
+
- `TABCLASS`: `TRANSP`=Transparent (most common), `POOL`, `CLUSTER`
|
|
274
|
+
- `CONTFLAG`: Delivery class — `A`=Application, `C`=Customizing, `S`=System, `G`=Customizing protected
|
|
275
|
+
|
|
276
|
+
**Note**: When abapGit serializes an existing table it also writes `<DD09L>` (technical settings) and `<DD03P_TABLE>` (field definitions). These sections are generated automatically from the ABAP Dictionary on pull — you only need the `<DD02V>` header when creating a new table. After the first pull the XML will be expanded with those sections.
|
|
277
|
+
|
|
278
|
+
**`DD03P` field-level rules** (apply when editing an existing table XML that includes `<DD03P_TABLE>`):
|
|
279
|
+
|
|
280
|
+
| Rule | Detail |
|
|
281
|
+
|---|---|
|
|
282
|
+
| `SHLPORIGIN` | Include `<SHLPORIGIN>D</SHLPORIGIN>` on fields where the Dictionary provides a value help (e.g. fields with a domain that has fixed values or a search help). Omit on fields with no value help. |
|
|
283
|
+
| Field order for raw-type fields | For fields with no `ROLLNAME` (raw type, e.g. `CHAR`, `NUMC`), the serializer writes `<MASK>` **before** `<DDTEXT>`. For fields with a `ROLLNAME`, only `ROLLNAME` appears (no `MASK` or `DDTEXT`). |
|
|
284
|
+
|
|
285
|
+
**Why this matters**: Missing `SHLPORIGIN` or wrong `MASK`/`DDTEXT` order causes a permanent diff between git and the system-serialized XML.
|
|
174
286
|
|
|
175
287
|
---
|
|
176
288
|
|
|
@@ -181,7 +293,7 @@ abapGit needs XML files to:
|
|
|
181
293
|
The XML format is identical for both types — only `SOURCE_TYPE` differs:
|
|
182
294
|
|
|
183
295
|
```xml
|
|
184
|
-
<?xml version="1.0" encoding="utf-8"?>
|
|
296
|
+
<?xml version="1.0" encoding="utf-8"?>
|
|
185
297
|
<abapGit version="v1.0.0" serializer="LCL_OBJECT_DDLS" serializer_version="v1.0.0">
|
|
186
298
|
<asx:abap xmlns:asx="http://www.sap.com/abapxml" version="1.0">
|
|
187
299
|
<asx:values>
|
|
@@ -207,8 +319,10 @@ The XML format is identical for both types — only `SOURCE_TYPE` differs:
|
|
|
207
319
|
|
|
208
320
|
**Filename**: `src/zmy_dtel.dtel.xml`
|
|
209
321
|
|
|
322
|
+
> **XML-only object** — no `.abap` source file. Pull with: `pull --files src/zmy_dtel.dtel.xml`
|
|
323
|
+
|
|
210
324
|
```xml
|
|
211
|
-
<?xml version="1.0" encoding="utf-8"?>
|
|
325
|
+
<?xml version="1.0" encoding="utf-8"?>
|
|
212
326
|
<abapGit version="v1.0.0" serializer="LCL_OBJECT_DTEL" serializer_version="v1.0.0">
|
|
213
327
|
<asx:abap xmlns:asx="http://www.sap.com/abapxml" version="1.0">
|
|
214
328
|
<asx:values>
|
|
@@ -217,9 +331,9 @@ The XML format is identical for both types — only `SOURCE_TYPE` differs:
|
|
|
217
331
|
<DDLANGUAGE>E</DDLANGUAGE>
|
|
218
332
|
<DDTEXT>Description of data element</DDTEXT>
|
|
219
333
|
<REPTEXT>Description</REPTEXT>
|
|
220
|
-
<SCRTEXT_S>Short</SCRTEXT_S>
|
|
221
|
-
<SCRTEXT_M>Medium</SCRTEXT_M>
|
|
222
|
-
<SCRTEXT_L>Long
|
|
334
|
+
<SCRTEXT_S>Short text</SCRTEXT_S>
|
|
335
|
+
<SCRTEXT_M>Medium text</SCRTEXT_M>
|
|
336
|
+
<SCRTEXT_L>Long description text</SCRTEXT_L>
|
|
223
337
|
<DTELMASTER>E</DTELMASTER>
|
|
224
338
|
<DATATYPE>CHAR</DATATYPE>
|
|
225
339
|
<LENG>000010</LENG>
|
|
@@ -231,9 +345,84 @@ The XML format is identical for both types — only `SOURCE_TYPE` differs:
|
|
|
231
345
|
|
|
232
346
|
**Key Fields**:
|
|
233
347
|
- `ROLLNAME`: Data element name
|
|
234
|
-
- `DDTEXT`: Description (
|
|
235
|
-
- `
|
|
236
|
-
- `
|
|
348
|
+
- `DDTEXT`: Description (**not** `DESCRIPT`)
|
|
349
|
+
- `REPTEXT` / `SCRTEXT_S` / `SCRTEXT_M` / `SCRTEXT_L`: Field labels (report heading, short, medium, long)
|
|
350
|
+
- `DTELMASTER`: Language key for label master (`E` for English)
|
|
351
|
+
- `DATATYPE`: Data type (`CHAR`, `NUMC`, `DATS`, `TIMS`, `INT4`, etc.)
|
|
352
|
+
- `LENG`: Length padded to 6 digits (e.g. `000010` for 10 characters)
|
|
353
|
+
|
|
354
|
+
**Omit `<PARAMID>`** unless you specifically need a SET/GET parameter ID — the serializer omits it when empty, so including an empty tag causes a permanent diff.
|
|
355
|
+
|
|
356
|
+
---
|
|
357
|
+
|
|
358
|
+
### Structure (STRU)
|
|
359
|
+
|
|
360
|
+
**Filename**: `src/zmy_struct.stru.xml`
|
|
361
|
+
|
|
362
|
+
> **XML-only object** — no `.abap` source file. abapGit uses the same TABL serializer for STRU.
|
|
363
|
+
> Pull with: `pull --files src/zmy_struct.stru.xml`
|
|
364
|
+
|
|
365
|
+
```xml
|
|
366
|
+
<?xml version="1.0" encoding="utf-8"?>
|
|
367
|
+
<abapGit version="v1.0.0" serializer="LCL_OBJECT_TABL" serializer_version="v1.0.0">
|
|
368
|
+
<asx:abap xmlns:asx="http://www.sap.com/abapxml" version="1.0">
|
|
369
|
+
<asx:values>
|
|
370
|
+
<DD02V>
|
|
371
|
+
<TABNAME>ZMY_STRUCT</TABNAME>
|
|
372
|
+
<DDLANGUAGE>E</DDLANGUAGE>
|
|
373
|
+
<TABCLASS>INTTAB</TABCLASS>
|
|
374
|
+
<DDTEXT>Description of the structure</DDTEXT>
|
|
375
|
+
<CONTFLAG>A</CONTFLAG>
|
|
376
|
+
</DD02V>
|
|
377
|
+
</asx:values>
|
|
378
|
+
</asx:abap>
|
|
379
|
+
</abapGit>
|
|
380
|
+
```
|
|
381
|
+
|
|
382
|
+
**Key difference from TABL**: `TABCLASS` is `INTTAB` (internal table / structure) instead of `TRANSP`.
|
|
383
|
+
|
|
384
|
+
**Note**: Like TABL, after the first pull abapGit expands the XML with `<DD03P_TABLE>` field definitions. When creating a new structure you only need the `<DD02V>` header.
|
|
385
|
+
|
|
386
|
+
---
|
|
387
|
+
|
|
388
|
+
### Table Type (TTYP)
|
|
389
|
+
|
|
390
|
+
**Filename**: `src/zmy_ttyp.ttyp.xml`
|
|
391
|
+
|
|
392
|
+
> **XML-only object** — no `.abap` source file.
|
|
393
|
+
> Pull with: `pull --files src/zmy_ttyp.ttyp.xml`
|
|
394
|
+
|
|
395
|
+
```xml
|
|
396
|
+
<?xml version="1.0" encoding="utf-8"?>
|
|
397
|
+
<abapGit version="v1.0.0" serializer="LCL_OBJECT_TTYP" serializer_version="v1.0.0">
|
|
398
|
+
<asx:abap xmlns:asx="http://www.sap.com/abapxml" version="1.0">
|
|
399
|
+
<asx:values>
|
|
400
|
+
<DD40V>
|
|
401
|
+
<TYPENAME>ZMY_TTYP</TYPENAME>
|
|
402
|
+
<DDLANGUAGE>E</DDLANGUAGE>
|
|
403
|
+
<DDTEXT>Description of table type</DDTEXT>
|
|
404
|
+
<ROWTYPE>ZMY_STRUCT</ROWTYPE>
|
|
405
|
+
<ROWKIND>S</ROWKIND>
|
|
406
|
+
<DATATYPE>TABLE_T</DATATYPE>
|
|
407
|
+
<ACCESSMODE>T</ACCESSMODE>
|
|
408
|
+
<KEYDEF>D</KEYDEF>
|
|
409
|
+
<KEYKIND>N</KEYKIND>
|
|
410
|
+
</DD40V>
|
|
411
|
+
</asx:values>
|
|
412
|
+
</asx:abap>
|
|
413
|
+
</abapGit>
|
|
414
|
+
```
|
|
415
|
+
|
|
416
|
+
**Key Fields**:
|
|
417
|
+
- `TYPENAME`: Table type name
|
|
418
|
+
- `ROWTYPE`: Row type (a structure or data element name)
|
|
419
|
+
- `ROWKIND`: Row kind — `S`=Structure/Type, `D`=Data element, `R`=Reference
|
|
420
|
+
- `DATATYPE`: Always `TABLE_T` for table types
|
|
421
|
+
- `ACCESSMODE`: Table kind — `T`=Standard, `S`=Sorted, `H`=Hashed
|
|
422
|
+
- `KEYDEF`: Key definition — `D`=Default (standard key), `K`=User-defined
|
|
423
|
+
- `KEYKIND`: Key uniqueness — `N`=Non-unique, `U`=Unique
|
|
424
|
+
|
|
425
|
+
**Note**: After the first pull abapGit may expand the XML with `<DD42V>` (component definitions) if key fields are explicitly defined.
|
|
237
426
|
|
|
238
427
|
---
|
|
239
428
|
|
|
@@ -12,14 +12,23 @@ grand_parent: ABAP Development
|
|
|
12
12
|
|
|
13
13
|
**Each ABAP object requires an XML metadata file for abapGit to understand how to handle it.**
|
|
14
14
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
|
19
|
-
|
|
20
|
-
|
|
|
21
|
-
|
|
|
22
|
-
|
|
|
15
|
+
Replace `<name>` with the actual object name from this project's naming conventions
|
|
16
|
+
(`guidelines/objects.local.md`, or `guidelines/objects.md` as fallback).
|
|
17
|
+
|
|
18
|
+
| Object Type | ABAP Source File | XML File | Details |
|
|
19
|
+
|-------------|-----------------|----------|---------|
|
|
20
|
+
| Class | `<name>.clas.abap` | `<name>.clas.xml` | See `guidelines/abapgit.md` |
|
|
21
|
+
| Interface | `<name>.intf.abap` | `<name>.intf.xml` | See `guidelines/abapgit.md` |
|
|
22
|
+
| Program | `<name>.prog.abap` | `<name>.prog.xml` | See `guidelines/abapgit.md` |
|
|
23
|
+
| **CDS View Entity** | `<name>.ddls.asddls` | `<name>.ddls.xml` | **Use by default** - See `guidelines/cds.md` |
|
|
24
|
+
| CDS View (legacy) | `<name>.ddls.asddls` | `<name>.ddls.xml` | Only if explicitly requested - See `guidelines/cds.md` |
|
|
25
|
+
| Table (TABL) | *(none — XML-only)* | `<name>.tabl.xml` | See `guidelines/abapgit.md` |
|
|
26
|
+
| Structure (STRU) | *(none — XML-only)* | `<name>.stru.xml` | See `guidelines/abapgit.md` |
|
|
27
|
+
| Data Element (DTEL) | *(none — XML-only)* | `<name>.dtel.xml` | See `guidelines/abapgit.md` |
|
|
28
|
+
| Table Type (TTYP) | *(none — XML-only)* | `<name>.ttyp.xml` | See `guidelines/abapgit.md` |
|
|
29
|
+
|
|
30
|
+
> **XML-only objects (TABL, STRU, DTEL, TTYP)**: create only the `.xml` file — there is no `.abap` source file.
|
|
31
|
+
> After committing and pushing, pull with: `pull --files <folder>/<name>.tabl.xml --sync-xml`
|
|
23
32
|
|
|
24
33
|
**IMPORTANT: When user says "create CDS view", create CDS View Entity by default.**
|
|
25
34
|
|
|
@@ -37,14 +46,14 @@ When a class needs local helper classes or test doubles, use separate files:
|
|
|
37
46
|
|
|
38
47
|
| File | Purpose |
|
|
39
48
|
|------|---------|
|
|
40
|
-
|
|
|
41
|
-
|
|
|
49
|
+
| `<name>.clas.locals_def.abap` | Local class definitions |
|
|
50
|
+
| `<name>.clas.locals_imp.abap` | Local class implementations |
|
|
42
51
|
|
|
43
52
|
**XML Configuration**: Add `<CLSCCINCL>X</CLSCCINCL>` to the class XML to include local class definitions:
|
|
44
53
|
|
|
45
54
|
```xml
|
|
46
55
|
<VSEOCLASS>
|
|
47
|
-
<CLSNAME>
|
|
56
|
+
<CLSNAME>MY_CLASS_NAME</CLSNAME>
|
|
48
57
|
...
|
|
49
58
|
<CLSCCINCL>X</CLSCCINCL>
|
|
50
59
|
</VSEOCLASS>
|
|
@@ -8,67 +8,78 @@ grand_parent: ABAP Development
|
|
|
8
8
|
|
|
9
9
|
# ABAP Object Naming Conventions
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
> That file is never overwritten by `abapgit-agent init --update` and is searched by the `ref` command.
|
|
11
|
+
**Searchable keywords**: naming convention, prefix, namespace, object type, CLAS, INTF, PROG, TABL, DDLS, SAP namespace, customer namespace, PoC, probe
|
|
13
12
|
|
|
14
|
-
|
|
13
|
+
## SAP Namespace vs Customer Namespace
|
|
15
14
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
15
|
+
| | SAP Namespace | Customer Namespace |
|
|
16
|
+
|---|---|---|
|
|
17
|
+
| **Object prefix** | `CL_*`, `IF_*`, `/NAME/CL_*`, `/NAME/IF_*`, etc. | `Z*`, `Y*` |
|
|
18
|
+
| **Package prefix** | SAP-delivered (e.g. `SFIN`, `CA_*`, `/NAME/*`) | `Z*`, `Y*`, `$*` |
|
|
19
|
+
| **Ownership** | Delivered and maintained by SAP | Owned by the customer |
|
|
20
|
+
| **In git repo** | Objects from an SAP-delivered package | Custom development objects |
|
|
20
21
|
|
|
21
|
-
|
|
22
|
+
> **Rule**: Never add customer-created objects (including PoC/probe classes) into SAP namespace
|
|
23
|
+
> packages. PoC objects always use `Z*`/`Y*` prefix and always go in a `Z*`, `Y*`, or `$*` package
|
|
24
|
+
> — even on a project where production objects use SAP namespace.
|
|
22
25
|
|
|
23
|
-
|
|
26
|
+
## How to Determine This Project's Naming Convention
|
|
24
27
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
| Program | Z | ZMY_PROGRAM |
|
|
30
|
-
| Package | $ | $MY_PACKAGE |
|
|
31
|
-
| Table | Z | ZMY_TABLE |
|
|
32
|
-
| CDS View | ZC | ZC_MY_VIEW |
|
|
33
|
-
| CDS Entity | ZE | ZE_MY_ENTITY |
|
|
34
|
-
| Data Element | Z | ZMY_ELEMENT |
|
|
35
|
-
| Structure | Z | ZMY_STRUCTURE |
|
|
36
|
-
| Table Type | Z | ZMY_TABLE_TYPE |
|
|
28
|
+
```
|
|
29
|
+
1. Check guidelines/objects.local.md ← this project's actual conventions (always check first)
|
|
30
|
+
2. No objects.local.md exists? ← assume customer namespace project, use Z/Y defaults below
|
|
31
|
+
```
|
|
37
32
|
|
|
38
|
-
|
|
33
|
+
`objects.local.md` is never overwritten by `abapgit-agent init --update`. It specifies the
|
|
34
|
+
naming pattern for production objects in this project — which could be customer namespace
|
|
35
|
+
(`ZCL_*`, `YCL_*`) or SAP namespace (`CL_*`, `/NAMESPACE/CL_*`).
|
|
39
36
|
|
|
40
|
-
|
|
37
|
+
## Default Naming Conventions (Z/Y customer namespace)
|
|
41
38
|
|
|
42
|
-
|
|
43
|
-
|------|-------------|-------------|
|
|
44
|
-
| CLAS | Classes | .clas.abap |
|
|
45
|
-
| PROG | Programs | .prog.abap |
|
|
46
|
-
| FUGR | Function Groups | .fugr.abap |
|
|
47
|
-
| INTF | Interfaces | .intf.abap |
|
|
48
|
-
| TABL | Tables | .tabl.abap |
|
|
49
|
-
| STRU | Structures | .stru.abap |
|
|
50
|
-
| DTEL | Data Elements | .dtel.abap |
|
|
51
|
-
| TTYP | Table Types | .ttyp.abap |
|
|
52
|
-
| DDLS | CDS Views | .ddls.asddls |
|
|
53
|
-
| DDLX | CDS Entities | .ddlx.asddlx |
|
|
39
|
+
Applied when no `objects.local.md` exists:
|
|
54
40
|
|
|
55
|
-
|
|
41
|
+
| Object Type | Default Prefix | Default Example |
|
|
42
|
+
|-------------|---------------|-----------------|
|
|
43
|
+
| Class | `ZCL_` | `ZCL_MY_CLASS` |
|
|
44
|
+
| Interface | `ZIF_` | `ZIF_MY_INTERFACE` |
|
|
45
|
+
| Program | `Z` | `ZMY_PROGRAM` |
|
|
46
|
+
| Package | `$` | `$MY_PACKAGE` |
|
|
47
|
+
| Table | `Z` | `ZMY_TABLE` |
|
|
48
|
+
| CDS View Entity | `ZC_` | `ZC_MY_VIEW` |
|
|
49
|
+
| Data Element | `Z` | `ZMY_ELEMENT` |
|
|
50
|
+
| Structure | `Z` | `ZMY_STRUCTURE` |
|
|
51
|
+
| Table Type | `Z` | `ZMY_TABLE_TYPE` |
|
|
56
52
|
|
|
57
|
-
|
|
53
|
+
## Project-Specific Conventions (`objects.local.md`)
|
|
58
54
|
|
|
59
|
-
|
|
55
|
+
`objects.local.md` should define both the naming prefix **and the correct package(s)** for
|
|
56
|
+
new objects. When package rules are present, Claude uses them directly without asking. When
|
|
57
|
+
absent, Claude must ask the user which package to use.
|
|
58
|
+
|
|
59
|
+
Examples of what `objects.local.md` might contain:
|
|
60
60
|
|
|
61
61
|
```
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
```
|
|
62
|
+
# Customer namespace — Y prefix
|
|
63
|
+
Class prefix: YCL_ e.g. YCL_MY_CLASS
|
|
64
|
+
Interface prefix: YIF_ e.g. YIF_MY_INTERFACE
|
|
65
|
+
Default package: YMYPROJECT
|
|
67
66
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
67
|
+
# SAP namespace project — single package
|
|
68
|
+
Class prefix: CL_ e.g. CL_MY_CLASS
|
|
69
|
+
Interface prefix: IF_ e.g. IF_MY_INTERFACE
|
|
70
|
+
Default package: MY_PACKAGE
|
|
71
|
+
|
|
72
|
+
# SAP namespace project — multiple packages
|
|
73
|
+
Class prefix: CL_ e.g. CL_MY_CLASS
|
|
74
|
+
Interface prefix: IF_ e.g. IF_MY_INTERFACE
|
|
75
|
+
Packages:
|
|
76
|
+
- Feature A objects → MY_PACKAGE_A
|
|
77
|
+
- Feature B objects → MY_PACKAGE_B
|
|
78
|
+
|
|
79
|
+
# SAP registered namespace
|
|
80
|
+
Class prefix: /MYNAMESPACE/CL_
|
|
81
|
+
Default package: /MYNAMESPACE/MAIN
|
|
74
82
|
```
|
|
83
|
+
|
|
84
|
+
→ For file structure (what files to create): `abapgit-agent ref --topic object-creation`
|
|
85
|
+
→ For XML templates: `abapgit-agent ref --topic abapgit`
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
---
|
|
2
|
+
layout: default
|
|
3
|
+
title: Probe and PoC Guide
|
|
4
|
+
nav_order: 19
|
|
5
|
+
parent: ABAP Coding Guidelines
|
|
6
|
+
grand_parent: ABAP Development
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Probe and PoC — Full Decision Flow
|
|
10
|
+
|
|
11
|
+
**Searchable keywords**: probe, PoC, proof of concept, scratchWorkspace, pocWorkspace,
|
|
12
|
+
disableProbeClasses, SAP namespace, customer namespace, throwaway class
|
|
13
|
+
|
|
14
|
+
## Probe vs PoC — Key Difference
|
|
15
|
+
|
|
16
|
+
| | Probe | PoC |
|
|
17
|
+
|---|---|---|
|
|
18
|
+
| Intent | Throwaway — run once to test something | Validate an idea — may persist, needs proper home |
|
|
19
|
+
| Naming | Auto-derived (`ZCL_{USER}_*`) | Developer chooses a meaningful name |
|
|
20
|
+
| Location | `scratchWorkspace` (separate repo) | `pocWorkspace` (separate repo, manually set up) |
|
|
21
|
+
| Config | `scratchWorkspace` in `.abapGitAgent` | `pocWorkspace` in `.abapGitAgent` |
|
|
22
|
+
|
|
23
|
+
Both always use `Z*`/`Y*` prefix and a customer namespace package (`Z*`, `Y*`, `$*`).
|
|
24
|
+
Never use SAP namespace prefix or SAP-delivered package for probe/PoC objects.
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
## How to Determine the Project Namespace
|
|
29
|
+
|
|
30
|
+
Before applying the decision flow, determine the project namespace from `objects.local.md`:
|
|
31
|
+
|
|
32
|
+
```
|
|
33
|
+
objects.local.md shows Z*/Y* prefix OR no objects.local.md exists
|
|
34
|
+
→ Customer namespace project
|
|
35
|
+
|
|
36
|
+
objects.local.md shows CL_*, IF_*, /NAMESPACE/* prefix
|
|
37
|
+
→ SAP namespace project
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
---
|
|
41
|
+
|
|
42
|
+
## Full Decision Flow
|
|
43
|
+
|
|
44
|
+
```
|
|
45
|
+
User asks to create an object
|
|
46
|
+
│
|
|
47
|
+
├── SAP namespace project AND user provides a Z*/Y* name
|
|
48
|
+
│ └── Ask: "Production objects here use CL_* prefix. Did you mean CL_MY_HELPER?
|
|
49
|
+
│ Or is this a PoC/probe object?"
|
|
50
|
+
│ ├── "PoC/probe" → continue as PoC or probe flow below
|
|
51
|
+
│ └── "Production" → correct the name to match project prefix, then proceed
|
|
52
|
+
│
|
|
53
|
+
├── User confirms PROBE
|
|
54
|
+
│ ├── Customer namespace project
|
|
55
|
+
│ │ ├── disableProbeClasses = false / not set
|
|
56
|
+
│ │ │ └── Create in current project (Z*/Y* prefix, Z*/Y*/$* package)
|
|
57
|
+
│ │ └── disableProbeClasses = true
|
|
58
|
+
│ │ ├── scratchWorkspace configured → create there (see workflow below)
|
|
59
|
+
│ │ └── scratchWorkspace NOT configured
|
|
60
|
+
│ │ └── STOP — tell user to configure scratchWorkspace in .abapGitAgent
|
|
61
|
+
│ │
|
|
62
|
+
│ └── SAP namespace project
|
|
63
|
+
│ ├── scratchWorkspace configured → create there (see workflow below)
|
|
64
|
+
│ └── scratchWorkspace NOT configured
|
|
65
|
+
│ └── STOP — tell user to configure scratchWorkspace in .abapGitAgent
|
|
66
|
+
│ (disableProbeClasses is irrelevant for SAP namespace projects —
|
|
67
|
+
│ they have no customer namespace packages to host probes)
|
|
68
|
+
│
|
|
69
|
+
└── User confirms POC
|
|
70
|
+
├── pocWorkspace.path configured in .abapGitAgent
|
|
71
|
+
│ └── Read {pocWorkspace.path}/.abapGitAgent → get package property
|
|
72
|
+
│ Show confirmation:
|
|
73
|
+
│ "I'll create this PoC object in:
|
|
74
|
+
│ Repo: {pocWorkspace.path}
|
|
75
|
+
│ Package: {package from that repo's .abapGitAgent}
|
|
76
|
+
│ Is this correct, or do you want a different PoC repo?"
|
|
77
|
+
│ ├── Confirmed → work in that repo using its naming/package rules
|
|
78
|
+
│ └── Different repo → ask user for the path, then confirm again
|
|
79
|
+
└── pocWorkspace.path NOT configured
|
|
80
|
+
└── STOP — tell user to set up a PoC repo first (see setup below)
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
---
|
|
84
|
+
|
|
85
|
+
## Probe Workflow (scratchWorkspace)
|
|
86
|
+
|
|
87
|
+
**Naming** — derive from `scratchWorkspace` config in `.abapGitAgent`:
|
|
88
|
+
- `classPrefix` (default: `ZCL_{USER}_`) + `<PURPOSE>`, max 30 chars
|
|
89
|
+
- Example: user=`JOHN`, purpose=`OPEN_TRANSPORTS` → `ZCL_JOHN_OPEN_TRANSPORTS`
|
|
90
|
+
- If name already exists in `{path}/src/`, append `_2`, `_3`, etc.
|
|
91
|
+
|
|
92
|
+
**Workflow:**
|
|
93
|
+
1. Read `{scratchWorkspace.path}/.abapGitAgent` to confirm `folder` property (e.g. `/src/`)
|
|
94
|
+
2. Write class files in `{path}/src/`
|
|
95
|
+
3. Commit and push from `{path}`:
|
|
96
|
+
```bash
|
|
97
|
+
cd {path} && git add . && git commit -m "probe: <description>" && git push
|
|
98
|
+
```
|
|
99
|
+
4. Activate:
|
|
100
|
+
```bash
|
|
101
|
+
cd {path} && abapgit-agent pull --files src/<classname>.clas.abap
|
|
102
|
+
```
|
|
103
|
+
5. Tell user (do NOT auto-run):
|
|
104
|
+
```
|
|
105
|
+
Class activated. Run with: abapgit-agent run --class <CLASSNAME>
|
|
106
|
+
```
|
|
107
|
+
Run the command from the original project directory, not `{path}`.
|
|
108
|
+
|
|
109
|
+
---
|
|
110
|
+
|
|
111
|
+
## PoC Workflow (pocWorkspace)
|
|
112
|
+
|
|
113
|
+
Once the user confirms the repo and package:
|
|
114
|
+
|
|
115
|
+
1. Read `{pocWorkspace.path}/.abapGitAgent` → get `folder` and `package`
|
|
116
|
+
2. Read `{pocWorkspace.path}/guidelines/objects.local.md` if it exists → use its naming rules
|
|
117
|
+
3. Write object files in `{pocWorkspace.path}/{folder}/`
|
|
118
|
+
4. Commit and push from `{pocWorkspace.path}`:
|
|
119
|
+
```bash
|
|
120
|
+
cd {pocWorkspace.path} && git add . && git commit -m "poc: <description>" && git push
|
|
121
|
+
```
|
|
122
|
+
5. Activate:
|
|
123
|
+
```bash
|
|
124
|
+
cd {pocWorkspace.path} && abapgit-agent pull --files {folder}/<name>.<ext> --sync-xml
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
---
|
|
128
|
+
|
|
129
|
+
## PoC Repo Setup (one-time, manual)
|
|
130
|
+
|
|
131
|
+
When `pocWorkspace.path` is not configured, tell the user to:
|
|
132
|
+
|
|
133
|
+
```
|
|
134
|
+
1. Create a git repo for the PoC:
|
|
135
|
+
mkdir my-poc && cd my-poc && git init && git remote add origin <url>
|
|
136
|
+
|
|
137
|
+
2. Link it to an ABAP package:
|
|
138
|
+
abapgit-agent init --package <POC_PACKAGE>
|
|
139
|
+
|
|
140
|
+
3. Add pocWorkspace to .abapGitAgent in the main project:
|
|
141
|
+
"pocWorkspace": { "path": "/absolute/path/to/my-poc" }
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
**Switching PoCs**: update `pocWorkspace.path` to point to the new PoC repo.
|
|
145
|
+
Claude always shows the current repo and package before creating anything —
|
|
146
|
+
a stale path is caught before any files are written.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "abapgit-agent",
|
|
3
|
-
"version": "1.13.
|
|
3
|
+
"version": "1.13.4",
|
|
4
4
|
"description": "ABAP Git Agent - Pull and activate ABAP code via abapGit from any git repository",
|
|
5
5
|
"files": [
|
|
6
6
|
"bin/",
|
|
@@ -27,6 +27,8 @@
|
|
|
27
27
|
"test:cmd:demo": "node tests/run-all.js --cmd --demo",
|
|
28
28
|
"test:cmd:syntax": "node tests/run-all.js --cmd --command=syntax",
|
|
29
29
|
"test:cmd:pull": "node tests/run-all.js --cmd --command=pull",
|
|
30
|
+
"test:sync-xml": "node tests/run-all.js --sync-xml",
|
|
31
|
+
"test:xml-only": "node tests/run-all.js --xml-only",
|
|
30
32
|
"test:cmd:inspect": "node tests/run-all.js --cmd --command=inspect",
|
|
31
33
|
"test:cmd:unit": "node tests/run-all.js --cmd --command=unit",
|
|
32
34
|
"test:cmd:view": "node tests/run-all.js --cmd --command=view",
|
package/src/commands/pull.js
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
const { printHttpError } = require('../utils/format-error');
|
|
6
6
|
const fs = require('fs');
|
|
7
7
|
const pathModule = require('path');
|
|
8
|
+
const { execSync } = require('child_process');
|
|
8
9
|
|
|
9
10
|
// Calculate display width accounting for emoji (2 cells) vs ASCII (1 cell)
|
|
10
11
|
function calcWidth(str) {
|
|
@@ -42,6 +43,7 @@ module.exports = {
|
|
|
42
43
|
async execute(args, context) {
|
|
43
44
|
const { loadConfig, AbapHttp, gitUtils, getTransport, getSafeguards, getConflictSettings, getTransportSettings } = context;
|
|
44
45
|
const verbose = args.includes('--verbose');
|
|
46
|
+
const syncXml = args.includes('--sync-xml');
|
|
45
47
|
|
|
46
48
|
// Check project-level safeguards
|
|
47
49
|
const safeguards = getSafeguards();
|
|
@@ -96,21 +98,31 @@ module.exports = {
|
|
|
96
98
|
if (filesArgIndex !== -1 && filesArgIndex + 1 < args.length) {
|
|
97
99
|
files = args[filesArgIndex + 1].split(',').map(f => f.trim());
|
|
98
100
|
|
|
99
|
-
// Validate that every file has a recognised
|
|
100
|
-
//
|
|
101
|
+
// Validate that every file has a recognised extension:
|
|
102
|
+
// - .abap / .asddls — ABAP source files
|
|
103
|
+
// - name.type.xml — XML-only objects (TABL, STRU, DTEL, TTYP, ...)
|
|
104
|
+
// Must have exactly 3 dot-separated parts with a non-empty name part
|
|
105
|
+
// to exclude .abapgit.xml, package.devc.xml, plain .xml, etc.
|
|
101
106
|
const ABAP_SOURCE_EXTS = new Set(['abap', 'asddls']);
|
|
107
|
+
const isXmlOnlyObject = (f) => {
|
|
108
|
+
const base = f.split('/').pop();
|
|
109
|
+
const parts = base.split('.');
|
|
110
|
+
return parts.length === 3 && parts[0].length > 0 && parts[2].toLowerCase() === 'xml';
|
|
111
|
+
};
|
|
102
112
|
const nonSourceFiles = files.filter(f => {
|
|
103
113
|
const base = f.split('/').pop(); // strip directory
|
|
104
114
|
const parts = base.split('.');
|
|
105
115
|
const ext = parts[parts.length - 1].toLowerCase();
|
|
106
|
-
|
|
116
|
+
if (ABAP_SOURCE_EXTS.has(ext)) return false; // .abap / .asddls — valid
|
|
117
|
+
if (isXmlOnlyObject(f)) return false; // name.type.xml — valid
|
|
118
|
+
return true; // everything else — invalid
|
|
107
119
|
});
|
|
108
120
|
if (nonSourceFiles.length > 0) {
|
|
109
|
-
console.error('❌ Error: --files only accepts ABAP source files (.abap, .asddls).');
|
|
110
|
-
console.error(' The following file(s) are not
|
|
121
|
+
console.error('❌ Error: --files only accepts ABAP source files (.abap, .asddls) or XML-only object files (name.type.xml).');
|
|
122
|
+
console.error(' The following file(s) are not recognised:');
|
|
111
123
|
nonSourceFiles.forEach(f => console.error(` ${f}`));
|
|
112
|
-
console.error(' Tip: pass the
|
|
113
|
-
console.error('
|
|
124
|
+
console.error(' Tip: for source objects pass the .abap file; for XML-only objects (TABL, STRU, DTEL, TTYP)');
|
|
125
|
+
console.error(' pass the .xml file, e.g. --files abap/ztable.tabl.xml');
|
|
114
126
|
process.exit(1);
|
|
115
127
|
}
|
|
116
128
|
|
|
@@ -198,13 +210,13 @@ module.exports = {
|
|
|
198
210
|
}
|
|
199
211
|
}
|
|
200
212
|
|
|
201
|
-
await this.pull(gitUrl, branch, files, transportRequest, loadConfig, AbapHttp, jsonOutput, undefined, conflictMode, verbose);
|
|
213
|
+
await this.pull(gitUrl, branch, files, transportRequest, loadConfig, AbapHttp, jsonOutput, undefined, conflictMode, verbose, syncXml);
|
|
202
214
|
},
|
|
203
215
|
|
|
204
|
-
async pull(gitUrl, branch = 'main', files = null, transportRequest = null, loadConfig, AbapHttp, jsonOutput = false, gitCredentials = undefined, conflictMode = 'abort', verbose = false) {
|
|
216
|
+
async pull(gitUrl, branch = 'main', files = null, transportRequest = null, loadConfig, AbapHttp, jsonOutput = false, gitCredentials = undefined, conflictMode = 'abort', verbose = false, syncXml = false, isRepull = false) {
|
|
205
217
|
const TERM_WIDTH = process.stdout.columns || 80;
|
|
206
218
|
|
|
207
|
-
if (!jsonOutput) {
|
|
219
|
+
if (!jsonOutput && !isRepull) {
|
|
208
220
|
console.log(`\n🚀 Starting pull for: ${gitUrl}`);
|
|
209
221
|
console.log(` Branch: ${branch}`);
|
|
210
222
|
if (files && files.length > 0) {
|
|
@@ -438,6 +450,71 @@ module.exports = {
|
|
|
438
450
|
throw err;
|
|
439
451
|
}
|
|
440
452
|
|
|
453
|
+
// --- Post-pull XML sync ---
|
|
454
|
+
// abapGit's status calculation already identified which XML files differ
|
|
455
|
+
// (match=false) — only those are returned in local_xml_files.
|
|
456
|
+
const localXmlFiles = result.local_xml_files || result.LOCAL_XML_FILES || [];
|
|
457
|
+
|
|
458
|
+
if (localXmlFiles.length > 0) {
|
|
459
|
+
const diffFiles = [];
|
|
460
|
+
for (const f of localXmlFiles) {
|
|
461
|
+
const relPath = ((f.path || f.PATH || '') + (f.filename || f.FILENAME || '')).replace(/^\//, '');
|
|
462
|
+
const absPath = pathModule.join(process.cwd(), relPath);
|
|
463
|
+
if (!fs.existsSync(absPath)) continue;
|
|
464
|
+
const incoming = Buffer.from(f.data || f.DATA, 'base64');
|
|
465
|
+
// Double-check: only write if bytes actually differ (guard against encoding quirks)
|
|
466
|
+
const current = fs.readFileSync(absPath);
|
|
467
|
+
if (!current.equals(incoming)) {
|
|
468
|
+
diffFiles.push({ relPath, absPath, incoming });
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
if (diffFiles.length > 0 && !syncXml) {
|
|
473
|
+
console.log(`\n⚠️ ${diffFiles.length} XML file(s) differ from serializer output:`);
|
|
474
|
+
for (const f of diffFiles) console.log(` ${f.relPath}`);
|
|
475
|
+
console.log(` Run with --sync-xml to accept serializer output and amend the last commit`);
|
|
476
|
+
} else if (diffFiles.length > 0 && syncXml) {
|
|
477
|
+
console.log(`\n🔄 Syncing ${diffFiles.length} XML file(s) to match serializer output:`);
|
|
478
|
+
for (const f of diffFiles) console.log(` ${f.relPath}`);
|
|
479
|
+
|
|
480
|
+
// 1. Write serializer XML to disk
|
|
481
|
+
for (const f of diffFiles) fs.writeFileSync(f.absPath, f.incoming);
|
|
482
|
+
|
|
483
|
+
// 2. Stage changed XML files
|
|
484
|
+
const quotedPaths = diffFiles.map(f => `"${f.relPath}"`).join(' ');
|
|
485
|
+
execSync(`git add ${quotedPaths}`, { cwd: process.cwd() });
|
|
486
|
+
|
|
487
|
+
// 3. Amend last commit
|
|
488
|
+
execSync('git commit --amend --no-edit', { cwd: process.cwd() });
|
|
489
|
+
|
|
490
|
+
// 4. Push with force-with-lease; if no upstream, set it automatically
|
|
491
|
+
let pushed = false;
|
|
492
|
+
try {
|
|
493
|
+
execSync('git push --force-with-lease', { cwd: process.cwd(), stdio: 'pipe' });
|
|
494
|
+
pushed = true;
|
|
495
|
+
} catch (pushErr) {
|
|
496
|
+
const msg = (pushErr.stderr || pushErr.stdout || pushErr.message || '').toString();
|
|
497
|
+
if (msg.includes('no upstream branch') || msg.includes('has no upstream')) {
|
|
498
|
+
// Branch not yet pushed — set upstream and force push (amend requires force)
|
|
499
|
+
execSync(`git push --force-with-lease --set-upstream origin ${branch}`, { cwd: process.cwd(), stdio: 'pipe' });
|
|
500
|
+
pushed = true;
|
|
501
|
+
}
|
|
502
|
+
// Any other push error (no remote at all, auth failure, etc.) → skip silently
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
if (pushed) {
|
|
506
|
+
console.log(` Re-pulling so ABAP system matches the amended commit...`);
|
|
507
|
+
// 5. Re-pull so ABAP system matches the amended commit (no sync loop)
|
|
508
|
+
await this.pull(gitUrl, branch, files, transportRequest, loadConfig, AbapHttp, jsonOutput, gitCredentials, conflictMode, verbose, false, true);
|
|
509
|
+
console.log(`\n✅ Synced ${diffFiles.length} XML file(s), amended commit, re-pulled`);
|
|
510
|
+
} else {
|
|
511
|
+
// No remote at all — files are written and committed locally
|
|
512
|
+
console.log(`\n✅ Synced ${diffFiles.length} XML file(s), amended commit`);
|
|
513
|
+
console.log(` Push skipped (no remote). Push manually to sync with remote.`);
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
|
|
441
518
|
return result;
|
|
442
519
|
} catch (error) {
|
|
443
520
|
if (error._isPullError) {
|