Compare commits

..

3 Commits

9 changed files with 48 additions and 246 deletions

View File

@ -18,7 +18,6 @@ When Git 2.18 or higher is not in your PATH, falls back to the REST API to downl
- Fetches only a single commit by default - Fetches only a single commit by default
- Script authenticated git commands - Script authenticated git commands
- Auth token persisted in the local git config - Auth token persisted in the local git config
- Supports SSH
- 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
- Improved layout - Improved layout
@ -27,6 +26,7 @@ When Git 2.18 or higher is not in your PATH, falls back to the REST API to downl
- Fallback to REST API download - Fallback to REST API download
- When Git 2.18 or higher is not in the PATH, the REST API will be used to download the files - When Git 2.18 or higher is not in the PATH, the REST API will be used to download the files
- When using a job container, the container's PATH is used - When using a job container, the container's PATH is used
- 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.
@ -117,6 +117,7 @@ Refer [here](https://github.com/actions/checkout/blob/v1/README.md) for previous
- [Checkout multiple repos (private)](#Checkout-multiple-repos-private) - [Checkout multiple repos (private)](#Checkout-multiple-repos-private)
- [Checkout pull request HEAD commit instead of merge commit](#Checkout-pull-request-HEAD-commit-instead-of-merge-commit) - [Checkout pull request HEAD commit instead of merge commit](#Checkout-pull-request-HEAD-commit-instead-of-merge-commit)
- [Checkout pull request on closed event](#Checkout-pull-request-on-closed-event) - [Checkout pull request on closed event](#Checkout-pull-request-on-closed-event)
- [Checkout submodules](#Checkout-submodules)
- [Fetch all tags](#Fetch-all-tags) - [Fetch all tags](#Fetch-all-tags)
- [Fetch all branches](#Fetch-all-branches) - [Fetch all branches](#Fetch-all-branches)
- [Fetch all history for all tags and branches](#Fetch-all-history-for-all-tags-and-branches) - [Fetch all history for all tags and branches](#Fetch-all-history-for-all-tags-and-branches)
@ -207,6 +208,20 @@ jobs:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
``` ```
## Checkout submodules
```yaml
- uses: actions/checkout@v2
- name: Checkout submodules
shell: bash
run: |
# If your submodules are configured to use SSH instead of HTTPS please uncomment the following line
# git config --global url."https://github.com/".insteadOf "git@github.com:"
auth_header="$(git config --local --get http.https://github.com/.extraheader)"
git submodule sync --recursive
git -c "http.extraheader=$auth_header" -c protocol.version=2 submodule update --init --force --recursive --depth=1
```
## Fetch all tags ## Fetch all tags
```yaml ```yaml

View File

@ -29,26 +29,14 @@ We want to take this opportunity to make behavioral changes, from v1. This docum
description: > description: >
Personal access token (PAT) used to fetch the repository. The PAT is configured Personal access token (PAT) used to fetch the repository. The PAT is configured
with the local git config, which enables your scripts to run authenticated git with the local git config, which enables your scripts to run authenticated git
commands. The post-job step removes the PAT. commands. The post-job step removes the PAT. [Learn more about creating and using
encrypted secrets](https://help.github.com/en/actions/automating-your-workflow-with-github-actions/creating-and-using-encrypted-secrets)
We recommend using a service account with the least permissions necessary.
Also when generating a new PAT, select the least scopes necessary.
[Learn more about creating and using encrypted secrets](https://help.github.com/en/actions/automating-your-workflow-with-github-actions/creating-and-using-encrypted-secrets)
default: ${{ github.token }} default: ${{ github.token }}
ssh-key: ssh-key:
description: > description: >
SSH key used to fetch the repository. The SSH key is configured with the local SSH key used to fetch the repository. SSH key is configured with the local
git config, which enables your scripts to run authenticated git commands. git config, which enables your scripts to run authenticated git commands.
The post-job step removes the SSH key. The post-job step removes the SSH key. [Learn more about creating and using
We recommend using a service account with the least permissions necessary.
[Learn more about creating and using
encrypted secrets](https://help.github.com/en/actions/automating-your-workflow-with-github-actions/creating-and-using-encrypted-secrets) encrypted secrets](https://help.github.com/en/actions/automating-your-workflow-with-github-actions/creating-and-using-encrypted-secrets)
ssh-known-hosts: ssh-known-hosts:
description: > description: >
@ -56,10 +44,7 @@ We want to take this opportunity to make behavioral changes, from v1. This docum
SSH keys for a host may be obtained using the utility `ssh-keyscan`. For example, SSH keys for a host may be obtained using the utility `ssh-keyscan`. For example,
`ssh-keyscan github.com`. The public key for github.com is always implicitly added. `ssh-keyscan github.com`. The public key for github.com is always implicitly added.
ssh-strict: ssh-strict:
description: > description: 'Whether to perform strict host key checking'
Whether to perform strict host key checking. When true, adds the options `StrictHostKeyChecking=yes`
and `CheckHostIP=no` to the SSH command line. Use the input `ssh-known-hosts` to
configure additional hosts.
default: true default: true
persist-credentials: persist-credentials:
description: 'Whether to configure the token or SSH key with the local git config' description: 'Whether to configure the token or SSH key with the local git config'
@ -79,11 +64,7 @@ We want to take this opportunity to make behavioral changes, from v1. This docum
description: > description: >
Whether to checkout submodules: `true` to checkout submodules or `recursive` to Whether to checkout submodules: `true` to checkout submodules or `recursive` to
recursively checkout submodules. recursively checkout submodules.
default: 'false'
When the `ssh-key` input is not provided, SSH URLs beginning with `git@github.com:` are
converted to HTTPS.
default: false
``` ```
Note: Note:

93
dist/index.js vendored
View File

@ -1266,46 +1266,6 @@ const windowsRelease = release => {
module.exports = windowsRelease; module.exports = windowsRelease;
/***/ }),
/***/ 81:
/***/ (function(__unusedmodule, exports, __webpack_require__) {
"use strict";
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];
result["default"] = mod;
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
const assert = __importStar(__webpack_require__(357));
const url_1 = __webpack_require__(835);
function getApiUrl() {
return process.env['GITHUB_API_URL'] || 'https://api.github.com';
}
exports.getApiUrl = getApiUrl;
function getFetchUrl(settings) {
assert.ok(settings.repositoryOwner, 'settings.repositoryOwner must be defined');
assert.ok(settings.repositoryName, 'settings.repositoryName must be defined');
const serviceUrl = getServerUrl();
const encodedOwner = encodeURIComponent(settings.repositoryOwner);
const encodedName = encodeURIComponent(settings.repositoryName);
if (settings.sshKey) {
return `git@${serviceUrl.hostname}:${encodedOwner}/${encodedName}.git`;
}
// "origin" is SCHEME://HOSTNAME[:PORT]
return `${serviceUrl.origin}/${encodedOwner}/${encodedName}`;
}
exports.getFetchUrl = getFetchUrl;
function getServerUrl() {
return new url_1.URL(process.env['GITHUB_URL'] || 'https://github.com');
}
exports.getServerUrl = getServerUrl;
/***/ }), /***/ }),
/***/ 87: /***/ 87:
@ -5149,9 +5109,9 @@ const os = __importStar(__webpack_require__(87));
const path = __importStar(__webpack_require__(622)); const path = __importStar(__webpack_require__(622));
const regexpHelper = __importStar(__webpack_require__(528)); const regexpHelper = __importStar(__webpack_require__(528));
const stateHelper = __importStar(__webpack_require__(153)); const stateHelper = __importStar(__webpack_require__(153));
const urlHelper = __importStar(__webpack_require__(81));
const v4_1 = __importDefault(__webpack_require__(826)); const v4_1 = __importDefault(__webpack_require__(826));
const IS_WINDOWS = process.platform === 'win32'; const IS_WINDOWS = process.platform === 'win32';
const HOSTNAME = 'github.com';
const SSH_COMMAND_KEY = 'core.sshCommand'; const SSH_COMMAND_KEY = 'core.sshCommand';
function createAuthHelper(git, settings) { function createAuthHelper(git, settings) {
return new GitAuthHelper(git, settings); return new GitAuthHelper(git, settings);
@ -5159,6 +5119,9 @@ function createAuthHelper(git, settings) {
exports.createAuthHelper = createAuthHelper; exports.createAuthHelper = createAuthHelper;
class GitAuthHelper { class GitAuthHelper {
constructor(gitCommandManager, gitSourceSettings) { constructor(gitCommandManager, gitSourceSettings) {
this.tokenConfigKey = `http.https://${HOSTNAME}/.extraheader`;
this.insteadOfKey = `url.https://${HOSTNAME}/.insteadOf`;
this.insteadOfValue = `git@${HOSTNAME}:`;
this.sshCommand = ''; this.sshCommand = '';
this.sshKeyPath = ''; this.sshKeyPath = '';
this.sshKnownHostsPath = ''; this.sshKnownHostsPath = '';
@ -5166,15 +5129,10 @@ class GitAuthHelper {
this.git = gitCommandManager; this.git = gitCommandManager;
this.settings = gitSourceSettings || {}; this.settings = gitSourceSettings || {};
// Token auth header // Token auth header
const serverUrl = urlHelper.getServerUrl();
this.tokenConfigKey = `http.${serverUrl.origin}/.extraheader`; // "origin" is SCHEME://HOSTNAME[:PORT]
const basicCredential = Buffer.from(`x-access-token:${this.settings.authToken}`, 'utf8').toString('base64'); const basicCredential = Buffer.from(`x-access-token:${this.settings.authToken}`, 'utf8').toString('base64');
core.setSecret(basicCredential); core.setSecret(basicCredential);
this.tokenPlaceholderConfigValue = `AUTHORIZATION: basic ***`; this.tokenPlaceholderConfigValue = `AUTHORIZATION: basic ***`;
this.tokenConfigValue = `AUTHORIZATION: basic ${basicCredential}`; this.tokenConfigValue = `AUTHORIZATION: basic ${basicCredential}`;
// Instead of SSH URL
this.insteadOfKey = `url.${serverUrl.origin}/.insteadOf`; // "origin" is SCHEME://HOSTNAME[:PORT]
this.insteadOfValue = `git@${serverUrl.hostname}:`;
} }
configureAuth() { configureAuth() {
return __awaiter(this, void 0, void 0, function* () { return __awaiter(this, void 0, void 0, function* () {
@ -5267,7 +5225,7 @@ class GitAuthHelper {
} }
removeGlobalAuth() { removeGlobalAuth() {
return __awaiter(this, void 0, void 0, function* () { return __awaiter(this, void 0, void 0, function* () {
core.debug(`Unsetting HOME override`); core.info(`Unsetting HOME override`);
this.git.removeEnvironmentVariable('HOME'); this.git.removeEnvironmentVariable('HOME');
yield io.rmRF(this.temporaryHomePath); yield io.rmRF(this.temporaryHomePath);
}); });
@ -5839,12 +5797,14 @@ const io = __importStar(__webpack_require__(1));
const path = __importStar(__webpack_require__(622)); const path = __importStar(__webpack_require__(622));
const refHelper = __importStar(__webpack_require__(227)); const refHelper = __importStar(__webpack_require__(227));
const stateHelper = __importStar(__webpack_require__(153)); const stateHelper = __importStar(__webpack_require__(153));
const urlHelper = __importStar(__webpack_require__(81)); const hostname = 'github.com';
function getSource(settings) { function getSource(settings) {
return __awaiter(this, void 0, void 0, function* () { return __awaiter(this, void 0, void 0, function* () {
// Repository URL // Repository URL
core.info(`Syncing repository: ${settings.repositoryOwner}/${settings.repositoryName}`); core.info(`Syncing repository: ${settings.repositoryOwner}/${settings.repositoryName}`);
const repositoryUrl = urlHelper.getFetchUrl(settings); const repositoryUrl = settings.sshKey
? `git@${hostname}:${encodeURIComponent(settings.repositoryOwner)}/${encodeURIComponent(settings.repositoryName)}.git`
: `https://${hostname}/${encodeURIComponent(settings.repositoryOwner)}/${encodeURIComponent(settings.repositoryName)}`;
// Remove conflicting file path // Remove conflicting file path
if (fsHelper.fileExistsSync(settings.repositoryPath)) { if (fsHelper.fileExistsSync(settings.repositoryPath)) {
yield io.rmRF(settings.repositoryPath); yield io.rmRF(settings.repositoryPath);
@ -5856,9 +5816,7 @@ function getSource(settings) {
yield io.mkdirP(settings.repositoryPath); yield io.mkdirP(settings.repositoryPath);
} }
// Git command manager // Git command manager
core.startGroup('Getting Git version info');
const git = yield getGitCommandManager(settings); const git = yield getGitCommandManager(settings);
core.endGroup();
// Prepare existing directory, otherwise recreate // Prepare existing directory, otherwise recreate
if (isExisting) { if (isExisting) {
yield gitDirectoryHelper.prepareExistingDirectory(git, settings.repositoryPath, repositoryUrl, settings.clean); yield gitDirectoryHelper.prepareExistingDirectory(git, settings.repositoryPath, repositoryUrl, settings.clean);
@ -5880,66 +5838,46 @@ function getSource(settings) {
stateHelper.setRepositoryPath(settings.repositoryPath); stateHelper.setRepositoryPath(settings.repositoryPath);
// Initialize the repository // Initialize the repository
if (!fsHelper.directoryExistsSync(path.join(settings.repositoryPath, '.git'))) { if (!fsHelper.directoryExistsSync(path.join(settings.repositoryPath, '.git'))) {
core.startGroup('Initializing the repository');
yield git.init(); yield git.init();
yield git.remoteAdd('origin', repositoryUrl); yield git.remoteAdd('origin', repositoryUrl);
core.endGroup();
} }
// Disable automatic garbage collection // Disable automatic garbage collection
core.startGroup('Disabling automatic garbage collection');
if (!(yield git.tryDisableAutomaticGarbageCollection())) { if (!(yield git.tryDisableAutomaticGarbageCollection())) {
core.warning(`Unable to turn off git automatic garbage collection. The git fetch operation may trigger garbage collection and cause a delay.`); core.warning(`Unable to turn off git automatic garbage collection. The git fetch operation may trigger garbage collection and cause a delay.`);
} }
core.endGroup();
const authHelper = gitAuthHelper.createAuthHelper(git, settings); const authHelper = gitAuthHelper.createAuthHelper(git, settings);
try { try {
// Configure auth // Configure auth
core.startGroup('Setting up auth');
yield authHelper.configureAuth(); yield authHelper.configureAuth();
core.endGroup();
// LFS install // LFS install
if (settings.lfs) { if (settings.lfs) {
yield git.lfsInstall(); yield git.lfsInstall();
} }
// Fetch // Fetch
core.startGroup('Fetching the repository');
const refSpec = refHelper.getRefSpec(settings.ref, settings.commit); const refSpec = refHelper.getRefSpec(settings.ref, settings.commit);
yield git.fetch(settings.fetchDepth, refSpec); yield git.fetch(settings.fetchDepth, refSpec);
core.endGroup();
// Checkout info // Checkout info
core.startGroup('Determining the checkout info');
const checkoutInfo = yield refHelper.getCheckoutInfo(git, settings.ref, settings.commit); const checkoutInfo = yield refHelper.getCheckoutInfo(git, settings.ref, settings.commit);
core.endGroup();
// LFS fetch // LFS fetch
// Explicit lfs-fetch to avoid slow checkout (fetches one lfs object at a time). // Explicit lfs-fetch to avoid slow checkout (fetches one lfs object at a time).
// Explicit lfs fetch will fetch lfs objects in parallel. // Explicit lfs fetch will fetch lfs objects in parallel.
if (settings.lfs) { if (settings.lfs) {
core.startGroup('Fetching LFS objects');
yield git.lfsFetch(checkoutInfo.startPoint || checkoutInfo.ref); yield git.lfsFetch(checkoutInfo.startPoint || checkoutInfo.ref);
core.endGroup();
} }
// Checkout // Checkout
core.startGroup('Checking out the ref');
yield git.checkout(checkoutInfo.ref, checkoutInfo.startPoint); yield git.checkout(checkoutInfo.ref, checkoutInfo.startPoint);
core.endGroup();
// Submodules // Submodules
if (settings.submodules) { if (settings.submodules) {
try { try {
// Temporarily override global config // Temporarily override global config
core.startGroup('Setting up auth for fetching submodules');
yield authHelper.configureGlobalAuth(); yield authHelper.configureGlobalAuth();
core.endGroup();
// Checkout submodules // Checkout submodules
core.startGroup('Fetching submodules');
yield git.submoduleSync(settings.nestedSubmodules); yield git.submoduleSync(settings.nestedSubmodules);
yield git.submoduleUpdate(settings.fetchDepth, settings.nestedSubmodules); yield git.submoduleUpdate(settings.fetchDepth, settings.nestedSubmodules);
yield git.submoduleForeach('git config --local gc.auto 0', settings.nestedSubmodules); yield git.submoduleForeach('git config --local gc.auto 0', settings.nestedSubmodules);
core.endGroup();
// Persist credentials // Persist credentials
if (settings.persistCredentials) { if (settings.persistCredentials) {
core.startGroup('Persisting credentials for submodules');
yield authHelper.configureSubmoduleAuth(); yield authHelper.configureSubmoduleAuth();
core.endGroup();
} }
} }
finally { finally {
@ -5953,9 +5891,7 @@ function getSource(settings) {
finally { finally {
// Remove auth // Remove auth
if (!settings.persistCredentials) { if (!settings.persistCredentials) {
core.startGroup('Removing auth');
yield authHelper.removeAuth(); yield authHelper.removeAuth();
core.endGroup();
} }
} }
}); });
@ -7255,7 +7191,6 @@ var __importStar = (this && this.__importStar) || function (mod) {
return result; return result;
}; };
Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "__esModule", { value: true });
const assert = __importStar(__webpack_require__(357));
const core = __importStar(__webpack_require__(470)); const core = __importStar(__webpack_require__(470));
const fs = __importStar(__webpack_require__(747)); const fs = __importStar(__webpack_require__(747));
const fsHelper = __importStar(__webpack_require__(618)); const fsHelper = __importStar(__webpack_require__(618));
@ -7263,9 +7198,6 @@ const io = __importStar(__webpack_require__(1));
const path = __importStar(__webpack_require__(622)); const path = __importStar(__webpack_require__(622));
function prepareExistingDirectory(git, repositoryPath, repositoryUrl, clean) { function prepareExistingDirectory(git, repositoryPath, repositoryUrl, clean) {
return __awaiter(this, void 0, void 0, function* () { return __awaiter(this, void 0, void 0, function* () {
assert.ok(repositoryPath, 'Expected repositoryPath to be defined');
assert.ok(repositoryUrl, 'Expected repositoryUrl to be defined');
// Indicates whether to delete the directory contents
let remove = false; let remove = false;
// Check whether using git or REST API // Check whether using git or REST API
if (!git) { if (!git) {
@ -7291,7 +7223,6 @@ function prepareExistingDirectory(git, repositoryPath, repositoryUrl, clean) {
} }
} }
try { try {
core.startGroup('Removing previously created refs, to avoid conflicts');
// Checkout detached HEAD // Checkout detached HEAD
if (!(yield git.isDetached())) { if (!(yield git.isDetached())) {
yield git.checkoutDetach(); yield git.checkoutDetach();
@ -7306,10 +7237,8 @@ function prepareExistingDirectory(git, repositoryPath, repositoryUrl, clean) {
for (const branch of branches) { for (const branch of branches) {
yield git.branchDelete(true, branch); yield git.branchDelete(true, branch);
} }
core.endGroup();
// Clean // Clean
if (clean) { if (clean) {
core.startGroup('Cleaning the repository');
if (!(yield git.tryClean())) { if (!(yield 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}'.`); 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; remove = true;
@ -7317,7 +7246,6 @@ function prepareExistingDirectory(git, repositoryPath, repositoryUrl, clean) {
else if (!(yield git.tryReset())) { else if (!(yield git.tryReset())) {
remove = true; remove = true;
} }
core.endGroup();
if (remove) { if (remove) {
core.warning(`Unable to clean or reset the repository. The repository will be recreated instead.`); core.warning(`Unable to clean or reset the repository. The repository will be recreated instead.`);
} }
@ -9231,7 +9159,6 @@ const io = __importStar(__webpack_require__(1));
const path = __importStar(__webpack_require__(622)); const path = __importStar(__webpack_require__(622));
const retryHelper = __importStar(__webpack_require__(587)); const retryHelper = __importStar(__webpack_require__(587));
const toolCache = __importStar(__webpack_require__(533)); const toolCache = __importStar(__webpack_require__(533));
const urlHelper = __importStar(__webpack_require__(81));
const v4_1 = __importDefault(__webpack_require__(826)); const v4_1 = __importDefault(__webpack_require__(826));
const IS_WINDOWS = process.platform === 'win32'; const IS_WINDOWS = process.platform === 'win32';
function downloadRepository(authToken, owner, repo, ref, commit, repositoryPath) { function downloadRepository(authToken, owner, repo, ref, commit, repositoryPath) {
@ -9282,7 +9209,7 @@ function downloadRepository(authToken, owner, repo, ref, commit, repositoryPath)
exports.downloadRepository = downloadRepository; exports.downloadRepository = downloadRepository;
function downloadArchive(authToken, owner, repo, ref, commit) { function downloadArchive(authToken, owner, repo, ref, commit) {
return __awaiter(this, void 0, void 0, function* () { return __awaiter(this, void 0, void 0, function* () {
const octokit = new github.GitHub(authToken, { baseUrl: urlHelper.getApiUrl() }); const octokit = new github.GitHub(authToken);
const params = { const params = {
owner: owner, owner: owner,
repo: repo, repo: repo,

View File

@ -7,12 +7,12 @@ import * as os from 'os'
import * as path from 'path' import * as path from 'path'
import * as regexpHelper from './regexp-helper' import * as regexpHelper from './regexp-helper'
import * as stateHelper from './state-helper' import * as stateHelper from './state-helper'
import * as urlHelper from './url-helper'
import {default as uuid} from 'uuid/v4' import {default as uuid} from 'uuid/v4'
import {IGitCommandManager} from './git-command-manager' import {IGitCommandManager} from './git-command-manager'
import {IGitSourceSettings} from './git-source-settings' import {IGitSourceSettings} from './git-source-settings'
const IS_WINDOWS = process.platform === 'win32' const IS_WINDOWS = process.platform === 'win32'
const HOSTNAME = 'github.com'
const SSH_COMMAND_KEY = 'core.sshCommand' const SSH_COMMAND_KEY = 'core.sshCommand'
export interface IGitAuthHelper { export interface IGitAuthHelper {
@ -33,15 +33,15 @@ export function createAuthHelper(
class GitAuthHelper { class GitAuthHelper {
private readonly git: IGitCommandManager private readonly git: IGitCommandManager
private readonly settings: IGitSourceSettings private readonly settings: IGitSourceSettings
private readonly tokenConfigKey: string private readonly tokenConfigKey: string = `http.https://${HOSTNAME}/.extraheader`
private readonly tokenConfigValue: string
private readonly tokenPlaceholderConfigValue: string private readonly tokenPlaceholderConfigValue: string
private readonly insteadOfKey: string private readonly insteadOfKey: string = `url.https://${HOSTNAME}/.insteadOf`
private readonly insteadOfValue: string private readonly insteadOfValue: string = `git@${HOSTNAME}:`
private sshCommand = '' private sshCommand = ''
private sshKeyPath = '' private sshKeyPath = ''
private sshKnownHostsPath = '' private sshKnownHostsPath = ''
private temporaryHomePath = '' private temporaryHomePath = ''
private tokenConfigValue: string
constructor( constructor(
gitCommandManager: IGitCommandManager, gitCommandManager: IGitCommandManager,
@ -51,8 +51,6 @@ class GitAuthHelper {
this.settings = gitSourceSettings || (({} as unknown) as IGitSourceSettings) this.settings = gitSourceSettings || (({} as unknown) as IGitSourceSettings)
// Token auth header // Token auth header
const serverUrl = urlHelper.getServerUrl()
this.tokenConfigKey = `http.${serverUrl.origin}/.extraheader` // "origin" is SCHEME://HOSTNAME[:PORT]
const basicCredential = Buffer.from( const basicCredential = Buffer.from(
`x-access-token:${this.settings.authToken}`, `x-access-token:${this.settings.authToken}`,
'utf8' 'utf8'
@ -60,10 +58,6 @@ class GitAuthHelper {
core.setSecret(basicCredential) core.setSecret(basicCredential)
this.tokenPlaceholderConfigValue = `AUTHORIZATION: basic ***` this.tokenPlaceholderConfigValue = `AUTHORIZATION: basic ***`
this.tokenConfigValue = `AUTHORIZATION: basic ${basicCredential}` this.tokenConfigValue = `AUTHORIZATION: basic ${basicCredential}`
// Instead of SSH URL
this.insteadOfKey = `url.${serverUrl.origin}/.insteadOf` // "origin" is SCHEME://HOSTNAME[:PORT]
this.insteadOfValue = `git@${serverUrl.hostname}:`
} }
async configureAuth(): Promise<void> { async configureAuth(): Promise<void> {
@ -173,7 +167,7 @@ class GitAuthHelper {
} }
async removeGlobalAuth(): Promise<void> { async removeGlobalAuth(): Promise<void> {
core.debug(`Unsetting HOME override`) core.info(`Unsetting HOME override`)
this.git.removeEnvironmentVariable('HOME') this.git.removeEnvironmentVariable('HOME')
await io.rmRF(this.temporaryHomePath) await io.rmRF(this.temporaryHomePath)
} }

View File

@ -1,11 +1,9 @@
import * as assert from 'assert'
import * as core from '@actions/core' import * as core from '@actions/core'
import * as fs from 'fs' import * as fs from 'fs'
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 {IGitCommandManager} from './git-command-manager' import {IGitCommandManager} from './git-command-manager'
import {IGitSourceSettings} from './git-source-settings'
export async function prepareExistingDirectory( export async function prepareExistingDirectory(
git: IGitCommandManager | undefined, git: IGitCommandManager | undefined,
@ -13,10 +11,6 @@ export async function prepareExistingDirectory(
repositoryUrl: string, repositoryUrl: string,
clean: boolean clean: boolean
): Promise<void> { ): Promise<void> {
assert.ok(repositoryPath, 'Expected repositoryPath to be defined')
assert.ok(repositoryUrl, 'Expected repositoryUrl to be defined')
// Indicates whether to delete the directory contents
let remove = false let remove = false
// Check whether using git or REST API // Check whether using git or REST API
@ -44,7 +38,6 @@ export async function prepareExistingDirectory(
} }
try { try {
core.startGroup('Removing previously created refs, to avoid conflicts')
// Checkout detached HEAD // Checkout detached HEAD
if (!(await git.isDetached())) { if (!(await git.isDetached())) {
await git.checkoutDetach() await git.checkoutDetach()
@ -61,11 +54,9 @@ export async function prepareExistingDirectory(
for (const branch of branches) { for (const branch of branches) {
await git.branchDelete(true, branch) await git.branchDelete(true, branch)
} }
core.endGroup()
// Clean // Clean
if (clean) { if (clean) {
core.startGroup('Cleaning the repository')
if (!(await git.tryClean())) { if (!(await git.tryClean())) {
core.debug( 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}'.` `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}'.`
@ -74,7 +65,6 @@ export async function prepareExistingDirectory(
} else if (!(await git.tryReset())) { } else if (!(await git.tryReset())) {
remove = true remove = true
} }
core.endGroup()
if (remove) { if (remove) {
core.warning( core.warning(

View File

@ -8,16 +8,23 @@ 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 * as stateHelper from './state-helper'
import * as urlHelper from './url-helper'
import {IGitCommandManager} from './git-command-manager' import {IGitCommandManager} from './git-command-manager'
import {IGitSourceSettings} from './git-source-settings' import {IGitSourceSettings} from './git-source-settings'
const hostname = 'github.com'
export async function getSource(settings: IGitSourceSettings): Promise<void> { export async function getSource(settings: IGitSourceSettings): Promise<void> {
// Repository URL // Repository URL
core.info( core.info(
`Syncing repository: ${settings.repositoryOwner}/${settings.repositoryName}` `Syncing repository: ${settings.repositoryOwner}/${settings.repositoryName}`
) )
const repositoryUrl = urlHelper.getFetchUrl(settings) const repositoryUrl = settings.sshKey
? `git@${hostname}:${encodeURIComponent(
settings.repositoryOwner
)}/${encodeURIComponent(settings.repositoryName)}.git`
: `https://${hostname}/${encodeURIComponent(
settings.repositoryOwner
)}/${encodeURIComponent(settings.repositoryName)}`
// Remove conflicting file path // Remove conflicting file path
if (fsHelper.fileExistsSync(settings.repositoryPath)) { if (fsHelper.fileExistsSync(settings.repositoryPath)) {
@ -32,9 +39,7 @@ export async function getSource(settings: IGitSourceSettings): Promise<void> {
} }
// Git command manager // Git command manager
core.startGroup('Getting Git version info')
const git = await getGitCommandManager(settings) const git = await getGitCommandManager(settings)
core.endGroup()
// Prepare existing directory, otherwise recreate // Prepare existing directory, otherwise recreate
if (isExisting) { if (isExisting) {
@ -80,27 +85,21 @@ export async function getSource(settings: IGitSourceSettings): Promise<void> {
if ( if (
!fsHelper.directoryExistsSync(path.join(settings.repositoryPath, '.git')) !fsHelper.directoryExistsSync(path.join(settings.repositoryPath, '.git'))
) { ) {
core.startGroup('Initializing the repository')
await git.init() await git.init()
await git.remoteAdd('origin', repositoryUrl) await git.remoteAdd('origin', repositoryUrl)
core.endGroup()
} }
// Disable automatic garbage collection // Disable automatic garbage collection
core.startGroup('Disabling automatic garbage collection')
if (!(await git.tryDisableAutomaticGarbageCollection())) { if (!(await git.tryDisableAutomaticGarbageCollection())) {
core.warning( core.warning(
`Unable to turn off git automatic garbage collection. The git fetch operation may trigger garbage collection and cause a delay.` `Unable to turn off git automatic garbage collection. The git fetch operation may trigger garbage collection and cause a delay.`
) )
} }
core.endGroup()
const authHelper = gitAuthHelper.createAuthHelper(git, settings) const authHelper = gitAuthHelper.createAuthHelper(git, settings)
try { try {
// Configure auth // Configure auth
core.startGroup('Setting up auth')
await authHelper.configureAuth() await authHelper.configureAuth()
core.endGroup()
// LFS install // LFS install
if (settings.lfs) { if (settings.lfs) {
@ -108,44 +107,33 @@ export async function getSource(settings: IGitSourceSettings): Promise<void> {
} }
// Fetch // Fetch
core.startGroup('Fetching the repository')
const refSpec = refHelper.getRefSpec(settings.ref, settings.commit) const refSpec = refHelper.getRefSpec(settings.ref, settings.commit)
await git.fetch(settings.fetchDepth, refSpec) await git.fetch(settings.fetchDepth, refSpec)
core.endGroup()
// Checkout info // Checkout info
core.startGroup('Determining the checkout info')
const checkoutInfo = await refHelper.getCheckoutInfo( const checkoutInfo = await refHelper.getCheckoutInfo(
git, git,
settings.ref, settings.ref,
settings.commit settings.commit
) )
core.endGroup()
// LFS fetch // LFS fetch
// Explicit lfs-fetch to avoid slow checkout (fetches one lfs object at a time). // Explicit lfs-fetch to avoid slow checkout (fetches one lfs object at a time).
// Explicit lfs fetch will fetch lfs objects in parallel. // Explicit lfs fetch will fetch lfs objects in parallel.
if (settings.lfs) { if (settings.lfs) {
core.startGroup('Fetching LFS objects')
await git.lfsFetch(checkoutInfo.startPoint || checkoutInfo.ref) await git.lfsFetch(checkoutInfo.startPoint || checkoutInfo.ref)
core.endGroup()
} }
// Checkout // Checkout
core.startGroup('Checking out the ref')
await git.checkout(checkoutInfo.ref, checkoutInfo.startPoint) await git.checkout(checkoutInfo.ref, checkoutInfo.startPoint)
core.endGroup()
// Submodules // Submodules
if (settings.submodules) { if (settings.submodules) {
try { try {
// Temporarily override global config // Temporarily override global config
core.startGroup('Setting up auth for fetching submodules')
await authHelper.configureGlobalAuth() await authHelper.configureGlobalAuth()
core.endGroup()
// Checkout submodules // Checkout submodules
core.startGroup('Fetching submodules')
await git.submoduleSync(settings.nestedSubmodules) await git.submoduleSync(settings.nestedSubmodules)
await git.submoduleUpdate( await git.submoduleUpdate(
settings.fetchDepth, settings.fetchDepth,
@ -155,13 +143,10 @@ export async function getSource(settings: IGitSourceSettings): Promise<void> {
'git config --local gc.auto 0', 'git config --local gc.auto 0',
settings.nestedSubmodules settings.nestedSubmodules
) )
core.endGroup()
// Persist credentials // Persist credentials
if (settings.persistCredentials) { if (settings.persistCredentials) {
core.startGroup('Persisting credentials for submodules')
await authHelper.configureSubmoduleAuth() await authHelper.configureSubmoduleAuth()
core.endGroup()
} }
} finally { } finally {
// Remove temporary global config override // Remove temporary global config override
@ -174,9 +159,7 @@ export async function getSource(settings: IGitSourceSettings): Promise<void> {
} finally { } finally {
// Remove auth // Remove auth
if (!settings.persistCredentials) { if (!settings.persistCredentials) {
core.startGroup('Removing auth')
await authHelper.removeAuth() await authHelper.removeAuth()
core.endGroup()
} }
} }
} }

View File

@ -1,76 +1,17 @@
export interface IGitSourceSettings { export interface IGitSourceSettings {
/**
* The location on disk where the repository will be placed
*/
repositoryPath: string repositoryPath: string
/**
* The repository owner
*/
repositoryOwner: string repositoryOwner: string
/**
* The repository name
*/
repositoryName: string repositoryName: string
/**
* The ref to fetch
*/
ref: string ref: string
/**
* The commit to checkout
*/
commit: string commit: string
/**
* Indicates whether to clean the repository
*/
clean: boolean clean: boolean
/**
* The depth when fetching
*/
fetchDepth: number fetchDepth: number
/**
* Indicates whether to fetch LFS objects
*/
lfs: boolean lfs: boolean
/**
* Indicates whether to checkout submodules
*/
submodules: boolean submodules: boolean
/**
* Indicates whether to recursively checkout submodules
*/
nestedSubmodules: boolean nestedSubmodules: boolean
/**
* The auth token to use when fetching the repository
*/
authToken: string authToken: string
/**
* The SSH key to configure
*/
sshKey: string sshKey: string
/**
* Additional SSH known hosts
*/
sshKnownHosts: string sshKnownHosts: string
/**
* Indicates whether the server must be a known host
*/
sshStrict: boolean sshStrict: boolean
/**
* Indicates whether to persist the credentials on disk to enable scripting authenticated git commands
*/
persistCredentials: boolean persistCredentials: boolean
} }

View File

@ -6,7 +6,6 @@ import * as io from '@actions/io'
import * as path from 'path' import * as path from 'path'
import * as retryHelper from './retry-helper' import * as retryHelper from './retry-helper'
import * as toolCache from '@actions/tool-cache' import * as toolCache from '@actions/tool-cache'
import * as urlHelper from './url-helper'
import {default as uuid} from 'uuid/v4' import {default as uuid} from 'uuid/v4'
import {ReposGetArchiveLinkParams} from '@octokit/rest' import {ReposGetArchiveLinkParams} from '@octokit/rest'
@ -75,7 +74,7 @@ async function downloadArchive(
ref: string, ref: string,
commit: string commit: string
): Promise<Buffer> { ): Promise<Buffer> {
const octokit = new github.GitHub(authToken, {baseUrl: urlHelper.getApiUrl()}) const octokit = new github.GitHub(authToken)
const params: ReposGetArchiveLinkParams = { const params: ReposGetArchiveLinkParams = {
owner: owner, owner: owner,
repo: repo, repo: repo,

View File

@ -1,28 +0,0 @@
import * as assert from 'assert'
import {IGitSourceSettings} from './git-source-settings'
import {URL} from 'url'
export function getApiUrl(): string {
return process.env['GITHUB_API_URL'] || 'https://api.github.com'
}
export function getFetchUrl(settings: IGitSourceSettings): string {
assert.ok(
settings.repositoryOwner,
'settings.repositoryOwner must be defined'
)
assert.ok(settings.repositoryName, 'settings.repositoryName must be defined')
const serviceUrl = getServerUrl()
const encodedOwner = encodeURIComponent(settings.repositoryOwner)
const encodedName = encodeURIComponent(settings.repositoryName)
if (settings.sshKey) {
return `git@${serviceUrl.hostname}:${encodedOwner}/${encodedName}.git`
}
// "origin" is SCHEME://HOSTNAME[:PORT]
return `${serviceUrl.origin}/${encodedOwner}/${encodedName}`
}
export function getServerUrl(): URL {
return new URL(process.env['GITHUB_URL'] || 'https://github.com')
}