workflow-direct: no panic if no changes

This commit is contained in:
2025-04-17 15:12:51 +02:00
parent bfeac63c57
commit f0de3ad54a
4 changed files with 55 additions and 39 deletions

View File

@@ -46,13 +46,14 @@ type GitStatusLister interface {
type Git interface { type Git interface {
// error if git, but wrong remote // error if git, but wrong remote
GitClone(repo, branch, remoteUrl string) error // clone, or check if path is already checked out remote and force pulls, error otherwise. GitClone(repo, branch, remoteUrl string) (string, error) // clone, or check if path is already checked out remote and force pulls, error otherwise. Return remotename, errror
GitParseCommits(cwd string, commitIDs []string) (parsedCommits []GitCommit, err error) GitParseCommits(cwd string, commitIDs []string) (parsedCommits []GitCommit, err error)
GitCatFile(cwd, commitId, filename string) (data []byte, err error) GitCatFile(cwd, commitId, filename string) (data []byte, err error)
GetPath() string GetPath() string
GitBranchHead(gitDir, branchName string) (string, error) GitBranchHead(gitDir, branchName string) (string, error)
GitRemoteHead(gitDir, remoteName, branchName string) (string, error)
io.Closer io.Closer
GitSubmoduleLister GitSubmoduleLister
@@ -125,12 +126,9 @@ func (s *gitHandlerGeneratorImpl) CreateGitHandler(org string) (Git, error) {
if fs, err := os.Stat(path); (err != nil && !os.IsNotExist(err)) || (err == nil && !fs.IsDir()) { if fs, err := os.Stat(path); (err != nil && !os.IsNotExist(err)) || (err == nil && !fs.IsDir()) {
return nil, err return nil, err
} else if err != nil && os.IsNotExist(err) { } else if err != nil && os.IsNotExist(err) {
log.Println("creating dirs")
if err := os.MkdirAll(path, 0o777); err != nil && !os.IsExist(err) { if err := os.MkdirAll(path, 0o777); err != nil && !os.IsExist(err) {
return nil, err return nil, err
} }
} else {
log.Println(fs, err)
} }
return s.ReadExistingPath(org) return s.ReadExistingPath(org)
@@ -200,10 +198,10 @@ func (refs *GitReferences) addReference(id, branch string) {
refs.refs = append(refs.refs, GitReference{Branch: branch, Id: id}) refs.refs = append(refs.refs, GitReference{Branch: branch, Id: id})
} }
func (e *GitHandlerImpl) GitClone(repo, branch, remoteUrl string) error { func (e *GitHandlerImpl) GitClone(repo, branch, remoteUrl string) (string, error) {
remoteUrlComp, err := ParseGitRemoteUrl(remoteUrl) remoteUrlComp, err := ParseGitRemoteUrl(remoteUrl)
if err != nil { if err != nil {
return fmt.Errorf("Cannot parse remote URL: %w", err) return "", fmt.Errorf("Cannot parse remote URL: %w", err)
} }
if len(branch) == 0 { if len(branch) == 0 {
branch = remoteUrlComp.Commit branch = remoteUrlComp.Commit
@@ -217,10 +215,10 @@ func (e *GitHandlerImpl) GitClone(repo, branch, remoteUrl string) error {
if fi, err := os.Stat(path.Join(e.GitPath, repo)); os.IsNotExist(err) { if fi, err := os.Stat(path.Join(e.GitPath, repo)); os.IsNotExist(err) {
if err = e.GitExec("", "clone", "--origin", remoteName, remoteUrl, repo); err != nil { if err = e.GitExec("", "clone", "--origin", remoteName, remoteUrl, repo); err != nil {
return err return remoteName, err
} }
} else if err != nil || !fi.IsDir() { } else if err != nil || !fi.IsDir() {
return fmt.Errorf("Clone location not a directory or Stat error: %w", err) return remoteName, fmt.Errorf("Clone location not a directory or Stat error: %w", err)
} else { } else {
clonedRemote := strings.TrimSpace(e.GitExecWithOutputOrPanic(repo, "remote", "get-url", remoteName)) clonedRemote := strings.TrimSpace(e.GitExecWithOutputOrPanic(repo, "remote", "get-url", remoteName))
if clonedRemote != remoteUrl { if clonedRemote != remoteUrl {
@@ -229,7 +227,7 @@ func (e *GitHandlerImpl) GitClone(repo, branch, remoteUrl string) error {
e.GitExecOrPanic(repo, "fetch", remoteName, branch) e.GitExecOrPanic(repo, "fetch", remoteName, branch)
} }
return e.GitExec(repo, "checkout", "-B", branch, "refs/remotes/"+remoteName+"/"+branch) return remoteName, e.GitExec(repo, "checkout", "-B", branch, "refs/remotes/"+remoteName+"/"+branch)
} }
func (e *GitHandlerImpl) GitBranchHead(gitDir, branchName string) (string, error) { func (e *GitHandlerImpl) GitBranchHead(gitDir, branchName string) (string, error) {
@@ -241,6 +239,15 @@ func (e *GitHandlerImpl) GitBranchHead(gitDir, branchName string) (string, error
return strings.TrimSpace(id), nil return strings.TrimSpace(id), nil
} }
func (e *GitHandlerImpl) GitRemoteHead(gitDir, remote, branchName string) (string, error) {
id, err := e.GitExecWithOutput(gitDir, "show-ref", "--hash", "--verify", "refs/remotes/"+remote+"/"+branchName)
if err != nil {
return "", fmt.Errorf("Can't find default branch: %s", branchName)
}
return strings.TrimSpace(id), nil
}
func (e *GitHandlerImpl) Close() error { func (e *GitHandlerImpl) Close() error {
e.lock.Unlock() e.lock.Unlock()
return nil return nil

View File

@@ -77,7 +77,7 @@ func TestGitClone(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
if err := g.GitClone(test.repo, test.branch, "file://"+d+test.remoteUrl); err != nil { if _, err := g.GitClone(test.repo, test.branch, "file://"+d+test.remoteUrl); err != nil {
t.Fatal(err) t.Fatal(err)
} }

View File

@@ -201,6 +201,10 @@ func (gitea *GiteaTransport) GetPullRequest(org, project string, num int64) (*mo
func (gitea *GiteaTransport) GetRepository(org, pkg string) (*models.Repository, error) { func (gitea *GiteaTransport) GetRepository(org, pkg string) (*models.Repository, error) {
repo, err := gitea.client.Repository.RepoGet(repository.NewRepoGetParams().WithDefaults().WithOwner(org).WithRepo(pkg), gitea.transport.DefaultAuthentication) repo, err := gitea.client.Repository.RepoGet(repository.NewRepoGetParams().WithDefaults().WithOwner(org).WithRepo(pkg), gitea.transport.DefaultAuthentication)
if err != nil { if err != nil {
switch err.(type) {
case *repository.RepoGetNotFound:
return nil, nil
}
return nil, err return nil, err
} }
@@ -627,6 +631,10 @@ func (gitea *GiteaTransport) GetRecentCommits(org, repo, branch string, commitNo
) )
if err != nil { if err != nil {
switch err.(type) {
case *repository.RepoGetAllCommitsNotFound:
return nil, nil
}
return nil, err return nil, err
} }

View File

@@ -19,7 +19,6 @@ package main
*/ */
import ( import (
"errors"
"flag" "flag"
"fmt" "fmt"
"io/fs" "io/fs"
@@ -107,9 +106,8 @@ func processConfiguredRepositoryAction(action *common.RepositoryWebhookEvent, co
return fmt.Errorf("Error accessing/creating prjgit: %s/%s#%d err: %w", gitOrg, gitPrj, gitBranch, err) return fmt.Errorf("Error accessing/creating prjgit: %s/%s#%d err: %w", gitOrg, gitPrj, gitBranch, err)
} }
if _, err := fs.Stat(os.DirFS(git.GetPath()), config.GitProjectName); errors.Is(err, os.ErrNotExist) { _, err = git.GitClone(gitPrj, gitBranch, prjGitRepo.SSHURL)
common.PanicOnError(git.GitClone(gitPrj, gitBranch, prjGitRepo.SSHURL)) common.PanicOnError(err)
}
switch action.Action { switch action.Action {
case "created": case "created":
@@ -194,9 +192,16 @@ func processConfiguredPushAction(action *common.PushWebhookEvent, config *common
return fmt.Errorf("Error accessing/creating prjgit: %s/%s err: %w", gitOrg, gitPrj, err) return fmt.Errorf("Error accessing/creating prjgit: %s/%s err: %w", gitOrg, gitPrj, err)
} }
if _, err := fs.Stat(os.DirFS(git.GetPath()), gitPrj); errors.Is(err, os.ErrNotExist) { remoteName, err := git.GitClone(gitPrj, gitBranch, prjGitRepo.SSHURL)
common.PanicOnError(git.GitClone(gitPrj, gitBranch, prjGitRepo.SSHURL)) common.PanicOnError(err)
headCommitId, err := git.GitRemoteHead(gitPrj, remoteName, gitBranch)
common.PanicOnError(err)
commit, ok := git.GitSubmoduleCommitId(gitPrj, action.Repository.Name, headCommitId)
for ok && action.Head_Commit.Id == commit {
log.Println(" -- nothing to do, commit already in ProjectGit")
return nil
} }
if stat, err := os.Stat(filepath.Join(git.GetPath(), gitPrj, action.Repository.Name)); err != nil || !stat.IsDir() { if stat, err := os.Stat(filepath.Join(git.GetPath(), gitPrj, action.Repository.Name)); err != nil || !stat.IsDir() {
if DebugMode { if DebugMode {
log.Println("Pushed to package that is not part of the project. Ignoring:", err) log.Println("Pushed to package that is not part of the project. Ignoring:", err)
@@ -209,17 +214,15 @@ func processConfiguredPushAction(action *common.PushWebhookEvent, config *common
if err := git.GitExec(filepath.Join(gitPrj, action.Repository.Name), "fetch", "--depth", "1", "--force", "origin", config.Branch+":"+config.Branch); err != nil { if err := git.GitExec(filepath.Join(gitPrj, action.Repository.Name), "fetch", "--depth", "1", "--force", "origin", config.Branch+":"+config.Branch); err != nil {
return fmt.Errorf("error fetching branch %s. ignoring as non-existent. err: %w", config.Branch, err) // no branch? so ignore repo here return fmt.Errorf("error fetching branch %s. ignoring as non-existent. err: %w", config.Branch, err) // no branch? so ignore repo here
} }
id, err := git.GitBranchHead(filepath.Join(gitPrj, action.Repository.Name), config.Branch) id, err := git.GitRemoteHead(filepath.Join(gitPrj, action.Repository.Name), "origin", config.Branch)
common.PanicOnError(err) common.PanicOnError(err)
for _, commitId := range action.Commits { if action.Head_Commit.Id == id {
if commitId.Id == id { git.GitExecOrPanic(filepath.Join(gitPrj, action.Repository.Name), "checkout", id)
git.GitExecOrPanic(filepath.Join(gitPrj, action.Repository.Name), "checkout", id) git.GitExecOrPanic(gitPrj, "commit", "-a", "-m", "Automatic update via push via Direct Workflow")
git.GitExecOrPanic(gitPrj, "commit", "-a", "-m", "Automatic update via push via Direct Workflow") if !noop {
if !noop { git.GitExecOrPanic(gitPrj, "push")
git.GitExecOrPanic(gitPrj, "push")
}
return nil
} }
return nil
} }
log.Println("push of refs not on the configured branch", config.Branch, ". ignoring.") log.Println("push of refs not on the configured branch", config.Branch, ". ignoring.")
@@ -243,9 +246,8 @@ func verifyProjectState(git common.Git, org string, config *common.AutogitConfig
return fmt.Errorf("Error fetching or creating '%s/%s' -- aborting verifyProjectState(). Err: %w", gitOrg, gitPrj, err) return fmt.Errorf("Error fetching or creating '%s/%s' -- aborting verifyProjectState(). Err: %w", gitOrg, gitPrj, err)
} }
if _, err := fs.Stat(os.DirFS(git.GetPath()), gitPrj); errors.Is(err, os.ErrNotExist) { _, err = git.GitClone(gitPrj, gitBranch, repo.SSHURL)
common.PanicOnError(git.GitClone(gitPrj, gitBranch, repo.SSHURL)) common.PanicOnError(err)
}
defer func() { common.PanicOnError(git.GitExec(gitPrj, "submodule", "deinit", "--all")) }() defer func() { common.PanicOnError(git.GitExec(gitPrj, "submodule", "deinit", "--all")) }()
log.Println(" * Getting submodule list") log.Println(" * Getting submodule list")
@@ -281,20 +283,18 @@ next_package:
} }
//} //}
log.Println(" verifying package:", filename, commitId, config.Branch) log.Printf(" verifying package: %s -> %s(%s)", commitId, filename, config.Branch)
commits, err := gitea.GetRecentCommits(org, filename, config.Branch, 10) commits, err := gitea.GetRecentCommits(org, filename, config.Branch, 10)
if err != nil { if len(commits) == 0 {
// assumption that package does not exist, remove from project if repo, err := gitea.GetRepository(org, filename); repo == nil && err == nil {
// https://github.com/go-gitea/gitea/issues/31976 git.GitExecOrPanic(gitPrj, "rm", filename)
if err := git.GitExec(gitPrj, "rm", filename); err != nil { isGitUpdated = true
return fmt.Errorf("Failed to remove deleted submodule. Err: %w", err)
} }
isGitUpdated = true }
if err != nil {
log.Println(" -> failed to fetch recent commits for package:", filename, " Err:", err)
continue continue
} }
// if err != nil {
// return fmt.Errorf("Failed to fetch recent commits for package: '%s'. Err: %w", filename, err)
// }
idx := 1000 idx := 1000
for i, c := range commits { for i, c := range commits {
@@ -340,10 +340,11 @@ next_package:
common.PanicOnError(git.GitExec(gitPrj, "submodule", "update", "--init", "--depth", "1", "--checkout", filename)) common.PanicOnError(git.GitExec(gitPrj, "submodule", "update", "--init", "--depth", "1", "--checkout", filename))
common.PanicOnError(git.GitExec(filepath.Join(gitPrj, filename), "fetch", "--depth", "1", "origin", commits[0].SHA)) common.PanicOnError(git.GitExec(filepath.Join(gitPrj, filename), "fetch", "--depth", "1", "origin", commits[0].SHA))
common.PanicOnError(git.GitExec(filepath.Join(gitPrj, filename), "checkout", commits[0].SHA)) common.PanicOnError(git.GitExec(filepath.Join(gitPrj, filename), "checkout", commits[0].SHA))
log.Println(" -> updated to", commits[0].SHA)
isGitUpdated = true isGitUpdated = true
} else { } else {
// probably need `merge-base` or `rev-list` here instead, or the project updated already // probably need `merge-base` or `rev-list` here instead, or the project updated already
return fmt.Errorf("Cannot find SHA of last matching update for package: '%s'. idx: %d", filename, idx) log.Println(" *** Cannot find SHA of last matching update for package:", filename, " Ignoring")
} }
} }
} }