| 274 | } |
| 275 | |
| 276 | async function checkUpdates() { |
| 277 | const spinner = p.spinner() |
| 278 | spinner.start('Fetching remote changes...') |
| 279 | |
| 280 | try { |
| 281 | exec('git submodule foreach git fetch') |
| 282 | spinner.stop('Fetched remote changes') |
| 283 | } |
| 284 | catch (e) { |
| 285 | spinner.stop(`Failed to fetch: ${e}`) |
| 286 | return |
| 287 | } |
| 288 | |
| 289 | const updates: { name: string, type: string, behind: number }[] = [] |
| 290 | |
| 291 | // Check sources |
| 292 | for (const name of Object.keys(submodules)) { |
| 293 | const path = join(root, 'sources', name) |
| 294 | if (!existsSync(path)) |
| 295 | continue |
| 296 | |
| 297 | const behind = execSafe('git rev-list HEAD..@{u} --count', path) |
| 298 | const count = behind ? Number.parseInt(behind) : 0 |
| 299 | if (count > 0) { |
| 300 | updates.push({ name, type: 'source', behind: count }) |
| 301 | } |
| 302 | } |
| 303 | |
| 304 | // Check vendors |
| 305 | for (const [name, config] of Object.entries(vendors)) { |
| 306 | const vendorConfig = config as VendorConfig |
| 307 | const path = join(root, 'vendor', name) |
| 308 | if (!existsSync(path)) |
| 309 | continue |
| 310 | |
| 311 | const behind = execSafe('git rev-list HEAD..@{u} --count', path) |
| 312 | const count = behind ? Number.parseInt(behind) : 0 |
| 313 | if (count > 0) { |
| 314 | const skillNames = Object.values(vendorConfig.skills).join(', ') |
| 315 | updates.push({ name: `${name} (${skillNames})`, type: 'vendor', behind: count }) |
| 316 | } |
| 317 | } |
| 318 | |
| 319 | if (updates.length === 0) { |
| 320 | p.log.success('All submodules are up to date') |
| 321 | } |
| 322 | else { |
| 323 | p.log.info('Updates available:') |
| 324 | for (const update of updates) { |
| 325 | p.log.message(` ${update.name} (${update.type}): ${update.behind} commits behind`) |
| 326 | } |
| 327 | } |
| 328 | } |
| 329 | |
| 330 | function getExpectedSkillNames(): Set<string> { |
| 331 | const expected = new Set<string>() |