git-directory-helper.ts 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111
  1. import * as assert from 'assert'
  2. import * as core from '@actions/core'
  3. import * as fs from 'fs'
  4. import * as fsHelper from './fs-helper'
  5. import * as io from '@actions/io'
  6. import * as path from 'path'
  7. import {IGitCommandManager} from './git-command-manager'
  8. import {IGitSourceSettings} from './git-source-settings'
  9. export async function prepareExistingDirectory(
  10. git: IGitCommandManager | undefined,
  11. repositoryPath: string,
  12. preferredRemoteUrl: string,
  13. allowedRemoteUrls: string[],
  14. clean: boolean
  15. ): Promise<void> {
  16. assert.ok(repositoryPath, 'Expected repositoryPath to be defined')
  17. assert.ok(preferredRemoteUrl, 'Expected preferredRemoteUrl to be defined')
  18. assert.ok(allowedRemoteUrls, 'Expected allowedRemoteUrls to be defined')
  19. assert.ok(
  20. allowedRemoteUrls.length,
  21. 'Expected allowedRemoteUrls to have at least one value'
  22. )
  23. // Indicates whether to delete the directory contents
  24. let remove = false
  25. // The remote URL
  26. let remoteUrl: string
  27. // Check whether using git or REST API
  28. if (!git) {
  29. remove = true
  30. }
  31. // Fetch URL does not match
  32. else if (
  33. !fsHelper.directoryExistsSync(path.join(repositoryPath, '.git')) ||
  34. allowedRemoteUrls.indexOf((remoteUrl = await git.tryGetRemoteUrl())) < 0
  35. ) {
  36. remove = true
  37. } else {
  38. // Delete any index.lock and shallow.lock left by a previously canceled run or crashed git process
  39. const lockPaths = [
  40. path.join(repositoryPath, '.git', 'index.lock'),
  41. path.join(repositoryPath, '.git', 'shallow.lock')
  42. ]
  43. for (const lockPath of lockPaths) {
  44. try {
  45. await io.rmRF(lockPath)
  46. } catch (error) {
  47. core.debug(`Unable to delete '${lockPath}'. ${error.message}`)
  48. }
  49. }
  50. try {
  51. // Checkout detached HEAD
  52. if (!(await git.isDetached())) {
  53. await git.checkoutDetach()
  54. }
  55. // Remove all refs/heads/*
  56. let branches = await git.branchList(false)
  57. for (const branch of branches) {
  58. await git.branchDelete(false, branch)
  59. }
  60. // Remove all refs/remotes/origin/* to avoid conflicts
  61. branches = await git.branchList(true)
  62. for (const branch of branches) {
  63. await git.branchDelete(true, branch)
  64. }
  65. // Clean
  66. if (clean) {
  67. if (!(await git.tryClean())) {
  68. core.debug(
  69. `The clean command failed. This might be caused by: 1) path too long, 2) permission issue, or 3) file in use. For futher investigation, manually run 'git clean -ffdx' on the directory '${repositoryPath}'.`
  70. )
  71. remove = true
  72. } else if (!(await git.tryReset())) {
  73. remove = true
  74. }
  75. if (remove) {
  76. core.warning(
  77. `Unable to clean or reset the repository. The repository will be recreated instead.`
  78. )
  79. }
  80. }
  81. // Update to the preferred remote URL
  82. if (remoteUrl !== preferredRemoteUrl) {
  83. await git.setRemoteUrl(preferredRemoteUrl)
  84. }
  85. } catch (error) {
  86. core.warning(
  87. `Unable to prepare the existing repository. The repository will be recreated instead.`
  88. )
  89. remove = true
  90. }
  91. }
  92. if (remove) {
  93. // Delete the contents of the directory. Don't delete the directory itself
  94. // since it might be the current working directory.
  95. core.info(`Deleting the contents of '${repositoryPath}'`)
  96. for (const file of await fs.promises.readdir(repositoryPath)) {
  97. await io.rmRF(path.join(repositoryPath, file))
  98. }
  99. }
  100. }