abapgit-agent 1.7.0 → 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/README.md +10 -0
- package/abap/.github/copilot-instructions.md +254 -0
- package/abap/CLAUDE.md +313 -0
- package/bin/abapgit-agent +183 -20
- package/package.json +8 -4
- 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
|
+
}
|
package/README.md
CHANGED
|
@@ -52,6 +52,9 @@ abapgit-agent init --folder /abap/ --package ZMY_PACKAGE
|
|
|
52
52
|
# Create online repository in ABAP
|
|
53
53
|
abapgit-agent create
|
|
54
54
|
|
|
55
|
+
# Delete online repository from ABAP (keeps local files)
|
|
56
|
+
abapgit-agent delete
|
|
57
|
+
|
|
55
58
|
# Import objects from ABAP package to git
|
|
56
59
|
abapgit-agent import
|
|
57
60
|
```
|
|
@@ -113,6 +116,11 @@ abapgit-agent preview --objects SFLIGHT --where "CARRID = 'AA'"
|
|
|
113
116
|
abapgit-agent preview --objects SFLIGHT --columns CARRID,CONNID,PRICE
|
|
114
117
|
abapgit-agent preview --objects SFLIGHT --vertical
|
|
115
118
|
abapgit-agent preview --objects SFLIGHT --compact
|
|
119
|
+
|
|
120
|
+
# Find where-used (objects using a specific object)
|
|
121
|
+
abapgit-agent where --objects ZCL_MY_CLASS
|
|
122
|
+
abapgit-agent where --objects ZIF_MY_INTERFACE
|
|
123
|
+
abapgit-agent where --objects ZCL_MY_CLASS --type CLAS
|
|
116
124
|
```
|
|
117
125
|
|
|
118
126
|
### Utility Commands
|
|
@@ -147,6 +155,7 @@ npm run pull -- --url <git-url> --branch main
|
|
|
147
155
|
| Installation & Setup | [INSTALL.md](INSTALL.md) |
|
|
148
156
|
| init Command | [docs/init-command.md](docs/init-command.md) |
|
|
149
157
|
| create Command | [docs/create-command.md](docs/create-command.md) |
|
|
158
|
+
| delete Command | [docs/delete-command.md](docs/delete-command.md) |
|
|
150
159
|
| import Command | [docs/import-command.md](docs/import-command.md) |
|
|
151
160
|
| pull Command | [docs/pull-command.md](docs/pull-command.md) |
|
|
152
161
|
| inspect Command | [docs/inspect-command.md](docs/inspect-command.md) |
|
|
@@ -154,6 +163,7 @@ npm run pull -- --url <git-url> --branch main
|
|
|
154
163
|
| tree Command | [docs/tree-command.md](docs/tree-command.md) |
|
|
155
164
|
| view Command | [docs/view-command.md](docs/view-command.md) |
|
|
156
165
|
| preview Command | [docs/preview-command.md](docs/preview-command.md) |
|
|
166
|
+
| where Command | [docs/where-command.md](docs/where-command.md) |
|
|
157
167
|
| ref Command | [docs/ref-command.md](docs/ref-command.md) |
|
|
158
168
|
| REST API Reference | [API.md](API.md) |
|
|
159
169
|
| Error Handling | [ERROR_HANDLING.md](ERROR_HANDLING.md) |
|
|
@@ -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
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
* abapgit-agent init --folder <folder> --package <package> # Initialize: copies config, CLAUDE.md, guidelines
|
|
7
7
|
* abapgit-agent init --update # Update existing files to latest version
|
|
8
8
|
* abapgit-agent create
|
|
9
|
+
* abapgit-agent delete
|
|
9
10
|
* abapgit-agent import [--message <message>]
|
|
10
11
|
* abapgit-agent pull [--branch <branch>]
|
|
11
12
|
* abapgit-agent pull --url <git-url> [--branch <branch>]
|
|
@@ -1228,10 +1229,19 @@ async function runInit(args) {
|
|
|
1228
1229
|
const updateMode = args.includes('--update');
|
|
1229
1230
|
|
|
1230
1231
|
// Get parameters
|
|
1231
|
-
|
|
1232
|
+
let folder = folderArgIndex !== -1 && folderArgIndex + 1 < args.length
|
|
1232
1233
|
? args[folderArgIndex + 1]
|
|
1233
1234
|
: '/src/';
|
|
1234
1235
|
|
|
1236
|
+
// Normalize folder path: ensure it starts with / and ends with /
|
|
1237
|
+
folder = folder.trim();
|
|
1238
|
+
if (!folder.startsWith('/')) {
|
|
1239
|
+
folder = '/' + folder;
|
|
1240
|
+
}
|
|
1241
|
+
if (!folder.endsWith('/')) {
|
|
1242
|
+
folder = folder + '/';
|
|
1243
|
+
}
|
|
1244
|
+
|
|
1235
1245
|
const packageName = packageArgIndex !== -1 && packageArgIndex + 1 < args.length
|
|
1236
1246
|
? args[packageArgIndex + 1]
|
|
1237
1247
|
: null;
|
|
@@ -1503,7 +1513,7 @@ To enable integration:
|
|
|
1503
1513
|
}
|
|
1504
1514
|
|
|
1505
1515
|
// Version compatibility check for commands that interact with ABAP
|
|
1506
|
-
const abapCommands = ['create', 'import', 'pull', 'inspect', 'unit', 'tree', 'view', 'preview', 'list'];
|
|
1516
|
+
const abapCommands = ['create', 'delete', 'import', 'pull', 'inspect', 'unit', 'tree', 'view', 'preview', 'list'];
|
|
1507
1517
|
if (command && abapCommands.includes(command)) {
|
|
1508
1518
|
await checkVersionCompatibility();
|
|
1509
1519
|
}
|
|
@@ -1605,6 +1615,67 @@ Examples:
|
|
|
1605
1615
|
break;
|
|
1606
1616
|
}
|
|
1607
1617
|
|
|
1618
|
+
case 'delete': {
|
|
1619
|
+
const helpIndex = args.findIndex(a => a === '--help' || a === '-h');
|
|
1620
|
+
|
|
1621
|
+
// Show help if requested
|
|
1622
|
+
if (helpIndex !== -1) {
|
|
1623
|
+
console.log(`
|
|
1624
|
+
Usage:
|
|
1625
|
+
abapgit-agent delete
|
|
1626
|
+
|
|
1627
|
+
Description:
|
|
1628
|
+
Delete abapGit online repository from ABAP system.
|
|
1629
|
+
Auto-detects URL from git remote of current directory.
|
|
1630
|
+
|
|
1631
|
+
Prerequisites:
|
|
1632
|
+
- Run "abapgit-agent create" first
|
|
1633
|
+
|
|
1634
|
+
Examples:
|
|
1635
|
+
abapgit-agent delete # Delete repo for current git remote
|
|
1636
|
+
`);
|
|
1637
|
+
return;
|
|
1638
|
+
}
|
|
1639
|
+
|
|
1640
|
+
// Get URL from current git remote
|
|
1641
|
+
const config = loadConfig();
|
|
1642
|
+
const repoUrl = getGitRemoteUrl();
|
|
1643
|
+
|
|
1644
|
+
if (!repoUrl) {
|
|
1645
|
+
console.error('Error: No git remote configured. Please configure a remote origin.');
|
|
1646
|
+
process.exit(1);
|
|
1647
|
+
}
|
|
1648
|
+
|
|
1649
|
+
console.log(`\n🗑️ Deleting online repository`);
|
|
1650
|
+
console.log(` URL: ${repoUrl}`);
|
|
1651
|
+
|
|
1652
|
+
const csrfToken = await fetchCsrfToken(config);
|
|
1653
|
+
|
|
1654
|
+
const data = {
|
|
1655
|
+
url: repoUrl
|
|
1656
|
+
};
|
|
1657
|
+
|
|
1658
|
+
const result = await request('POST', '/sap/bc/z_abapgit_agent/delete', data, { csrfToken });
|
|
1659
|
+
|
|
1660
|
+
console.log('\n');
|
|
1661
|
+
|
|
1662
|
+
// Handle uppercase keys from ABAP
|
|
1663
|
+
const success = result.SUCCESS || result.success;
|
|
1664
|
+
const repoKey = result.REPO_KEY || result.repo_key;
|
|
1665
|
+
const message = result.MESSAGE || result.message;
|
|
1666
|
+
const error = result.ERROR || result.error;
|
|
1667
|
+
|
|
1668
|
+
if (success === 'X' || success === true) {
|
|
1669
|
+
console.log(`✅ Repository deleted successfully!`);
|
|
1670
|
+
console.log(` Key: ${repoKey}`);
|
|
1671
|
+
} else {
|
|
1672
|
+
console.log(`❌ Failed to delete repository`);
|
|
1673
|
+
console.log(` Error: ${error || message || 'Unknown error'}`);
|
|
1674
|
+
process.exit(1);
|
|
1675
|
+
}
|
|
1676
|
+
break;
|
|
1677
|
+
}
|
|
1678
|
+
|
|
1608
1679
|
case 'import': {
|
|
1609
1680
|
const helpIndex = args.findIndex(a => a === '--help' || a === '-h');
|
|
1610
1681
|
|
|
@@ -1739,6 +1810,34 @@ Examples:
|
|
|
1739
1810
|
if (isAbapIntegrationEnabled()) {
|
|
1740
1811
|
console.log('✅ ABAP Git Agent is ENABLED');
|
|
1741
1812
|
console.log(' Config location:', pathModule.join(process.cwd(), '.abapGitAgent'));
|
|
1813
|
+
|
|
1814
|
+
// Check if repo exists in ABAP
|
|
1815
|
+
const config = loadConfig();
|
|
1816
|
+
const repoUrl = getGitRemoteUrl();
|
|
1817
|
+
|
|
1818
|
+
if (repoUrl) {
|
|
1819
|
+
try {
|
|
1820
|
+
const csrfToken = await fetchCsrfToken(config);
|
|
1821
|
+
const result = await request('POST', '/sap/bc/z_abapgit_agent/status', { url: repoUrl }, { csrfToken });
|
|
1822
|
+
|
|
1823
|
+
const status = result.status || result.STATUS || result.SUCCESS;
|
|
1824
|
+
if (status === 'Found' || status === 'X' || status === true) {
|
|
1825
|
+
console.log(' Repository: ✅ Created');
|
|
1826
|
+
console.log(` Package: ${result.PACKAGE || result.package}`);
|
|
1827
|
+
console.log(` URL: ${repoUrl}`);
|
|
1828
|
+
console.log(` Key: ${result.REPO_KEY || result.repo_key}`);
|
|
1829
|
+
} else {
|
|
1830
|
+
console.log(' Repository: ❌ Not created in ABAP system');
|
|
1831
|
+
console.log(` URL: ${repoUrl}`);
|
|
1832
|
+
console.log(' Run "abapgit-agent create" to create repository');
|
|
1833
|
+
}
|
|
1834
|
+
} catch (err) {
|
|
1835
|
+
console.log(' Repository: ⚠️ Unable to check status');
|
|
1836
|
+
console.log(' Error:', err.message);
|
|
1837
|
+
}
|
|
1838
|
+
} else {
|
|
1839
|
+
console.log(' No git remote configured');
|
|
1840
|
+
}
|
|
1742
1841
|
} else {
|
|
1743
1842
|
console.log('❌ ABAP Git Agent is NOT configured');
|
|
1744
1843
|
}
|
|
@@ -2206,10 +2305,11 @@ Examples:
|
|
|
2206
2305
|
const objectsArgIndex = args.indexOf('--objects');
|
|
2207
2306
|
if (objectsArgIndex === -1 || objectsArgIndex + 1 >= args.length) {
|
|
2208
2307
|
console.error('Error: --objects parameter required');
|
|
2209
|
-
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]');
|
|
2210
2309
|
console.error('Example: abapgit-agent preview --objects SFLIGHT');
|
|
2211
2310
|
console.error('Example: abapgit-agent preview --objects ZC_MY_CDS_VIEW --type DDLS');
|
|
2212
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');
|
|
2213
2313
|
process.exit(1);
|
|
2214
2314
|
}
|
|
2215
2315
|
|
|
@@ -2217,7 +2317,13 @@ Examples:
|
|
|
2217
2317
|
const typeArg = args.indexOf('--type');
|
|
2218
2318
|
const type = typeArg !== -1 ? args[typeArg + 1].toUpperCase() : null;
|
|
2219
2319
|
const limitArg = args.indexOf('--limit');
|
|
2220
|
-
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;
|
|
2221
2327
|
const whereArg = args.indexOf('--where');
|
|
2222
2328
|
const where = whereArg !== -1 ? args[whereArg + 1] : null;
|
|
2223
2329
|
const columnsArg = args.indexOf('--columns');
|
|
@@ -2233,7 +2339,8 @@ Examples:
|
|
|
2233
2339
|
|
|
2234
2340
|
const data = {
|
|
2235
2341
|
objects: objects,
|
|
2236
|
-
limit: Math.min(Math.max(1, limit),
|
|
2342
|
+
limit: Math.min(Math.max(1, limit), 500),
|
|
2343
|
+
offset: Math.max(0, offset)
|
|
2237
2344
|
};
|
|
2238
2345
|
|
|
2239
2346
|
if (type) {
|
|
@@ -2261,10 +2368,30 @@ Examples:
|
|
|
2261
2368
|
break;
|
|
2262
2369
|
}
|
|
2263
2370
|
|
|
2371
|
+
const pagination = result.PAGINATION || result.pagination || null;
|
|
2372
|
+
|
|
2264
2373
|
if (jsonOutput) {
|
|
2265
2374
|
console.log(JSON.stringify(result, null, 2));
|
|
2266
2375
|
} else {
|
|
2267
|
-
|
|
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}`);
|
|
2268
2395
|
console.log('');
|
|
2269
2396
|
|
|
2270
2397
|
// Track if columns were explicitly specified
|
|
@@ -2443,10 +2570,11 @@ Examples:
|
|
|
2443
2570
|
const objectsArgIndex = args.indexOf('--objects');
|
|
2444
2571
|
if (objectsArgIndex === -1 || objectsArgIndex + 1 >= args.length) {
|
|
2445
2572
|
console.error('Error: --objects parameter required');
|
|
2446
|
-
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]');
|
|
2447
2574
|
console.error('Example: abapgit-agent where --objects ZCL_MY_CLASS');
|
|
2448
2575
|
console.error('Example: abapgit-agent where --objects ZIF_MY_INTERFACE');
|
|
2449
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');
|
|
2450
2578
|
process.exit(1);
|
|
2451
2579
|
}
|
|
2452
2580
|
|
|
@@ -2454,7 +2582,13 @@ Examples:
|
|
|
2454
2582
|
const typeArg = args.indexOf('--type');
|
|
2455
2583
|
const type = typeArg !== -1 ? args[typeArg + 1].toUpperCase() : null;
|
|
2456
2584
|
const limitArg = args.indexOf('--limit');
|
|
2457
|
-
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;
|
|
2458
2592
|
const jsonOutput = args.includes('--json');
|
|
2459
2593
|
|
|
2460
2594
|
console.log(`\n Where-used list for ${objects.length} object(s)`);
|
|
@@ -2464,7 +2598,8 @@ Examples:
|
|
|
2464
2598
|
|
|
2465
2599
|
const data = {
|
|
2466
2600
|
objects: objects,
|
|
2467
|
-
limit: Math.min(Math.max(1, limit), 500)
|
|
2601
|
+
limit: Math.min(Math.max(1, limit), 500),
|
|
2602
|
+
offset: Math.max(0, offset)
|
|
2468
2603
|
};
|
|
2469
2604
|
|
|
2470
2605
|
if (type) {
|
|
@@ -2478,6 +2613,7 @@ Examples:
|
|
|
2478
2613
|
const whereObjects = result.OBJECTS || result.objects || [];
|
|
2479
2614
|
const message = result.MESSAGE || result.message || '';
|
|
2480
2615
|
const error = result.ERROR || result.error;
|
|
2616
|
+
const pagination = result.PAGINATION || result.pagination || null;
|
|
2481
2617
|
|
|
2482
2618
|
if (!success || error) {
|
|
2483
2619
|
console.error(`\n Error: ${error || 'Failed to get where-used list'}`);
|
|
@@ -2487,7 +2623,25 @@ Examples:
|
|
|
2487
2623
|
if (jsonOutput) {
|
|
2488
2624
|
console.log(JSON.stringify(result, null, 2));
|
|
2489
2625
|
} else {
|
|
2490
|
-
|
|
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}`);
|
|
2491
2645
|
console.log('');
|
|
2492
2646
|
|
|
2493
2647
|
for (let i = 0; i < whereObjects.length; i++) {
|
|
@@ -2541,17 +2695,21 @@ Examples:
|
|
|
2541
2695
|
case 'ref': {
|
|
2542
2696
|
const refSearch = require('../src/ref-search');
|
|
2543
2697
|
const topicIndex = args.indexOf('--topic');
|
|
2698
|
+
const cloneIndex = args.indexOf('--clone');
|
|
2699
|
+
const nameIndex = args.indexOf('--name');
|
|
2544
2700
|
const listTopics = args.includes('--list-topics') || args.includes('-l');
|
|
2545
2701
|
const listRepos = args.includes('--list-repos') || args.includes('-r');
|
|
2546
|
-
const exportGuidelines = args.includes('--export') || args.includes('-e');
|
|
2547
2702
|
const jsonOutput = args.includes('--json');
|
|
2548
2703
|
|
|
2549
|
-
|
|
2550
|
-
|
|
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);
|
|
2551
2709
|
if (jsonOutput) {
|
|
2552
2710
|
console.log(JSON.stringify(result, null, 2));
|
|
2553
2711
|
} else {
|
|
2554
|
-
refSearch.
|
|
2712
|
+
refSearch.displayCloneResult(result);
|
|
2555
2713
|
}
|
|
2556
2714
|
break;
|
|
2557
2715
|
}
|
|
@@ -2596,15 +2754,16 @@ Examples:
|
|
|
2596
2754
|
console.error(' abapgit-agent ref <pattern> Search for pattern');
|
|
2597
2755
|
console.error(' abapgit-agent ref --topic <name> View specific topic');
|
|
2598
2756
|
console.error(' abapgit-agent ref --list-topics List available topics');
|
|
2599
|
-
console.error(' abapgit-agent ref --list-repos
|
|
2600
|
-
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');
|
|
2601
2759
|
console.error('');
|
|
2602
2760
|
console.error('Examples:');
|
|
2603
2761
|
console.error(' abapgit-agent ref "CORRESPONDING"');
|
|
2604
2762
|
console.error(' abapgit-agent ref --topic exceptions');
|
|
2605
2763
|
console.error(' abapgit-agent ref --list-topics');
|
|
2606
2764
|
console.error(' abapgit-agent ref --list-repos');
|
|
2607
|
-
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');
|
|
2608
2767
|
process.exit(1);
|
|
2609
2768
|
}
|
|
2610
2769
|
|
|
@@ -2678,8 +2837,10 @@ Commands:
|
|
|
2678
2837
|
ref --list-repos
|
|
2679
2838
|
List all reference repositories in the reference folder
|
|
2680
2839
|
|
|
2681
|
-
ref --
|
|
2682
|
-
|
|
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)
|
|
2683
2844
|
|
|
2684
2845
|
health
|
|
2685
2846
|
Check if ABAP REST API is healthy
|
|
@@ -2691,6 +2852,7 @@ Examples:
|
|
|
2691
2852
|
abapgit-agent init --folder /src --package ZMY_PACKAGE # Initialize
|
|
2692
2853
|
abapgit-agent init --update # Update files to latest
|
|
2693
2854
|
abapgit-agent create # Create repo
|
|
2855
|
+
abapgit-agent delete # Delete repo
|
|
2694
2856
|
abapgit-agent import # Import objects to git
|
|
2695
2857
|
abapgit-agent import --message "Initial import" # Import with message
|
|
2696
2858
|
abapgit-agent pull # Auto-detect from git
|
|
@@ -2723,7 +2885,8 @@ Examples:
|
|
|
2723
2885
|
abapgit-agent ref --topic unit-tests # View unit test topic
|
|
2724
2886
|
abapgit-agent ref --list-topics # List all topics
|
|
2725
2887
|
abapgit-agent ref --list-repos # List reference repositories
|
|
2726
|
-
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
|
|
2727
2890
|
abapgit-agent health
|
|
2728
2891
|
abapgit-agent status
|
|
2729
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",
|
|
@@ -18,8 +21,9 @@
|
|
|
18
21
|
"test": "jest",
|
|
19
22
|
"test:all": "node scripts/test-all.js",
|
|
20
23
|
"test:jest": "jest",
|
|
21
|
-
"test:aunit": "node scripts/test-all.js --
|
|
22
|
-
"test:cmd": "node scripts/test-all.js --
|
|
24
|
+
"test:aunit": "node scripts/test-all.js --aunit",
|
|
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
|
};
|