mirror of
				https://github.com/actions/checkout.git
				synced 2025-11-04 15:58:09 +08:00 
			
		
		
		
	Compare commits
	
		
			1 Commits
		
	
	
		
			v2.0.0
			...
			Update-des
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					3204e0bf8c | 
@@ -1,3 +0,0 @@
 | 
				
			|||||||
dist/
 | 
					 | 
				
			||||||
lib/
 | 
					 | 
				
			||||||
node_modules/
 | 
					 | 
				
			||||||
@@ -1,58 +0,0 @@
 | 
				
			|||||||
{
 | 
					 | 
				
			||||||
  "plugins": ["jest", "@typescript-eslint"],
 | 
					 | 
				
			||||||
  "extends": ["plugin:github/es6"],
 | 
					 | 
				
			||||||
  "parser": "@typescript-eslint/parser",
 | 
					 | 
				
			||||||
  "parserOptions": {
 | 
					 | 
				
			||||||
    "ecmaVersion": 9,
 | 
					 | 
				
			||||||
    "sourceType": "module",
 | 
					 | 
				
			||||||
    "project": "./tsconfig.json"
 | 
					 | 
				
			||||||
  },
 | 
					 | 
				
			||||||
  "rules": {
 | 
					 | 
				
			||||||
    "eslint-comments/no-use": "off",
 | 
					 | 
				
			||||||
    "import/no-namespace": "off",
 | 
					 | 
				
			||||||
    "no-unused-vars": "off",
 | 
					 | 
				
			||||||
    "@typescript-eslint/no-unused-vars": "error",
 | 
					 | 
				
			||||||
    "@typescript-eslint/explicit-member-accessibility": ["error", {"accessibility": "no-public"}],
 | 
					 | 
				
			||||||
    "@typescript-eslint/no-require-imports": "error",
 | 
					 | 
				
			||||||
    "@typescript-eslint/array-type": "error",
 | 
					 | 
				
			||||||
    "@typescript-eslint/await-thenable": "error",
 | 
					 | 
				
			||||||
    "@typescript-eslint/ban-ts-ignore": "error",
 | 
					 | 
				
			||||||
    "camelcase": "off",
 | 
					 | 
				
			||||||
    "@typescript-eslint/camelcase": "error",
 | 
					 | 
				
			||||||
    "@typescript-eslint/class-name-casing": "error",
 | 
					 | 
				
			||||||
    "@typescript-eslint/explicit-function-return-type": ["error", {"allowExpressions": true}],
 | 
					 | 
				
			||||||
    "@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-empty-interface": "error",
 | 
					 | 
				
			||||||
    "@typescript-eslint/no-explicit-any": "error",
 | 
					 | 
				
			||||||
    "@typescript-eslint/no-extraneous-class": "error",
 | 
					 | 
				
			||||||
    "@typescript-eslint/no-for-in-array": "error",
 | 
					 | 
				
			||||||
    "@typescript-eslint/no-inferrable-types": "error",
 | 
					 | 
				
			||||||
    "@typescript-eslint/no-misused-new": "error",
 | 
					 | 
				
			||||||
    "@typescript-eslint/no-namespace": "error",
 | 
					 | 
				
			||||||
    "@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-type-assertion": "error",
 | 
					 | 
				
			||||||
    "@typescript-eslint/no-useless-constructor": "error",
 | 
					 | 
				
			||||||
    "@typescript-eslint/no-var-requires": "error",
 | 
					 | 
				
			||||||
    "@typescript-eslint/prefer-for-of": "warn",
 | 
					 | 
				
			||||||
    "@typescript-eslint/prefer-function-type": "warn",
 | 
					 | 
				
			||||||
    "@typescript-eslint/prefer-includes": "error",
 | 
					 | 
				
			||||||
    "@typescript-eslint/prefer-interface": "error",
 | 
					 | 
				
			||||||
    "@typescript-eslint/prefer-string-starts-ends-with": "error",
 | 
					 | 
				
			||||||
    "@typescript-eslint/promise-function-async": "error",
 | 
					 | 
				
			||||||
    "@typescript-eslint/require-array-sort-compare": "error",
 | 
					 | 
				
			||||||
    "@typescript-eslint/restrict-plus-operands": "error",
 | 
					 | 
				
			||||||
    "semi": "off",
 | 
					 | 
				
			||||||
    "@typescript-eslint/semi": ["error", "never"],
 | 
					 | 
				
			||||||
    "@typescript-eslint/type-annotation-spacing": "error",
 | 
					 | 
				
			||||||
    "@typescript-eslint/unbound-method": "error"
 | 
					 | 
				
			||||||
  },
 | 
					 | 
				
			||||||
  "env": {
 | 
					 | 
				
			||||||
    "node": true,
 | 
					 | 
				
			||||||
    "es6": true,
 | 
					 | 
				
			||||||
    "jest/globals": true
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
							
								
								
									
										101
									
								
								.github/workflows/test.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										101
									
								
								.github/workflows/test.yml
									
									
									
									
										vendored
									
									
								
							@@ -1,101 +0,0 @@
 | 
				
			|||||||
name: Build and Test
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
on:
 | 
					 | 
				
			||||||
  pull_request:
 | 
					 | 
				
			||||||
  push:
 | 
					 | 
				
			||||||
    branches:
 | 
					 | 
				
			||||||
      - master
 | 
					 | 
				
			||||||
      - releases/*
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
jobs:
 | 
					 | 
				
			||||||
  build:
 | 
					 | 
				
			||||||
    runs-on: ubuntu-latest
 | 
					 | 
				
			||||||
    steps:
 | 
					 | 
				
			||||||
      - uses: actions/checkout@v1 # todo: switch to v2
 | 
					 | 
				
			||||||
      - run: npm ci
 | 
					 | 
				
			||||||
      - run: npm run build
 | 
					 | 
				
			||||||
      - run: npm run format-check
 | 
					 | 
				
			||||||
      - run: npm run lint
 | 
					 | 
				
			||||||
      - run: npm run pack
 | 
					 | 
				
			||||||
      - run: npm run gendocs
 | 
					 | 
				
			||||||
      - run: npm test
 | 
					 | 
				
			||||||
      - name: Verify no unstaged changes
 | 
					 | 
				
			||||||
        run: __test__/verify-no-unstaged-changes.sh
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  test:
 | 
					 | 
				
			||||||
    strategy:
 | 
					 | 
				
			||||||
      matrix:
 | 
					 | 
				
			||||||
        runs-on: [ubuntu-latest, macos-latest, windows-latest]
 | 
					 | 
				
			||||||
    runs-on: ${{ matrix.runs-on }}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    steps:
 | 
					 | 
				
			||||||
      # Clone this repo
 | 
					 | 
				
			||||||
      - name: Checkout
 | 
					 | 
				
			||||||
        uses: actions/checkout@v2
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      # Basic checkout
 | 
					 | 
				
			||||||
      - name: Basic checkout
 | 
					 | 
				
			||||||
        uses: ./
 | 
					 | 
				
			||||||
        with:
 | 
					 | 
				
			||||||
          ref: test-data/v2/basic
 | 
					 | 
				
			||||||
          path: basic
 | 
					 | 
				
			||||||
      - name: Verify basic
 | 
					 | 
				
			||||||
        shell: bash
 | 
					 | 
				
			||||||
        run: __test__/verify-basic.sh
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      # Clean
 | 
					 | 
				
			||||||
      - name: Modify work tree
 | 
					 | 
				
			||||||
        shell: bash
 | 
					 | 
				
			||||||
        run: __test__/modify-work-tree.sh
 | 
					 | 
				
			||||||
      - name: Clean checkout
 | 
					 | 
				
			||||||
        uses: ./
 | 
					 | 
				
			||||||
        with:
 | 
					 | 
				
			||||||
          ref: test-data/v2/basic
 | 
					 | 
				
			||||||
          path: basic
 | 
					 | 
				
			||||||
      - name: Verify clean
 | 
					 | 
				
			||||||
        shell: bash
 | 
					 | 
				
			||||||
        run: __test__/verify-clean.sh
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      # Side by side
 | 
					 | 
				
			||||||
      - name: Side by side checkout 1
 | 
					 | 
				
			||||||
        uses: ./
 | 
					 | 
				
			||||||
        with:
 | 
					 | 
				
			||||||
          ref: test-data/v2/side-by-side-1
 | 
					 | 
				
			||||||
          path: side-by-side-1
 | 
					 | 
				
			||||||
      - name: Side by side checkout 2
 | 
					 | 
				
			||||||
        uses: ./
 | 
					 | 
				
			||||||
        with:
 | 
					 | 
				
			||||||
          ref: test-data/v2/side-by-side-2
 | 
					 | 
				
			||||||
          path: side-by-side-2
 | 
					 | 
				
			||||||
      - name: Verify side by side
 | 
					 | 
				
			||||||
        shell: bash
 | 
					 | 
				
			||||||
        run: __test__/verify-side-by-side.sh
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      # LFS
 | 
					 | 
				
			||||||
      - name: LFS checkout
 | 
					 | 
				
			||||||
        uses: ./
 | 
					 | 
				
			||||||
        with:
 | 
					 | 
				
			||||||
          repository: actions/checkout # hardcoded, otherwise doesn't work from a fork
 | 
					 | 
				
			||||||
          ref: test-data/v2/lfs
 | 
					 | 
				
			||||||
          path: lfs
 | 
					 | 
				
			||||||
          lfs: true
 | 
					 | 
				
			||||||
      - name: Verify LFS
 | 
					 | 
				
			||||||
        shell: bash
 | 
					 | 
				
			||||||
        run: __test__/verify-lfs.sh
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  test-job-container:
 | 
					 | 
				
			||||||
    runs-on: ubuntu-latest
 | 
					 | 
				
			||||||
    container: alpine:latest
 | 
					 | 
				
			||||||
    steps:
 | 
					 | 
				
			||||||
      # Clone this repo
 | 
					 | 
				
			||||||
      - name: Checkout
 | 
					 | 
				
			||||||
        uses: actions/checkout@v2
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      # Basic checkout
 | 
					 | 
				
			||||||
      - name: Basic checkout
 | 
					 | 
				
			||||||
        uses: ./
 | 
					 | 
				
			||||||
        with:
 | 
					 | 
				
			||||||
          ref: test-data/v2/basic
 | 
					 | 
				
			||||||
          path: basic
 | 
					 | 
				
			||||||
      - name: Verify basic
 | 
					 | 
				
			||||||
        run: __test__/verify-basic.sh --archive
 | 
					 | 
				
			||||||
							
								
								
									
										2
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							@@ -1,2 +0,0 @@
 | 
				
			|||||||
lib/
 | 
					 | 
				
			||||||
node_modules/
 | 
					 | 
				
			||||||
@@ -1,3 +0,0 @@
 | 
				
			|||||||
dist/
 | 
					 | 
				
			||||||
lib/
 | 
					 | 
				
			||||||
node_modules/
 | 
					 | 
				
			||||||
@@ -1,11 +0,0 @@
 | 
				
			|||||||
{
 | 
					 | 
				
			||||||
  "printWidth": 80,
 | 
					 | 
				
			||||||
  "tabWidth": 2,
 | 
					 | 
				
			||||||
  "useTabs": false,
 | 
					 | 
				
			||||||
  "semi": false,
 | 
					 | 
				
			||||||
  "singleQuote": true,
 | 
					 | 
				
			||||||
  "trailingComma": "none",
 | 
					 | 
				
			||||||
  "bracketSpacing": false,
 | 
					 | 
				
			||||||
  "arrowParens": "avoid",
 | 
					 | 
				
			||||||
  "parser": "typescript"
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
							
								
								
									
										23
									
								
								CHANGELOG.md
									
									
									
									
									
								
							
							
						
						
									
										23
									
								
								CHANGELOG.md
									
									
									
									
									
								
							@@ -1,23 +0,0 @@
 | 
				
			|||||||
# Changelog
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
## v2 (beta)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
- Improved fetch performance
 | 
					 | 
				
			||||||
  - The default behavior now fetches only the SHA being checked-out
 | 
					 | 
				
			||||||
- Script authenticated git commands
 | 
					 | 
				
			||||||
  - Persists `with.token` in the local git config
 | 
					 | 
				
			||||||
  - Enables your scripts to run authenticated git commands
 | 
					 | 
				
			||||||
  - Post-job cleanup removes the token
 | 
					 | 
				
			||||||
  - Coming soon: Opt out by setting `with.persist-credentials` to `false`
 | 
					 | 
				
			||||||
- Creates a local branch
 | 
					 | 
				
			||||||
  - No longer detached HEAD when checking out a branch
 | 
					 | 
				
			||||||
  - A local branch is created with the corresponding upstream branch set
 | 
					 | 
				
			||||||
- Improved layout
 | 
					 | 
				
			||||||
  - `with.path` is always relative to `github.workspace`
 | 
					 | 
				
			||||||
  - Aligns better with container actions, where `github.workspace` gets mapped in
 | 
					 | 
				
			||||||
- Removed input `submodules`
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
## v1
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Refer [here](https://github.com/actions/checkout/blob/v1/CHANGELOG.md) for the V1 changelog
 | 
					 | 
				
			||||||
							
								
								
									
										105
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										105
									
								
								README.md
									
									
									
									
									
								
							@@ -1,103 +1,20 @@
 | 
				
			|||||||
<p align="center">
 | 
					# checkout
 | 
				
			||||||
  <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>
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Checkout V2
 | 
					This action checks out your repository so that your workflow operates from the root of the repository
 | 
				
			||||||
 | 
					 | 
				
			||||||
This action checks-out your repository under `$GITHUB_WORKSPACE`, so your workflow can access it.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
By default, the repository that triggered the workflow is checked-out, for the ref/SHA that triggered the event.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Refer [here](https://help.github.com/en/articles/events-that-trigger-workflows) to learn which commit `$GITHUB_SHA` points to for different events.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# What's new
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
- Improved fetch performance
 | 
					 | 
				
			||||||
  - The default behavior now fetches only the commit being checked-out
 | 
					 | 
				
			||||||
- Script authenticated git commands
 | 
					 | 
				
			||||||
  - Persists the input `token` in the local git config
 | 
					 | 
				
			||||||
  - Enables your scripts to run authenticated git commands
 | 
					 | 
				
			||||||
  - Post-job cleanup removes the token
 | 
					 | 
				
			||||||
  - Opt out by setting the input `persist-credentials: false`
 | 
					 | 
				
			||||||
- Creates a local branch
 | 
					 | 
				
			||||||
  - No longer detached HEAD when checking out a branch
 | 
					 | 
				
			||||||
  - A local branch is created with the corresponding upstream branch set
 | 
					 | 
				
			||||||
- 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
 | 
					 | 
				
			||||||
- Removed input `submodules`
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Refer [here](https://github.com/actions/checkout/blob/v1/README.md) for previous versions.
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Usage
 | 
					# Usage
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<!-- start usage -->
 | 
					See [action.yml](action.yml)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Basic:
 | 
				
			||||||
```yaml
 | 
					```yaml
 | 
				
			||||||
- uses: actions/checkout@v2
 | 
					steps:
 | 
				
			||||||
 | 
					- uses: actions/checkout@master
 | 
				
			||||||
 | 
					- uses: actions/setup-node@master
 | 
				
			||||||
  with:
 | 
					  with:
 | 
				
			||||||
    # Repository name with owner. For example, actions/checkout
 | 
					    version: 10.x 
 | 
				
			||||||
    # Default: ${{ github.repository }}
 | 
					- run: npm install
 | 
				
			||||||
    repository: ''
 | 
					- run: npm test
 | 
				
			||||||
 | 
					 | 
				
			||||||
    # The branch, tag or SHA to checkout. When checking out the repository that
 | 
					 | 
				
			||||||
    # triggered a workflow, this defaults to the reference or SHA for that event.
 | 
					 | 
				
			||||||
    # Otherwise, defaults to `master`.
 | 
					 | 
				
			||||||
    ref: ''
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    # Auth token used to fetch the repository. The token is stored in the local git
 | 
					 | 
				
			||||||
    # config, which enables your scripts to run authenticated git commands. The
 | 
					 | 
				
			||||||
    # post-job step removes the token from the git config.
 | 
					 | 
				
			||||||
    # Default: ${{ github.token }}
 | 
					 | 
				
			||||||
    token: ''
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    # Whether to persist the token in the git config
 | 
					 | 
				
			||||||
    # Default: true
 | 
					 | 
				
			||||||
    persist-credentials: ''
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    # Relative path under $GITHUB_WORKSPACE to place the repository
 | 
					 | 
				
			||||||
    path: ''
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    # Whether to execute `git clean -ffdx && git reset --hard HEAD` before fetching
 | 
					 | 
				
			||||||
    # Default: true
 | 
					 | 
				
			||||||
    clean: ''
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    # Number of commits to fetch. 0 indicates all history.
 | 
					 | 
				
			||||||
    # Default: 1
 | 
					 | 
				
			||||||
    fetch-depth: ''
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    # Whether to download Git-LFS files
 | 
					 | 
				
			||||||
    # Default: false
 | 
					 | 
				
			||||||
    lfs: ''
 | 
					 | 
				
			||||||
```
 | 
					 | 
				
			||||||
<!-- end usage -->
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
## Checkout a different branch
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
```yaml
 | 
					 | 
				
			||||||
- uses: actions/checkout@v2
 | 
					 | 
				
			||||||
  with:
 | 
					 | 
				
			||||||
    ref: some-branch
 | 
					 | 
				
			||||||
```
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
## Checkout a different, private repository
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
```yaml
 | 
					 | 
				
			||||||
- uses: actions/checkout@v2
 | 
					 | 
				
			||||||
  with:
 | 
					 | 
				
			||||||
    repository: myAccount/myRepository
 | 
					 | 
				
			||||||
    ref: refs/heads/master
 | 
					 | 
				
			||||||
    token: ${{ secrets.GitHub_PAT }} # `GitHub_PAT` is a secret that contains your PAT
 | 
					 | 
				
			||||||
```
 | 
					 | 
				
			||||||
> - `${{ github.token }}` is scoped to the current repository, so if you want to checkout another repository that is private you will need to provide your own [PAT](https://help.github.com/en/github/authenticating-to-github/creating-a-personal-access-token-for-the-command-line).
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
## Checkout the HEAD commit of a PR, rather than the merge commit
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
```yaml
 | 
					 | 
				
			||||||
- uses: actions/checkout@v2
 | 
					 | 
				
			||||||
  with:
 | 
					 | 
				
			||||||
    ref: ${{ github.event.pull_request.head.sha }}
 | 
					 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# License
 | 
					# License
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,45 +0,0 @@
 | 
				
			|||||||
import {GitVersion} from '../lib/git-version'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
describe('git-version tests', () => {
 | 
					 | 
				
			||||||
  it('basics', async () => {
 | 
					 | 
				
			||||||
    let version = new GitVersion('')
 | 
					 | 
				
			||||||
    expect(version.isValid()).toBeFalsy()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    version = new GitVersion('asdf')
 | 
					 | 
				
			||||||
    expect(version.isValid()).toBeFalsy()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    version = new GitVersion('1.2')
 | 
					 | 
				
			||||||
    expect(version.isValid()).toBeTruthy()
 | 
					 | 
				
			||||||
    expect(version.toString()).toBe('1.2')
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    version = new GitVersion('1.2.3')
 | 
					 | 
				
			||||||
    expect(version.isValid()).toBeTruthy()
 | 
					 | 
				
			||||||
    expect(version.toString()).toBe('1.2.3')
 | 
					 | 
				
			||||||
  })
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  it('check minimum', async () => {
 | 
					 | 
				
			||||||
    let version = new GitVersion('4.5')
 | 
					 | 
				
			||||||
    expect(version.checkMinimum(new GitVersion('3.6'))).toBeTruthy()
 | 
					 | 
				
			||||||
    expect(version.checkMinimum(new GitVersion('3.6.7'))).toBeTruthy()
 | 
					 | 
				
			||||||
    expect(version.checkMinimum(new GitVersion('4.4'))).toBeTruthy()
 | 
					 | 
				
			||||||
    expect(version.checkMinimum(new GitVersion('4.5'))).toBeTruthy()
 | 
					 | 
				
			||||||
    expect(version.checkMinimum(new GitVersion('4.5.0'))).toBeTruthy()
 | 
					 | 
				
			||||||
    expect(version.checkMinimum(new GitVersion('4.6'))).toBeFalsy()
 | 
					 | 
				
			||||||
    expect(version.checkMinimum(new GitVersion('4.6.0'))).toBeFalsy()
 | 
					 | 
				
			||||||
    expect(version.checkMinimum(new GitVersion('5.1'))).toBeFalsy()
 | 
					 | 
				
			||||||
    expect(version.checkMinimum(new GitVersion('5.1.2'))).toBeFalsy()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    version = new GitVersion('4.5.6')
 | 
					 | 
				
			||||||
    expect(version.checkMinimum(new GitVersion('3.6'))).toBeTruthy()
 | 
					 | 
				
			||||||
    expect(version.checkMinimum(new GitVersion('3.6.7'))).toBeTruthy()
 | 
					 | 
				
			||||||
    expect(version.checkMinimum(new GitVersion('4.4'))).toBeTruthy()
 | 
					 | 
				
			||||||
    expect(version.checkMinimum(new GitVersion('4.5'))).toBeTruthy()
 | 
					 | 
				
			||||||
    expect(version.checkMinimum(new GitVersion('4.5.5'))).toBeTruthy()
 | 
					 | 
				
			||||||
    expect(version.checkMinimum(new GitVersion('4.5.6'))).toBeTruthy()
 | 
					 | 
				
			||||||
    expect(version.checkMinimum(new GitVersion('4.5.7'))).toBeFalsy()
 | 
					 | 
				
			||||||
    expect(version.checkMinimum(new GitVersion('4.6'))).toBeFalsy()
 | 
					 | 
				
			||||||
    expect(version.checkMinimum(new GitVersion('4.6.0'))).toBeFalsy()
 | 
					 | 
				
			||||||
    expect(version.checkMinimum(new GitVersion('5.1'))).toBeFalsy()
 | 
					 | 
				
			||||||
    expect(version.checkMinimum(new GitVersion('5.1.2'))).toBeFalsy()
 | 
					 | 
				
			||||||
  })
 | 
					 | 
				
			||||||
})
 | 
					 | 
				
			||||||
@@ -1,120 +0,0 @@
 | 
				
			|||||||
import * as assert from 'assert'
 | 
					 | 
				
			||||||
import * as path from 'path'
 | 
					 | 
				
			||||||
import {ISourceSettings} from '../lib/git-source-provider'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const originalGitHubWorkspace = process.env['GITHUB_WORKSPACE']
 | 
					 | 
				
			||||||
const gitHubWorkspace = path.resolve('/checkout-tests/workspace')
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// Late bind
 | 
					 | 
				
			||||||
let inputHelper: any
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// Mock @actions/core
 | 
					 | 
				
			||||||
let inputs = {} as any
 | 
					 | 
				
			||||||
const mockCore = jest.genMockFromModule('@actions/core') as any
 | 
					 | 
				
			||||||
mockCore.getInput = (name: string) => {
 | 
					 | 
				
			||||||
  return inputs[name]
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// Mock @actions/github
 | 
					 | 
				
			||||||
const mockGitHub = jest.genMockFromModule('@actions/github') as any
 | 
					 | 
				
			||||||
mockGitHub.context = {
 | 
					 | 
				
			||||||
  repo: {
 | 
					 | 
				
			||||||
    owner: 'some-owner',
 | 
					 | 
				
			||||||
    repo: 'some-repo'
 | 
					 | 
				
			||||||
  },
 | 
					 | 
				
			||||||
  ref: 'refs/heads/some-ref',
 | 
					 | 
				
			||||||
  sha: '1234567890123456789012345678901234567890'
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// Mock ./fs-helper
 | 
					 | 
				
			||||||
const mockFSHelper = jest.genMockFromModule('../lib/fs-helper') as any
 | 
					 | 
				
			||||||
mockFSHelper.directoryExistsSync = (path: string) => path == gitHubWorkspace
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
describe('input-helper tests', () => {
 | 
					 | 
				
			||||||
  beforeAll(() => {
 | 
					 | 
				
			||||||
    // GitHub workspace
 | 
					 | 
				
			||||||
    process.env['GITHUB_WORKSPACE'] = gitHubWorkspace
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // Mocks
 | 
					 | 
				
			||||||
    jest.setMock('@actions/core', mockCore)
 | 
					 | 
				
			||||||
    jest.setMock('@actions/github', mockGitHub)
 | 
					 | 
				
			||||||
    jest.setMock('../lib/fs-helper', mockFSHelper)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // Now import
 | 
					 | 
				
			||||||
    inputHelper = require('../lib/input-helper')
 | 
					 | 
				
			||||||
  })
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  beforeEach(() => {
 | 
					 | 
				
			||||||
    // Reset inputs
 | 
					 | 
				
			||||||
    inputs = {}
 | 
					 | 
				
			||||||
  })
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  afterAll(() => {
 | 
					 | 
				
			||||||
    // Reset GitHub workspace
 | 
					 | 
				
			||||||
    delete process.env['GITHUB_WORKSPACE']
 | 
					 | 
				
			||||||
    if (originalGitHubWorkspace) {
 | 
					 | 
				
			||||||
      process.env['GITHUB_WORKSPACE'] = originalGitHubWorkspace
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // Reset modules
 | 
					 | 
				
			||||||
    jest.resetModules()
 | 
					 | 
				
			||||||
  })
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  it('sets defaults', () => {
 | 
					 | 
				
			||||||
    const settings: ISourceSettings = inputHelper.getInputs()
 | 
					 | 
				
			||||||
    expect(settings).toBeTruthy()
 | 
					 | 
				
			||||||
    expect(settings.authToken).toBeFalsy()
 | 
					 | 
				
			||||||
    expect(settings.clean).toBe(true)
 | 
					 | 
				
			||||||
    expect(settings.commit).toBeTruthy()
 | 
					 | 
				
			||||||
    expect(settings.commit).toBe('1234567890123456789012345678901234567890')
 | 
					 | 
				
			||||||
    expect(settings.fetchDepth).toBe(1)
 | 
					 | 
				
			||||||
    expect(settings.lfs).toBe(false)
 | 
					 | 
				
			||||||
    expect(settings.ref).toBe('refs/heads/some-ref')
 | 
					 | 
				
			||||||
    expect(settings.repositoryName).toBe('some-repo')
 | 
					 | 
				
			||||||
    expect(settings.repositoryOwner).toBe('some-owner')
 | 
					 | 
				
			||||||
    expect(settings.repositoryPath).toBe(gitHubWorkspace)
 | 
					 | 
				
			||||||
  })
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  it('requires qualified repo', () => {
 | 
					 | 
				
			||||||
    inputs.repository = 'some-unqualified-repo'
 | 
					 | 
				
			||||||
    assert.throws(() => {
 | 
					 | 
				
			||||||
      inputHelper.getInputs()
 | 
					 | 
				
			||||||
    }, /Invalid repository 'some-unqualified-repo'/)
 | 
					 | 
				
			||||||
  })
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  it('roots path', () => {
 | 
					 | 
				
			||||||
    inputs.path = 'some-directory/some-subdirectory'
 | 
					 | 
				
			||||||
    const settings: ISourceSettings = inputHelper.getInputs()
 | 
					 | 
				
			||||||
    expect(settings.repositoryPath).toBe(
 | 
					 | 
				
			||||||
      path.join(gitHubWorkspace, 'some-directory', 'some-subdirectory')
 | 
					 | 
				
			||||||
    )
 | 
					 | 
				
			||||||
  })
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  it('sets correct default ref/sha for other repo', () => {
 | 
					 | 
				
			||||||
    inputs.repository = 'some-owner/some-other-repo'
 | 
					 | 
				
			||||||
    const settings: ISourceSettings = inputHelper.getInputs()
 | 
					 | 
				
			||||||
    expect(settings.ref).toBe('refs/heads/master')
 | 
					 | 
				
			||||||
    expect(settings.commit).toBeFalsy()
 | 
					 | 
				
			||||||
  })
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  it('sets ref to empty when explicit sha', () => {
 | 
					 | 
				
			||||||
    inputs.ref = '1111111111222222222233333333334444444444'
 | 
					 | 
				
			||||||
    const settings: ISourceSettings = inputHelper.getInputs()
 | 
					 | 
				
			||||||
    expect(settings.ref).toBeFalsy()
 | 
					 | 
				
			||||||
    expect(settings.commit).toBe('1111111111222222222233333333334444444444')
 | 
					 | 
				
			||||||
  })
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  it('sets sha to empty when explicit ref', () => {
 | 
					 | 
				
			||||||
    inputs.ref = 'refs/heads/some-other-ref'
 | 
					 | 
				
			||||||
    const settings: ISourceSettings = inputHelper.getInputs()
 | 
					 | 
				
			||||||
    expect(settings.ref).toBe('refs/heads/some-other-ref')
 | 
					 | 
				
			||||||
    expect(settings.commit).toBeFalsy()
 | 
					 | 
				
			||||||
  })
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  it('gives good error message for submodules input', () => {
 | 
					 | 
				
			||||||
    inputs.submodules = 'true'
 | 
					 | 
				
			||||||
    assert.throws(() => {
 | 
					 | 
				
			||||||
      inputHelper.getInputs()
 | 
					 | 
				
			||||||
    }, /The input 'submodules' is not supported/)
 | 
					 | 
				
			||||||
  })
 | 
					 | 
				
			||||||
})
 | 
					 | 
				
			||||||
@@ -1,10 +0,0 @@
 | 
				
			|||||||
#!/bin/bash
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
if [ ! -f "./basic/basic-file.txt" ]; then
 | 
					 | 
				
			||||||
    echo "Expected basic file does not exist"
 | 
					 | 
				
			||||||
    exit 1
 | 
					 | 
				
			||||||
fi
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
echo hello >> ./basic/basic-file.txt
 | 
					 | 
				
			||||||
echo hello >> ./basic/new-file.txt
 | 
					 | 
				
			||||||
git -C ./basic status
 | 
					 | 
				
			||||||
@@ -1,168 +0,0 @@
 | 
				
			|||||||
import * as assert from 'assert'
 | 
					 | 
				
			||||||
import * as refHelper from '../lib/ref-helper'
 | 
					 | 
				
			||||||
import {IGitCommandManager} from '../lib/git-command-manager'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const commit = '1234567890123456789012345678901234567890'
 | 
					 | 
				
			||||||
let git: IGitCommandManager
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
describe('ref-helper tests', () => {
 | 
					 | 
				
			||||||
  beforeEach(() => {
 | 
					 | 
				
			||||||
    git = ({} as unknown) as IGitCommandManager
 | 
					 | 
				
			||||||
  })
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  it('getCheckoutInfo requires git', async () => {
 | 
					 | 
				
			||||||
    const git = (null as unknown) as IGitCommandManager
 | 
					 | 
				
			||||||
    try {
 | 
					 | 
				
			||||||
      await refHelper.getCheckoutInfo(git, 'refs/heads/my/branch', commit)
 | 
					 | 
				
			||||||
      throw new Error('Should not reach here')
 | 
					 | 
				
			||||||
    } catch (err) {
 | 
					 | 
				
			||||||
      expect(err.message).toBe('Arg git cannot be empty')
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  })
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  it('getCheckoutInfo requires ref or commit', async () => {
 | 
					 | 
				
			||||||
    try {
 | 
					 | 
				
			||||||
      await refHelper.getCheckoutInfo(git, '', '')
 | 
					 | 
				
			||||||
      throw new Error('Should not reach here')
 | 
					 | 
				
			||||||
    } catch (err) {
 | 
					 | 
				
			||||||
      expect(err.message).toBe('Args ref and commit cannot both be empty')
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  })
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  it('getCheckoutInfo sha only', async () => {
 | 
					 | 
				
			||||||
    const checkoutInfo = await refHelper.getCheckoutInfo(git, '', commit)
 | 
					 | 
				
			||||||
    expect(checkoutInfo.ref).toBe(commit)
 | 
					 | 
				
			||||||
    expect(checkoutInfo.startPoint).toBeFalsy()
 | 
					 | 
				
			||||||
  })
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  it('getCheckoutInfo refs/heads/', async () => {
 | 
					 | 
				
			||||||
    const checkoutInfo = await refHelper.getCheckoutInfo(
 | 
					 | 
				
			||||||
      git,
 | 
					 | 
				
			||||||
      'refs/heads/my/branch',
 | 
					 | 
				
			||||||
      commit
 | 
					 | 
				
			||||||
    )
 | 
					 | 
				
			||||||
    expect(checkoutInfo.ref).toBe('my/branch')
 | 
					 | 
				
			||||||
    expect(checkoutInfo.startPoint).toBe('refs/remotes/origin/my/branch')
 | 
					 | 
				
			||||||
  })
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  it('getCheckoutInfo refs/pull/', async () => {
 | 
					 | 
				
			||||||
    const checkoutInfo = await refHelper.getCheckoutInfo(
 | 
					 | 
				
			||||||
      git,
 | 
					 | 
				
			||||||
      'refs/pull/123/merge',
 | 
					 | 
				
			||||||
      commit
 | 
					 | 
				
			||||||
    )
 | 
					 | 
				
			||||||
    expect(checkoutInfo.ref).toBe('refs/remotes/pull/123/merge')
 | 
					 | 
				
			||||||
    expect(checkoutInfo.startPoint).toBeFalsy()
 | 
					 | 
				
			||||||
  })
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  it('getCheckoutInfo refs/tags/', async () => {
 | 
					 | 
				
			||||||
    const checkoutInfo = await refHelper.getCheckoutInfo(
 | 
					 | 
				
			||||||
      git,
 | 
					 | 
				
			||||||
      'refs/tags/my-tag',
 | 
					 | 
				
			||||||
      commit
 | 
					 | 
				
			||||||
    )
 | 
					 | 
				
			||||||
    expect(checkoutInfo.ref).toBe('refs/tags/my-tag')
 | 
					 | 
				
			||||||
    expect(checkoutInfo.startPoint).toBeFalsy()
 | 
					 | 
				
			||||||
  })
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  it('getCheckoutInfo unqualified branch only', async () => {
 | 
					 | 
				
			||||||
    git.branchExists = jest.fn(async (remote: boolean, pattern: string) => {
 | 
					 | 
				
			||||||
      return true
 | 
					 | 
				
			||||||
    })
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    const checkoutInfo = await refHelper.getCheckoutInfo(git, 'my/branch', '')
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    expect(checkoutInfo.ref).toBe('my/branch')
 | 
					 | 
				
			||||||
    expect(checkoutInfo.startPoint).toBe('refs/remotes/origin/my/branch')
 | 
					 | 
				
			||||||
  })
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  it('getCheckoutInfo unqualified tag only', async () => {
 | 
					 | 
				
			||||||
    git.branchExists = jest.fn(async (remote: boolean, pattern: string) => {
 | 
					 | 
				
			||||||
      return false
 | 
					 | 
				
			||||||
    })
 | 
					 | 
				
			||||||
    git.tagExists = jest.fn(async (pattern: string) => {
 | 
					 | 
				
			||||||
      return true
 | 
					 | 
				
			||||||
    })
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    const checkoutInfo = await refHelper.getCheckoutInfo(git, 'my-tag', '')
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    expect(checkoutInfo.ref).toBe('refs/tags/my-tag')
 | 
					 | 
				
			||||||
    expect(checkoutInfo.startPoint).toBeFalsy()
 | 
					 | 
				
			||||||
  })
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  it('getCheckoutInfo unqualified ref only, not a branch or tag', async () => {
 | 
					 | 
				
			||||||
    git.branchExists = jest.fn(async (remote: boolean, pattern: string) => {
 | 
					 | 
				
			||||||
      return false
 | 
					 | 
				
			||||||
    })
 | 
					 | 
				
			||||||
    git.tagExists = jest.fn(async (pattern: string) => {
 | 
					 | 
				
			||||||
      return false
 | 
					 | 
				
			||||||
    })
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    try {
 | 
					 | 
				
			||||||
      await refHelper.getCheckoutInfo(git, 'my-ref', '')
 | 
					 | 
				
			||||||
      throw new Error('Should not reach here')
 | 
					 | 
				
			||||||
    } catch (err) {
 | 
					 | 
				
			||||||
      expect(err.message).toBe(
 | 
					 | 
				
			||||||
        "A branch or tag with the name 'my-ref' could not be found"
 | 
					 | 
				
			||||||
      )
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  })
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  it('getRefSpec requires ref or commit', async () => {
 | 
					 | 
				
			||||||
    assert.throws(
 | 
					 | 
				
			||||||
      () => refHelper.getRefSpec('', ''),
 | 
					 | 
				
			||||||
      /Args ref and commit cannot both be empty/
 | 
					 | 
				
			||||||
    )
 | 
					 | 
				
			||||||
  })
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  it('getRefSpec sha + refs/heads/', async () => {
 | 
					 | 
				
			||||||
    const refSpec = refHelper.getRefSpec('refs/heads/my/branch', commit)
 | 
					 | 
				
			||||||
    expect(refSpec.length).toBe(1)
 | 
					 | 
				
			||||||
    expect(refSpec[0]).toBe(`+${commit}:refs/remotes/origin/my/branch`)
 | 
					 | 
				
			||||||
  })
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  it('getRefSpec sha + refs/pull/', async () => {
 | 
					 | 
				
			||||||
    const refSpec = refHelper.getRefSpec('refs/pull/123/merge', commit)
 | 
					 | 
				
			||||||
    expect(refSpec.length).toBe(1)
 | 
					 | 
				
			||||||
    expect(refSpec[0]).toBe(`+${commit}:refs/remotes/pull/123/merge`)
 | 
					 | 
				
			||||||
  })
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  it('getRefSpec sha + refs/tags/', async () => {
 | 
					 | 
				
			||||||
    const refSpec = refHelper.getRefSpec('refs/tags/my-tag', commit)
 | 
					 | 
				
			||||||
    expect(refSpec.length).toBe(1)
 | 
					 | 
				
			||||||
    expect(refSpec[0]).toBe(`+${commit}:refs/tags/my-tag`)
 | 
					 | 
				
			||||||
  })
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  it('getRefSpec sha only', async () => {
 | 
					 | 
				
			||||||
    const refSpec = refHelper.getRefSpec('', commit)
 | 
					 | 
				
			||||||
    expect(refSpec.length).toBe(1)
 | 
					 | 
				
			||||||
    expect(refSpec[0]).toBe(commit)
 | 
					 | 
				
			||||||
  })
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  it('getRefSpec unqualified ref only', async () => {
 | 
					 | 
				
			||||||
    const refSpec = refHelper.getRefSpec('my-ref', '')
 | 
					 | 
				
			||||||
    expect(refSpec.length).toBe(2)
 | 
					 | 
				
			||||||
    expect(refSpec[0]).toBe('+refs/heads/my-ref*:refs/remotes/origin/my-ref*')
 | 
					 | 
				
			||||||
    expect(refSpec[1]).toBe('+refs/tags/my-ref*:refs/tags/my-ref*')
 | 
					 | 
				
			||||||
  })
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  it('getRefSpec refs/heads/ only', async () => {
 | 
					 | 
				
			||||||
    const refSpec = refHelper.getRefSpec('refs/heads/my/branch', '')
 | 
					 | 
				
			||||||
    expect(refSpec.length).toBe(1)
 | 
					 | 
				
			||||||
    expect(refSpec[0]).toBe(
 | 
					 | 
				
			||||||
      '+refs/heads/my/branch:refs/remotes/origin/my/branch'
 | 
					 | 
				
			||||||
    )
 | 
					 | 
				
			||||||
  })
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  it('getRefSpec refs/pull/ only', async () => {
 | 
					 | 
				
			||||||
    const refSpec = refHelper.getRefSpec('refs/pull/123/merge', '')
 | 
					 | 
				
			||||||
    expect(refSpec.length).toBe(1)
 | 
					 | 
				
			||||||
    expect(refSpec[0]).toBe('+refs/pull/123/merge:refs/remotes/pull/123/merge')
 | 
					 | 
				
			||||||
  })
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  it('getRefSpec refs/tags/ only', async () => {
 | 
					 | 
				
			||||||
    const refSpec = refHelper.getRefSpec('refs/tags/my-tag', '')
 | 
					 | 
				
			||||||
    expect(refSpec.length).toBe(1)
 | 
					 | 
				
			||||||
    expect(refSpec[0]).toBe('+refs/tags/my-tag:refs/tags/my-tag')
 | 
					 | 
				
			||||||
  })
 | 
					 | 
				
			||||||
})
 | 
					 | 
				
			||||||
@@ -1,88 +0,0 @@
 | 
				
			|||||||
const mockCore = jest.genMockFromModule('@actions/core') as any
 | 
					 | 
				
			||||||
mockCore.info = (message: string) => {
 | 
					 | 
				
			||||||
  info.push(message)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
let info: string[]
 | 
					 | 
				
			||||||
let retryHelper: any
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
describe('retry-helper tests', () => {
 | 
					 | 
				
			||||||
  beforeAll(() => {
 | 
					 | 
				
			||||||
    // Mocks
 | 
					 | 
				
			||||||
    jest.setMock('@actions/core', mockCore)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // Now import
 | 
					 | 
				
			||||||
    const retryHelperModule = require('../lib/retry-helper')
 | 
					 | 
				
			||||||
    retryHelper = new retryHelperModule.RetryHelper(3, 0, 0)
 | 
					 | 
				
			||||||
  })
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  beforeEach(() => {
 | 
					 | 
				
			||||||
    // Reset info
 | 
					 | 
				
			||||||
    info = []
 | 
					 | 
				
			||||||
  })
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  afterAll(() => {
 | 
					 | 
				
			||||||
    // Reset modules
 | 
					 | 
				
			||||||
    jest.resetModules()
 | 
					 | 
				
			||||||
  })
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  it('first attempt succeeds', async () => {
 | 
					 | 
				
			||||||
    const actual = await retryHelper.execute(async () => {
 | 
					 | 
				
			||||||
      return 'some result'
 | 
					 | 
				
			||||||
    })
 | 
					 | 
				
			||||||
    expect(actual).toBe('some result')
 | 
					 | 
				
			||||||
    expect(info).toHaveLength(0)
 | 
					 | 
				
			||||||
  })
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  it('second attempt succeeds', async () => {
 | 
					 | 
				
			||||||
    let attempts = 0
 | 
					 | 
				
			||||||
    const actual = await retryHelper.execute(() => {
 | 
					 | 
				
			||||||
      if (++attempts == 1) {
 | 
					 | 
				
			||||||
        throw new Error('some error')
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      return Promise.resolve('some result')
 | 
					 | 
				
			||||||
    })
 | 
					 | 
				
			||||||
    expect(attempts).toBe(2)
 | 
					 | 
				
			||||||
    expect(actual).toBe('some result')
 | 
					 | 
				
			||||||
    expect(info).toHaveLength(2)
 | 
					 | 
				
			||||||
    expect(info[0]).toBe('some error')
 | 
					 | 
				
			||||||
    expect(info[1]).toMatch(/Waiting .+ seconds before trying again/)
 | 
					 | 
				
			||||||
  })
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  it('third attempt succeeds', async () => {
 | 
					 | 
				
			||||||
    let attempts = 0
 | 
					 | 
				
			||||||
    const actual = await retryHelper.execute(() => {
 | 
					 | 
				
			||||||
      if (++attempts < 3) {
 | 
					 | 
				
			||||||
        throw new Error(`some error ${attempts}`)
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      return Promise.resolve('some result')
 | 
					 | 
				
			||||||
    })
 | 
					 | 
				
			||||||
    expect(attempts).toBe(3)
 | 
					 | 
				
			||||||
    expect(actual).toBe('some result')
 | 
					 | 
				
			||||||
    expect(info).toHaveLength(4)
 | 
					 | 
				
			||||||
    expect(info[0]).toBe('some error 1')
 | 
					 | 
				
			||||||
    expect(info[1]).toMatch(/Waiting .+ seconds before trying again/)
 | 
					 | 
				
			||||||
    expect(info[2]).toBe('some error 2')
 | 
					 | 
				
			||||||
    expect(info[3]).toMatch(/Waiting .+ seconds before trying again/)
 | 
					 | 
				
			||||||
  })
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  it('all attempts fail succeeds', async () => {
 | 
					 | 
				
			||||||
    let attempts = 0
 | 
					 | 
				
			||||||
    let error: Error = (null as unknown) as Error
 | 
					 | 
				
			||||||
    try {
 | 
					 | 
				
			||||||
      await retryHelper.execute(() => {
 | 
					 | 
				
			||||||
        throw new Error(`some error ${++attempts}`)
 | 
					 | 
				
			||||||
      })
 | 
					 | 
				
			||||||
    } catch (err) {
 | 
					 | 
				
			||||||
      error = err
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    expect(error.message).toBe('some error 3')
 | 
					 | 
				
			||||||
    expect(attempts).toBe(3)
 | 
					 | 
				
			||||||
    expect(info).toHaveLength(4)
 | 
					 | 
				
			||||||
    expect(info[0]).toBe('some error 1')
 | 
					 | 
				
			||||||
    expect(info[1]).toMatch(/Waiting .+ seconds before trying again/)
 | 
					 | 
				
			||||||
    expect(info[2]).toBe('some error 2')
 | 
					 | 
				
			||||||
    expect(info[3]).toMatch(/Waiting .+ seconds before trying again/)
 | 
					 | 
				
			||||||
  })
 | 
					 | 
				
			||||||
})
 | 
					 | 
				
			||||||
@@ -1,24 +0,0 @@
 | 
				
			|||||||
#!/bin/sh
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
if [ ! -f "./basic/basic-file.txt" ]; then
 | 
					 | 
				
			||||||
    echo "Expected basic file does not exist"
 | 
					 | 
				
			||||||
    exit 1
 | 
					 | 
				
			||||||
fi
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
if [ "$1" = "--archive" ]; then
 | 
					 | 
				
			||||||
  # Verify no .git folder
 | 
					 | 
				
			||||||
  if [ -d "./basic/.git" ]; then
 | 
					 | 
				
			||||||
    echo "Did not expect ./basic/.git folder to exist"
 | 
					 | 
				
			||||||
    exit 1
 | 
					 | 
				
			||||||
  fi
 | 
					 | 
				
			||||||
else
 | 
					 | 
				
			||||||
  # Verify .git folder
 | 
					 | 
				
			||||||
  if [ ! -d "./basic/.git" ]; then
 | 
					 | 
				
			||||||
    echo "Expected ./basic/.git folder to exist"
 | 
					 | 
				
			||||||
    exit 1
 | 
					 | 
				
			||||||
  fi
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  # Verify auth token
 | 
					 | 
				
			||||||
  cd basic
 | 
					 | 
				
			||||||
  git fetch --no-tags --depth=1 origin +refs/heads/master:refs/remotes/origin/master
 | 
					 | 
				
			||||||
fi
 | 
					 | 
				
			||||||
@@ -1,13 +0,0 @@
 | 
				
			|||||||
#!/bin/bash
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
if [[ "$(git -C ./basic status --porcelain)" != "" ]]; then
 | 
					 | 
				
			||||||
    echo ----------------------------------------
 | 
					 | 
				
			||||||
    echo git status
 | 
					 | 
				
			||||||
    echo ----------------------------------------
 | 
					 | 
				
			||||||
    git status
 | 
					 | 
				
			||||||
    echo ----------------------------------------
 | 
					 | 
				
			||||||
    echo git diff
 | 
					 | 
				
			||||||
    echo ----------------------------------------
 | 
					 | 
				
			||||||
    git diff
 | 
					 | 
				
			||||||
    exit 1
 | 
					 | 
				
			||||||
fi
 | 
					 | 
				
			||||||
@@ -1,11 +0,0 @@
 | 
				
			|||||||
#!/bin/bash
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
if [ ! -f "./lfs/regular-file.txt" ]; then
 | 
					 | 
				
			||||||
    echo "Expected regular file does not exist"
 | 
					 | 
				
			||||||
    exit 1
 | 
					 | 
				
			||||||
fi
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
if [ ! -f "./lfs/lfs-file.bin" ]; then
 | 
					 | 
				
			||||||
    echo "Expected lfs file does not exist"
 | 
					 | 
				
			||||||
    exit 1
 | 
					 | 
				
			||||||
fi
 | 
					 | 
				
			||||||
@@ -1,17 +0,0 @@
 | 
				
			|||||||
#!/bin/bash
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
if [[ "$(git status --porcelain)" != "" ]]; then
 | 
					 | 
				
			||||||
    echo ----------------------------------------
 | 
					 | 
				
			||||||
    echo git status
 | 
					 | 
				
			||||||
    echo ----------------------------------------
 | 
					 | 
				
			||||||
    git status
 | 
					 | 
				
			||||||
    echo ----------------------------------------
 | 
					 | 
				
			||||||
    echo git diff
 | 
					 | 
				
			||||||
    echo ----------------------------------------
 | 
					 | 
				
			||||||
    git diff
 | 
					 | 
				
			||||||
    echo ----------------------------------------
 | 
					 | 
				
			||||||
    echo Troubleshooting
 | 
					 | 
				
			||||||
    echo ----------------------------------------
 | 
					 | 
				
			||||||
    echo "::error::Unstaged changes detected. Locally try running: git clean -ffdx && npm ci && npm run all"
 | 
					 | 
				
			||||||
    exit 1
 | 
					 | 
				
			||||||
fi
 | 
					 | 
				
			||||||
@@ -1,11 +0,0 @@
 | 
				
			|||||||
#!/bin/bash
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
if [ ! -f "./side-by-side-1/side-by-side-test-file-1.txt" ]; then
 | 
					 | 
				
			||||||
    echo "Expected file 1 does not exist"
 | 
					 | 
				
			||||||
    exit 1
 | 
					 | 
				
			||||||
fi
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
if [ ! -f "./side-by-side-2/side-by-side-test-file-2.txt" ]; then
 | 
					 | 
				
			||||||
    echo "Expected file 2 does not exist"
 | 
					 | 
				
			||||||
    exit 1
 | 
					 | 
				
			||||||
fi
 | 
					 | 
				
			||||||
@@ -1,11 +0,0 @@
 | 
				
			|||||||
#!/bin/bash
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
if [ ! -f "./submodules-not-checked-out/regular-file.txt" ]; then
 | 
					 | 
				
			||||||
    echo "Expected regular file does not exist"
 | 
					 | 
				
			||||||
    exit 1
 | 
					 | 
				
			||||||
fi
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
if [ -f "./submodules-not-checked-out/submodule-level-1/submodule-file.txt" ]; then
 | 
					 | 
				
			||||||
    echo "Unexpected submodule file exists"
 | 
					 | 
				
			||||||
    exit 1
 | 
					 | 
				
			||||||
fi
 | 
					 | 
				
			||||||
							
								
								
									
										39
									
								
								action.yml
									
									
									
									
									
								
							
							
						
						
									
										39
									
								
								action.yml
									
									
									
									
									
								
							@@ -1,35 +1,22 @@
 | 
				
			|||||||
name: 'Checkout'
 | 
					name: 'Checkout'
 | 
				
			||||||
description: 'Checkout a Git repository at a particular version'
 | 
					description: 'Checkout a Git repository'
 | 
				
			||||||
inputs: 
 | 
					inputs: 
 | 
				
			||||||
  repository:
 | 
					  repository:
 | 
				
			||||||
    description: 'Repository name with owner. For example, actions/checkout'
 | 
					    description: 'Repository name'
 | 
				
			||||||
    default: ${{ github.repository }}
 | 
					 | 
				
			||||||
  ref:
 | 
					  ref:
 | 
				
			||||||
    description: >
 | 
					    description: 'Ref to checkout (SHA, branch, tag)'
 | 
				
			||||||
      The branch, tag or SHA to checkout. When checking out the repository that
 | 
					 | 
				
			||||||
      triggered a workflow, this defaults to the reference or SHA for that
 | 
					 | 
				
			||||||
      event.  Otherwise, defaults to `master`.
 | 
					 | 
				
			||||||
  token:
 | 
					  token:
 | 
				
			||||||
    description: >
 | 
					    description: 'Access token for clone repository'
 | 
				
			||||||
      Auth token used to fetch the repository. The token is stored in the local
 | 
					 | 
				
			||||||
      git config, which enables your scripts to run authenticated git commands.
 | 
					 | 
				
			||||||
      The post-job step removes the token from the git config.
 | 
					 | 
				
			||||||
    default: ${{ github.token }}
 | 
					 | 
				
			||||||
  persist-credentials:
 | 
					 | 
				
			||||||
    description: 'Whether to persist the token in the git config'
 | 
					 | 
				
			||||||
    default: true
 | 
					 | 
				
			||||||
  path:
 | 
					 | 
				
			||||||
    description: 'Relative path under $GITHUB_WORKSPACE to place the repository'
 | 
					 | 
				
			||||||
  clean:
 | 
					  clean:
 | 
				
			||||||
    description: 'Whether to execute `git clean -ffdx && git reset --hard HEAD` before fetching'
 | 
					    description: 'If true, execute `execute git clean -ffdx && git reset --hard HEAD` before fetching'
 | 
				
			||||||
    default: true
 | 
					    default: true
 | 
				
			||||||
  fetch-depth:
 | 
					  submodules:
 | 
				
			||||||
    description: 'Number of commits to fetch. 0 indicates all history.'
 | 
					    description: 'Directory containing files to upload'
 | 
				
			||||||
    default: 1
 | 
					 | 
				
			||||||
  lfs:
 | 
					  lfs:
 | 
				
			||||||
    description: 'Whether to download Git-LFS files'
 | 
					    description: 'Whether to download Git-LFS files; defaults to false'
 | 
				
			||||||
    default: false
 | 
					  fetch-depth:
 | 
				
			||||||
 | 
					    description: 'The depth of commits to ask Git to fetch; defaults to no limit'  
 | 
				
			||||||
 | 
					  path:
 | 
				
			||||||
 | 
					    description: 'Optional path to check out source code'  
 | 
				
			||||||
runs:
 | 
					runs:
 | 
				
			||||||
  using: node12
 | 
					  plugin: 'checkout'
 | 
				
			||||||
  main: dist/index.js
 | 
					 | 
				
			||||||
  post: dist/index.js
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										16294
									
								
								dist/index.js
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										16294
									
								
								dist/index.js
									
									
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										13
									
								
								dist/problem-matcher.json
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										13
									
								
								dist/problem-matcher.json
									
									
									
									
										vendored
									
									
								
							@@ -1,13 +0,0 @@
 | 
				
			|||||||
{
 | 
					 | 
				
			||||||
    "problemMatcher": [
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            "owner": "checkout-git",
 | 
					 | 
				
			||||||
            "pattern": [
 | 
					 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                    "regexp": "^(fatal|error): (.*)$",
 | 
					 | 
				
			||||||
                    "message": 2
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            ]
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    ]
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -1,11 +0,0 @@
 | 
				
			|||||||
module.exports = {
 | 
					 | 
				
			||||||
  clearMocks: true,
 | 
					 | 
				
			||||||
  moduleFileExtensions: ['js', 'ts'],
 | 
					 | 
				
			||||||
  testEnvironment: 'node',
 | 
					 | 
				
			||||||
  testMatch: ['**/*.test.ts'],
 | 
					 | 
				
			||||||
  testRunner: 'jest-circus/runner',
 | 
					 | 
				
			||||||
  transform: {
 | 
					 | 
				
			||||||
    '^.+\\.ts$': 'ts-jest'
 | 
					 | 
				
			||||||
  },
 | 
					 | 
				
			||||||
  verbose: true
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
							
								
								
									
										7053
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										7053
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										55
									
								
								package.json
									
									
									
									
									
								
							
							
						
						
									
										55
									
								
								package.json
									
									
									
									
									
								
							@@ -1,55 +0,0 @@
 | 
				
			|||||||
{
 | 
					 | 
				
			||||||
  "name": "checkout",
 | 
					 | 
				
			||||||
  "version": "2.0.0",
 | 
					 | 
				
			||||||
  "description": "checkout action",
 | 
					 | 
				
			||||||
  "main": "lib/main.js",
 | 
					 | 
				
			||||||
  "scripts": {
 | 
					 | 
				
			||||||
    "build": "tsc",
 | 
					 | 
				
			||||||
    "format": "prettier --write **/*.ts",
 | 
					 | 
				
			||||||
    "format-check": "prettier --check **/*.ts",
 | 
					 | 
				
			||||||
    "lint": "eslint src/**/*.ts",
 | 
					 | 
				
			||||||
    "pack": "ncc build",
 | 
					 | 
				
			||||||
    "gendocs": "node lib/misc/generate-docs.js",
 | 
					 | 
				
			||||||
    "test": "jest",
 | 
					 | 
				
			||||||
    "all": "npm run build && npm run format && npm run lint && npm run pack && npm run gendocs && npm test"
 | 
					 | 
				
			||||||
  },
 | 
					 | 
				
			||||||
  "repository": {
 | 
					 | 
				
			||||||
    "type": "git",
 | 
					 | 
				
			||||||
    "url": "git+https://github.com/actions/checkout.git"
 | 
					 | 
				
			||||||
  },
 | 
					 | 
				
			||||||
  "keywords": [
 | 
					 | 
				
			||||||
    "github",
 | 
					 | 
				
			||||||
    "actions",
 | 
					 | 
				
			||||||
    "checkout"
 | 
					 | 
				
			||||||
  ],
 | 
					 | 
				
			||||||
  "author": "GitHub",
 | 
					 | 
				
			||||||
  "license": "MIT",
 | 
					 | 
				
			||||||
  "bugs": {
 | 
					 | 
				
			||||||
    "url": "https://github.com/actions/checkout/issues"
 | 
					 | 
				
			||||||
  },
 | 
					 | 
				
			||||||
  "homepage": "https://github.com/actions/checkout#readme",
 | 
					 | 
				
			||||||
  "dependencies": {
 | 
					 | 
				
			||||||
    "@actions/core": "^1.1.3",
 | 
					 | 
				
			||||||
    "@actions/exec": "^1.0.1",
 | 
					 | 
				
			||||||
    "@actions/github": "^2.0.0",
 | 
					 | 
				
			||||||
    "@actions/io": "^1.0.1",
 | 
					 | 
				
			||||||
    "@actions/tool-cache": "^1.1.2",
 | 
					 | 
				
			||||||
    "uuid": "^3.3.3"
 | 
					 | 
				
			||||||
  },
 | 
					 | 
				
			||||||
  "devDependencies": {
 | 
					 | 
				
			||||||
    "@types/jest": "^24.0.23",
 | 
					 | 
				
			||||||
    "@types/node": "^12.7.12",
 | 
					 | 
				
			||||||
    "@types/uuid": "^3.4.6",
 | 
					 | 
				
			||||||
    "@typescript-eslint/parser": "^2.8.0",
 | 
					 | 
				
			||||||
    "@zeit/ncc": "^0.20.5",
 | 
					 | 
				
			||||||
    "eslint": "^5.16.0",
 | 
					 | 
				
			||||||
    "eslint-plugin-github": "^2.0.0",
 | 
					 | 
				
			||||||
    "eslint-plugin-jest": "^22.21.0",
 | 
					 | 
				
			||||||
    "jest": "^24.9.0",
 | 
					 | 
				
			||||||
    "jest-circus": "^24.9.0",
 | 
					 | 
				
			||||||
    "js-yaml": "^3.13.1",
 | 
					 | 
				
			||||||
    "prettier": "^1.19.1",
 | 
					 | 
				
			||||||
    "ts-jest": "^24.2.0",
 | 
					 | 
				
			||||||
    "typescript": "^3.6.4"
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -1,77 +0,0 @@
 | 
				
			|||||||
import * as fs from 'fs'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export function directoryExistsSync(path: string, required?: boolean): boolean {
 | 
					 | 
				
			||||||
  if (!path) {
 | 
					 | 
				
			||||||
    throw new Error("Arg 'path' must not be empty")
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  let stats: fs.Stats
 | 
					 | 
				
			||||||
  try {
 | 
					 | 
				
			||||||
    stats = fs.statSync(path)
 | 
					 | 
				
			||||||
  } catch (error) {
 | 
					 | 
				
			||||||
    if (error.code === 'ENOENT') {
 | 
					 | 
				
			||||||
      if (!required) {
 | 
					 | 
				
			||||||
        return false
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      throw new Error(`Directory '${path}' does not exist`)
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    throw new Error(
 | 
					 | 
				
			||||||
      `Encountered an error when checking whether path '${path}' exists: ${error.message}`
 | 
					 | 
				
			||||||
    )
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  if (stats.isDirectory()) {
 | 
					 | 
				
			||||||
    return true
 | 
					 | 
				
			||||||
  } else if (!required) {
 | 
					 | 
				
			||||||
    return false
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  throw new Error(`Directory '${path}' does not exist`)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export function existsSync(path: string): boolean {
 | 
					 | 
				
			||||||
  if (!path) {
 | 
					 | 
				
			||||||
    throw new Error("Arg 'path' must not be empty")
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  try {
 | 
					 | 
				
			||||||
    fs.statSync(path)
 | 
					 | 
				
			||||||
  } catch (error) {
 | 
					 | 
				
			||||||
    if (error.code === 'ENOENT') {
 | 
					 | 
				
			||||||
      return false
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    throw new Error(
 | 
					 | 
				
			||||||
      `Encountered an error when checking whether path '${path}' exists: ${error.message}`
 | 
					 | 
				
			||||||
    )
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  return true
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export function fileExistsSync(path: string): boolean {
 | 
					 | 
				
			||||||
  if (!path) {
 | 
					 | 
				
			||||||
    throw new Error("Arg 'path' must not be empty")
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  let stats: fs.Stats
 | 
					 | 
				
			||||||
  try {
 | 
					 | 
				
			||||||
    stats = fs.statSync(path)
 | 
					 | 
				
			||||||
  } catch (error) {
 | 
					 | 
				
			||||||
    if (error.code === 'ENOENT') {
 | 
					 | 
				
			||||||
      return false
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    throw new Error(
 | 
					 | 
				
			||||||
      `Encountered an error when checking whether path '${path}' exists: ${error.message}`
 | 
					 | 
				
			||||||
    )
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  if (!stats.isDirectory()) {
 | 
					 | 
				
			||||||
    return true
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  return false
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -1,369 +0,0 @@
 | 
				
			|||||||
import * as core from '@actions/core'
 | 
					 | 
				
			||||||
import * as exec from '@actions/exec'
 | 
					 | 
				
			||||||
import * as fshelper from './fs-helper'
 | 
					 | 
				
			||||||
import * as io from '@actions/io'
 | 
					 | 
				
			||||||
import * as path from 'path'
 | 
					 | 
				
			||||||
import * as retryHelper from './retry-helper'
 | 
					 | 
				
			||||||
import {GitVersion} from './git-version'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// Auth header not supported before 2.9
 | 
					 | 
				
			||||||
// Wire protocol v2 not supported before 2.18
 | 
					 | 
				
			||||||
export const MinimumGitVersion = new GitVersion('2.18')
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export interface IGitCommandManager {
 | 
					 | 
				
			||||||
  branchDelete(remote: boolean, branch: string): Promise<void>
 | 
					 | 
				
			||||||
  branchExists(remote: boolean, pattern: string): Promise<boolean>
 | 
					 | 
				
			||||||
  branchList(remote: boolean): Promise<string[]>
 | 
					 | 
				
			||||||
  checkout(ref: string, startPoint: string): Promise<void>
 | 
					 | 
				
			||||||
  checkoutDetach(): Promise<void>
 | 
					 | 
				
			||||||
  config(configKey: string, configValue: string): Promise<void>
 | 
					 | 
				
			||||||
  configExists(configKey: string): Promise<boolean>
 | 
					 | 
				
			||||||
  fetch(fetchDepth: number, refSpec: string[]): Promise<void>
 | 
					 | 
				
			||||||
  getWorkingDirectory(): string
 | 
					 | 
				
			||||||
  init(): Promise<void>
 | 
					 | 
				
			||||||
  isDetached(): Promise<boolean>
 | 
					 | 
				
			||||||
  lfsFetch(ref: string): Promise<void>
 | 
					 | 
				
			||||||
  lfsInstall(): Promise<void>
 | 
					 | 
				
			||||||
  log1(): Promise<void>
 | 
					 | 
				
			||||||
  remoteAdd(remoteName: string, remoteUrl: string): Promise<void>
 | 
					 | 
				
			||||||
  tagExists(pattern: string): Promise<boolean>
 | 
					 | 
				
			||||||
  tryClean(): Promise<boolean>
 | 
					 | 
				
			||||||
  tryConfigUnset(configKey: string): Promise<boolean>
 | 
					 | 
				
			||||||
  tryDisableAutomaticGarbageCollection(): Promise<boolean>
 | 
					 | 
				
			||||||
  tryGetFetchUrl(): Promise<string>
 | 
					 | 
				
			||||||
  tryReset(): Promise<boolean>
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export async function CreateCommandManager(
 | 
					 | 
				
			||||||
  workingDirectory: string,
 | 
					 | 
				
			||||||
  lfs: boolean
 | 
					 | 
				
			||||||
): Promise<IGitCommandManager> {
 | 
					 | 
				
			||||||
  return await GitCommandManager.createCommandManager(workingDirectory, lfs)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class GitCommandManager {
 | 
					 | 
				
			||||||
  private gitEnv = {
 | 
					 | 
				
			||||||
    GIT_TERMINAL_PROMPT: '0', // Disable git prompt
 | 
					 | 
				
			||||||
    GCM_INTERACTIVE: 'Never' // Disable prompting for git credential manager
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  private gitPath = ''
 | 
					 | 
				
			||||||
  private lfs = false
 | 
					 | 
				
			||||||
  private workingDirectory = ''
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // Private constructor; use createCommandManager()
 | 
					 | 
				
			||||||
  private constructor() {}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  async branchDelete(remote: boolean, branch: string): Promise<void> {
 | 
					 | 
				
			||||||
    const args = ['branch', '--delete', '--force']
 | 
					 | 
				
			||||||
    if (remote) {
 | 
					 | 
				
			||||||
      args.push('--remote')
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    args.push(branch)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    await this.execGit(args)
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  async branchExists(remote: boolean, pattern: string): Promise<boolean> {
 | 
					 | 
				
			||||||
    const args = ['branch', '--list']
 | 
					 | 
				
			||||||
    if (remote) {
 | 
					 | 
				
			||||||
      args.push('--remote')
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    args.push(pattern)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    const output = await this.execGit(args)
 | 
					 | 
				
			||||||
    return !!output.stdout.trim()
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  async branchList(remote: boolean): Promise<string[]> {
 | 
					 | 
				
			||||||
    const result: string[] = []
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // Note, this implementation uses "rev-parse --symbolic" because the output from
 | 
					 | 
				
			||||||
    // "branch --list" is more difficult when in a detached HEAD state.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    const args = ['rev-parse', '--symbolic']
 | 
					 | 
				
			||||||
    if (remote) {
 | 
					 | 
				
			||||||
      args.push('--remotes=origin')
 | 
					 | 
				
			||||||
    } else {
 | 
					 | 
				
			||||||
      args.push('--branches')
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    const output = await this.execGit(args)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    for (let branch of output.stdout.trim().split('\n')) {
 | 
					 | 
				
			||||||
      branch = branch.trim()
 | 
					 | 
				
			||||||
      if (branch) {
 | 
					 | 
				
			||||||
        result.push(branch)
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return result
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  async checkout(ref: string, startPoint: string): Promise<void> {
 | 
					 | 
				
			||||||
    const args = ['checkout', '--progress', '--force']
 | 
					 | 
				
			||||||
    if (startPoint) {
 | 
					 | 
				
			||||||
      args.push('-B', ref, startPoint)
 | 
					 | 
				
			||||||
    } else {
 | 
					 | 
				
			||||||
      args.push(ref)
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    await this.execGit(args)
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  async checkoutDetach(): Promise<void> {
 | 
					 | 
				
			||||||
    const args = ['checkout', '--detach']
 | 
					 | 
				
			||||||
    await this.execGit(args)
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  async config(configKey: string, configValue: string): Promise<void> {
 | 
					 | 
				
			||||||
    await this.execGit(['config', '--local', configKey, configValue])
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  async configExists(configKey: string): Promise<boolean> {
 | 
					 | 
				
			||||||
    const pattern = configKey.replace(/[^a-zA-Z0-9_]/g, x => {
 | 
					 | 
				
			||||||
      return `\\${x}`
 | 
					 | 
				
			||||||
    })
 | 
					 | 
				
			||||||
    const output = await this.execGit(
 | 
					 | 
				
			||||||
      ['config', '--local', '--name-only', '--get-regexp', pattern],
 | 
					 | 
				
			||||||
      true
 | 
					 | 
				
			||||||
    )
 | 
					 | 
				
			||||||
    return output.exitCode === 0
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  async fetch(fetchDepth: number, refSpec: string[]): Promise<void> {
 | 
					 | 
				
			||||||
    const args = [
 | 
					 | 
				
			||||||
      '-c',
 | 
					 | 
				
			||||||
      'protocol.version=2',
 | 
					 | 
				
			||||||
      'fetch',
 | 
					 | 
				
			||||||
      '--no-tags',
 | 
					 | 
				
			||||||
      '--prune',
 | 
					 | 
				
			||||||
      '--progress',
 | 
					 | 
				
			||||||
      '--no-recurse-submodules'
 | 
					 | 
				
			||||||
    ]
 | 
					 | 
				
			||||||
    if (fetchDepth > 0) {
 | 
					 | 
				
			||||||
      args.push(`--depth=${fetchDepth}`)
 | 
					 | 
				
			||||||
    } else if (
 | 
					 | 
				
			||||||
      fshelper.fileExistsSync(
 | 
					 | 
				
			||||||
        path.join(this.workingDirectory, '.git', 'shallow')
 | 
					 | 
				
			||||||
      )
 | 
					 | 
				
			||||||
    ) {
 | 
					 | 
				
			||||||
      args.push('--unshallow')
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    args.push('origin')
 | 
					 | 
				
			||||||
    for (const arg of refSpec) {
 | 
					 | 
				
			||||||
      args.push(arg)
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    const that = this
 | 
					 | 
				
			||||||
    await retryHelper.execute(async () => {
 | 
					 | 
				
			||||||
      await that.execGit(args)
 | 
					 | 
				
			||||||
    })
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  getWorkingDirectory(): string {
 | 
					 | 
				
			||||||
    return this.workingDirectory
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  async init(): Promise<void> {
 | 
					 | 
				
			||||||
    await this.execGit(['init', this.workingDirectory])
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  async isDetached(): Promise<boolean> {
 | 
					 | 
				
			||||||
    // Note, this implementation uses "branch --show-current" because
 | 
					 | 
				
			||||||
    // "rev-parse --symbolic-full-name HEAD" can fail on a new repo
 | 
					 | 
				
			||||||
    // with nothing checked out.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    const output = await this.execGit(['branch', '--show-current'])
 | 
					 | 
				
			||||||
    return output.stdout.trim() === ''
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  async lfsFetch(ref: string): Promise<void> {
 | 
					 | 
				
			||||||
    const args = ['lfs', 'fetch', 'origin', ref]
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    const that = this
 | 
					 | 
				
			||||||
    await retryHelper.execute(async () => {
 | 
					 | 
				
			||||||
      await that.execGit(args)
 | 
					 | 
				
			||||||
    })
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  async lfsInstall(): Promise<void> {
 | 
					 | 
				
			||||||
    await this.execGit(['lfs', 'install', '--local'])
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  async log1(): Promise<void> {
 | 
					 | 
				
			||||||
    await this.execGit(['log', '-1'])
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  async remoteAdd(remoteName: string, remoteUrl: string): Promise<void> {
 | 
					 | 
				
			||||||
    await this.execGit(['remote', 'add', remoteName, remoteUrl])
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  async tagExists(pattern: string): Promise<boolean> {
 | 
					 | 
				
			||||||
    const output = await this.execGit(['tag', '--list', pattern])
 | 
					 | 
				
			||||||
    return !!output.stdout.trim()
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  async tryClean(): Promise<boolean> {
 | 
					 | 
				
			||||||
    const output = await this.execGit(['clean', '-ffdx'], true)
 | 
					 | 
				
			||||||
    return output.exitCode === 0
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  async tryConfigUnset(configKey: string): Promise<boolean> {
 | 
					 | 
				
			||||||
    const output = await this.execGit(
 | 
					 | 
				
			||||||
      ['config', '--local', '--unset-all', configKey],
 | 
					 | 
				
			||||||
      true
 | 
					 | 
				
			||||||
    )
 | 
					 | 
				
			||||||
    return output.exitCode === 0
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  async tryDisableAutomaticGarbageCollection(): Promise<boolean> {
 | 
					 | 
				
			||||||
    const output = await this.execGit(
 | 
					 | 
				
			||||||
      ['config', '--local', 'gc.auto', '0'],
 | 
					 | 
				
			||||||
      true
 | 
					 | 
				
			||||||
    )
 | 
					 | 
				
			||||||
    return output.exitCode === 0
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  async tryGetFetchUrl(): Promise<string> {
 | 
					 | 
				
			||||||
    const output = await this.execGit(
 | 
					 | 
				
			||||||
      ['config', '--local', '--get', 'remote.origin.url'],
 | 
					 | 
				
			||||||
      true
 | 
					 | 
				
			||||||
    )
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (output.exitCode !== 0) {
 | 
					 | 
				
			||||||
      return ''
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    const stdout = output.stdout.trim()
 | 
					 | 
				
			||||||
    if (stdout.includes('\n')) {
 | 
					 | 
				
			||||||
      return ''
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return stdout
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  async tryReset(): Promise<boolean> {
 | 
					 | 
				
			||||||
    const output = await this.execGit(['reset', '--hard', 'HEAD'], true)
 | 
					 | 
				
			||||||
    return output.exitCode === 0
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  static async createCommandManager(
 | 
					 | 
				
			||||||
    workingDirectory: string,
 | 
					 | 
				
			||||||
    lfs: boolean
 | 
					 | 
				
			||||||
  ): Promise<GitCommandManager> {
 | 
					 | 
				
			||||||
    const result = new GitCommandManager()
 | 
					 | 
				
			||||||
    await result.initializeCommandManager(workingDirectory, lfs)
 | 
					 | 
				
			||||||
    return result
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  private async execGit(
 | 
					 | 
				
			||||||
    args: string[],
 | 
					 | 
				
			||||||
    allowAllExitCodes = false
 | 
					 | 
				
			||||||
  ): Promise<GitOutput> {
 | 
					 | 
				
			||||||
    fshelper.directoryExistsSync(this.workingDirectory, true)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    const result = new GitOutput()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    const env = {}
 | 
					 | 
				
			||||||
    for (const key of Object.keys(process.env)) {
 | 
					 | 
				
			||||||
      env[key] = process.env[key]
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    for (const key of Object.keys(this.gitEnv)) {
 | 
					 | 
				
			||||||
      env[key] = this.gitEnv[key]
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    const stdout: string[] = []
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    const options = {
 | 
					 | 
				
			||||||
      cwd: this.workingDirectory,
 | 
					 | 
				
			||||||
      env,
 | 
					 | 
				
			||||||
      ignoreReturnCode: allowAllExitCodes,
 | 
					 | 
				
			||||||
      listeners: {
 | 
					 | 
				
			||||||
        stdout: (data: Buffer) => {
 | 
					 | 
				
			||||||
          stdout.push(data.toString())
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    result.exitCode = await exec.exec(`"${this.gitPath}"`, args, options)
 | 
					 | 
				
			||||||
    result.stdout = stdout.join('')
 | 
					 | 
				
			||||||
    return result
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  private async initializeCommandManager(
 | 
					 | 
				
			||||||
    workingDirectory: string,
 | 
					 | 
				
			||||||
    lfs: boolean
 | 
					 | 
				
			||||||
  ): Promise<void> {
 | 
					 | 
				
			||||||
    this.workingDirectory = workingDirectory
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // Git-lfs will try to pull down assets if any of the local/user/system setting exist.
 | 
					 | 
				
			||||||
    // If the user didn't enable `LFS` in their pipeline definition, disable LFS fetch/checkout.
 | 
					 | 
				
			||||||
    this.lfs = lfs
 | 
					 | 
				
			||||||
    if (!this.lfs) {
 | 
					 | 
				
			||||||
      this.gitEnv['GIT_LFS_SKIP_SMUDGE'] = '1'
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    this.gitPath = await io.which('git', true)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // Git version
 | 
					 | 
				
			||||||
    core.debug('Getting git version')
 | 
					 | 
				
			||||||
    let gitVersion = new GitVersion()
 | 
					 | 
				
			||||||
    let gitOutput = await this.execGit(['version'])
 | 
					 | 
				
			||||||
    let stdout = gitOutput.stdout.trim()
 | 
					 | 
				
			||||||
    if (!stdout.includes('\n')) {
 | 
					 | 
				
			||||||
      const match = stdout.match(/\d+\.\d+(\.\d+)?/)
 | 
					 | 
				
			||||||
      if (match) {
 | 
					 | 
				
			||||||
        gitVersion = new GitVersion(match[0])
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    if (!gitVersion.isValid()) {
 | 
					 | 
				
			||||||
      throw new Error('Unable to determine git version')
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // Minimum git version
 | 
					 | 
				
			||||||
    if (!gitVersion.checkMinimum(MinimumGitVersion)) {
 | 
					 | 
				
			||||||
      throw new Error(
 | 
					 | 
				
			||||||
        `Minimum required git version is ${MinimumGitVersion}. Your git ('${this.gitPath}') is ${gitVersion}`
 | 
					 | 
				
			||||||
      )
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (this.lfs) {
 | 
					 | 
				
			||||||
      // Git-lfs version
 | 
					 | 
				
			||||||
      core.debug('Getting git-lfs version')
 | 
					 | 
				
			||||||
      let gitLfsVersion = new GitVersion()
 | 
					 | 
				
			||||||
      const gitLfsPath = await io.which('git-lfs', true)
 | 
					 | 
				
			||||||
      gitOutput = await this.execGit(['lfs', 'version'])
 | 
					 | 
				
			||||||
      stdout = gitOutput.stdout.trim()
 | 
					 | 
				
			||||||
      if (!stdout.includes('\n')) {
 | 
					 | 
				
			||||||
        const match = stdout.match(/\d+\.\d+(\.\d+)?/)
 | 
					 | 
				
			||||||
        if (match) {
 | 
					 | 
				
			||||||
          gitLfsVersion = new GitVersion(match[0])
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
      if (!gitLfsVersion.isValid()) {
 | 
					 | 
				
			||||||
        throw new Error('Unable to determine git-lfs version')
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      // Minimum git-lfs version
 | 
					 | 
				
			||||||
      // Note:
 | 
					 | 
				
			||||||
      // - Auth header not supported before 2.1
 | 
					 | 
				
			||||||
      const minimumGitLfsVersion = new GitVersion('2.1')
 | 
					 | 
				
			||||||
      if (!gitLfsVersion.checkMinimum(minimumGitLfsVersion)) {
 | 
					 | 
				
			||||||
        throw new Error(
 | 
					 | 
				
			||||||
          `Minimum required git-lfs version is ${minimumGitLfsVersion}. Your git-lfs ('${gitLfsPath}') is ${gitLfsVersion}`
 | 
					 | 
				
			||||||
        )
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // Set the user agent
 | 
					 | 
				
			||||||
    const gitHttpUserAgent = `git/${gitVersion} (github-actions-checkout)`
 | 
					 | 
				
			||||||
    core.debug(`Set git useragent to: ${gitHttpUserAgent}`)
 | 
					 | 
				
			||||||
    this.gitEnv['GIT_HTTP_USER_AGENT'] = gitHttpUserAgent
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class GitOutput {
 | 
					 | 
				
			||||||
  stdout = ''
 | 
					 | 
				
			||||||
  exitCode = 0
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -1,303 +0,0 @@
 | 
				
			|||||||
import * as core from '@actions/core'
 | 
					 | 
				
			||||||
import * as fs from 'fs'
 | 
					 | 
				
			||||||
import * as fsHelper from './fs-helper'
 | 
					 | 
				
			||||||
import * as gitCommandManager from './git-command-manager'
 | 
					 | 
				
			||||||
import * as githubApiHelper from './github-api-helper'
 | 
					 | 
				
			||||||
import * as io from '@actions/io'
 | 
					 | 
				
			||||||
import * as path from 'path'
 | 
					 | 
				
			||||||
import * as refHelper from './ref-helper'
 | 
					 | 
				
			||||||
import * as stateHelper from './state-helper'
 | 
					 | 
				
			||||||
import {IGitCommandManager} from './git-command-manager'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const authConfigKey = `http.https://github.com/.extraheader`
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export interface ISourceSettings {
 | 
					 | 
				
			||||||
  repositoryPath: string
 | 
					 | 
				
			||||||
  repositoryOwner: string
 | 
					 | 
				
			||||||
  repositoryName: string
 | 
					 | 
				
			||||||
  ref: string
 | 
					 | 
				
			||||||
  commit: string
 | 
					 | 
				
			||||||
  clean: boolean
 | 
					 | 
				
			||||||
  fetchDepth: number
 | 
					 | 
				
			||||||
  lfs: boolean
 | 
					 | 
				
			||||||
  authToken: string
 | 
					 | 
				
			||||||
  persistCredentials: boolean
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export async function getSource(settings: ISourceSettings): Promise<void> {
 | 
					 | 
				
			||||||
  // Repository URL
 | 
					 | 
				
			||||||
  core.info(
 | 
					 | 
				
			||||||
    `Syncing repository: ${settings.repositoryOwner}/${settings.repositoryName}`
 | 
					 | 
				
			||||||
  )
 | 
					 | 
				
			||||||
  const repositoryUrl = `https://github.com/${encodeURIComponent(
 | 
					 | 
				
			||||||
    settings.repositoryOwner
 | 
					 | 
				
			||||||
  )}/${encodeURIComponent(settings.repositoryName)}`
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // Remove conflicting file path
 | 
					 | 
				
			||||||
  if (fsHelper.fileExistsSync(settings.repositoryPath)) {
 | 
					 | 
				
			||||||
    await io.rmRF(settings.repositoryPath)
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // Create directory
 | 
					 | 
				
			||||||
  let isExisting = true
 | 
					 | 
				
			||||||
  if (!fsHelper.directoryExistsSync(settings.repositoryPath)) {
 | 
					 | 
				
			||||||
    isExisting = false
 | 
					 | 
				
			||||||
    await io.mkdirP(settings.repositoryPath)
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // Git command manager
 | 
					 | 
				
			||||||
  const git = await getGitCommandManager(settings)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // Prepare existing directory, otherwise recreate
 | 
					 | 
				
			||||||
  if (isExisting) {
 | 
					 | 
				
			||||||
    await prepareExistingDirectory(
 | 
					 | 
				
			||||||
      git,
 | 
					 | 
				
			||||||
      settings.repositoryPath,
 | 
					 | 
				
			||||||
      repositoryUrl,
 | 
					 | 
				
			||||||
      settings.clean
 | 
					 | 
				
			||||||
    )
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  if (!git) {
 | 
					 | 
				
			||||||
    // Downloading using REST API
 | 
					 | 
				
			||||||
    core.info(`The repository will be downloaded using the GitHub REST API`)
 | 
					 | 
				
			||||||
    core.info(
 | 
					 | 
				
			||||||
      `To create a local Git repository instead, add Git ${gitCommandManager.MinimumGitVersion} or higher to the PATH`
 | 
					 | 
				
			||||||
    )
 | 
					 | 
				
			||||||
    await githubApiHelper.downloadRepository(
 | 
					 | 
				
			||||||
      settings.authToken,
 | 
					 | 
				
			||||||
      settings.repositoryOwner,
 | 
					 | 
				
			||||||
      settings.repositoryName,
 | 
					 | 
				
			||||||
      settings.ref,
 | 
					 | 
				
			||||||
      settings.commit,
 | 
					 | 
				
			||||||
      settings.repositoryPath
 | 
					 | 
				
			||||||
    )
 | 
					 | 
				
			||||||
  } else {
 | 
					 | 
				
			||||||
    // Save state for POST action
 | 
					 | 
				
			||||||
    stateHelper.setRepositoryPath(settings.repositoryPath)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // Initialize the repository
 | 
					 | 
				
			||||||
    if (
 | 
					 | 
				
			||||||
      !fsHelper.directoryExistsSync(path.join(settings.repositoryPath, '.git'))
 | 
					 | 
				
			||||||
    ) {
 | 
					 | 
				
			||||||
      await git.init()
 | 
					 | 
				
			||||||
      await git.remoteAdd('origin', repositoryUrl)
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // Disable 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.`
 | 
					 | 
				
			||||||
      )
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // Remove possible previous extraheader
 | 
					 | 
				
			||||||
    await removeGitConfig(git, authConfigKey)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    try {
 | 
					 | 
				
			||||||
      // Config auth token
 | 
					 | 
				
			||||||
      await configureAuthToken(git, settings.authToken)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      // LFS install
 | 
					 | 
				
			||||||
      if (settings.lfs) {
 | 
					 | 
				
			||||||
        await git.lfsInstall()
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      // Fetch
 | 
					 | 
				
			||||||
      const refSpec = refHelper.getRefSpec(settings.ref, settings.commit)
 | 
					 | 
				
			||||||
      await git.fetch(settings.fetchDepth, refSpec)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      // Checkout info
 | 
					 | 
				
			||||||
      const checkoutInfo = await refHelper.getCheckoutInfo(
 | 
					 | 
				
			||||||
        git,
 | 
					 | 
				
			||||||
        settings.ref,
 | 
					 | 
				
			||||||
        settings.commit
 | 
					 | 
				
			||||||
      )
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      // LFS fetch
 | 
					 | 
				
			||||||
      // Explicit lfs-fetch to avoid slow checkout (fetches one lfs object at a time).
 | 
					 | 
				
			||||||
      // Explicit lfs fetch will fetch lfs objects in parallel.
 | 
					 | 
				
			||||||
      if (settings.lfs) {
 | 
					 | 
				
			||||||
        await git.lfsFetch(checkoutInfo.startPoint || checkoutInfo.ref)
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      // Checkout
 | 
					 | 
				
			||||||
      await git.checkout(checkoutInfo.ref, checkoutInfo.startPoint)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      // Dump some info about the checked out commit
 | 
					 | 
				
			||||||
      await git.log1()
 | 
					 | 
				
			||||||
    } finally {
 | 
					 | 
				
			||||||
      if (!settings.persistCredentials) {
 | 
					 | 
				
			||||||
        await removeGitConfig(git, authConfigKey)
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export async function cleanup(repositoryPath: string): Promise<void> {
 | 
					 | 
				
			||||||
  // Repo exists?
 | 
					 | 
				
			||||||
  if (!fsHelper.fileExistsSync(path.join(repositoryPath, '.git', 'config'))) {
 | 
					 | 
				
			||||||
    return
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  fsHelper.directoryExistsSync(repositoryPath, true)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // Remove the config key
 | 
					 | 
				
			||||||
  const git = await gitCommandManager.CreateCommandManager(
 | 
					 | 
				
			||||||
    repositoryPath,
 | 
					 | 
				
			||||||
    false
 | 
					 | 
				
			||||||
  )
 | 
					 | 
				
			||||||
  await removeGitConfig(git, authConfigKey)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
async function getGitCommandManager(
 | 
					 | 
				
			||||||
  settings: ISourceSettings
 | 
					 | 
				
			||||||
): Promise<IGitCommandManager> {
 | 
					 | 
				
			||||||
  core.info(`Working directory is '${settings.repositoryPath}'`)
 | 
					 | 
				
			||||||
  let git = (null as unknown) as IGitCommandManager
 | 
					 | 
				
			||||||
  try {
 | 
					 | 
				
			||||||
    return await gitCommandManager.CreateCommandManager(
 | 
					 | 
				
			||||||
      settings.repositoryPath,
 | 
					 | 
				
			||||||
      settings.lfs
 | 
					 | 
				
			||||||
    )
 | 
					 | 
				
			||||||
  } catch (err) {
 | 
					 | 
				
			||||||
    // Git is required for LFS
 | 
					 | 
				
			||||||
    if (settings.lfs) {
 | 
					 | 
				
			||||||
      throw err
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // Otherwise fallback to REST API
 | 
					 | 
				
			||||||
    return (null as unknown) as IGitCommandManager
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
async function prepareExistingDirectory(
 | 
					 | 
				
			||||||
  git: IGitCommandManager,
 | 
					 | 
				
			||||||
  repositoryPath: string,
 | 
					 | 
				
			||||||
  repositoryUrl: string,
 | 
					 | 
				
			||||||
  clean: boolean
 | 
					 | 
				
			||||||
): Promise<void> {
 | 
					 | 
				
			||||||
  let remove = false
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // Check whether using git or REST API
 | 
					 | 
				
			||||||
  if (!git) {
 | 
					 | 
				
			||||||
    remove = true
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  // Fetch URL does not match
 | 
					 | 
				
			||||||
  else if (
 | 
					 | 
				
			||||||
    !fsHelper.directoryExistsSync(path.join(repositoryPath, '.git')) ||
 | 
					 | 
				
			||||||
    repositoryUrl !== (await git.tryGetFetchUrl())
 | 
					 | 
				
			||||||
  ) {
 | 
					 | 
				
			||||||
    remove = true
 | 
					 | 
				
			||||||
  } else {
 | 
					 | 
				
			||||||
    // Delete any index.lock and shallow.lock left by a previously canceled run or crashed git process
 | 
					 | 
				
			||||||
    const lockPaths = [
 | 
					 | 
				
			||||||
      path.join(repositoryPath, '.git', 'index.lock'),
 | 
					 | 
				
			||||||
      path.join(repositoryPath, '.git', 'shallow.lock')
 | 
					 | 
				
			||||||
    ]
 | 
					 | 
				
			||||||
    for (const lockPath of lockPaths) {
 | 
					 | 
				
			||||||
      try {
 | 
					 | 
				
			||||||
        await io.rmRF(lockPath)
 | 
					 | 
				
			||||||
      } catch (error) {
 | 
					 | 
				
			||||||
        core.debug(`Unable to delete '${lockPath}'. ${error.message}`)
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    try {
 | 
					 | 
				
			||||||
      // Checkout detached HEAD
 | 
					 | 
				
			||||||
      if (!(await git.isDetached())) {
 | 
					 | 
				
			||||||
        await git.checkoutDetach()
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      // Remove all refs/heads/*
 | 
					 | 
				
			||||||
      let branches = await git.branchList(false)
 | 
					 | 
				
			||||||
      for (const branch of branches) {
 | 
					 | 
				
			||||||
        await git.branchDelete(false, branch)
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      // Remove all refs/remotes/origin/* to avoid conflicts
 | 
					 | 
				
			||||||
      branches = await git.branchList(true)
 | 
					 | 
				
			||||||
      for (const branch of branches) {
 | 
					 | 
				
			||||||
        await git.branchDelete(true, branch)
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      // Clean
 | 
					 | 
				
			||||||
      if (clean) {
 | 
					 | 
				
			||||||
        if (!(await git.tryClean())) {
 | 
					 | 
				
			||||||
          core.debug(
 | 
					 | 
				
			||||||
            `The clean command failed. This might be caused by: 1) path too long, 2) permission issue, or 3) file in use. For futher investigation, manually run 'git clean -ffdx' on the directory '${repositoryPath}'.`
 | 
					 | 
				
			||||||
          )
 | 
					 | 
				
			||||||
          remove = true
 | 
					 | 
				
			||||||
        } else if (!(await git.tryReset())) {
 | 
					 | 
				
			||||||
          remove = true
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if (remove) {
 | 
					 | 
				
			||||||
          core.warning(
 | 
					 | 
				
			||||||
            `Unable to clean or reset the repository. The repository will be recreated instead.`
 | 
					 | 
				
			||||||
          )
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    } catch (error) {
 | 
					 | 
				
			||||||
      core.warning(
 | 
					 | 
				
			||||||
        `Unable to prepare the existing repository. The repository will be recreated instead.`
 | 
					 | 
				
			||||||
      )
 | 
					 | 
				
			||||||
      remove = true
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  if (remove) {
 | 
					 | 
				
			||||||
    // Delete the contents of the directory. Don't delete the directory itself
 | 
					 | 
				
			||||||
    // since it might be the current working directory.
 | 
					 | 
				
			||||||
    core.info(`Deleting the contents of '${repositoryPath}'`)
 | 
					 | 
				
			||||||
    for (const file of await fs.promises.readdir(repositoryPath)) {
 | 
					 | 
				
			||||||
      await io.rmRF(path.join(repositoryPath, file))
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
async function configureAuthToken(
 | 
					 | 
				
			||||||
  git: IGitCommandManager,
 | 
					 | 
				
			||||||
  authToken: string
 | 
					 | 
				
			||||||
): Promise<void> {
 | 
					 | 
				
			||||||
  // Configure a placeholder value. This approach avoids the credential being captured
 | 
					 | 
				
			||||||
  // by process creation audit events, which are commonly logged. For more information,
 | 
					 | 
				
			||||||
  // refer to https://docs.microsoft.com/en-us/windows-server/identity/ad-ds/manage/component-updates/command-line-process-auditing
 | 
					 | 
				
			||||||
  const placeholder = `AUTHORIZATION: basic ***`
 | 
					 | 
				
			||||||
  await git.config(authConfigKey, placeholder)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // Determine the basic credential value
 | 
					 | 
				
			||||||
  const basicCredential = Buffer.from(
 | 
					 | 
				
			||||||
    `x-access-token:${authToken}`,
 | 
					 | 
				
			||||||
    'utf8'
 | 
					 | 
				
			||||||
  ).toString('base64')
 | 
					 | 
				
			||||||
  core.setSecret(basicCredential)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // Replace the value in the config file
 | 
					 | 
				
			||||||
  const configPath = path.join(git.getWorkingDirectory(), '.git', 'config')
 | 
					 | 
				
			||||||
  let content = (await fs.promises.readFile(configPath)).toString()
 | 
					 | 
				
			||||||
  const placeholderIndex = content.indexOf(placeholder)
 | 
					 | 
				
			||||||
  if (
 | 
					 | 
				
			||||||
    placeholderIndex < 0 ||
 | 
					 | 
				
			||||||
    placeholderIndex != content.lastIndexOf(placeholder)
 | 
					 | 
				
			||||||
  ) {
 | 
					 | 
				
			||||||
    throw new Error('Unable to replace auth placeholder in .git/config')
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  content = content.replace(
 | 
					 | 
				
			||||||
    placeholder,
 | 
					 | 
				
			||||||
    `AUTHORIZATION: basic ${basicCredential}`
 | 
					 | 
				
			||||||
  )
 | 
					 | 
				
			||||||
  await fs.promises.writeFile(configPath, content)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
async function removeGitConfig(
 | 
					 | 
				
			||||||
  git: IGitCommandManager,
 | 
					 | 
				
			||||||
  configKey: string
 | 
					 | 
				
			||||||
): Promise<void> {
 | 
					 | 
				
			||||||
  if (
 | 
					 | 
				
			||||||
    (await git.configExists(configKey)) &&
 | 
					 | 
				
			||||||
    !(await git.tryConfigUnset(configKey))
 | 
					 | 
				
			||||||
  ) {
 | 
					 | 
				
			||||||
    // Load the config contents
 | 
					 | 
				
			||||||
    core.warning(`Failed to remove '${configKey}' from the git config`)
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -1,77 +0,0 @@
 | 
				
			|||||||
export class GitVersion {
 | 
					 | 
				
			||||||
  private readonly major: number = NaN
 | 
					 | 
				
			||||||
  private readonly minor: number = NaN
 | 
					 | 
				
			||||||
  private readonly patch: number = NaN
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  /**
 | 
					 | 
				
			||||||
   * Used for comparing the version of git and git-lfs against the minimum required version
 | 
					 | 
				
			||||||
   * @param version the version string, e.g. 1.2 or 1.2.3
 | 
					 | 
				
			||||||
   */
 | 
					 | 
				
			||||||
  constructor(version?: string) {
 | 
					 | 
				
			||||||
    if (version) {
 | 
					 | 
				
			||||||
      const match = version.match(/^(\d+)\.(\d+)(\.(\d+))?$/)
 | 
					 | 
				
			||||||
      if (match) {
 | 
					 | 
				
			||||||
        this.major = Number(match[1])
 | 
					 | 
				
			||||||
        this.minor = Number(match[2])
 | 
					 | 
				
			||||||
        if (match[4]) {
 | 
					 | 
				
			||||||
          this.patch = Number(match[4])
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  /**
 | 
					 | 
				
			||||||
   * Compares the instance against a minimum required version
 | 
					 | 
				
			||||||
   * @param minimum Minimum version
 | 
					 | 
				
			||||||
   */
 | 
					 | 
				
			||||||
  checkMinimum(minimum: GitVersion): boolean {
 | 
					 | 
				
			||||||
    if (!minimum.isValid()) {
 | 
					 | 
				
			||||||
      throw new Error('Arg minimum is not a valid version')
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // Major is insufficient
 | 
					 | 
				
			||||||
    if (this.major < minimum.major) {
 | 
					 | 
				
			||||||
      return false
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // Major is equal
 | 
					 | 
				
			||||||
    if (this.major === minimum.major) {
 | 
					 | 
				
			||||||
      // Minor is insufficient
 | 
					 | 
				
			||||||
      if (this.minor < minimum.minor) {
 | 
					 | 
				
			||||||
        return false
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      // Minor is equal
 | 
					 | 
				
			||||||
      if (this.minor === minimum.minor) {
 | 
					 | 
				
			||||||
        // Patch is insufficient
 | 
					 | 
				
			||||||
        if (this.patch && this.patch < (minimum.patch || 0)) {
 | 
					 | 
				
			||||||
          return false
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return true
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  /**
 | 
					 | 
				
			||||||
   * Indicates whether the instance was constructed from a valid version string
 | 
					 | 
				
			||||||
   */
 | 
					 | 
				
			||||||
  isValid(): boolean {
 | 
					 | 
				
			||||||
    return !isNaN(this.major)
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  /**
 | 
					 | 
				
			||||||
   * Returns the version as a string, e.g. 1.2 or 1.2.3
 | 
					 | 
				
			||||||
   */
 | 
					 | 
				
			||||||
  toString(): string {
 | 
					 | 
				
			||||||
    let result = ''
 | 
					 | 
				
			||||||
    if (this.isValid()) {
 | 
					 | 
				
			||||||
      result = `${this.major}.${this.minor}`
 | 
					 | 
				
			||||||
      if (!isNaN(this.patch)) {
 | 
					 | 
				
			||||||
        result += `.${this.patch}`
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return result
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -1,92 +0,0 @@
 | 
				
			|||||||
import * as assert from 'assert'
 | 
					 | 
				
			||||||
import * as core from '@actions/core'
 | 
					 | 
				
			||||||
import * as fs from 'fs'
 | 
					 | 
				
			||||||
import * as github from '@actions/github'
 | 
					 | 
				
			||||||
import * as io from '@actions/io'
 | 
					 | 
				
			||||||
import * as path from 'path'
 | 
					 | 
				
			||||||
import * as retryHelper from './retry-helper'
 | 
					 | 
				
			||||||
import * as toolCache from '@actions/tool-cache'
 | 
					 | 
				
			||||||
import {default as uuid} from 'uuid/v4'
 | 
					 | 
				
			||||||
import {ReposGetArchiveLinkParams} from '@octokit/rest'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const IS_WINDOWS = process.platform === 'win32'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export async function downloadRepository(
 | 
					 | 
				
			||||||
  authToken: string,
 | 
					 | 
				
			||||||
  owner: string,
 | 
					 | 
				
			||||||
  repo: string,
 | 
					 | 
				
			||||||
  ref: string,
 | 
					 | 
				
			||||||
  commit: string,
 | 
					 | 
				
			||||||
  repositoryPath: string
 | 
					 | 
				
			||||||
): Promise<void> {
 | 
					 | 
				
			||||||
  // Download the archive
 | 
					 | 
				
			||||||
  let archiveData = await retryHelper.execute(async () => {
 | 
					 | 
				
			||||||
    core.info('Downloading the archive')
 | 
					 | 
				
			||||||
    return await downloadArchive(authToken, owner, repo, ref, commit)
 | 
					 | 
				
			||||||
  })
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // Write archive to disk
 | 
					 | 
				
			||||||
  core.info('Writing archive to disk')
 | 
					 | 
				
			||||||
  const uniqueId = uuid()
 | 
					 | 
				
			||||||
  const archivePath = path.join(repositoryPath, `${uniqueId}.tar.gz`)
 | 
					 | 
				
			||||||
  await fs.promises.writeFile(archivePath, archiveData)
 | 
					 | 
				
			||||||
  archiveData = Buffer.from('') // Free memory
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // Extract archive
 | 
					 | 
				
			||||||
  core.info('Extracting the archive')
 | 
					 | 
				
			||||||
  const extractPath = path.join(repositoryPath, uniqueId)
 | 
					 | 
				
			||||||
  await io.mkdirP(extractPath)
 | 
					 | 
				
			||||||
  if (IS_WINDOWS) {
 | 
					 | 
				
			||||||
    await toolCache.extractZip(archivePath, extractPath)
 | 
					 | 
				
			||||||
  } else {
 | 
					 | 
				
			||||||
    await toolCache.extractTar(archivePath, extractPath)
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  io.rmRF(archivePath)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // Determine the path of the repository content. The archive contains
 | 
					 | 
				
			||||||
  // a top-level folder and the repository content is inside.
 | 
					 | 
				
			||||||
  const archiveFileNames = await fs.promises.readdir(extractPath)
 | 
					 | 
				
			||||||
  assert.ok(
 | 
					 | 
				
			||||||
    archiveFileNames.length == 1,
 | 
					 | 
				
			||||||
    'Expected exactly one directory inside archive'
 | 
					 | 
				
			||||||
  )
 | 
					 | 
				
			||||||
  const archiveVersion = archiveFileNames[0] // The top-level folder name includes the short SHA
 | 
					 | 
				
			||||||
  core.info(`Resolved version ${archiveVersion}`)
 | 
					 | 
				
			||||||
  const tempRepositoryPath = path.join(extractPath, archiveVersion)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // Move the files
 | 
					 | 
				
			||||||
  for (const fileName of await fs.promises.readdir(tempRepositoryPath)) {
 | 
					 | 
				
			||||||
    const sourcePath = path.join(tempRepositoryPath, fileName)
 | 
					 | 
				
			||||||
    const targetPath = path.join(repositoryPath, fileName)
 | 
					 | 
				
			||||||
    if (IS_WINDOWS) {
 | 
					 | 
				
			||||||
      await io.cp(sourcePath, targetPath, {recursive: true}) // Copy on Windows (Windows Defender may have a lock)
 | 
					 | 
				
			||||||
    } else {
 | 
					 | 
				
			||||||
      await io.mv(sourcePath, targetPath)
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  io.rmRF(extractPath)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
async function downloadArchive(
 | 
					 | 
				
			||||||
  authToken: string,
 | 
					 | 
				
			||||||
  owner: string,
 | 
					 | 
				
			||||||
  repo: string,
 | 
					 | 
				
			||||||
  ref: string,
 | 
					 | 
				
			||||||
  commit: string
 | 
					 | 
				
			||||||
): Promise<Buffer> {
 | 
					 | 
				
			||||||
  const octokit = new github.GitHub(authToken)
 | 
					 | 
				
			||||||
  const params: ReposGetArchiveLinkParams = {
 | 
					 | 
				
			||||||
    owner: owner,
 | 
					 | 
				
			||||||
    repo: repo,
 | 
					 | 
				
			||||||
    archive_format: IS_WINDOWS ? 'zipball' : 'tarball',
 | 
					 | 
				
			||||||
    ref: commit || ref
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  const response = await octokit.repos.getArchiveLink(params)
 | 
					 | 
				
			||||||
  if (response.status != 200) {
 | 
					 | 
				
			||||||
    throw new Error(
 | 
					 | 
				
			||||||
      `Unexpected response from GitHub API. Status: ${response.status}, Data: ${response.data}`
 | 
					 | 
				
			||||||
    )
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  return Buffer.from(response.data) // response.data is ArrayBuffer
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -1,108 +0,0 @@
 | 
				
			|||||||
import * as core from '@actions/core'
 | 
					 | 
				
			||||||
import * as fsHelper from './fs-helper'
 | 
					 | 
				
			||||||
import * as github from '@actions/github'
 | 
					 | 
				
			||||||
import * as path from 'path'
 | 
					 | 
				
			||||||
import {ISourceSettings} from './git-source-provider'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export function getInputs(): ISourceSettings {
 | 
					 | 
				
			||||||
  const result = ({} as unknown) as ISourceSettings
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // GitHub workspace
 | 
					 | 
				
			||||||
  let githubWorkspacePath = process.env['GITHUB_WORKSPACE']
 | 
					 | 
				
			||||||
  if (!githubWorkspacePath) {
 | 
					 | 
				
			||||||
    throw new Error('GITHUB_WORKSPACE not defined')
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  githubWorkspacePath = path.resolve(githubWorkspacePath)
 | 
					 | 
				
			||||||
  core.debug(`GITHUB_WORKSPACE = '${githubWorkspacePath}'`)
 | 
					 | 
				
			||||||
  fsHelper.directoryExistsSync(githubWorkspacePath, true)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // Qualified repository
 | 
					 | 
				
			||||||
  const qualifiedRepository =
 | 
					 | 
				
			||||||
    core.getInput('repository') ||
 | 
					 | 
				
			||||||
    `${github.context.repo.owner}/${github.context.repo.repo}`
 | 
					 | 
				
			||||||
  core.debug(`qualified repository = '${qualifiedRepository}'`)
 | 
					 | 
				
			||||||
  const splitRepository = qualifiedRepository.split('/')
 | 
					 | 
				
			||||||
  if (
 | 
					 | 
				
			||||||
    splitRepository.length !== 2 ||
 | 
					 | 
				
			||||||
    !splitRepository[0] ||
 | 
					 | 
				
			||||||
    !splitRepository[1]
 | 
					 | 
				
			||||||
  ) {
 | 
					 | 
				
			||||||
    throw new Error(
 | 
					 | 
				
			||||||
      `Invalid repository '${qualifiedRepository}'. Expected format {owner}/{repo}.`
 | 
					 | 
				
			||||||
    )
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  result.repositoryOwner = splitRepository[0]
 | 
					 | 
				
			||||||
  result.repositoryName = splitRepository[1]
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // Repository path
 | 
					 | 
				
			||||||
  result.repositoryPath = core.getInput('path') || '.'
 | 
					 | 
				
			||||||
  result.repositoryPath = path.resolve(
 | 
					 | 
				
			||||||
    githubWorkspacePath,
 | 
					 | 
				
			||||||
    result.repositoryPath
 | 
					 | 
				
			||||||
  )
 | 
					 | 
				
			||||||
  if (
 | 
					 | 
				
			||||||
    !(result.repositoryPath + path.sep).startsWith(
 | 
					 | 
				
			||||||
      githubWorkspacePath + path.sep
 | 
					 | 
				
			||||||
    )
 | 
					 | 
				
			||||||
  ) {
 | 
					 | 
				
			||||||
    throw new Error(
 | 
					 | 
				
			||||||
      `Repository path '${result.repositoryPath}' is not under '${githubWorkspacePath}'`
 | 
					 | 
				
			||||||
    )
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // Workflow repository?
 | 
					 | 
				
			||||||
  const isWorkflowRepository =
 | 
					 | 
				
			||||||
    qualifiedRepository.toUpperCase() ===
 | 
					 | 
				
			||||||
    `${github.context.repo.owner}/${github.context.repo.repo}`.toUpperCase()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // Source branch, source version
 | 
					 | 
				
			||||||
  result.ref = core.getInput('ref')
 | 
					 | 
				
			||||||
  if (!result.ref) {
 | 
					 | 
				
			||||||
    if (isWorkflowRepository) {
 | 
					 | 
				
			||||||
      result.ref = github.context.ref
 | 
					 | 
				
			||||||
      result.commit = github.context.sha
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (!result.ref && !result.commit) {
 | 
					 | 
				
			||||||
      result.ref = 'refs/heads/master'
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  // SHA?
 | 
					 | 
				
			||||||
  else if (result.ref.match(/^[0-9a-fA-F]{40}$/)) {
 | 
					 | 
				
			||||||
    result.commit = result.ref
 | 
					 | 
				
			||||||
    result.ref = ''
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  core.debug(`ref = '${result.ref}'`)
 | 
					 | 
				
			||||||
  core.debug(`commit = '${result.commit}'`)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // Clean
 | 
					 | 
				
			||||||
  result.clean = (core.getInput('clean') || 'true').toUpperCase() === 'TRUE'
 | 
					 | 
				
			||||||
  core.debug(`clean = ${result.clean}`)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // Submodules
 | 
					 | 
				
			||||||
  if (core.getInput('submodules')) {
 | 
					 | 
				
			||||||
    throw new Error(
 | 
					 | 
				
			||||||
      "The input 'submodules' is not supported in actions/checkout@v2"
 | 
					 | 
				
			||||||
    )
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // Fetch depth
 | 
					 | 
				
			||||||
  result.fetchDepth = Math.floor(Number(core.getInput('fetch-depth') || '1'))
 | 
					 | 
				
			||||||
  if (isNaN(result.fetchDepth) || result.fetchDepth < 0) {
 | 
					 | 
				
			||||||
    result.fetchDepth = 0
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  core.debug(`fetch depth = ${result.fetchDepth}`)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // LFS
 | 
					 | 
				
			||||||
  result.lfs = (core.getInput('lfs') || 'false').toUpperCase() === 'TRUE'
 | 
					 | 
				
			||||||
  core.debug(`lfs = ${result.lfs}`)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // Auth token
 | 
					 | 
				
			||||||
  result.authToken = core.getInput('token')
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // Persist credentials
 | 
					 | 
				
			||||||
  result.persistCredentials =
 | 
					 | 
				
			||||||
    (core.getInput('persist-credentials') || 'false').toUpperCase() === 'TRUE'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  return result
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
							
								
								
									
										46
									
								
								src/main.ts
									
									
									
									
									
								
							
							
						
						
									
										46
									
								
								src/main.ts
									
									
									
									
									
								
							@@ -1,46 +0,0 @@
 | 
				
			|||||||
import * as core from '@actions/core'
 | 
					 | 
				
			||||||
import * as coreCommand from '@actions/core/lib/command'
 | 
					 | 
				
			||||||
import * as gitSourceProvider from './git-source-provider'
 | 
					 | 
				
			||||||
import * as inputHelper from './input-helper'
 | 
					 | 
				
			||||||
import * as path from 'path'
 | 
					 | 
				
			||||||
import * as stateHelper from './state-helper'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
async function run(): Promise<void> {
 | 
					 | 
				
			||||||
  try {
 | 
					 | 
				
			||||||
    const sourceSettings = inputHelper.getInputs()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    try {
 | 
					 | 
				
			||||||
      // Register problem matcher
 | 
					 | 
				
			||||||
      coreCommand.issueCommand(
 | 
					 | 
				
			||||||
        'add-matcher',
 | 
					 | 
				
			||||||
        {},
 | 
					 | 
				
			||||||
        path.join(__dirname, 'problem-matcher.json')
 | 
					 | 
				
			||||||
      )
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      // Get sources
 | 
					 | 
				
			||||||
      await gitSourceProvider.getSource(sourceSettings)
 | 
					 | 
				
			||||||
    } finally {
 | 
					 | 
				
			||||||
      // Unregister problem matcher
 | 
					 | 
				
			||||||
      coreCommand.issueCommand('remove-matcher', {owner: 'checkout-git'}, '')
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  } catch (error) {
 | 
					 | 
				
			||||||
    core.setFailed(error.message)
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
async function cleanup(): Promise<void> {
 | 
					 | 
				
			||||||
  try {
 | 
					 | 
				
			||||||
    await gitSourceProvider.cleanup(stateHelper.RepositoryPath)
 | 
					 | 
				
			||||||
  } catch (error) {
 | 
					 | 
				
			||||||
    core.warning(error.message)
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// Main
 | 
					 | 
				
			||||||
if (!stateHelper.IsPost) {
 | 
					 | 
				
			||||||
  run()
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
// Post
 | 
					 | 
				
			||||||
else {
 | 
					 | 
				
			||||||
  cleanup()
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -1,102 +0,0 @@
 | 
				
			|||||||
import * as fs from 'fs'
 | 
					 | 
				
			||||||
import * as os from 'os'
 | 
					 | 
				
			||||||
import * as path from 'path'
 | 
					 | 
				
			||||||
import * as yaml from 'js-yaml'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
//
 | 
					 | 
				
			||||||
// SUMMARY
 | 
					 | 
				
			||||||
//
 | 
					 | 
				
			||||||
// This script rebuilds the usage section in the README.md to be consistent with the action.yml
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
function updateUsage(
 | 
					 | 
				
			||||||
  actionReference: string,
 | 
					 | 
				
			||||||
  actionYamlPath: string = 'action.yml',
 | 
					 | 
				
			||||||
  readmePath: string = 'README.md',
 | 
					 | 
				
			||||||
  startToken: string = '<!-- start usage -->',
 | 
					 | 
				
			||||||
  endToken: string = '<!-- end usage -->'
 | 
					 | 
				
			||||||
): void {
 | 
					 | 
				
			||||||
  if (!actionReference) {
 | 
					 | 
				
			||||||
    throw new Error('Parameter actionReference must not be empty')
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // Load the action.yml
 | 
					 | 
				
			||||||
  const actionYaml = yaml.safeLoad(fs.readFileSync(actionYamlPath).toString())
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // Load the README
 | 
					 | 
				
			||||||
  const originalReadme = fs.readFileSync(readmePath).toString()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // Find the start token
 | 
					 | 
				
			||||||
  const startTokenIndex = originalReadme.indexOf(startToken)
 | 
					 | 
				
			||||||
  if (startTokenIndex < 0) {
 | 
					 | 
				
			||||||
    throw new Error(`Start token '${startToken}' not found`)
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // Find the end token
 | 
					 | 
				
			||||||
  const endTokenIndex = originalReadme.indexOf(endToken)
 | 
					 | 
				
			||||||
  if (endTokenIndex < 0) {
 | 
					 | 
				
			||||||
    throw new Error(`End token '${endToken}' not found`)
 | 
					 | 
				
			||||||
  } else if (endTokenIndex < startTokenIndex) {
 | 
					 | 
				
			||||||
    throw new Error('Start token must appear before end token')
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // Build the new README
 | 
					 | 
				
			||||||
  const newReadme: string[] = []
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // Append the beginning
 | 
					 | 
				
			||||||
  newReadme.push(originalReadme.substr(0, startTokenIndex + startToken.length))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // Build the new usage section
 | 
					 | 
				
			||||||
  newReadme.push('```yaml', `- uses: ${actionReference}`, '  with:')
 | 
					 | 
				
			||||||
  const inputs = actionYaml.inputs
 | 
					 | 
				
			||||||
  let firstInput = true
 | 
					 | 
				
			||||||
  for (const key of Object.keys(inputs)) {
 | 
					 | 
				
			||||||
    const input = inputs[key]
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // Line break between inputs
 | 
					 | 
				
			||||||
    if (!firstInput) {
 | 
					 | 
				
			||||||
      newReadme.push('')
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // Constrain the width of the description
 | 
					 | 
				
			||||||
    const width = 80
 | 
					 | 
				
			||||||
    let description = input.description as string
 | 
					 | 
				
			||||||
    while (description) {
 | 
					 | 
				
			||||||
      // Longer than width? Find a space to break apart
 | 
					 | 
				
			||||||
      let segment: string = description
 | 
					 | 
				
			||||||
      if (description.length > width) {
 | 
					 | 
				
			||||||
        segment = description.substr(0, width + 1)
 | 
					 | 
				
			||||||
        while (!segment.endsWith(' ')) {
 | 
					 | 
				
			||||||
          segment = segment.substr(0, segment.length - 1)
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
      } else {
 | 
					 | 
				
			||||||
        segment = description
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      description = description.substr(segment.length) // Remaining
 | 
					 | 
				
			||||||
      segment = segment.trimRight() // Trim the trailing space
 | 
					 | 
				
			||||||
      newReadme.push(`    # ${segment}`)
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // Input and default
 | 
					 | 
				
			||||||
    if (input.default !== undefined) {
 | 
					 | 
				
			||||||
      newReadme.push(`    # Default: ${input.default}`)
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    newReadme.push(`    ${key}: ''`)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    firstInput = false
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  newReadme.push('```')
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // Append the end
 | 
					 | 
				
			||||||
  newReadme.push(originalReadme.substr(endTokenIndex))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // Write the new README
 | 
					 | 
				
			||||||
  fs.writeFileSync(readmePath, newReadme.join(os.EOL))
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
updateUsage(
 | 
					 | 
				
			||||||
  'actions/checkout@v2',
 | 
					 | 
				
			||||||
  path.join(__dirname, '..', '..', 'action.yml'),
 | 
					 | 
				
			||||||
  path.join(__dirname, '..', '..', 'README.md')
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
@@ -1,109 +0,0 @@
 | 
				
			|||||||
import {IGitCommandManager} from './git-command-manager'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export interface ICheckoutInfo {
 | 
					 | 
				
			||||||
  ref: string
 | 
					 | 
				
			||||||
  startPoint: string
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export async function getCheckoutInfo(
 | 
					 | 
				
			||||||
  git: IGitCommandManager,
 | 
					 | 
				
			||||||
  ref: string,
 | 
					 | 
				
			||||||
  commit: string
 | 
					 | 
				
			||||||
): Promise<ICheckoutInfo> {
 | 
					 | 
				
			||||||
  if (!git) {
 | 
					 | 
				
			||||||
    throw new Error('Arg git cannot be empty')
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  if (!ref && !commit) {
 | 
					 | 
				
			||||||
    throw new Error('Args ref and commit cannot both be empty')
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  const result = ({} as unknown) as ICheckoutInfo
 | 
					 | 
				
			||||||
  const upperRef = (ref || '').toUpperCase()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // SHA only
 | 
					 | 
				
			||||||
  if (!ref) {
 | 
					 | 
				
			||||||
    result.ref = commit
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  // refs/heads/
 | 
					 | 
				
			||||||
  else if (upperRef.startsWith('REFS/HEADS/')) {
 | 
					 | 
				
			||||||
    const branch = ref.substring('refs/heads/'.length)
 | 
					 | 
				
			||||||
    result.ref = branch
 | 
					 | 
				
			||||||
    result.startPoint = `refs/remotes/origin/${branch}`
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  // refs/pull/
 | 
					 | 
				
			||||||
  else if (upperRef.startsWith('REFS/PULL/')) {
 | 
					 | 
				
			||||||
    const branch = ref.substring('refs/pull/'.length)
 | 
					 | 
				
			||||||
    result.ref = `refs/remotes/pull/${branch}`
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  // refs/tags/
 | 
					 | 
				
			||||||
  else if (upperRef.startsWith('REFS/')) {
 | 
					 | 
				
			||||||
    result.ref = ref
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  // Unqualified ref, check for a matching branch or tag
 | 
					 | 
				
			||||||
  else {
 | 
					 | 
				
			||||||
    if (await git.branchExists(true, `origin/${ref}`)) {
 | 
					 | 
				
			||||||
      result.ref = ref
 | 
					 | 
				
			||||||
      result.startPoint = `refs/remotes/origin/${ref}`
 | 
					 | 
				
			||||||
    } else if (await git.tagExists(`${ref}`)) {
 | 
					 | 
				
			||||||
      result.ref = `refs/tags/${ref}`
 | 
					 | 
				
			||||||
    } else {
 | 
					 | 
				
			||||||
      throw new Error(
 | 
					 | 
				
			||||||
        `A branch or tag with the name '${ref}' could not be found`
 | 
					 | 
				
			||||||
      )
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  return result
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export function getRefSpec(ref: string, commit: string): string[] {
 | 
					 | 
				
			||||||
  if (!ref && !commit) {
 | 
					 | 
				
			||||||
    throw new Error('Args ref and commit cannot both be empty')
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  const upperRef = (ref || '').toUpperCase()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // SHA
 | 
					 | 
				
			||||||
  if (commit) {
 | 
					 | 
				
			||||||
    // refs/heads
 | 
					 | 
				
			||||||
    if (upperRef.startsWith('REFS/HEADS/')) {
 | 
					 | 
				
			||||||
      const branch = ref.substring('refs/heads/'.length)
 | 
					 | 
				
			||||||
      return [`+${commit}:refs/remotes/origin/${branch}`]
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    // refs/pull/
 | 
					 | 
				
			||||||
    else if (upperRef.startsWith('REFS/PULL/')) {
 | 
					 | 
				
			||||||
      const branch = ref.substring('refs/pull/'.length)
 | 
					 | 
				
			||||||
      return [`+${commit}:refs/remotes/pull/${branch}`]
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    // refs/tags/
 | 
					 | 
				
			||||||
    else if (upperRef.startsWith('REFS/TAGS/')) {
 | 
					 | 
				
			||||||
      return [`+${commit}:${ref}`]
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    // Otherwise no destination ref
 | 
					 | 
				
			||||||
    else {
 | 
					 | 
				
			||||||
      return [commit]
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  // Unqualified ref, check for a matching branch or tag
 | 
					 | 
				
			||||||
  else if (!upperRef.startsWith('REFS/')) {
 | 
					 | 
				
			||||||
    return [
 | 
					 | 
				
			||||||
      `+refs/heads/${ref}*:refs/remotes/origin/${ref}*`,
 | 
					 | 
				
			||||||
      `+refs/tags/${ref}*:refs/tags/${ref}*`
 | 
					 | 
				
			||||||
    ]
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  // refs/heads/
 | 
					 | 
				
			||||||
  else if (upperRef.startsWith('REFS/HEADS/')) {
 | 
					 | 
				
			||||||
    const branch = ref.substring('refs/heads/'.length)
 | 
					 | 
				
			||||||
    return [`+${ref}:refs/remotes/origin/${branch}`]
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  // refs/pull/
 | 
					 | 
				
			||||||
  else if (upperRef.startsWith('REFS/PULL/')) {
 | 
					 | 
				
			||||||
    const branch = ref.substring('refs/pull/'.length)
 | 
					 | 
				
			||||||
    return [`+${ref}:refs/remotes/pull/${branch}`]
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  // refs/tags/
 | 
					 | 
				
			||||||
  else {
 | 
					 | 
				
			||||||
    return [`+${ref}:${ref}`]
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -1,61 +0,0 @@
 | 
				
			|||||||
import * as core from '@actions/core'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const defaultMaxAttempts = 3
 | 
					 | 
				
			||||||
const defaultMinSeconds = 10
 | 
					 | 
				
			||||||
const defaultMaxSeconds = 20
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export class RetryHelper {
 | 
					 | 
				
			||||||
  private maxAttempts: number
 | 
					 | 
				
			||||||
  private minSeconds: number
 | 
					 | 
				
			||||||
  private maxSeconds: number
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  constructor(
 | 
					 | 
				
			||||||
    maxAttempts: number = defaultMaxAttempts,
 | 
					 | 
				
			||||||
    minSeconds: number = defaultMinSeconds,
 | 
					 | 
				
			||||||
    maxSeconds: number = defaultMaxSeconds
 | 
					 | 
				
			||||||
  ) {
 | 
					 | 
				
			||||||
    this.maxAttempts = maxAttempts
 | 
					 | 
				
			||||||
    this.minSeconds = Math.floor(minSeconds)
 | 
					 | 
				
			||||||
    this.maxSeconds = Math.floor(maxSeconds)
 | 
					 | 
				
			||||||
    if (this.minSeconds > this.maxSeconds) {
 | 
					 | 
				
			||||||
      throw new Error('min seconds should be less than or equal to max seconds')
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  async execute<T>(action: () => Promise<T>): Promise<T> {
 | 
					 | 
				
			||||||
    let attempt = 1
 | 
					 | 
				
			||||||
    while (attempt < this.maxAttempts) {
 | 
					 | 
				
			||||||
      // Try
 | 
					 | 
				
			||||||
      try {
 | 
					 | 
				
			||||||
        return await action()
 | 
					 | 
				
			||||||
      } catch (err) {
 | 
					 | 
				
			||||||
        core.info(err.message)
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      // Sleep
 | 
					 | 
				
			||||||
      const seconds = this.getSleepAmount()
 | 
					 | 
				
			||||||
      core.info(`Waiting ${seconds} seconds before trying again`)
 | 
					 | 
				
			||||||
      await this.sleep(seconds)
 | 
					 | 
				
			||||||
      attempt++
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // Last attempt
 | 
					 | 
				
			||||||
    return await action()
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  private getSleepAmount(): number {
 | 
					 | 
				
			||||||
    return (
 | 
					 | 
				
			||||||
      Math.floor(Math.random() * (this.maxSeconds - this.minSeconds + 1)) +
 | 
					 | 
				
			||||||
      this.minSeconds
 | 
					 | 
				
			||||||
    )
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  private async sleep(seconds: number): Promise<void> {
 | 
					 | 
				
			||||||
    return new Promise(resolve => setTimeout(resolve, seconds * 1000))
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export async function execute<T>(action: () => Promise<T>): Promise<T> {
 | 
					 | 
				
			||||||
  const retryHelper = new RetryHelper()
 | 
					 | 
				
			||||||
  return await retryHelper.execute(action)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -1,30 +0,0 @@
 | 
				
			|||||||
import * as core from '@actions/core'
 | 
					 | 
				
			||||||
import * as coreCommand from '@actions/core/lib/command'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 * Indicates whether the POST action is running
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
export const IsPost = !!process.env['STATE_isPost']
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 * The repository path for the POST action. The value is empty during the MAIN action.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
export const RepositoryPath =
 | 
					 | 
				
			||||||
  (process.env['STATE_repositoryPath'] as string) || ''
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 * Save the repository path so the POST action can retrieve the value.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
export function setRepositoryPath(repositoryPath: string) {
 | 
					 | 
				
			||||||
  coreCommand.issueCommand(
 | 
					 | 
				
			||||||
    'save-state',
 | 
					 | 
				
			||||||
    {name: 'repositoryPath'},
 | 
					 | 
				
			||||||
    repositoryPath
 | 
					 | 
				
			||||||
  )
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// 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.
 | 
					 | 
				
			||||||
if (!IsPost) {
 | 
					 | 
				
			||||||
  coreCommand.issueCommand('save-state', {name: 'isPost'}, 'true')
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -1,16 +0,0 @@
 | 
				
			|||||||
{
 | 
					 | 
				
			||||||
  "compilerOptions": {
 | 
					 | 
				
			||||||
    "target": "es6",
 | 
					 | 
				
			||||||
    "module": "commonjs",
 | 
					 | 
				
			||||||
    "lib": [
 | 
					 | 
				
			||||||
      "es6"
 | 
					 | 
				
			||||||
    ],
 | 
					 | 
				
			||||||
    "outDir": "./lib",
 | 
					 | 
				
			||||||
    "rootDir": "./src",
 | 
					 | 
				
			||||||
    "declaration": true,
 | 
					 | 
				
			||||||
    "strict": true,
 | 
					 | 
				
			||||||
    "noImplicitAny": false,
 | 
					 | 
				
			||||||
    "esModuleInterop": true
 | 
					 | 
				
			||||||
  },
 | 
					 | 
				
			||||||
  "exclude": ["__test__", "lib", "node_modules"]
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
		Reference in New Issue
	
	Block a user