mirror of
				https://github.com/actions/checkout.git
				synced 2025-10-31 01:58:36 +08:00 
			
		
		
		
	Merge branch 'actions:main' into jwi-pathdocu
This commit is contained in:
		
						commit
						f80349a6ad
					
				|  | @ -1,6 +1,6 @@ | ||||||
| { | { | ||||||
|   "plugins": ["jest", "@typescript-eslint"], |   "plugins": ["jest", "@typescript-eslint"], | ||||||
|   "extends": ["plugin:github/es6"], |   "extends": ["plugin:github/recommended"], | ||||||
|   "parser": "@typescript-eslint/parser", |   "parser": "@typescript-eslint/parser", | ||||||
|   "parserOptions": { |   "parserOptions": { | ||||||
|     "ecmaVersion": 9, |     "ecmaVersion": 9, | ||||||
|  | @ -16,23 +16,19 @@ | ||||||
|     "@typescript-eslint/no-require-imports": "error", |     "@typescript-eslint/no-require-imports": "error", | ||||||
|     "@typescript-eslint/array-type": "error", |     "@typescript-eslint/array-type": "error", | ||||||
|     "@typescript-eslint/await-thenable": "error", |     "@typescript-eslint/await-thenable": "error", | ||||||
|     "@typescript-eslint/ban-ts-ignore": "error", |  | ||||||
|     "camelcase": "off", |     "camelcase": "off", | ||||||
|     "@typescript-eslint/camelcase": "error", |  | ||||||
|     "@typescript-eslint/class-name-casing": "error", |  | ||||||
|     "@typescript-eslint/explicit-function-return-type": ["error", {"allowExpressions": true}], |     "@typescript-eslint/explicit-function-return-type": ["error", {"allowExpressions": true}], | ||||||
|     "@typescript-eslint/func-call-spacing": ["error", "never"], |     "@typescript-eslint/func-call-spacing": ["error", "never"], | ||||||
|     "@typescript-eslint/generic-type-naming": ["error", "^[A-Z][A-Za-z]*$"], |  | ||||||
|     "@typescript-eslint/no-array-constructor": "error", |     "@typescript-eslint/no-array-constructor": "error", | ||||||
|     "@typescript-eslint/no-empty-interface": "error", |     "@typescript-eslint/no-empty-interface": "error", | ||||||
|     "@typescript-eslint/no-explicit-any": "error", |     "@typescript-eslint/no-explicit-any": "error", | ||||||
|     "@typescript-eslint/no-extraneous-class": "error", |     "@typescript-eslint/no-extraneous-class": "error", | ||||||
|  |     "@typescript-eslint/no-floating-promises": "error", | ||||||
|     "@typescript-eslint/no-for-in-array": "error", |     "@typescript-eslint/no-for-in-array": "error", | ||||||
|     "@typescript-eslint/no-inferrable-types": "error", |     "@typescript-eslint/no-inferrable-types": "error", | ||||||
|     "@typescript-eslint/no-misused-new": "error", |     "@typescript-eslint/no-misused-new": "error", | ||||||
|     "@typescript-eslint/no-namespace": "error", |     "@typescript-eslint/no-namespace": "error", | ||||||
|     "@typescript-eslint/no-non-null-assertion": "warn", |     "@typescript-eslint/no-non-null-assertion": "warn", | ||||||
|     "@typescript-eslint/no-object-literal-type-assertion": "error", |  | ||||||
|     "@typescript-eslint/no-unnecessary-qualifier": "error", |     "@typescript-eslint/no-unnecessary-qualifier": "error", | ||||||
|     "@typescript-eslint/no-unnecessary-type-assertion": "error", |     "@typescript-eslint/no-unnecessary-type-assertion": "error", | ||||||
|     "@typescript-eslint/no-useless-constructor": "error", |     "@typescript-eslint/no-useless-constructor": "error", | ||||||
|  | @ -40,7 +36,6 @@ | ||||||
|     "@typescript-eslint/prefer-for-of": "warn", |     "@typescript-eslint/prefer-for-of": "warn", | ||||||
|     "@typescript-eslint/prefer-function-type": "warn", |     "@typescript-eslint/prefer-function-type": "warn", | ||||||
|     "@typescript-eslint/prefer-includes": "error", |     "@typescript-eslint/prefer-includes": "error", | ||||||
|     "@typescript-eslint/prefer-interface": "error", |  | ||||||
|     "@typescript-eslint/prefer-string-starts-ends-with": "error", |     "@typescript-eslint/prefer-string-starts-ends-with": "error", | ||||||
|     "@typescript-eslint/promise-function-async": "error", |     "@typescript-eslint/promise-function-async": "error", | ||||||
|     "@typescript-eslint/require-array-sort-compare": "error", |     "@typescript-eslint/require-array-sort-compare": "error", | ||||||
|  |  | ||||||
							
								
								
									
										51
									
								
								.github/workflows/check-dist.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								.github/workflows/check-dist.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,51 @@ | ||||||
|  | # `dist/index.js` is a special file in Actions. | ||||||
|  | # When you reference an action with `uses:` in a workflow, | ||||||
|  | # `index.js` is the code that will run. | ||||||
|  | # For our project, we generate this file through a build process | ||||||
|  | # from other source files. | ||||||
|  | # We need to make sure the checked-in `index.js` actually matches what we expect it to be. | ||||||
|  | name: Check dist | ||||||
|  | 
 | ||||||
|  | on: | ||||||
|  |   push: | ||||||
|  |     branches: | ||||||
|  |       - main | ||||||
|  |     paths-ignore: | ||||||
|  |       - '**.md' | ||||||
|  |   pull_request: | ||||||
|  |     paths-ignore: | ||||||
|  |       - '**.md' | ||||||
|  |   workflow_dispatch: | ||||||
|  | 
 | ||||||
|  | jobs: | ||||||
|  |   check-dist: | ||||||
|  |     runs-on: ubuntu-latest | ||||||
|  | 
 | ||||||
|  |     steps: | ||||||
|  |       - uses: actions/checkout@v3 | ||||||
|  | 
 | ||||||
|  |       - name: Set Node.js 16.x | ||||||
|  |         uses: actions/setup-node@v1 | ||||||
|  |         with: | ||||||
|  |           node-version: 16.x | ||||||
|  | 
 | ||||||
|  |       - name: Install dependencies | ||||||
|  |         run: npm ci | ||||||
|  | 
 | ||||||
|  |       - name: Rebuild the index.js file | ||||||
|  |         run: npm run build | ||||||
|  | 
 | ||||||
|  |       - name: Compare the expected and actual dist/ directories | ||||||
|  |         run: | | ||||||
|  |           if [ "$(git diff --ignore-space-at-eol dist/ | wc -l)" -gt "0" ]; then | ||||||
|  |             echo "Detected uncommitted changes after build.  See status below:" | ||||||
|  |             git diff | ||||||
|  |             exit 1 | ||||||
|  |           fi | ||||||
|  | 
 | ||||||
|  |       # If dist/ was different than expected, upload the expected version as an artifact | ||||||
|  |       - uses: actions/upload-artifact@v2 | ||||||
|  |         if: ${{ failure() && steps.diff.conclusion == 'failure' }} | ||||||
|  |         with: | ||||||
|  |           name: dist | ||||||
|  |           path: dist/ | ||||||
							
								
								
									
										58
									
								
								.github/workflows/codeql-analysis.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										58
									
								
								.github/workflows/codeql-analysis.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,58 @@ | ||||||
|  | # For most projects, this workflow file will not need changing; you simply need | ||||||
|  | # to commit it to your repository. | ||||||
|  | # | ||||||
|  | # You may wish to alter this file to override the set of languages analyzed, | ||||||
|  | # or to provide custom queries or build logic. | ||||||
|  | # | ||||||
|  | # ******** NOTE ******** | ||||||
|  | # We have attempted to detect the languages in your repository. Please check | ||||||
|  | # the `language` matrix defined below to confirm you have the correct set of | ||||||
|  | # supported CodeQL languages. | ||||||
|  | # | ||||||
|  | name: "CodeQL" | ||||||
|  | 
 | ||||||
|  | on: | ||||||
|  |   push: | ||||||
|  |     branches: [ main ] | ||||||
|  |   pull_request: | ||||||
|  |     # The branches below must be a subset of the branches above | ||||||
|  |     branches: [ main ] | ||||||
|  |   schedule: | ||||||
|  |     - cron: '28 9 * * 0' | ||||||
|  | 
 | ||||||
|  | jobs: | ||||||
|  |   analyze: | ||||||
|  |     name: Analyze | ||||||
|  |     runs-on: ubuntu-latest | ||||||
|  |     permissions: | ||||||
|  |       actions: read | ||||||
|  |       contents: read | ||||||
|  |       security-events: write | ||||||
|  | 
 | ||||||
|  |     strategy: | ||||||
|  |       fail-fast: false | ||||||
|  |       matrix: | ||||||
|  |         language: [ 'javascript' ] | ||||||
|  |         # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ] | ||||||
|  |         # Learn more: | ||||||
|  |         # https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed | ||||||
|  | 
 | ||||||
|  |     steps: | ||||||
|  |     - name: Checkout repository | ||||||
|  |       uses: actions/checkout@v3 | ||||||
|  | 
 | ||||||
|  |     - name: Initialize CodeQL | ||||||
|  |       uses: github/codeql-action/init@v1 | ||||||
|  |       with: | ||||||
|  |         languages: ${{ matrix.language }} | ||||||
|  |         # If you wish to specify custom queries, you can do so here or in a config file. | ||||||
|  |         # By default, queries listed here will override any specified in a config file. | ||||||
|  |         # Prefix the list here with "+" to use these queries and those in the config file. | ||||||
|  |         # queries: ./path/to/local/query, your-org/your-repo/queries@main | ||||||
|  | 
 | ||||||
|  |     - run: npm ci | ||||||
|  |     - run: npm run build | ||||||
|  |     - run: rm -rf dist # We want code scanning to analyze lib instead (individual .js files) | ||||||
|  | 
 | ||||||
|  |     - name: Perform CodeQL Analysis | ||||||
|  |       uses: github/codeql-action/analyze@v1 | ||||||
							
								
								
									
										10
									
								
								.github/workflows/licensed.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										10
									
								
								.github/workflows/licensed.yml
									
									
									
									
										vendored
									
									
								
							|  | @ -9,12 +9,6 @@ jobs: | ||||||
|     runs-on: ubuntu-latest |     runs-on: ubuntu-latest | ||||||
|     name: Check licenses |     name: Check licenses | ||||||
|     steps: |     steps: | ||||||
|       - uses: actions/checkout@v2 |       - uses: actions/checkout@v3 | ||||||
|       - run: npm ci |       - run: npm ci | ||||||
|       - name: Install licensed |       - run: npm run licensed-check | ||||||
|         run: | |  | ||||||
|           cd $RUNNER_TEMP |  | ||||||
|           curl -Lfs -o licensed.tar.gz https://github.com/github/licensed/releases/download/2.12.2/licensed-2.12.2-linux-x64.tar.gz |  | ||||||
|           sudo tar -xzf licensed.tar.gz |  | ||||||
|           sudo mv licensed /usr/local/bin/licensed |  | ||||||
|       - run: licensed status |  | ||||||
							
								
								
									
										48
									
								
								.github/workflows/test.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										48
									
								
								.github/workflows/test.yml
									
									
									
									
										vendored
									
									
								
							|  | @ -13,8 +13,8 @@ jobs: | ||||||
|     steps: |     steps: | ||||||
|       - uses: actions/setup-node@v1 |       - uses: actions/setup-node@v1 | ||||||
|         with: |         with: | ||||||
|           node-version: 12.x |           node-version: 16.x | ||||||
|       - uses: actions/checkout@v2 |       - uses: actions/checkout@v3 | ||||||
|       - run: npm ci |       - run: npm ci | ||||||
|       - run: npm run build |       - run: npm run build | ||||||
|       - run: npm run format-check |       - run: npm run format-check | ||||||
|  | @ -34,7 +34,7 @@ jobs: | ||||||
|     steps: |     steps: | ||||||
|       # Clone this repo |       # Clone this repo | ||||||
|       - name: Checkout |       - name: Checkout | ||||||
|         uses: actions/checkout@v2 |         uses: actions/checkout@v3 | ||||||
| 
 | 
 | ||||||
|       # Basic checkout |       # Basic checkout | ||||||
|       - name: Checkout basic |       - name: Checkout basic | ||||||
|  | @ -162,7 +162,7 @@ jobs: | ||||||
|     steps: |     steps: | ||||||
|       # Clone this repo |       # Clone this repo | ||||||
|       - name: Checkout |       - name: Checkout | ||||||
|         uses: actions/checkout@v2 |         uses: actions/checkout@v3 | ||||||
| 
 | 
 | ||||||
|       # Basic checkout using git |       # Basic checkout using git | ||||||
|       - name: Checkout basic |       - name: Checkout basic | ||||||
|  | @ -194,7 +194,7 @@ jobs: | ||||||
|     steps: |     steps: | ||||||
|       # Clone this repo |       # Clone this repo | ||||||
|       - name: Checkout |       - name: Checkout | ||||||
|         uses: actions/checkout@v2 |         uses: actions/checkout@v3 | ||||||
| 
 | 
 | ||||||
|       # Basic checkout using git |       # Basic checkout using git | ||||||
|       - name: Checkout basic |       - name: Checkout basic | ||||||
|  | @ -217,3 +217,41 @@ jobs: | ||||||
|           path: basic |           path: basic | ||||||
|       - name: Verify basic |       - name: Verify basic | ||||||
|         run: __test__/verify-basic.sh --archive |         run: __test__/verify-basic.sh --archive | ||||||
|  |      | ||||||
|  |   test-git-container: | ||||||
|  |     runs-on: ubuntu-latest | ||||||
|  |     container: bitnami/git:latest | ||||||
|  |     steps: | ||||||
|  |       # Clone this repo | ||||||
|  |       - name: Checkout | ||||||
|  |         uses: actions/checkout@v3 | ||||||
|  |         with: | ||||||
|  |           path: v3 | ||||||
|  | 
 | ||||||
|  |       # Basic checkout using git | ||||||
|  |       - name: Checkout basic | ||||||
|  |         uses: ./v3 | ||||||
|  |         with: | ||||||
|  |           ref: test-data/v2/basic | ||||||
|  |       - name: Verify basic | ||||||
|  |         run: | | ||||||
|  |           if [ ! -f "./basic-file.txt" ]; then | ||||||
|  |               echo "Expected basic file does not exist" | ||||||
|  |               exit 1 | ||||||
|  |           fi | ||||||
|  | 
 | ||||||
|  |           # Verify .git folder | ||||||
|  |           if [ ! -d "./.git" ]; then | ||||||
|  |             echo "Expected ./.git folder to exist" | ||||||
|  |             exit 1 | ||||||
|  |           fi | ||||||
|  | 
 | ||||||
|  |           # Verify auth token | ||||||
|  |           git config --global --add safe.directory "*" | ||||||
|  |           git fetch --no-tags --depth=1 origin +refs/heads/main:refs/remotes/origin/main | ||||||
|  | 
 | ||||||
|  |       # needed to make checkout post cleanup succeed | ||||||
|  |       - name: Fix Checkout v3 | ||||||
|  |         uses: actions/checkout@v3 | ||||||
|  |         with: | ||||||
|  |           path: v3 | ||||||
							
								
								
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							|  | @ -1,3 +1,4 @@ | ||||||
| __test__/_temp | __test__/_temp | ||||||
|  | _temp/ | ||||||
| lib/ | lib/ | ||||||
| node_modules/ | node_modules/ | ||||||
							
								
								
									
										
											BIN
										
									
								
								.licenses/npm/@actions/core.dep.yml
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										
											BIN
										
									
								
								.licenses/npm/@actions/core.dep.yml
									
									
									
										generated
									
									
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								.licenses/npm/call-bind.dep.yml
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								.licenses/npm/call-bind.dep.yml
									
									
									
										generated
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								.licenses/npm/function-bind.dep.yml
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								.licenses/npm/function-bind.dep.yml
									
									
									
										generated
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								.licenses/npm/get-intrinsic.dep.yml
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								.licenses/npm/get-intrinsic.dep.yml
									
									
									
										generated
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								.licenses/npm/has-symbols.dep.yml
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								.licenses/npm/has-symbols.dep.yml
									
									
									
										generated
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								.licenses/npm/has.dep.yml
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								.licenses/npm/has.dep.yml
									
									
									
										generated
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								.licenses/npm/node-fetch.dep.yml
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										
											BIN
										
									
								
								.licenses/npm/node-fetch.dep.yml
									
									
									
										generated
									
									
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								.licenses/npm/object-inspect.dep.yml
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								.licenses/npm/object-inspect.dep.yml
									
									
									
										generated
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								.licenses/npm/qs.dep.yml
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								.licenses/npm/qs.dep.yml
									
									
									
										generated
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								.licenses/npm/side-channel.dep.yml
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								.licenses/npm/side-channel.dep.yml
									
									
									
										generated
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								.licenses/npm/tr46.dep.yml
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								.licenses/npm/tr46.dep.yml
									
									
									
										generated
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								.licenses/npm/typed-rest-client.dep.yml
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										
											BIN
										
									
								
								.licenses/npm/typed-rest-client.dep.yml
									
									
									
										generated
									
									
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								.licenses/npm/underscore.dep.yml
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										
											BIN
										
									
								
								.licenses/npm/underscore.dep.yml
									
									
									
										generated
									
									
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								.licenses/npm/webidl-conversions.dep.yml
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								.licenses/npm/webidl-conversions.dep.yml
									
									
									
										generated
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										12
									
								
								CHANGELOG.md
									
									
									
									
									
								
							
							
						
						
									
										12
									
								
								CHANGELOG.md
									
									
									
									
									
								
							|  | @ -1,10 +1,20 @@ | ||||||
| # Changelog | # Changelog | ||||||
| 
 | 
 | ||||||
|  | ## v3.0.2 | ||||||
|  | - [Add input `set-safe-directory`](https://github.com/actions/checkout/pull/770) | ||||||
|  | 
 | ||||||
|  | ## v3.0.1 | ||||||
|  | - [Fixed an issue where checkout failed to run in container jobs due to the new git setting `safe.directory`](https://github.com/actions/checkout/pull/762) | ||||||
|  | - [Bumped various npm package versions](https://github.com/actions/checkout/pull/744) | ||||||
|  | 
 | ||||||
|  | ## v3.0.0 | ||||||
|  | 
 | ||||||
|  | - [Update to node 16](https://github.com/actions/checkout/pull/689) | ||||||
|  | 
 | ||||||
| ## v2.3.1 | ## v2.3.1 | ||||||
| 
 | 
 | ||||||
| - [Fix default branch resolution for .wiki and when using SSH](https://github.com/actions/checkout/pull/284) | - [Fix default branch resolution for .wiki and when using SSH](https://github.com/actions/checkout/pull/284) | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
| ## v2.3.0 | ## v2.3.0 | ||||||
| 
 | 
 | ||||||
| - [Fallback to the default branch](https://github.com/actions/checkout/pull/278) | - [Fallback to the default branch](https://github.com/actions/checkout/pull/278) | ||||||
|  |  | ||||||
							
								
								
									
										1
									
								
								CODEOWNERS
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								CODEOWNERS
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1 @@ | ||||||
|  | * @actions/actions-runtime | ||||||
							
								
								
									
										52
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										52
									
								
								README.md
									
									
									
									
									
								
							|  | @ -2,7 +2,7 @@ | ||||||
|   <a href="https://github.com/actions/checkout"><img alt="GitHub Actions status" src="https://github.com/actions/checkout/workflows/test-local/badge.svg"></a> |   <a href="https://github.com/actions/checkout"><img alt="GitHub Actions status" src="https://github.com/actions/checkout/workflows/test-local/badge.svg"></a> | ||||||
| </p> | </p> | ||||||
| 
 | 
 | ||||||
| # Checkout V2 | # Checkout V3 | ||||||
| 
 | 
 | ||||||
| This action checks-out your repository under `$GITHUB_WORKSPACE`, so your workflow can access it. | This action checks-out your repository under `$GITHUB_WORKSPACE`, so your workflow can access it. | ||||||
| 
 | 
 | ||||||
|  | @ -14,27 +14,14 @@ When Git 2.18 or higher is not in your PATH, falls back to the REST API to downl | ||||||
| 
 | 
 | ||||||
| # What's new | # What's new | ||||||
| 
 | 
 | ||||||
| - Improved performance | - Updated to the node16 runtime by default | ||||||
|   - Fetches only a single commit by default |   - This requires a minimum [Actions Runner](https://github.com/actions/runner/releases/tag/v2.285.0) version of v2.285.0 to run, which is by default available in GHES 3.4 or later. | ||||||
| - Script authenticated git commands |  | ||||||
|   - Auth token persisted in the local git config |  | ||||||
| - Supports SSH |  | ||||||
| - Creates a local branch |  | ||||||
|   - No longer detached HEAD when checking out a branch |  | ||||||
| - Improved layout |  | ||||||
|   - The input `path` is always relative to $GITHUB_WORKSPACE |  | ||||||
|   - Aligns better with container actions, where $GITHUB_WORKSPACE gets mapped in |  | ||||||
| - Fallback to REST API download |  | ||||||
|   - When Git 2.18 or higher is not in the PATH, the REST API will be used to download the files |  | ||||||
|   - When using a job container, the container's PATH is used |  | ||||||
| 
 |  | ||||||
| Refer [here](https://github.com/actions/checkout/blob/v1/README.md) for previous versions. |  | ||||||
| 
 | 
 | ||||||
| # Usage | # Usage | ||||||
| 
 | 
 | ||||||
| <!-- start usage --> | <!-- start usage --> | ||||||
| ```yaml | ```yaml | ||||||
| - uses: actions/checkout@v2 | - uses: actions/checkout@v3 | ||||||
|   with: |   with: | ||||||
|     # Repository name with owner. For example, actions/checkout |     # Repository name with owner. For example, actions/checkout | ||||||
|     # Default: ${{ github.repository }} |     # Default: ${{ github.repository }} | ||||||
|  | @ -105,6 +92,11 @@ Refer [here](https://github.com/actions/checkout/blob/v1/README.md) for previous | ||||||
|     # |     # | ||||||
|     # Default: false |     # Default: false | ||||||
|     submodules: '' |     submodules: '' | ||||||
|  | 
 | ||||||
|  |     # Add repository path as safe.directory for Git global config by running `git | ||||||
|  |     # config --global --add safe.directory <path>` | ||||||
|  |     # Default: true | ||||||
|  |     set-safe-directory: '' | ||||||
| ``` | ``` | ||||||
| <!-- end usage --> | <!-- end usage --> | ||||||
| 
 | 
 | ||||||
|  | @ -123,7 +115,7 @@ Refer [here](https://github.com/actions/checkout/blob/v1/README.md) for previous | ||||||
| ## Fetch all history for all tags and branches | ## Fetch all history for all tags and branches | ||||||
| 
 | 
 | ||||||
| ```yaml | ```yaml | ||||||
| - uses: actions/checkout@v2 | - uses: actions/checkout@v3 | ||||||
|   with: |   with: | ||||||
|     fetch-depth: 0 |     fetch-depth: 0 | ||||||
| ``` | ``` | ||||||
|  | @ -131,7 +123,7 @@ Refer [here](https://github.com/actions/checkout/blob/v1/README.md) for previous | ||||||
| ## Checkout a different branch | ## Checkout a different branch | ||||||
| 
 | 
 | ||||||
| ```yaml | ```yaml | ||||||
| - uses: actions/checkout@v2 | - uses: actions/checkout@v3 | ||||||
|   with: |   with: | ||||||
|     ref: my-branch |     ref: my-branch | ||||||
| ``` | ``` | ||||||
|  | @ -139,7 +131,7 @@ Refer [here](https://github.com/actions/checkout/blob/v1/README.md) for previous | ||||||
| ## Checkout HEAD^ | ## Checkout HEAD^ | ||||||
| 
 | 
 | ||||||
| ```yaml | ```yaml | ||||||
| - uses: actions/checkout@v2 | - uses: actions/checkout@v3 | ||||||
|   with: |   with: | ||||||
|     fetch-depth: 2 |     fetch-depth: 2 | ||||||
| - run: git checkout HEAD^ | - run: git checkout HEAD^ | ||||||
|  | @ -149,12 +141,12 @@ Refer [here](https://github.com/actions/checkout/blob/v1/README.md) for previous | ||||||
| 
 | 
 | ||||||
| ```yaml | ```yaml | ||||||
| - name: Checkout | - name: Checkout | ||||||
|   uses: actions/checkout@v2 |   uses: actions/checkout@v3 | ||||||
|   with: |   with: | ||||||
|     path: main |     path: main | ||||||
| 
 | 
 | ||||||
| - name: Checkout tools repo | - name: Checkout tools repo | ||||||
|   uses: actions/checkout@v2 |   uses: actions/checkout@v3 | ||||||
|   with: |   with: | ||||||
|     repository: my-org/my-tools |     repository: my-org/my-tools | ||||||
|     path: my-tools |     path: my-tools | ||||||
|  | @ -176,10 +168,10 @@ steps: | ||||||
| 
 | 
 | ||||||
| ```yaml | ```yaml | ||||||
| - name: Checkout | - name: Checkout | ||||||
|   uses: actions/checkout@v2 |   uses: actions/checkout@v3 | ||||||
| 
 | 
 | ||||||
| - name: Checkout tools repo | - name: Checkout tools repo | ||||||
|   uses: actions/checkout@v2 |   uses: actions/checkout@v3 | ||||||
|   with: |   with: | ||||||
|     repository: my-org/my-tools |     repository: my-org/my-tools | ||||||
|     path: my-tools |     path: my-tools | ||||||
|  | @ -189,15 +181,15 @@ steps: | ||||||
| 
 | 
 | ||||||
| ```yaml | ```yaml | ||||||
| - name: Checkout | - name: Checkout | ||||||
|   uses: actions/checkout@v2 |   uses: actions/checkout@v3 | ||||||
|   with: |   with: | ||||||
|     path: main |     path: main | ||||||
| 
 | 
 | ||||||
| - name: Checkout private tools | - name: Checkout private tools | ||||||
|   uses: actions/checkout@v2 |   uses: actions/checkout@v3 | ||||||
|   with: |   with: | ||||||
|     repository: my-org/my-private-tools |     repository: my-org/my-private-tools | ||||||
|     token: ${{ secrets.GitHub_PAT }} # `GitHub_PAT` is a secret that contains your PAT |     token: ${{ secrets.GH_PAT }} # `GH_PAT` is a secret that contains your PAT | ||||||
|     path: my-tools |     path: my-tools | ||||||
| ``` | ``` | ||||||
| 
 | 
 | ||||||
|  | @ -207,7 +199,7 @@ steps: | ||||||
| ## Checkout pull request HEAD commit instead of merge commit | ## Checkout pull request HEAD commit instead of merge commit | ||||||
| 
 | 
 | ||||||
| ```yaml | ```yaml | ||||||
| - uses: actions/checkout@v2 | - uses: actions/checkout@v3 | ||||||
|   with: |   with: | ||||||
|     ref: ${{ github.event.pull_request.head.sha }} |     ref: ${{ github.event.pull_request.head.sha }} | ||||||
| ``` | ``` | ||||||
|  | @ -223,7 +215,7 @@ jobs: | ||||||
|   build: |   build: | ||||||
|     runs-on: ubuntu-latest |     runs-on: ubuntu-latest | ||||||
|     steps: |     steps: | ||||||
|       - uses: actions/checkout@v2 |       - uses: actions/checkout@v3 | ||||||
| ``` | ``` | ||||||
| 
 | 
 | ||||||
| ## Push a commit using the built-in token | ## Push a commit using the built-in token | ||||||
|  | @ -234,7 +226,7 @@ jobs: | ||||||
|   build: |   build: | ||||||
|     runs-on: ubuntu-latest |     runs-on: ubuntu-latest | ||||||
|     steps: |     steps: | ||||||
|       - uses: actions/checkout@v2 |       - uses: actions/checkout@v3 | ||||||
|       - run: | |       - run: | | ||||||
|           date > generated.txt |           date > generated.txt | ||||||
|           git config user.name github-actions |           git config user.name github-actions | ||||||
|  |  | ||||||
|  | @ -417,7 +417,7 @@ describe('git-auth-helper tests', () => { | ||||||
|           `Did not expect file to exist: '${globalGitConfigPath}'` |           `Did not expect file to exist: '${globalGitConfigPath}'` | ||||||
|         ) |         ) | ||||||
|       } catch (err) { |       } catch (err) { | ||||||
|         if (err.code !== 'ENOENT') { |         if ((err as any)?.code !== 'ENOENT') { | ||||||
|           throw err |           throw err | ||||||
|         } |         } | ||||||
|       } |       } | ||||||
|  | @ -518,12 +518,17 @@ describe('git-auth-helper tests', () => { | ||||||
|       await authHelper.configureSubmoduleAuth() |       await authHelper.configureSubmoduleAuth() | ||||||
| 
 | 
 | ||||||
|       // Assert
 |       // Assert
 | ||||||
|       expect(mockSubmoduleForeach).toHaveBeenCalledTimes(3) |       expect(mockSubmoduleForeach).toHaveBeenCalledTimes(4) | ||||||
|       expect(mockSubmoduleForeach.mock.calls[0][0]).toMatch( |       expect(mockSubmoduleForeach.mock.calls[0][0]).toMatch( | ||||||
|         /unset-all.*insteadOf/ |         /unset-all.*insteadOf/ | ||||||
|       ) |       ) | ||||||
|       expect(mockSubmoduleForeach.mock.calls[1][0]).toMatch(/http.*extraheader/) |       expect(mockSubmoduleForeach.mock.calls[1][0]).toMatch(/http.*extraheader/) | ||||||
|       expect(mockSubmoduleForeach.mock.calls[2][0]).toMatch(/url.*insteadOf/) |       expect(mockSubmoduleForeach.mock.calls[2][0]).toMatch( | ||||||
|  |         /url.*insteadOf.*git@github.com:/ | ||||||
|  |       ) | ||||||
|  |       expect(mockSubmoduleForeach.mock.calls[3][0]).toMatch( | ||||||
|  |         /url.*insteadOf.*org-123456@github.com:/ | ||||||
|  |       ) | ||||||
|     } |     } | ||||||
|   ) |   ) | ||||||
| 
 | 
 | ||||||
|  | @ -601,7 +606,7 @@ describe('git-auth-helper tests', () => { | ||||||
|       await fs.promises.stat(actualKeyPath) |       await fs.promises.stat(actualKeyPath) | ||||||
|       throw new Error('SSH key should have been deleted') |       throw new Error('SSH key should have been deleted') | ||||||
|     } catch (err) { |     } catch (err) { | ||||||
|       if (err.code !== 'ENOENT') { |       if ((err as any)?.code !== 'ENOENT') { | ||||||
|         throw err |         throw err | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
|  | @ -611,7 +616,7 @@ describe('git-auth-helper tests', () => { | ||||||
|       await fs.promises.stat(actualKnownHostsPath) |       await fs.promises.stat(actualKnownHostsPath) | ||||||
|       throw new Error('SSH known hosts should have been deleted') |       throw new Error('SSH known hosts should have been deleted') | ||||||
|     } catch (err) { |     } catch (err) { | ||||||
|       if (err.code !== 'ENOENT') { |       if ((err as any)?.code !== 'ENOENT') { | ||||||
|         throw err |         throw err | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
|  | @ -638,10 +643,11 @@ describe('git-auth-helper tests', () => { | ||||||
|     expect(gitConfigContent.indexOf('http.')).toBeLessThan(0) |     expect(gitConfigContent.indexOf('http.')).toBeLessThan(0) | ||||||
|   }) |   }) | ||||||
| 
 | 
 | ||||||
|   const removeGlobalAuth_removesOverride = 'removeGlobalAuth removes override' |   const removeGlobalConfig_removesOverride = | ||||||
|   it(removeGlobalAuth_removesOverride, async () => { |     'removeGlobalConfig removes override' | ||||||
|  |   it(removeGlobalConfig_removesOverride, async () => { | ||||||
|     // Arrange
 |     // Arrange
 | ||||||
|     await setup(removeGlobalAuth_removesOverride) |     await setup(removeGlobalConfig_removesOverride) | ||||||
|     const authHelper = gitAuthHelper.createAuthHelper(git, settings) |     const authHelper = gitAuthHelper.createAuthHelper(git, settings) | ||||||
|     await authHelper.configureAuth() |     await authHelper.configureAuth() | ||||||
|     await authHelper.configureGlobalAuth() |     await authHelper.configureGlobalAuth() | ||||||
|  | @ -650,7 +656,7 @@ describe('git-auth-helper tests', () => { | ||||||
|     await fs.promises.stat(path.join(git.env['HOME'], '.gitconfig')) |     await fs.promises.stat(path.join(git.env['HOME'], '.gitconfig')) | ||||||
| 
 | 
 | ||||||
|     // Act
 |     // Act
 | ||||||
|     await authHelper.removeGlobalAuth() |     await authHelper.removeGlobalConfig() | ||||||
| 
 | 
 | ||||||
|     // Assert
 |     // Assert
 | ||||||
|     expect(git.env['HOME']).toBeUndefined() |     expect(git.env['HOME']).toBeUndefined() | ||||||
|  | @ -658,7 +664,7 @@ describe('git-auth-helper tests', () => { | ||||||
|       await fs.promises.stat(homeOverride) |       await fs.promises.stat(homeOverride) | ||||||
|       throw new Error(`Should have been deleted '${homeOverride}'`) |       throw new Error(`Should have been deleted '${homeOverride}'`) | ||||||
|     } catch (err) { |     } catch (err) { | ||||||
|       if (err.code !== 'ENOENT') { |       if ((err as any)?.code !== 'ENOENT') { | ||||||
|         throw err |         throw err | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
|  | @ -770,7 +776,9 @@ async function setup(testName: string): Promise<void> { | ||||||
|     repositoryPath: '', |     repositoryPath: '', | ||||||
|     sshKey: sshPath ? 'some ssh private key' : '', |     sshKey: sshPath ? 'some ssh private key' : '', | ||||||
|     sshKnownHosts: '', |     sshKnownHosts: '', | ||||||
|     sshStrict: true |     sshStrict: true, | ||||||
|  |     workflowOrganizationId: 123456, | ||||||
|  |     setSafeDirectory: true | ||||||
|   } |   } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -1,9 +1,9 @@ | ||||||
| import * as assert from 'assert' |  | ||||||
| import * as core from '@actions/core' | import * as core from '@actions/core' | ||||||
| import * as fsHelper from '../lib/fs-helper' | import * as fsHelper from '../lib/fs-helper' | ||||||
| import * as github from '@actions/github' | import * as github from '@actions/github' | ||||||
| import * as inputHelper from '../lib/input-helper' | import * as inputHelper from '../lib/input-helper' | ||||||
| import * as path from 'path' | import * as path from 'path' | ||||||
|  | import * as workflowContextHelper from '../lib/workflow-context-helper' | ||||||
| import {IGitSourceSettings} from '../lib/git-source-settings' | import {IGitSourceSettings} from '../lib/git-source-settings' | ||||||
| 
 | 
 | ||||||
| const originalGitHubWorkspace = process.env['GITHUB_WORKSPACE'] | const originalGitHubWorkspace = process.env['GITHUB_WORKSPACE'] | ||||||
|  | @ -43,6 +43,11 @@ describe('input-helper tests', () => { | ||||||
|       .spyOn(fsHelper, 'directoryExistsSync') |       .spyOn(fsHelper, 'directoryExistsSync') | ||||||
|       .mockImplementation((path: string) => path == gitHubWorkspace) |       .mockImplementation((path: string) => path == gitHubWorkspace) | ||||||
| 
 | 
 | ||||||
|  |     // Mock ./workflowContextHelper getOrganizationId()
 | ||||||
|  |     jest | ||||||
|  |       .spyOn(workflowContextHelper, 'getOrganizationId') | ||||||
|  |       .mockImplementation(() => Promise.resolve(123456)) | ||||||
|  | 
 | ||||||
|     // GitHub workspace
 |     // GitHub workspace
 | ||||||
|     process.env['GITHUB_WORKSPACE'] = gitHubWorkspace |     process.env['GITHUB_WORKSPACE'] = gitHubWorkspace | ||||||
|   }) |   }) | ||||||
|  | @ -67,8 +72,8 @@ describe('input-helper tests', () => { | ||||||
|     jest.restoreAllMocks() |     jest.restoreAllMocks() | ||||||
|   }) |   }) | ||||||
| 
 | 
 | ||||||
|   it('sets defaults', () => { |   it('sets defaults', async () => { | ||||||
|     const settings: IGitSourceSettings = inputHelper.getInputs() |     const settings: IGitSourceSettings = await inputHelper.getInputs() | ||||||
|     expect(settings).toBeTruthy() |     expect(settings).toBeTruthy() | ||||||
|     expect(settings.authToken).toBeFalsy() |     expect(settings.authToken).toBeFalsy() | ||||||
|     expect(settings.clean).toBe(true) |     expect(settings.clean).toBe(true) | ||||||
|  | @ -80,13 +85,14 @@ describe('input-helper tests', () => { | ||||||
|     expect(settings.repositoryName).toBe('some-repo') |     expect(settings.repositoryName).toBe('some-repo') | ||||||
|     expect(settings.repositoryOwner).toBe('some-owner') |     expect(settings.repositoryOwner).toBe('some-owner') | ||||||
|     expect(settings.repositoryPath).toBe(gitHubWorkspace) |     expect(settings.repositoryPath).toBe(gitHubWorkspace) | ||||||
|  |     expect(settings.setSafeDirectory).toBe(true) | ||||||
|   }) |   }) | ||||||
| 
 | 
 | ||||||
|   it('qualifies ref', () => { |   it('qualifies ref', async () => { | ||||||
|     let originalRef = github.context.ref |     let originalRef = github.context.ref | ||||||
|     try { |     try { | ||||||
|       github.context.ref = 'some-unqualified-ref' |       github.context.ref = 'some-unqualified-ref' | ||||||
|       const settings: IGitSourceSettings = inputHelper.getInputs() |       const settings: IGitSourceSettings = await inputHelper.getInputs() | ||||||
|       expect(settings).toBeTruthy() |       expect(settings).toBeTruthy() | ||||||
|       expect(settings.commit).toBe('1234567890123456789012345678901234567890') |       expect(settings.commit).toBe('1234567890123456789012345678901234567890') | ||||||
|       expect(settings.ref).toBe('refs/heads/some-unqualified-ref') |       expect(settings.ref).toBe('refs/heads/some-unqualified-ref') | ||||||
|  | @ -95,32 +101,42 @@ describe('input-helper tests', () => { | ||||||
|     } |     } | ||||||
|   }) |   }) | ||||||
| 
 | 
 | ||||||
|   it('requires qualified repo', () => { |   it('requires qualified repo', async () => { | ||||||
|     inputs.repository = 'some-unqualified-repo' |     inputs.repository = 'some-unqualified-repo' | ||||||
|     assert.throws(() => { |     try { | ||||||
|       inputHelper.getInputs() |       await inputHelper.getInputs() | ||||||
|     }, /Invalid repository 'some-unqualified-repo'/) |       throw 'should not reach here' | ||||||
|  |     } catch (err) { | ||||||
|  |       expect(`(${(err as any).message}`).toMatch( | ||||||
|  |         "Invalid repository 'some-unqualified-repo'" | ||||||
|  |       ) | ||||||
|  |     } | ||||||
|   }) |   }) | ||||||
| 
 | 
 | ||||||
|   it('roots path', () => { |   it('roots path', async () => { | ||||||
|     inputs.path = 'some-directory/some-subdirectory' |     inputs.path = 'some-directory/some-subdirectory' | ||||||
|     const settings: IGitSourceSettings = inputHelper.getInputs() |     const settings: IGitSourceSettings = await inputHelper.getInputs() | ||||||
|     expect(settings.repositoryPath).toBe( |     expect(settings.repositoryPath).toBe( | ||||||
|       path.join(gitHubWorkspace, 'some-directory', 'some-subdirectory') |       path.join(gitHubWorkspace, 'some-directory', 'some-subdirectory') | ||||||
|     ) |     ) | ||||||
|   }) |   }) | ||||||
| 
 | 
 | ||||||
|   it('sets ref to empty when explicit sha', () => { |   it('sets ref to empty when explicit sha', async () => { | ||||||
|     inputs.ref = '1111111111222222222233333333334444444444' |     inputs.ref = '1111111111222222222233333333334444444444' | ||||||
|     const settings: IGitSourceSettings = inputHelper.getInputs() |     const settings: IGitSourceSettings = await inputHelper.getInputs() | ||||||
|     expect(settings.ref).toBeFalsy() |     expect(settings.ref).toBeFalsy() | ||||||
|     expect(settings.commit).toBe('1111111111222222222233333333334444444444') |     expect(settings.commit).toBe('1111111111222222222233333333334444444444') | ||||||
|   }) |   }) | ||||||
| 
 | 
 | ||||||
|   it('sets sha to empty when explicit ref', () => { |   it('sets sha to empty when explicit ref', async () => { | ||||||
|     inputs.ref = 'refs/heads/some-other-ref' |     inputs.ref = 'refs/heads/some-other-ref' | ||||||
|     const settings: IGitSourceSettings = inputHelper.getInputs() |     const settings: IGitSourceSettings = await inputHelper.getInputs() | ||||||
|     expect(settings.ref).toBe('refs/heads/some-other-ref') |     expect(settings.ref).toBe('refs/heads/some-other-ref') | ||||||
|     expect(settings.commit).toBeFalsy() |     expect(settings.commit).toBeFalsy() | ||||||
|   }) |   }) | ||||||
|  | 
 | ||||||
|  |   it('sets workflow organization ID', async () => { | ||||||
|  |     const settings: IGitSourceSettings = await inputHelper.getInputs() | ||||||
|  |     expect(settings.workflowOrganizationId).toBe(123456) | ||||||
|  |   }) | ||||||
| }) | }) | ||||||
|  |  | ||||||
|  | @ -16,7 +16,7 @@ describe('ref-helper tests', () => { | ||||||
|       await refHelper.getCheckoutInfo(git, 'refs/heads/my/branch', commit) |       await refHelper.getCheckoutInfo(git, 'refs/heads/my/branch', commit) | ||||||
|       throw new Error('Should not reach here') |       throw new Error('Should not reach here') | ||||||
|     } catch (err) { |     } catch (err) { | ||||||
|       expect(err.message).toBe('Arg git cannot be empty') |       expect((err as any)?.message).toBe('Arg git cannot be empty') | ||||||
|     } |     } | ||||||
|   }) |   }) | ||||||
| 
 | 
 | ||||||
|  | @ -25,7 +25,9 @@ describe('ref-helper tests', () => { | ||||||
|       await refHelper.getCheckoutInfo(git, '', '') |       await refHelper.getCheckoutInfo(git, '', '') | ||||||
|       throw new Error('Should not reach here') |       throw new Error('Should not reach here') | ||||||
|     } catch (err) { |     } catch (err) { | ||||||
|       expect(err.message).toBe('Args ref and commit cannot both be empty') |       expect((err as any)?.message).toBe( | ||||||
|  |         'Args ref and commit cannot both be empty' | ||||||
|  |       ) | ||||||
|     } |     } | ||||||
|   }) |   }) | ||||||
| 
 | 
 | ||||||
|  | @ -102,7 +104,7 @@ describe('ref-helper tests', () => { | ||||||
|       await refHelper.getCheckoutInfo(git, 'my-ref', '') |       await refHelper.getCheckoutInfo(git, 'my-ref', '') | ||||||
|       throw new Error('Should not reach here') |       throw new Error('Should not reach here') | ||||||
|     } catch (err) { |     } catch (err) { | ||||||
|       expect(err.message).toBe( |       expect((err as any)?.message).toBe( | ||||||
|         "A branch or tag with the name 'my-ref' could not be found" |         "A branch or tag with the name 'my-ref' could not be found" | ||||||
|       ) |       ) | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  | @ -74,7 +74,7 @@ describe('retry-helper tests', () => { | ||||||
|         throw new Error(`some error ${++attempts}`) |         throw new Error(`some error ${++attempts}`) | ||||||
|       }) |       }) | ||||||
|     } catch (err) { |     } catch (err) { | ||||||
|       error = err |       error = err as Error | ||||||
|     } |     } | ||||||
|     expect(error.message).toBe('some error 3') |     expect(error.message).toBe('some error 3') | ||||||
|     expect(attempts).toBe(3) |     expect(attempts).toBe(3) | ||||||
|  |  | ||||||
|  | @ -68,7 +68,10 @@ inputs: | ||||||
|       When the `ssh-key` input is not provided, SSH URLs beginning with `git@github.com:` are |       When the `ssh-key` input is not provided, SSH URLs beginning with `git@github.com:` are | ||||||
|       converted to HTTPS. |       converted to HTTPS. | ||||||
|     default: false |     default: false | ||||||
|  |   set-safe-directory: | ||||||
|  |     description: Add repository path as safe.directory for Git global config by running `git config --global --add safe.directory <path>` | ||||||
|  |     default: true | ||||||
| runs: | runs: | ||||||
|   using: node12 |   using: node16 | ||||||
|   main: dist/index.js |   main: dist/index.js | ||||||
|   post: dist/index.js |   post: dist/index.js | ||||||
|  |  | ||||||
							
								
								
									
										5617
									
								
								dist/index.js
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										5617
									
								
								dist/index.js
									
									
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										18953
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										18953
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										24
									
								
								package.json
									
									
									
									
									
								
							
							
						
						
									
										24
									
								
								package.json
									
									
									
									
									
								
							|  | @ -8,7 +8,9 @@ | ||||||
|     "format": "prettier --write '**/*.ts'", |     "format": "prettier --write '**/*.ts'", | ||||||
|     "format-check": "prettier --check '**/*.ts'", |     "format-check": "prettier --check '**/*.ts'", | ||||||
|     "lint": "eslint src/**/*.ts", |     "lint": "eslint src/**/*.ts", | ||||||
|     "test": "jest" |     "test": "jest", | ||||||
|  |     "licensed-check": "src/misc/licensed-check.sh", | ||||||
|  |     "licensed-generate": "src/misc/licensed-generate.sh" | ||||||
|   }, |   }, | ||||||
|   "repository": { |   "repository": { | ||||||
|     "type": "git", |     "type": "git", | ||||||
|  | @ -26,7 +28,7 @@ | ||||||
|   }, |   }, | ||||||
|   "homepage": "https://github.com/actions/checkout#readme", |   "homepage": "https://github.com/actions/checkout#readme", | ||||||
|   "dependencies": { |   "dependencies": { | ||||||
|     "@actions/core": "^1.1.3", |     "@actions/core": "^1.2.6", | ||||||
|     "@actions/exec": "^1.0.1", |     "@actions/exec": "^1.0.1", | ||||||
|     "@actions/github": "^2.2.0", |     "@actions/github": "^2.2.0", | ||||||
|     "@actions/io": "^1.0.1", |     "@actions/io": "^1.0.1", | ||||||
|  | @ -34,19 +36,19 @@ | ||||||
|     "uuid": "^3.3.3" |     "uuid": "^3.3.3" | ||||||
|   }, |   }, | ||||||
|   "devDependencies": { |   "devDependencies": { | ||||||
|     "@types/jest": "^24.0.23", |     "@types/jest": "^27.0.2", | ||||||
|     "@types/node": "^12.7.12", |     "@types/node": "^12.7.12", | ||||||
|     "@types/uuid": "^3.4.6", |     "@types/uuid": "^3.4.6", | ||||||
|     "@typescript-eslint/parser": "^2.8.0", |     "@typescript-eslint/parser": "^5.1.0", | ||||||
|     "@zeit/ncc": "^0.20.5", |     "@zeit/ncc": "^0.20.5", | ||||||
|     "eslint": "^5.16.0", |     "eslint": "^7.32.0", | ||||||
|     "eslint-plugin-github": "^2.0.0", |     "eslint-plugin-github": "^4.3.2", | ||||||
|     "eslint-plugin-jest": "^22.21.0", |     "eslint-plugin-jest": "^25.2.2", | ||||||
|     "jest": "^24.9.0", |     "jest": "^27.3.0", | ||||||
|     "jest-circus": "^24.9.0", |     "jest-circus": "^27.3.0", | ||||||
|     "js-yaml": "^3.13.1", |     "js-yaml": "^3.13.1", | ||||||
|     "prettier": "^1.19.1", |     "prettier": "^1.19.1", | ||||||
|     "ts-jest": "^24.2.0", |     "ts-jest": "^27.0.7", | ||||||
|     "typescript": "^3.6.4" |     "typescript": "^4.4.4" | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -9,7 +9,7 @@ export function directoryExistsSync(path: string, required?: boolean): boolean { | ||||||
|   try { |   try { | ||||||
|     stats = fs.statSync(path) |     stats = fs.statSync(path) | ||||||
|   } catch (error) { |   } catch (error) { | ||||||
|     if (error.code === 'ENOENT') { |     if ((error as any)?.code === 'ENOENT') { | ||||||
|       if (!required) { |       if (!required) { | ||||||
|         return false |         return false | ||||||
|       } |       } | ||||||
|  | @ -18,7 +18,8 @@ export function directoryExistsSync(path: string, required?: boolean): boolean { | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     throw new Error( |     throw new Error( | ||||||
|       `Encountered an error when checking whether path '${path}' exists: ${error.message}` |       `Encountered an error when checking whether path '${path}' exists: ${(error as any) | ||||||
|  |         ?.message ?? error}` | ||||||
|     ) |     ) | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  | @ -39,12 +40,13 @@ export function existsSync(path: string): boolean { | ||||||
|   try { |   try { | ||||||
|     fs.statSync(path) |     fs.statSync(path) | ||||||
|   } catch (error) { |   } catch (error) { | ||||||
|     if (error.code === 'ENOENT') { |     if ((error as any)?.code === 'ENOENT') { | ||||||
|       return false |       return false | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     throw new Error( |     throw new Error( | ||||||
|       `Encountered an error when checking whether path '${path}' exists: ${error.message}` |       `Encountered an error when checking whether path '${path}' exists: ${(error as any) | ||||||
|  |         ?.message ?? error}` | ||||||
|     ) |     ) | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  | @ -60,12 +62,13 @@ export function fileExistsSync(path: string): boolean { | ||||||
|   try { |   try { | ||||||
|     stats = fs.statSync(path) |     stats = fs.statSync(path) | ||||||
|   } catch (error) { |   } catch (error) { | ||||||
|     if (error.code === 'ENOENT') { |     if ((error as any)?.code === 'ENOENT') { | ||||||
|       return false |       return false | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     throw new Error( |     throw new Error( | ||||||
|       `Encountered an error when checking whether path '${path}' exists: ${error.message}` |       `Encountered an error when checking whether path '${path}' exists: ${(error as any) | ||||||
|  |         ?.message ?? error}` | ||||||
|     ) |     ) | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -19,8 +19,9 @@ export interface IGitAuthHelper { | ||||||
|   configureAuth(): Promise<void> |   configureAuth(): Promise<void> | ||||||
|   configureGlobalAuth(): Promise<void> |   configureGlobalAuth(): Promise<void> | ||||||
|   configureSubmoduleAuth(): Promise<void> |   configureSubmoduleAuth(): Promise<void> | ||||||
|  |   configureTempGlobalConfig(): Promise<string> | ||||||
|   removeAuth(): Promise<void> |   removeAuth(): Promise<void> | ||||||
|   removeGlobalAuth(): Promise<void> |   removeGlobalConfig(): Promise<void> | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| export function createAuthHelper( | export function createAuthHelper( | ||||||
|  | @ -37,7 +38,7 @@ class GitAuthHelper { | ||||||
|   private readonly tokenConfigValue: string |   private readonly tokenConfigValue: string | ||||||
|   private readonly tokenPlaceholderConfigValue: string |   private readonly tokenPlaceholderConfigValue: string | ||||||
|   private readonly insteadOfKey: string |   private readonly insteadOfKey: string | ||||||
|   private readonly insteadOfValue: string |   private readonly insteadOfValues: string[] = [] | ||||||
|   private sshCommand = '' |   private sshCommand = '' | ||||||
|   private sshKeyPath = '' |   private sshKeyPath = '' | ||||||
|   private sshKnownHostsPath = '' |   private sshKnownHostsPath = '' | ||||||
|  | @ -45,7 +46,7 @@ class GitAuthHelper { | ||||||
| 
 | 
 | ||||||
|   constructor( |   constructor( | ||||||
|     gitCommandManager: IGitCommandManager, |     gitCommandManager: IGitCommandManager, | ||||||
|     gitSourceSettings?: IGitSourceSettings |     gitSourceSettings: IGitSourceSettings | undefined | ||||||
|   ) { |   ) { | ||||||
|     this.git = gitCommandManager |     this.git = gitCommandManager | ||||||
|     this.settings = gitSourceSettings || (({} as unknown) as IGitSourceSettings) |     this.settings = gitSourceSettings || (({} as unknown) as IGitSourceSettings) | ||||||
|  | @ -63,7 +64,12 @@ class GitAuthHelper { | ||||||
| 
 | 
 | ||||||
|     // Instead of SSH URL
 |     // Instead of SSH URL
 | ||||||
|     this.insteadOfKey = `url.${serverUrl.origin}/.insteadOf` // "origin" is SCHEME://HOSTNAME[:PORT]
 |     this.insteadOfKey = `url.${serverUrl.origin}/.insteadOf` // "origin" is SCHEME://HOSTNAME[:PORT]
 | ||||||
|     this.insteadOfValue = `git@${serverUrl.hostname}:` |     this.insteadOfValues.push(`git@${serverUrl.hostname}:`) | ||||||
|  |     if (this.settings.workflowOrganizationId) { | ||||||
|  |       this.insteadOfValues.push( | ||||||
|  |         `org-${this.settings.workflowOrganizationId}@github.com:` | ||||||
|  |       ) | ||||||
|  |     } | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   async configureAuth(): Promise<void> { |   async configureAuth(): Promise<void> { | ||||||
|  | @ -75,7 +81,11 @@ class GitAuthHelper { | ||||||
|     await this.configureToken() |     await this.configureToken() | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   async configureGlobalAuth(): Promise<void> { |   async configureTempGlobalConfig(): Promise<string> { | ||||||
|  |     // Already setup global config
 | ||||||
|  |     if (this.temporaryHomePath?.length > 0) { | ||||||
|  |       return path.join(this.temporaryHomePath, '.gitconfig') | ||||||
|  |     } | ||||||
|     // Create a temp home directory
 |     // Create a temp home directory
 | ||||||
|     const runnerTemp = process.env['RUNNER_TEMP'] || '' |     const runnerTemp = process.env['RUNNER_TEMP'] || '' | ||||||
|     assert.ok(runnerTemp, 'RUNNER_TEMP is not defined') |     assert.ok(runnerTemp, 'RUNNER_TEMP is not defined') | ||||||
|  | @ -94,7 +104,7 @@ class GitAuthHelper { | ||||||
|       await fs.promises.stat(gitConfigPath) |       await fs.promises.stat(gitConfigPath) | ||||||
|       configExists = true |       configExists = true | ||||||
|     } catch (err) { |     } catch (err) { | ||||||
|       if (err.code !== 'ENOENT') { |       if ((err as any)?.code !== 'ENOENT') { | ||||||
|         throw err |         throw err | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
|  | @ -105,20 +115,28 @@ class GitAuthHelper { | ||||||
|       await fs.promises.writeFile(newGitConfigPath, '') |       await fs.promises.writeFile(newGitConfigPath, '') | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     try { |     // Override HOME
 | ||||||
|       // Override HOME
 |     core.info( | ||||||
|       core.info( |       `Temporarily overriding HOME='${this.temporaryHomePath}' before making global git config changes` | ||||||
|         `Temporarily overriding HOME='${this.temporaryHomePath}' before making global git config changes` |     ) | ||||||
|       ) |     this.git.setEnvironmentVariable('HOME', this.temporaryHomePath) | ||||||
|       this.git.setEnvironmentVariable('HOME', this.temporaryHomePath) |  | ||||||
| 
 | 
 | ||||||
|  |     return newGitConfigPath | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   async configureGlobalAuth(): Promise<void> { | ||||||
|  |     // 'configureTempGlobalConfig' noops if already set, just returns the path
 | ||||||
|  |     const newGitConfigPath = await this.configureTempGlobalConfig() | ||||||
|  |     try { | ||||||
|       // Configure the token
 |       // Configure the token
 | ||||||
|       await this.configureToken(newGitConfigPath, true) |       await this.configureToken(newGitConfigPath, true) | ||||||
| 
 | 
 | ||||||
|       // Configure HTTPS instead of SSH
 |       // Configure HTTPS instead of SSH
 | ||||||
|       await this.git.tryConfigUnset(this.insteadOfKey, true) |       await this.git.tryConfigUnset(this.insteadOfKey, true) | ||||||
|       if (!this.settings.sshKey) { |       if (!this.settings.sshKey) { | ||||||
|         await this.git.config(this.insteadOfKey, this.insteadOfValue, true) |         for (const insteadOfValue of this.insteadOfValues) { | ||||||
|  |           await this.git.config(this.insteadOfKey, insteadOfValue, true, true) | ||||||
|  |         } | ||||||
|       } |       } | ||||||
|     } catch (err) { |     } catch (err) { | ||||||
|       // Unset in case somehow written to the real global config
 |       // Unset in case somehow written to the real global config
 | ||||||
|  | @ -148,7 +166,7 @@ class GitAuthHelper { | ||||||
|         output.match(/(?<=(^|\n)file:)[^\t]+(?=\tremote\.origin\.url)/g) || [] |         output.match(/(?<=(^|\n)file:)[^\t]+(?=\tremote\.origin\.url)/g) || [] | ||||||
|       for (const configPath of configPaths) { |       for (const configPath of configPaths) { | ||||||
|         core.debug(`Replacing token placeholder in '${configPath}'`) |         core.debug(`Replacing token placeholder in '${configPath}'`) | ||||||
|         this.replaceTokenPlaceholder(configPath) |         await this.replaceTokenPlaceholder(configPath) | ||||||
|       } |       } | ||||||
| 
 | 
 | ||||||
|       if (this.settings.sshKey) { |       if (this.settings.sshKey) { | ||||||
|  | @ -159,10 +177,12 @@ class GitAuthHelper { | ||||||
|         ) |         ) | ||||||
|       } else { |       } else { | ||||||
|         // Configure HTTPS instead of SSH
 |         // Configure HTTPS instead of SSH
 | ||||||
|         await this.git.submoduleForeach( |         for (const insteadOfValue of this.insteadOfValues) { | ||||||
|           `git config --local '${this.insteadOfKey}' '${this.insteadOfValue}'`, |           await this.git.submoduleForeach( | ||||||
|           this.settings.nestedSubmodules |             `git config --local --add '${this.insteadOfKey}' '${insteadOfValue}'`, | ||||||
|         ) |             this.settings.nestedSubmodules | ||||||
|  |           ) | ||||||
|  |         } | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|  | @ -172,10 +192,12 @@ class GitAuthHelper { | ||||||
|     await this.removeToken() |     await this.removeToken() | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   async removeGlobalAuth(): Promise<void> { |   async removeGlobalConfig(): Promise<void> { | ||||||
|     core.debug(`Unsetting HOME override`) |     if (this.temporaryHomePath?.length > 0) { | ||||||
|     this.git.removeEnvironmentVariable('HOME') |       core.debug(`Unsetting HOME override`) | ||||||
|     await io.rmRF(this.temporaryHomePath) |       this.git.removeEnvironmentVariable('HOME') | ||||||
|  |       await io.rmRF(this.temporaryHomePath) | ||||||
|  |     } | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   private async configureSsh(): Promise<void> { |   private async configureSsh(): Promise<void> { | ||||||
|  | @ -213,7 +235,7 @@ class GitAuthHelper { | ||||||
|         await fs.promises.readFile(userKnownHostsPath) |         await fs.promises.readFile(userKnownHostsPath) | ||||||
|       ).toString() |       ).toString() | ||||||
|     } catch (err) { |     } catch (err) { | ||||||
|       if (err.code !== 'ENOENT') { |       if ((err as any)?.code !== 'ENOENT') { | ||||||
|         throw err |         throw err | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
|  | @ -302,7 +324,7 @@ class GitAuthHelper { | ||||||
|       try { |       try { | ||||||
|         await io.rmRF(keyPath) |         await io.rmRF(keyPath) | ||||||
|       } catch (err) { |       } catch (err) { | ||||||
|         core.debug(err.message) |         core.debug(`${(err as any)?.message ?? err}`) | ||||||
|         core.warning(`Failed to remove SSH key '${keyPath}'`) |         core.warning(`Failed to remove SSH key '${keyPath}'`) | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  | @ -21,7 +21,8 @@ export interface IGitCommandManager { | ||||||
|   config( |   config( | ||||||
|     configKey: string, |     configKey: string, | ||||||
|     configValue: string, |     configValue: string, | ||||||
|     globalConfig?: boolean |     globalConfig?: boolean, | ||||||
|  |     add?: boolean | ||||||
|   ): Promise<void> |   ): Promise<void> | ||||||
|   configExists(configKey: string, globalConfig?: boolean): Promise<boolean> |   configExists(configKey: string, globalConfig?: boolean): Promise<boolean> | ||||||
|   fetch(refSpec: string[], fetchDepth?: number): Promise<void> |   fetch(refSpec: string[], fetchDepth?: number): Promise<void> | ||||||
|  | @ -140,14 +141,15 @@ class GitCommandManager { | ||||||
|   async config( |   async config( | ||||||
|     configKey: string, |     configKey: string, | ||||||
|     configValue: string, |     configValue: string, | ||||||
|     globalConfig?: boolean |     globalConfig?: boolean, | ||||||
|  |     add?: boolean | ||||||
|   ): Promise<void> { |   ): Promise<void> { | ||||||
|     await this.execGit([ |     const args: string[] = ['config', globalConfig ? '--global' : '--local'] | ||||||
|       'config', |     if (add) { | ||||||
|       globalConfig ? '--global' : '--local', |       args.push('--add') | ||||||
|       configKey, |     } | ||||||
|       configValue |     args.push(...[configKey, configValue]) | ||||||
|     ]) |     await this.execGit(args) | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   async configExists( |   async configExists( | ||||||
|  |  | ||||||
|  | @ -39,7 +39,9 @@ export async function prepareExistingDirectory( | ||||||
|       try { |       try { | ||||||
|         await io.rmRF(lockPath) |         await io.rmRF(lockPath) | ||||||
|       } catch (error) { |       } catch (error) { | ||||||
|         core.debug(`Unable to delete '${lockPath}'. ${error.message}`) |         core.debug( | ||||||
|  |           `Unable to delete '${lockPath}'. ${(error as any)?.message ?? error}` | ||||||
|  |         ) | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -36,68 +36,94 @@ export async function getSource(settings: IGitSourceSettings): Promise<void> { | ||||||
|   const git = await getGitCommandManager(settings) |   const git = await getGitCommandManager(settings) | ||||||
|   core.endGroup() |   core.endGroup() | ||||||
| 
 | 
 | ||||||
|   // Prepare existing directory, otherwise recreate
 |   let authHelper: gitAuthHelper.IGitAuthHelper | null = null | ||||||
|   if (isExisting) { |   try { | ||||||
|     await gitDirectoryHelper.prepareExistingDirectory( |     if (git) { | ||||||
|       git, |       authHelper = gitAuthHelper.createAuthHelper(git, settings) | ||||||
|       settings.repositoryPath, |       if (settings.setSafeDirectory) { | ||||||
|       repositoryUrl, |         // Setup the repository path as a safe directory, so if we pass this into a container job with a different user it doesn't fail
 | ||||||
|       settings.clean, |         // Otherwise all git commands we run in a container fail
 | ||||||
|       settings.ref |         await authHelper.configureTempGlobalConfig() | ||||||
|     ) |         core.info( | ||||||
|   } |           `Adding repository directory to the temporary git global config as a safe directory` | ||||||
|  |         ) | ||||||
| 
 | 
 | ||||||
|   if (!git) { |         await git | ||||||
|     // Downloading using REST API
 |           .config('safe.directory', settings.repositoryPath, true, true) | ||||||
|     core.info(`The repository will be downloaded using the GitHub REST API`) |           .catch(error => { | ||||||
|     core.info( |             core.info( | ||||||
|       `To create a local Git repository instead, add Git ${gitCommandManager.MinimumGitVersion} or higher to the PATH` |               `Failed to initialize safe directory with error: ${error}` | ||||||
|     ) |             ) | ||||||
|     if (settings.submodules) { |           }) | ||||||
|       throw new Error( | 
 | ||||||
|         `Input 'submodules' not supported when falling back to download using the GitHub REST API. To create a local Git repository instead, add Git ${gitCommandManager.MinimumGitVersion} or higher to the PATH.` |         stateHelper.setSafeDirectory() | ||||||
|       ) |       } | ||||||
|     } else if (settings.sshKey) { |     } | ||||||
|       throw new Error( | 
 | ||||||
|         `Input 'ssh-key' not supported when falling back to download using the GitHub REST API. To create a local Git repository instead, add Git ${gitCommandManager.MinimumGitVersion} or higher to the PATH.` |     // Prepare existing directory, otherwise recreate
 | ||||||
|  |     if (isExisting) { | ||||||
|  |       await gitDirectoryHelper.prepareExistingDirectory( | ||||||
|  |         git, | ||||||
|  |         settings.repositoryPath, | ||||||
|  |         repositoryUrl, | ||||||
|  |         settings.clean, | ||||||
|  |         settings.ref | ||||||
|       ) |       ) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     await githubApiHelper.downloadRepository( |     if (!git) { | ||||||
|       settings.authToken, |       // Downloading using REST API
 | ||||||
|       settings.repositoryOwner, |       core.info(`The repository will be downloaded using the GitHub REST API`) | ||||||
|       settings.repositoryName, |       core.info( | ||||||
|       settings.ref, |         `To create a local Git repository instead, add Git ${gitCommandManager.MinimumGitVersion} or higher to the PATH` | ||||||
|       settings.commit, |       ) | ||||||
|       settings.repositoryPath |       if (settings.submodules) { | ||||||
|     ) |         throw new Error( | ||||||
|     return |           `Input 'submodules' not supported when falling back to download using the GitHub REST API. To create a local Git repository instead, add Git ${gitCommandManager.MinimumGitVersion} or higher to the PATH.` | ||||||
|   } |         ) | ||||||
|  |       } else if (settings.sshKey) { | ||||||
|  |         throw new Error( | ||||||
|  |           `Input 'ssh-key' not supported when falling back to download using the GitHub REST API. To create a local Git repository instead, add Git ${gitCommandManager.MinimumGitVersion} or higher to the PATH.` | ||||||
|  |         ) | ||||||
|  |       } | ||||||
| 
 | 
 | ||||||
|   // Save state for POST action
 |       await githubApiHelper.downloadRepository( | ||||||
|   stateHelper.setRepositoryPath(settings.repositoryPath) |         settings.authToken, | ||||||
|  |         settings.repositoryOwner, | ||||||
|  |         settings.repositoryName, | ||||||
|  |         settings.ref, | ||||||
|  |         settings.commit, | ||||||
|  |         settings.repositoryPath | ||||||
|  |       ) | ||||||
|  |       return | ||||||
|  |     } | ||||||
| 
 | 
 | ||||||
|   // Initialize the repository
 |     // Save state for POST action
 | ||||||
|   if ( |     stateHelper.setRepositoryPath(settings.repositoryPath) | ||||||
|     !fsHelper.directoryExistsSync(path.join(settings.repositoryPath, '.git')) | 
 | ||||||
|   ) { |     // Initialize the repository
 | ||||||
|     core.startGroup('Initializing the repository') |     if ( | ||||||
|     await git.init() |       !fsHelper.directoryExistsSync(path.join(settings.repositoryPath, '.git')) | ||||||
|     await git.remoteAdd('origin', repositoryUrl) |     ) { | ||||||
|  |       core.startGroup('Initializing the repository') | ||||||
|  |       await git.init() | ||||||
|  |       await git.remoteAdd('origin', repositoryUrl) | ||||||
|  |       core.endGroup() | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     // Disable automatic garbage collection
 | ||||||
|  |     core.startGroup('Disabling automatic garbage collection') | ||||||
|  |     if (!(await git.tryDisableAutomaticGarbageCollection())) { | ||||||
|  |       core.warning( | ||||||
|  |         `Unable to turn off git automatic garbage collection. The git fetch operation may trigger garbage collection and cause a delay.` | ||||||
|  |       ) | ||||||
|  |     } | ||||||
|     core.endGroup() |     core.endGroup() | ||||||
|   } |  | ||||||
| 
 | 
 | ||||||
|   // Disable automatic garbage collection
 |     // If we didn't initialize it above, do it now
 | ||||||
|   core.startGroup('Disabling automatic garbage collection') |     if (!authHelper) { | ||||||
|   if (!(await git.tryDisableAutomaticGarbageCollection())) { |       authHelper = gitAuthHelper.createAuthHelper(git, settings) | ||||||
|     core.warning( |     } | ||||||
|       `Unable to turn off git automatic garbage collection. The git fetch operation may trigger garbage collection and cause a delay.` |  | ||||||
|     ) |  | ||||||
|   } |  | ||||||
|   core.endGroup() |  | ||||||
| 
 |  | ||||||
|   const authHelper = gitAuthHelper.createAuthHelper(git, settings) |  | ||||||
|   try { |  | ||||||
|     // Configure auth
 |     // Configure auth
 | ||||||
|     core.startGroup('Setting up auth') |     core.startGroup('Setting up auth') | ||||||
|     await authHelper.configureAuth() |     await authHelper.configureAuth() | ||||||
|  | @ -170,34 +196,26 @@ export async function getSource(settings: IGitSourceSettings): Promise<void> { | ||||||
| 
 | 
 | ||||||
|     // Submodules
 |     // Submodules
 | ||||||
|     if (settings.submodules) { |     if (settings.submodules) { | ||||||
|       try { |       // Temporarily override global config
 | ||||||
|         // Temporarily override global config
 |       core.startGroup('Setting up auth for fetching submodules') | ||||||
|         core.startGroup('Setting up auth for fetching submodules') |       await authHelper.configureGlobalAuth() | ||||||
|         await authHelper.configureGlobalAuth() |       core.endGroup() | ||||||
|         core.endGroup() |  | ||||||
| 
 | 
 | ||||||
|         // Checkout submodules
 |       // Checkout submodules
 | ||||||
|         core.startGroup('Fetching submodules') |       core.startGroup('Fetching submodules') | ||||||
|         await git.submoduleSync(settings.nestedSubmodules) |       await git.submoduleSync(settings.nestedSubmodules) | ||||||
|         await git.submoduleUpdate( |       await git.submoduleUpdate(settings.fetchDepth, settings.nestedSubmodules) | ||||||
|           settings.fetchDepth, |       await git.submoduleForeach( | ||||||
|           settings.nestedSubmodules |         'git config --local gc.auto 0', | ||||||
|         ) |         settings.nestedSubmodules | ||||||
|         await git.submoduleForeach( |       ) | ||||||
|           'git config --local gc.auto 0', |       core.endGroup() | ||||||
|           settings.nestedSubmodules |  | ||||||
|         ) |  | ||||||
|         core.endGroup() |  | ||||||
| 
 | 
 | ||||||
|         // Persist credentials
 |       // Persist credentials
 | ||||||
|         if (settings.persistCredentials) { |       if (settings.persistCredentials) { | ||||||
|           core.startGroup('Persisting credentials for submodules') |         core.startGroup('Persisting credentials for submodules') | ||||||
|           await authHelper.configureSubmoduleAuth() |         await authHelper.configureSubmoduleAuth() | ||||||
|           core.endGroup() |         core.endGroup() | ||||||
|         } |  | ||||||
|       } finally { |  | ||||||
|         // Remove temporary global config override
 |  | ||||||
|         await authHelper.removeGlobalAuth() |  | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | @ -218,10 +236,13 @@ export async function getSource(settings: IGitSourceSettings): Promise<void> { | ||||||
|     ) |     ) | ||||||
|   } finally { |   } finally { | ||||||
|     // Remove auth
 |     // Remove auth
 | ||||||
|     if (!settings.persistCredentials) { |     if (authHelper) { | ||||||
|       core.startGroup('Removing auth') |       if (!settings.persistCredentials) { | ||||||
|       await authHelper.removeAuth() |         core.startGroup('Removing auth') | ||||||
|       core.endGroup() |         await authHelper.removeAuth() | ||||||
|  |         core.endGroup() | ||||||
|  |       } | ||||||
|  |       authHelper.removeGlobalConfig() | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  | @ -244,7 +265,26 @@ export async function cleanup(repositoryPath: string): Promise<void> { | ||||||
| 
 | 
 | ||||||
|   // Remove auth
 |   // Remove auth
 | ||||||
|   const authHelper = gitAuthHelper.createAuthHelper(git) |   const authHelper = gitAuthHelper.createAuthHelper(git) | ||||||
|   await authHelper.removeAuth() |   try { | ||||||
|  |     if (stateHelper.PostSetSafeDirectory) { | ||||||
|  |       // Setup the repository path as a safe directory, so if we pass this into a container job with a different user it doesn't fail
 | ||||||
|  |       // Otherwise all git commands we run in a container fail
 | ||||||
|  |       await authHelper.configureTempGlobalConfig() | ||||||
|  |       core.info( | ||||||
|  |         `Adding repository directory to the temporary git global config as a safe directory` | ||||||
|  |       ) | ||||||
|  | 
 | ||||||
|  |       await git | ||||||
|  |         .config('safe.directory', repositoryPath, true, true) | ||||||
|  |         .catch(error => { | ||||||
|  |           core.info(`Failed to initialize safe directory with error: ${error}`) | ||||||
|  |         }) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     await authHelper.removeAuth() | ||||||
|  |   } finally { | ||||||
|  |     await authHelper.removeGlobalConfig() | ||||||
|  |   } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| async function getGitCommandManager( | async function getGitCommandManager( | ||||||
|  |  | ||||||
|  | @ -73,4 +73,14 @@ export interface IGitSourceSettings { | ||||||
|    * Indicates whether to persist the credentials on disk to enable scripting authenticated git commands |    * Indicates whether to persist the credentials on disk to enable scripting authenticated git commands | ||||||
|    */ |    */ | ||||||
|   persistCredentials: boolean |   persistCredentials: boolean | ||||||
|  | 
 | ||||||
|  |   /** | ||||||
|  |    * Organization ID for the currently running workflow (used for auth settings) | ||||||
|  |    */ | ||||||
|  |   workflowOrganizationId: number | undefined | ||||||
|  | 
 | ||||||
|  |   /** | ||||||
|  |    * Indicates whether to add repositoryPath as safe.directory in git global config | ||||||
|  |    */ | ||||||
|  |   setSafeDirectory: boolean | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -47,7 +47,7 @@ export async function downloadRepository( | ||||||
|   } else { |   } else { | ||||||
|     await toolCache.extractTar(archivePath, extractPath) |     await toolCache.extractTar(archivePath, extractPath) | ||||||
|   } |   } | ||||||
|   io.rmRF(archivePath) |   await io.rmRF(archivePath) | ||||||
| 
 | 
 | ||||||
|   // Determine the path of the repository content. The archive contains
 |   // Determine the path of the repository content. The archive contains
 | ||||||
|   // a top-level folder and the repository content is inside.
 |   // a top-level folder and the repository content is inside.
 | ||||||
|  | @ -70,7 +70,7 @@ export async function downloadRepository( | ||||||
|       await io.mv(sourcePath, targetPath) |       await io.mv(sourcePath, targetPath) | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|   io.rmRF(extractPath) |   await io.rmRF(extractPath) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
|  | @ -92,7 +92,10 @@ export async function getDefaultBranch( | ||||||
|       assert.ok(result, 'default_branch cannot be empty') |       assert.ok(result, 'default_branch cannot be empty') | ||||||
|     } catch (err) { |     } catch (err) { | ||||||
|       // Handle .wiki repo
 |       // Handle .wiki repo
 | ||||||
|       if (err['status'] === 404 && repo.toUpperCase().endsWith('.WIKI')) { |       if ( | ||||||
|  |         (err as any)?.status === 404 && | ||||||
|  |         repo.toUpperCase().endsWith('.WIKI') | ||||||
|  |       ) { | ||||||
|         result = 'master' |         result = 'master' | ||||||
|       } |       } | ||||||
|       // Otherwise error
 |       // Otherwise error
 | ||||||
|  |  | ||||||
|  | @ -2,9 +2,10 @@ import * as core from '@actions/core' | ||||||
| import * as fsHelper from './fs-helper' | import * as fsHelper from './fs-helper' | ||||||
| import * as github from '@actions/github' | import * as github from '@actions/github' | ||||||
| import * as path from 'path' | import * as path from 'path' | ||||||
|  | import * as workflowContextHelper from './workflow-context-helper' | ||||||
| import {IGitSourceSettings} from './git-source-settings' | import {IGitSourceSettings} from './git-source-settings' | ||||||
| 
 | 
 | ||||||
| export function getInputs(): IGitSourceSettings { | export async function getInputs(): Promise<IGitSourceSettings> { | ||||||
|   const result = ({} as unknown) as IGitSourceSettings |   const result = ({} as unknown) as IGitSourceSettings | ||||||
| 
 | 
 | ||||||
|   // GitHub workspace
 |   // GitHub workspace
 | ||||||
|  | @ -118,5 +119,11 @@ export function getInputs(): IGitSourceSettings { | ||||||
|   result.persistCredentials = |   result.persistCredentials = | ||||||
|     (core.getInput('persist-credentials') || 'false').toUpperCase() === 'TRUE' |     (core.getInput('persist-credentials') || 'false').toUpperCase() === 'TRUE' | ||||||
| 
 | 
 | ||||||
|  |   // Workflow organization ID
 | ||||||
|  |   result.workflowOrganizationId = await workflowContextHelper.getOrganizationId() | ||||||
|  | 
 | ||||||
|  |   // Set safe.directory in git global config.
 | ||||||
|  |   result.setSafeDirectory = | ||||||
|  |     (core.getInput('set-safe-directory') || 'true').toUpperCase() === 'TRUE' | ||||||
|   return result |   return result | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -7,7 +7,7 @@ import * as stateHelper from './state-helper' | ||||||
| 
 | 
 | ||||||
| async function run(): Promise<void> { | async function run(): Promise<void> { | ||||||
|   try { |   try { | ||||||
|     const sourceSettings = inputHelper.getInputs() |     const sourceSettings = await inputHelper.getInputs() | ||||||
| 
 | 
 | ||||||
|     try { |     try { | ||||||
|       // Register problem matcher
 |       // Register problem matcher
 | ||||||
|  | @ -24,7 +24,7 @@ async function run(): Promise<void> { | ||||||
|       coreCommand.issueCommand('remove-matcher', {owner: 'checkout-git'}, '') |       coreCommand.issueCommand('remove-matcher', {owner: 'checkout-git'}, '') | ||||||
|     } |     } | ||||||
|   } catch (error) { |   } catch (error) { | ||||||
|     core.setFailed(error.message) |     core.setFailed(`${(error as any)?.message ?? error}`) | ||||||
|   } |   } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -32,7 +32,7 @@ async function cleanup(): Promise<void> { | ||||||
|   try { |   try { | ||||||
|     await gitSourceProvider.cleanup(stateHelper.RepositoryPath) |     await gitSourceProvider.cleanup(stateHelper.RepositoryPath) | ||||||
|   } catch (error) { |   } catch (error) { | ||||||
|     core.warning(error.message) |     core.warning(`${(error as any)?.message ?? error}`) | ||||||
|   } |   } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -10,10 +10,10 @@ import * as yaml from 'js-yaml' | ||||||
| 
 | 
 | ||||||
| function updateUsage( | function updateUsage( | ||||||
|   actionReference: string, |   actionReference: string, | ||||||
|   actionYamlPath: string = 'action.yml', |   actionYamlPath = 'action.yml', | ||||||
|   readmePath: string = 'README.md', |   readmePath = 'README.md', | ||||||
|   startToken: string = '<!-- start usage -->', |   startToken = '<!-- start usage -->', | ||||||
|   endToken: string = '<!-- end usage -->' |   endToken = '<!-- end usage -->' | ||||||
| ): void { | ): void { | ||||||
|   if (!actionReference) { |   if (!actionReference) { | ||||||
|     throw new Error('Parameter actionReference must not be empty') |     throw new Error('Parameter actionReference must not be empty') | ||||||
|  | @ -120,7 +120,7 @@ function updateUsage( | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| updateUsage( | updateUsage( | ||||||
|   'actions/checkout@v2', |   'actions/checkout@v3', | ||||||
|   path.join(__dirname, '..', '..', 'action.yml'), |   path.join(__dirname, '..', '..', 'action.yml'), | ||||||
|   path.join(__dirname, '..', '..', 'README.md') |   path.join(__dirname, '..', '..', 'README.md') | ||||||
| ) | ) | ||||||
|  |  | ||||||
							
								
								
									
										8
									
								
								src/misc/licensed-check.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										8
									
								
								src/misc/licensed-check.sh
									
									
									
									
									
										Executable file
									
								
							|  | @ -0,0 +1,8 @@ | ||||||
|  | #!/bin/bash | ||||||
|  | 
 | ||||||
|  | set -e | ||||||
|  | 
 | ||||||
|  | src/misc/licensed-download.sh | ||||||
|  | 
 | ||||||
|  | echo 'Running: licensed cached' | ||||||
|  | _temp/licensed-3.6.0/licensed status | ||||||
							
								
								
									
										24
									
								
								src/misc/licensed-download.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										24
									
								
								src/misc/licensed-download.sh
									
									
									
									
									
										Executable file
									
								
							|  | @ -0,0 +1,24 @@ | ||||||
|  | #!/bin/bash | ||||||
|  | 
 | ||||||
|  | set -e | ||||||
|  | 
 | ||||||
|  | if [ ! -f _temp/licensed-3.6.0.done ]; then | ||||||
|  |   echo 'Clearing temp' | ||||||
|  |   rm -rf _temp/licensed-3.6.0 || true | ||||||
|  | 
 | ||||||
|  |   echo 'Downloading licensed' | ||||||
|  |   mkdir -p _temp/licensed-3.6.0 | ||||||
|  |   pushd _temp/licensed-3.6.0 | ||||||
|  |   if [[ "$OSTYPE" == "darwin"* ]]; then | ||||||
|  |     curl -Lfs -o licensed.tar.gz https://github.com/github/licensed/releases/download/3.6.0/licensed-3.6.0-darwin-x64.tar.gz | ||||||
|  |   else | ||||||
|  |     curl -Lfs -o licensed.tar.gz https://github.com/github/licensed/releases/download/3.6.0/licensed-3.6.0-linux-x64.tar.gz | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   echo 'Extracting licenesed' | ||||||
|  |   tar -xzf licensed.tar.gz | ||||||
|  |   popd | ||||||
|  |   touch _temp/licensed-3.6.0.done | ||||||
|  | else | ||||||
|  |   echo 'Licensed already downloaded' | ||||||
|  | fi | ||||||
							
								
								
									
										8
									
								
								src/misc/licensed-generate.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										8
									
								
								src/misc/licensed-generate.sh
									
									
									
									
									
										Executable file
									
								
							|  | @ -0,0 +1,8 @@ | ||||||
|  | #!/bin/bash | ||||||
|  | 
 | ||||||
|  | set -e | ||||||
|  | 
 | ||||||
|  | src/misc/licensed-download.sh | ||||||
|  | 
 | ||||||
|  | echo 'Running: licensed cached' | ||||||
|  | _temp/licensed-3.6.0/licensed cache | ||||||
|  | @ -253,7 +253,9 @@ export async function checkCommitInfo( | ||||||
|       await octokit.repos.get({owner: repositoryOwner, repo: repositoryName}) |       await octokit.repos.get({owner: repositoryOwner, repo: repositoryName}) | ||||||
|     } |     } | ||||||
|   } catch (err) { |   } catch (err) { | ||||||
|     core.debug(`Error when validating commit info: ${err.stack}`) |     core.debug( | ||||||
|  |       `Error when validating commit info: ${(err as any)?.stack ?? err}` | ||||||
|  |     ) | ||||||
|   } |   } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -29,7 +29,7 @@ export class RetryHelper { | ||||||
|       try { |       try { | ||||||
|         return await action() |         return await action() | ||||||
|       } catch (err) { |       } catch (err) { | ||||||
|         core.info(err.message) |         core.info((err as any)?.message) | ||||||
|       } |       } | ||||||
| 
 | 
 | ||||||
|       // Sleep
 |       // Sleep
 | ||||||
|  |  | ||||||
|  | @ -11,6 +11,12 @@ export const IsPost = !!process.env['STATE_isPost'] | ||||||
| export const RepositoryPath = | export const RepositoryPath = | ||||||
|   (process.env['STATE_repositoryPath'] as string) || '' |   (process.env['STATE_repositoryPath'] as string) || '' | ||||||
| 
 | 
 | ||||||
|  | /** | ||||||
|  |  * The set-safe-directory for the POST action. The value is set if input: 'safe-directory' is set during the MAIN action. | ||||||
|  |  */ | ||||||
|  | export const PostSetSafeDirectory = | ||||||
|  |   (process.env['STATE_setSafeDirectory'] as string) === 'true' | ||||||
|  | 
 | ||||||
| /** | /** | ||||||
|  * The SSH key path for the POST action. The value is empty during the MAIN action. |  * The SSH key path for the POST action. The value is empty during the MAIN action. | ||||||
|  */ |  */ | ||||||
|  | @ -51,6 +57,13 @@ export function setSshKnownHostsPath(sshKnownHostsPath: string) { | ||||||
|   ) |   ) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | /** | ||||||
|  |  * Save the sef-safe-directory input so the POST action can retrieve the value. | ||||||
|  |  */ | ||||||
|  | export function setSafeDirectory() { | ||||||
|  |   coreCommand.issueCommand('save-state', {name: 'setSafeDirectory'}, 'true') | ||||||
|  | } | ||||||
|  | 
 | ||||||
| // Publish a variable so that when the POST action runs, it can determine it should run the cleanup logic.
 | // Publish a variable so that when the POST action runs, it can determine it should run the cleanup logic.
 | ||||||
| // This is necessary since we don't have a separate entry point.
 | // This is necessary since we don't have a separate entry point.
 | ||||||
| if (!IsPost) { | if (!IsPost) { | ||||||
|  |  | ||||||
							
								
								
									
										30
									
								
								src/workflow-context-helper.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								src/workflow-context-helper.ts
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,30 @@ | ||||||
|  | import * as core from '@actions/core' | ||||||
|  | import * as fs from 'fs' | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Gets the organization ID of the running workflow or undefined if the value cannot be loaded from the GITHUB_EVENT_PATH | ||||||
|  |  */ | ||||||
|  | export async function getOrganizationId(): Promise<number | undefined> { | ||||||
|  |   try { | ||||||
|  |     const eventPath = process.env.GITHUB_EVENT_PATH | ||||||
|  |     if (!eventPath) { | ||||||
|  |       core.debug(`GITHUB_EVENT_PATH is not defined`) | ||||||
|  |       return | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     const content = await fs.promises.readFile(eventPath, {encoding: 'utf8'}) | ||||||
|  |     const event = JSON.parse(content) | ||||||
|  |     const id = event?.repository?.owner?.id | ||||||
|  |     if (typeof id !== 'number') { | ||||||
|  |       core.debug('Repository owner ID not found within GITHUB event info') | ||||||
|  |       return | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return id as number | ||||||
|  |   } catch (err) { | ||||||
|  |     core.debug( | ||||||
|  |       `Unable to load organization ID from GITHUB_EVENT_PATH: ${(err as any) | ||||||
|  |         .message || err}` | ||||||
|  |     ) | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | @ -10,7 +10,8 @@ | ||||||
|     "declaration": true, |     "declaration": true, | ||||||
|     "strict": true, |     "strict": true, | ||||||
|     "noImplicitAny": false, |     "noImplicitAny": false, | ||||||
|     "esModuleInterop": true |     "esModuleInterop": true, | ||||||
|  |     "skipLibCheck": true | ||||||
|   }, |   }, | ||||||
|   "exclude": ["__test__", "lib", "node_modules"] |   "exclude": ["__test__", "lib", "node_modules"] | ||||||
| } | } | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue
	
	Block a user
	 Johnny Willemsen
						Johnny Willemsen