Public Access
1
0
mirror of https://github.com/actions/checkout.git synced 2025-07-13 12:13:51 +00:00

Compare commits

..

1 Commits

Author SHA1 Message Date
e9fadf668a pr head commit scenario 2019-12-03 18:12:12 -05:00
16 changed files with 857 additions and 4191 deletions

View File

@ -18,7 +18,6 @@ jobs:
- run: npm run lint - run: npm run lint
- run: npm run pack - run: npm run pack
- run: npm run gendocs - run: npm run gendocs
- run: npm test
- name: Verify no unstaged changes - name: Verify no unstaged changes
run: __test__/verify-no-unstaged-changes.sh run: __test__/verify-no-unstaged-changes.sh
@ -31,7 +30,7 @@ jobs:
steps: steps:
# Clone this repo # Clone this repo
- name: Checkout - name: Checkout
uses: actions/checkout@v2-beta uses: actions/checkout@v1 # todo: switch to V2
# Basic checkout # Basic checkout
- name: Basic checkout - name: Basic checkout
@ -82,21 +81,3 @@ jobs:
- name: Verify LFS - name: Verify LFS
shell: bash shell: bash
run: __test__/verify-lfs.sh run: __test__/verify-lfs.sh
test-job-container:
runs-on: ubuntu-latest
container: alpine:latest
steps:
# Clone this repo
# todo: after v2-beta contains the latest changes, switch this to "uses: actions/checkout@v2-beta"
- name: Checkout
uses: actions/checkout@a572f640b07e96fc5837b3adfa0e5a2ddd8dae21
# Basic checkout
- name: Basic checkout
uses: ./
with:
ref: test-data/v2/basic
path: basic
- name: Verify basic
run: __test__/verify-basic.sh --archive

View File

