abapgit-agent 1.7.1 → 1.7.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.abapGitAgent.example +11 -0
- package/abap/.github/copilot-instructions.md +254 -0
- package/abap/CLAUDE.md +313 -0
- package/bin/abapgit-agent +81 -18
- package/package.json +6 -2
- package/src/abap-client.js +9 -6
- package/src/agent.js +10 -6
- package/src/ref-search.js +119 -1
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
{
|
|
2
|
+
"host": "your-sap-system.com",
|
|
3
|
+
"sapport": 443,
|
|
4
|
+
"client": "100",
|
|
5
|
+
"user": "TECH_USER",
|
|
6
|
+
"password": "your-password",
|
|
7
|
+
"language": "EN",
|
|
8
|
+
"gitUsername": "github-username",
|
|
9
|
+
"gitPassword": "github-token",
|
|
10
|
+
"referenceFolder": "~/abap-reference"
|
|
11
|
+
}
|
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
# ABAP Development with abapGit
|
|
2
|
+
|
|
3
|
+
You are working on an ABAP project using abapGit for version control.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Critical Rules
|
|
8
|
+
|
|
9
|
+
### 1. Use `ref` Command for Unfamiliar Topics
|
|
10
|
+
|
|
11
|
+
**When starting to work on ANY unfamiliar ABAP topic, syntax, or pattern, you MUST use the `ref` command BEFORE writing any code.**
|
|
12
|
+
|
|
13
|
+
```
|
|
14
|
+
❌ WRONG: Start writing code immediately based on assumptions
|
|
15
|
+
✅ CORRECT: Run ref command first to look up the correct pattern
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
**Why**: ABAP syntax is strict. Guessing leads to activation errors that waste time.
|
|
19
|
+
|
|
20
|
+
| Scenario | Example |
|
|
21
|
+
|----------|---------|
|
|
22
|
+
| Implementing new ABAP feature | "How do I use FILTER operator?" |
|
|
23
|
+
| Unfamiliar pattern | "What's the correct VALUE #() syntax?" |
|
|
24
|
+
| SQL operations | "How to write a proper SELECT with JOIN?" |
|
|
25
|
+
| CDS views | "How to define CDS view with associations?" |
|
|
26
|
+
| Getting syntax errors | Check reference before trying approaches |
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
# For CDS topics
|
|
30
|
+
abapgit-agent ref --topic cds
|
|
31
|
+
abapgit-agent ref "CDS view"
|
|
32
|
+
abapgit-agent ref "association"
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
# Search for a pattern
|
|
37
|
+
abapgit-agent ref "CORRESPONDING"
|
|
38
|
+
abapgit-agent ref "FILTER #"
|
|
39
|
+
|
|
40
|
+
# Browse by topic
|
|
41
|
+
abapgit-agent ref --topic exceptions
|
|
42
|
+
abapgit-agent ref --topic sql
|
|
43
|
+
|
|
44
|
+
# List all topics
|
|
45
|
+
abapgit-agent ref --list-topics
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### 2. Read `.abapGitAgent` for Folder Location
|
|
49
|
+
|
|
50
|
+
**Before creating ANY ABAP object file, you MUST read `.abapGitAgent` to determine the correct folder.**
|
|
51
|
+
|
|
52
|
+
```
|
|
53
|
+
❌ WRONG: Assume files go in "abap/" folder
|
|
54
|
+
✅ CORRECT: Read .abapGitAgent to get the "folder" property value
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
The folder is configured in `.abapGitAgent` (property: `folder`):
|
|
58
|
+
- If `folder` is `/src/` → files go in `src/` (e.g., `src/zcl_my_class.clas.abap`)
|
|
59
|
+
- If `folder` is `/abap/` → files go in `abap/` (e.g., `abap/zcl_my_class.clas.abap`)
|
|
60
|
+
|
|
61
|
+
### 3. Create XML Metadata for Each ABAP Object
|
|
62
|
+
|
|
63
|
+
**Each ABAP object requires an XML metadata file for abapGit to understand how to handle it.**
|
|
64
|
+
|
|
65
|
+
| Object Type | ABAP File (if folder=/src/) | XML File |
|
|
66
|
+
|-------------|------------------------------|----------|
|
|
67
|
+
| Class | `src/zcl_*.clas.abap` | `src/zcl_*.clas.xml` |
|
|
68
|
+
| Interface | `src/zif_*.intf.abap` | `src/zif_*.intf.xml` |
|
|
69
|
+
| Program | `src/z*.prog.abap` | `src/z*.prog.xml` |
|
|
70
|
+
| Table | `src/z*.tabl.abap` | `src/z*.tabl.xml` |
|
|
71
|
+
| CDS View | `src/zc_*.ddls.asddls` | `src/zc_*.ddls.xml` |
|
|
72
|
+
|
|
73
|
+
**Use `ref --topic abapgit` for complete XML templates.**
|
|
74
|
+
|
|
75
|
+
### 4. Use `unit` Command for Unit Tests
|
|
76
|
+
|
|
77
|
+
**Use `abapgit-agent unit` to run ABAP unit tests (AUnit).**
|
|
78
|
+
|
|
79
|
+
```
|
|
80
|
+
❌ WRONG: Try to use SE24 or other transaction codes
|
|
81
|
+
✅ CORRECT: Use abapgit-agent unit --files src/zcl_test.clas.testclasses.abap
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
# Run unit tests (after pulling to ABAP)
|
|
86
|
+
abapgit-agent unit --files src/zcl_test.clas.testclasses.abap
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
### 5. Use CDS Test Double Framework for CDS View Tests
|
|
90
|
+
|
|
91
|
+
**When creating unit tests for CDS views, use the CDS Test Double Framework (`CL_CDS_TEST_ENVIRONMENT`).**
|
|
92
|
+
|
|
93
|
+
```
|
|
94
|
+
❌ WRONG: Use regular AUnit test class without test doubles
|
|
95
|
+
✅ CORRECT: Use CL_CDS_TEST_ENVIRONMENT to create test doubles for CDS views
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
**Why**: CDS views read from database tables. Using test doubles allows:
|
|
99
|
+
- Injecting test data without affecting production data
|
|
100
|
+
- Testing specific scenarios that may not exist in production
|
|
101
|
+
- Fast, isolated tests that don't depend on database state
|
|
102
|
+
|
|
103
|
+
See `../guidelines/03_testing.md` for code examples.
|
|
104
|
+
|
|
105
|
+
---
|
|
106
|
+
|
|
107
|
+
## Development Workflow
|
|
108
|
+
|
|
109
|
+
```
|
|
110
|
+
1. Read .abapGitAgent → get folder value
|
|
111
|
+
│
|
|
112
|
+
▼
|
|
113
|
+
2. Research → use ref command for unfamiliar topics
|
|
114
|
+
│
|
|
115
|
+
▼
|
|
116
|
+
3. Write code → place in correct folder (e.g., src/zcl_*.clas.abap)
|
|
117
|
+
│
|
|
118
|
+
▼
|
|
119
|
+
4. Commit and push → git add . && git commit && git push
|
|
120
|
+
│
|
|
121
|
+
▼
|
|
122
|
+
5. Activate → abapgit-agent pull --files src/file.clas.abap
|
|
123
|
+
│
|
|
124
|
+
▼
|
|
125
|
+
6. Verify → Check pull output
|
|
126
|
+
- **Do NOT run inspect before commit/push/pull** - ABAP validates on pull
|
|
127
|
+
- **Do NOT run unit before pull** - Tests run against ABAP system, code must be activated first
|
|
128
|
+
- Objects NOT in "Activated Objects" but in "Failed Objects Log" → Syntax error (check inspect)
|
|
129
|
+
- Objects NOT appearing at all → XML metadata issue
|
|
130
|
+
│
|
|
131
|
+
▼
|
|
132
|
+
7. (Optional) Run unit tests → abapgit-agent unit --files src/zcl_test.clas.testclasses.abap (ONLY if test file exists, AFTER successful pull)
|
|
133
|
+
│
|
|
134
|
+
▼
|
|
135
|
+
8. If needed → Use inspect to check syntax (runs against ABAP system)
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
**IMPORTANT**:
|
|
139
|
+
- **ALWAYS push to git BEFORE running pull** - abapGit reads from git
|
|
140
|
+
- **Use inspect AFTER pull** to check syntax on objects already in ABAP
|
|
141
|
+
- **Check pull output**:
|
|
142
|
+
- In "Failed Objects Log" → Syntax error (use inspect for details)
|
|
143
|
+
- Not appearing at all → XML metadata is wrong
|
|
144
|
+
|
|
145
|
+
**When to use inspect vs view**:
|
|
146
|
+
- **inspect**: Use when there are SYNTAX ERRORS (to find line numbers and details)
|
|
147
|
+
- **view**: Use when you need to understand an object STRUCTURE (table fields, class methods)
|
|
148
|
+
- Do NOT use view to debug syntax errors - view shows definitions, not errors
|
|
149
|
+
|
|
150
|
+
### Commands
|
|
151
|
+
|
|
152
|
+
```bash
|
|
153
|
+
# 1. Pull/activate after pushing to git (abapGit reads from git!)
|
|
154
|
+
abapgit-agent pull --files src/zcl_class1.clas.abap,src/zcl_class2.clas.abap
|
|
155
|
+
|
|
156
|
+
# 2. Inspect AFTER pull to check syntax (runs against ABAP system)
|
|
157
|
+
abapgit-agent inspect --files src/zcl_class1.clas.abap,src/zif_interface1.intf.abap
|
|
158
|
+
|
|
159
|
+
# Run unit tests (multiple test classes)
|
|
160
|
+
abapgit-agent unit --files src/zcl_test1.clas.testclasses.abap,src/zcl_test2.clas.testclasses.abap
|
|
161
|
+
|
|
162
|
+
# View object definitions (multiple objects)
|
|
163
|
+
abapgit-agent view --objects ZCL_CLASS1,ZCL_CLASS2,ZIF_INTERFACE
|
|
164
|
+
|
|
165
|
+
# Preview table data (multiple tables/views)
|
|
166
|
+
abapgit-agent preview --objects ZTABLE1,ZTABLE2
|
|
167
|
+
|
|
168
|
+
# Explore table structures
|
|
169
|
+
abapgit-agent view --objects ZTABLE --type TABL
|
|
170
|
+
|
|
171
|
+
# Display package tree
|
|
172
|
+
abapgit-agent tree --package \$MY_PACKAGE
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
---
|
|
176
|
+
|
|
177
|
+
## Explore Unknown Objects
|
|
178
|
+
|
|
179
|
+
**Before working with unfamiliar objects, use `view` command:**
|
|
180
|
+
|
|
181
|
+
```bash
|
|
182
|
+
# Check table structure
|
|
183
|
+
abapgit-agent view --objects ZMY_TABLE --type TABL
|
|
184
|
+
|
|
185
|
+
# Check class definition
|
|
186
|
+
abapgit-agent view --objects ZCL_UNKNOWN_CLASS
|
|
187
|
+
|
|
188
|
+
# Check interface
|
|
189
|
+
abapgit-agent view --objects ZIF_UNKNOWN_INTERFACE
|
|
190
|
+
|
|
191
|
+
# Check data element
|
|
192
|
+
abapgit-agent view --objects ZMY_DTEL --type DTEL
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
AI assistant SHOULD call `view` command when:
|
|
196
|
+
- User asks to "check", "look up", or "explore" an unfamiliar object
|
|
197
|
+
- Working with a table/structure and you don't know the fields
|
|
198
|
+
- Calling a class/interface method and you don't know the parameters
|
|
199
|
+
|
|
200
|
+
---
|
|
201
|
+
|
|
202
|
+
## Key ABAP Rules
|
|
203
|
+
|
|
204
|
+
1. **Global classes MUST use `PUBLIC`**:
|
|
205
|
+
```abap
|
|
206
|
+
CLASS zcl_my_class DEFINITION PUBLIC. " <- REQUIRED
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
2. **Use `/ui2/cl_json` for JSON**:
|
|
210
|
+
```abap
|
|
211
|
+
DATA ls_data TYPE ty_request.
|
|
212
|
+
ls_data = /ui2/cl_json=>deserialize( json = lv_json ).
|
|
213
|
+
lv_json = /ui2/cl_json=>serialize( data = ls_response ).
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
3. **Test class name max 30 chars**: `ltcl_util` (not `ltcl_abgagt_util_test`)
|
|
217
|
+
|
|
218
|
+
4. **Interface method implementation**: Use prefix `zif_interface~method_name`
|
|
219
|
+
|
|
220
|
+
---
|
|
221
|
+
|
|
222
|
+
## Error Handling
|
|
223
|
+
|
|
224
|
+
- **"Error updating where-used list"** → This is a **SYNTAX ERROR** (not a warning!)
|
|
225
|
+
- Use `abapgit-agent inspect --files <file>` for detailed error messages with line numbers
|
|
226
|
+
|
|
227
|
+
---
|
|
228
|
+
|
|
229
|
+
## Guidelines Index
|
|
230
|
+
|
|
231
|
+
Detailed guidelines are available in the `guidelines/` folder:
|
|
232
|
+
|
|
233
|
+
| File | Topic |
|
|
234
|
+
|------|-------|
|
|
235
|
+
| `../guidelines/01_sql.md` | ABAP SQL Best Practices |
|
|
236
|
+
| `../guidelines/02_exceptions.md` | Exception Handling |
|
|
237
|
+
| `../guidelines/03_testing.md` | Unit Testing (including CDS) |
|
|
238
|
+
| `../guidelines/04_cds.md` | CDS Views |
|
|
239
|
+
| `../guidelines/05_classes.md` | ABAP Classes and Objects |
|
|
240
|
+
| `../guidelines/06_objects.md` | Object Naming Conventions |
|
|
241
|
+
| `../guidelines/07_json.md` | JSON Handling |
|
|
242
|
+
| `../guidelines/08_abapgit.md` | abapGit XML Metadata Templates |
|
|
243
|
+
|
|
244
|
+
These guidelines are automatically searched by the `ref` command.
|
|
245
|
+
|
|
246
|
+
---
|
|
247
|
+
|
|
248
|
+
## Object Naming
|
|
249
|
+
|
|
250
|
+
| Pattern | Type |
|
|
251
|
+
|---------|------|
|
|
252
|
+
| `ZCL_*` | Class |
|
|
253
|
+
| `ZIF_*` | Interface |
|
|
254
|
+
| `Z*` | Other objects |
|
package/abap/CLAUDE.md
ADDED
|
@@ -0,0 +1,313 @@
|
|
|
1
|
+
# ABAP Project Guidelines - Template
|
|
2
|
+
|
|
3
|
+
This file provides guidelines for **generating ABAP code** in abapGit repositories.
|
|
4
|
+
|
|
5
|
+
**Use this file as a template**: Copy it to your ABAP repository root when setting up new projects with Claude Code.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Critical Rules
|
|
10
|
+
|
|
11
|
+
### 1. Use `ref` Command for Unfamiliar Topics
|
|
12
|
+
|
|
13
|
+
**When starting to work on ANY unfamiliar ABAP topic, syntax, or pattern, you MUST use the `ref` command BEFORE writing any code.**
|
|
14
|
+
|
|
15
|
+
```
|
|
16
|
+
❌ WRONG: Start writing code immediately based on assumptions
|
|
17
|
+
✅ CORRECT: Run ref command first to look up the correct pattern
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
**Why**: ABAP syntax is strict. Guessing leads to activation errors that waste time.
|
|
21
|
+
|
|
22
|
+
| Scenario | Example |
|
|
23
|
+
|----------|---------|
|
|
24
|
+
| Implementing new ABAP feature | "How do I use FILTER operator?" |
|
|
25
|
+
| Unfamiliar pattern | "What's the correct VALUE #() syntax?" |
|
|
26
|
+
| SQL operations | "How to write a proper SELECT with JOIN?" |
|
|
27
|
+
| CDS views | "How to define CDS view with associations?" |
|
|
28
|
+
| Getting syntax errors | Check reference before trying approaches |
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
# For CDS topics
|
|
32
|
+
abapgit-agent ref --topic cds
|
|
33
|
+
abapgit-agent ref "CDS view"
|
|
34
|
+
abapgit-agent ref "association"
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
# Search for a pattern
|
|
39
|
+
abapgit-agent ref "CORRESPONDING"
|
|
40
|
+
abapgit-agent ref "FILTER #"
|
|
41
|
+
|
|
42
|
+
# Browse by topic
|
|
43
|
+
abapgit-agent ref --topic exceptions
|
|
44
|
+
abapgit-agent ref --topic sql
|
|
45
|
+
|
|
46
|
+
# List all topics
|
|
47
|
+
abapgit-agent ref --list-topics
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### 2. Read `.abapGitAgent` for Folder Location
|
|
51
|
+
|
|
52
|
+
**Before creating ANY ABAP object file, you MUST read `.abapGitAgent` to determine the correct folder.**
|
|
53
|
+
|
|
54
|
+
```
|
|
55
|
+
❌ WRONG: Assume files go in "abap/" folder
|
|
56
|
+
✅ CORRECT: Read .abapGitAgent to get the "folder" property value
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
The folder is configured in `.abapGitAgent` (property: `folder`):
|
|
60
|
+
- If `folder` is `/src/` → files go in `src/` (e.g., `src/zcl_my_class.clas.abap`)
|
|
61
|
+
- If `folder` is `/abap/` → files go in `abap/` (e.g., `abap/zcl_my_class.clas.abap`)
|
|
62
|
+
|
|
63
|
+
---
|
|
64
|
+
|
|
65
|
+
### 3. Create XML Metadata for Each ABAP Object
|
|
66
|
+
|
|
67
|
+
**Each ABAP object requires an XML metadata file for abapGit to understand how to handle it.**
|
|
68
|
+
|
|
69
|
+
| Object Type | ABAP File (if folder=/src/) | XML File |
|
|
70
|
+
|-------------|------------------------------|----------|
|
|
71
|
+
| Class | `src/zcl_*.clas.abap` | `src/zcl_*.clas.xml` |
|
|
72
|
+
| Interface | `src/zif_*.intf.abap` | `src/zif_*.intf.xml` |
|
|
73
|
+
| Program | `src/z*.prog.abap` | `src/z*.prog.xml` |
|
|
74
|
+
| Table | `src/z*.tabl.abap` | `src/z*.tabl.xml` |
|
|
75
|
+
| CDS View | `src/zc_*.ddls.asddls` | `src/zc_*.ddls.xml` |
|
|
76
|
+
|
|
77
|
+
**Use `ref --topic abapgit` for complete XML templates.**
|
|
78
|
+
|
|
79
|
+
---
|
|
80
|
+
|
|
81
|
+
### 4. NEVER Run Inspect Before Push/Pull (MOST IMPORTANT!)
|
|
82
|
+
|
|
83
|
+
```
|
|
84
|
+
❌ WRONG: Make changes → Run inspect → Check errors → Repeat
|
|
85
|
+
✅ CORRECT: Make changes → Commit → Push → Run pull → Then inspect ONLY if pull fails
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
**Why**: Inspect runs against the ABAP system, not git. The code must be in git and pulled to ABAP first.
|
|
89
|
+
|
|
90
|
+
---
|
|
91
|
+
|
|
92
|
+
### 5. Local Classes (Test Doubles, Helpers)
|
|
93
|
+
|
|
94
|
+
When a class needs local helper classes or test doubles, use separate files:
|
|
95
|
+
|
|
96
|
+
| File | Purpose |
|
|
97
|
+
|------|---------|
|
|
98
|
+
| `zcl_xxx.clas.locals_def.abap` | Local class definitions |
|
|
99
|
+
| `zcl_xxx.clas.locals_imp.abap` | Local class implementations |
|
|
100
|
+
|
|
101
|
+
**XML Configuration**: Add `<CLSCCINCL>X</CLSCCINCL>` to the class XML to include local class definitions:
|
|
102
|
+
|
|
103
|
+
```xml
|
|
104
|
+
<VSEOCLASS>
|
|
105
|
+
<CLSNAME>ZCL_XXX</CLSNAME>
|
|
106
|
+
...
|
|
107
|
+
<CLSCCINCL>X</CLSCCINCL>
|
|
108
|
+
</VSEOCLASS>
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
### 6. Use `ref`, `view` and `where` Commands to Learn About Unknown Classes/Methods
|
|
112
|
+
|
|
113
|
+
**When working with unfamiliar ABAP classes or methods, follow this priority:**
|
|
114
|
+
|
|
115
|
+
```
|
|
116
|
+
1. First: Check local git repo for usage examples
|
|
117
|
+
2. Second: Check ABAP reference/cheat sheets
|
|
118
|
+
3. Third: Use view/where commands to query ABAP system (if needed)
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
#### Priority 1: Check Local Git Repository
|
|
122
|
+
|
|
123
|
+
**Look for usage examples in your local ABAP project first:**
|
|
124
|
+
- Search for class/interface names in your codebase
|
|
125
|
+
- Check how similar classes are implemented
|
|
126
|
+
- This gives the most relevant context for your project
|
|
127
|
+
|
|
128
|
+
#### Priority 2: Check ABAP References
|
|
129
|
+
|
|
130
|
+
```bash
|
|
131
|
+
# Search in ABAP cheat sheets and guidelines
|
|
132
|
+
abapgit-agent ref "CLASS"
|
|
133
|
+
abapgit-agent ref "INTERFACE"
|
|
134
|
+
abapgit-agent ref --topic classes
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
#### Priority 3: Use `where` and `view` Commands (Query ABAP System)
|
|
138
|
+
|
|
139
|
+
**If local/references don't have the answer, query the ABAP system:**
|
|
140
|
+
|
|
141
|
+
```bash
|
|
142
|
+
# Find where a class/interface is USED (where command)
|
|
143
|
+
abapgit-agent where --objects ZIF_UNKNOWN_INTERFACE
|
|
144
|
+
|
|
145
|
+
# With pagination (default limit: 50, offset: 0)
|
|
146
|
+
abapgit-agent where --objects ZIF_UNKNOWN_INTERFACE --limit 20
|
|
147
|
+
abapgit-agent where --objects ZIF_UNKNOWN_INTERFACE --offset 50 --limit 20
|
|
148
|
+
|
|
149
|
+
# View CLASS DEFINITION (view command)
|
|
150
|
+
abapgit-agent view --objects ZCL_UNKNOWN_CLASS
|
|
151
|
+
|
|
152
|
+
# View specific METHOD implementation
|
|
153
|
+
abapgit-agent view --objects ZCL_UNKNOWN_CLASS=============CM001
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
**Example workflow for AI:**
|
|
157
|
+
```
|
|
158
|
+
User: "How do I use ZCL_ABGAGT_AGENT?"
|
|
159
|
+
|
|
160
|
+
AI thought process:
|
|
161
|
+
1. Search local repo for ZCL_ABGAGT_AGENT usage
|
|
162
|
+
2. Found: It's instantiated in several places with ->pull() method
|
|
163
|
+
3. Still unclear about parameters? Check view command
|
|
164
|
+
4. View: abapgit-agent view --objects ZCL_ABGAGT_AGENT
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
**Key differences:**
|
|
168
|
+
- `where`: Shows WHERE an object is USED (references)
|
|
169
|
+
- `view`: Shows what an object DEFINES (structure, methods, source)
|
|
170
|
+
|
|
171
|
+
---
|
|
172
|
+
|
|
173
|
+
### 7. Use CDS Test Double Framework for CDS View Tests
|
|
174
|
+
|
|
175
|
+
**When creating unit tests for CDS views, use the CDS Test Double Framework (`CL_CDS_TEST_ENVIRONMENT`).**
|
|
176
|
+
|
|
177
|
+
```
|
|
178
|
+
❌ WRONG: Use regular AUnit test class without test doubles
|
|
179
|
+
✅ CORRECT: Use CL_CDS_TEST_ENVIRONMENT to create test doubles for CDS views
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
**Why**: CDS views read from database tables. Using test doubles allows:
|
|
183
|
+
- Injecting test data without affecting production data
|
|
184
|
+
- Testing specific scenarios that may not exist in production
|
|
185
|
+
- Fast, isolated tests that don't depend on database state
|
|
186
|
+
|
|
187
|
+
See `guidelines/03_testing.md` for code examples.
|
|
188
|
+
|
|
189
|
+
---
|
|
190
|
+
|
|
191
|
+
### 8. Use `unit` Command for Unit Tests
|
|
192
|
+
|
|
193
|
+
**Use `abapgit-agent unit` to run ABAP unit tests (AUnit).**
|
|
194
|
+
|
|
195
|
+
```
|
|
196
|
+
❌ WRONG: Try to use SE24, SE37, or other transaction codes
|
|
197
|
+
✅ CORRECT: Use abapgit-agent unit --files src/zcl_test.clas.testclasses.abap
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
```bash
|
|
201
|
+
# Run unit tests (after pulling to ABAP)
|
|
202
|
+
abapgit-agent unit --files src/zcl_test.clas.testclasses.abap
|
|
203
|
+
|
|
204
|
+
# Multiple test classes
|
|
205
|
+
abapgit-agent unit --files src/zcl_test1.clas.testclasses.abap,src/zcl_test2.clas.testclasses.abap
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
---
|
|
209
|
+
|
|
210
|
+
## Development Workflow
|
|
211
|
+
|
|
212
|
+
```
|
|
213
|
+
1. Read .abapGitAgent → get folder value
|
|
214
|
+
│
|
|
215
|
+
▼
|
|
216
|
+
2. Research → use ref command for unfamiliar topics
|
|
217
|
+
│
|
|
218
|
+
▼
|
|
219
|
+
3. Write code → place in correct folder (e.g., src/zcl_*.clas.abap)
|
|
220
|
+
│
|
|
221
|
+
▼
|
|
222
|
+
4. Commit and push → git add . && git commit && git push
|
|
223
|
+
│
|
|
224
|
+
▼
|
|
225
|
+
5. Activate → abapgit-agent pull --files src/file.clas.abap
|
|
226
|
+
│
|
|
227
|
+
▼
|
|
228
|
+
6. Verify → Check pull output
|
|
229
|
+
- **Do NOT run inspect before commit/push/pull** - ABAP validates on pull
|
|
230
|
+
- **Do NOT run unit before pull** - Tests run against ABAP system, code must be activated first
|
|
231
|
+
- **"Error updating where-used list"** → This is a **SYNTAX ERROR** (check inspect for details)
|
|
232
|
+
- Objects NOT in "Activated Objects" but in "Failed Objects Log" → Syntax error (check inspect)
|
|
233
|
+
- Objects NOT appearing at all → XML metadata issue (check XML format in 08_abapgit.md)
|
|
234
|
+
│
|
|
235
|
+
▼
|
|
236
|
+
7. (Optional) Run unit tests → abapgit-agent unit --files src/zcl_test.clas.testclasses.abap (ONLY if test file exists, AFTER successful pull)
|
|
237
|
+
│
|
|
238
|
+
▼
|
|
239
|
+
8. If needed → Use inspect to check syntax (runs against ABAP system)
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
**IMPORTANT**:
|
|
243
|
+
- **ALWAYS push to git BEFORE running pull** - abapGit reads from git
|
|
244
|
+
- **Use inspect AFTER pull** to check syntax on objects already in ABAP
|
|
245
|
+
- **Check pull output**:
|
|
246
|
+
- In "Failed Objects Log" → Syntax error (use inspect for details)
|
|
247
|
+
- Not appearing at all → XML metadata is wrong
|
|
248
|
+
|
|
249
|
+
**When to use inspect vs view**:
|
|
250
|
+
- **inspect**: Use when there are SYNTAX ERRORS (to find line numbers and details)
|
|
251
|
+
- **view**: Use when you need to understand an object STRUCTURE (table fields, class methods)
|
|
252
|
+
- Do NOT use view to debug syntax errors - view shows definitions, not errors
|
|
253
|
+
|
|
254
|
+
### Commands
|
|
255
|
+
|
|
256
|
+
```bash
|
|
257
|
+
# 1. Pull/activate after pushing to git (abapGit reads from git!)
|
|
258
|
+
abapgit-agent pull --files src/zcl_class1.clas.abap,src/zcl_class2.clas.abap
|
|
259
|
+
|
|
260
|
+
# 2. Inspect AFTER pull to check syntax (runs against ABAP system)
|
|
261
|
+
abapgit-agent inspect --files src/zcl_class1.clas.abap
|
|
262
|
+
|
|
263
|
+
# Run unit tests (multiple test classes)
|
|
264
|
+
abapgit-agent unit --files src/zcl_test1.clas.testclasses.abap,src/zcl_test2.clas.testclasses.abap
|
|
265
|
+
|
|
266
|
+
# View object definitions (multiple objects)
|
|
267
|
+
abapgit-agent view --objects ZCL_CLASS1,ZCL_CLASS2,ZIF_INTERFACE
|
|
268
|
+
|
|
269
|
+
# Preview table data (multiple tables/views)
|
|
270
|
+
abapgit-agent preview --objects ZTABLE1,ZTABLE2
|
|
271
|
+
|
|
272
|
+
# Explore table structures
|
|
273
|
+
abapgit-agent view --objects ZTABLE --type TABL
|
|
274
|
+
|
|
275
|
+
# Display package tree
|
|
276
|
+
abapgit-agent tree --package \$MY_PACKAGE
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
---
|
|
280
|
+
|
|
281
|
+
## Guidelines Index
|
|
282
|
+
|
|
283
|
+
Detailed guidelines are available in the `guidelines/` folder:
|
|
284
|
+
|
|
285
|
+
| File | Topic |
|
|
286
|
+
|------|-------|
|
|
287
|
+
| `guidelines/01_sql.md` | ABAP SQL Best Practices |
|
|
288
|
+
| `guidelines/02_exceptions.md` | Exception Handling |
|
|
289
|
+
| `guidelines/03_testing.md` | Unit Testing (including CDS) |
|
|
290
|
+
| `guidelines/04_cds.md` | CDS Views |
|
|
291
|
+
| `guidelines/05_classes.md` | ABAP Classes and Objects |
|
|
292
|
+
| `guidelines/06_objects.md` | Object Naming Conventions |
|
|
293
|
+
| `guidelines/07_json.md` | JSON Handling |
|
|
294
|
+
| `guidelines/08_abapgit.md` | abapGit XML Metadata Templates |
|
|
295
|
+
|
|
296
|
+
These guidelines are automatically searched by the `ref` command.
|
|
297
|
+
|
|
298
|
+
---
|
|
299
|
+
|
|
300
|
+
## Custom Guidelines
|
|
301
|
+
|
|
302
|
+
You can add your own guidelines:
|
|
303
|
+
|
|
304
|
+
1. Create `.md` files in `guidelines/` folder
|
|
305
|
+
2. Export to reference folder: `abapgit-agent ref export`
|
|
306
|
+
3. The `ref` command will search both cheat sheets and your custom guidelines
|
|
307
|
+
|
|
308
|
+
---
|
|
309
|
+
|
|
310
|
+
## For More Information
|
|
311
|
+
|
|
312
|
+
- [SAP ABAP Cheat Sheets](https://github.com/SAP-samples/abap-cheat-sheets)
|
|
313
|
+
- [ABAP Keyword Documentation](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm)
|
package/bin/abapgit-agent
CHANGED
|
@@ -2305,10 +2305,11 @@ Examples:
|
|
|
2305
2305
|
const objectsArgIndex = args.indexOf('--objects');
|
|
2306
2306
|
if (objectsArgIndex === -1 || objectsArgIndex + 1 >= args.length) {
|
|
2307
2307
|
console.error('Error: --objects parameter required');
|
|
2308
|
-
console.error('Usage: abapgit-agent preview --objects <table1>,<view1>,... [--type <type>] [--limit <n>] [--where <condition>] [--columns <cols>] [--vertical] [--compact] [--json]');
|
|
2308
|
+
console.error('Usage: abapgit-agent preview --objects <table1>,<view1>,... [--type <type>] [--limit <n>] [--offset <n>] [--where <condition>] [--columns <cols>] [--vertical] [--compact] [--json]');
|
|
2309
2309
|
console.error('Example: abapgit-agent preview --objects SFLIGHT');
|
|
2310
2310
|
console.error('Example: abapgit-agent preview --objects ZC_MY_CDS_VIEW --type DDLS');
|
|
2311
2311
|
console.error('Example: abapgit-agent preview --objects SFLIGHT --where "CARRID = \'AA\'"');
|
|
2312
|
+
console.error('Example: abapgit-agent preview --objects SFLIGHT --offset 10 --limit 20');
|
|
2312
2313
|
process.exit(1);
|
|
2313
2314
|
}
|
|
2314
2315
|
|
|
@@ -2316,7 +2317,13 @@ Examples:
|
|
|
2316
2317
|
const typeArg = args.indexOf('--type');
|
|
2317
2318
|
const type = typeArg !== -1 ? args[typeArg + 1].toUpperCase() : null;
|
|
2318
2319
|
const limitArg = args.indexOf('--limit');
|
|
2319
|
-
const
|
|
2320
|
+
const limitRaw = limitArg !== -1 ? args[limitArg + 1] : null;
|
|
2321
|
+
const limitParsed = parseInt(limitRaw, 10);
|
|
2322
|
+
const limit = limitRaw && !limitRaw.startsWith('--') && !isNaN(limitParsed) ? Math.max(1, limitParsed) : 100;
|
|
2323
|
+
const offsetArg = args.indexOf('--offset');
|
|
2324
|
+
const offsetRaw = offsetArg !== -1 ? args[offsetArg + 1] : null;
|
|
2325
|
+
const offsetParsed = parseInt(offsetRaw, 10);
|
|
2326
|
+
const offset = offsetRaw && !offsetRaw.startsWith('--') && !isNaN(offsetParsed) ? Math.max(0, offsetParsed) : 0;
|
|
2320
2327
|
const whereArg = args.indexOf('--where');
|
|
2321
2328
|
const where = whereArg !== -1 ? args[whereArg + 1] : null;
|
|
2322
2329
|
const columnsArg = args.indexOf('--columns');
|
|
@@ -2332,7 +2339,8 @@ Examples:
|
|
|
2332
2339
|
|
|
2333
2340
|
const data = {
|
|
2334
2341
|
objects: objects,
|
|
2335
|
-
limit: Math.min(Math.max(1, limit),
|
|
2342
|
+
limit: Math.min(Math.max(1, limit), 500),
|
|
2343
|
+
offset: Math.max(0, offset)
|
|
2336
2344
|
};
|
|
2337
2345
|
|
|
2338
2346
|
if (type) {
|
|
@@ -2360,10 +2368,30 @@ Examples:
|
|
|
2360
2368
|
break;
|
|
2361
2369
|
}
|
|
2362
2370
|
|
|
2371
|
+
const pagination = result.PAGINATION || result.pagination || null;
|
|
2372
|
+
|
|
2363
2373
|
if (jsonOutput) {
|
|
2364
2374
|
console.log(JSON.stringify(result, null, 2));
|
|
2365
2375
|
} else {
|
|
2366
|
-
|
|
2376
|
+
// Build pagination message
|
|
2377
|
+
let paginationMsg = '';
|
|
2378
|
+
const paginationTotal = pagination ? (pagination.TOTAL || pagination.total || 0) : 0;
|
|
2379
|
+
const paginationHasMore = pagination ? (pagination.HAS_MORE || pagination.has_more || false) : false;
|
|
2380
|
+
if (pagination && paginationTotal > 0) {
|
|
2381
|
+
// Handle case where offset exceeds total
|
|
2382
|
+
if (offset >= paginationTotal) {
|
|
2383
|
+
paginationMsg = ` (Offset ${offset} exceeds total ${paginationTotal})`;
|
|
2384
|
+
} else {
|
|
2385
|
+
const start = offset + 1;
|
|
2386
|
+
const end = Math.min(offset + limit, paginationTotal);
|
|
2387
|
+
paginationMsg = ` (Showing ${start}-${end} of ${paginationTotal})`;
|
|
2388
|
+
if (paginationHasMore) {
|
|
2389
|
+
paginationMsg += ` — Use --offset ${offset + limit} to see more`;
|
|
2390
|
+
}
|
|
2391
|
+
}
|
|
2392
|
+
}
|
|
2393
|
+
|
|
2394
|
+
console.log(`\n ${message}${paginationMsg}`);
|
|
2367
2395
|
console.log('');
|
|
2368
2396
|
|
|
2369
2397
|
// Track if columns were explicitly specified
|
|
@@ -2542,10 +2570,11 @@ Examples:
|
|
|
2542
2570
|
const objectsArgIndex = args.indexOf('--objects');
|
|
2543
2571
|
if (objectsArgIndex === -1 || objectsArgIndex + 1 >= args.length) {
|
|
2544
2572
|
console.error('Error: --objects parameter required');
|
|
2545
|
-
console.error('Usage: abapgit-agent where --objects <obj1>,<obj2>,... [--type <type>] [--limit <n>] [--json]');
|
|
2573
|
+
console.error('Usage: abapgit-agent where --objects <obj1>,<obj2>,... [--type <type>] [--limit <n>] [--offset <n>] [--json]');
|
|
2546
2574
|
console.error('Example: abapgit-agent where --objects ZCL_MY_CLASS');
|
|
2547
2575
|
console.error('Example: abapgit-agent where --objects ZIF_MY_INTERFACE');
|
|
2548
2576
|
console.error('Example: abapgit-agent where --objects CL_SUT_AUNIT_RUNNER --limit 20');
|
|
2577
|
+
console.error('Example: abapgit-agent where --objects CL_SUT_AUNIT_RUNNER --offset 100');
|
|
2549
2578
|
process.exit(1);
|
|
2550
2579
|
}
|
|
2551
2580
|
|
|
@@ -2553,7 +2582,13 @@ Examples:
|
|
|
2553
2582
|
const typeArg = args.indexOf('--type');
|
|
2554
2583
|
const type = typeArg !== -1 ? args[typeArg + 1].toUpperCase() : null;
|
|
2555
2584
|
const limitArg = args.indexOf('--limit');
|
|
2556
|
-
const
|
|
2585
|
+
const limitRaw = limitArg !== -1 ? args[limitArg + 1] : null;
|
|
2586
|
+
const limitParsed = parseInt(limitRaw, 10);
|
|
2587
|
+
const limit = limitRaw && !limitRaw.startsWith('--') && !isNaN(limitParsed) ? Math.max(1, limitParsed) : 100;
|
|
2588
|
+
const offsetArg = args.indexOf('--offset');
|
|
2589
|
+
const offsetRaw = offsetArg !== -1 ? args[offsetArg + 1] : null;
|
|
2590
|
+
const offsetParsed = parseInt(offsetRaw, 10);
|
|
2591
|
+
const offset = offsetRaw && !offsetRaw.startsWith('--') && !isNaN(offsetParsed) ? Math.max(0, offsetParsed) : 0;
|
|
2557
2592
|
const jsonOutput = args.includes('--json');
|
|
2558
2593
|
|
|
2559
2594
|
console.log(`\n Where-used list for ${objects.length} object(s)`);
|
|
@@ -2563,7 +2598,8 @@ Examples:
|
|
|
2563
2598
|
|
|
2564
2599
|
const data = {
|
|
2565
2600
|
objects: objects,
|
|
2566
|
-
limit: Math.min(Math.max(1, limit), 500)
|
|
2601
|
+
limit: Math.min(Math.max(1, limit), 500),
|
|
2602
|
+
offset: Math.max(0, offset)
|
|
2567
2603
|
};
|
|
2568
2604
|
|
|
2569
2605
|
if (type) {
|
|
@@ -2577,6 +2613,7 @@ Examples:
|
|
|
2577
2613
|
const whereObjects = result.OBJECTS || result.objects || [];
|
|
2578
2614
|
const message = result.MESSAGE || result.message || '';
|
|
2579
2615
|
const error = result.ERROR || result.error;
|
|
2616
|
+
const pagination = result.PAGINATION || result.pagination || null;
|
|
2580
2617
|
|
|
2581
2618
|
if (!success || error) {
|
|
2582
2619
|
console.error(`\n Error: ${error || 'Failed to get where-used list'}`);
|
|
@@ -2586,7 +2623,25 @@ Examples:
|
|
|
2586
2623
|
if (jsonOutput) {
|
|
2587
2624
|
console.log(JSON.stringify(result, null, 2));
|
|
2588
2625
|
} else {
|
|
2589
|
-
|
|
2626
|
+
// Build pagination message
|
|
2627
|
+
let paginationMsg = '';
|
|
2628
|
+
const paginationTotal = pagination.TOTAL || pagination.total || 0;
|
|
2629
|
+
const paginationHasMore = pagination.HAS_MORE || pagination.has_more || false;
|
|
2630
|
+
if (pagination && paginationTotal > 0) {
|
|
2631
|
+
// Handle case where offset exceeds total
|
|
2632
|
+
if (offset >= paginationTotal) {
|
|
2633
|
+
paginationMsg = ` (Offset ${offset} exceeds total ${paginationTotal})`;
|
|
2634
|
+
} else {
|
|
2635
|
+
const start = offset + 1;
|
|
2636
|
+
const end = Math.min(offset + limit, paginationTotal);
|
|
2637
|
+
paginationMsg = ` (Showing ${start}-${end} of ${paginationTotal})`;
|
|
2638
|
+
if (paginationHasMore) {
|
|
2639
|
+
paginationMsg += ` — Use --offset ${offset + limit} to see more`;
|
|
2640
|
+
}
|
|
2641
|
+
}
|
|
2642
|
+
}
|
|
2643
|
+
|
|
2644
|
+
console.log(`\n ${message}${paginationMsg}`);
|
|
2590
2645
|
console.log('');
|
|
2591
2646
|
|
|
2592
2647
|
for (let i = 0; i < whereObjects.length; i++) {
|
|
@@ -2640,17 +2695,21 @@ Examples:
|
|
|
2640
2695
|
case 'ref': {
|
|
2641
2696
|
const refSearch = require('../src/ref-search');
|
|
2642
2697
|
const topicIndex = args.indexOf('--topic');
|
|
2698
|
+
const cloneIndex = args.indexOf('--clone');
|
|
2699
|
+
const nameIndex = args.indexOf('--name');
|
|
2643
2700
|
const listTopics = args.includes('--list-topics') || args.includes('-l');
|
|
2644
2701
|
const listRepos = args.includes('--list-repos') || args.includes('-r');
|
|
2645
|
-
const exportGuidelines = args.includes('--export') || args.includes('-e');
|
|
2646
2702
|
const jsonOutput = args.includes('--json');
|
|
2647
2703
|
|
|
2648
|
-
|
|
2649
|
-
|
|
2704
|
+
// Handle --clone option
|
|
2705
|
+
if (cloneIndex !== -1 && cloneIndex + 1 < args.length) {
|
|
2706
|
+
const repoUrl = args[cloneIndex + 1];
|
|
2707
|
+
const name = nameIndex !== -1 && nameIndex + 1 < args.length ? args[nameIndex + 1] : null;
|
|
2708
|
+
const result = refSearch.cloneRepository(repoUrl, name);
|
|
2650
2709
|
if (jsonOutput) {
|
|
2651
2710
|
console.log(JSON.stringify(result, null, 2));
|
|
2652
2711
|
} else {
|
|
2653
|
-
refSearch.
|
|
2712
|
+
refSearch.displayCloneResult(result);
|
|
2654
2713
|
}
|
|
2655
2714
|
break;
|
|
2656
2715
|
}
|
|
@@ -2695,15 +2754,16 @@ Examples:
|
|
|
2695
2754
|
console.error(' abapgit-agent ref <pattern> Search for pattern');
|
|
2696
2755
|
console.error(' abapgit-agent ref --topic <name> View specific topic');
|
|
2697
2756
|
console.error(' abapgit-agent ref --list-topics List available topics');
|
|
2698
|
-
console.error(' abapgit-agent ref --list-repos
|
|
2699
|
-
console.error(' abapgit-agent ref --
|
|
2757
|
+
console.error(' abapgit-agent ref --list-repos List reference repositories');
|
|
2758
|
+
console.error(' abapgit-agent ref --clone <repo> Clone a repository');
|
|
2700
2759
|
console.error('');
|
|
2701
2760
|
console.error('Examples:');
|
|
2702
2761
|
console.error(' abapgit-agent ref "CORRESPONDING"');
|
|
2703
2762
|
console.error(' abapgit-agent ref --topic exceptions');
|
|
2704
2763
|
console.error(' abapgit-agent ref --list-topics');
|
|
2705
2764
|
console.error(' abapgit-agent ref --list-repos');
|
|
2706
|
-
console.error(' abapgit-agent ref --
|
|
2765
|
+
console.error(' abapgit-agent ref --clone SAP-samples/abap-cheat-sheets');
|
|
2766
|
+
console.error(' abapgit-agent ref --clone https://github.com/abapGit/abapGit.git');
|
|
2707
2767
|
process.exit(1);
|
|
2708
2768
|
}
|
|
2709
2769
|
|
|
@@ -2777,8 +2837,10 @@ Commands:
|
|
|
2777
2837
|
ref --list-repos
|
|
2778
2838
|
List all reference repositories in the reference folder
|
|
2779
2839
|
|
|
2780
|
-
ref --
|
|
2781
|
-
|
|
2840
|
+
ref --clone <repo> [--name <folder>]
|
|
2841
|
+
Clone a GitHub repository to the reference folder
|
|
2842
|
+
- Use full URL: https://github.com/user/repo.git
|
|
2843
|
+
- Or short name: user/repo or user/repo (assumes github.com)
|
|
2782
2844
|
|
|
2783
2845
|
health
|
|
2784
2846
|
Check if ABAP REST API is healthy
|
|
@@ -2823,7 +2885,8 @@ Examples:
|
|
|
2823
2885
|
abapgit-agent ref --topic unit-tests # View unit test topic
|
|
2824
2886
|
abapgit-agent ref --list-topics # List all topics
|
|
2825
2887
|
abapgit-agent ref --list-repos # List reference repositories
|
|
2826
|
-
abapgit-agent ref --
|
|
2888
|
+
abapgit-agent ref --clone SAP-samples/abap-cheat-sheets # Clone repo to reference folder
|
|
2889
|
+
abapgit-agent ref --clone https://github.com/user/repo.git # Clone from URL
|
|
2827
2890
|
abapgit-agent health
|
|
2828
2891
|
abapgit-agent status
|
|
2829
2892
|
`);
|
package/package.json
CHANGED
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "abapgit-agent",
|
|
3
|
-
"version": "1.7.
|
|
3
|
+
"version": "1.7.2",
|
|
4
4
|
"description": "ABAP Git Agent - Pull and activate ABAP code via abapGit from any git repository",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"files": [
|
|
7
7
|
"bin/",
|
|
8
8
|
"src/",
|
|
9
|
-
"abap/guidelines/"
|
|
9
|
+
"abap/guidelines/",
|
|
10
|
+
"abap/CLAUDE.md",
|
|
11
|
+
"abap/.github/copilot-instructions.md",
|
|
12
|
+
".abapGitAgent.example"
|
|
10
13
|
],
|
|
11
14
|
"bin": {
|
|
12
15
|
"abapgit-agent": "bin/abapgit-agent",
|
|
@@ -20,6 +23,7 @@
|
|
|
20
23
|
"test:jest": "jest",
|
|
21
24
|
"test:aunit": "node scripts/test-all.js --aunit",
|
|
22
25
|
"test:cmd": "node scripts/test-all.js --cmd",
|
|
26
|
+
"test:cmd:demo": "node scripts/test-all.js --cmd --demo",
|
|
23
27
|
"pull": "node bin/abapgit-agent",
|
|
24
28
|
"release": "node scripts/release.js",
|
|
25
29
|
"unrelease": "node scripts/unrelease.js"
|
package/src/abap-client.js
CHANGED
|
@@ -379,13 +379,14 @@ class ABAPClient {
|
|
|
379
379
|
return await this.request('POST', '/tree', data, { csrfToken: this.csrfToken });
|
|
380
380
|
}
|
|
381
381
|
|
|
382
|
-
async preview(objects, type = null, limit =
|
|
382
|
+
async preview(objects, type = null, limit = 100, offset = 0, where = null, columns = null) {
|
|
383
383
|
// Fetch CSRF token first
|
|
384
384
|
await this.fetchCsrfToken();
|
|
385
385
|
|
|
386
386
|
const data = {
|
|
387
387
|
objects: objects,
|
|
388
|
-
limit: Math.min(Math.max(1, limit),
|
|
388
|
+
limit: Math.min(Math.max(1, limit), 500),
|
|
389
|
+
offset: Math.max(0, offset)
|
|
389
390
|
};
|
|
390
391
|
|
|
391
392
|
if (type) {
|
|
@@ -402,7 +403,7 @@ class ABAPClient {
|
|
|
402
403
|
data.columns = columns;
|
|
403
404
|
}
|
|
404
405
|
|
|
405
|
-
logger.info('Previewing data', { objects, type, limit: data.limit, where: data.where, service: 'abapgit-agent' });
|
|
406
|
+
logger.info('Previewing data', { objects, type, limit: data.limit, offset: data.offset, where: data.where, service: 'abapgit-agent' });
|
|
406
407
|
|
|
407
408
|
return await this.request('POST', '/preview', data, { csrfToken: this.csrfToken });
|
|
408
409
|
}
|
|
@@ -487,21 +488,23 @@ class ABAPClient {
|
|
|
487
488
|
* @param {Array} objects - Array of object names to search
|
|
488
489
|
* @param {string} type - Object type (optional)
|
|
489
490
|
* @param {number} limit - Maximum results (default: 100, max: 500)
|
|
491
|
+
* @param {number} offset - Number of results to skip (default: 0)
|
|
490
492
|
* @returns {object} Where-used result with found objects
|
|
491
493
|
*/
|
|
492
|
-
async where(objects, type = null, limit = 100) {
|
|
494
|
+
async where(objects, type = null, limit = 100, offset = 0) {
|
|
493
495
|
await this.fetchCsrfToken();
|
|
494
496
|
|
|
495
497
|
const data = {
|
|
496
498
|
objects: objects,
|
|
497
|
-
limit: Math.min(Math.max(1, limit), 500)
|
|
499
|
+
limit: Math.min(Math.max(1, limit), 500),
|
|
500
|
+
offset: Math.max(0, offset)
|
|
498
501
|
};
|
|
499
502
|
|
|
500
503
|
if (type) {
|
|
501
504
|
data.type = type;
|
|
502
505
|
}
|
|
503
506
|
|
|
504
|
-
logger.info('Finding where-used', { objects, type, limit: data.limit, service: 'abapgit-agent' });
|
|
507
|
+
logger.info('Finding where-used', { objects, type, limit: data.limit, offset: data.offset, service: 'abapgit-agent' });
|
|
505
508
|
|
|
506
509
|
return await this.request('POST', '/where', data, { csrfToken: this.csrfToken });
|
|
507
510
|
}
|
package/src/agent.js
CHANGED
|
@@ -197,21 +197,23 @@ class ABAPGitAgent {
|
|
|
197
197
|
* @param {Array} objects - Array of table/view names
|
|
198
198
|
* @param {string} type - Object type (TABL, DDLS, etc.)
|
|
199
199
|
* @param {number} limit - Maximum rows to return
|
|
200
|
+
* @param {number} offset - Number of rows to skip
|
|
200
201
|
* @param {string} where - WHERE clause filter
|
|
201
202
|
* @param {Array} columns - Array of column names to display
|
|
202
203
|
* @returns {object} Preview result with rows, fields, and metadata
|
|
203
204
|
*/
|
|
204
|
-
async preview(objects, type = null, limit =
|
|
205
|
-
logger.info('Previewing data', { objects, type, limit, where, columns });
|
|
205
|
+
async preview(objects, type = null, limit = 100, offset = 0, where = null, columns = null) {
|
|
206
|
+
logger.info('Previewing data', { objects, type, limit, offset, where, columns });
|
|
206
207
|
|
|
207
208
|
try {
|
|
208
|
-
const result = await this.abap.preview(objects, type, limit, where, columns);
|
|
209
|
+
const result = await this.abap.preview(objects, type, limit, offset, where, columns);
|
|
209
210
|
return {
|
|
210
211
|
success: result.SUCCESS === 'X' || result.success === 'X' || result.success === true,
|
|
211
212
|
command: result.COMMAND || result.command || 'PREVIEW',
|
|
212
213
|
message: result.MESSAGE || result.message || '',
|
|
213
214
|
objects: result.OBJECTS || result.objects || [],
|
|
214
215
|
summary: result.SUMMARY || result.summary || null,
|
|
216
|
+
pagination: result.PAGINATION || result.pagination || null,
|
|
215
217
|
error: result.ERROR || result.error || null
|
|
216
218
|
};
|
|
217
219
|
} catch (error) {
|
|
@@ -293,18 +295,20 @@ class ABAPGitAgent {
|
|
|
293
295
|
* @param {Array} objects - Array of object names to search
|
|
294
296
|
* @param {string} type - Object type (optional)
|
|
295
297
|
* @param {number} limit - Maximum results (default: 100, max: 500)
|
|
298
|
+
* @param {number} offset - Number of results to skip (default: 0)
|
|
296
299
|
* @returns {object} Where-used result with found objects
|
|
297
300
|
*/
|
|
298
|
-
async where(objects, type = null, limit = 100) {
|
|
299
|
-
logger.info('Finding where-used', { objects, type, limit });
|
|
301
|
+
async where(objects, type = null, limit = 100, offset = 0) {
|
|
302
|
+
logger.info('Finding where-used', { objects, type, limit, offset });
|
|
300
303
|
|
|
301
304
|
try {
|
|
302
|
-
const result = await this.abap.where(objects, type, limit);
|
|
305
|
+
const result = await this.abap.where(objects, type, limit, offset);
|
|
303
306
|
return {
|
|
304
307
|
success: result.SUCCESS === 'X' || result.success === 'X' || result.success === true,
|
|
305
308
|
command: result.COMMAND || result.command || 'WHERE',
|
|
306
309
|
objects: result.OBJECTS || result.objects || [],
|
|
307
310
|
message: result.MESSAGE || result.message || '',
|
|
311
|
+
pagination: result.PAGINATION || result.pagination || null,
|
|
308
312
|
error: result.ERROR || result.error || null
|
|
309
313
|
};
|
|
310
314
|
} catch (error) {
|
package/src/ref-search.js
CHANGED
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
const fs = require('fs');
|
|
9
9
|
const path = require('path');
|
|
10
10
|
const { promisify } = require('util');
|
|
11
|
+
const { execSync } = require('child_process');
|
|
11
12
|
const readdir = promisify(fs.readdir);
|
|
12
13
|
const readFile = promisify(fs.readFile);
|
|
13
14
|
const stat = promisify(fs.stat);
|
|
@@ -63,6 +64,120 @@ const TOPIC_MAP = {
|
|
|
63
64
|
'tables': '01_Internal_Tables.md'
|
|
64
65
|
};
|
|
65
66
|
|
|
67
|
+
/**
|
|
68
|
+
* Ensure reference folder exists, create if necessary
|
|
69
|
+
* @returns {string|null} Path to reference folder or null if cannot create
|
|
70
|
+
*/
|
|
71
|
+
function ensureReferenceFolder() {
|
|
72
|
+
let refFolder = detectReferenceFolder();
|
|
73
|
+
|
|
74
|
+
if (refFolder && fs.existsSync(refFolder)) {
|
|
75
|
+
return refFolder;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// Try to create the reference folder at default location
|
|
79
|
+
const homeDir = require('os').homedir();
|
|
80
|
+
const defaultPath = path.join(homeDir, 'abap-reference');
|
|
81
|
+
|
|
82
|
+
try {
|
|
83
|
+
if (!fs.existsSync(defaultPath)) {
|
|
84
|
+
fs.mkdirSync(defaultPath, { recursive: true });
|
|
85
|
+
}
|
|
86
|
+
return defaultPath;
|
|
87
|
+
} catch (error) {
|
|
88
|
+
return null;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Clone a repository to the reference folder
|
|
94
|
+
* @param {string} repoUrl - Git repository URL or short name (e.g., "SAP-samples/abap-cheat-sheets")
|
|
95
|
+
* @param {string|null} name - Optional folder name for the cloned repo
|
|
96
|
+
* @returns {Object} Clone result
|
|
97
|
+
*/
|
|
98
|
+
function cloneRepository(repoUrl, name = null) {
|
|
99
|
+
const refFolder = ensureReferenceFolder();
|
|
100
|
+
|
|
101
|
+
if (!refFolder) {
|
|
102
|
+
return {
|
|
103
|
+
success: false,
|
|
104
|
+
error: 'Could not create reference folder',
|
|
105
|
+
hint: 'Set referenceFolder in .abapGitAgent or ensure ~/abap-reference is writable'
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// Parse the repo URL
|
|
110
|
+
let targetName = name;
|
|
111
|
+
let cloneUrl = repoUrl;
|
|
112
|
+
|
|
113
|
+
// Handle short names (e.g., "SAP-samples/abap-cheat-sheets")
|
|
114
|
+
if (!repoUrl.startsWith('http://') && !repoUrl.startsWith('https://') && !repoUrl.startsWith('git@')) {
|
|
115
|
+
cloneUrl = `https://github.com/${repoUrl}.git`;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// If no name provided, extract from URL
|
|
119
|
+
if (!targetName) {
|
|
120
|
+
// Extract repo name from URL
|
|
121
|
+
const urlParts = cloneUrl.split('/');
|
|
122
|
+
const repoWithGit = urlParts[urlParts.length - 1];
|
|
123
|
+
targetName = repoWithGit.replace(/\.git$/, '');
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
const targetPath = path.join(refFolder, targetName);
|
|
127
|
+
|
|
128
|
+
// Check if already exists
|
|
129
|
+
if (fs.existsSync(targetPath)) {
|
|
130
|
+
return {
|
|
131
|
+
success: false,
|
|
132
|
+
error: `Repository already exists: ${targetName}`,
|
|
133
|
+
hint: `Delete '${targetPath}' to re-clone, or use --name to specify a different folder name`,
|
|
134
|
+
existingPath: targetPath
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
try {
|
|
139
|
+
// Run git clone
|
|
140
|
+
execSync(`git clone "${cloneUrl}" "${targetPath}"`, {
|
|
141
|
+
stdio: 'pipe',
|
|
142
|
+
encoding: 'utf8'
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
return {
|
|
146
|
+
success: true,
|
|
147
|
+
message: `Successfully cloned ${repoUrl}`,
|
|
148
|
+
repository: targetName,
|
|
149
|
+
folder: targetPath,
|
|
150
|
+
referenceFolder: refFolder
|
|
151
|
+
};
|
|
152
|
+
} catch (error) {
|
|
153
|
+
return {
|
|
154
|
+
success: false,
|
|
155
|
+
error: `Failed to clone: ${error.message}`,
|
|
156
|
+
hint: 'Check the repository URL and your network connection'
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Display clone result in console format
|
|
163
|
+
* @param {Object} result - Clone result
|
|
164
|
+
*/
|
|
165
|
+
function displayCloneResult(result) {
|
|
166
|
+
if (result.success) {
|
|
167
|
+
console.log(`\n ✅ ${result.message}`);
|
|
168
|
+
console.log(`\n 📁 Repository: ${result.repository}`);
|
|
169
|
+
console.log(` 📁 Location: ${result.folder}`);
|
|
170
|
+
console.log(` 📁 Reference folder: ${result.referenceFolder}`);
|
|
171
|
+
console.log(`\n 💡 You can now search this repository with:`);
|
|
172
|
+
console.log(` abapgit-agent ref --list-repos`);
|
|
173
|
+
} else {
|
|
174
|
+
console.error(`\n ❌ ${result.error}`);
|
|
175
|
+
if (result.hint) {
|
|
176
|
+
console.error(`\n 💡 ${result.hint}`);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
66
181
|
/**
|
|
67
182
|
* Detect reference folder from config or common locations
|
|
68
183
|
* @returns {string|null} Path to reference folder or null if not found
|
|
@@ -1005,7 +1120,7 @@ function displayInitResult(result) {
|
|
|
1005
1120
|
console.log(`\n 💡 Next steps:`);
|
|
1006
1121
|
console.log(` 1. Review the guidelines in abap/guidelines/`);
|
|
1007
1122
|
console.log(` 2. Customize as needed for your project`);
|
|
1008
|
-
console.log(` 3.
|
|
1123
|
+
console.log(` 3. Guidelines are automatically searchable with 'ref' command`);
|
|
1009
1124
|
} else {
|
|
1010
1125
|
console.error(`\n ❌ ${result.error}`);
|
|
1011
1126
|
if (result.hint) {
|
|
@@ -1016,6 +1131,7 @@ function displayInitResult(result) {
|
|
|
1016
1131
|
|
|
1017
1132
|
module.exports = {
|
|
1018
1133
|
detectReferenceFolder,
|
|
1134
|
+
ensureReferenceFolder,
|
|
1019
1135
|
detectGuidelinesFolder,
|
|
1020
1136
|
getBuiltInGuidelinesPath,
|
|
1021
1137
|
initGuidelines,
|
|
@@ -1027,11 +1143,13 @@ module.exports = {
|
|
|
1027
1143
|
listTopics,
|
|
1028
1144
|
listRepositories,
|
|
1029
1145
|
exportGuidelines,
|
|
1146
|
+
cloneRepository,
|
|
1030
1147
|
displaySearchResults,
|
|
1031
1148
|
displayTopic,
|
|
1032
1149
|
displayTopics,
|
|
1033
1150
|
displayRepositories,
|
|
1034
1151
|
displayExportResult,
|
|
1035
1152
|
displayInitResult,
|
|
1153
|
+
displayCloneResult,
|
|
1036
1154
|
TOPIC_MAP
|
|
1037
1155
|
};
|