package forgepb import ( "errors" "fmt" "os" "path/filepath" "strings" "go.wit.com/lib/protobuf/gitpb" "go.wit.com/log" ) // creates a patchset // works from the user branches against the devel branches func (f *Forge) SubmitDevelPatchSet(name string) (*Patchset, error) { pset := new(Patchset) pset.Name = name if os.Getenv("GIT_AUTHOR_NAME") == "" { return nil, fmt.Errorf("GIT_AUTHOR_NAME not set") } else { pset.GitAuthorName = os.Getenv("GIT_AUTHOR_NAME") } if os.Getenv("GIT_AUTHOR_EMAIL") == "" { return nil, fmt.Errorf("GIT_AUTHOR_EMAIL not set") } else { pset.GitAuthorEmail = os.Getenv("GIT_AUTHOR_EMAIL") } dir, err := os.MkdirTemp("", "forge") if err != nil { return nil, err } defer os.RemoveAll(dir) // clean up pset.TmpDir = dir all := f.Repos.SortByFullPath() for all.Scan() { repo := all.Next() if !repo.ExistsUserBranch() { continue } if !repo.ExistsDevelBranch() { continue } // make a patchset from user to devel // TODO: verify branches are otherwise exact pset.StartBranchName = repo.GetDevelBranchName() pset.EndBranchName = repo.GetUserBranchName() err := pset.makePatchSetNew(repo) if err != nil { return nil, err } } if err := f.submitPatchset(pset); err != nil { return nil, err } return pset, nil } func (f *Forge) MakeMasterPatchSet() (*Patchset, error) { pset := new(Patchset) dir, err := os.MkdirTemp("", "forge") if err != nil { return nil, err } defer os.RemoveAll(dir) // clean up pset.TmpDir = dir all := f.Repos.SortByFullPath() for all.Scan() { repo := all.Next() startb := repo.GetMasterBranchName() endb := repo.GetUserBranchName() if startb == "" { continue } if endb == "" { continue } // log.Info("repo", repo.GetGoPath(), startb, "..", endb) pset.StartBranchName = startb pset.EndBranchName = endb err := pset.makePatchSetNew(repo) if err != nil { return nil, err } } return pset, nil } func (pset *Patchset) makePatchSetNew(repo *gitpb.Repo) error { startBranch := pset.StartBranchName endBranch := pset.EndBranchName repoDir := filepath.Join(pset.TmpDir, repo.GetGoPath()) err := os.MkdirAll(repoDir, 0755) if err != nil { return err } // git format-patch branch1..branch2 cmd := []string{"git", "format-patch", "-o", repoDir, startBranch + ".." + endBranch} r := repo.Run(cmd) if r.Error != nil { log.Info("git format-patch", repo.FullPath) log.Info("git format-patch", cmd) log.Info("git format-patch error", r.Error) return r.Error } if r.Exit != 0 { log.Info("git format-patch", repo.FullPath) log.Info("git format-patch", cmd) log.Info("git format-patch exit", r.Exit) return errors.New(fmt.Sprintf("git returned %d", r.Exit)) } if len(r.Stdout) == 0 { // git created no files to add return nil } return pset.addPatchFiles(repo) } // process each file in pDir/ func (p *Patchset) addPatchFiles(repo *gitpb.Repo) error { psetDir := repo.GetGoPath() tmpDir := p.TmpDir // log.Info("ADD PATCH FILES ADDED DIR", tmpDir) fullDir := filepath.Join(tmpDir, psetDir) var baderr error filepath.Walk(fullDir, func(path string, info os.FileInfo, err error) error { if err != nil { // Handle possible errors, like permission issues fmt.Fprintf(os.Stderr, "error accessing path %q: %v\n", path, err) baderr = err return err } if info.IsDir() { return nil } // log.Info("IS THIS A FULL PATH ?", path) // log.Info("trim this from path ?", fullDir) // log.Info("trim this from path ?", psetDir) // log.Info("trim this from path ?", tmpDir) data, err := os.ReadFile(path) if err != nil { log.Info("addPatchFile() failed", path) baderr = err return err } patch := new(Patch) patch.Filename, _ = filepath.Rel(p.TmpDir, path) patch.Data = data patch.parseData() patch.StartHash = repo.DevelHash() if p.Patches == nil { p.Patches = new(Patches) } p.Patches.Append(patch) // log.Info("ADDED PATCH FILE", path) return nil }) return baderr } // looks at the git format-patch output // saves the commit Hash // saves the diff lines func (p *Patch) parseData() string { lines := strings.Split(string(p.Data), "\n") for _, line := range lines { fields := strings.Fields(line) if len(fields) < 2 { continue } switch fields[0] { case "From": p.CommitHash = fields[1] case "diff": p.Files = append(p.Files, line) } } return "" } // just an example of how to walk only directories func onlyWalkDirs(pDir string) error { log.Info("DIR", pDir) // var all []string var baderr error filepath.WalkDir(pDir, func(path string, d os.DirEntry, err error) error { if err != nil { // Handle possible errors, like permission issues fmt.Fprintf(os.Stderr, "error accessing path %q: %v\n", path, err) baderr = err return err } log.Info("TESTING DIR", path) if d.IsDir() { return filepath.SkipDir } log.Info("NEVER GETS HERE? WHAT IS THIS?", path) return nil }) return baderr } func (f *Forge) submitPatchset(pset *Patchset) error { var url string url = forgeURL + "patchset" msg, err := pset.Marshal() if err != nil { log.Info("proto.Marshal() failed:", err) return err } log.Info("proto.Marshal() msg len", len(msg)) body, err := f.HttpPost(url, msg) if err != nil { log.Info("httpPost() failed:", err) return err } test := strings.TrimSpace(string(body)) lines := strings.Split(test, "\n") count := 0 for _, line := range lines { log.Info("got back:", line) count += 1 } log.Info("Total patches:", count) return nil }