Browse code

api/search: Reset `is_automated` field to `false`

The field will still be present in the response, but will always be
`false`.
Searching for `is-automated=true` will yield no results, while
`is-automated=false` will effectively be a no-op.

Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>

Paweł Gronowski authored on 2024/03/01 21:19:51
Showing 6 changed files
... ...
@@ -8774,8 +8774,7 @@ paths:
8774 8774
 
8775 8775
                     <p><br /></p>
8776 8776
 
8777
-                    > **Deprecated**: This field is deprecated and will always
8778
-                    > be "false" in future.
8777
+                    > **Deprecated**: This field is deprecated and will always be "false".
8779 8778
                   type: "boolean"
8780 8779
                   example: false
8781 8780
                 name:
... ...
@@ -8818,13 +8817,8 @@ paths:
8818 8818
           description: |
8819 8819
             A JSON encoded value of the filters (a `map[string][]string`) to process on the images list. Available filters:
8820 8820
 
8821
-            - `is-automated=(true|false)` (deprecated, see below)
8822 8821
             - `is-official=(true|false)`
8823 8822
             - `stars=<number>` Matches images that has at least 'number' stars.
8824
-
8825
-            The `is-automated` filter is deprecated. The `is_automated` field has
8826
-            been deprecated by Docker Hub's search API. Consequently, searching
8827
-            for `is-automated=true` will yield no results.
8828 8823
           type: "string"
8829 8824
       tags: ["Image"]
8830 8825
   /images/prune:
