Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 37 additions & 0 deletions cmd/push.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package cmd

import (
"fmt"

"github.com/logrusorgru/aurora/v4"
"github.com/obcode/glabs/v2/config"
"github.com/obcode/glabs/v2/gitlab"
"github.com/spf13/cobra"
)

var pushCmd = &cobra.Command{
Use: "push course assignment branch [groups...|students...]",
Short: "Push one deferred branch to student/group repos",
Long: `Push one deferred branch to student/group repos.
You can specify students or groups in order to push only for these.
You cannot push all deferred branches at once.`,
Args: cobra.MinimumNArgs(3), //nolint:gomnd
Run: func(cmd *cobra.Command, args []string) {
course := args[0]
assignment := args[1]
branchname := args[2]
assignmentConfig := config.GetAssignmentConfig(course, assignment, args[3:]...)
assignmentConfig.Show()
fmt.Println(aurora.Magenta("Config okay? Press 'Enter' to continue or 'Ctrl-C' to stop ..."))
fmt.Scanln() //nolint:errcheck
c := gitlab.NewClient()
err := c.Push(assignmentConfig, branchname)
if err != nil {
fmt.Printf("error: %s", err.Error())
}
},
}

func init() {
rootCmd.AddCommand(pushCmd)
}
37 changes: 37 additions & 0 deletions config/assignment.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,42 @@ func GetAssignmentConfig(course, assignment string, onlyForStudentsOrGroups ...s
branchRules := branches(assignmentKey, starter)
defaultCloneBranch := defaultBranch(branchRules, "main")

deferredBranches := make(map[string]*DeferredBranch)
deferredBranchesCfg := viper.GetStringMap(assignmentKey + ".deferredBranches")
if len(deferredBranchesCfg) > 0 {
for name := range deferredBranchesCfg {
configMap := viper.GetStringMapString(assignmentKey + ".deferredBranches." + name)

url, ok := configMap["url"]
if !ok {
url = starter.URL
}
fromBranch := configMap["frombranch"]
toBranch, ok := configMap["tobranch"]
if !ok {
toBranch = fromBranch
}
orphanValue, ok := configMap["orphan"]
orphan := true
if ok && orphanValue == "false" {
orphan = false
}

orphanMessage, ok := configMap["orphanmessage"]
if !ok {
orphanMessage = fmt.Sprintf("Snapshot of %s", name)
}

deferredBranches[name] = &DeferredBranch{
URL: url,
FromBranch: fromBranch,
ToBranch: toBranch,
Orphan: orphan,
OrphanMessage: orphanMessage,
}
}
}

assignmentConfig := &AssignmentConfig{
Course: course,
Name: assignment,
Expand All @@ -64,6 +100,7 @@ func GetAssignmentConfig(course, assignment string, onlyForStudentsOrGroups ...s
Clone: clone(assignmentKey, defaultCloneBranch),
Release: release,
Seeder: seeder(assignmentKey),
DeferredBranches: deferredBranches,
}

return assignmentConfig
Expand Down
14 changes: 14 additions & 0 deletions config/show.go
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,20 @@ func (cfg *AssignmentConfig) Show() {
}
}

writeSectionHeader("DeferredBranches")
if len(cfg.DeferredBranches) == 0 {
writeSectionNotDefined()
} else {
for name, branch := range cfg.DeferredBranches {
writeIndentedHeader(2, fmt.Sprintf("- %s", name))
writeSectionField(" URL", branch.URL)
writeSectionField(" FromBranch", branch.FromBranch)
writeSectionField(" ToBranch", branch.ToBranch)
writeSectionField(" Orphan", branch.Orphan)
writeSectionField(" OrphanMessage", branch.OrphanMessage)
}
}

writeSectionHeader("MergeRequest")
writeSectionField("MergeMethod", mergeMethod)
writeSectionField("SquashOption", squashOption)
Expand Down
9 changes: 9 additions & 0 deletions config/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,15 @@ type AssignmentConfig struct {
Clone *Clone
Release *Release
Seeder *Seeder
DeferredBranches map[string]*DeferredBranch
}

type DeferredBranch struct {
URL string
FromBranch string
ToBranch string
Orphan bool
OrphanMessage string
}

type Per string
Expand Down
39 changes: 38 additions & 1 deletion docs/commands.md
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,44 @@ Print glabs version.
glabs version
```

## push

You can push one deferred branch at a time to all student/group repositories using the `push` command. You can define more than one deferred branch.

### Assignment Config Example

```yaml
deferredBranches:
solution:
url: # (optional) source repo, defaults to startercode URL
fromBranch: # (default: solution)
toBranch: # (default: solution)
orphan: # (default: true)
orphanMessage: # (default: Snapshot of solution)
anotherbranch:
url: # (optional) source repo, defaults to startercode URL
fromBranch: # (default: anotherbranch)
toBranch: # (default: anotherbranch)
orphan: # (default: true)
orphanMessage: # (default: Snapshot of anotherbranch)
```

- If `orphan: true`, a new orphan branch is created in each repo with a single commit from the deferred branch.
- If `orphan: false`, the deferred branch is pushed as a normal branch (with complete history).
- deferred branches are always pushed with `--force`

**Usage:**

```sh
glabs push <course> <assignment> <deferred-branch> [groups...|students...]
```

e.g.

```sh
glabs push mpd ass1 solution
```

## Filtering students or groups

When specifying `[groups...|students...]`, patterns are treated as regular expressions:
Expand Down Expand Up @@ -209,4 +247,3 @@ glabs generate --help # Show generate help with flags
glabs protect --help # Show protect help
glabs report --help # Show report help
glabs -v generate mpd blatt01 # Run with verbose logging
```
6 changes: 3 additions & 3 deletions git/clone.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,16 +26,16 @@ func Clone(cfg *config.AssignmentConfig, noSpinner bool) {
case config.PerStudent:
for _, stud := range cfg.Students {
suffix := cfg.RepoSuffix(stud)
clone(localpath(cfg, suffix), cfg.Clone.Branch, cloneurl(cfg, suffix), auth, cfg.Clone.Force, noSpinner)
clone(localpath(cfg, suffix), cfg.Clone.Branch, ProjectRepoUrl(cfg, suffix), auth, cfg.Clone.Force, noSpinner)
}
case config.PerGroup:
for _, grp := range cfg.Groups {
clone(localpath(cfg, grp.Name), cfg.Clone.Branch, cloneurl(cfg, grp.Name), auth, cfg.Clone.Force, noSpinner)
clone(localpath(cfg, grp.Name), cfg.Clone.Branch, ProjectRepoUrl(cfg, grp.Name), auth, cfg.Clone.Force, noSpinner)
}
}
}

