Compare commits

..

5 Commits

Author SHA1 Message Date
c455122937 . 2020-03-19 00:43:38 -04:00
605b7eb961 . 2020-03-19 00:37:38 -04:00
036772999d . 2020-03-19 00:14:00 -04:00
46054cf00b . 2020-03-18 23:34:02 -04:00
85a425b582 use token for workflow repo 2020-03-18 23:33:26 -04:00
13 changed files with 190 additions and 158 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
- Script authenticated git commands
- Auth token persisted in the local git config
- Supports SSH
- Creates a local branch
- No longer detached HEAD when checking out a branch
- Improved layout
@ -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
- 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
- Removed input `submodules`
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 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 submodules](#Checkout-submodules)
- [Fetch all tags](#Fetch-all-tags)
- [Fetch all branches](#Fetch-all-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
```
## 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
```yaml

View File

@ -725,6 +725,7 @@ async function setup(testName: string): Promise<void> {
setEnvironmentVariable: jest.fn((name: string, value: string) => {
git.env[name] = value
}),
setRemoteUrl: jest.fn(),
submoduleForeach: jest.fn(async () => {
return ''
}),
@ -748,7 +749,7 @@ async function setup(testName: string): Promise<void> {
}
),
tryDisableAutomaticGarbageCollection: jest.fn(),
tryGetFetchUrl: jest.fn(),
tryGetRemoteUrl: jest.fn(),
tryReset: jest.fn()
}
@ -757,6 +758,7 @@ async function setup(testName: string): Promise<void> {
clean: true,
commit: '',
fetchDepth: 1,
isWorkflowRepository: true,
lfs: false,
submodules: false,
nestedSubmodules: false,

View File

@ -7,7 +7,8 @@ import {IGitCommandManager} from '../lib/git-command-manager'
const testWorkspace = path.join(__dirname, '_temp', 'git-directory-helper')
let repositoryPath: string
let repositoryUrl: string
let httpsUrl: string
let sshUrl: string
let clean: boolean
let git: IGitCommandManager
@ -40,7 +41,8 @@ describe('git-directory-helper tests', () => {
await gitDirectoryHelper.prepareExistingDirectory(
git,
repositoryPath,
repositoryUrl,
httpsUrl,
[httpsUrl, sshUrl],
clean
)
@ -62,7 +64,8 @@ describe('git-directory-helper tests', () => {
await gitDirectoryHelper.prepareExistingDirectory(
git,
repositoryPath,
repositoryUrl,
httpsUrl,
[httpsUrl, sshUrl],
clean
)
@ -87,7 +90,8 @@ describe('git-directory-helper tests', () => {
await gitDirectoryHelper.prepareExistingDirectory(
git,
repositoryPath,
repositoryUrl,
httpsUrl,
[httpsUrl, sshUrl],
clean
)
@ -108,7 +112,8 @@ describe('git-directory-helper tests', () => {
await gitDirectoryHelper.prepareExistingDirectory(
git,
repositoryPath,
repositoryUrl,
httpsUrl,
[httpsUrl, sshUrl],
clean
)
@ -136,7 +141,8 @@ describe('git-directory-helper tests', () => {
await gitDirectoryHelper.prepareExistingDirectory(
git,
repositoryPath,
repositoryUrl,
httpsUrl,
[httpsUrl, sshUrl],
clean
)
@ -155,14 +161,15 @@ describe('git-directory-helper tests', () => {
await setup(removesContentsWhenDifferentRepositoryUrl)
clean = false
await fs.promises.writeFile(path.join(repositoryPath, 'my-file'), '')
const differentRepositoryUrl =
const differentRemoteUrl =
'https://github.com/my-different-org/my-different-repo'
// Act
await gitDirectoryHelper.prepareExistingDirectory(
git,
repositoryPath,
differentRepositoryUrl,
differentRemoteUrl,
[differentRemoteUrl],
clean
)
@ -186,7 +193,8 @@ describe('git-directory-helper tests', () => {
await gitDirectoryHelper.prepareExistingDirectory(
git,
repositoryPath,
repositoryUrl,
httpsUrl,
[httpsUrl, sshUrl],
clean
)
@ -211,7 +219,8 @@ describe('git-directory-helper tests', () => {
await gitDirectoryHelper.prepareExistingDirectory(
git,
repositoryPath,
repositoryUrl,
httpsUrl,
[httpsUrl, sshUrl],
clean
)
@ -235,7 +244,8 @@ describe('git-directory-helper tests', () => {
await gitDirectoryHelper.prepareExistingDirectory(
undefined,
repositoryPath,
repositoryUrl,
httpsUrl,
[httpsUrl, sshUrl],
clean
)
@ -259,7 +269,8 @@ describe('git-directory-helper tests', () => {
await gitDirectoryHelper.prepareExistingDirectory(
git,
repositoryPath,
repositoryUrl,
httpsUrl,
[httpsUrl, sshUrl],
clean
)
@ -289,7 +300,8 @@ describe('git-directory-helper tests', () => {
await gitDirectoryHelper.prepareExistingDirectory(
git,
repositoryPath,
repositoryUrl,
httpsUrl,
[httpsUrl, sshUrl],
clean
)
@ -319,7 +331,8 @@ describe('git-directory-helper tests', () => {
await gitDirectoryHelper.prepareExistingDirectory(
git,
repositoryPath,
repositoryUrl,
httpsUrl,
[httpsUrl, sshUrl],
clean
)
@ -329,6 +342,30 @@ describe('git-directory-helper tests', () => {
expect(git.branchDelete).toHaveBeenCalledWith(true, 'remote-branch-1')
expect(git.branchDelete).toHaveBeenCalledWith(true, 'remote-branch-2')
})
const updatesRemoteUrl = 'updates remote URL'
it(updatesRemoteUrl, async () => {
// Arrange
await setup(updatesRemoteUrl)
await fs.promises.writeFile(path.join(repositoryPath, 'my-file'), '')
// Act
await gitDirectoryHelper.prepareExistingDirectory(
git,
repositoryPath,
sshUrl,
[sshUrl, httpsUrl],
clean
)
// Assert
const files = await fs.promises.readdir(repositoryPath)
expect(files.sort()).toEqual(['.git', 'my-file'])
expect(git.isDetached).toHaveBeenCalled()
expect(git.branchList).toHaveBeenCalled()
expect(core.warning).not.toHaveBeenCalled()
expect(git.setRemoteUrl).toHaveBeenCalledWith(sshUrl)
})
})
async function setup(testName: string): Promise<void> {
@ -338,8 +375,9 @@ async function setup(testName: string): Promise<void> {
repositoryPath = path.join(testWorkspace, testName)
await fs.promises.mkdir(path.join(repositoryPath, '.git'), {recursive: true})
// Repository URL
repositoryUrl = 'https://github.com/my-org/my-repo'
// Remote URLs
httpsUrl = 'https://github.com/my-org/my-repo'
sshUrl = 'git@github.com:my-org/my-repo'
// Clean
clean = true
@ -365,6 +403,7 @@ async function setup(testName: string): Promise<void> {
remoteAdd: jest.fn(),
removeEnvironmentVariable: jest.fn(),
setEnvironmentVariable: jest.fn(),
setRemoteUrl: jest.fn(),
submoduleForeach: jest.fn(),
submoduleSync: jest.fn(),
submoduleUpdate: jest.fn(),
@ -374,10 +413,10 @@ async function setup(testName: string): Promise<void> {
}),
tryConfigUnset: jest.fn(),
tryDisableAutomaticGarbageCollection: jest.fn(),
tryGetFetchUrl: jest.fn(async () => {
tryGetRemoteUrl: jest.fn(async () => {
// Sanity check - this function shouldn't be called when the .git directory doesn't exist
await fs.promises.stat(path.join(repositoryPath, '.git'))
return repositoryUrl
return httpsUrl
}),
tryReset: jest.fn(async () => {
return true

View File

@ -29,26 +29,14 @@ We want to take this opportunity to make behavioral changes, from v1. This docum
description: >
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
commands. The post-job step removes the PAT.
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)
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)
default: ${{ github.token }}
ssh-key:
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.
The post-job step removes the SSH key.
We recommend using a service account with the least permissions necessary.
[Learn more about creating and using
The post-job step removes the SSH key. [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)
ssh-known-hosts:
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-keyscan github.com`. The public key for github.com is always implicitly added.
ssh-strict:
description: >
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.
description: 'Whether to perform strict host key checking'
default: true
persist-credentials:
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: >
Whether to checkout submodules: `true` to checkout submodules or `recursive` to
recursively checkout submodules.
When the `ssh-key` input is not provided, SSH URLs beginning with `git@github.com:` are
converted to HTTPS.
default: false
default: 'false'
```
Note:

103
dist/index.js vendored
View File

@ -1266,46 +1266,6 @@ const windowsRelease = release => {
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:
@ -5149,9 +5109,9 @@ const os = __importStar(__webpack_require__(87));
const path = __importStar(__webpack_require__(622));
const regexpHelper = __importStar(__webpack_require__(528));
const stateHelper = __importStar(__webpack_require__(153));
const urlHelper = __importStar(__webpack_require__(81));
const v4_1 = __importDefault(__webpack_require__(826));
const IS_WINDOWS = process.platform === 'win32';
const HOSTNAME = 'github.com';
const SSH_COMMAND_KEY = 'core.sshCommand';
function createAuthHelper(git, settings) {
return new GitAuthHelper(git, settings);
@ -5159,6 +5119,9 @@ function createAuthHelper(git, settings) {
exports.createAuthHelper = createAuthHelper;
class GitAuthHelper {
constructor(gitCommandManager, gitSourceSettings) {
this.tokenConfigKey = `http.https://${HOSTNAME}/.extraheader`;
this.insteadOfKey = `url.https://${HOSTNAME}/.insteadOf`;
this.insteadOfValue = `git@${HOSTNAME}:`;
this.sshCommand = '';
this.sshKeyPath = '';
this.sshKnownHostsPath = '';
@ -5166,15 +5129,10 @@ class GitAuthHelper {
this.git = gitCommandManager;
this.settings = gitSourceSettings || {};
// 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');
core.setSecret(basicCredential);
this.tokenPlaceholderConfigValue = `AUTHORIZATION: basic ***`;
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() {
return __awaiter(this, void 0, void 0, function* () {
@ -5623,6 +5581,11 @@ class GitCommandManager {
setEnvironmentVariable(name, value) {
this.gitEnv[name] = value;
}
setRemoteUrl(value) {
return __awaiter(this, void 0, void 0, function* () {
yield this.config('git.remote.url', value);
});
}
submoduleForeach(command, recursive) {
return __awaiter(this, void 0, void 0, function* () {
const args = ['submodule', 'foreach'];
@ -5685,7 +5648,7 @@ class GitCommandManager {
return output.exitCode === 0;
});
}
tryGetFetchUrl() {
tryGetRemoteUrl() {
return __awaiter(this, void 0, void 0, function* () {
const output = yield this.execGit(['config', '--local', '--get', 'remote.origin.url'], true);
if (output.exitCode !== 0) {
@ -5839,12 +5802,15 @@ const io = __importStar(__webpack_require__(1));
const path = __importStar(__webpack_require__(622));
const refHelper = __importStar(__webpack_require__(227));
const stateHelper = __importStar(__webpack_require__(153));
const urlHelper = __importStar(__webpack_require__(81));
const hostname = 'github.com';
function getSource(settings) {
return __awaiter(this, void 0, void 0, function* () {
// Repository URL
core.info(`Syncing repository: ${settings.repositoryOwner}/${settings.repositoryName}`);
const repositoryUrl = urlHelper.getFetchUrl(settings);
// Remote URL
const httpsUrl = `https://${hostname}/${encodeURIComponent(settings.repositoryOwner)}/${encodeURIComponent(settings.repositoryName)}`;
const sshUrl = `git@${hostname}:${encodeURIComponent(settings.repositoryOwner)}/${encodeURIComponent(settings.repositoryName)}.git`;
// Always fetch the workflow repository using the token, not the SSH key
const initialRemoteUrl = !settings.sshKey || settings.isWorkflowRepository ? httpsUrl : sshUrl;
// Remove conflicting file path
if (fsHelper.fileExistsSync(settings.repositoryPath)) {
yield io.rmRF(settings.repositoryPath);
@ -5861,7 +5827,7 @@ function getSource(settings) {
core.endGroup();
// Prepare existing directory, otherwise recreate
if (isExisting) {
yield gitDirectoryHelper.prepareExistingDirectory(git, settings.repositoryPath, repositoryUrl, settings.clean);
yield gitDirectoryHelper.prepareExistingDirectory(git, settings.repositoryPath, initialRemoteUrl, [httpsUrl, sshUrl], settings.clean);
}
if (!git) {
// Downloading using REST API
@ -5882,7 +5848,7 @@ function getSource(settings) {
if (!fsHelper.directoryExistsSync(path.join(settings.repositoryPath, '.git'))) {
core.startGroup('Initializing the repository');
yield git.init();
yield git.remoteAdd('origin', repositoryUrl);
yield git.remoteAdd('origin', initialRemoteUrl);
core.endGroup();
}
// Disable automatic garbage collection
@ -5918,6 +5884,12 @@ function getSource(settings) {
yield git.lfsFetch(checkoutInfo.startPoint || checkoutInfo.ref);
core.endGroup();
}
// Fix URL when using SSH
if (settings.sshKey && initialRemoteUrl !== sshUrl) {
core.startGroup('Updating the remote URL');
yield git.setRemoteUrl(sshUrl);
core.endGroup();
}
// Checkout
core.startGroup('Checking out the ref');
yield git.checkout(checkoutInfo.ref, checkoutInfo.startPoint);
@ -7261,19 +7233,23 @@ const fs = __importStar(__webpack_require__(747));
const fsHelper = __importStar(__webpack_require__(618));
const io = __importStar(__webpack_require__(1));
const path = __importStar(__webpack_require__(622));
function prepareExistingDirectory(git, repositoryPath, repositoryUrl, clean) {
function prepareExistingDirectory(git, repositoryPath, preferredRemoteUrl, allowedRemoteUrls, clean) {
return __awaiter(this, void 0, void 0, function* () {
assert.ok(repositoryPath, 'Expected repositoryPath to be defined');
assert.ok(repositoryUrl, 'Expected repositoryUrl to be defined');
assert.ok(preferredRemoteUrl, 'Expected preferredRemoteUrl to be defined');
assert.ok(allowedRemoteUrls, 'Expected allowedRemoteUrls to be defined');
assert.ok(allowedRemoteUrls.length, 'Expected allowedRemoteUrls to have at least one value');
// Indicates whether to delete the directory contents
let remove = false;
// The remote URL
let remoteUrl;
// 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 !== (yield git.tryGetFetchUrl())) {
allowedRemoteUrls.indexOf((remoteUrl = yield git.tryGetRemoteUrl())) < 0) {
remove = true;
}
else {
@ -7322,6 +7298,12 @@ function prepareExistingDirectory(git, repositoryPath, repositoryUrl, clean) {
core.warning(`Unable to clean or reset the repository. The repository will be recreated instead.`);
}
}
// Update to the preferred remote URL
if (remoteUrl !== preferredRemoteUrl) {
core.startGroup('Updating the remote URL');
yield git.setRemoteUrl(preferredRemoteUrl);
core.endGroup();
}
}
catch (error) {
core.warning(`Unable to prepare the existing repository. The repository will be recreated instead.`);
@ -9231,7 +9213,6 @@ const io = __importStar(__webpack_require__(1));
const path = __importStar(__webpack_require__(622));
const retryHelper = __importStar(__webpack_require__(587));
const toolCache = __importStar(__webpack_require__(533));
const urlHelper = __importStar(__webpack_require__(81));
const v4_1 = __importDefault(__webpack_require__(826));
const IS_WINDOWS = process.platform === 'win32';
function downloadRepository(authToken, owner, repo, ref, commit, repositoryPath) {
@ -9282,7 +9263,7 @@ function downloadRepository(authToken, owner, repo, ref, commit, repositoryPath)
exports.downloadRepository = downloadRepository;
function downloadArchive(authToken, owner, repo, ref, commit) {
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 = {
owner: owner,
repo: repo,
@ -14062,6 +14043,7 @@ const core = __importStar(__webpack_require__(470));
const fsHelper = __importStar(__webpack_require__(618));
const github = __importStar(__webpack_require__(469));
const path = __importStar(__webpack_require__(622));
const hostname = 'github.com';
function getInputs() {
const result = {};
// GitHub workspace
@ -14091,12 +14073,13 @@ function getInputs() {
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();
result.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) {
if (result.isWorkflowRepository) {
result.ref = github.context.ref;
result.commit = github.context.sha;
// Some events have an unqualifed ref. For example when a PR is merged (pull_request closed event),

View File

@ -7,12 +7,12 @@ import * as os from 'os'
import * as path from 'path'
import * as regexpHelper from './regexp-helper'
import * as stateHelper from './state-helper'
import * as urlHelper from './url-helper'
import {default as uuid} from 'uuid/v4'
import {IGitCommandManager} from './git-command-manager'
import {IGitSourceSettings} from './git-source-settings'
const IS_WINDOWS = process.platform === 'win32'
const HOSTNAME = 'github.com'
const SSH_COMMAND_KEY = 'core.sshCommand'
export interface IGitAuthHelper {
@ -33,15 +33,15 @@ export function createAuthHelper(
class GitAuthHelper {
private readonly git: IGitCommandManager
private readonly settings: IGitSourceSettings
private readonly tokenConfigKey: string
private readonly tokenConfigValue: string
private readonly tokenConfigKey: string = `http.https://${HOSTNAME}/.extraheader`
private readonly tokenPlaceholderConfigValue: string
private readonly insteadOfKey: string
private readonly insteadOfValue: string
private readonly insteadOfKey: string = `url.https://${HOSTNAME}/.insteadOf`
private readonly insteadOfValue: string = `git@${HOSTNAME}:`
private sshCommand = ''
private sshKeyPath = ''
private sshKnownHostsPath = ''
private temporaryHomePath = ''
private tokenConfigValue: string
constructor(
gitCommandManager: IGitCommandManager,
@ -51,8 +51,6 @@ class GitAuthHelper {
this.settings = gitSourceSettings || (({} as unknown) as IGitSourceSettings)
// 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'
@ -60,10 +58,6 @@ class GitAuthHelper {
core.setSecret(basicCredential)
this.tokenPlaceholderConfigValue = `AUTHORIZATION: basic ***`
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> {

View File

@ -33,6 +33,7 @@ export interface IGitCommandManager {
remoteAdd(remoteName: string, remoteUrl: string): Promise<void>
removeEnvironmentVariable(name: string): void
setEnvironmentVariable(name: string, value: string): void
setRemoteUrl(url: string): Promise<void>
submoduleForeach(command: string, recursive: boolean): Promise<string>
submoduleSync(recursive: boolean): Promise<void>
submoduleUpdate(fetchDepth: number, recursive: boolean): Promise<void>
@ -40,7 +41,7 @@ export interface IGitCommandManager {
tryClean(): Promise<boolean>
tryConfigUnset(configKey: string, globalConfig?: boolean): Promise<boolean>
tryDisableAutomaticGarbageCollection(): Promise<boolean>
tryGetFetchUrl(): Promise<string>
tryGetRemoteUrl(): Promise<string>
tryReset(): Promise<boolean>
}
@ -241,6 +242,10 @@ class GitCommandManager {
this.gitEnv[name] = value
}
async setRemoteUrl(value: string): Promise<void> {
await this.config('git.remote.url', value)
}
async submoduleForeach(command: string, recursive: boolean): Promise<string> {
const args = ['submodule', 'foreach']
if (recursive) {
@ -309,7 +314,7 @@ class GitCommandManager {
return output.exitCode === 0
}
async tryGetFetchUrl(): Promise<string> {
async tryGetRemoteUrl(): Promise<string> {
const output = await this.execGit(
['config', '--local', '--get', 'remote.origin.url'],
true

View File

@ -10,15 +10,24 @@ import {IGitSourceSettings} from './git-source-settings'
export async function prepareExistingDirectory(
git: IGitCommandManager | undefined,
repositoryPath: string,
repositoryUrl: string,
preferredRemoteUrl: string,
allowedRemoteUrls: string[],
clean: boolean
): Promise<void> {
assert.ok(repositoryPath, 'Expected repositoryPath to be defined')
assert.ok(repositoryUrl, 'Expected repositoryUrl to be defined')
assert.ok(preferredRemoteUrl, 'Expected preferredRemoteUrl to be defined')
assert.ok(allowedRemoteUrls, 'Expected allowedRemoteUrls to be defined')
assert.ok(
allowedRemoteUrls.length,
'Expected allowedRemoteUrls to have at least one value'
)
// Indicates whether to delete the directory contents
let remove = false
// The remote URL
let remoteUrl: string
// Check whether using git or REST API
if (!git) {
remove = true
@ -26,7 +35,7 @@ export async function prepareExistingDirectory(
// Fetch URL does not match
else if (
!fsHelper.directoryExistsSync(path.join(repositoryPath, '.git')) ||
repositoryUrl !== (await git.tryGetFetchUrl())
allowedRemoteUrls.indexOf((remoteUrl = await git.tryGetRemoteUrl())) < 0
) {
remove = true
} else {
@ -82,6 +91,13 @@ export async function prepareExistingDirectory(
)
}
}
// Update to the preferred remote URL
if (remoteUrl !== preferredRemoteUrl) {
core.startGroup('Updating the remote URL')
await git.setRemoteUrl(preferredRemoteUrl)
core.endGroup()
}
} catch (error) {
core.warning(
`Unable to prepare the existing repository. The repository will be recreated instead.`

View File

@ -8,16 +8,27 @@ import * as io from '@actions/io'
import * as path from 'path'
import * as refHelper from './ref-helper'
import * as stateHelper from './state-helper'
import * as urlHelper from './url-helper'
import {IGitCommandManager} from './git-command-manager'
import {IGitSourceSettings} from './git-source-settings'
const hostname = 'github.com'
export async function getSource(settings: IGitSourceSettings): Promise<void> {
// Repository URL
core.info(
`Syncing repository: ${settings.repositoryOwner}/${settings.repositoryName}`
)
const repositoryUrl = urlHelper.getFetchUrl(settings)
// Remote URL
const httpsUrl = `https://${hostname}/${encodeURIComponent(
settings.repositoryOwner
)}/${encodeURIComponent(settings.repositoryName)}`
const sshUrl = `git@${hostname}:${encodeURIComponent(
settings.repositoryOwner
)}/${encodeURIComponent(settings.repositoryName)}.git`
// Always fetch the workflow repository using the token, not the SSH key
const initialRemoteUrl =
!settings.sshKey || settings.isWorkflowRepository ? httpsUrl : sshUrl
// Remove conflicting file path
if (fsHelper.fileExistsSync(settings.repositoryPath)) {
@ -41,7 +52,8 @@ export async function getSource(settings: IGitSourceSettings): Promise<void> {
await gitDirectoryHelper.prepareExistingDirectory(
git,
settings.repositoryPath,
repositoryUrl,
initialRemoteUrl,
[httpsUrl, sshUrl],
settings.clean
)
}
@ -82,7 +94,7 @@ export async function getSource(settings: IGitSourceSettings): Promise<void> {
) {
core.startGroup('Initializing the repository')
await git.init()
await git.remoteAdd('origin', repositoryUrl)
await git.remoteAdd('origin', initialRemoteUrl)
core.endGroup()
}
@ -131,6 +143,13 @@ export async function getSource(settings: IGitSourceSettings): Promise<void> {
core.endGroup()
}
// Fix URL when using SSH
if (settings.sshKey && initialRemoteUrl !== sshUrl) {
core.startGroup('Updating the remote URL')
await git.setRemoteUrl(sshUrl)
core.endGroup()
}
// Checkout
core.startGroup('Checking out the ref')
await git.checkout(checkoutInfo.ref, checkoutInfo.startPoint)

View File

@ -14,6 +14,11 @@ export interface IGitSourceSettings {
*/
repositoryName: string
/**
* Indicates whether the repository is main workflow repository
*/
isWorkflowRepository: boolean
/**
* The ref to fetch
*/

View File

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

View File

@ -4,6 +4,8 @@ import * as github from '@actions/github'
import * as path from 'path'
import {IGitSourceSettings} from './git-source-settings'
const hostname = 'github.com'
export function getInputs(): IGitSourceSettings {
const result = ({} as unknown) as IGitSourceSettings
@ -51,14 +53,14 @@ export function getInputs(): IGitSourceSettings {
}
// Workflow repository?
const isWorkflowRepository =
result.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) {
if (result.isWorkflowRepository) {
result.ref = github.context.ref
result.commit = github.context.sha

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