Skip to content
This repository was archived by the owner on Mar 21, 2025. It is now read-only.

Commit ee02438

Browse files
author
Michael Sauter
authored
Merge pull request #715 from opendevstack/fix/artifacts-upload
Consult artifact repository in artifact check
2 parents ecf8e75 + c547e15 commit ee02438

File tree

7 files changed

+152
-48
lines changed

7 files changed

+152
-48
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ listed in the changelog.
1212

1313
### Fixed
1414

15+
- Artifacts may not be uploaded to target repository when the target repository differs from the source repository ([#715](https://github.com/opendevstack/ods-pipeline/pull/715))
1516
- Gradle build script changes twice into working dir ([#705](https://github.com/opendevstack/ods-pipeline/issues/705))
1617

1718
## [0.13.1] - 2023-06-05

cmd/finish/main.go

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -213,19 +213,27 @@ func uploadArtifacts(
213213
if err != nil {
214214
return err
215215
}
216+
if am.Repository != nexusRepository {
217+
logger.Infof("Artifacts were downloaded from %q but should be uploaded to %q. Checking for existing artifacts in %q before proceeding ...", am.Repository, nexusRepository, nexusRepository)
218+
group := pipelinectxt.ArtifactGroupBase(ctxt)
219+
am, err = pipelinectxt.DownloadGroup(nexusClient, nexusRepository, group, "", logger)
220+
if err != nil {
221+
return err
222+
}
223+
}
216224
for artifactsSubDir, files := range artifactsMap {
217225
for _, filename := range files {
218-
if am.Contains(artifactsSubDir, filename) {
219-
logger.Infof("Artifact %s is already present in Nexus repository %s.", filename, nexusRepository)
226+
if am.Contains(nexusRepository, artifactsSubDir, filename) {
227+
logger.Infof("Artifact %q is already present in Nexus repository %q.", filename, nexusRepository)
220228
} else {
221229
nexusGroup := artifactGroup(ctxt, artifactsSubDir, opts)
222230
localFile := filepath.Join(checkoutDir, pipelinectxt.ArtifactsPath, artifactsSubDir, filename)
223-
logger.Infof("Uploading %s to Nexus repository %s, group %s ...", localFile, nexusRepository, nexusGroup)
231+
logger.Infof("Uploading %q to Nexus repository %q, group %q ...", localFile, nexusRepository, nexusGroup)
224232
link, err := nexusClient.Upload(nexusRepository, nexusGroup, localFile)
225233
if err != nil {
226234
return err
227235
}
228-
logger.Infof("Successfully uploaded %s to %s", localFile, link)
236+
logger.Infof("Successfully uploaded %q to %s", localFile, link)
229237
}
230238
}
231239
}

cmd/finish/main_test.go

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -28,33 +28,35 @@ func TestUploadArtifacts(t *testing.T) {
2828
Repository: "my-repo",
2929
GitCommitSHA: "8d351a10fb428c0c1239530256e21cf24f136e73",
3030
}
31-
t.Log("Write dummy artifact")
31+
t.Logf("Write dummy image-digest artifact to %q\n", pipelinectxt.ArtifactsPath)
3232
artifactsDir := filepath.Join(tempWorkingDir, pipelinectxt.ArtifactsPath)
3333
err = writeArtifactFile(artifactsDir, pipelinectxt.ImageDigestsDir, "foo.json")
3434
if err != nil {
3535
t.Fatal(err)
3636
}
3737

38-
err = uploadArtifacts(logger, nexusClient, nexusRepo, tempWorkingDir, ctxt, options{aggregateTasksStatus: "Succeeded"})
39-
if err != nil {
38+
t.Logf("Upload dummy image-digest artifact to %q on PR failure\n", nexusRepo)
39+
opts := options{pipelineRunName: "pipelineRun", aggregateTasksStatus: "Failed"}
40+
if err := uploadArtifacts(logger, nexusClient, nexusRepo, tempWorkingDir, ctxt, opts); err != nil {
4041
t.Fatal(err)
4142
}
4243
if len(nexusClient.Artifacts[nexusRepo]) != 1 {
4344
t.Fatalf("want 1 uploaded file, got: %v", nexusClient.Artifacts[nexusRepo])
4445
}
45-
wantFile := "/my-project/my-repo/8d351a10fb428c0c1239530256e21cf24f136e73/image-digests/foo.json"
46+
wantFile := "/my-project/my-repo/8d351a10fb428c0c1239530256e21cf24f136e73/failed-pipelineRun-artifacts/image-digests/foo.json"
4647
if !nexusRepoContains(nexusClient.Artifacts[nexusRepo], wantFile) {
4748
t.Fatalf("want: %s, got: %s", wantFile, nexusClient.Artifacts[nexusRepo][0])
4849
}
4950

50-
err = uploadArtifacts(logger, nexusClient, nexusRepo, tempWorkingDir, ctxt, options{pipelineRunName: "pipelineRun", aggregateTasksStatus: "Failed"})
51-
if err != nil {
51+
t.Logf("Upload dummy image-digest artifact to %q on PR success\n", nexusRepo)
52+
opts = options{pipelineRunName: "pipelineRun", aggregateTasksStatus: "Succeeded"}
53+
if err := uploadArtifacts(logger, nexusClient, nexusRepo, tempWorkingDir, ctxt, opts); err != nil {
5254
t.Fatal(err)
5355
}
5456
if len(nexusClient.Artifacts[nexusRepo]) != 2 {
55-
t.Fatalf("expected one additional file upload, got: %v", nexusClient.Artifacts[nexusRepo])
57+
t.Fatalf("expected two artifacts in repo, got: %v", nexusClient.Artifacts[nexusRepo])
5658
}
57-
wantFile = "/my-project/my-repo/8d351a10fb428c0c1239530256e21cf24f136e73/failed-pipelineRun-artifacts/image-digests/foo.json"
59+
wantFile = "/my-project/my-repo/8d351a10fb428c0c1239530256e21cf24f136e73/image-digests/foo.json"
5860
if !nexusRepoContains(nexusClient.Artifacts[nexusRepo], wantFile) {
5961
t.Fatalf("want: %s, got: %s", wantFile, nexusClient.Artifacts[nexusRepo][1])
6062
}
@@ -109,7 +111,7 @@ func TestHandleArtifacts(t *testing.T) {
109111
}
110112
t.Log("Write empty artifacts manifest for subrepository")
111113
subrepoArtifactsDir := filepath.Join(subrepoDir, pipelinectxt.ArtifactsPath)
112-
err = writeArtifactsManifest(subrepoArtifactsDir)
114+
err = writeArtifactsManifest("nexus-repo", subrepoArtifactsDir)
113115
if err != nil {
114116
t.Fatal(err)
115117
}
@@ -156,7 +158,7 @@ func prepareTempWorkingDir(nexusRepo string) (string, func(), error) {
156158
}
157159
cleanup = func() { os.RemoveAll(tempWorkingDir) }
158160
artifactsDir := filepath.Join(tempWorkingDir, pipelinectxt.ArtifactsPath)
159-
err = writeArtifactsManifest(artifactsDir)
161+
err = writeArtifactsManifest("nexus-repo", artifactsDir)
160162
if err != nil {
161163
return tempWorkingDir, cleanup, err
162164
}
@@ -190,9 +192,7 @@ func writeArtifactFile(artifactsDir, subdir, filename string) error {
190192
}
191193

192194
// writeArtifactsManifest writes an artigact manifest JSON file into artifactsDir.
193-
func writeArtifactsManifest(artifactsDir string) error {
194-
am := &pipelinectxt.ArtifactsManifest{
195-
Artifacts: []pipelinectxt.ArtifactInfo{},
196-
}
195+
func writeArtifactsManifest(repository, artifactsDir string) error {
196+
am := pipelinectxt.NewArtifactsManifest(repository)
197197
return pipelinectxt.WriteJsonArtifact(am, artifactsDir, pipelinectxt.ArtifactsManifestFilename)
198198
}

cmd/start/main.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -232,7 +232,7 @@ func main() {
232232
}
233233

234234
func writeEmptyArtifactManifests(subrepoContexts []*pipelinectxt.ODSContext) error {
235-
emptyManifest := &pipelinectxt.ArtifactsManifest{Artifacts: []pipelinectxt.ArtifactInfo{}}
235+
emptyManifest := pipelinectxt.NewArtifactsManifest("")
236236
err := pipelinectxt.WriteJsonArtifact(emptyManifest, pipelinectxt.ArtifactsPath, pipelinectxt.ArtifactsManifestFilename)
237237
if err != nil {
238238
return fmt.Errorf("write repo empty manifest: %w", err)

pkg/pipelinectxt/artifacts.go

Lines changed: 39 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,9 @@ const (
4444

4545
// ArtifactsManifest represents all downloaded artifacts.
4646
type ArtifactsManifest struct {
47+
// Repository is the artifact repository from which the manifests were downloaded.
48+
Repository string `json:"repository"`
49+
// Artifacts lists all artifacts downloaded.
4750
Artifacts []ArtifactInfo `json:"artifacts"`
4851
}
4952

@@ -54,6 +57,11 @@ type ArtifactInfo struct {
5457
Name string `json:"name"`
5558
}
5659

60+
// NewArtifactsManifest returns a new ArtifactsManifest instance.
61+
func NewArtifactsManifest(repository string, artifacts ...ArtifactInfo) *ArtifactsManifest {
62+
return &ArtifactsManifest{Repository: repository, Artifacts: artifacts}
63+
}
64+
5765
// ReadArtifactsManifestFromFile reads an artifact manifest from given filename or errors.
5866
func ReadArtifactsManifestFromFile(filename string) (*ArtifactsManifest, error) {
5967
body, err := os.ReadFile(filename)
@@ -72,7 +80,10 @@ func ReadArtifactsManifestFromFile(filename string) (*ArtifactsManifest, error)
7280
}
7381

7482
// Contains checks whether given directory/name is already present in repository.
75-
func (am *ArtifactsManifest) Contains(directory, name string) bool {
83+
func (am *ArtifactsManifest) Contains(repository, directory, name string) bool {
84+
if am.Repository != repository {
85+
return false
86+
}
7687
for _, a := range am.Artifacts {
7788
if a.Directory == directory && a.Name == name {
7889
return true
@@ -203,46 +214,53 @@ func ArtifactGroup(ctxt *ODSContext, subdir string) string {
203214

204215
// DownloadGroup searches given repositories in order for assets in given group.
205216
// As soon as one repository has any asset in the group, the search is stopped
206-
// and all fond artifacts are downloaded into artifactsDir.
217+
// and all found artifacts are downloaded into artifactsDir.
207218
// An artifacts manifest is returned describing the downloaded files.
208219
// When none of the given repositories contains any artifacts under the group,
209220
// no artifacts are downloaded and no error is returned.
210-
func DownloadGroup(nexusClient nexus.ClientInterface, repository string, group, artifactsDir string, logger logging.LeveledLoggerInterface) (*ArtifactsManifest, error) {
221+
// If artifactsDir is an empty string, the searched files are not downloaded but
222+
// the artifacts are still recorded in the returned manifest.
223+
func DownloadGroup(
224+
nexusClient nexus.ClientInterface,
225+
repository, group, artifactsDir string,
226+
logger logging.LeveledLoggerInterface) (*ArtifactsManifest, error) {
211227
// We want to target all artifacts underneath the group, hence the trailing '*'.
212228
nexusSearchGroup := fmt.Sprintf("%s/*", group)
213-
am := &ArtifactsManifest{
214-
Artifacts: []ArtifactInfo{},
215-
}
229+
am := NewArtifactsManifest(repository)
216230
urls, err := searchForAssets(nexusClient, nexusSearchGroup, repository, logger)
217231
if err != nil {
218232
return nil, err
219233
}
220234

235+
if artifactsDir == "" {
236+
logger.Debugf("Artifacts will not be downloaded but only added to the manifest ...")
237+
}
238+
221239
for _, s := range urls {
222240
u, err := url.Parse(s)
223241
if err != nil {
224242
return nil, err
225243
}
226-
urlPathParts := strings.Split(u.Path, fmt.Sprintf("%s/", group))
227-
if len(urlPathParts) != 2 {
228-
return nil, fmt.Errorf("unexpected URL path (must contain two parts after group '%s'): %s", group, u.Path)
244+
_, fileWithSubPath, ok := strings.Cut(u.Path, fmt.Sprintf("%s/", group)) // e.g. "pipeline-runs/foo-zh9gt0.json"
245+
if !ok {
246+
return nil, fmt.Errorf("unexpected URL path (must contain group '%s'): %s", group, u.Path)
229247
}
230-
fileWithSubPath := urlPathParts[1] // e.g. "pipeline-runs/foo-zh9gt0.json"
231248
if !strings.Contains(fileWithSubPath, "/") {
232249
return nil, fmt.Errorf("unexpected URL path (must contain a subfolder after the commit SHA): %s", fileWithSubPath)
233250
}
234251
aritfactName := path.Base(fileWithSubPath) // e.g. "pipeline-runs"
235252
artifactType := path.Dir(fileWithSubPath) // e.g. "foo-zh9gt0.json"
236-
artifactsSubPath := filepath.Join(artifactsDir, artifactType)
237-
if _, err := os.Stat(artifactsSubPath); os.IsNotExist(err) {
238-
if err := os.MkdirAll(artifactsSubPath, 0755); err != nil {
239-
return nil, fmt.Errorf("failed to create directory: %s, error: %w", artifactsSubPath, err)
253+
if artifactsDir != "" {
254+
artifactsSubPath := filepath.Join(artifactsDir, artifactType)
255+
if _, err := os.Stat(artifactsSubPath); os.IsNotExist(err) {
256+
if err := os.MkdirAll(artifactsSubPath, 0755); err != nil {
257+
return nil, fmt.Errorf("failed to create directory: %s, error: %w", artifactsSubPath, err)
258+
}
259+
}
260+
outfile := filepath.Join(artifactsDir, fileWithSubPath)
261+
if _, err := nexusClient.Download(s, outfile); err != nil {
262+
return nil, err
240263
}
241-
}
242-
outfile := filepath.Join(artifactsDir, fileWithSubPath)
243-
_, err = nexusClient.Download(s, outfile)
244-
if err != nil {
245-
return nil, err
246264
}
247265
am.Artifacts = append(am.Artifacts, ArtifactInfo{
248266
URL: s,
@@ -261,9 +279,9 @@ func searchForAssets(nexusClient nexus.ClientInterface, searchGroup string, repo
261279
return nil, err
262280
}
263281
if len(urls) > 0 {
264-
logger.Infof("Found artifacts in repository %s inside group %s ...", repository, searchGroup)
282+
logger.Infof("Found artifacts in repository %q inside group %q ...", repository, searchGroup)
265283
return urls, nil
266284
}
267-
logger.Infof("No artifacts found in repository %s inside group %s.", repository, searchGroup)
285+
logger.Infof("No artifacts found in repository %q inside group %q.", repository, searchGroup)
268286
return []string{}, nil
269287
}

pkg/pipelinectxt/artifacts_test.go

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,84 @@ func TestDownloadGroup(t *testing.T) {
118118
}
119119
}
120120

121+
func TestContains(t *testing.T) {
122+
tests := map[string]struct {
123+
manifest *ArtifactsManifest
124+
repo string
125+
dir string
126+
name string
127+
want bool
128+
}{
129+
"different repo": {
130+
manifest: &ArtifactsManifest{
131+
Repository: "a",
132+
Artifacts: []ArtifactInfo{
133+
{
134+
Directory: "b",
135+
Name: "c",
136+
},
137+
},
138+
},
139+
repo: "x",
140+
dir: "b",
141+
name: "c",
142+
want: false,
143+
},
144+
"same repo, different dir": {
145+
manifest: &ArtifactsManifest{
146+
Repository: "a",
147+
Artifacts: []ArtifactInfo{
148+
{
149+
Directory: "b",
150+
Name: "c",
151+
},
152+
},
153+
},
154+
repo: "a",
155+
dir: "x",
156+
name: "c",
157+
want: false,
158+
},
159+
"same repo, same dir, different name": {
160+
manifest: &ArtifactsManifest{
161+
Repository: "a",
162+
Artifacts: []ArtifactInfo{
163+
{
164+
Directory: "b",
165+
Name: "c",
166+
},
167+
},
168+
},
169+
repo: "a",
170+
dir: "b",
171+
name: "x",
172+
want: false,
173+
},
174+
"match": {
175+
manifest: &ArtifactsManifest{
176+
Repository: "a",
177+
Artifacts: []ArtifactInfo{
178+
{
179+
Directory: "b",
180+
Name: "c",
181+
},
182+
},
183+
},
184+
repo: "a",
185+
dir: "b",
186+
name: "c",
187+
want: true,
188+
},
189+
}
190+
for name, tc := range tests {
191+
t.Run(name, func(t *testing.T) {
192+
if tc.manifest.Contains(tc.repo, tc.dir, tc.name) != tc.want {
193+
t.Errorf("Want %q to contain=%v, but did not", name, tc.want)
194+
}
195+
})
196+
}
197+
}
198+
121199
func findArtifact(url string, artifacts []ArtifactInfo) *ArtifactInfo {
122200
for _, a := range artifacts {
123201
if a.URL == url {

test/tasks/ods-finish_test.go

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -59,14 +59,13 @@ func TestTaskODSFinish(t *testing.T) {
5959
); err != nil {
6060
t.Fatal(err)
6161
}
62-
am := pipelinectxt.ArtifactsManifest{
63-
Artifacts: []pipelinectxt.ArtifactInfo{
64-
{
65-
Directory: pipelinectxt.CodeCoveragesDir,
66-
Name: "coverage.out",
67-
},
62+
am := pipelinectxt.NewArtifactsManifest(
63+
nexus.TestTemporaryRepository,
64+
pipelinectxt.ArtifactInfo{
65+
Directory: pipelinectxt.CodeCoveragesDir,
66+
Name: "coverage.out",
6867
},
69-
}
68+
)
7069
if err := pipelinectxt.WriteJsonArtifact(
7170
am,
7271
filepath.Join(wsDir, pipelinectxt.ArtifactsPath),
@@ -87,7 +86,7 @@ func TestTaskODSFinish(t *testing.T) {
8786
checkBuildStatus(t, bitbucketClient, ctxt.ODS.GitCommitSHA, bitbucket.BuildStatusSuccessful)
8887
checkArtifactsAreInNexus(t, ctxt, nexus.TestTemporaryRepository)
8988

90-
wantLogMsg := "Artifact coverage.out is already present in Nexus repository"
89+
wantLogMsg := "Artifact \"coverage.out\" is already present in Nexus repository"
9190
if !strings.Contains(string(ctxt.CollectedLogs), wantLogMsg) {
9291
t.Fatalf("Want:\n%s\n\nGot:\n%s", wantLogMsg, string(ctxt.CollectedLogs))
9392
}

0 commit comments

Comments
 (0)