-
Notifications
You must be signed in to change notification settings - Fork 71
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix: Function "runPromote" is overly complex #1343
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -189,40 +189,75 @@ func runPromote(opts *promoteOptions) error { | |
branchname := opts.project + "-" + opts.tags[0] + promotionBranchSuffix | ||
|
||
// Get the github org and repo from the fork slug | ||
repo, err := prepareRepository(branchname, opts) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
defer func() { | ||
if mustRun(opts, "Clean fork directory?") { | ||
err = repo.Cleanup() | ||
} else { | ||
logrus.Infof("All modified files will be left untouched in %s", repo.Dir()) | ||
} | ||
}() | ||
|
||
// Handle manifests | ||
modified, err := handleManifests(ctx, repo, opts) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
if !modified { | ||
logrus.Info("No changes detected in the promoter images list, exiting without changes") | ||
return nil | ||
} | ||
|
||
// Commit and push changes | ||
err = commitAndPushChanges(repo, branchname, opts) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
// Create the pull request | ||
if mustRun(opts, "Create pull request?") { | ||
err = createPullRequest(opts, branchname) | ||
if err != nil { | ||
return err | ||
} | ||
} | ||
|
||
return nil | ||
} | ||
|
||
func prepareRepository(branchname string, opts *promoteOptions) (*git.Repo, error) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Two nits:
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Additionally, I'd make all these functions that take |
||
userForkOrg, userForkRepo, err := git.ParseRepoSlug(opts.userFork) | ||
if err != nil { | ||
return fmt.Errorf("parsing user's fork: %w", err) | ||
return nil, fmt.Errorf("parsing user's fork: %w", err) | ||
} | ||
if userForkRepo == "" { | ||
userForkRepo = k8sioRepo | ||
} | ||
|
||
// Check Environment | ||
gh := github.New() | ||
|
||
// Verify the repository is a fork of k8s.io | ||
if err = github.VerifyFork( | ||
branchname, userForkOrg, userForkRepo, git.DefaultGithubOrg, k8sioRepo, | ||
); err != nil { | ||
return fmt.Errorf("while checking fork of %s/%s: %w ", git.DefaultGithubOrg, k8sioRepo, err) | ||
return nil, fmt.Errorf("while checking fork of %s/%s: %w ", git.DefaultGithubOrg, k8sioRepo, err) | ||
} | ||
|
||
// Clone k8s.io | ||
// We might want to set options to pass for the clone, nothing for now | ||
gitCloneOpts := &gogit.CloneOptions{} | ||
repo, err := github.PrepareFork(branchname, git.DefaultGithubOrg, k8sioRepo, userForkOrg, userForkRepo, opts.useSSH, opts.updateRepo, gitCloneOpts) | ||
if err != nil { | ||
return fmt.Errorf("while preparing k/k8s.io fork: %w", err) | ||
return nil, fmt.Errorf("while preparing k/k8s.io fork: %w", err) | ||
} | ||
|
||
defer func() { | ||
if mustRun(opts, "Clean fork directory?") { | ||
err = repo.Cleanup() | ||
} else { | ||
logrus.Infof("All modified files will be left untouched in %s", repo.Dir()) | ||
} | ||
}() | ||
return repo, nil | ||
} | ||
|
||
func handleManifests(ctx context.Context, repo *git.Repo, opts *promoteOptions) (bool, error) { | ||
// Path to the promoter image list | ||
imagesListPath := filepath.Join( | ||
consts.ProdRegistry, | ||
|
@@ -232,78 +267,82 @@ func runPromote(opts *promoteOptions) error { | |
) | ||
|
||
// Read the current manifest to check later if new images come up | ||
oldlist := make([]byte, 0) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why did you change this? |
||
var oldlist []byte | ||
var err error | ||
|
||
// Run the promoter manifest grower | ||
if mustRun(opts, "Grow the manifests to add the new tags?") { | ||
if util.Exists(filepath.Join(repo.Dir(), imagesListPath)) { | ||
logrus.Debug("Reading the current image promoter manifest (image list)") | ||
oldlist, err = os.ReadFile(filepath.Join(repo.Dir(), imagesListPath)) | ||
if err != nil { | ||
return fmt.Errorf("while reading the current promoter image list: %w", err) | ||
return false, fmt.Errorf("while reading the current promoter image list: %w", err) | ||
} | ||
} | ||
|
||
opt := manifest.GrowOptions{} | ||
if err := opt.Populate( | ||
filepath.Join(repo.Dir(), consts.ProdRegistry), | ||
consts.StagingRepoPrefix+opts.project, opts.images, opts.digests, opts.tags); err != nil { | ||
return fmt.Errorf("populating image promoter options for tag %s with image filter %s: %w", opts.tags, opts.images, err) | ||
return false, fmt.Errorf("populating image promoter options for tag %s with image filter %s: %w", opts.tags, opts.images, err) | ||
} | ||
|
||
if err := opt.Validate(); err != nil { | ||
return fmt.Errorf("validate promoter options tag %s with image filter %s: %w", opts.tags, opts.images, err) | ||
return false, fmt.Errorf("validate promoter options tag %s with image filter %s: %w", opts.tags, opts.images, err) | ||
} | ||
|
||
logrus.Infof("Growing manifests for images matching filter %s and matching tag %s", opts.images, opts.tags) | ||
if err := manifest.Grow(ctx, &opt); err != nil { | ||
return fmt.Errorf("growing manifest with image filter %s and tag %s: %w", opts.images, opts.tags, err) | ||
return false, fmt.Errorf("growing manifest with image filter %s and tag %s: %w", opts.images, opts.tags, err) | ||
} | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The original code is in the |
||
|
||
// Re-write the image list without the mock images | ||
rawImageList, err := image.NewManifestListFromFile(filepath.Join(repo.Dir(), imagesListPath)) | ||
if err != nil { | ||
return fmt.Errorf("parsing the current manifest: %w", err) | ||
} | ||
// Re-write the image list without the mock images | ||
rawImageList, err := image.NewManifestListFromFile(filepath.Join(repo.Dir(), imagesListPath)) | ||
if err != nil { | ||
return false, fmt.Errorf("parsing the current manifest: %w", err) | ||
} | ||
|
||
// Create a new imagelist to copy the non-mock images | ||
newImageList := &image.ManifestList{} | ||
// Create a new imagelist to copy the non-mock images | ||
newImageList := &image.ManifestList{} | ||
|
||
// Copy all non mock-images: | ||
for _, imageData := range *rawImageList { | ||
if !strings.Contains(imageData.Name, "mock/") { | ||
*newImageList = append(*newImageList, imageData) | ||
// Copy all non mock-images: | ||
for _, imageData := range *rawImageList { | ||
if !strings.Contains(imageData.Name, "mock/") { | ||
*newImageList = append(*newImageList, imageData) | ||
} | ||
} | ||
} | ||
|
||
// Write the modified manifest | ||
if err := newImageList.Write(filepath.Join(repo.Dir(), imagesListPath)); err != nil { | ||
return fmt.Errorf("while writing the promoter image list: %w", err) | ||
} | ||
// Write the modified manifest | ||
if err := newImageList.Write(filepath.Join(repo.Dir(), imagesListPath)); err != nil { | ||
return false, fmt.Errorf("while writing the promoter image list: %w", err) | ||
} | ||
|
||
// Check if the image list was modified | ||
if len(oldlist) > 0 { | ||
logrus.Debug("Checking if the image list was modified") | ||
// read the newly modified manifest | ||
newlist, err := os.ReadFile(filepath.Join(repo.Dir(), imagesListPath)) | ||
if err != nil { | ||
return fmt.Errorf("while reading the modified manifest images list: %w", err) | ||
// Check if the image list was modified | ||
if len(oldlist) > 0 { | ||
logrus.Debug("Checking if the image list was modified") | ||
// read the newly modified manifest | ||
newlist, err := os.ReadFile(filepath.Join(repo.Dir(), imagesListPath)) | ||
if err != nil { | ||
return false, fmt.Errorf("while reading the modified manifest images list: %w", err) | ||
} | ||
|
||
// If the manifest was not modified, exit now | ||
if bytes.Equal(newlist, oldlist) { | ||
return false, nil | ||
} | ||
} | ||
|
||
// If the manifest was not modified, exit now | ||
if bytes.Equal(newlist, oldlist) { | ||
logrus.Info("No changes detected in the promoter images list, exiting without changes") | ||
return nil | ||
// add the modified manifest to staging | ||
logrus.Debugf("Adding %s to staging area", imagesListPath) | ||
if err := repo.Add(imagesListPath); err != nil { | ||
return false, fmt.Errorf("adding image manifest to staging area: %w", err) | ||
} | ||
Comment on lines
+335
to
339
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For some reason, this doesn't really feel like part of this function to me. Additionally, if you would put it in the |
||
} | ||
|
||
// add the modified manifest to staging | ||
logrus.Debugf("Adding %s to staging area", imagesListPath) | ||
if err := repo.Add(imagesListPath); err != nil { | ||
return fmt.Errorf("adding image manifest to staging area: %w", err) | ||
} | ||
return true, nil | ||
} | ||
|
||
func commitAndPushChanges(repo *git.Repo, branchname string, opts *promoteOptions) error { | ||
commitMessage := "Image promotion for " + opts.project + " " + strings.Join(opts.tags, " / ") | ||
if opts.project == consts.StagingRepoSuffix { | ||
commitMessage = "releng: " + commitMessage | ||
|
@@ -316,33 +355,35 @@ func runPromote(opts *promoteOptions) error { | |
} | ||
|
||
// Push to fork | ||
if mustRun(opts, fmt.Sprintf("Push changes to user's fork at %s/%s?", userForkOrg, userForkRepo)) { | ||
logrus.Infof("Pushing manifest changes to %s/%s", userForkOrg, userForkRepo) | ||
if mustRun(opts, fmt.Sprintf("Push changes to user's fork at %s/%s?", opts.userFork, k8sioRepo)) { | ||
logrus.Infof("Pushing manifest changes to %s/%s", opts.userFork, k8sioRepo) | ||
if err := repo.PushToRemote(github.UserForkName, branchname); err != nil { | ||
return fmt.Errorf("pushing %s to %s/%s: %w", github.UserForkName, userForkOrg, userForkRepo, err) | ||
return fmt.Errorf("pushing %s to %s/%s: %w", github.UserForkName, opts.userFork, k8sioRepo, err) | ||
Comment on lines
+358
to
+361
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This looks wrong to me, why did you replace |
||
} | ||
} else { | ||
// Exit if no push was made | ||
|
||
logrus.Infof("Exiting without creating a PR since changes were not pushed to %s/%s", userForkOrg, userForkRepo) | ||
logrus.Infof("Exiting without creating a PR since changes were not pushed to %s/%s", opts.userFork, k8sioRepo) | ||
return nil | ||
Comment on lines
+365
to
366
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The tool is supposed to exit here, however, it would continue running after this function. You should do something similar as in |
||
} | ||
|
||
// Create the Pull Request | ||
if mustRun(opts, "Create pull request?") { | ||
pr, err := gh.CreatePullRequest( | ||
git.DefaultGithubOrg, k8sioRepo, k8sioDefaultBranch, | ||
fmt.Sprintf("%s:%s", userForkOrg, branchname), | ||
commitMessage, generatePRBody(opts), | ||
) | ||
if err != nil { | ||
return fmt.Errorf("creating the pull request in k/k8s.io: %w", err) | ||
} | ||
logrus.Infof( | ||
"Successfully created PR: %s%s/%s/pull/%d", | ||
github.GitHubURL, git.DefaultGithubOrg, k8sioRepo, pr.GetNumber(), | ||
) | ||
return nil | ||
} | ||
|
||
func createPullRequest(opts *promoteOptions, branchname string) error { | ||
gh := github.New() | ||
pr, err := gh.CreatePullRequest( | ||
git.DefaultGithubOrg, k8sioRepo, k8sioDefaultBranch, | ||
fmt.Sprintf("%s:%s", opts.userFork, branchname), | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why did you replace |
||
"Image promotion for "+opts.project+" "+strings.Join(opts.tags, " / "), | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This doesn't match the original behavior, the commit message can be extended in some case, e.g. with the |
||
generatePRBody(opts), | ||
) | ||
if err != nil { | ||
return fmt.Errorf("creating the pull request in k/k8s.io: %w", err) | ||
} | ||
logrus.Infof( | ||
"Successfully created PR: %s%s/%s/pull/%d", | ||
github.GitHubURL, git.DefaultGithubOrg, k8sioRepo, pr.GetNumber(), | ||
) | ||
|
||
// Success! | ||
return nil | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
handleManifests
is a bit broad name, what do you think about calling itgrowManifest
instead?