diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index 1c855a3..0b627c3 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -16,7 +16,7 @@ jobs: - name: Set up Go uses: actions/setup-go@v4 with: - go-version: '1.20' + go-version: '1.22' - name: Build run: go build -v ./... diff --git a/cmd/run.go b/cmd/run.go index c8e2346..459af3b 100644 --- a/cmd/run.go +++ b/cmd/run.go @@ -29,13 +29,6 @@ var runCmd = &cobra.Command{ } gitConfig := config.MkGitConfig(cfg) - repositoryStatus := repository.RepositoryStatus{} - repository, err := repository.New(gitConfig, repositoryStatus) - if err != nil { - logrus.Errorf("Failed to initialize the repository: %s", err) - os.Exit(1) - } - machineId, err := utils.ReadMachineId() if err != nil { logrus.Error(err) @@ -49,6 +42,19 @@ var runCmd = &cobra.Command{ logrus.Errorf("Ignoring the state file %s because of the loading error: %s", storeFilename, err) } metrics.SetBuildInfo(cmd.Version) + + // We get the last mainCommitId to avoid useless + // redeployment as well as non fast forward checkouts + var mainCommitId string + if ok, lastDeployment := store.LastDeployment(); ok { + mainCommitId = lastDeployment.Generation.MainCommitId + } + repository, err := repository.New(gitConfig, mainCommitId) + if err != nil { + logrus.Errorf("Failed to initialize the repository: %s", err) + os.Exit(1) + } + manager := manager.New(repository, store, metrics, gitConfig.Path, cfg.Hostname, machineId) go poller.Poller(manager, cfg.Remotes) http.Serve(manager, diff --git a/flake.lock b/flake.lock index 7052972..81aee39 100644 --- a/flake.lock +++ b/flake.lock @@ -2,10 +2,10 @@ "nodes": { "nixpkgs": { "locked": { - "lastModified": 1701539137, - "narHash": "sha256-nVO/5QYpf1GwjvtpXhyxx5M3U/WN0MwBro4Lsk+9mL0=", - "path": "/nix/store/chi01x4fh8hx7wwh0rqd7m1c8583iyhv-source", - "rev": "933d7dc155096e7575d207be6fb7792bc9f34f6d", + "lastModified": 1717281328, + "narHash": "sha256-evZPzpf59oNcDUXxh2GHcxHkTEG4fjae2ytWP85jXRo=", + "path": "/nix/store/f3rv70nrmkfya581f1j2z9a6yx0b83np-source", + "rev": "b3b2b28c1daa04fe2ae47c21bb76fd226eac4ca1", "type": "path" }, "original": { diff --git a/go.mod b/go.mod index 096f06c..bd40102 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/nlewo/comin -go 1.17 +go 1.22 require ( github.com/barkimedes/go-deepcopy v0.0.0-20220514131651-17c30cfc62df diff --git a/internal/deployment/deployment.go b/internal/deployment/deployment.go index 7cc0d1b..802e744 100644 --- a/internal/deployment/deployment.go +++ b/internal/deployment/deployment.go @@ -46,7 +46,7 @@ func StatusFromString(status string) Status { return Init } -type DeployFunc func(context.Context, string, string, string) (bool, error) +type DeployFunc func(context.Context, string, string, string) (bool, string, error) type Deployment struct { UUID string `json:"uuid"` @@ -57,6 +57,7 @@ type Deployment struct { Err error `json:"-"` ErrorMsg string `json:"error_msg"` RestartComin bool `json:"restart_comin"` + ProfilePath string `json:"profile_path"` Status Status `json:"status"` Operation string `json:"operation"` @@ -68,6 +69,7 @@ type DeploymentResult struct { Err error EndAt time.Time RestartComin bool + ProfilePath string } func New(g generation.Generation, deployerFunc DeployFunc, deploymentCh chan DeploymentResult) Deployment { @@ -93,6 +95,7 @@ func (d Deployment) Update(dr DeploymentResult) Deployment { d.ErrorMsg = dr.Err.Error() } d.RestartComin = dr.RestartComin + d.ProfilePath = dr.ProfilePath if dr.Err == nil { d.Status = Done } else { @@ -111,7 +114,7 @@ func (d Deployment) IsTesting() bool { func (d Deployment) Deploy(ctx context.Context) Deployment { go func() { // FIXME: propagate context - cominNeedRestart, err := d.deployerFunc( + cominNeedRestart, profilePath, err := d.deployerFunc( ctx, d.Generation.EvalMachineId, d.Generation.OutPath, @@ -127,6 +130,7 @@ func (d Deployment) Deploy(ctx context.Context) Deployment { deploymentResult.EndAt = time.Now().UTC() deploymentResult.RestartComin = cominNeedRestart + deploymentResult.ProfilePath = profilePath d.deploymentCh <- deploymentResult }() d.Status = Running diff --git a/internal/generation/generation.go b/internal/generation/generation.go index 2c2806a..b58e86b 100644 --- a/internal/generation/generation.go +++ b/internal/generation/generation.go @@ -72,12 +72,17 @@ type Generation struct { Status Status `json:"status"` + SelectedRemoteUrl string `json:"remote-url"` SelectedRemoteName string `json:"remote-name"` SelectedBranchName string `json:"branch-name"` SelectedCommitId string `json:"commit-id"` SelectedCommitMsg string `json:"commit-msg"` SelectedBranchIsTesting bool `json:"branch-is-testing"` + MainCommitId string `json:"main-commit-id"` + MainRemoteName string `json:"main-remote-name"` + MainBranchName string `json:"main-branch-name"` + EvalStartedAt time.Time `json:"eval-started-at"` evalTimeout time.Duration evalFunc EvalFunc @@ -113,20 +118,32 @@ type EvalResult struct { } func New(repositoryStatus repository.RepositoryStatus, flakeUrl, hostname, machineId string, evalFunc EvalFunc, buildFunc BuildFunc) Generation { + remoteUrl := "" + for _, r := range repositoryStatus.Remotes { + if r.Name == repositoryStatus.SelectedRemoteName { + remoteUrl = r.Url + } + } return Generation{ UUID: uuid.NewString(), + SelectedRemoteUrl: remoteUrl, SelectedRemoteName: repositoryStatus.SelectedRemoteName, SelectedBranchName: repositoryStatus.SelectedBranchName, SelectedCommitId: repositoryStatus.SelectedCommitId, SelectedCommitMsg: repositoryStatus.SelectedCommitMsg, SelectedBranchIsTesting: repositoryStatus.SelectedBranchIsTesting, - evalTimeout: 6 * time.Second, - evalFunc: evalFunc, - buildFunc: buildFunc, - FlakeUrl: flakeUrl, - Hostname: hostname, - MachineId: machineId, - Status: Init, + + MainRemoteName: repositoryStatus.MainRemoteName, + MainBranchName: repositoryStatus.MainBranchName, + MainCommitId: repositoryStatus.MainCommitId, + + evalTimeout: 6 * time.Second, + evalFunc: evalFunc, + buildFunc: buildFunc, + FlakeUrl: flakeUrl, + Hostname: hostname, + MachineId: machineId, + Status: Init, } } diff --git a/internal/manager/manager.go b/internal/manager/manager.go index 9bba588..5b1907d 100644 --- a/internal/manager/manager.go +++ b/internal/manager/manager.go @@ -30,7 +30,7 @@ type Manager struct { hostname string // The machine id of the current host machineId string - triggerRepository chan string + triggerRepository chan []string generationFactory func(repository.RepositoryStatus, string, string) generation.Generation stateRequestCh chan struct{} stateResultCh chan State @@ -68,7 +68,7 @@ func New(r repository.Repository, s store.Store, p prometheus.Prometheus, path, evalFunc: nix.Eval, buildFunc: nix.Build, deployerFunc: nix.Deploy, - triggerRepository: make(chan string), + triggerRepository: make(chan []string), stateRequestCh: make(chan struct{}), stateResultCh: make(chan State), cominServiceRestartFunc: utils.CominServiceRestart, @@ -92,8 +92,8 @@ func (m Manager) GetState() State { return <-m.stateResultCh } -func (m Manager) Fetch(remote string) { - m.triggerRepository <- remote +func (m Manager) Fetch(remotes []string) { + m.triggerRepository <- remotes } func (m Manager) toState() State { @@ -180,7 +180,7 @@ func (m Manager) onRepositoryStatus(ctx context.Context, rs repository.Repositor return m } -func (m Manager) onTriggerRepository(ctx context.Context, remoteName string) Manager { +func (m Manager) onTriggerRepository(ctx context.Context, remoteNames []string) Manager { if m.isFetching { logrus.Debugf("The manager is already fetching the repository") return m @@ -190,10 +190,10 @@ func (m Manager) onTriggerRepository(ctx context.Context, remoteName string) Man logrus.Debugf("The manager is already running: it is currently not able to run tasks in parallel") return m } - logrus.Debugf("Trigger fetch and update remote %s", remoteName) + logrus.Debugf("Trigger fetch and update remotes %s", remoteNames) m.isRunning = true m.isFetching = true - m.repositoryStatusCh = m.repository.FetchAndUpdate(ctx, remoteName) + m.repositoryStatusCh = m.repository.FetchAndUpdate(ctx, remoteNames) return m } @@ -204,12 +204,13 @@ func (m Manager) Run() { logrus.Infof(" hostname = %s", m.hostname) logrus.Infof(" machineId = %s", m.machineId) logrus.Infof(" repositoryPath = %s", m.repositoryPath) + for { select { case <-m.stateRequestCh: m.stateResultCh <- m.toState() - case remoteName := <-m.triggerRepository: - m = m.onTriggerRepository(ctx, remoteName) + case remoteNames := <-m.triggerRepository: + m = m.onTriggerRepository(ctx, remoteNames) case rs := <-m.repositoryStatusCh: m = m.onRepositoryStatus(ctx, rs) case evalResult := <-m.generation.EvalCh(): diff --git a/internal/manager/manager_test.go b/internal/manager/manager_test.go index 0386460..694414f 100644 --- a/internal/manager/manager_test.go +++ b/internal/manager/manager_test.go @@ -27,7 +27,7 @@ func newRepositoryMock() (r *repositoryMock) { rsCh: rsCh, } } -func (r *repositoryMock) FetchAndUpdate(ctx context.Context, remoteName string) (rsCh chan repository.RepositoryStatus) { +func (r *repositoryMock) FetchAndUpdate(ctx context.Context, remoteNames []string) (rsCh chan repository.RepositoryStatus) { return r.rsCh } @@ -49,8 +49,8 @@ func TestRun(t *testing.T) { m.evalFunc = nixEvalMock m.buildFunc = nixBuildMock - deployFunc := func(context.Context, string, string, string) (bool, error) { - return false, nil + deployFunc := func(context.Context, string, string, string) (bool, string, error) { + return false, "", nil } m.deployerFunc = deployFunc @@ -60,7 +60,7 @@ func TestRun(t *testing.T) { assert.Equal(t, State{}, m.GetState()) // the repository is fetched - m.Fetch("origin") + m.Fetch([]string{"origin"}) assert.Equal(t, repository.RepositoryStatus{}, m.GetState().RepositoryStatus) // we inject a repositoryStatus @@ -100,10 +100,10 @@ func TestFetchBusy(t *testing.T) { assert.Equal(t, State{}, m.GetState()) - m.Fetch("origin") + m.Fetch([]string{"origin"}) assert.Equal(t, repository.RepositoryStatus{}, m.GetState().RepositoryStatus) - m.Fetch("origin") + m.Fetch([]string{"origin"}) assert.Equal(t, repository.RepositoryStatus{}, m.GetState().RepositoryStatus) } @@ -150,7 +150,7 @@ func TestOptionnalMachineId(t *testing.T) { m.buildFunc = nixBuildMock go m.Run() - m.Fetch("origin") + m.Fetch([]string{"origin"}) r.rsCh <- repository.RepositoryStatus{SelectedCommitId: "foo"} // we simulate the end of the evaluation @@ -185,7 +185,7 @@ func TestIncorrectMachineId(t *testing.T) { assert.Equal(t, State{}, m.GetState()) // the repository is fetched - m.Fetch("origin") + m.Fetch([]string{"origin"}) r.rsCh <- repository.RepositoryStatus{SelectedCommitId: "foo"} assert.True(t, m.GetState().IsRunning) diff --git a/internal/nix/nix.go b/internal/nix/nix.go index 99db71d..8276638 100644 --- a/internal/nix/nix.go +++ b/internal/nix/nix.go @@ -9,6 +9,7 @@ import ( "io" "os" "os/exec" + "path" "path/filepath" "strings" @@ -49,7 +50,7 @@ func runNixCommand(args []string, stdout, stderr io.Writer) (err error) { commonArgs := []string{"--extra-experimental-features", "nix-command", "--extra-experimental-features", "flakes", "--accept-flake-config"} args = append(commonArgs, args...) cmdStr := fmt.Sprintf("nix %s", strings.Join(args, " ")) - logrus.Infof("Running '%s'", cmdStr) + logrus.Infof("nix: running '%s'", cmdStr) cmd := exec.Command("nix", args...) cmd.Stdout = stdout cmd.Stderr = stderr @@ -75,6 +76,7 @@ func ShowDerivation(ctx context.Context, flakeUrl, hostname string) (drvPath str "show-derivation", installable, "-L", + "--show-trace", } var stdout bytes.Buffer err = runNixCommand(args, &stdout, os.Stderr) @@ -93,8 +95,8 @@ func ShowDerivation(ctx context.Context, flakeUrl, hostname string) (drvPath str } drvPath = keys[0] outPath = output[drvPath].Outputs.Out.Path - logrus.Infof("The derivation path is %s", drvPath) - logrus.Infof("The output path is %s", outPath) + logrus.Infof("nix: the derivation path is %s", drvPath) + logrus.Infof("nix: the output path is %s", outPath) return } @@ -152,86 +154,84 @@ func Build(ctx context.Context, drvPath string) (err error) { return } -func setSystemProfile(operation string, outPath string, dryRun bool) error { +// setSystemProfile creates a link into the directory +// /nix/var/nix/profiles/system-profiles/comin to the built system +// store path. This is used by the switch-to-configuration script to +// install all entries into the bootloader. +// Note also comin uses these links as gcroots +// See https://github.com/nixos/nixpkgs/blob/df98ab81f908bed57c443a58ec5230f7f7de9bd3/pkgs/os-specific/linux/nixos-rebuild/nixos-rebuild.sh#L711 +// and https://github.com/nixos/nixpkgs/blob/df98ab81f908bed57c443a58ec5230f7f7de9bd3/nixos/modules/system/boot/loader/systemd-boot/systemd-boot-builder.py#L247 +func setSystemProfile(operation string, outPath string, dryRun bool) (profilePath string, err error) { + systemProfilesDir := "/nix/var/nix/profiles/system-profiles" + profile := systemProfilesDir + "/comin" if operation == "switch" || operation == "boot" { - cmdStr := fmt.Sprintf("nix-env --profile /nix/var/nix/profiles/system --set %s", outPath) - logrus.Infof("Running '%s'", cmdStr) - cmd := exec.Command("nix-env", "--profile", "/nix/var/nix/profiles/system", "--set", outPath) + err := os.MkdirAll(systemProfilesDir, os.ModeDir) + if err != nil && !os.IsExist(err) { + return profilePath, fmt.Errorf("nix: failed to create the profile directory: %s", systemProfilesDir) + } + cmdStr := fmt.Sprintf("nix-env --profile %s --set %s", profile, outPath) + logrus.Infof("nix: running '%s'", cmdStr) + cmd := exec.Command("nix-env", "--profile", profile, "--set", outPath) cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr if dryRun { - logrus.Infof("Dry-run enabled: '%s' has not been executed", cmdStr) + logrus.Infof("nix: dry-run enabled: '%s' has not been executed", cmdStr) } else { err := cmd.Run() if err != nil { - return fmt.Errorf("Command '%s' fails with %s", cmdStr, err) + return profilePath, fmt.Errorf("nix: command '%s' fails with %s", cmdStr, err) + } + logrus.Infof("nix: command '%s' succeeded", cmdStr) + dst, err := os.Readlink(profile) + if err != nil { + return profilePath, fmt.Errorf("nix: failed to os.Readlink(%s)", profile) } - logrus.Infof("Command '%s' succeeded", cmdStr) + profilePath = path.Join(systemProfilesDir, dst) + logrus.Infof("nix: the profile %s has been created", profilePath) } } - return nil -} - -func createGcRoot(stateDir, outPath string, dryRun bool) error { - gcRootDir := filepath.Join(stateDir, "gcroots") - gcRoot := filepath.Join( - gcRootDir, - fmt.Sprintf("switch-to-configuration")) - if dryRun { - logrus.Infof("Dry-run enabled: 'ln -s %s %s'", outPath, gcRoot) - return nil - } - if err := os.MkdirAll(gcRootDir, 0750); err != nil { - return err - } - // TODO: only remove if file already exists - os.Remove(gcRoot) - if err := os.Symlink(outPath, gcRoot); err != nil { - return fmt.Errorf("Failed to create symlink 'ln -s %s %s': %s", outPath, gcRoot, err) - } - logrus.Infof("Creating gcroot '%s'", gcRoot) - return nil + return } func cominUnitFileHash() string { - logrus.Infof("Generating the comin.service unit file sha256: 'systemctl cat comin.service | sha256sum'") + logrus.Infof("nix: generating the comin.service unit file sha256: 'systemctl cat comin.service | sha256sum'") cmd := exec.Command("systemctl", "cat", "comin.service") var stdout bytes.Buffer cmd.Stdout = &stdout cmd.Stderr = os.Stderr if err := cmd.Run(); err != nil { - logrus.Infof("Command 'systemctl cat comin.service' fails with '%s'", err) + logrus.Infof("nix: command 'systemctl cat comin.service' fails with '%s'", err) return "" } sum := sha256.Sum256(stdout.Bytes()) hash := fmt.Sprintf("%x", sum) - logrus.Infof("The comin.service unit file sha256 is '%s'", hash) + logrus.Infof("nix: the comin.service unit file sha256 is '%s'", hash) return hash } func switchToConfiguration(operation string, outPath string, dryRun bool) error { switchToConfigurationExe := filepath.Join(outPath, "bin", "switch-to-configuration") - logrus.Infof("Running '%s %s'", switchToConfigurationExe, operation) + logrus.Infof("nix: running '%s %s'", switchToConfigurationExe, operation) cmd := exec.Command(switchToConfigurationExe, operation) cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr if dryRun { - logrus.Infof("Dry-run enabled: '%s switch' has not been executed", switchToConfigurationExe) + logrus.Infof("nix: dry-run enabled: '%s switch' has not been executed", switchToConfigurationExe) } else { if err := cmd.Run(); err != nil { return fmt.Errorf("Command %s switch fails with %s", switchToConfigurationExe, err) } - logrus.Infof("Switch successfully terminated") + logrus.Infof("nix: switch successfully terminated") } return nil } -func Deploy(ctx context.Context, expectedMachineId, outPath, operation string) (needToRestartComin bool, err error) { +func Deploy(ctx context.Context, expectedMachineId, outPath, operation string) (needToRestartComin bool, profilePath string, err error) { beforeCominUnitFileHash := cominUnitFileHash() // This is required to write boot entries // Only do this is operation is switch or boot - if err = setSystemProfile(operation, outPath, false); err != nil { + if profilePath, err = setSystemProfile(operation, outPath, false); err != nil { return } @@ -245,7 +245,7 @@ func Deploy(ctx context.Context, expectedMachineId, outPath, operation string) ( needToRestartComin = true } - logrus.Infof("Deployment succeeded") + logrus.Infof("nix: deployment ended") return } diff --git a/internal/poller/poller.go b/internal/poller/poller.go index 5e59a62..9b273aa 100644 --- a/internal/poller/poller.go +++ b/internal/poller/poller.go @@ -21,11 +21,15 @@ func Poller(m manager.Manager, remotes []types.Remote) { } counter := 0 for { + toFetch := make([]string, 0) for _, remote := range remotes { if remote.Poller.Period != 0 && counter%remote.Poller.Period == 0 { - m.Fetch(remote.Name) + toFetch = append(toFetch, remote.Name) } } + if len(toFetch) > 0 { + m.Fetch(toFetch) + } time.Sleep(time.Second) counter += 1 } diff --git a/internal/repository/repository.go b/internal/repository/repository.go index 3c3ec4f..b4c8bce 100644 --- a/internal/repository/repository.go +++ b/internal/repository/repository.go @@ -2,7 +2,7 @@ package repository import ( "context" - "fmt" + "slices" "time" "github.com/go-git/go-git/v5" @@ -18,11 +18,11 @@ type repository struct { } type Repository interface { - FetchAndUpdate(ctx context.Context, remoteName string) (rsCh chan RepositoryStatus) + FetchAndUpdate(ctx context.Context, remoteNames []string) (rsCh chan RepositoryStatus) } // repositoryStatus is the last saved repositoryStatus -func New(config types.GitConfig, repositoryStatus RepositoryStatus) (r *repository, err error) { +func New(config types.GitConfig, mainCommitId string) (r *repository, err error) { r = &repository{} r.GitConfig = config r.Repository, err = repositoryOpen(config) @@ -33,15 +33,15 @@ func New(config types.GitConfig, repositoryStatus RepositoryStatus) (r *reposito if err != nil { return } - r.RepositoryStatus = NewRepositoryStatus(config, repositoryStatus) + r.RepositoryStatus = NewRepositoryStatus(config, mainCommitId) return } -func (r *repository) FetchAndUpdate(ctx context.Context, remoteName string) (rsCh chan RepositoryStatus) { +func (r *repository) FetchAndUpdate(ctx context.Context, remoteNames []string) (rsCh chan RepositoryStatus) { rsCh = make(chan RepositoryStatus) go func() { // FIXME: switch to the FetchContext to clean resource up on timeout - err := r.Fetch(remoteName) + err := r.Fetch(remoteNames) if err == nil { r.Update() } @@ -50,27 +50,13 @@ func (r *repository) FetchAndUpdate(ctx context.Context, remoteName string) (rsC return rsCh } -func (r *repository) Fetch(remoteName string) (err error) { - var found bool +func (r *repository) Fetch(remoteNames []string) (err error) { r.RepositoryStatus.Error = nil r.RepositoryStatus.ErrorMsg = "" - if remoteName != "" { - for _, remote := range r.GitConfig.Remotes { - if remote.Name == remoteName { - found = true - } - } - if !found { - r.RepositoryStatus.Error = err - r.RepositoryStatus.ErrorMsg = err.Error() - return fmt.Errorf("The remote '%s' doesn't exist", remoteName) - } - } - for _, remote := range r.GitConfig.Remotes { repositoryStatusRemote := r.RepositoryStatus.GetRemote(remote.Name) repositoryStatusRemote.LastFetched = false - if remoteName != "" && remote.Name != remoteName { + if !slices.Contains(remoteNames, remote.Name) { continue } repositoryStatusRemote.LastFetched = true diff --git a/internal/repository/repository_status.go b/internal/repository/repository_status.go index 8ec768b..8b88eb3 100644 --- a/internal/repository/repository_status.go +++ b/internal/repository/repository_status.go @@ -53,9 +53,9 @@ type RepositoryStatus struct { ErrorMsg string `json:"error_msg"` } -func NewRepositoryStatus(config types.GitConfig, repositoryStatus RepositoryStatus) RepositoryStatus { +func NewRepositoryStatus(config types.GitConfig, mainCommitId string) RepositoryStatus { r := RepositoryStatus{ - MainCommitId: repositoryStatus.MainCommitId, + MainCommitId: mainCommitId, } r.Remotes = make([]*Remote, len(config.Remotes)) for i, remote := range config.Remotes { diff --git a/internal/repository/repository_test.go b/internal/repository/repository_test.go index 29d784d..2cc2c65 100644 --- a/internal/repository/repository_test.go +++ b/internal/repository/repository_test.go @@ -31,7 +31,7 @@ func TestNew(t *testing.T) { }, }, } - r, err := New(gitConfig, RepositoryStatus{}) + r, err := New(gitConfig, "") assert.Nil(t, err) assert.Equal(t, "r1", r.RepositoryStatus.Remotes[0].Name) } @@ -60,11 +60,11 @@ func TestPreferMain(t *testing.T) { }, }, } - r, err := New(gitConfig, RepositoryStatus{}) + r, err := New(gitConfig, "") assert.Nil(t, err) // r1/main: c1 - c2 - *c3 // r1/testing: c1 - c2 - c3 - err = r.Fetch("") + err = r.Fetch([]string{"r1"}) assert.Nil(t, err) err = r.Update() assert.Nil(t, err) @@ -75,7 +75,7 @@ func TestPreferMain(t *testing.T) { // r1/main: c1 - c2 - c3 // r1/testing: c1 - c2 - c3 - *c4 c4, err := commitFile(r1, r1Dir, "testing", "file-4") - err = r.Fetch("") + err = r.Fetch([]string{"r1"}) assert.Nil(t, err) err = r.Update() assert.Nil(t, err) @@ -86,7 +86,7 @@ func TestPreferMain(t *testing.T) { // r1/main: c1 - c2 - c3 - *c4 // r1/testing: c1 - c2 - c3 - c4 c4, err = commitFile(r1, r1Dir, "main", "file-4") - err = r.Fetch("") + err = r.Fetch([]string{"r1"}) assert.Nil(t, err) err = r.Update() assert.Nil(t, err) @@ -118,16 +118,14 @@ func TestMainCommitId(t *testing.T) { }, }, } - r, _ := New(gitConfig, RepositoryStatus{ - MainCommitId: cMain, - }) + r, _ := New(gitConfig, cMain) // r1/main: c1 - c2 - c3 - c4 // r1/testing: c1 - c2 - c3 - c4 - c5 c4, _ := commitFile(r1, r1Dir, "main", "file-4") commitFile(r1, r1Dir, "testing", "file-4") c5, _ := commitFile(r1, r1Dir, "testing", "file-5") - r.Fetch("") + r.Fetch([]string{"r1"}) r.Update() assert.Equal(t, c4, r.RepositoryStatus.MainCommitId) assert.Equal(t, c5, r.RepositoryStatus.SelectedCommitId) @@ -173,10 +171,9 @@ func TestContinueIfHardReset(t *testing.T) { }, }, } - r, _ := New(gitConfig, RepositoryStatus{ - MainCommitId: cMain, - }) - r.Fetch("") + r, _ := New(gitConfig, cMain) + + r.Fetch([]string{"r1", "r2"}) r.Update() // r1/main: c1 - c2 - ^c3 @@ -184,7 +181,7 @@ func TestContinueIfHardReset(t *testing.T) { // r2/main: c1 - c2 - c3 // r2/testing: c1 - c2 - c3 - *c4 c4, _ := commitFile(r2, r2Dir, "testing", "file-4") - r.Fetch("") + r.Fetch([]string{"r1", "r2"}) r.Update() assert.Equal(t, c4, r.RepositoryStatus.SelectedCommitId) assert.Equal(t, "testing", r.RepositoryStatus.SelectedBranchName) @@ -195,7 +192,7 @@ func TestContinueIfHardReset(t *testing.T) { // r2/main: c1 - c2 - c3 - *c4 // r2/testing: c1 - c2 - c3 - ^c4 c4, _ = commitFile(r2, r2Dir, "main", "file-4") - r.Fetch("") + r.Fetch([]string{"r1", "r2"}) r.Update() assert.Equal(t, c4, r.RepositoryStatus.SelectedCommitId) assert.Equal(t, "main", r.RepositoryStatus.MainBranchName) @@ -242,11 +239,11 @@ func TestMultipleRemote(t *testing.T) { }, }, } - r, err := New(gitConfig, RepositoryStatus{}) + r, err := New(gitConfig, "") assert.Nil(t, err) // r1/main: c1 - c2 - *c3 // r2/main: c1 - c2 - c3 - _ = r.Fetch("") + _ = r.Fetch([]string{"r1", "r2"}) _ = r.Update() assert.Equal(t, HeadCommitId(r.Repository), r.RepositoryStatus.SelectedCommitId) assert.Equal(t, "main", r.RepositoryStatus.SelectedBranchName) @@ -256,7 +253,7 @@ func TestMultipleRemote(t *testing.T) { // r2/main: c1 - c2 - c3 newCommitId, err := commitFile(r1, r1Dir, "main", "file-4") assert.Nil(t, err) - _ = r.Fetch("") + _ = r.Fetch([]string{"r1", "r2"}) _ = r.Update() assert.Equal(t, newCommitId, r.RepositoryStatus.SelectedCommitId) assert.Equal(t, "main", r.RepositoryStatus.SelectedBranchName) @@ -267,7 +264,7 @@ func TestMultipleRemote(t *testing.T) { commitFile(r2, r2Dir, "main", "file-4") newCommitId, err = commitFile(r2, r2Dir, "main", "file-5") assert.Nil(t, err) - _ = r.Fetch("") + _ = r.Fetch([]string{"r1", "r2"}) _ = r.Update() assert.Equal(t, newCommitId, r.RepositoryStatus.SelectedCommitId) assert.Equal(t, "main", r.RepositoryStatus.SelectedBranchName) @@ -277,7 +274,7 @@ func TestMultipleRemote(t *testing.T) { // r2/main: c1 - c2 - c3 - c4 - c5 newCommitId, err = commitFile(r1, r1Dir, "main", "file-5") assert.Nil(t, err) - _ = r.Fetch("") + _ = r.Fetch([]string{"r1", "r2"}) _ = r.Update() assert.Equal(t, newCommitId, r.RepositoryStatus.SelectedCommitId) assert.Equal(t, "main", r.RepositoryStatus.SelectedBranchName) @@ -292,7 +289,7 @@ func TestMultipleRemote(t *testing.T) { commitFile(r2, r2Dir, "testing", "file-5") commitFile(r2, r2Dir, "testing", "file-6") c7, _ := commitFile(r2, r2Dir, "testing", "file-7") - _ = r.Fetch("") + _ = r.Fetch([]string{"r1", "r2"}) _ = r.Update() assert.Equal(t, c6, r.RepositoryStatus.MainCommitId) assert.Equal(t, c7, r.RepositoryStatus.SelectedCommitId) @@ -302,7 +299,7 @@ func TestMultipleRemote(t *testing.T) { // r1/main: c1 - c2 - c3 - c4 - c5 - c6 // r2/main: c1 - c2 - c3 - c4 - c5 - c6 // r2/testing: c1 - c2 - c3 - c4 - c5 - c6 - *c7 - _ = r.Fetch("") + _ = r.Fetch([]string{"r1", "r2"}) _ = r.Update() assert.Equal(t, c7, r.RepositoryStatus.SelectedCommitId) assert.Equal(t, "testing", r.RepositoryStatus.SelectedBranchName) @@ -313,7 +310,7 @@ func TestMultipleRemote(t *testing.T) { // r2/main: c1 - c2 - c3 - c4 - c5 - c6 // r2/testing: c1 - c2 - c3 - c4 - c5 - c6 - c7 c8, _ := commitFile(r1, r1Dir, "main", "file-8") - _ = r.Fetch("") + _ = r.Fetch([]string{"r1", "r2"}) _ = r.Update() assert.Equal(t, c8, r.RepositoryStatus.SelectedCommitId) assert.Equal(t, "main", r.RepositoryStatus.SelectedBranchName) @@ -324,7 +321,7 @@ func TestMultipleRemote(t *testing.T) { // r2/main: c1 - c2 - c3 - c4 - c5 - c6 // r2/testing: c1 - c2 - c3 - c4 - c5 - c6 - c7 c9, _ := commitFile(r1, r1Dir, "main", "file-9") - _ = r.Fetch("r2") + _ = r.Fetch([]string{"r2"}) _ = r.Update() assert.Equal(t, c8, r.RepositoryStatus.SelectedCommitId) assert.Equal(t, "main", r.RepositoryStatus.SelectedBranchName) @@ -339,7 +336,7 @@ func TestMultipleRemote(t *testing.T) { // r1/main: c1 - c2 - c3 - c4 - c5 - c6 - c8 - *c9 // r2/main: c1 - c2 - c3 - c4 - c5 - c6 // r2/testing: c1 - c2 - c3 - c4 - c5 - c6 - c7 - _ = r.Fetch("r1") + _ = r.Fetch([]string{"r1"}) _ = r.Update() assert.Equal(t, c9, r.RepositoryStatus.SelectedCommitId) assert.Equal(t, "main", r.RepositoryStatus.SelectedBranchName) @@ -384,13 +381,13 @@ func TestTestingSwitch(t *testing.T) { }, }, } - r, _ := New(gitConfig, RepositoryStatus{}) + r, _ := New(gitConfig, "") // r1/main: c1 - c2 - *c3 // r1/testing: c1 - c2 - c3 // r2/main: c1 - c2 - c3 // r2/testing: c1 - c2 - c3 - _ = r.Fetch("") + _ = r.Fetch([]string{"r1", "r2"}) _ = r.Update() assert.Equal(t, cMain, r.RepositoryStatus.SelectedCommitId) assert.Equal(t, "main", r.RepositoryStatus.SelectedBranchName) @@ -401,7 +398,7 @@ func TestTestingSwitch(t *testing.T) { // r2/main: c1 - c2 - c3 // r2/testing: c1 - c2 - c3 - *c4 c4, _ := commitFile(r2, r2Dir, "testing", "file-4") - _ = r.Fetch("") + _ = r.Fetch([]string{"r1", "r2"}) _ = r.Update() assert.Equal(t, c4, r.RepositoryStatus.SelectedCommitId) assert.Equal(t, "testing", r.RepositoryStatus.SelectedBranchName) @@ -411,7 +408,7 @@ func TestTestingSwitch(t *testing.T) { // r1/testing: c1 - c2 - c3 // r2/main: c1 - c2 - c3 // r2/testing: c1 - c2 - c3 - *c4 - _ = r.Fetch("") + _ = r.Fetch([]string{"r1", "r2"}) _ = r.Update() assert.Equal(t, "testing", r.RepositoryStatus.SelectedBranchName) assert.Equal(t, "r2", r.RepositoryStatus.SelectedRemoteName) @@ -422,7 +419,7 @@ func TestTestingSwitch(t *testing.T) { // r2/main: c1 - c2 - c3 - *c4 // r2/testing: c1 - c2 - c3 - c4 commitFile(r2, r2Dir, "main", "file-4") - _ = r.Fetch("") + _ = r.Fetch([]string{"r1", "r2"}) _ = r.Update() assert.Equal(t, c4, r.RepositoryStatus.SelectedCommitId) assert.Equal(t, "main", r.RepositoryStatus.SelectedBranchName) @@ -453,9 +450,9 @@ func TestWithoutTesting(t *testing.T) { }, }, } - r, _ := New(gitConfig, RepositoryStatus{}) + r, _ := New(gitConfig, "") - _ = r.Fetch("") + _ = r.Fetch([]string{"r1"}) _ = r.Update() assert.Equal(t, HeadCommitId(r.Repository), r.RepositoryStatus.SelectedCommitId) assert.Equal(t, "main", r.RepositoryStatus.SelectedBranchName) @@ -486,17 +483,17 @@ func TestRepositoryUpdateMain(t *testing.T) { }, }, } - r, _ := New(gitConfig, RepositoryStatus{}) + r, _ := New(gitConfig, "") // The remote repository is initially checkouted - _ = r.Fetch("") + _ = r.Fetch([]string{"origin"}) _ = r.Update() assert.Equal(t, HeadCommitId(r.Repository), r.RepositoryStatus.SelectedCommitId) assert.Equal(t, "main", r.RepositoryStatus.SelectedBranchName) assert.Equal(t, "origin", r.RepositoryStatus.SelectedRemoteName) // Without any new remote commits, the local repository is not updated - _ = r.Fetch("") + _ = r.Fetch([]string{"origin"}) _ = r.Update() assert.Equal(t, HeadCommitId(r.Repository), r.RepositoryStatus.SelectedCommitId) assert.Equal(t, "main", r.RepositoryStatus.SelectedBranchName) @@ -505,7 +502,7 @@ func TestRepositoryUpdateMain(t *testing.T) { // A new commit is pushed to the remote repository: the local // repository is updated newCommitId, err := commitFile(remoteRepository, remoteRepositoryDir, "main", "file-4") - _ = r.Fetch("") + _ = r.Fetch([]string{"origin"}) _ = r.Update() assert.Equal(t, newCommitId, r.RepositoryStatus.SelectedCommitId) assert.Equal(t, "main", r.RepositoryStatus.SelectedBranchName) @@ -514,7 +511,7 @@ func TestRepositoryUpdateMain(t *testing.T) { // A commit is pushed to the testing branch which is currently // behind the main branch: the repository is not updated _, err = commitFile(remoteRepository, remoteRepositoryDir, "testing", "file-5") - _ = r.Fetch("") + _ = r.Fetch([]string{"origin"}) _ = r.Update() assert.Equal(t, newCommitId, r.RepositoryStatus.SelectedCommitId) assert.Equal(t, "main", r.RepositoryStatus.SelectedBranchName) @@ -545,10 +542,10 @@ func TestRepositoryUpdateHardResetMain(t *testing.T) { }, }, } - r, _ := New(gitConfig, RepositoryStatus{}) + r, _ := New(gitConfig, "") // The remote repository is initially checkouted - _ = r.Fetch("") + _ = r.Fetch([]string{"origin"}) _ = r.Update() assert.Equal(t, HeadCommitId(r.Repository), r.RepositoryStatus.SelectedCommitId) assert.Equal(t, "main", r.RepositoryStatus.SelectedBranchName) @@ -559,7 +556,7 @@ func TestRepositoryUpdateHardResetMain(t *testing.T) { previousHash, err := commitFile(remoteRepository, remoteRepositoryDir, "main", "file-4") newCommitId, err := commitFile(remoteRepository, remoteRepositoryDir, "main", "file-5") - _ = r.Fetch("") + _ = r.Fetch([]string{"origin"}) _ = r.Update() assert.Equal(t, newCommitId, r.RepositoryStatus.SelectedCommitId) assert.Equal(t, "main", r.RepositoryStatus.SelectedBranchName) @@ -572,7 +569,7 @@ func TestRepositoryUpdateHardResetMain(t *testing.T) { if err != nil { return } - _ = r.Fetch("") + _ = r.Fetch([]string{"origin"}) _ = r.Update() assert.Equal(t, newCommitId, r.RepositoryStatus.SelectedCommitId) assert.Equal(t, "main", r.RepositoryStatus.SelectedBranchName) @@ -604,10 +601,10 @@ func TestRepositoryUpdateTesting(t *testing.T) { }, }, } - r, _ := New(gitConfig, RepositoryStatus{}) + r, _ := New(gitConfig, "") // The remote repository is initially checkouted on main - _ = r.Fetch("") + _ = r.Fetch([]string{"origin"}) _ = r.Update() assert.Equal(t, HeadCommitId(r.Repository), r.RepositoryStatus.SelectedCommitId) assert.Equal(t, "main", r.RepositoryStatus.SelectedBranchName) @@ -616,7 +613,7 @@ func TestRepositoryUpdateTesting(t *testing.T) { // A new commit is pushed to the testing branch remote repository: the local // repository is updated commitId4, err := commitFile(remoteRepository, remoteRepositoryDir, "testing", "file-4") - _ = r.Fetch("") + _ = r.Fetch([]string{"origin"}) _ = r.Update() assert.Equal(t, commitId4, r.RepositoryStatus.SelectedCommitId) assert.Equal(t, "testing", r.RepositoryStatus.SelectedBranchName) @@ -625,7 +622,7 @@ func TestRepositoryUpdateTesting(t *testing.T) { // A new commit is pushed to the testing branch remote repository: the local // repository is updated commitId5, err := commitFile(remoteRepository, remoteRepositoryDir, "testing", "file-5") - _ = r.Fetch("") + _ = r.Fetch([]string{"origin"}) _ = r.Update() assert.Equal(t, commitId5, r.RepositoryStatus.SelectedCommitId) assert.Equal(t, "testing", r.RepositoryStatus.SelectedBranchName) @@ -641,7 +638,7 @@ func TestRepositoryUpdateTesting(t *testing.T) { if err != nil { return } - _ = r.Fetch("") + _ = r.Fetch([]string{"origin"}) _ = r.Update() assert.Equal(t, commitId5, r.RepositoryStatus.SelectedCommitId) assert.Equal(t, "main", r.RepositoryStatus.SelectedBranchName) @@ -672,11 +669,11 @@ func TestTestingHardReset(t *testing.T) { }, }, } - r, err := New(gitConfig, RepositoryStatus{}) + r, err := New(gitConfig, "") assert.Nil(t, err) // r1/main: c1 - c2 - *c3 // r1/testing: c1 - c2 - c3 - err = r.Fetch("") + err = r.Fetch([]string{"r1"}) assert.Nil(t, err) err = r.Update() assert.Nil(t, err) @@ -687,7 +684,7 @@ func TestTestingHardReset(t *testing.T) { // r1/main: c1 - c2 - c3 // r1/testing: c1 - c2 - c3 - *c4 c4, err := commitFile(r1, r1Dir, "testing", "file-4") - err = r.Fetch("") + err = r.Fetch([]string{"r1"}) assert.Nil(t, err) err = r.Update() assert.Nil(t, err) @@ -699,7 +696,7 @@ func TestTestingHardReset(t *testing.T) { // r1/testing: c1 - c2 - c3 ref := plumbing.NewHashReference("refs/heads/testing", plumbing.NewHash(cMain)) r1.Storer.SetReference(ref) - err = r.Fetch("") + err = r.Fetch([]string{"r1"}) assert.Nil(t, err) err = r.Update() assert.Nil(t, err)