mirror of
https://github.com/actions/checkout
synced 2024-11-09 23:22:40 +00:00
telemetry for incorrect merge commit (#253)
This commit is contained in:
parent
df86c829eb
commit
2ff2fbdea4
4 changed files with 218 additions and 7 deletions
98
dist/index.js
vendored
98
dist/index.js
vendored
|
@ -3359,7 +3359,7 @@ module.exports = {"name":"@octokit/rest","version":"16.43.1","publishConfig":{"a
|
||||||
/***/ }),
|
/***/ }),
|
||||||
|
|
||||||
/***/ 227:
|
/***/ 227:
|
||||||
/***/ (function(__unusedmodule, exports) {
|
/***/ (function(__unusedmodule, exports, __webpack_require__) {
|
||||||
|
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
|
@ -3372,7 +3372,17 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
||||||
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
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 });
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
const url_1 = __webpack_require__(835);
|
||||||
|
const core = __importStar(__webpack_require__(470));
|
||||||
|
const github = __importStar(__webpack_require__(469));
|
||||||
function getCheckoutInfo(git, ref, commit) {
|
function getCheckoutInfo(git, ref, commit) {
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
if (!git) {
|
if (!git) {
|
||||||
|
@ -3468,6 +3478,85 @@ function getRefSpec(ref, commit) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
exports.getRefSpec = getRefSpec;
|
exports.getRefSpec = getRefSpec;
|
||||||
|
function checkCommitInfo(token, commitInfo, repositoryOwner, repositoryName, ref, commit) {
|
||||||
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
|
try {
|
||||||
|
// GHES?
|
||||||
|
if (isGhes()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Auth token?
|
||||||
|
if (!token) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Public PR synchronize, for workflow repo?
|
||||||
|
if (fromPayload('repository.private') !== false ||
|
||||||
|
github.context.eventName !== 'pull_request' ||
|
||||||
|
fromPayload('action') !== 'synchronize' ||
|
||||||
|
repositoryOwner !== github.context.repo.owner ||
|
||||||
|
repositoryName !== github.context.repo.repo ||
|
||||||
|
ref !== github.context.ref ||
|
||||||
|
!ref.startsWith('refs/pull/') ||
|
||||||
|
commit !== github.context.sha) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Head SHA
|
||||||
|
const expectedHeadSha = fromPayload('after');
|
||||||
|
if (!expectedHeadSha) {
|
||||||
|
core.debug('Unable to determine head sha');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Base SHA
|
||||||
|
const expectedBaseSha = fromPayload('pull_request.base.sha');
|
||||||
|
if (!expectedBaseSha) {
|
||||||
|
core.debug('Unable to determine base sha');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Expected message?
|
||||||
|
const expectedMessage = `Merge ${expectedHeadSha} into ${expectedBaseSha}`;
|
||||||
|
if (commitInfo.indexOf(expectedMessage) >= 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Extract details from message
|
||||||
|
const match = commitInfo.match(/Merge ([0-9a-f]{40}) into ([0-9a-f]{40})/);
|
||||||
|
if (!match) {
|
||||||
|
core.debug('Unexpected message format');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Post telemetry
|
||||||
|
const actualHeadSha = match[1];
|
||||||
|
if (actualHeadSha !== expectedHeadSha) {
|
||||||
|
core.debug(`Expected head sha ${expectedHeadSha}; actual head sha ${actualHeadSha}`);
|
||||||
|
const octokit = new github.GitHub(token, {
|
||||||
|
userAgent: `actions-checkout-tracepoint/1.0 (code=STALE_MERGE;owner=${repositoryOwner};repo=${repositoryName};pr=${fromPayload('number')};run_id=${process.env['GITHUB_RUN_ID']};expected_head_sha=${expectedHeadSha};actual_head_sha=${actualHeadSha})`
|
||||||
|
});
|
||||||
|
yield octokit.repos.get({ owner: repositoryOwner, repo: repositoryName });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (err) {
|
||||||
|
core.debug(`Error when validating commit info: ${err.stack}`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
exports.checkCommitInfo = checkCommitInfo;
|
||||||
|
function fromPayload(path) {
|
||||||
|
return select(github.context.payload, path);
|
||||||
|
}
|
||||||
|
function select(obj, path) {
|
||||||
|
if (!obj) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
const i = path.indexOf('.');
|
||||||
|
if (i < 0) {
|
||||||
|
return obj[path];
|
||||||
|
}
|
||||||
|
const key = path.substr(0, i);
|
||||||
|
return select(obj[key], path.substr(i + 1));
|
||||||
|
}
|
||||||
|
function isGhes() {
|
||||||
|
const ghUrl = new url_1.URL(process.env['GITHUB_SERVER_URL'] || 'https://github.com');
|
||||||
|
return ghUrl.hostname.toUpperCase() !== 'GITHUB.COM';
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/***/ }),
|
/***/ }),
|
||||||
|
@ -5718,7 +5807,8 @@ class GitCommandManager {
|
||||||
}
|
}
|
||||||
log1() {
|
log1() {
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
yield this.execGit(['log', '-1']);
|
const output = yield this.execGit(['log', '-1']);
|
||||||
|
return output.stdout;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
remoteAdd(remoteName, remoteUrl) {
|
remoteAdd(remoteName, remoteUrl) {
|
||||||
|
@ -6057,7 +6147,9 @@ function getSource(settings) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Dump some info about the checked out commit
|
// Dump some info about the checked out commit
|
||||||
yield git.log1();
|
const commitInfo = yield git.log1();
|
||||||
|
// Check for incorrect pull request merge commit
|
||||||
|
yield refHelper.checkCommitInfo(settings.authToken, commitInfo, settings.repositoryOwner, settings.repositoryName, settings.ref, settings.commit);
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
// Remove auth
|
// Remove auth
|
||||||
|
|
|
@ -29,7 +29,7 @@ export interface IGitCommandManager {
|
||||||
isDetached(): Promise<boolean>
|
isDetached(): Promise<boolean>
|
||||||
lfsFetch(ref: string): Promise<void>
|
lfsFetch(ref: string): Promise<void>
|
||||||
lfsInstall(): Promise<void>
|
lfsInstall(): Promise<void>
|
||||||
log1(): Promise<void>
|
log1(): Promise<string>
|
||||||
remoteAdd(remoteName: string, remoteUrl: string): Promise<void>
|
remoteAdd(remoteName: string, remoteUrl: string): Promise<void>
|
||||||
removeEnvironmentVariable(name: string): void
|
removeEnvironmentVariable(name: string): void
|
||||||
setEnvironmentVariable(name: string, value: string): void
|
setEnvironmentVariable(name: string, value: string): void
|
||||||
|
@ -225,8 +225,9 @@ class GitCommandManager {
|
||||||
await this.execGit(['lfs', 'install', '--local'])
|
await this.execGit(['lfs', 'install', '--local'])
|
||||||
}
|
}
|
||||||
|
|
||||||
async log1(): Promise<void> {
|
async log1(): Promise<string> {
|
||||||
await this.execGit(['log', '-1'])
|
const output = await this.execGit(['log', '-1'])
|
||||||
|
return output.stdout
|
||||||
}
|
}
|
||||||
|
|
||||||
async remoteAdd(remoteName: string, remoteUrl: string): Promise<void> {
|
async remoteAdd(remoteName: string, remoteUrl: string): Promise<void> {
|
||||||
|
|
|
@ -170,7 +170,17 @@ export async function getSource(settings: IGitSourceSettings): Promise<void> {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Dump some info about the checked out commit
|
// Dump some info about the checked out commit
|
||||||
await git.log1()
|
const commitInfo = await git.log1()
|
||||||
|
|
||||||
|
// Check for incorrect pull request merge commit
|
||||||
|
await refHelper.checkCommitInfo(
|
||||||
|
settings.authToken,
|
||||||
|
commitInfo,
|
||||||
|
settings.repositoryOwner,
|
||||||
|
settings.repositoryName,
|
||||||
|
settings.ref,
|
||||||
|
settings.commit
|
||||||
|
)
|
||||||
} finally {
|
} finally {
|
||||||
// Remove auth
|
// Remove auth
|
||||||
if (!settings.persistCredentials) {
|
if (!settings.persistCredentials) {
|
||||||
|
|
|
@ -1,4 +1,7 @@
|
||||||
|
import {URL} from 'url'
|
||||||
import {IGitCommandManager} from './git-command-manager'
|
import {IGitCommandManager} from './git-command-manager'
|
||||||
|
import * as core from '@actions/core'
|
||||||
|
import * as github from '@actions/github'
|
||||||
|
|
||||||
export interface ICheckoutInfo {
|
export interface ICheckoutInfo {
|
||||||
ref: string
|
ref: string
|
||||||
|
@ -107,3 +110,108 @@ export function getRefSpec(ref: string, commit: string): string[] {
|
||||||
return [`+${ref}:${ref}`]
|
return [`+${ref}:${ref}`]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function checkCommitInfo(
|
||||||
|
token: string,
|
||||||
|
commitInfo: string,
|
||||||
|
repositoryOwner: string,
|
||||||
|
repositoryName: string,
|
||||||
|
ref: string,
|
||||||
|
commit: string
|
||||||
|
): Promise<void> {
|
||||||
|
try {
|
||||||
|
// GHES?
|
||||||
|
if (isGhes()) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Auth token?
|
||||||
|
if (!token) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Public PR synchronize, for workflow repo?
|
||||||
|
if (
|
||||||
|
fromPayload('repository.private') !== false ||
|
||||||
|
github.context.eventName !== 'pull_request' ||
|
||||||
|
fromPayload('action') !== 'synchronize' ||
|
||||||
|
repositoryOwner !== github.context.repo.owner ||
|
||||||
|
repositoryName !== github.context.repo.repo ||
|
||||||
|
ref !== github.context.ref ||
|
||||||
|
!ref.startsWith('refs/pull/') ||
|
||||||
|
commit !== github.context.sha
|
||||||
|
) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Head SHA
|
||||||
|
const expectedHeadSha = fromPayload('after')
|
||||||
|
if (!expectedHeadSha) {
|
||||||
|
core.debug('Unable to determine head sha')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Base SHA
|
||||||
|
const expectedBaseSha = fromPayload('pull_request.base.sha')
|
||||||
|
if (!expectedBaseSha) {
|
||||||
|
core.debug('Unable to determine base sha')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Expected message?
|
||||||
|
const expectedMessage = `Merge ${expectedHeadSha} into ${expectedBaseSha}`
|
||||||
|
if (commitInfo.indexOf(expectedMessage) >= 0) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extract details from message
|
||||||
|
const match = commitInfo.match(/Merge ([0-9a-f]{40}) into ([0-9a-f]{40})/)
|
||||||
|
if (!match) {
|
||||||
|
core.debug('Unexpected message format')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Post telemetry
|
||||||
|
const actualHeadSha = match[1]
|
||||||
|
if (actualHeadSha !== expectedHeadSha) {
|
||||||
|
core.debug(
|
||||||
|
`Expected head sha ${expectedHeadSha}; actual head sha ${actualHeadSha}`
|
||||||
|
)
|
||||||
|
const octokit = new github.GitHub(token, {
|
||||||
|
userAgent: `actions-checkout-tracepoint/1.0 (code=STALE_MERGE;owner=${repositoryOwner};repo=${repositoryName};pr=${fromPayload(
|
||||||
|
'number'
|
||||||
|
)};run_id=${
|
||||||
|
process.env['GITHUB_RUN_ID']
|
||||||
|
};expected_head_sha=${expectedHeadSha};actual_head_sha=${actualHeadSha})`
|
||||||
|
})
|
||||||
|
await octokit.repos.get({owner: repositoryOwner, repo: repositoryName})
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
core.debug(`Error when validating commit info: ${err.stack}`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function fromPayload(path: string): any {
|
||||||
|
return select(github.context.payload, path)
|
||||||
|
}
|
||||||
|
|
||||||
|
function select(obj: any, path: string): any {
|
||||||
|
if (!obj) {
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
|
|
||||||
|
const i = path.indexOf('.')
|
||||||
|
if (i < 0) {
|
||||||
|
return obj[path]
|
||||||
|
}
|
||||||
|
|
||||||
|
const key = path.substr(0, i)
|
||||||
|
return select(obj[key], path.substr(i + 1))
|
||||||
|
}
|
||||||
|
|
||||||
|
function isGhes(): boolean {
|
||||||
|
const ghUrl = new URL(
|
||||||
|
process.env['GITHUB_SERVER_URL'] || 'https://github.com'
|
||||||
|
)
|
||||||
|
return ghUrl.hostname.toUpperCase() !== 'GITHUB.COM'
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue