Skip to content

Commit 5134a5a

Browse files
tiffanny29631google-oss-prow[bot]
authored andcommitted
test: skip deleting Bitbucket repo stuck in bad state (#1831)
1 parent 2964012 commit 5134a5a

File tree

1 file changed

+77
-18
lines changed

1 file changed

+77
-18
lines changed

e2e/nomostest/gitproviders/bitbucket.go

Lines changed: 77 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import (
2727
"github.com/google/uuid"
2828
"go.uber.org/multierr"
2929
"kpt.dev/configsync/e2e"
30+
"kpt.dev/configsync/e2e/nomostest/retry"
3031
"kpt.dev/configsync/e2e/nomostest/testlogger"
3132
)
3233

@@ -140,31 +141,69 @@ func (b *BitbucketClient) DeleteRepositories(names ...string) error {
140141
return deleteRepos(accessToken, names...)
141142
}
142143

144+
// TODO: This is a temporary workaround for the known issue
145+
// go/acm-e2e-testing#bitbucket-repository-deletion-failure
146+
// Until this is fixed, we are skipping removal of repos stuck in bad state
143147
func deleteRepos(accessToken string, names ...string) error {
144148
var errs error
145149
for _, name := range names {
146-
out, err := exec.Command("curl", "-sX", "DELETE",
147-
"-H", fmt.Sprintf("Authorization:Bearer %s", accessToken),
148-
fmt.Sprintf("https://api.bitbucket.org/2.0/repositories/%s/%s",
149-
bitbucketWorkspace, name)).CombinedOutput()
150-
150+
_, err := retry.Retry(30*time.Second, func() error {
151+
return deleteSingleRepo(accessToken, name)
152+
})
151153
if err != nil {
152-
errs = multierr.Append(errs, fmt.Errorf("%s: %w", string(out), err))
153-
}
154-
if len(out) != 0 {
155-
errs = multierr.Append(errs, errors.New(string(out)))
154+
// Skip repositories that are currently unavailable
155+
if strings.Contains(err.Error(), "Repository currently not available") {
156+
fmt.Printf("[BITBUCKET] Skipping repository %s: %v\n", name, err)
157+
continue
158+
}
159+
errs = multierr.Append(errs, err)
156160
}
157161
}
158162
return errs
159163
}
160164

165+
// deleteSingleRepo deletes a single repository
166+
func deleteSingleRepo(accessToken, name string) error {
167+
out, err := exec.Command("curl", "-sX", "DELETE",
168+
"-H", fmt.Sprintf("Authorization:Bearer %s", accessToken),
169+
fmt.Sprintf("https://api.bitbucket.org/2.0/repositories/%s/%s",
170+
bitbucketWorkspace, name)).CombinedOutput()
171+
172+
if err != nil {
173+
return fmt.Errorf("%s: %w", string(out), err)
174+
}
175+
if len(out) != 0 {
176+
return errors.New(string(out))
177+
}
178+
return nil
179+
}
180+
161181
// DeleteObsoleteRepos deletes all repos that were created more than 24 hours ago.
162182
func (b *BitbucketClient) DeleteObsoleteRepos() error {
163183
accessToken, err := b.refreshAccessToken()
164184
if err != nil {
165185
return err
166186
}
167187

188+
// Count total obsolete repos first
189+
totalObsoleteRepos, err := b.countObsoleteRepos(accessToken)
190+
if err != nil {
191+
return err
192+
}
193+
194+
// TODO: This is a temporary workaround for the known issue
195+
// go/acm-e2e-testing#bitbucket-repository-deletion-failure
196+
// Until this is fixed, we are skipping removal of repos stuck in bad state.
197+
//
198+
// The 1000 limit is a guestimation that does not exceed the 1GB limit of
199+
// workspace for a free account. If that number is exceeded, engineer
200+
// will need to replace the workspace until the root cause of unresponsive
201+
// repo is known.
202+
if totalObsoleteRepos > 1000 {
203+
return fmt.Errorf("total number of obsolete repositories (%d) exceeds 1000, manual cleanup required", totalObsoleteRepos)
204+
}
205+
206+
// Now delete the obsolete repos
168207
page := 1
169208
for page != -1 {
170209
page, err = b.deleteObsoleteReposByPage(accessToken, page)
@@ -214,21 +253,41 @@ func FetchCloudSecret(name string) (string, error) {
214253
}
215254

216255
func (b *BitbucketClient) deleteObsoleteReposByPage(accessToken string, page int) (int, error) {
217-
out, err := exec.Command("curl", "-sX", "GET",
218-
"-H", fmt.Sprintf("Authorization:Bearer %s", accessToken),
219-
fmt.Sprintf(`https://api.bitbucket.org/2.0/repositories/%s?q=project.key="%s"&page=%d`,
220-
bitbucketWorkspace, bitbucketProject, page)).CombinedOutput()
221-
if err != nil {
222-
return -1, fmt.Errorf("%s: %w", string(out), err)
223-
}
224-
repos, page, err := b.filterObsoleteRepos(out)
256+
repos, nextPage, err := b.getObsoleteReposByPage(accessToken, page)
225257
if err != nil {
226258
return -1, err
227259
}
228260

229261
b.logger.Infof("Deleting the following repos: %s", strings.Join(repos, ", "))
230262
err = deleteRepos(accessToken, repos...)
231-
return page, err
263+
return nextPage, err
264+
}
265+
266+
// countObsoleteRepos counts all obsolete repositories across all pages
267+
func (b *BitbucketClient) countObsoleteRepos(accessToken string) (int, error) {
268+
totalObsoleteRepos := 0
269+
page := 1
270+
for page != -1 {
271+
repos, nextPage, err := b.getObsoleteReposByPage(accessToken, page)
272+
if err != nil {
273+
return 0, err
274+
}
275+
totalObsoleteRepos += len(repos)
276+
page = nextPage
277+
}
278+
return totalObsoleteRepos, nil
279+
}
280+
281+
// getObsoleteReposByPage fetches obsolete repos for a given page
282+
func (b *BitbucketClient) getObsoleteReposByPage(accessToken string, page int) ([]string, int, error) {
283+
out, err := exec.Command("curl", "-sX", "GET",
284+
"-H", fmt.Sprintf("Authorization:Bearer %s", accessToken),
285+
fmt.Sprintf(`https://api.bitbucket.org/2.0/repositories/%s?q=project.key="%s"&page=%d`,
286+
bitbucketWorkspace, bitbucketProject, page)).CombinedOutput()
287+
if err != nil {
288+
return nil, -1, fmt.Errorf("%s: %w", string(out), err)
289+
}
290+
return b.filterObsoleteRepos(out)
232291
}
233292

234293
// filterObsoleteRepos extracts the names of the repos that were created more than 24 hours ago.

0 commit comments

Comments
 (0)