telemetry for incorrect merge commit (#253)
This commit is contained in:
		@@ -29,7 +29,7 @@ export interface IGitCommandManager {
 | 
			
		||||
  isDetached(): Promise<boolean>
 | 
			
		||||
  lfsFetch(ref: string): Promise<void>
 | 
			
		||||
  lfsInstall(): Promise<void>
 | 
			
		||||
  log1(): Promise<void>
 | 
			
		||||
  log1(): Promise<string>
 | 
			
		||||
  remoteAdd(remoteName: string, remoteUrl: string): Promise<void>
 | 
			
		||||
  removeEnvironmentVariable(name: string): void
 | 
			
		||||
  setEnvironmentVariable(name: string, value: string): void
 | 
			
		||||
@@ -225,8 +225,9 @@ class GitCommandManager {
 | 
			
		||||
    await this.execGit(['lfs', 'install', '--local'])
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  async log1(): Promise<void> {
 | 
			
		||||
    await this.execGit(['log', '-1'])
 | 
			
		||||
  async log1(): Promise<string> {
 | 
			
		||||
    const output = await this.execGit(['log', '-1'])
 | 
			
		||||
    return output.stdout
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  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
 | 
			
		||||
    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 {
 | 
			
		||||
    // Remove auth
 | 
			
		||||
    if (!settings.persistCredentials) {
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,7 @@
 | 
			
		||||
import {URL} from 'url'
 | 
			
		||||
import {IGitCommandManager} from './git-command-manager'
 | 
			
		||||
import * as core from '@actions/core'
 | 
			
		||||
import * as github from '@actions/github'
 | 
			
		||||
 | 
			
		||||
export interface ICheckoutInfo {
 | 
			
		||||
  ref: string
 | 
			
		||||
@@ -107,3 +110,108 @@ export function getRefSpec(ref: string, commit: string): string[] {
 | 
			
		||||
    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'
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user