... ...
@@ -94,7 +94,7 @@ type SearchResult struct {
94 94
 	Name string `json:"name"`
95 95
 	// IsAutomated indicates whether the result is automated.
96 96
 	//
97
-	// Deprecated: the "is_automated" field is deprecated and will always be "false" in the future.
97
+	// Deprecated: the "is_automated" field is deprecated and will always be "false".
98 98
 	IsAutomated bool `json:"is_automated"`
99 99
 	// Description is a textual description of the repository
100 100
 	Description string `json:"description"`
... ...
@@ -19,6 +19,9 @@ keywords: "API, Docker, rcli, REST, documentation"
19 19
 
20 20
 * `POST /containers/create` now supports `VolumeOptions.Subpath` which allows a
21 21
   subpath of a named volume to be mounted.
22
+* `POST /images/search` will always assume a `false` value for the `is-automated`
23
+  field. Consequently, searching for `is-automated=true` will yield no results,
24
+  while `is-automated=false` will be a no-op.
22 25
 
23 26
 ## v1.44 API changes
24 27
 
... ...
@@ -8,6 +8,7 @@ import (
8 8
 
9 9
 	"github.com/docker/docker/integration-cli/cli"
10 10
 	"gotest.tools/v3/assert"
11
+	is "gotest.tools/v3/assert/cmp"
11 12
 )
12 13
 
13 14
 type DockerCLISearchSuite struct {
... ...
@@ -52,9 +53,9 @@ func (s *DockerCLISearchSuite) TestSearchCmdOptions(c *testing.T) {
52 52
 
53 53
 	outSearchCmdautomated := cli.DockerCmd(c, "search", "--filter", "is-automated=true", "busybox").Combined() // The busybox is a busybox base image, not an AUTOMATED image.
54 54
 	outSearchCmdautomatedSlice := strings.Split(outSearchCmdautomated, "\n")
55
-	for i := range outSearchCmdautomatedSlice {
56
-		assert.Assert(c, !strings.HasPrefix(outSearchCmdautomatedSlice[i], "busybox "), "The busybox is not an AUTOMATED image: %s", outSearchCmdautomated)
57
-	}
55
+
56
+	// is-automated=true should produce no results (only a header)
57
+	assert.Check(c, is.Len(outSearchCmdautomatedSlice, 2))
58 58
 
59 59
 	outSearchCmdNotOfficial := cli.DockerCmd(c, "search", "--filter", "is-official=false", "busybox").Combined() // The busybox is a busybox base image, official image.
60 60
 	outSearchCmdNotOfficialSlice := strings.Split(outSearchCmdNotOfficial, "\n")
... ...
@@ -27,11 +27,16 @@ func (s *Service) Search(ctx context.Context, searchFilters filters.Args, term s
27 27
 		return nil, err
28 28
 	}
29 29
 
30
-	// TODO(thaJeztah): the "is-automated" field is deprecated; reset the field for the next release (v26.0.0). Return early when using "is-automated=true", and ignore "is-automated=false".
31 30
 	isAutomated, err := searchFilters.GetBoolOrDefault("is-automated", false)
32 31
 	if err != nil {
33 32
 		return nil, err
34 33
 	}
34
+
35
+	// "is-automated" is deprecated and filtering for `true` will yield no results.
36
+	if isAutomated {
37
+		return []registry.SearchResult{}, nil
38
+	}
39
+
35 40
 	isOfficial, err := searchFilters.GetBoolOrDefault("is-official", false)
36 41
 	if err != nil {
37 42
 		return nil, err
... ...
@@ -51,7 +56,6 @@ func (s *Service) Search(ctx context.Context, searchFilters filters.Args, term s
51 51
 		}
52 52
 	}
53 53
 
54
-	// TODO(thaJeztah): the "is-automated" field is deprecated. Reset the field for the next release (v26.0.0) if any "true" values are present.
55 54
 	unfilteredResult, err := s.searchUnfiltered(ctx, term, limit, authConfig, headers)
56 55
 	if err != nil {
57 56
 		return nil, err
... ...
@@ -59,11 +63,6 @@ func (s *Service) Search(ctx context.Context, searchFilters filters.Args, term s
59 59
 
60 60
 	filteredResults := []registry.SearchResult{}
61 61
 	for _, result := range unfilteredResult.Results {
62
-		if searchFilters.Contains("is-automated") {
63
-			if isAutomated != result.IsAutomated { //nolint:staticcheck // ignore SA1019 for old API versions.
64
-				continue
65
-			}
66
-		}
67 62
 		if searchFilters.Contains("is-official") {
68 63
 			if isOfficial != result.IsOfficial {
69 64
 				continue
... ...
@@ -74,6 +73,10 @@ func (s *Service) Search(ctx context.Context, searchFilters filters.Args, term s
74 74
 				continue
75 75
 			}
76 76
 		}
77
+		// "is-automated" is deprecated and the value in Docker Hub search
78
+		// results is untrustworthy. Force it to false so as to not mislead our
79
+		// clients.
80
+		result.IsAutomated = false //nolint:staticcheck  // ignore SA1019 (field is deprecated)
77 81
 		filteredResults = append(filteredResults, result)
78 82
 	}
79 83
 
... ...
@@ -206,25 +206,25 @@ func TestSearch(t *testing.T) {
206 206
 					IsAutomated: true, //nolint:staticcheck // ignore SA1019 (field is deprecated).
207 207
 				},
208 208
 			},
209
-			expectedResults: []registry.SearchResult{
209
+			expectedResults: []registry.SearchResult{},
210
+		},
211
+		{
212
+			name:        "is-automated=false, IsAutomated reset to false",
213
+			filtersArgs: filters.NewArgs(filters.Arg("is-automated", "false")),
214
+			registryResults: []registry.SearchResult{
210 215
 				{
211 216
 					Name:        "name",
212 217
 					Description: "description",
213 218
 					IsAutomated: true, //nolint:staticcheck // ignore SA1019 (field is deprecated).
214 219
 				},
215 220
 			},
216
-		},
217
-		{
218
-			name:        "is-automated=false, no results",
219
-			filtersArgs: filters.NewArgs(filters.Arg("is-automated", "false")),
220
-			registryResults: []registry.SearchResult{
221
+			expectedResults: []registry.SearchResult{
221 222
 				{
222 223
 					Name:        "name",
223 224
 					Description: "description",
224
-					IsAutomated: true, //nolint:staticcheck // ignore SA1019 (field is deprecated).
225
+					IsAutomated: false, //nolint:staticcheck // ignore SA1019 (field is deprecated).
225 226
 				},
226 227
 			},
227
-			expectedResults: []registry.SearchResult{},
228 228
 		},
229 229
 		{
230 230
 			name:        "is-automated=false",
... ...
@@ -390,15 +390,7 @@ func TestSearch(t *testing.T) {
390 390
 					IsAutomated: true, //nolint:staticcheck // ignore SA1019 (field is deprecated).
391 391
 				},
392 392
 			},
393
-			expectedResults: []registry.SearchResult{
394
-				{
395
-					Name:        "name3",
396
-					Description: "description3",
397
-					StarCount:   2,
398
-					IsOfficial:  true,
399
-					IsAutomated: true, //nolint:staticcheck // ignore SA1019 (field is deprecated).
400
-				},
401
-			},
393
+			expectedResults: []registry.SearchResult{},
402 394
 		},
403 395
 	}
404 396
 	for _, tc := range successCases {