77import type { Request , Response } from 'express' ;
88import type { SettingsService } from '../../../services/settings-service.js' ;
99import type { UpdateCheckResult } from '@automaker/types' ;
10- import crypto from 'crypto' ;
1110import {
1211 execAsync ,
1312 execEnv ,
@@ -17,6 +16,7 @@ import {
1716 isGitRepo ,
1817 isGitAvailable ,
1918 isValidGitUrl ,
19+ withTempGitRemote ,
2020 getErrorMessage ,
2121 logError ,
2222} from '../common.js' ;
@@ -62,65 +62,56 @@ export function createCheckHandler(settingsService: SettingsService) {
6262 const localVersion = await getCurrentCommit ( installPath ) ;
6363 const localVersionShort = await getShortCommit ( installPath ) ;
6464
65- // Use a random remote name to avoid conflicts with concurrent checks
66- const tempRemoteName = `automaker-update-check-${ crypto . randomBytes ( 8 ) . toString ( 'hex' ) } ` ;
67-
6865 try {
69- // Add temporary remote
70- await execAsync ( `git remote add ${ tempRemoteName } "${ sourceUrl } "` , {
71- cwd : installPath ,
72- env : execEnv ,
73- } ) ;
74-
75- // Fetch from the temporary remote
76- await execAsync ( `git fetch ${ tempRemoteName } main` , {
77- cwd : installPath ,
78- env : execEnv ,
79- } ) ;
80-
81- // Get remote version
82- const { stdout : remoteVersionOutput } = await execAsync (
83- `git rev-parse ${ tempRemoteName } /main` ,
84- { cwd : installPath , env : execEnv }
85- ) ;
86- const remoteVersion = remoteVersionOutput . trim ( ) ;
87-
88- // Get short remote version
89- const { stdout : remoteVersionShortOutput } = await execAsync (
90- `git rev-parse --short ${ tempRemoteName } /main` ,
91- { cwd : installPath , env : execEnv }
92- ) ;
93- const remoteVersionShort = remoteVersionShortOutput . trim ( ) ;
66+ const result = await withTempGitRemote ( installPath , sourceUrl , async ( tempRemoteName ) => {
67+ // Fetch from the temporary remote
68+ await execAsync ( `git fetch ${ tempRemoteName } main` , {
69+ cwd : installPath ,
70+ env : execEnv ,
71+ } ) ;
9472
95- // Check if remote is ahead of local (update available)
96- // git merge-base --is-ancestor <commit1> <commit2> returns 0 if commit1 is ancestor of commit2
97- let updateAvailable = false ;
98- if ( localVersion !== remoteVersion ) {
99- try {
100- // Check if local is already an ancestor of remote (remote is ahead)
101- await execAsync ( `git merge-base --is-ancestor ${ localVersion } ${ remoteVersion } ` , {
102- cwd : installPath ,
103- env : execEnv ,
104- } ) ;
105- // If we get here (exit code 0), local is ancestor of remote, so update is available
106- updateAvailable = true ;
107- } catch {
108- // Exit code 1 means local is NOT an ancestor of remote
109- // This means either local is ahead, or branches have diverged
110- // In either case, we don't show "update available"
111- updateAvailable = false ;
73+ // Get remote version
74+ const { stdout : remoteVersionOutput } = await execAsync (
75+ `git rev-parse ${ tempRemoteName } /main` ,
76+ { cwd : installPath , env : execEnv }
77+ ) ;
78+ const remoteVersion = remoteVersionOutput . trim ( ) ;
79+
80+ // Get short remote version
81+ const { stdout : remoteVersionShortOutput } = await execAsync (
82+ `git rev-parse --short ${ tempRemoteName } /main` ,
83+ { cwd : installPath , env : execEnv }
84+ ) ;
85+ const remoteVersionShort = remoteVersionShortOutput . trim ( ) ;
86+
87+ // Check if remote is ahead of local (update available)
88+ let updateAvailable = false ;
89+ if ( localVersion !== remoteVersion ) {
90+ try {
91+ // Check if local is already an ancestor of remote (remote is ahead)
92+ await execAsync ( `git merge-base --is-ancestor ${ localVersion } ${ remoteVersion } ` , {
93+ cwd : installPath ,
94+ env : execEnv ,
95+ } ) ;
96+ // If we get here (exit code 0), local is ancestor of remote, so update is available
97+ updateAvailable = true ;
98+ } catch {
99+ // Exit code 1 means local is NOT an ancestor of remote
100+ // This means either local is ahead, or branches have diverged
101+ updateAvailable = false ;
102+ }
112103 }
113- }
114104
115- const result : UpdateCheckResult = {
116- updateAvailable,
117- localVersion,
118- localVersionShort,
119- remoteVersion,
120- remoteVersionShort,
121- sourceUrl,
122- installPath,
123- } ;
105+ return {
106+ updateAvailable,
107+ localVersion,
108+ localVersionShort,
109+ remoteVersion,
110+ remoteVersionShort,
111+ sourceUrl,
112+ installPath,
113+ } satisfies UpdateCheckResult ;
114+ } ) ;
124115
125116 res . json ( {
126117 success : true ,
@@ -143,16 +134,6 @@ export function createCheckHandler(settingsService: SettingsService) {
143134 error : `Could not fetch from upstream: ${ errorMsg } ` ,
144135 } satisfies UpdateCheckResult ,
145136 } ) ;
146- } finally {
147- // Always clean up temp remote
148- try {
149- await execAsync ( `git remote remove ${ tempRemoteName } ` , {
150- cwd : installPath ,
151- env : execEnv ,
152- } ) ;
153- } catch {
154- // Ignore cleanup errors
155- }
156137 }
157138 } catch ( error ) {
158139 logError ( error , 'Update check failed' ) ;
0 commit comments