func cloneurl(cfg *config.AssignmentConfig, suffix string) string {
func ProjectRepoUrl(cfg *config.AssignmentConfig, suffix string) string {
return fmt.Sprintf("%s/%s-%s",
strings.Replace(strings.Replace(cfg.URL, "https://", "git@", 1), "/", ":", 1),
cfg.RepoBaseName(), suffix)
Expand Down
6 changes: 3 additions & 3 deletions git/clone_helpers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ func TestCloneurl_HTTPS(t *testing.T) {
UseCoursenameAsPrefix: true,
}

got := cloneurl(cfg, "alice")
got := ProjectRepoUrl(cfg, "alice")
want := "git@gitlab.example.org:mpd/ss26/blatt-01/mpd-blatt01-alice"
if got != want {
t.Fatalf("cloneurl() = %q, want %q", got, want)
Expand All @@ -30,7 +30,7 @@ func TestCloneurl_ContainsExpectedParts(t *testing.T) {
UseCoursenameAsPrefix: true,
}

got := cloneurl(cfg, "bob")
got := ProjectRepoUrl(cfg, "bob")

if strings.Contains(got, "https://") {
t.Fatalf("cloneurl() should not contain https://, got %q", got)
Expand All @@ -51,7 +51,7 @@ func TestCloneurl_WithoutCoursePrefix(t *testing.T) {
UseCoursenameAsPrefix: false,
}

got := cloneurl(cfg, "team1")
got := ProjectRepoUrl(cfg, "team1")
want := "git@gitlab.example.org:mpd/ss26/blatt-01/blatt01-team1"
if got != want {
t.Fatalf("cloneurl() = %q, want %q", got, want)
Expand Down
Loading
Loading