diff --git a/README.md b/README.md index 2bb6115..50dc081 100644 --- a/README.md +++ b/README.md @@ -72,7 +72,9 @@ mpd: per: student startercode: url: git@gitlab.example.org:mpd/startercode/blatt-01.git - fromBranch: template + fromBranch: startercode + template: true + templateMessage: Initial Commit ``` ### 3) Validate config and generate repos diff --git a/config/repo.go b/config/repo.go index db64e63..0421af8 100644 --- a/config/repo.go +++ b/config/repo.go @@ -27,6 +27,13 @@ func startercode(assignmentKey string) *Startercode { fromBranch = fB } + template := viper.GetBool(assignmentKey + ".startercode.template") + + templateMessage := "Initial" + if tM := viper.GetString(assignmentKey + ".startercode.templateMessage"); len(tM) > 0 { + templateMessage = tM + } + toBranch := "main" if tB := viper.GetString(assignmentKey + ".startercode.toBranch"); len(tB) > 0 { toBranch = tB @@ -37,6 +44,8 @@ func startercode(assignmentKey string) *Startercode { return &Startercode{ URL: url, FromBranch: fromBranch, + Template: template, + TemplateMessage: templateMessage, ToBranch: toBranch, AdditionalBranches: additionalBranches, } diff --git a/config/show.go b/config/show.go index 1ccd260..0034446 100644 --- a/config/show.go +++ b/config/show.go @@ -169,6 +169,8 @@ func (cfg *AssignmentConfig) Show() { } else { writeSectionField("URL", cfg.Startercode.URL) writeSectionField("FromBranch", cfg.Startercode.FromBranch) + writeSectionField("Template", cfg.Startercode.Template) + writeSectionField("TemplateMessage", cfg.Startercode.TemplateMessage) writeSectionField("ToBranch", cfg.Startercode.ToBranch) writeSectionField("AdditionalBranches", cfg.Startercode.AdditionalBranches) } diff --git a/config/types.go b/config/types.go index a1fe0d3..2876b4a 100644 --- a/config/types.go +++ b/config/types.go @@ -76,6 +76,8 @@ type Seeder struct { type Startercode struct { URL string FromBranch string + Template bool + TemplateMessage string ToBranch string AdditionalBranches []string } diff --git a/docs/advanced.md b/docs/advanced.md index efda68f..2544ec1 100644 --- a/docs/advanced.md +++ b/docs/advanced.md @@ -15,8 +15,10 @@ mpd: blatt02: startercode: url: git@gitlab.lrz.de:mpd/starter.git - fromBranch: template + fromBranch: startercode toBranch: main + template: true + templateMessage: Initial Startercode branches: - name: main diff --git a/docs/getting-started.md b/docs/getting-started.md index 121a879..acd4f84 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -66,9 +66,13 @@ mpd: per: student startercode: url: git@gitlab.example.org:mpd/startercode/blatt-01.git - fromBranch: template + fromBranch: startercode + template: true ``` +If you set `template: true` all commits in startercode will be squashed to just +one commit using the `templateMessage`. + ## Important defaults at a glance | Area | Key | Default | @@ -84,6 +88,8 @@ mpd: | Assignment | `mergeRequest.allThreadsMustBeResolved` | `false` | | Assignment | `mergeRequest.statusChecksMustSucceed` | `false` | | Startercode | `fromBranch` | `main` | +| Startercode | `template` | `false` | +| Startercode | `templateMessage` | `Initial` | | Startercode | `toBranch` | `main` | | Startercode | `additionalBranches` | `[]` | | Branches | first `branches[].default` | `true` on first branch | diff --git a/git/push.go b/git/push.go index ceddbf4..bb92192 100644 --- a/git/push.go +++ b/git/push.go @@ -18,7 +18,7 @@ import ( gitlab "gitlab.com/gitlab-org/api/client-go/v2" ) -func CloneBranch(url, fromBranch string, orphan bool, orphanMessage string) (*git.Repository, plumbing.ReferenceName, error) { +func CloneBranch(url, fromBranch string, singleCommit bool, commitMessage string) (*SourceRepo, error) { cfg := yacspin.Config{ Frequency: 100 * time.Millisecond, CharSet: yacspin.CharSets[69], @@ -46,7 +46,7 @@ func CloneBranch(url, fromBranch string, orphan bool, orphanMessage string) (*gi auth, err := GetAuth() if err != nil { fmt.Printf("error: %v", err) - return nil, "", err + return nil, err } storer := memory.NewStorage() @@ -67,7 +67,7 @@ func CloneBranch(url, fromBranch string, orphan bool, orphanMessage string) (*gi if err != nil { log.Debug().Err(err).Msg("cannot stop spinner") } - return nil, "", err + return nil, err } wt, err := repo.Worktree() @@ -78,7 +78,7 @@ func CloneBranch(url, fromBranch string, orphan bool, orphanMessage string) (*gi if err != nil { log.Debug().Err(err).Msg("cannot stop spinner") } - return nil, "", err + return nil, err } if err := wt.Checkout(&git.CheckoutOptions{ @@ -91,11 +91,15 @@ func CloneBranch(url, fromBranch string, orphan bool, orphanMessage string) (*gi if err != nil { log.Debug().Err(err).Msg("cannot stop spinner") } - return nil, "", err + return nil, err } - if !orphan { - return repo, sourceRef, nil + if !singleCommit { + return &SourceRepo{ + Repo: repo, + Ref: sourceRef, + Auth: auth, + }, nil } headRef, err := repo.Head() @@ -106,7 +110,7 @@ func CloneBranch(url, fromBranch string, orphan bool, orphanMessage string) (*gi if err != nil { log.Debug().Err(err).Msg("cannot stop spinner") } - return nil, "", err + return nil, err } headCommit, err := repo.CommitObject(headRef.Hash()) @@ -117,7 +121,7 @@ func CloneBranch(url, fromBranch string, orphan bool, orphanMessage string) (*gi if err != nil { log.Debug().Err(err).Msg("cannot stop spinner") } - return nil, "", err + return nil, err } tree, err := headCommit.Tree() @@ -128,11 +132,11 @@ func CloneBranch(url, fromBranch string, orphan bool, orphanMessage string) (*gi if err != nil { log.Debug().Err(err).Msg("cannot stop spinner") } - return nil, "", err + return nil, err } - orphanBranchName := fmt.Sprintf("orphan-%s-%d", fromBranch, time.Now().UnixNano()) - orphanRef := plumbing.NewBranchReferenceName(orphanBranchName) + singleCommitBranchName := fmt.Sprintf("orphan-%s-%d", fromBranch, time.Now().UnixNano()) + refName := plumbing.NewBranchReferenceName(singleCommitBranchName) committerName := "glabs" committerEmail := "glabs-bot@noreply.example.com" @@ -154,7 +158,7 @@ func CloneBranch(url, fromBranch string, orphan bool, orphanMessage string) (*gi Email: committerEmail, When: now, }, - Message: orphanMessage, + Message: commitMessage, TreeHash: tree.Hash, } @@ -166,7 +170,7 @@ func CloneBranch(url, fromBranch string, orphan bool, orphanMessage string) (*gi if err != nil { log.Debug().Err(err).Msg("cannot stop spinner") } - return nil, "", err + return nil, err } commitHash, err := repo.Storer.SetEncodedObject(encoded) @@ -177,22 +181,22 @@ func CloneBranch(url, fromBranch string, orphan bool, orphanMessage string) (*gi if err != nil { log.Debug().Err(err).Msg("cannot stop spinner") } - return nil, "", err + return nil, err } - if err := repo.Storer.SetReference(plumbing.NewHashReference(orphanRef, commitHash)); err != nil { + if err := repo.Storer.SetReference(plumbing.NewHashReference(refName, commitHash)); err != nil { spinner.StopFailMessage(fmt.Sprintf("problem: %v", err)) err := spinner.StopFail() if err != nil { log.Debug().Err(err).Msg("cannot stop spinner") } - return nil, "", err + return nil, err } if err := repo.CreateBranch(&gitconfig.Branch{ - Name: orphanRef.Short(), - Merge: orphanRef, + Name: refName.Short(), + Merge: refName, }); err != nil && err != git.ErrBranchExists { spinner.StopFailMessage(fmt.Sprintf("problem: %v", err)) @@ -200,11 +204,11 @@ func CloneBranch(url, fromBranch string, orphan bool, orphanMessage string) (*gi if err != nil { log.Debug().Err(err).Msg("cannot stop spinner") } - return nil, "", err + return nil, err } if err := wt.Checkout(&git.CheckoutOptions{ - Branch: orphanRef, + Branch: refName, Force: true, }); err != nil { spinner.StopFailMessage(fmt.Sprintf("problem: %v", err)) @@ -213,26 +217,30 @@ func CloneBranch(url, fromBranch string, orphan bool, orphanMessage string) (*gi if err != nil { log.Debug().Err(err).Msg("cannot stop spinner") } - return nil, "", err + return nil, err } - if orphan { - spinner.StopMessage(fmt.Sprintf("using branch '%s' with single commit '%s'", orphanRef.Short(), orphanMessage)) + if singleCommit { + spinner.StopMessage(fmt.Sprintf("using branch '%s' with single commit '%s'", refName.Short(), commitMessage)) } errs := spinner.Stop() if errs != nil { log.Debug().Err(err).Msg("cannot stop spinner") } - return repo, orphanRef, nil + return &SourceRepo{ + Repo: repo, + Ref: refName, + Auth: auth, + }, nil } -func PushBranch(assignmentCfg *config.AssignmentConfig, projectname string, repo *git.Repository, localRef plumbing.ReferenceName, toBranch string, force bool, project *gitlab.Project) error { +func PushBranch(assignmentCfg *config.AssignmentConfig, projectname string, sourceRepo *SourceRepo, toBranch string, force bool, project *gitlab.Project) error { cfg := yacspin.Config{ Frequency: 100 * time.Millisecond, CharSet: yacspin.CharSets[69], Suffix: aurora.Sprintf(aurora.Cyan(" pushing branch %s to project %s / branch %s"), - aurora.Yellow(localRef.Short()), + aurora.Yellow(sourceRepo.Ref.Short()), aurora.Magenta(assignmentCfg.URL+"/"+project.Name), aurora.Magenta(toBranch), ), @@ -258,7 +266,7 @@ func PushBranch(assignmentCfg *config.AssignmentConfig, projectname string, repo URLs: []string{project.SSHURLToRepo}, } - remote, err := repo.CreateRemote(conf) + remote, err := sourceRepo.Repo.CreateRemote(conf) if err != nil { spinner.StopFailMessage(fmt.Sprintf("problem: %v", err)) @@ -272,19 +280,7 @@ func PushBranch(assignmentCfg *config.AssignmentConfig, projectname string, repo return fmt.Errorf("cannot create remote: %w", err) } - auth, err := GetAuth() - if err != nil { - spinner.StopFailMessage(fmt.Sprintf("problem: %v", err)) - - err := spinner.StopFail() - if err != nil { - log.Debug().Err(err).Msg("cannot stop spinner") - } - fmt.Printf("error: %v", err) - return err - } - - spec := localRef.String() + ":" + plumbing.NewBranchReferenceName(toBranch).String() + spec := sourceRepo.Ref.String() + ":" + plumbing.NewBranchReferenceName(toBranch).String() if force { spec = "+" + spec } @@ -292,10 +288,10 @@ func PushBranch(assignmentCfg *config.AssignmentConfig, projectname string, repo pushOpts := &git.PushOptions{ RemoteName: remote.Config().Name, RefSpecs: []gitconfig.RefSpec{gitconfig.RefSpec(spec)}, - Auth: auth, + Auth: sourceRepo.Auth, } - err = repo.Push(pushOpts) + err = sourceRepo.Repo.Push(pushOpts) if err != nil { spinner.StopFailMessage(fmt.Sprintf("problem: %v", err)) diff --git a/git/starterrepo.go b/git/starterrepo.go index 31b86f9..c22d6ca 100644 --- a/git/starterrepo.go +++ b/git/starterrepo.go @@ -6,18 +6,12 @@ import ( git "github.com/go-git/go-git/v5" "github.com/go-git/go-git/v5/plumbing" - "github.com/go-git/go-git/v5/plumbing/transport/ssh" "github.com/go-git/go-git/v5/storage/memory" "github.com/logrusorgru/aurora" "github.com/rs/zerolog/log" "github.com/theckman/yacspin" ) -type SourceRepo struct { - Repo *git.Repository - Auth ssh.AuthMethod -} - func PrepareSourceRepo(url, fromBranch string) (*SourceRepo, error) { cfg := yacspin.Config{ Frequency: 100 * time.Millisecond, @@ -71,6 +65,7 @@ func PrepareSourceRepo(url, fromBranch string) (*SourceRepo, error) { return &SourceRepo{ Repo: r, + Ref: plumbing.ReferenceName("refs/heads/" + fromBranch), Auth: auth, }, nil } diff --git a/git/types.go b/git/types.go new file mode 100644 index 0000000..12ba425 --- /dev/null +++ b/git/types.go @@ -0,0 +1,13 @@ +package git + +import ( + git "github.com/go-git/go-git/v5" + "github.com/go-git/go-git/v5/plumbing" + "github.com/go-git/go-git/v5/plumbing/transport/ssh" +) + +type SourceRepo struct { + Repo *git.Repository + Ref plumbing.ReferenceName + Auth ssh.AuthMethod +} diff --git a/gitlab/generate.go b/gitlab/generate.go index 86b11a7..123fab9 100644 --- a/gitlab/generate.go +++ b/gitlab/generate.go @@ -29,7 +29,7 @@ func (c *Client) Generate(assignmentCfg *config.AssignmentConfig) { var starterrepo *git.SourceRepo if assignmentCfg.Startercode != nil { - starterrepo, err = git.PrepareSourceRepo(assignmentCfg.Startercode.URL, assignmentCfg.Startercode.FromBranch) + starterrepo, err = git.CloneBranch(assignmentCfg.Startercode.URL, assignmentCfg.Startercode.FromBranch, assignmentCfg.Startercode.Template, assignmentCfg.Startercode.TemplateMessage) if err != nil { fmt.Println(err) diff --git a/gitlab/push.go b/gitlab/push.go index 0f97b57..536d459 100644 --- a/gitlab/push.go +++ b/gitlab/push.go @@ -13,7 +13,7 @@ func (c *Client) Push(assignmentCfg *config.AssignmentConfig, branchname string) return fmt.Errorf("error: no config for deferred branch \"%s\" found\n", branchname) } - repo, branchRef, err := git.CloneBranch(branch.URL, branch.FromBranch, branch.Orphan, branch.OrphanMessage) + sourceRepo, err := git.CloneBranch(branch.URL, branch.FromBranch, branch.Orphan, branch.OrphanMessage) if err != nil { return err } @@ -39,7 +39,7 @@ func (c *Client) Push(assignmentCfg *config.AssignmentConfig, branchname string) return err } - err = git.PushBranch(assignmentCfg, projectname, repo, branchRef, branch.ToBranch, true, project) + err = git.PushBranch(assignmentCfg, projectname, sourceRepo, branch.ToBranch, true, project) if err != nil { return err } diff --git a/gitlab/starterrepo.go b/gitlab/starterrepo.go index aeb8264..6336ea9 100644 --- a/gitlab/starterrepo.go +++ b/gitlab/starterrepo.go @@ -27,7 +27,7 @@ func (c *Client) pushStartercode(assignmentCfg *cfg.AssignmentConfig, from *g.So refSpec := config.RefSpec( fmt.Sprintf("+refs/heads/%s:refs/heads/%s", - assignmentCfg.Startercode.FromBranch, + from.Ref.Short(), assignmentCfg.Startercode.ToBranch), ) @@ -35,7 +35,7 @@ func (c *Client) pushStartercode(assignmentCfg *cfg.AssignmentConfig, from *g.So Str("refSpec", string(refSpec)). Str("name", project.Name). Str("toURL", project.SSHURLToRepo). - Str("fromBranch", assignmentCfg.Startercode.FromBranch). + Str("fromBranch", from.Ref.Short()). Str("toBranch", assignmentCfg.Startercode.ToBranch). Msg("pushing starter code")