Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Split upload method into two mode-specific ones #323

Merged
merged 13 commits into from
Jan 6, 2021
Merged

Conversation

sampart
Copy link
Contributor

@sampart sampart commented Nov 26, 2020

Continuing to think about reducing our long argument lists, this PR splits the upload method into two mode-specific ones, which are called from the runner- or actions-specific code so that it's obvious which one to use without requiring a mode parameter. uploadFiles still has the optional parameters, but at least that's not an exported method.

  • runAnalyze now just does one thing - running an analysis, rather than having a side-effect of uploading.
  • 11(!) arguments removed from runAnalyze

Merge / deployment checklist

  • Confirm this change is backwards compatible with existing workflows.
  • Confirm the readme has been updated if necessary.

src/analyze.ts Outdated
Comment on lines 261 to 288
let uploadStats: upload_lib.UploadStatusReport;
if (mode == "actions") {
uploadStats = await upload_lib.uploadFromActions(
outputDir,
repositoryNwo,
commitOid,
ref,
analysisKey!,
analysisName!,
workflowRunID!,
checkoutPath,
environment!,
apiDetails,
logger
);
} else if (mode == "runner") {
uploadStats = await upload_lib.uploadFromRunner(
outputDir,
repositoryNwo,
commitOid,
ref,
checkoutPath,
apiDetails,
logger
);
} else {
throw new Error(`Unknown mode "${mode}"`);
}
Copy link
Contributor Author

@sampart sampart Nov 26, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This conditional (and the user of !) bothers me. I could avoid it by moving the calls to the upload* methods into analyze-action.ts and runner.ts. That would have the additional advantage of reducing the number of arguments for runAnalyze. Would you be happy with that change, @robertbrignull?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah as you say, unfortunately splitting up the upload* methods hasn't really helped as it's just pushed the problem one method earlier so now we have a big switch in analyze.ts and have to worry about values being undefined here.

We could try moving the calls to upload to being in analyze-action.ts and runner.ts. You'd need to return some data from the analyze code but that should be fine. I don't know if it'll end up better overall but it would be good to try it and see how it looks.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've moved the calls up in ff28c8d. I'm not sure how easy the overall diff of this PR is to read, I'm afraid.

Here are some of my thoughts:

Advantages

  • runAnalyze now just does one thing - running an analysis, rather than having a side-effect of uploading.
  • 11(!) arguments removed from runAnalyze 🎊
  • We now see the benefits of the split out upload* methods - fewer parameters (and no undefineds) in the argument list in the runner (uploadFromRunner does have a similar situation, but that doesn't feel so bad to me).

Disadvantages

  • runAnalyze might only do one thing now, but the side effect has only moved as far as the calling methods. I think it's less bad that the runner method (as opposed to run in src/analyze-action.ts) does multiple things, though, since that's basically procedural code that does everything all in one place anyway.
  • Similarly, run in src/analyze-action.ts has now got even longer. It would be an interesting exercise to try and decompose it into smaller functions (not in this PR)
  • Likewise, the action in the runner is even longer too. Again decomposition would be an interesting exercise

What are your thoughts?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Robert and I discussed this on a call, and we're going to go with it. I've tweaked the PR description accordingly

Likewise, the action in the runner is even longer too. Again decomposition would be an interesting exercise

I've added this to https://github.com/github/code-scanning/issues/1874#issuecomment-728215299

logger
);

