Skip to content

Commit 8fc1874

Browse files
authored
Use the public product versions API for creating the versions list (#4423)
Replacing the artifact API with the more stable source.
1 parent 19d623a commit 8fc1874

20 files changed

+788
-316
lines changed

.agent-versions.json

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
{
22
"testVersions": [
3-
"8.14.0-SNAPSHOT",
43
"8.13.0-SNAPSHOT",
4+
"8.12.3-SNAPSHOT",
55
"8.12.2",
6+
"8.12.1",
7+
"7.17.19-SNAPSHOT",
68
"7.17.18"
79
]
810
}

magefile.go

+27-5
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,9 @@ import (
3636
"github.com/elastic/elastic-agent/pkg/testing/multipass"
3737
"github.com/elastic/elastic-agent/pkg/testing/ogc"
3838
"github.com/elastic/elastic-agent/pkg/testing/runner"
39-
"github.com/elastic/elastic-agent/pkg/testing/tools"
39+
"github.com/elastic/elastic-agent/pkg/testing/tools/git"
40+
pv "github.com/elastic/elastic-agent/pkg/testing/tools/product_versions"
41+
"github.com/elastic/elastic-agent/pkg/testing/tools/snapshots"
4042
"github.com/elastic/elastic-agent/pkg/version"
4143
"github.com/elastic/elastic-agent/testing/upgradetest"
4244
bversion "github.com/elastic/elastic-agent/version"
@@ -1576,17 +1578,37 @@ func (Integration) Single(ctx context.Context, testName string) error {
15761578
// UpdateVersions runs an update on the `.agent-versions.json` fetching
15771579
// the latest version list from the artifact API.
15781580
func (Integration) UpdateVersions(ctx context.Context) error {
1579-
// test 2 current 8.x version, 1 previous 7.x version and 1 recent snapshot
1581+
maxSnapshots := 3
1582+
1583+
branches, err := git.GetReleaseBranches(ctx)
1584+
if err != nil {
1585+
return fmt.Errorf("failed to list release branches: %w", err)
1586+
}
1587+
1588+
// -1 because we manually add 7.17 below
1589+
if len(branches) > maxSnapshots-1 {
1590+
branches = branches[:maxSnapshots-1]
1591+
}
1592+
1593+
// it's not a part of this repository, cannot be retrieved with `GetReleaseBranches`
1594+
branches = append(branches, "7.17")
1595+
1596+
// uncomment if want to have the current version snapshot on the list as well
1597+
// branches = append([]string{"master"}, branches...)
1598+
15801599
reqs := upgradetest.VersionRequirements{
15811600
UpgradeToVersion: bversion.Agent,
15821601
CurrentMajors: 2,
15831602
PreviousMinors: 1,
15841603
PreviousMajors: 1,
1585-
RecentSnapshots: 1,
1604+
SnapshotBranches: branches,
15861605
}
1606+
b, _ := json.MarshalIndent(reqs, "", " ")
1607+
fmt.Printf("Current version requirements: \n%s\n", b)
15871608

1588-
aac := tools.NewArtifactAPIClient(tools.WithLogFunc(log.Default().Printf))
1589-
versions, err := upgradetest.FetchUpgradableVersions(ctx, aac, reqs)
1609+
pvc := pv.NewProductVersionsClient()
1610+
sc := snapshots.NewSnapshotsClient()
1611+
versions, err := upgradetest.FetchUpgradableVersions(ctx, pvc, sc, reqs)
15901612
if err != nil {
15911613
return fmt.Errorf("failed to fetch upgradable versions: %w", err)
15921614
}

pkg/testing/tools/artifacts_api.go

+8-92
Original file line numberDiff line numberDiff line change
@@ -9,34 +9,24 @@ import (
99
"encoding/json"
1010
"errors"
1111
"fmt"
12-
"io"
1312
"net/http"
1413
"net/url"
15-
"sort"
1614
"time"
17-
18-
"github.com/elastic/elastic-agent/pkg/version"
1915
)
2016

2117
const (
2218
defaultArtifactAPIURL = "https://artifacts-api.elastic.co/"
2319

24-
artifactsAPIV1VersionsEndpoint = "v1/versions/"
2520
artifactsAPIV1VersionBuildsEndpoint = "v1/versions/%s/builds/"
2621
artifactAPIV1BuildDetailsEndpoint = "v1/versions/%s/builds/%s"
27-
// artifactAPIV1SearchVersionPackage = "v1/search/%s/%s"
2822

2923
artifactElasticAgentProject = "elastic-agent-package"
3024
maxAttemptsForArtifactsAPICall = 6
3125
retryIntervalForArtifactsAPICall = 5 * time.Second
3226
)
3327

3428
var (
35-
ErrLatestVersionNil = errors.New("latest version is nil")
36-
ErrSnapshotVersionsEmpty = errors.New("snapshot list is nil")
37-
ErrInvalidVersionRetrieved = errors.New("invalid version retrieved from artifact API")
38-
ErrBuildNotFound = errors.New("there are no build that satisfy given conditions")
39-
29+
ErrBuildNotFound = errors.New("there are no builds that satisfy given conditions")
4030
ErrBadHTTPStatusCode = errors.New("bad http status code")
4131
)
4232

@@ -45,12 +35,6 @@ type Manifests struct {
4535
SecondsSinceLastUpdate int `json:"seconds-since-last-update"`
4636
}
4737

48-
type VersionList struct {
49-
Versions []string `json:"versions"`
50-
Aliases []string `json:"aliases"`
51-
Manifests Manifests `json:"manifests"`
52-
}
53-
5438
type VersionBuilds struct {
5539
Builds []string `json:"builds"`
5640
Manifests Manifests `json:"manifests"`
@@ -107,11 +91,6 @@ type BuildDetails struct {
10791
Manifests Manifests `json:"manifests"`
10892
}
10993

110-
type SearchPackageResult struct {
111-
Packages map[string]Package `json:"packages"`
112-
Manifests Manifests `json:"manifests"`
113-
}
114-
11594
type httpDoer interface {
11695
Do(req *http.Request) (*http.Response, error)
11796
}
@@ -156,26 +135,10 @@ func NewArtifactAPIClient(opts ...ArtifactAPIClientOpt) *ArtifactAPIClient {
156135
return c
157136
}
158137

159-
// GetVersions returns a list of versions as server by the Artifact API along with some aliases and manifest information
160-
func (aac ArtifactAPIClient) GetVersions(ctx context.Context) (list *VersionList, err error) {
161-
joinedURL, err := aac.composeURL(artifactsAPIV1VersionsEndpoint)
162-
if err != nil {
163-
return nil, err
164-
}
165-
166-
resp, err := aac.createAndPerformRequest(ctx, joinedURL)
167-
if err != nil {
168-
return nil, fmt.Errorf("getting versions: %w", err)
169-
}
170-
171-
defer resp.Body.Close()
172-
return checkResponseAndUnmarshal[VersionList](resp)
173-
}
174-
175138
// GetBuildsForVersion returns a list of builds for a specific version.
176139
// version should be one of the version strings returned by the GetVersions (expected format is semver
177140
// with optional prerelease but no build metadata, for example 8.9.0-SNAPSHOT)
178-
func (aac ArtifactAPIClient) GetBuildsForVersion(ctx context.Context, version string) (builds *VersionBuilds, err error) {
141+
func (aac ArtifactAPIClient) getBuildsForVersion(ctx context.Context, version string) (builds *VersionBuilds, err error) {
179142
joinedURL, err := aac.composeURL(fmt.Sprintf(artifactsAPIV1VersionBuildsEndpoint, version))
180143
if err != nil {
181144
return nil, err
@@ -196,15 +159,15 @@ func (aac ArtifactAPIClient) GetBuildsForVersion(ctx context.Context, version st
196159
// Setting `offset` to 0 includes all builds, 1 skips the latest, and so forth.
197160
// If there are no builds matching these conditions, returns `ErrBuildNotFound`.
198161
func (aac ArtifactAPIClient) FindBuild(ctx context.Context, version, excludeHash string, offset int) (buildDetails *BuildDetails, err error) {
199-
resp, err := aac.GetBuildsForVersion(ctx, version)
162+
resp, err := aac.getBuildsForVersion(ctx, version)
200163
if err != nil {
201164
return nil, fmt.Errorf("failed to get a list of builds: %w", err)
202165
}
203166
if len(resp.Builds) < offset+1 {
204167
return nil, ErrBuildNotFound
205168
}
206169
for _, buildID := range resp.Builds[offset:] {
207-
details, err := aac.GetBuildDetails(ctx, version, buildID)
170+
details, err := aac.getBuildDetails(ctx, version, buildID)
208171
if err != nil {
209172
return nil, fmt.Errorf("failed to get build information for %q: %w", buildID, err)
210173
}
@@ -219,7 +182,7 @@ func (aac ArtifactAPIClient) FindBuild(ctx context.Context, version, excludeHash
219182
// GetBuildDetails returns the list of project and artifacts related to a specific build.
220183
// Version parameter format follows semver (without build metadata) and buildID format is <major>.<minor>.<patch>-<buildhash> as returned by
221184
// GetBuildsForVersion()
222-
func (aac ArtifactAPIClient) GetBuildDetails(ctx context.Context, version string, buildID string) (buildDetails *BuildDetails, err error) {
185+
func (aac ArtifactAPIClient) getBuildDetails(ctx context.Context, version string, buildID string) (buildDetails *BuildDetails, err error) {
223186
joinedURL, err := aac.composeURL(fmt.Sprintf(artifactAPIV1BuildDetailsEndpoint, version, buildID))
224187
if err != nil {
225188
return nil, err
@@ -291,59 +254,12 @@ func checkResponseAndUnmarshal[T any](resp *http.Response) (*T, error) {
291254
return nil, fmt.Errorf("%d: %w", resp.StatusCode, ErrBadHTTPStatusCode)
292255
}
293256

294-
respBytes, err := io.ReadAll(resp.Body)
295-
if err != nil {
296-
return nil, fmt.Errorf("reading response body: %w", err)
297-
}
257+
d := json.NewDecoder(resp.Body)
298258
result := new(T)
299-
err = json.Unmarshal(respBytes, result)
300-
259+
err := d.Decode(&result)
301260
if err != nil {
302-
return nil, fmt.Errorf("unmarshaling: %w", err)
261+
return nil, fmt.Errorf("failed to parse response: %w", err)
303262
}
304263

305264
return result, nil
306265
}
307-
308-
func (aac ArtifactAPIClient) GetLatestSnapshotVersion(ctx context.Context) (*version.ParsedSemVer, error) {
309-
vList, err := aac.GetVersions(ctx)
310-
if err != nil {
311-
return nil, err
312-
}
313-
314-
if vList == nil {
315-
return nil, ErrSnapshotVersionsEmpty
316-
}
317-
318-
sortedParsedVersions := make(version.SortableParsedVersions, 0, len(vList.Versions))
319-
for _, v := range vList.Versions {
320-
pv, err := version.ParseVersion(v)
321-
if err != nil {
322-
aac.logFunc("invalid version retrieved from artifact API: %q", v)
323-
return nil, ErrInvalidVersionRetrieved
324-
}
325-
sortedParsedVersions = append(sortedParsedVersions, pv)
326-
}
327-
328-
if len(sortedParsedVersions) == 0 {
329-
return nil, ErrSnapshotVersionsEmpty
330-
}
331-
332-
// normally the output of the versions returned by artifact API is already
333-
// sorted in ascending order.If we want to sort in descending order we need
334-
// to pass a sort.Reverse to sort.Sort.
335-
sort.Sort(sort.Reverse(sortedParsedVersions))
336-
337-
var latestSnapshotVersion *version.ParsedSemVer
338-
// fetch the latest SNAPSHOT build
339-
for _, pv := range sortedParsedVersions {
340-
if pv.IsSnapshot() {
341-
latestSnapshotVersion = pv
342-
break
343-
}
344-
}
345-
if latestSnapshotVersion == nil {
346-
return nil, ErrLatestVersionNil
347-
}
348-
return latestSnapshotVersion, nil
349-
}

0 commit comments

Comments
 (0)