@ -10,23 +10,20 @@ By default, the repository that triggered the workflow is checked-out, for the r
Refer [here](https://help.github.com/en/articles/events-that-trigger-workflows) to learn which commit `$GITHUB_SHA` points to for different events. 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 Changes in V2:
- Improved fetch performance - Improved fetch performance
- The default behavior now fetches only the commit being checked-out - The default behavior now fetches only the SHA being checked-out
- Script authenticated git commands - Script authenticated git commands
- Persists the input `token` in the local git config - Persists `with.token` in the local git config
- Enables your scripts to run authenticated git commands - Enables your scripts to run authenticated git commands
- Post-job cleanup removes the token - Post-job cleanup removes the token
- Opt out by setting the input `persist-credentials: false` - Coming soon: Opt out by setting `with.persist-credentials` to `false`
- Creates a local branch - Creates a local branch
- No longer detached HEAD when checking out a branch - No longer detached HEAD when checking out a branch
- A local branch is created with the corresponding upstream branch set - A local branch is created with the corresponding upstream branch set
- Improved layout - Improved layout
- The input `path` is always relative to $GITHUB_WORKSPACE - `with.path` is always relative to `github.workspace`
- Aligns better with container actions, where $GITHUB_WORKSPACE gets mapped in - 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` - Removed input `submodules`
Refer [here](https://github.com/actions/checkout/blob/v1/README.md) for previous versions. Refer [here](https://github.com/actions/checkout/blob/v1/README.md) for previous versions.
@ -41,21 +38,14 @@ Refer [here](https://github.com/actions/checkout/blob/v1/README.md) for previous
# Default: ${{ github.repository }} # Default: ${{ github.repository }}
repository: '' repository: ''
# The branch, tag or SHA to checkout. When checking out the repository that # Ref to checkout (SHA, branch, tag). For the repository that triggered the
# triggered a workflow, this defaults to the reference or SHA for that event. # workflow, defaults to the ref/SHA for the event. Otherwise defaults to master.
# Otherwise, defaults to `master`.
ref: '' ref: ''
# Auth token used to fetch the repository. The token is stored in the local git # Access token for clone repository
# config, which enables your scripts to run authenticated git commands. The
# post-job step removes the token from the git config.
# Default: ${{ github.token }} # Default: ${{ github.token }}
token: '' token: ''
# Whether to persist the token in the git config
# Default: true
persist-credentials: ''
# Relative path under $GITHUB_WORKSPACE to place the repository # Relative path under $GITHUB_WORKSPACE to place the repository
path: '' path: ''
@ -97,7 +87,7 @@ Refer [here](https://github.com/actions/checkout/blob/v1/README.md) for previous
```yaml ```yaml
- uses: actions/checkout@v2-beta - uses: actions/checkout@v2-beta
with: with:
ref: ${{ github.event.pull_request.head.sha }} ref: refs/pull/${{ github.event.number }}/head
``` ```
# License # License

View File

@ -63,7 +63,7 @@ describe('input-helper tests', () => {
it('sets defaults', () => { it('sets defaults', () => {
const settings: ISourceSettings = inputHelper.getInputs() const settings: ISourceSettings = inputHelper.getInputs()
expect(settings).toBeTruthy() expect(settings).toBeTruthy()
expect(settings.authToken).toBeFalsy() expect(settings.accessToken).toBeFalsy()
expect(settings.clean).toBe(true) expect(settings.clean).toBe(true)
expect(settings.commit).toBeTruthy() expect(settings.commit).toBeTruthy()
expect(settings.commit).toBe('1234567890123456789012345678901234567890') expect(settings.commit).toBe('1234567890123456789012345678901234567890')

View File

@ -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/)
})
})

View File

@ -1,24 +1,10 @@
#!/bin/sh #!/bin/bash
if [ ! -f "./basic/basic-file.txt" ]; then if [ ! -f "./basic/basic-file.txt" ]; then
echo "Expected basic file does not exist" echo "Expected basic file does not exist"
exit 1 exit 1
fi fi
if [ "$1" = "--archive" ]; then # Verify auth token
# Verify no .git folder cd basic
if [ -d "./basic/.git" ]; then git fetch
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

View File

@ -1,23 +1,16 @@
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 with owner. For example, actions/checkout'
default: ${{ github.repository }} default: ${{ github.repository }}
ref: ref:
description: > description: >
The branch, tag or SHA to checkout. When checking out the repository that Ref to checkout (SHA, branch, tag). For the repository that triggered the
triggered a workflow, this defaults to the reference or SHA for that workflow, defaults to the ref/SHA for the event. Otherwise defaults to master.
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 }} default: ${{ github.token }}
persist-credentials:
description: 'Whether to persist the token in the git config'
default: true
path: path:
description: 'Relative path under $GITHUB_WORKSPACE to place the repository' description: 'Relative path under $GITHUB_WORKSPACE to place the repository'
clean: clean:

3968
dist/index.js vendored

File diff suppressed because one or more lines are too long

146
package-lock.json generated
View File

@ -15,11 +15,11 @@
"integrity": "sha512-nvFkxwiicvpzNiCBF4wFBDfnBvi7xp/as7LE1hBxBxKG2L29+gkIPBiLKMVORL+Hg3JNf07AKRfl0V5djoypjQ==" "integrity": "sha512-nvFkxwiicvpzNiCBF4wFBDfnBvi7xp/as7LE1hBxBxKG2L29+gkIPBiLKMVORL+Hg3JNf07AKRfl0V5djoypjQ=="
}, },
"@actions/github": { "@actions/github": {
"version": "2.0.0", "version": "1.1.0",
"resolved": "https://registry.npmjs.org/@actions/github/-/github-2.0.0.tgz", "resolved": "https://registry.npmjs.org/@actions/github/-/github-1.1.0.tgz",
"integrity": "sha512-sNpZ5dJyJyfJIO5lNYx8r/Gha4Tlm8R0MLO2cBkGdOnAAEn3t1M/MHVcoBhY/VPfjGVe5RNAUPz+6INrViiUPA==", "integrity": "sha512-cHf6PyoNMdei13jEdGPhKprIMFmjVVW/dnM5/9QmQDJ1ZTaGVyezUSCUIC/ySNLRvDUpeFwPYMdThSEJldSbUw==",
"requires": { "requires": {
"@octokit/graphql": "^4.3.1", "@octokit/graphql": "^2.0.1",
"@octokit/rest": "^16.15.0" "@octokit/rest": "^16.15.0"
} }
}, },
@ -28,26 +28,6 @@
"resolved": "https://registry.npmjs.org/@actions/io/-/io-1.0.1.tgz", "resolved": "https://registry.npmjs.org/@actions/io/-/io-1.0.1.tgz",
"integrity": "sha512-rhq+tfZukbtaus7xyUtwKfuiCRXd1hWSfmJNEpFgBQJ4woqPEpsBw04awicjwz9tyG2/MVhAEMfVn664Cri5zA==" "integrity": "sha512-rhq+tfZukbtaus7xyUtwKfuiCRXd1hWSfmJNEpFgBQJ4woqPEpsBw04awicjwz9tyG2/MVhAEMfVn664Cri5zA=="
}, },
"@actions/tool-cache": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/@actions/tool-cache/-/tool-cache-1.1.2.tgz",
"integrity": "sha512-IJczPaZr02ECa3Lgws/TJEVco9tjOujiQSZbO3dHuXXjhd5vrUtfOgGwhmz3/f97L910OraPZ8SknofUk6RvOQ==",
"requires": {
"@actions/core": "^1.1.0",
"@actions/exec": "^1.0.1",
"@actions/io": "^1.0.1",
"semver": "^6.1.0",
"typed-rest-client": "^1.4.0",
"uuid": "^3.3.2"
},
"dependencies": {
"semver": {
"version": "6.3.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw=="
}
}
},
"@babel/code-frame": { "@babel/code-frame": {
"version": "7.5.5", "version": "7.5.5",
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.5.5.tgz", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.5.5.tgz",
@ -598,56 +578,72 @@
} }
}, },
"@octokit/endpoint": { "@octokit/endpoint": {
"version": "5.5.1", "version": "5.4.0",
"resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-5.5.1.tgz", "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-5.4.0.tgz",
"integrity": "sha512-nBFhRUb5YzVTCX/iAK1MgQ4uWo89Gu0TH00qQHoYRCsE12dWcG1OiLd7v2EIo2+tpUKPMOQ62QFy9hy9Vg2ULg==", "integrity": "sha512-DWTNgEKg5KXzvNjKTzcFTnkZiL7te6pQxxumvxPjyjDpcY5V3xzywnNu1WVqySY3Ct1flF/kAoyDdZos6acq3Q==",
"requires": { "requires": {
"@octokit/types": "^2.0.0",
"is-plain-object": "^3.0.0", "is-plain-object": "^3.0.0",
"universal-user-agent": "^4.0.0" "universal-user-agent": "^4.0.0"
},
"dependencies": {
"universal-user-agent": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-4.0.0.tgz",
"integrity": "sha512-eM8knLpev67iBDizr/YtqkJsF3GK8gzDc6st/WKzrTuPtcsOKW/0IdL4cnMBsU69pOx0otavLWBDGTwg+dB0aA==",
"requires": {
"os-name": "^3.1.0"
}
}
} }
}, },
"@octokit/graphql": { "@octokit/graphql": {
"version": "4.3.1", "version": "2.1.3",
"resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-4.3.1.tgz", "resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-2.1.3.tgz",
"integrity": "sha512-hCdTjfvrK+ilU2keAdqNBWOk+gm1kai1ZcdjRfB30oA3/T6n53UVJb7w0L5cR3/rhU91xT3HSqCd+qbvH06yxA==", "integrity": "sha512-XoXJqL2ondwdnMIW3wtqJWEwcBfKk37jO/rYkoxNPEVeLBDGsGO1TCWggrAlq3keGt/O+C/7VepXnukUxwt5vA==",
"requires": { "requires": {
"@octokit/request": "^5.3.0", "@octokit/request": "^5.0.0",
"@octokit/types": "^2.0.0", "universal-user-agent": "^2.0.3"
"universal-user-agent": "^4.0.0"
} }
}, },
"@octokit/request": { "@octokit/request": {
"version": "5.3.1", "version": "5.1.0",
"resolved": "https://registry.npmjs.org/@octokit/request/-/request-5.3.1.tgz", "resolved": "https://registry.npmjs.org/@octokit/request/-/request-5.1.0.tgz",
"integrity": "sha512-5/X0AL1ZgoU32fAepTfEoggFinO3rxsMLtzhlUX+RctLrusn/CApJuGFCd0v7GMFhF+8UiCsTTfsu7Fh1HnEJg==", "integrity": "sha512-I15T9PwjFs4tbWyhtFU2Kq7WDPidYMvRB7spmxoQRZfxSmiqullG+Nz+KbSmpkfnlvHwTr1e31R5WReFRKMXjg==",
"requires": { "requires": {
"@octokit/endpoint": "^5.5.0", "@octokit/endpoint": "^5.1.0",
"@octokit/request-error": "^1.0.1", "@octokit/request-error": "^1.0.1",
"@octokit/types": "^2.0.0",
"deprecation": "^2.0.0", "deprecation": "^2.0.0",
"is-plain-object": "^3.0.0", "is-plain-object": "^3.0.0",
"node-fetch": "^2.3.0", "node-fetch": "^2.3.0",
"once": "^1.4.0", "once": "^1.4.0",
"universal-user-agent": "^4.0.0" "universal-user-agent": "^4.0.0"
},
"dependencies": {
"universal-user-agent": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-4.0.0.tgz",
"integrity": "sha512-eM8knLpev67iBDizr/YtqkJsF3GK8gzDc6st/WKzrTuPtcsOKW/0IdL4cnMBsU69pOx0otavLWBDGTwg+dB0aA==",
"requires": {
"os-name": "^3.1.0"
}
}
} }
}, },
"@octokit/request-error": { "@octokit/request-error": {
"version": "1.2.0", "version": "1.0.4",
"resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-1.2.0.tgz", "resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-1.0.4.tgz",
"integrity": "sha512-DNBhROBYjjV/I9n7A8kVkmQNkqFAMem90dSxqvPq57e2hBr7mNTX98y3R2zDpqMQHVRpBDjsvsfIGgBzy+4PAg==", "integrity": "sha512-L4JaJDXn8SGT+5G0uX79rZLv0MNJmfGa4vb4vy1NnpjSnWDLJRy6m90udGwvMmavwsStgbv2QNkPzzTCMmL+ig==",
"requires": { "requires": {
"@octokit/types": "^2.0.0",
"deprecation": "^2.0.0", "deprecation": "^2.0.0",
"once": "^1.4.0" "once": "^1.4.0"
} }
}, },
"@octokit/rest": { "@octokit/rest": {
"version": "16.35.0", "version": "16.33.0",
"resolved": "https://registry.npmjs.org/@octokit/rest/-/rest-16.35.0.tgz", "resolved": "https://registry.npmjs.org/@octokit/rest/-/rest-16.33.0.tgz",
"integrity": "sha512-9ShFqYWo0CLoGYhA1FdtdykJuMzS/9H6vSbbQWDX4pWr4p9v+15MsH/wpd/3fIU+tSxylaNO48+PIHqOkBRx3w==", "integrity": "sha512-t4jMR+odsfooQwmHiREoTQixVTX2DfdbSaO+lKrW9R5XBuk0DW+5T/JdfwtxAGUAHgvDDpWY/NVVDfEPTzxD6g==",
"requires": { "requires": {
"@octokit/request": "^5.2.0", "@octokit/request": "^5.0.0",
"@octokit/request-error": "^1.0.2", "@octokit/request-error": "^1.0.2",
"atob-lite": "^2.0.0", "atob-lite": "^2.0.0",
"before-after-hook": "^2.0.0", "before-after-hook": "^2.0.0",
@ -659,14 +655,16 @@
"octokit-pagination-methods": "^1.1.0", "octokit-pagination-methods": "^1.1.0",
"once": "^1.4.0", "once": "^1.4.0",
"universal-user-agent": "^4.0.0" "universal-user-agent": "^4.0.0"
}
}, },
"@octokit/types": { "dependencies": {
"version": "2.0.2", "universal-user-agent": {
"resolved": "https://registry.npmjs.org/@octokit/types/-/types-2.0.2.tgz", "version": "4.0.0",
"integrity": "sha512-StASIL2lgT3TRjxv17z9pAqbnI7HGu9DrJlg3sEBFfCLaMEqp+O3IQPUF6EZtQ4xkAu2ml6kMBBCtGxjvmtmuQ==", "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-4.0.0.tgz",
"integrity": "sha512-eM8knLpev67iBDizr/YtqkJsF3GK8gzDc6st/WKzrTuPtcsOKW/0IdL4cnMBsU69pOx0otavLWBDGTwg+dB0aA==",
"requires": { "requires": {
"@types/node": ">= 8" "os-name": "^3.1.0"
}
}
} }
}, },
"@types/babel__core": { "@types/babel__core": {
@ -759,7 +757,8 @@
"@types/node": { "@types/node": {
"version": "12.7.12", "version": "12.7.12",
"resolved": "https://registry.npmjs.org/@types/node/-/node-12.7.12.tgz", "resolved": "https://registry.npmjs.org/@types/node/-/node-12.7.12.tgz",
"integrity": "sha512-KPYGmfD0/b1eXurQ59fXD1GBzhSQfz6/lKBxkaHX9dKTzjXbK68Zt7yGUxUsCS1jeTy/8aL+d9JEr+S54mpkWQ==" "integrity": "sha512-KPYGmfD0/b1eXurQ59fXD1GBzhSQfz6/lKBxkaHX9dKTzjXbK68Zt7yGUxUsCS1jeTy/8aL+d9JEr+S54mpkWQ==",
"dev": true
}, },
"@types/stack-utils": { "@types/stack-utils": {
"version": "1.0.1", "version": "1.0.1",
@ -767,15 +766,6 @@
"integrity": "sha512-l42BggppR6zLmpfU6fq9HEa2oGPEI8yrSPL3GITjfRInppYFahObbIQOQK3UGxEnyQpltZLaPe75046NOZQikw==", "integrity": "sha512-l42BggppR6zLmpfU6fq9HEa2oGPEI8yrSPL3GITjfRInppYFahObbIQOQK3UGxEnyQpltZLaPe75046NOZQikw==",
"dev": true "dev": true
}, },
"@types/uuid": {
"version": "3.4.6",
"resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-3.4.6.tgz",
"integrity": "sha512-cCdlC/1kGEZdEglzOieLDYBxHsvEOIg7kp/2FYyVR9Pxakq+Qf/inL3RKQ+PA8gOlI/NnL+fXmQH12nwcGzsHw==",
"dev": true,
"requires": {
"@types/node": "*"
}
},
"@types/yargs": { "@types/yargs": {
"version": "13.0.3", "version": "13.0.3",
"resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-13.0.3.tgz", "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-13.0.3.tgz",
@ -6613,11 +6603,6 @@
"tslib": "^1.8.1" "tslib": "^1.8.1"
} }
}, },
"tunnel": {
"version": "0.0.4",
"resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.4.tgz",
"integrity": "sha1-LTeFoVjBdMmhbcLARuxfxfF0IhM="
},
"tunnel-agent": { "tunnel-agent": {
"version": "0.6.0", "version": "0.6.0",
"resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
@ -6642,15 +6627,6 @@
"prelude-ls": "~1.1.2" "prelude-ls": "~1.1.2"
} }
}, },
"typed-rest-client": {
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/typed-rest-client/-/typed-rest-client-1.5.0.tgz",
"integrity": "sha512-DVZRlmsfnTjp6ZJaatcdyvvwYwbWvR4YDNFDqb+qdTxpvaVP99YCpBkA8rxsLtAPjBVoDe4fNsnMIdZTiPuKWg==",
"requires": {
"tunnel": "0.0.4",
"underscore": "1.8.3"
}
},
"typescript": { "typescript": {
"version": "3.6.4", "version": "3.6.4",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-3.6.4.tgz", "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.6.4.tgz",
@ -6677,11 +6653,6 @@
} }
} }
}, },
"underscore": {
"version": "1.8.3",
"resolved": "https://registry.npmjs.org/underscore/-/underscore-1.8.3.tgz",
"integrity": "sha1-Tz+1OxBuYJf8+ctBCfKl6b36UCI="
},
"union-value": { "union-value": {
"version": "1.0.1", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz",
@ -6695,11 +6666,11 @@
} }
}, },
"universal-user-agent": { "universal-user-agent": {
"version": "4.0.0", "version": "2.1.0",
"resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-4.0.0.tgz", "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-2.1.0.tgz",
"integrity": "sha512-eM8knLpev67iBDizr/YtqkJsF3GK8gzDc6st/WKzrTuPtcsOKW/0IdL4cnMBsU69pOx0otavLWBDGTwg+dB0aA==", "integrity": "sha512-8itiX7G05Tu3mGDTdNY2fB4KJ8MgZLS54RdG6PkkfwMAavrXu1mV/lls/GABx9O3Rw4PnTtasxrvbMQoBYY92Q==",
"requires": { "requires": {
"os-name": "^3.1.0" "os-name": "^3.0.0"
} }
}, },
"unset-value": { "unset-value": {
@ -6782,7 +6753,8 @@
"uuid": { "uuid": {
"version": "3.3.3", "version": "3.3.3",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.3.tgz", "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.3.tgz",
"integrity": "sha512-pW0No1RGHgzlpHJO1nsVrHKpOEIxkGg1xB+v0ZmdNH5OAeAwzAVrCnI2/6Mtx+Uys6iaylxa+D3g4j63IKKjSQ==" "integrity": "sha512-pW0No1RGHgzlpHJO1nsVrHKpOEIxkGg1xB+v0ZmdNH5OAeAwzAVrCnI2/6Mtx+Uys6iaylxa+D3g4j63IKKjSQ==",
"dev": true
}, },
"validate-npm-package-license": { "validate-npm-package-license": {
"version": "3.0.4", "version": "3.0.4",

View File

@ -31,15 +31,12 @@
"dependencies": { "dependencies": {
"@actions/core": "^1.1.3", "@actions/core": "^1.1.3",
"@actions/exec": "^1.0.1", "@actions/exec": "^1.0.1",
"@actions/github": "^2.0.0", "@actions/github": "^1.1.0",
"@actions/io": "^1.0.1", "@actions/io": "^1.0.1"
"@actions/tool-cache": "^1.1.2",
"uuid": "^3.3.3"
}, },
"devDependencies": { "devDependencies": {
"@types/jest": "^24.0.23", "@types/jest": "^24.0.23",
"@types/node": "^12.7.12", "@types/node": "^12.7.12",
"@types/uuid": "^3.4.6",
"@typescript-eslint/parser": "^2.8.0", "@typescript-eslint/parser": "^2.8.0",
"@zeit/ncc": "^0.20.5", "@zeit/ncc": "^0.20.5",
"eslint": "^5.16.0", "eslint": "^5.16.0",

View File

@ -3,13 +3,8 @@ import * as exec from '@actions/exec'
import * as fshelper from './fs-helper' import * as fshelper from './fs-helper'
import * as io from '@actions/io' import * as io from '@actions/io'
import * as path from 'path' import * as path from 'path'
import * as retryHelper from './retry-helper'
import {GitVersion} from './git-version' 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 { export interface IGitCommandManager {
branchDelete(remote: boolean, branch: string): Promise<void> branchDelete(remote: boolean, branch: string): Promise<void>
branchExists(remote: boolean, pattern: string): Promise<boolean> branchExists(remote: boolean, pattern: string): Promise<boolean>
@ -116,7 +111,7 @@ class GitCommandManager {
} }
async config(configKey: string, configValue: string): Promise<void> { async config(configKey: string, configValue: string): Promise<void> {
await this.execGit(['config', '--local', configKey, configValue]) await this.execGit(['config', configKey, configValue])
} }
async configExists(configKey: string): Promise<boolean> { async configExists(configKey: string): Promise<boolean> {
@ -124,7 +119,7 @@ class GitCommandManager {
return `\\${x}` return `\\${x}`
}) })
const output = await this.execGit( const output = await this.execGit(
['config', '--local', '--name-only', '--get-regexp', pattern], ['config', '--name-only', '--get-regexp', pattern],
true true
) )
return output.exitCode === 0 return output.exitCode === 0
@ -155,10 +150,22 @@ class GitCommandManager {
args.push(arg) args.push(arg)
} }
const that = this let attempt = 1
await retryHelper.execute(async () => { const maxAttempts = 3
await that.execGit(args) while (attempt <= maxAttempts) {
}) const allowAllExitCodes = attempt < maxAttempts
const output = await this.execGit(args, allowAllExitCodes)
if (output.exitCode === 0) {
break
}
const seconds = this.getRandomIntInclusive(1, 10)
core.warning(
`Git fetch failed with exit code ${output.exitCode}. Waiting ${seconds} seconds before trying again.`
)
await this.sleep(seconds * 1000)
attempt++
}
} }
getWorkingDirectory(): string { getWorkingDirectory(): string {
@ -181,10 +188,22 @@ class GitCommandManager {
async lfsFetch(ref: string): Promise<void> { async lfsFetch(ref: string): Promise<void> {
const args = ['lfs', 'fetch', 'origin', ref] const args = ['lfs', 'fetch', 'origin', ref]
const that = this let attempt = 1
await retryHelper.execute(async () => { const maxAttempts = 3
await that.execGit(args) while (attempt <= maxAttempts) {
}) const allowAllExitCodes = attempt < maxAttempts
const output = await this.execGit(args, allowAllExitCodes)
if (output.exitCode === 0) {
break
}
const seconds = this.getRandomIntInclusive(1, 10)
core.warning(
`Git lfs fetch failed with exit code ${output.exitCode}. Waiting ${seconds} seconds before trying again.`
)
await this.sleep(seconds * 1000)
attempt++
}
} }
async lfsInstall(): Promise<void> { async lfsInstall(): Promise<void> {
@ -211,23 +230,20 @@ class GitCommandManager {
async tryConfigUnset(configKey: string): Promise<boolean> { async tryConfigUnset(configKey: string): Promise<boolean> {
const output = await this.execGit( const output = await this.execGit(
['config', '--local', '--unset-all', configKey], ['config', '--unset-all', configKey],
true true
) )
return output.exitCode === 0 return output.exitCode === 0
} }
async tryDisableAutomaticGarbageCollection(): Promise<boolean> { async tryDisableAutomaticGarbageCollection(): Promise<boolean> {
const output = await this.execGit( const output = await this.execGit(['config', 'gc.auto', '0'], true)
['config', '--local', 'gc.auto', '0'],
true
)
return output.exitCode === 0 return output.exitCode === 0
} }
async tryGetFetchUrl(): Promise<string> { async tryGetFetchUrl(): Promise<string> {
const output = await this.execGit( const output = await this.execGit(
['config', '--local', '--get', 'remote.origin.url'], ['config', '--get', 'remote.origin.url'],
true true
) )
@ -322,9 +338,13 @@ class GitCommandManager {
} }
// Minimum git version // Minimum git version
if (!gitVersion.checkMinimum(MinimumGitVersion)) { // Note:
// - Auth header not supported before 2.9
// - Wire protocol v2 not supported before 2.18
const minimumGitVersion = new GitVersion('2.18')
if (!gitVersion.checkMinimum(minimumGitVersion)) {
throw new Error( throw new Error(
`Minimum required git version is ${MinimumGitVersion}. Your git ('${this.gitPath}') is ${gitVersion}` `Minimum required git version is ${minimumGitVersion}. Your git ('${this.gitPath}') is ${gitVersion}`
) )
} }
@ -361,6 +381,16 @@ class GitCommandManager {
core.debug(`Set git useragent to: ${gitHttpUserAgent}`) core.debug(`Set git useragent to: ${gitHttpUserAgent}`)
this.gitEnv['GIT_HTTP_USER_AGENT'] = gitHttpUserAgent this.gitEnv['GIT_HTTP_USER_AGENT'] = gitHttpUserAgent
} }
private getRandomIntInclusive(minimum: number, maximum: number): number {
minimum = Math.floor(minimum)
maximum = Math.floor(maximum)
return Math.floor(Math.random() * (maximum - minimum + 1)) + minimum
}
private async sleep(milliseconds): Promise<void> {
return new Promise(resolve => setTimeout(resolve, milliseconds))
}
} }
class GitOutput { class GitOutput {

View File

@ -1,12 +1,11 @@
import * as core from '@actions/core' import * as core from '@actions/core'
import * as coreCommand from '@actions/core/lib/command'
import * as fs from 'fs' import * as fs from 'fs'
import * as fsHelper from './fs-helper' import * as fsHelper from './fs-helper'
import * as gitCommandManager from './git-command-manager' import * as gitCommandManager from './git-command-manager'
import * as githubApiHelper from './github-api-helper'
import * as io from '@actions/io' import * as io from '@actions/io'
import * as path from 'path' import * as path from 'path'
import * as refHelper from './ref-helper' import * as refHelper from './ref-helper'
import * as stateHelper from './state-helper'
import {IGitCommandManager} from './git-command-manager' import {IGitCommandManager} from './git-command-manager'
const authConfigKey = `http.https://github.com/.extraheader` const authConfigKey = `http.https://github.com/.extraheader`
@ -20,12 +19,10 @@ export interface ISourceSettings {
clean: boolean clean: boolean
fetchDepth: number fetchDepth: number
lfs: boolean lfs: boolean
authToken: string accessToken: string
persistCredentials: boolean
} }
export async function getSource(settings: ISourceSettings): Promise<void> { export async function getSource(settings: ISourceSettings): Promise<void> {
// Repository URL
core.info( core.info(
`Syncing repository: ${settings.repositoryOwner}/${settings.repositoryName}` `Syncing repository: ${settings.repositoryOwner}/${settings.repositoryName}`
) )
@ -46,35 +43,29 @@ export async function getSource(settings: ISourceSettings): Promise<void> {
} }
// Git command manager // Git command manager
const git = await getGitCommandManager(settings) core.info(`Working directory is '${settings.repositoryPath}'`)
const git = await gitCommandManager.CreateCommandManager(
settings.repositoryPath,
settings.lfs
)
// Prepare existing directory, otherwise recreate // Try prepare existing directory, otherwise recreate
if (isExisting) { if (
await prepareExistingDirectory( isExisting &&
!(await tryPrepareExistingDirectory(
git, git,
settings.repositoryPath, settings.repositoryPath,
repositoryUrl, repositoryUrl,
settings.clean settings.clean
) ))
) {
// Delete the contents of the directory. Don't delete the directory itself
// since it may be the current working directory.
core.info(`Deleting the contents of '${settings.repositoryPath}'`)
for (const file of await fs.promises.readdir(settings.repositoryPath)) {
await io.rmRF(path.join(settings.repositoryPath, file))
}
} }
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 // Initialize the repository
if ( if (
@ -94,9 +85,14 @@ export async function getSource(settings: ISourceSettings): Promise<void> {
// Remove possible previous extraheader // Remove possible previous extraheader
await removeGitConfig(git, authConfigKey) await removeGitConfig(git, authConfigKey)
try { // Add extraheader (auth)
// Config auth token const base64Credentials = Buffer.from(
await configureAuthToken(git, settings.authToken) `x-access-token:${settings.accessToken}`,
'utf8'
).toString('base64')
core.setSecret(base64Credentials)
const authConfigValue = `AUTHORIZATION: basic ${base64Credentials}`
await git.config(authConfigKey, authConfigValue)
// LFS install // LFS install
if (settings.lfs) { if (settings.lfs) {
@ -126,12 +122,13 @@ export async function getSource(settings: ISourceSettings): Promise<void> {
// Dump some info about the checked out commit // Dump some info about the checked out commit
await git.log1() await git.log1()
} finally {
if (!settings.persistCredentials) { // Set intra-task state for cleanup
await removeGitConfig(git, authConfigKey) coreCommand.issueCommand(
} 'save-state',
} {name: 'repositoryPath'},
} settings.repositoryPath
)
} }
export async function cleanup(repositoryPath: string): Promise<void> { export async function cleanup(repositoryPath: string): Promise<void> {
@ -149,46 +146,20 @@ export async function cleanup(repositoryPath: string): Promise<void> {
await removeGitConfig(git, authConfigKey) await removeGitConfig(git, authConfigKey)
} }
async function getGitCommandManager( async function tryPrepareExistingDirectory(
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, git: IGitCommandManager,
repositoryPath: string, repositoryPath: string,
repositoryUrl: string, repositoryUrl: string,
clean: boolean clean: boolean
): Promise<void> { ): Promise<boolean> {
let remove = false
// Check whether using git or REST API
if (!git) {
remove = true
}
// Fetch URL does not match // Fetch URL does not match
else if ( if (
!fsHelper.directoryExistsSync(path.join(repositoryPath, '.git')) || !fsHelper.directoryExistsSync(path.join(repositoryPath, '.git')) ||
repositoryUrl !== (await git.tryGetFetchUrl()) repositoryUrl !== (await git.tryGetFetchUrl())
) { ) {
remove = true return false
} else { }
// Delete any index.lock and shallow.lock left by a previously canceled run or crashed git process // Delete any index.lock and shallow.lock left by a previously canceled run or crashed git process
const lockPaths = [ const lockPaths = [
path.join(repositoryPath, '.git', 'index.lock'), path.join(repositoryPath, '.git', 'index.lock'),
@ -219,74 +190,35 @@ async function prepareExistingDirectory(
for (const branch of branches) { for (const branch of branches) {
await git.branchDelete(true, branch) 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) { } catch (error) {
core.warning( core.warning(
`Unable to prepare the existing repository. The repository will be recreated instead.` `Unable to prepare the existing repository. The repository will be recreated instead.`
) )
remove = true return false
}
} }
if (remove) { // Clean
// Delete the contents of the directory. Don't delete the directory itself if (clean) {
// since it might be the current working directory. let succeeded = true
core.info(`Deleting the contents of '${repositoryPath}'`) if (!(await git.tryClean())) {
for (const file of await fs.promises.readdir(repositoryPath)) { core.debug(
await io.rmRF(path.join(repositoryPath, file)) `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}'.`
}
}
}
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) succeeded = false
} else if (!(await git.tryReset())) {
succeeded = false
}
if (!succeeded) {
core.warning(
`Unable to clean or reset the repository. The repository will be recreated instead.`
)
}
return succeeded
}
return true
} }
async function removeGitConfig( async function removeGitConfig(
@ -298,6 +230,21 @@ async function removeGitConfig(
!(await git.tryConfigUnset(configKey)) !(await git.tryConfigUnset(configKey))
) { ) {
// Load the config contents // Load the config contents
core.warning(`Failed to remove '${configKey}' from the git config`) core.warning(
`Failed to remove '${configKey}' from the git config. Attempting to remove the config value by editing the file directly.`
)
const configPath = path.join(git.getWorkingDirectory(), '.git', 'config')
fsHelper.fileExistsSync(configPath)
let contents = fs.readFileSync(configPath).toString() || ''
// Filter - only includes lines that do not contain the config key
const upperConfigKey = configKey.toUpperCase()
const split = contents
.split('\n')
.filter(x => !x.toUpperCase().includes(upperConfigKey))
contents = split.join('\n')
// Rewrite the config file
fs.writeFileSync(configPath, contents)
} }
} }

View File

@ -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
}

View File

@ -97,12 +97,8 @@ export function getInputs(): ISourceSettings {
result.lfs = (core.getInput('lfs') || 'false').toUpperCase() === 'TRUE' result.lfs = (core.getInput('lfs') || 'false').toUpperCase() === 'TRUE'
core.debug(`lfs = ${result.lfs}`) core.debug(`lfs = ${result.lfs}`)
// Auth token // Access token
result.authToken = core.getInput('token') result.accessToken = core.getInput('token')
// Persist credentials
result.persistCredentials =
(core.getInput('persist-credentials') || 'false').toUpperCase() === 'TRUE'
return result return result
} }

View File

@ -3,7 +3,8 @@ import * as coreCommand from '@actions/core/lib/command'
import * as gitSourceProvider from './git-source-provider' import * as gitSourceProvider from './git-source-provider'
import * as inputHelper from './input-helper' import * as inputHelper from './input-helper'
import * as path from 'path' import * as path from 'path'
import * as stateHelper from './state-helper'
const cleanupRepositoryPath = process.env['STATE_repositoryPath'] as string
async function run(): Promise<void> { async function run(): Promise<void> {
try { try {
@ -30,14 +31,14 @@ async function run(): Promise<void> {
async function cleanup(): Promise<void> { async function cleanup(): Promise<void> {
try { try {
await gitSourceProvider.cleanup(stateHelper.RepositoryPath) await gitSourceProvider.cleanup(cleanupRepositoryPath)
} catch (error) { } catch (error) {
core.warning(error.message) core.warning(error.message)
} }
} }
// Main // Main
if (!stateHelper.IsPost) { if (!cleanupRepositoryPath) {
run() run()
} }
// Post // Post

View File

@ -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)
}

View File

@ -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')
}