Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
50 commits
Select commit Hold shift + click to select a range
a5a8524
Update supported GitHub Enterprise Server versions
github-actions[bot] Dec 27, 2024
18c1cbf
Update changelog and version after v3.28.1
github-actions[bot] Jan 10, 2025
fd3c034
Update checked-in dependencies
github-actions[bot] Jan 10, 2025
2b9e645
Merge pull request #2682 from github/mergeback/v3.28.1-to-main-b6a472f6
angelapwen Jan 10, 2025
c050c40
Stop updating `releases/v2` branch
angelapwen Jan 10, 2025
47835cd
Merge pull request #2684 from github/angelapwen/stop-updating-v2-branch
angelapwen Jan 10, 2025
87fc816
Merge pull request #2669 from github/update-supported-enterprise-serv…
henrymercer Jan 10, 2025
fe593c3
Mark invalid external repo specifiers as configuration error
henrymercer Jan 10, 2025
79c9494
Remove the word 'to'
josiahaltschuler Jan 10, 2025
db7177a
Merge pull request #2686 from josiahaltschuler/fix-typo-in-changelog
aeisenberg Jan 10, 2025
a477602
Change 'an' to 'a'
josiahaltschuler Jan 11, 2025
c0addec
Add period to end of sentence
josiahaltschuler Jan 11, 2025
e02d65a
Filter registry credentials by language
marcogario Jan 10, 2025
1f86f55
Merge pull request #2685 from github/henrymercer/invalid-specifier-co…
henrymercer Jan 13, 2025
68378a3
getPullRequestEditedDiffRanges: use GitHub API
cklin Jan 13, 2025
de0f9cf
Support both namings for java
marcogario Jan 13, 2025
cecb471
Merge branch 'main' into typo-change-an-to-a
aeisenberg Jan 13, 2025
2584941
Merge pull request #2687 from josiahaltschuler/typo-change-an-to-a
aeisenberg Jan 13, 2025
a082142
Merge branch 'main' into add-period-to-sentence
aeisenberg Jan 13, 2025
7269bf6
build(deps): bump the npm group with 8 updates
dependabot[bot] Jan 13, 2025
e5a7c90
Update checked-in dependencies
github-actions[bot] Jan 13, 2025
10a3f07
Merge pull request #2689 from josiahaltschuler/add-period-to-sentence
aeisenberg Jan 13, 2025
68b1b4e
getPullRequestEditedDiffRanges: compute diff ranges
cklin Jan 13, 2025
63d1f4f
getPullRequestEditedDiffRanges: check the number of changed files
cklin Jan 13, 2025
d4c56bb
getDiffRanges: improve handling for missing patch
cklin Jan 9, 2025
7848967
getDiffRanges: add unit tests
cklin Jan 13, 2025
52315a9
setupDiffInformedQueryRun: log setup failure
cklin Jan 9, 2025
3548ff5
writeDiffRangeDataExtensionPack: escape special characters in filenames
cklin Jan 10, 2025
ae19466
build: refresh js files
cklin Jan 13, 2025
31d11b1
Use Language type
marcogario Jan 14, 2025
1efc6bb
Merge pull request #2679 from github/cklin/get-diff-from-api
cklin Jan 14, 2025
3b4f4d9
Merge pull request #2680 from github/marcogario/filter_registries
marcogario Jan 15, 2025
02dfacf
Fix linting errors
henrymercer Jan 15, 2025
048b0a2
Remove Node 16 compilation PR check
henrymercer Jan 15, 2025
fc8d71f
Add reminder to CONTRIBUTING.md
henrymercer Jan 15, 2025
b40fa61
Merge pull request #2695 from github/henrymercer/remove-node-16-check
henrymercer Jan 15, 2025
4de061d
Merge branch 'main' into dependabot/npm_and_yarn/npm-006da05bd8
henrymercer Jan 15, 2025
93da9f2
Merge pull request #2690 from github/dependabot/npm_and_yarn/npm-006d…
henrymercer Jan 15, 2025
bd76a92
PR checks: Remove code for unsupported versions
henrymercer Jan 15, 2025
40a203a
Remove redundant version checks
henrymercer Jan 15, 2025
7ae5fc3
Merge pull request #2696 from github/henrymercer/delete-code
henrymercer Jan 16, 2025
5889cfd
Add analysis_is_diff_informed to status report
cklin Jan 16, 2025
071996f
getDiffRanges: better fallback for absent patch
cklin Jan 16, 2025
94f08f3
Merge pull request #2698 from github/cklin/diff-informed-status-report
cklin Jan 16, 2025
2d608a3
Merge branch 'main' into cklin/diff-informed-file-fallback
cklin Jan 16, 2025
0f1559a
Merge pull request #2699 from github/cklin/diff-informed-file-fallback
cklin Jan 16, 2025
c168638
build(deps): bump the npm group with 3 updates
dependabot[bot] Jan 20, 2025
7b7562b
Update checked-in dependencies
github-actions[bot] Jan 20, 2025
d90e07f
Merge pull request #2703 from github/dependabot/npm_and_yarn/npm-cd3f…
aeisenberg Jan 20, 2025
ea23796
Update changelog for v3.28.2
github-actions[bot] Jan 21, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
getPullRequestEditedDiffRanges: use GitHub API
  • Loading branch information
