github.com/bitrise-io/bitrise-step-update-gitops-repository@v0.0.0-20240426081835-1466be593380/pkg/gitops/update_files.go (about)

     1  package gitops
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"log"
     7  )
     8  
     9  // Integration is a GitOps integration for Bitrise CI.
    10  type Integration struct {
    11  	// Repo is local clone of remote repository.
    12  	Repo localRepository
    13  	// ExportEnv is an environment variable exporter.
    14  	ExportEnv envExporter
    15  	// Renderer renders templates to a given repository.
    16  	Renderer allFilesRenderer
    17  }
    18  
    19  // UpdateFilesParams are parameters for UpdateFiles function.
    20  type UpdateFilesParams struct {
    21  	// PullRequest won't push to the branch. It will open a PR only instead.
    22  	PullRequest bool
    23  	// PullRequestTitle is the title of the opened pull request.
    24  	PullRequestTitle string
    25  	// PullRequestBody is the body of the opened pull request.
    26  	PullRequestBody string
    27  	// CommitMessage is the created commit's message.
    28  	CommitMessage string
    29  }
    30  
    31  // UpdateFiles updates files in a GitOps repository.
    32  // It either pushes changes to the given branch directly
    33  // or opens a pull request for manual approval.
    34  // URL of the pull request is exported to the
    35  // PR_URL environment variable in the latter case.
    36  func (i Integration) UpdateFiles(ctx context.Context, p UpdateFilesParams) error {
    37  	// Render all templates to the local clone of the repository.
    38  	if err := i.Renderer.renderAllFiles(); err != nil {
    39  		return fmt.Errorf("render all files: %w", err)
    40  	}
    41  
    42  	// If rendering the templates didn't cause any changes, we are done here.
    43  	clean, err := i.Repo.workingDirectoryClean()
    44  	if err != nil {
    45  		return fmt.Errorf("checking if working directory is clean: %w", err)
    46  	}
    47  	if clean {
    48  		log.Println("Deployment configuration didn't change, nothing to push.")
    49  		return nil
    50  	}
    51  
    52  	if p.PullRequest {
    53  		// Changes are pushed to a new branch in PR-only mode.
    54  		if err := i.Repo.gitCheckoutNewBranch(); err != nil {
    55  			return fmt.Errorf("git push: %w", err)
    56  		}
    57  	}
    58  	// Commit all local changes to the current branch
    59  	// and push them to the remote repository.
    60  	if err := i.Repo.gitCommitAndPush(p.CommitMessage); err != nil {
    61  		return fmt.Errorf("git push: %w", err)
    62  	}
    63  	// If we aren't running in PR mode, we are done here
    64  	// (changes were pushed directly to the given branch).
    65  	if !p.PullRequest {
    66  		return nil
    67  	}
    68  
    69  	// Open Github pull request.
    70  	prURL, err := i.Repo.openPullRequest(ctx, p.PullRequestTitle, p.PullRequestBody)
    71  	if err != nil {
    72  		return fmt.Errorf("open pull request: %w", err)
    73  	}
    74  	// Export it's URL as an environment variable (following steps can use it).
    75  	if err := i.ExportEnv("PR_URL", prURL); err != nil {
    76  		return fmt.Errorf("export PR_URL env var: %w", err)
    77  	}
    78  	return nil
    79  }