@jfrog/opencode-jfrog-plugin 0.0.2 → 0.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +105 -51
- package/dist/index.js +30 -238
- package/package.json +6 -6
- package/skills/jfrog/SKILL.md +529 -0
- package/skills/jfrog/assets/.gitkeep +0 -0
- package/skills/jfrog/references/apptrust-entities.md +154 -0
- package/skills/jfrog/references/artifactory-api-gaps.md +206 -0
- package/skills/jfrog/references/artifactory-aql-syntax.md +656 -0
- package/skills/jfrog/references/artifactory-entities.md +236 -0
- package/skills/jfrog/references/artifactory-operations.md +178 -0
- package/skills/jfrog/references/catalog-entities.md +219 -0
- package/skills/jfrog/references/general-bulk-operations-and-agent-patterns.md +93 -0
- package/skills/jfrog/references/general-parallel-execution.md +131 -0
- package/skills/jfrog/references/general-use-case-hints.md +27 -0
- package/skills/jfrog/references/jfrog-brand-html-report.md +98 -0
- package/skills/jfrog/references/jfrog-cli-install-upgrade.md +30 -0
- package/skills/jfrog/references/jfrog-entity-index.md +112 -0
- package/skills/jfrog/references/jfrog-login-flow.md +132 -0
- package/skills/jfrog/references/jfrog-url-references.md +51 -0
- package/skills/jfrog/references/onemodel-common-patterns.md +323 -0
- package/skills/jfrog/references/onemodel-graphql.md +446 -0
- package/skills/jfrog/references/onemodel-query-examples.md +753 -0
- package/skills/jfrog/references/platform-access-entities.md +200 -0
- package/skills/jfrog/references/platform-admin-api-gaps.md +164 -0
- package/skills/jfrog/references/platform-admin-operations.md +58 -0
- package/skills/jfrog/references/projects-api.md +241 -0
- package/skills/jfrog/references/release-lifecycle-entities.md +180 -0
- package/skills/jfrog/references/stored-packages-entities.md +165 -0
- package/skills/jfrog/references/xray-entities.md +740 -0
- package/skills/jfrog/scripts/check-environment.sh +224 -0
- package/skills/jfrog/scripts/jfrog-login-register-session.sh +84 -0
- package/skills/jfrog/scripts/jfrog-login-save-credentials.sh +128 -0
- package/skills/jfrog-package-safety-and-download/SKILL.md +275 -0
- package/sync-skills-vendor.json +5 -0
|
@@ -0,0 +1,656 @@
|
|
|
1
|
+
# AQL (Artifactory Query Language)
|
|
2
|
+
|
|
3
|
+
AQL queries are sent as POST requests with `Content-Type: text/plain`:
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
jf api /artifactory/api/search/aql \
|
|
7
|
+
-X POST -H "Content-Type: text/plain" -d '<query>'
|
|
8
|
+
```
|
|
9
|
+
|
|
10
|
+
## Query structure
|
|
11
|
+
|
|
12
|
+
```
|
|
13
|
+
<domain>.find(<criteria>)
|
|
14
|
+
.include(<fields>)
|
|
15
|
+
.sort(<sort>)
|
|
16
|
+
.offset(<n>)
|
|
17
|
+
.limit(<n>)
|
|
18
|
+
.distinct(<boolean>)
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Only `.find()` is required. The others are optional and chainable.
|
|
22
|
+
**The chain order above is enforced by the server.** `.include()` must come
|
|
23
|
+
before `.sort()`, `.sort()` before `.offset()`, etc. Putting them out of
|
|
24
|
+
order (e.g. `.sort()` before `.include()`) produces a parse error.
|
|
25
|
+
|
|
26
|
+
**Mandatory include fields:** `items` requires `"repo","path","name"`;
|
|
27
|
+
`builds` requires `"name","number","repo"`. Always include these even when
|
|
28
|
+
you only need a subset — narrow results with `jq` post-query instead:
|
|
29
|
+
|
|
30
|
+
```
|
|
31
|
+
items.find({"name":"commons-lang3-3.12.0.jar"})
|
|
32
|
+
.include("repo","path","name")
|
|
33
|
+
.distinct(true)
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Domains
|
|
37
|
+
|
|
38
|
+
AQL has 13 queryable domains. Each domain represents a different entity type
|
|
39
|
+
and has its own set of fields.
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
| Domain | Query name | Description |
|
|
43
|
+
| -------------------- | ------------------- | ---------------------------------------------- |
|
|
44
|
+
| Items | `items` | Artifacts stored in repositories (most common) |
|
|
45
|
+
| Properties | `properties` | Key-value properties on items |
|
|
46
|
+
| Item infos | `item.infos` | Property modification metadata |
|
|
47
|
+
| Statistics | `stats` | Download statistics (local and remote) |
|
|
48
|
+
| Builds | `builds` | Build info records |
|
|
49
|
+
| Build modules | `modules` | Modules within a build |
|
|
50
|
+
| Build artifacts | `artifacts` | Artifacts produced by a build module |
|
|
51
|
+
| Build dependencies | `dependencies` | Dependencies consumed by a build module |
|
|
52
|
+
| Build properties | `build.properties` | Key-value properties on builds |
|
|
53
|
+
| Build promotions | `build.promotions` | Build promotion records |
|
|
54
|
+
| Module properties | `module.properties` | Key-value properties on build modules |
|
|
55
|
+
| Release bundles | `releases` | Release bundle records |
|
|
56
|
+
| Release bundle files | `release_artifacts` | Files within a release bundle |
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
## Domain relationships
|
|
60
|
+
|
|
61
|
+
Domains connect through the following join paths. Cross-domain queries
|
|
62
|
+
traverse these links — fields from related domains can appear in criteria
|
|
63
|
+
and include clauses by prefixing the domain path.
|
|
64
|
+
|
|
65
|
+
```mermaid
|
|
66
|
+
erDiagram
|
|
67
|
+
items ||--o{ properties : "has"
|
|
68
|
+
items ||--o| item_infos : "has"
|
|
69
|
+
items ||--o{ stats : "has"
|
|
70
|
+
items ||--o{ artifacts : "via checksum"
|
|
71
|
+
items ||--o{ dependencies : "via checksum"
|
|
72
|
+
items ||--o{ release_artifacts : "has"
|
|
73
|
+
artifacts }o--|| modules : "belongs to"
|
|
74
|
+
dependencies }o--|| modules : "belongs to"
|
|
75
|
+
modules }o--|| builds : "belongs to"
|
|
76
|
+
modules ||--o{ module_properties : "has"
|
|
77
|
+
builds ||--o{ build_properties : "has"
|
|
78
|
+
builds ||--o{ build_promotions : "has"
|
|
79
|
+
release_artifacts }o--|| releases : "belongs to"
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
**Key:** Items connect to build artifacts and dependencies through SHA-1
|
|
85
|
+
checksum matching, not a direct key. This means a cross-domain query from
|
|
86
|
+
items to builds traverses: items → artifacts → modules → builds.
|
|
87
|
+
|
|
88
|
+
### Cross-domain field paths
|
|
89
|
+
|
|
90
|
+
To reference a field from a related domain, use dot-separated domain paths:
|
|
91
|
+
|
|
92
|
+
```
|
|
93
|
+
items.find({"artifact.module.build.name":"my-build"})
|
|
94
|
+
.include("name","repo","path","artifact.module.build.number")
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
Common cross-domain paths from items:
|
|
98
|
+
|
|
99
|
+
- `stat.downloads`, `stat.downloaded` — download statistics
|
|
100
|
+
- `property.key`, `property.value` — item properties
|
|
101
|
+
- `artifact.module.build.name` — build that produced the item
|
|
102
|
+
- `artifact.module.build.number` — build number
|
|
103
|
+
|
|
104
|
+
From builds:
|
|
105
|
+
|
|
106
|
+
- `module.artifact.name` — artifacts in build modules
|
|
107
|
+
- `module.dependency.name` — dependencies of build modules
|
|
108
|
+
|
|
109
|
+
## Fields by domain
|
|
110
|
+
|
|
111
|
+
Field types: `string`, `date`, `int`, `long`, `itemType` (`file`, `folder`,
|
|
112
|
+
or `any`). Fields marked "default" are returned without explicit `.include()`.
|
|
113
|
+
|
|
114
|
+
### items
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
| Field | Type | Default |
|
|
118
|
+
| --------------- | -------- | ------- |
|
|
119
|
+
| `repo` | string | yes |
|
|
120
|
+
| `path` | string | yes |
|
|
121
|
+
| `name` | string | yes |
|
|
122
|
+
| `type` | itemType | yes |
|
|
123
|
+
| `size` | long | yes |
|
|
124
|
+
| `depth` | int | yes |
|
|
125
|
+
| `created` | date | yes |
|
|
126
|
+
| `created_by` | string | yes |
|
|
127
|
+
| `modified` | date | yes |
|
|
128
|
+
| `modified_by` | string | yes |
|
|
129
|
+
| `updated` | date | yes |
|
|
130
|
+
| `actual_md5` | string | no |
|
|
131
|
+
| `actual_sha1` | string | no |
|
|
132
|
+
| `sha256` | string | no |
|
|
133
|
+
| `original_md5` | string | no |
|
|
134
|
+
| `original_sha1` | string | no |
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
Computed field: `virtual_repos` — returns virtual repositories that include
|
|
138
|
+
the item's actual repository. Must use `.include("virtual_repos")` explicitly;
|
|
139
|
+
requires `repo`, `path`, `name` in the result set.
|
|
140
|
+
|
|
141
|
+
### properties
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
| Field | Type | Default |
|
|
145
|
+
| ------- | ------ | ------- |
|
|
146
|
+
| `key` | string | yes |
|
|
147
|
+
| `value` | string | yes |
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
### stats
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
| Field | Type | Default |
|
|
154
|
+
| ---------------------- | ------ | ------- |
|
|
155
|
+
| `downloads` | int | yes |
|
|
156
|
+
| `downloaded` | date | yes |
|
|
157
|
+
| `downloaded_by` | string | yes |
|
|
158
|
+
| `remote_downloads` | int | yes |
|
|
159
|
+
| `remote_downloaded` | date | yes |
|
|
160
|
+
| `remote_downloaded_by` | string | yes |
|
|
161
|
+
| `remote_origin` | string | yes |
|
|
162
|
+
| `remote_path` | string | yes |
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
### item.infos
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
| Field | Type | Default |
|
|
169
|
+
| ------------------- | ------ | ------- |
|
|
170
|
+
| `props_modified` | date | yes |
|
|
171
|
+
| `props_modified_by` | string | yes |
|
|
172
|
+
| `props_md5` | string | yes |
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
### builds
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
| Field | Type | Default |
|
|
179
|
+
| ------------- | ------ | ------- |
|
|
180
|
+
| `url` | string | yes |
|
|
181
|
+
| `name` | string | yes |
|
|
182
|
+
| `number` | string | yes |
|
|
183
|
+
| `started` | date | yes |
|
|
184
|
+
| `created` | date | yes |
|
|
185
|
+
| `created_by` | string | yes |
|
|
186
|
+
| `modified` | date | yes |
|
|
187
|
+
| `modified_by` | string | yes |
|
|
188
|
+
| `repo` | string | no |
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
### modules
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
| Field | Type | Default |
|
|
195
|
+
| ------ | ------ | ------- |
|
|
196
|
+
| `name` | string | yes |
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
### artifacts
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
| Field | Type | Default |
|
|
203
|
+
| ------ | ------ | ------- |
|
|
204
|
+
| `name` | string | yes |
|
|
205
|
+
| `type` | string | yes |
|
|
206
|
+
| `sha1` | string | yes |
|
|
207
|
+
| `md5` | string | yes |
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
### dependencies
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
| Field | Type | Default |
|
|
214
|
+
| ------- | ------ | ------- |
|
|
215
|
+
| `name` | string | yes |
|
|
216
|
+
| `scope` | string | yes |
|
|
217
|
+
| `type` | string | yes |
|
|
218
|
+
| `sha1` | string | yes |
|
|
219
|
+
| `md5` | string | yes |
|
|
220
|
+
|
|
221
|
+
|
|
222
|
+
### build.properties
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
| Field | Type | Default |
|
|
226
|
+
| ------- | ------ | ------- |
|
|
227
|
+
| `key` | string | yes |
|
|
228
|
+
| `value` | string | yes |
|
|
229
|
+
|
|
230
|
+
|
|
231
|
+
### build.promotions
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
| Field | Type | Default |
|
|
235
|
+
| ------------ | ------ | ------- |
|
|
236
|
+
| `created` | date | yes |
|
|
237
|
+
| `created_by` | string | yes |
|
|
238
|
+
| `status` | string | yes |
|
|
239
|
+
| `repo` | string | yes |
|
|
240
|
+
| `comment` | string | yes |
|
|
241
|
+
| `user` | string | yes |
|
|
242
|
+
|
|
243
|
+
|
|
244
|
+
### module.properties
|
|
245
|
+
|
|
246
|
+
|
|
247
|
+
| Field | Type | Default |
|
|
248
|
+
| ------- | ------ | ------- |
|
|
249
|
+
| `key` | string | yes |
|
|
250
|
+
| `value` | string | yes |
|
|
251
|
+
|
|
252
|
+
|
|
253
|
+
### releases
|
|
254
|
+
|
|
255
|
+
|
|
256
|
+
| Field | Type | Default |
|
|
257
|
+
| -------------- | --------------------------- | ------- |
|
|
258
|
+
| `name` | string | yes |
|
|
259
|
+
| `version` | string | yes |
|
|
260
|
+
| `status` | string | yes |
|
|
261
|
+
| `created` | date | yes |
|
|
262
|
+
| `signature` | string | yes |
|
|
263
|
+
| `type` | string (`SOURCE`, `TARGET`) | yes |
|
|
264
|
+
| `storing_repo` | string | yes |
|
|
265
|
+
|
|
266
|
+
|
|
267
|
+
### release_artifacts
|
|
268
|
+
|
|
269
|
+
|
|
270
|
+
| Field | Type | Default |
|
|
271
|
+
| ------ | ------ | ------- |
|
|
272
|
+
| `path` | string | yes |
|
|
273
|
+
|
|
274
|
+
|
|
275
|
+
## Comparators
|
|
276
|
+
|
|
277
|
+
|
|
278
|
+
| Operator | Meaning | Example |
|
|
279
|
+
| ---------- | -------------------------------- | ------------------------------------ |
|
|
280
|
+
| `$eq` | Equals (default if omitted) | `{"type":"file"}` |
|
|
281
|
+
| `$ne` | Not equals | `{"type":{"$ne":"folder"}}` |
|
|
282
|
+
| `$eqic` | Equals, case-insensitive | `{"name":{"$eqic":"README.md"}}` |
|
|
283
|
+
| `$match` | Wildcard match (`*`, `?`) | `{"name":{"$match":"*.jar"}}` |
|
|
284
|
+
| `$matchic` | Wildcard match, case-insensitive | `{"name":{"$matchic":"*.JAR"}}` |
|
|
285
|
+
| `$nmatch` | Wildcard not-match | `{"name":{"$nmatch":"*-SNAPSHOT*"}}` |
|
|
286
|
+
| `$gt` | Greater than | `{"size":{"$gt":"1000000"}}` |
|
|
287
|
+
| `$gte` | Greater than or equal | `{"stat.downloads":{"$gte":"10"}}` |
|
|
288
|
+
| `$lt` | Less than | `{"size":{"$lt":"5000"}}` |
|
|
289
|
+
| `$lte` | Less than or equal | `{"modified":{"$lte":"2025-01-01"}}` |
|
|
290
|
+
|
|
291
|
+
|
|
292
|
+
### Boolean operators
|
|
293
|
+
|
|
294
|
+
|
|
295
|
+
| Operator | Description |
|
|
296
|
+
| -------- | ---------------------------------------------------------------------- |
|
|
297
|
+
| `$and` | All conditions must match (implicit when fields are at the same level) |
|
|
298
|
+
| `$or` | Any condition must match |
|
|
299
|
+
|
|
300
|
+
|
|
301
|
+
```
|
|
302
|
+
items.find({"$and":[
|
|
303
|
+
{"repo":"my-repo"},
|
|
304
|
+
{"$or":[
|
|
305
|
+
{"name":{"$match":"*.jar"}},
|
|
306
|
+
{"name":{"$match":"*.war"}}
|
|
307
|
+
]}
|
|
308
|
+
]})
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
### Relative date comparators
|
|
312
|
+
|
|
313
|
+
AQL supports relative date queries with `$last` and `$before`:
|
|
314
|
+
|
|
315
|
+
|
|
316
|
+
| Operator | Meaning | Example |
|
|
317
|
+
| --------- | ------------------------------------------------------- | ------------------------------- |
|
|
318
|
+
| `$last` | Within the last N period (equivalent to `$gt` from now) | `{"modified":{"$last":"7d"}}` |
|
|
319
|
+
| `$before` | Before the last N period (equivalent to `$lt` from now) | `{"created":{"$before":"3mo"}}` |
|
|
320
|
+
|
|
321
|
+
|
|
322
|
+
Supported units: `d` (days), `w` (weeks), `mo` (months), `y` (years),
|
|
323
|
+
`s` (seconds), `mi` (minutes), `ms` (milliseconds).
|
|
324
|
+
|
|
325
|
+
### Multi-property AND
|
|
326
|
+
|
|
327
|
+
To match items that have property A=1 **and** property B=2 (different
|
|
328
|
+
property rows), use `$and` with `@` shorthand:
|
|
329
|
+
|
|
330
|
+
```
|
|
331
|
+
items.find({"$and":[
|
|
332
|
+
{"@build.name":"my-build"},
|
|
333
|
+
{"@build.number":"42"}
|
|
334
|
+
]})
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
AQL also documents a `$msp` (multi-set property) operator for this purpose,
|
|
338
|
+
but `$msp` is **unreliable in practice** — it returns 0 results on many
|
|
339
|
+
server versions even when matching items exist. Prefer `$and` with `@`
|
|
340
|
+
shorthand, which is verified to work correctly.
|
|
341
|
+
|
|
342
|
+
## Date queries
|
|
343
|
+
|
|
344
|
+
Dates use ISO 8601 format for absolute dates:
|
|
345
|
+
|
|
346
|
+
```
|
|
347
|
+
items.find({"modified":{"$gt":"2025-06-01T00:00:00.000Z"}})
|
|
348
|
+
```
|
|
349
|
+
|
|
350
|
+
Or use relative dates (preferred — avoids hardcoding timestamps):
|
|
351
|
+
|
|
352
|
+
```
|
|
353
|
+
items.find({"modified":{"$last":"30d"}})
|
|
354
|
+
items.find({"created":{"$before":"6mo"}})
|
|
355
|
+
```
|
|
356
|
+
|
|
357
|
+
## Property queries
|
|
358
|
+
|
|
359
|
+
Two equivalent syntaxes for property filtering:
|
|
360
|
+
|
|
361
|
+
**`@key` shorthand** — concise, works for single property conditions:
|
|
362
|
+
|
|
363
|
+
```
|
|
364
|
+
items.find({"repo":"my-repo","@build.name":"my-build","type":"file"})
|
|
365
|
+
```
|
|
366
|
+
|
|
367
|
+
**Explicit form** — `property.key`/`property.value` pairs:
|
|
368
|
+
|
|
369
|
+
```
|
|
370
|
+
items.find({
|
|
371
|
+
"repo":"my-repo",
|
|
372
|
+
"property.key":"build.name",
|
|
373
|
+
"property.value":"my-build"
|
|
374
|
+
})
|
|
375
|
+
```
|
|
376
|
+
|
|
377
|
+
**Multi-property AND** — use `$and` with `@` shorthand to match across
|
|
378
|
+
different property rows:
|
|
379
|
+
|
|
380
|
+
```
|
|
381
|
+
items.find({"$and":[
|
|
382
|
+
{"@build.name":"my-build"},
|
|
383
|
+
{"@build.number":"42"}
|
|
384
|
+
]})
|
|
385
|
+
```
|
|
386
|
+
|
|
387
|
+
> **Note:** The `@key` shorthand works inside `$and`. For `$or`, use the
|
|
388
|
+
> explicit `property.key`/`property.value` form if the shorthand does not
|
|
389
|
+
> return expected results.
|
|
390
|
+
|
|
391
|
+
## Include
|
|
392
|
+
|
|
393
|
+
Select which fields to return. Without `.include()`, AQL returns each
|
|
394
|
+
domain's default field set.
|
|
395
|
+
|
|
396
|
+
**When you use `.include()`, you replace the defaults — so you must
|
|
397
|
+
explicitly list any required fields:**
|
|
398
|
+
|
|
399
|
+
- `items` domain: always include `"repo","path","name"` (server rejects
|
|
400
|
+
the query otherwise)
|
|
401
|
+
- `builds` domain: always include `"name","number","repo"`
|
|
402
|
+
|
|
403
|
+
```
|
|
404
|
+
items.find({"repo":"my-repo"})
|
|
405
|
+
.include("name","repo","path","size","sha256","stat.downloads")
|
|
406
|
+
```
|
|
407
|
+
|
|
408
|
+
Cross-domain includes use dot-separated paths:
|
|
409
|
+
|
|
410
|
+
```
|
|
411
|
+
items.find({"repo":"my-repo"})
|
|
412
|
+
.include("name","repo","path","property.key","property.value")
|
|
413
|
+
```
|
|
414
|
+
|
|
415
|
+
## Sort and pagination
|
|
416
|
+
|
|
417
|
+
```
|
|
418
|
+
items.find({"repo":"my-repo"})
|
|
419
|
+
.sort({"$desc":["modified"]})
|
|
420
|
+
.offset(0)
|
|
421
|
+
.limit(50)
|
|
422
|
+
```
|
|
423
|
+
|
|
424
|
+
Sort directions: `$asc`, `$desc`. Sort fields must also appear in the result
|
|
425
|
+
set (explicit `.include()` or default fields). See
|
|
426
|
+
[Before constructing a query](#before-constructing-a-query) for sort
|
|
427
|
+
performance rules.
|
|
428
|
+
|
|
429
|
+
## Distinct
|
|
430
|
+
|
|
431
|
+
Deduplicate result rows:
|
|
432
|
+
|
|
433
|
+
```
|
|
434
|
+
items.find({"repo":"my-repo"}).distinct(true)
|
|
435
|
+
```
|
|
436
|
+
|
|
437
|
+
## Validation rules
|
|
438
|
+
|
|
439
|
+
The server enforces these constraints — violating them produces an error:
|
|
440
|
+
|
|
441
|
+
**Non-admin users:**
|
|
442
|
+
|
|
443
|
+
- `items` domain queries must include `repo`, `path`, `name` in results
|
|
444
|
+
(needed for permission filtering)
|
|
445
|
+
- `builds` domain queries must include `name`, `number`, `repo` in results
|
|
446
|
+
|
|
447
|
+
**Transitive mode** (`.transitive()` for querying through virtual repos):
|
|
448
|
+
|
|
449
|
+
- Only works with `items` domain
|
|
450
|
+
- Include subdomains limited to `items` and `properties`
|
|
451
|
+
- Repo criteria must use `$eq` (exact match) with a single repository
|
|
452
|
+
- No `offset` or `sort` allowed
|
|
453
|
+
|
|
454
|
+
## Before constructing a query
|
|
455
|
+
|
|
456
|
+
Run through these checks before writing any AQL query:
|
|
457
|
+
|
|
458
|
+
1. **Never `.sort()` without a `repo` filter** — forces a full table scan
|
|
459
|
+
across all repositories. Sort client-side with `jq` instead. Also,
|
|
460
|
+
`.sort()` on cross-domain fields (e.g. `stat.downloads` in `items.find()`)
|
|
461
|
+
is silently ignored — fetch all rows and sort client-side.
|
|
462
|
+
2. **Always set `.limit()`** — no built-in default limit; unbounded queries
|
|
463
|
+
can time out or OOM. Broad queries without a `repo` filter are especially
|
|
464
|
+
expensive.
|
|
465
|
+
3. **`range.total` = returned count, not total matching** — AQL has no
|
|
466
|
+
count-only mode. To find the true total, paginate with `.offset()` until
|
|
467
|
+
a page returns fewer results than the limit.
|
|
468
|
+
4. **AQL has no repo-type field** — to restrict to local repos, either
|
|
469
|
+
pre-query `GET /api/repositories?type=local` and add repo names to
|
|
470
|
+
criteria (practical when count is small), or query without a repo filter
|
|
471
|
+
and exclude `-cache` / `-virtual` suffixed repos client-side with `jq`.
|
|
472
|
+
5. **Narrow server-side first** — add every applicable filter (`created_by`,
|
|
473
|
+
`created`, `type`, `name`) before relying on client-side `jq` filtering.
|
|
474
|
+
|
|
475
|
+
## Common query patterns
|
|
476
|
+
|
|
477
|
+
### Find all JARs in a repo
|
|
478
|
+
|
|
479
|
+
```
|
|
480
|
+
items.find({"repo":"libs-release","name":{"$match":"*.jar"}})
|
|
481
|
+
```
|
|
482
|
+
|
|
483
|
+
### Find large files (> 100 MB)
|
|
484
|
+
|
|
485
|
+
```
|
|
486
|
+
items.find({"repo":"my-repo","size":{"$gt":"104857600"},"type":"file"})
|
|
487
|
+
```
|
|
488
|
+
|
|
489
|
+
### Find Maven SNAPSHOT JARs
|
|
490
|
+
|
|
491
|
+
Use `*-SNAPSHOT*.jar` (not `*-SNAPSHOT.jar`) to also match classifier
|
|
492
|
+
artifacts like `-sources.jar` and `-javadoc.jar`:
|
|
493
|
+
|
|
494
|
+
```
|
|
495
|
+
items.find({"repo":"libs-snapshot","name":{"$match":"*-SNAPSHOT*.jar"},"type":"file"})
|
|
496
|
+
```
|
|
497
|
+
|
|
498
|
+
### Find artifacts modified in the last 7 days
|
|
499
|
+
|
|
500
|
+
```
|
|
501
|
+
items.find({"repo":"my-repo","modified":{"$last":"7d"},"type":"file"})
|
|
502
|
+
.sort({"$desc":["modified"]})
|
|
503
|
+
.limit(100)
|
|
504
|
+
```
|
|
505
|
+
|
|
506
|
+
### Docker queries
|
|
507
|
+
|
|
508
|
+
Use `"name":"manifest.json"` to **list tags** (one per tag). Use
|
|
509
|
+
`"name":{"$match":"*manifest.json"}` to **query all manifests** (includes
|
|
510
|
+
`list.manifest.json` for multi-arch tags — see [Gotchas](#gotchas)).
|
|
511
|
+
|
|
512
|
+
```
|
|
513
|
+
items.find({"repo":"docker-local","path":{"$match":"my-image/*"},"name":"manifest.json"})
|
|
514
|
+
```
|
|
515
|
+
|
|
516
|
+
### Docker image size
|
|
517
|
+
|
|
518
|
+
**Do not use AQL** — layer blobs live at `<image>/sha256:<digest>/`, not
|
|
519
|
+
under `<image>/<tag>/`. Use the V2 manifest API (returns `layers[].size`):
|
|
520
|
+
|
|
521
|
+
```bash
|
|
522
|
+
jf api "/artifactory/api/docker/<repo>/v2/<image>/manifests/<tag>" \
|
|
523
|
+
-H "Accept: application/vnd.docker.distribution.manifest.v2+json"
|
|
524
|
+
```
|
|
525
|
+
|
|
526
|
+
For multi-arch images the response is an image index; fetch each platform
|
|
527
|
+
manifest by digest to get its layers.
|
|
528
|
+
|
|
529
|
+
### Find artifacts with a specific property
|
|
530
|
+
|
|
531
|
+
```
|
|
532
|
+
items.find({"repo":"my-repo","@build.name":"my-build","type":"file"})
|
|
533
|
+
```
|
|
534
|
+
|
|
535
|
+
### Find never-downloaded files (zero download count)
|
|
536
|
+
|
|
537
|
+
Zero-download items lack a stats row — filter client-side instead
|
|
538
|
+
(see [Gotchas](#gotchas)):
|
|
539
|
+
|
|
540
|
+
```bash
|
|
541
|
+
jf api /artifactory/api/search/aql \
|
|
542
|
+
-X POST -H "Content-Type: text/plain" -d '
|
|
543
|
+
items.find({"repo":"my-repo","type":"file"})
|
|
544
|
+
.include("repo","path","name","size","stat.downloads")
|
|
545
|
+
' | jq '[.results[] | select((.stats[0].downloads // 0) == 0) | {repo, path, name, size}]'
|
|
546
|
+
```
|
|
547
|
+
|
|
548
|
+
### Find artifacts not downloaded in 90 days
|
|
549
|
+
|
|
550
|
+
Only matches previously-downloaded items (see [Gotchas](#gotchas)).
|
|
551
|
+
Combine with the never-downloaded pattern above for full coverage.
|
|
552
|
+
|
|
553
|
+
```
|
|
554
|
+
items.find({
|
|
555
|
+
"repo":"my-repo",
|
|
556
|
+
"type":"file",
|
|
557
|
+
"stat.downloaded":{"$before":"90d"}
|
|
558
|
+
}).include("name","repo","path","stat.downloaded","size")
|
|
559
|
+
```
|
|
560
|
+
|
|
561
|
+
### Find items by build name (cross-domain)
|
|
562
|
+
|
|
563
|
+
```
|
|
564
|
+
items.find({"artifact.module.build.name":"my-service"})
|
|
565
|
+
.include("name","repo","path","artifact.module.build.number")
|
|
566
|
+
.sort({"$desc":["modified"]})
|
|
567
|
+
.limit(50)
|
|
568
|
+
```
|
|
569
|
+
|
|
570
|
+
### Find builds by name
|
|
571
|
+
|
|
572
|
+
Non-admin users must include `name`, `number`, `repo` — omitting any
|
|
573
|
+
produces an error.
|
|
574
|
+
|
|
575
|
+
```
|
|
576
|
+
builds.find({"name":{"$match":"*my-service*"}})
|
|
577
|
+
.include("name","number","repo","started")
|
|
578
|
+
.sort({"$desc":["started"]})
|
|
579
|
+
.limit(10)
|
|
580
|
+
```
|
|
581
|
+
|
|
582
|
+
### Find build artifacts
|
|
583
|
+
|
|
584
|
+
```
|
|
585
|
+
artifacts.find({"module.build.name":"my-service","module.build.number":"42"})
|
|
586
|
+
.include("name","type","sha1","md5")
|
|
587
|
+
```
|
|
588
|
+
|
|
589
|
+
### Find build dependencies
|
|
590
|
+
|
|
591
|
+
```
|
|
592
|
+
dependencies.find({"module.build.name":"my-service","module.build.number":"42"})
|
|
593
|
+
.include("name","scope","type","sha1")
|
|
594
|
+
```
|
|
595
|
+
|
|
596
|
+
### Remote repository content
|
|
597
|
+
|
|
598
|
+
Remote repo artifacts are stored in a `-cache` suffixed repo. Always query
|
|
599
|
+
the cache repo, not the remote repo itself:
|
|
600
|
+
|
|
601
|
+
```
|
|
602
|
+
items.find({"repo":"npm-remote-cache","name":{"$match":"*.tgz"}})
|
|
603
|
+
```
|
|
604
|
+
|
|
605
|
+
## Gotchas
|
|
606
|
+
|
|
607
|
+
- The request body is **plain text**, not JSON — use
|
|
608
|
+
`Content-Type: text/plain`.
|
|
609
|
+
- String values in criteria must be quoted, including numeric comparisons
|
|
610
|
+
(`"size":{"$gt":"1000"}` not `"size":{"$gt":1000}`).
|
|
611
|
+
- Remote repo content lives in `<repo>-cache`, not `<repo>`.
|
|
612
|
+
- Sort fields must appear in the result set (included explicitly or by
|
|
613
|
+
default).
|
|
614
|
+
- Non-admin `items` queries must return `repo`, `path`, `name`.
|
|
615
|
+
- Non-admin `builds` queries must return `name`, `number`, `repo`.
|
|
616
|
+
- Items connect to builds through checksum matching (SHA-1), so cross-domain
|
|
617
|
+
queries between items and builds are valid but traverse multiple joins.
|
|
618
|
+
- The `path` value for items at the **root** of a repository is `"."`, not
|
|
619
|
+
`""` or `"/"`. Use `"path":"."` to match root-level files.
|
|
620
|
+
- **Docker `list.manifest.json`** — multi-arch images store two manifest files per
|
|
621
|
+
tag: `manifest.json` (platform-specific manifest) and `list.manifest.json` (OCI
|
|
622
|
+
image index). Filtering by `"name":"manifest.json"` is correct for tag listing
|
|
623
|
+
(one result per tag), but silently excludes `list.manifest.json` entries. Use
|
|
624
|
+
`"name":{"$match":"*manifest.json"}` when querying by uploader, date range, or
|
|
625
|
+
any context where all manifest pushes should be counted.
|
|
626
|
+
- **`stat.downloads` filters do not match zero-download items** — never-downloaded
|
|
627
|
+
items lack a stats row so the join finds nothing. Use the client-side `jq`
|
|
628
|
+
approach in "Find never-downloaded files" above.
|
|
629
|
+
- `$match` uses SQL-style wildcards: `*` matches any characters, `?` matches
|
|
630
|
+
exactly one character. It is **not** regex. Literal `_` and `%` in patterns
|
|
631
|
+
are escaped automatically.
|
|
632
|
+
- The `builds.number` field is a **string**, not an integer. Build numbers
|
|
633
|
+
like `"42"`, `"1.0.3"`, and `"SNAPSHOT-1"` are all valid.
|
|
634
|
+
- Release bundle `type` values are uppercase strings: `"SOURCE"` or
|
|
635
|
+
`"TARGET"`.
|
|
636
|
+
- Dates accept both ISO 8601 format (`"2025-06-01T00:00:00.000Z"`) and
|
|
637
|
+
epoch milliseconds as a string (`"1719792000000"`).
|
|
638
|
+
- The server silently excludes trash, support-bundle, and in-transit
|
|
639
|
+
repository content from AQL results. If an item exists but doesn't appear
|
|
640
|
+
in results, it may be in one of these hidden repos.
|
|
641
|
+
- Virtual repo queries are rewritten to search the underlying physical repos.
|
|
642
|
+
The `repo` field in results shows the physical repo name, not the virtual
|
|
643
|
+
repo name you queried.
|
|
644
|
+
|
|
645
|
+
## Official documentation
|
|
646
|
+
|
|
647
|
+
- [Artifactory Query Language](https://docs.jfrog.com/artifactory/docs/artifactory-query-language) — overview and architecture
|
|
648
|
+
- [Query Structure and Syntax](https://docs.jfrog.com/artifactory/docs/aql-syntax) — domain queries, field references, JSON-like syntax rules
|
|
649
|
+
- [Search Criteria and Operators](https://docs.jfrog.com/artifactory/docs/aql-search-criteria) — comparators, wildcards, `$msp`, relative time
|
|
650
|
+
- [AQL Entities and Fields Reference](https://docs.jfrog.com/artifactory/docs/aql-entities-fields-reference) — complete field list for all domains
|
|
651
|
+
- [Query Output and Modifiers](https://docs.jfrog.com/artifactory/docs/aql-query-output) — `.include()`, `.sort()`, `.offset()`, `.limit()`, `.distinct()`
|
|
652
|
+
- [Query Execution and Permissions](https://docs.jfrog.com/artifactory/docs/aql-query-execution) — authentication, scoped tokens, HTTP errors, streaming
|
|
653
|
+
- [AQL Examples and Common Patterns](https://docs.jfrog.com/artifactory/docs/aql-examples) — ready-to-use queries by use case
|
|
654
|
+
- [Repository-Specific Queries](https://docs.jfrog.com/artifactory/docs/aql-repository-queries) — `.transitive()`, virtual repos, remote search
|
|
655
|
+
- [Performance and Operational Controls](https://docs.jfrog.com/artifactory/docs/aql-performance) — result limits, timeouts, rate limiting, optimization
|
|
656
|
+
|