cklin committed Jan 13, 2025
commit 68378a359ac317d632ec5fb17a2a5f39f7f33da6
2 changes: 1 addition & 1 deletion src/analyze-action.ts
Original file line number Diff line number Diff line change
Expand Up @@ -268,7 +268,7 @@ async function run() {
pull_request &&
(await setupDiffInformedQueryRun(
pull_request.base.ref as string,
pull_request.head.ref as string,
pull_request.head.label as string,
codeql,
logger,
features,
Expand Down
156 changes: 56 additions & 100 deletions src/analyze.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import del from "del";
import * as yaml from "js-yaml";

import * as actionsUtil from "./actions-util";
import { getApiClient } from "./api-client";
import { setupCppAutobuild } from "./autobuild";
import {
CODEQL_VERSION_ANALYSIS_SUMMARY_V2,
Expand All @@ -17,7 +18,6 @@ import * as configUtils from "./config-utils";
import { addDiagnostic, makeDiagnostic } from "./diagnostics";
import { EnvVar } from "./environment";
import { FeatureEnablement, Feature } from "./feature-flags";
import * as gitUtils from "./git-utils";
import { isScannedLanguage, Language } from "./languages";
import { Logger, withGroupAsync } from "./logging";
import { DatabaseCreationTimings, EventReport } from "./status-report";
Expand Down Expand Up @@ -240,7 +240,8 @@ async function finalizeDatabaseCreation(
* Set up the diff-informed analysis feature.
*
* @param baseRef The base branch name, used for calculating the diff range.
* @param headRef The head branch name, used for calculating the diff range.
* @param headLabel The label that uniquely identifies the head branch across
* repositories, used for calculating the diff range.
* @param codeql
* @param logger
* @param features
Expand All @@ -249,7 +250,7 @@ async function finalizeDatabaseCreation(
*/
export async function setupDiffInformedQueryRun(
baseRef: string,
headRef: string,
headLabel: string,
codeql: CodeQL,
logger: Logger,
features: FeatureEnablement,
Expand All @@ -262,7 +263,7 @@ export async function setupDiffInformedQueryRun(
async () => {
const diffRanges = await getPullRequestEditedDiffRanges(
baseRef,
headRef,
headLabel,
logger,
);
return writeDiffRangeDataExtensionPack(logger, diffRanges);
Expand All @@ -280,7 +281,8 @@ interface DiffThunkRange {
* Return the file line ranges that were added or modified in the pull request.
*
* @param baseRef The base branch name, used for calculating the diff range.
* @param headRef The head branch name, used for calculating the diff range.
* @param headLabel The label that uniquely identifies the head branch across
* repositories, used for calculating the diff range.
* @param logger
* @returns An array of tuples, where each tuple contains the absolute path of a
* file, the start line and the end line (both 1-based and inclusive) of an
Expand All @@ -289,107 +291,61 @@ interface DiffThunkRange {
*/
async function getPullRequestEditedDiffRanges(
baseRef: string,
headRef: string,
headLabel: string,
logger: Logger,
): Promise<DiffThunkRange[] | undefined> {
const checkoutPath = actionsUtil.getOptionalInput("checkout_path");
if (checkoutPath === undefined) {
return undefined;
}

// To compute the merge bases between the base branch and the PR topic branch,
// we need to fetch the commit graph from the branch heads to those merge
// babes. The following 6-step procedure does so while limiting the amount of
// history fetched.

// Step 1: Deepen from the PR merge commit to the base branch head and the PR
// topic branch head, so that the PR merge commit is no longer considered a
// grafted commit.
await gitUtils.deepenGitHistory();
// Step 2: Fetch the base branch shallow history. This step ensures that the
// base branch name is present in the local repository. Normally the base
// branch name would be added by Step 4. However, if the base branch head is
// an ancestor of the PR topic branch head, Step 4 would fail without doing
// anything, so we need to fetch the base branch explicitly.
await gitUtils.gitFetch(baseRef, ["--depth=1"]);
// Step 3: Fetch the PR topic branch history, stopping when we reach commits
// that are reachable from the base branch head.
await gitUtils.gitFetch(headRef, [`--shallow-exclude=${baseRef}`]);
// Step 4: Fetch the base branch history, stopping when we reach commits that
// are reachable from the PR topic branch head.
await gitUtils.gitFetch(baseRef, [`--shallow-exclude=${headRef}`]);
// Step 5: Repack the history to remove the shallow grafts that were added by
// the previous fetches. This step works around a bug that causes subsequent
// deepening fetches to fail with "fatal: error in object: unshallow <SHA>".
// See https://stackoverflow.com/q/63878612
await gitUtils.gitRepack(["-d"]);
// Step 6: Deepen the history so that we have the merge bases between the base
// branch and the PR topic branch.
await gitUtils.deepenGitHistory();

// To compute the exact same diff as GitHub would compute for the PR, we need
// to use the same merge base as GitHub. That is easy to do if there is only
// one merge base, which is by far the most common case. If there are multiple
// merge bases, we stop without producing a diff range.
const mergeBases = await gitUtils.getAllGitMergeBases([baseRef, headRef]);
logger.info(`Merge bases: ${mergeBases.join(", ")}`);
if (mergeBases.length !== 1) {
logger.info(
"Cannot compute diff range because baseRef and headRef " +
`have ${mergeBases.length} merge bases (instead of exactly 1).`,
);
return undefined;
}

const diffHunkHeaders = await gitUtils.getGitDiffHunkHeaders(
mergeBases[0],
headRef,
);
if (diffHunkHeaders === undefined) {
return undefined;
}
await getFileDiffsWithBasehead(baseRef, headLabel, logger);
return undefined;
}

const results = new Array<DiffThunkRange>();

let changedFile = "";
for (const line of diffHunkHeaders) {
if (line.startsWith("+++ ")) {
const filePath = gitUtils.decodeGitFilePath(line.substring(4));
if (filePath.startsWith("b/")) {
// The file was edited: track all hunks in the file
changedFile = filePath.substring(2);
} else if (filePath === "/dev/null") {
// The file was deleted: skip all hunks in the file
changedFile = "";
} else {
logger.warning(`Failed to parse diff hunk header line: ${line}`);
return undefined;
}
continue;
}
if (line.startsWith("@@ ")) {
if (changedFile === "") continue;
/**
* This interface is an abbreviated version of the file diff object returned by
* the GitHub API.
*/
interface FileDiff {
filename: string;
changes: number;
// A patch may be absent if the file is binary, if the file diff is too large,
// or if the file is unchanged.
patch?: string | undefined;
}

const match = line.match(/^@@ -\d+(?:,\d+)? \+(\d+)(?:,(\d+))? @@/);
if (match === null) {
logger.warning(`Failed to parse diff hunk header line: ${line}`);
return undefined;
}
const startLine = parseInt(match[1], 10);
const numLines = parseInt(match[2], 10);
if (numLines === 0) {
// The hunk was a deletion: skip it
continue;
}
const endLine = startLine + (numLines || 1) - 1;
results.push({
path: path.join(checkoutPath, changedFile),
startLine,
endLine,
});
async function getFileDiffsWithBasehead(
baseRef: string,
headLabel: string,
logger: Logger,
): Promise<FileDiff[] | undefined> {
const ownerRepo = util.getRequiredEnvParam("GITHUB_REPOSITORY").split("/");
const owner = ownerRepo[0];
const repo = ownerRepo[1];
const basehead = `${baseRef}...${headLabel}`;
try {
const response = await getApiClient().rest.repos.compareCommitsWithBasehead(
{
owner,
repo,
basehead,
per_page: 1,
},
);
logger.debug(
`Response from compareCommitsWithBasehead(${basehead}):` +
`\n${JSON.stringify(response, null, 2)}`,
);
return response.data.files;
} catch (error: any) {
if (error.status) {
logger.warning(`Error retrieving diff ${basehead}: ${error.message}`);
logger.debug(
`Error running compareCommitsWithBasehead(${basehead}):` +
`\nRequest: ${JSON.stringify(error.request, null, 2)}` +
`\nError Response: ${JSON.stringify(error.response, null, 2)}`,
);
return undefined;
} else {
throw error;
}
}
return results;
}

/**
Expand Down