func()

in shells/abstract.go [887:989]


func (b *AbstractShell) writeSubmoduleUpdateCmd(w ShellWriter, build *common.Build, recursive bool) error {
	depth := build.GetSubmoduleDepth()

	b.writeSubmoduleUpdateNoticeMsg(w, recursive, depth)

	var pathArgs []string

	submodulePaths, err := build.GetSubmodulePaths()
	if err != nil {
		return err
	}

	if len(submodulePaths) != 0 {
		pathArgs = append(pathArgs, "--")
		pathArgs = append(pathArgs, submodulePaths...)
	}

	// Init submodules must occur prior to sync to ensure completeness of .git/config
	w.Command("git", "submodule", "init")

	// Sync .git/config to .gitmodules in case URL changes (e.g. new build token)
	syncArgs := []string{"submodule", "sync"}
	if recursive {
		syncArgs = append(syncArgs, "--recursive")
	}
	syncArgs = append(syncArgs, pathArgs...)
	w.Command("git", syncArgs...)

	// Update / initialize submodules
	gitURLArgs, err := build.GetURLInsteadOfArgs()
	if err != nil {
		return fmt.Errorf("writing submodule update commands: %w", err)
	}

	if credConfigFile := b.credConfigFile(build, w); credConfigFile != "" {
		gitURLArgs = append(gitURLArgs, "-c", "include.path="+credConfigFile)
	}

	updateArgs := append(gitURLArgs, "submodule", "update", "--init") //nolint:gocritic
	foreachArgs := []string{"submodule", "foreach"}
	if recursive {
		updateArgs = append(updateArgs, "--recursive")
		foreachArgs = append(foreachArgs, "--recursive")
	}
	if depth > 0 {
		updateArgs = append(updateArgs, "--depth", strconv.Itoa(depth))
	}
	submoduleUpdateFlags := build.GetGitSubmoduleUpdateFlags()
	updateArgs = append(updateArgs, submoduleUpdateFlags...)
	updateArgs = append(updateArgs, pathArgs...)

	// Clean changed files in submodules
	cleanFlags := []string{"-ffdx"}
	if len(build.GetGitCleanFlags()) > 0 {
		cleanFlags = build.GetGitCleanFlags()
	}
	cleanCommand := []string{"git clean " + strings.Join(cleanFlags, " ")}

	w.Command("git", append(foreachArgs, cleanCommand...)...)
	w.Command("git", append(foreachArgs, "git reset --hard")...)

	w.IfCmdWithOutput("git", updateArgs...)
	w.Noticef("Updated submodules")
	w.Command("git", syncArgs...)
	w.Else()
	// call sync and update again if the initial update fails
	w.Warningf("Updating submodules failed. Retrying...")

	hasSubmoduleRemoteFlag := slices.ContainsFunc(submoduleUpdateFlags, func(s string) bool {
		return strings.EqualFold(s, "--remote")
	})
	if hasSubmoduleRemoteFlag {
		// We've observed issues like
		//	fatal: Unable to find refs/remotes/origin/dev revision in submodule path 'subs-1'
		// when updating submodule with `--remote` and `branch` was set in `.gitmodules` (which is not the default branch). To
		// work around that, we explicitly pull in the remote heads.
		// We only do this as a fallback / on retry *and* when the `--remote` update flag is used, so that we don't
		// unnecessarily pull in a ton of remote heads.
		// This renders a command similar to:
		//	git \
		//		-c url.https://test.local.insteadOf=ssh://git@test.local \
		//		-c include.path=blipp/blarp/blarz.conf \
		//		submodule foreach 'git fetch origin +refs/heads/*:refs/remotes/origin/*'
		w.Command("git", slices.Concat(
			gitURLArgs, foreachArgs, []string{"git fetch origin +refs/heads/*:refs/remotes/origin/*"},
		)...)
	}

	w.Command("git", syncArgs...)
	w.Command("git", updateArgs...)
	w.Command("git", append(foreachArgs, "git reset --hard")...)
	w.EndIf()

	w.Command("git", append(foreachArgs, cleanCommand...)...)

	if !build.IsLFSSmudgeDisabled() {
		w.IfCmd("git", "lfs", "version")
		w.Command("git", append(append(gitURLArgs, foreachArgs...), "git lfs pull")...)
		w.EndIf()
	}

	return nil
}