if (actionsUtil.getRequiredInput("upload") !== "true") {
Copy link
Contributor Author

@sampart sampart Dec 22, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The uploading happens here now. Previously, it was a side-effect of runAnalyze, which was one of the reasons it needed so many params.

Likewise in runner.ts below.

@@ -117,22 +160,7 @@ export async function upload(
} else {
sarifFiles.push(sarifPath);
}

return await uploadFiles(
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The diff is confusing here - this uploadFiles call has been replaced by the one on line 128 above. The differ doesn't realise that I've extracted the SARIF file path stuff into a new method (getSarifFilePaths)

@sampart sampart marked this pull request as ready for review December 22, 2020 11:54
Copy link
Contributor

@robertbrignull robertbrignull left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I had a few comments with minor points, but generally this is looking good. I do like splitting the upload method up and I think that part is a big benefit. Just some minor details to make sure we avoid changing behaviour.


if (actionsUtil.getRequiredInput("upload") !== "true") {
logger.info("Not uploading results");
return;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you return here then it wont send the status report. Probably need to add an else branch instead of returning early.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ooh, good spot. Fixed in 1da4ce5

@@ -68,7 +69,23 @@ async function run() {
auth: actionsUtil.getRequiredInput("token"),
url: actionsUtil.getRequiredEnvParam("GITHUB_SERVER_URL"),
};
stats = await runAnalyze(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The AnalysisStatusReport type is still defined in analyze.ts but it doesn't need to be there as it's now only used from this file. You could just move that type definition to this file, or in fact if you want you could get rid of it and replace all uses with upload_lib.UploadStatusReport & QueriesStatusReport and it isn't too onerous.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice one. I've kept the type but moved it in 4bc186c

);
}

function getSarifFilePaths(sarifPath: string) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's a merge conflict here. You want to solve it by taking your version but then deleting the const sarifFiles: string[] = []; line, so it looks like

// Uploads a single sarif file or a directory of sarif files
// depending on what the path happens to refer to.
// Returns true iff the upload occurred and succeeded
export async function uploadFromRunner(
  sarifPath: string,
  repositoryNwo: RepositoryNwo,
  commitOid: string,
  ref: string,
  checkoutPath: string,
  apiDetails: api.GitHubApiDetails,
  logger: Logger
): Promise<UploadStatusReport> {
  return await uploadFiles(
    getSarifFilePaths(sarifPath),
    repositoryNwo,
    commitOid,
    ref,
    undefined,
    undefined,
    undefined,
    checkoutPath,
    undefined,
    apiDetails,
    "runner",
    logger
  );
}

function getSarifFilePaths(sarifPath: string) {
  if (!fs.existsSync(sarifPath)) {
    throw new Error(`Path does not exist: ${sarifPath}`);
  }

  let sarifFiles: string[];
  if (fs.lstatSync(sarifPath).isDirectory()) {
    sarifFiles = findSarifFilesInDir(sarifPath);
    if (sarifFiles.length === 0) {
      throw new Error(`No SARIF files found to upload in "${sarifPath}".`);
    }
  } else {
    sarifFiles = [sarifPath];
  }
  return sarifFiles;
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks so much for this. I'd have been scratching my head for ages over the conflict otherwise!

@@ -276,6 +303,7 @@ async function uploadFiles(

const toolNames = util.getToolNames(sarifPayload);

const gitHubVersion = await util.getGitHubVersion(apiDetails);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can see the desire to move this here and avoid passing it through a few methods, however it does change behaviour slightly in that we'll query the github api for its version a second time instead of using the version we already obtained in the init action. That's why from the analyze action it would pass in the github version from the config, and from the upload-sarif action it would fetch a new copy because we don't have a config around.

Admittedly it's a very small cost to make one extra HTTP request but it's also a small cost to have an extra argument so it's hard to compare those two points. I don't think this argument comes under the original intent of the PR so unless you feel strongly I'd like to put this argument back for now.

We could look at ways of improving this situation but as another PR. Perhaps it could be included into GitHubApiDetails, but then that would complicate the construction of that object, so I think it's worth doing as a separate change. I'm also already suggesting changing that type in #357 though that PR may not be merged.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reverted in 54e0c67

@sampart sampart merged commit a0c4707 into main Jan 6, 2021
@sampart sampart deleted the split-upload-method branch January 6, 2021 12:02
@github-actions github-actions bot mentioned this pull request Jan 11, 2021
aofaof0907 pushed a commit to aofaof0907/codeql-action that referenced this pull request Jul 29, 2021
aofaof0907 pushed a commit to aofaof0907/codeql-action that referenced this pull request Jul 29, 2021
aofaof0907 pushed a commit to aofaof0907/codeql-action that referenced this pull request Jul 29, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants