From 325e1689f514fa2603704f625ba41e7dae911a1c Mon Sep 17 00:00:00 2001
From: EscapeB <EscapeB@users.noreply.github.com>
Date: Thu, 22 Feb 2024 15:20:23 +0800
Subject: [PATCH] fix: cr fix

---
 apps/sparo-lib/src/cli/commands/checkout.ts     | 12 ++----------
 apps/sparo-lib/src/cli/commands/fetch.ts        | 17 +++++++++++++----
 apps/sparo-lib/src/cli/commands/git-checkout.ts |  6 +++---
 apps/sparo-lib/src/cli/commands/git-clone.ts    |  6 +++---
 apps/sparo-lib/src/cli/commands/git-fetch.ts    |  6 +++---
 apps/sparo-lib/src/cli/commands/git-pull.ts     |  6 +++---
 apps/sparo-lib/src/services/GitService.ts       | 16 ++++++++++++++++
 apps/sparo/bin/sparo                            |  0
 apps/sparo/bin/sparo-ci                         |  0
 .../sparo/fix-cr_fix_2024-02-22-07-24.json      | 10 ++++++++++
 common/reviews/api/sparo-lib.api.md             |  2 ++
 11 files changed, 55 insertions(+), 26 deletions(-)
 mode change 100644 => 100755 apps/sparo/bin/sparo
 mode change 100644 => 100755 apps/sparo/bin/sparo-ci
 create mode 100644 common/changes/sparo/fix-cr_fix_2024-02-22-07-24.json

diff --git a/apps/sparo-lib/src/cli/commands/checkout.ts b/apps/sparo-lib/src/cli/commands/checkout.ts
index 991e762..1f619a7 100644
--- a/apps/sparo-lib/src/cli/commands/checkout.ts
+++ b/apps/sparo-lib/src/cli/commands/checkout.ts
@@ -181,7 +181,8 @@ export class CheckoutCommand implements ICommand<ICheckoutCommandOptions> {
     );
     if (!branchExistsInLocal) {
       // fetch from remote
-      const remote: string = this._getBranchRemote();
+      const remote: string = this._gitService.getBranchRemote(branch);
+
       const fetchResult: child_process.SpawnSyncReturns<string> = this._gitService.executeGitCommand({
         args: ['fetch', remote, `refs/heads/${branch}:refs/remotes/${remote}/${branch}`]
       });
@@ -210,15 +211,6 @@ export class CheckoutCommand implements ICommand<ICheckoutCommandOptions> {
     return currentBranch;
   }
 
-  private _getBranchRemote(): string {
-    /**
-     * TODO: Git supports multiple remotes. We need to support using a different
-     *   remote from "origin". A possible way is reading from git config by running
-     *   "git config --get branch.<branch>.remote"
-     */
-    return 'origin';
-  }
-
   private _processProfilesFromArg(profilesFromArg: string[]): { isNoProfile: boolean; profiles: string[] } {
     /**
      * --profile is defined as array type parameter, specifying --no-profile is resolved to false by yargs.
diff --git a/apps/sparo-lib/src/cli/commands/fetch.ts b/apps/sparo-lib/src/cli/commands/fetch.ts
index f77322b..2c587cc 100644
--- a/apps/sparo-lib/src/cli/commands/fetch.ts
+++ b/apps/sparo-lib/src/cli/commands/fetch.ts
@@ -10,16 +10,25 @@ import type { TerminalService } from '../../services/TerminalService';
 export interface IFetchCommandOptions {
   all?: boolean;
   branch?: string;
+  remote?: string;
 }
 
 @Command()
 export class FetchCommand implements ICommand<IFetchCommandOptions> {
-  public cmd: string = 'fetch';
+  public cmd: string = 'fetch [remote] [branch]';
   public description: string = 'fetch remote branch to local';
 
   @inject(GitService) private _gitService!: GitService;
   public builder(yargs: Argv<{}>): void {
-    yargs.boolean('full');
+    /**
+     * sparo fetch <remote> <branch> [--all]
+     */
+    yargs
+      .positional('remote', { type: 'string' })
+      .positional('branch', { type: 'string' })
+      .string('remote')
+      .string('branch')
+      .boolean('full');
   }
 
   public handler = async (
@@ -32,13 +41,13 @@ export class FetchCommand implements ICommand<IFetchCommandOptions> {
     const { branch: defaultBranch } = repoInfo;
 
     terminal.writeDebugLine(`got args in fetch command: ${JSON.stringify(args)}`);
-    const { all, branch = defaultBranch } = args;
+    const { all, branch = defaultBranch, remote = this._gitService.getBranchRemote(branch) } = args;
     const fetchArgs: string[] = ['fetch'];
 
     if (all) {
       fetchArgs.push('--all');
     } else {
-      fetchArgs.push('origin', branch);
+      fetchArgs.push(remote, branch);
     }
 
     gitService.executeGitCommand({ args: fetchArgs });
diff --git a/apps/sparo-lib/src/cli/commands/git-checkout.ts b/apps/sparo-lib/src/cli/commands/git-checkout.ts
index ac271d1..9e55010 100644
--- a/apps/sparo-lib/src/cli/commands/git-checkout.ts
+++ b/apps/sparo-lib/src/cli/commands/git-checkout.ts
@@ -18,9 +18,9 @@ export class GitCheckoutCommand implements ICommand<{}> {
     const { _gitService: gitService } = this;
     const { terminal } = terminalService;
     const rawArgs: string[] = process.argv.slice(2);
-    const idx: number = rawArgs.indexOf(this.cmd);
-    if (idx >= 0) {
-      rawArgs[idx] = 'checkout';
+    const index: number = rawArgs.indexOf(this.cmd);
+    if (index >= 0) {
+      rawArgs[index] = 'checkout';
     }
     terminal.writeDebugLine(`proxy args in git-checkout command: ${JSON.stringify(rawArgs)}`);
     gitService.executeGitCommand({ args: rawArgs });
diff --git a/apps/sparo-lib/src/cli/commands/git-clone.ts b/apps/sparo-lib/src/cli/commands/git-clone.ts
index c9318ee..9c2d15a 100644
--- a/apps/sparo-lib/src/cli/commands/git-clone.ts
+++ b/apps/sparo-lib/src/cli/commands/git-clone.ts
@@ -18,9 +18,9 @@ export class GitCloneCommand implements ICommand<{}> {
     const { _gitService: gitService } = this;
     const { terminal } = terminalService;
     const rawArgs: string[] = process.argv.slice(2);
-    const idx: number = rawArgs.indexOf(this.cmd);
-    if (idx >= 0) {
-      rawArgs[idx] = 'clone';
+    const index: number = rawArgs.indexOf(this.cmd);
+    if (index >= 0) {
+      rawArgs[index] = 'clone';
     }
     terminal.writeDebugLine(`proxy args in git-clone command: ${JSON.stringify(rawArgs)}`);
     gitService.executeGitCommand({ args: rawArgs });
diff --git a/apps/sparo-lib/src/cli/commands/git-fetch.ts b/apps/sparo-lib/src/cli/commands/git-fetch.ts
index 301833d..36f2e8d 100644
--- a/apps/sparo-lib/src/cli/commands/git-fetch.ts
+++ b/apps/sparo-lib/src/cli/commands/git-fetch.ts
@@ -19,9 +19,9 @@ export class GitFetchCommand implements ICommand<{}> {
     const { _gitService: gitService } = this;
     const { terminal } = terminalService;
     const rawArgs: string[] = process.argv.slice(2);
-    const idx: number = rawArgs.indexOf(this.cmd);
-    if (idx >= 0) {
-      rawArgs[idx] = 'fetch';
+    const index: number = rawArgs.indexOf(this.cmd);
+    if (index >= 0) {
+      rawArgs[index] = 'fetch';
     }
     terminal.writeDebugLine(`proxy args in git-fetch command: ${JSON.stringify(rawArgs)}`);
     gitService.executeGitCommand({ args: rawArgs });
diff --git a/apps/sparo-lib/src/cli/commands/git-pull.ts b/apps/sparo-lib/src/cli/commands/git-pull.ts
index 96fcb93..0a83aad 100644
--- a/apps/sparo-lib/src/cli/commands/git-pull.ts
+++ b/apps/sparo-lib/src/cli/commands/git-pull.ts
@@ -16,9 +16,9 @@ export class GitPullCommand implements ICommand<{}> {
     const { _gitService: gitService } = this;
     const { terminal } = terminalService;
     const rawArgs: string[] = process.argv.slice(2);
-    const idx: number = rawArgs.indexOf(this.cmd);
-    if (idx >= 0) {
-      rawArgs[idx] = 'pull';
+    const index: number = rawArgs.indexOf(this.cmd);
+    if (index >= 0) {
+      rawArgs[index] = 'pull';
     }
     terminal.writeDebugLine(`proxy args in git-pull command: ${JSON.stringify(rawArgs)}`);
     gitService.executeGitCommand({ args: rawArgs });
diff --git a/apps/sparo-lib/src/services/GitService.ts b/apps/sparo-lib/src/services/GitService.ts
index e3d6e6f..4a0c950 100644
--- a/apps/sparo-lib/src/services/GitService.ts
+++ b/apps/sparo-lib/src/services/GitService.ts
@@ -346,6 +346,22 @@ Please specify a directory on the command line
     return getRepoInfo();
   }
 
+  public getBranchRemote(branch: string): string {
+    const gitPath: string = this.getGitPathOrThrow();
+    const { stdout, status } = Executable.spawnSync(gitPath, ['config', `branch.${branch}.remote`]);
+
+    if (status === 1 && stdout.trim().length === 0) {
+      // git config branch.<branch_name>.remote can't get correct remote in these two scenarios
+      // 1. If target branch is not checked out locally.
+      // 2. If target branch is a newly created local branch and not pushed to remote.
+      // For these two scenarios, just return origin as default.
+      return 'origin';
+    } else if (status !== 0) {
+      throw new Error(`Can't get remote for branch ${branch}`);
+    }
+    return stdout.trim();
+  }
+
   public getGitVersion(): [number, number, number] | undefined {
     let result: [number, number, number] | undefined;
 
diff --git a/apps/sparo/bin/sparo b/apps/sparo/bin/sparo
old mode 100644
new mode 100755
diff --git a/apps/sparo/bin/sparo-ci b/apps/sparo/bin/sparo-ci
old mode 100644
new mode 100755
diff --git a/common/changes/sparo/fix-cr_fix_2024-02-22-07-24.json b/common/changes/sparo/fix-cr_fix_2024-02-22-07-24.json
new file mode 100644
index 0000000..7c8276b
--- /dev/null
+++ b/common/changes/sparo/fix-cr_fix_2024-02-22-07-24.json
@@ -0,0 +1,10 @@
+{
+  "changes": [
+    {
+      "packageName": "sparo",
+      "comment": "add remote and branch arguments for sparo fetch & cr fix",
+      "type": "none"
+    }
+  ],
+  "packageName": "sparo"
+}
\ No newline at end of file
diff --git a/common/reviews/api/sparo-lib.api.md b/common/reviews/api/sparo-lib.api.md
index bfb2e15..4a7102b 100644
--- a/common/reviews/api/sparo-lib.api.md
+++ b/common/reviews/api/sparo-lib.api.md
@@ -23,6 +23,8 @@ export class GitService {
     executeGitCommandAndCaptureOutput({ args, workingDirectory }: IExecuteGitCommandParams): string;
     getBasenameFromUrl(url: string): string;
     // (undocumented)
+    getBranchRemote(branch: string): string;
+    // (undocumented)
     getGitConfig(k: string, option?: {
         dryRun?: boolean;
         global?: boolean;