Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
92 changes: 63 additions & 29 deletions lib/entry-points.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

122 changes: 122 additions & 0 deletions src/config-utils.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,14 @@ import test, { ExecutionContext } from "ava";
import * as yaml from "js-yaml";
import * as sinon from "sinon";

import { ActionState } from "./action-common";
import * as actionsUtil from "./actions-util";
import { AnalysisKind, supportedAnalysisKinds } from "./analyses";
import * as api from "./api-client";
import { CachingKind } from "./caching-utils";
import { createStubCodeQL } from "./codeql";
import { UserConfig } from "./config/db-config";
import * as file from "./config/file";
import * as configUtils from "./config-utils";
import * as errorMessages from "./error-messages";
import { Feature } from "./feature-flags";
Expand All @@ -38,6 +40,8 @@ import {
makeMacro,
initAllState,
callee,
SAMPLE_DOTCOM_API_DETAILS,
setupBaseActionsVars,
} from "./testing-utils";
import {
GitHubVariant,
Expand Down Expand Up @@ -440,6 +444,7 @@ test.serial("load non-existent input", async (t) => {

try {
const state = initAllState();
setupBaseActionsVars({}, state.env);
await configUtils.initConfig(
state,
createTestInitConfigInputs({
Expand Down Expand Up @@ -2529,3 +2534,120 @@ test("determineUserConfig - ignores config file input outside Default Setup if F
});
});
});

test("loadUserConfig - loads local configuration files", async (t) => {
await withTmpDir(async (workspaceDir) => {
await withTmpDir(async (tmpDir) => {
// Construct the test target.
const loadUserConfig = (
actionState: ActionState<["Logger", "Env", "FeatureFlags"]>,
filePath: string,
) =>
configUtils.loadUserConfig(
actionState,
filePath,
workspaceDir,
SAMPLE_DOTCOM_API_DETAILS,
tmpDir,
);
const target = callee(loadUserConfig);

// `loadUserConfig` should load local configuration files if they are inside the workspace:
const insideOfWorkspace = path.join(workspaceDir, "some-file.yml");
fs.writeFileSync(insideOfWorkspace, "test-key: present", "utf8");

await target
.withArgs(insideOfWorkspace)
.passes(t.deepEqual, { "test-key": "present" });

// `loadUserConfig` should normally throw if the path is outside of the workspace:
const outsideOfWorkspace = path.join(
tmpDir,
"not-the-generated-file.yml",
);
fs.writeFileSync(outsideOfWorkspace, "test-key: present", "utf8");

await target
.withArgs(outsideOfWorkspace)
.throws(t, { instanceOf: ConfigurationError });

// `loadUserConfig` does not throw if the path is the result of `userConfigFromActionPath`:
const generatedPath = configUtils.userConfigFromActionPath(tmpDir);
fs.writeFileSync(generatedPath, "test-key: present", "utf8");

await target
.withArgs(generatedPath)
.passes(t.deepEqual, { "test-key": "present" });
});
});
});

test.serial("loadUserConfig - loads remote configuration files", async (t) => {
await withTmpDir(async (tmpDir) => {
const getRemoteConfig = sinon.stub(file, "getRemoteConfig").resolves({});

const remoteAddress = "owner/repo/file@ref";
await callee(configUtils.loadUserConfig)
.withArgs(remoteAddress, tmpDir, SAMPLE_DOTCOM_API_DETAILS, tmpDir)
.passes(t.deepEqual, {});

t.true(
getRemoteConfig.calledOnceWithExactly(
sinon.match.any,
remoteAddress,
SAMPLE_DOTCOM_API_DETAILS,
),
);
});
});

test.serial(
"loadUserConfig - loads remote configuration files (new format, partial)",
async (t) => {
await withTmpDir(async (tmpDir) => {
const getRemoteConfig = sinon.stub(file, "getRemoteConfig").resolves({});
const target = callee(configUtils.loadUserConfig)
.withDefaultActionsEnv()
.withFeatures([Feature.NewRemoteFileAddresses]);

const testTargetWith = async (remoteAddress: string) => {
getRemoteConfig.resetHistory();

await target
.withArgs(remoteAddress, tmpDir, SAMPLE_DOTCOM_API_DETAILS, tmpDir)
.passes(t.deepEqual, {});

t.true(
getRemoteConfig.calledOnceWithExactly(
sinon.match.any,
remoteAddress,
SAMPLE_DOTCOM_API_DETAILS,
),
);
};

// When the new format FF is enabled, all inputs that don't explicitly refer
// to a local file that can be found will be tried as remote addresses.
await testTargetWith("repo:file");
await testTargetWith("input");
await testTargetWith("../input");
await testTargetWith("repo@main");

// An explicitly local path can still override this.
const explicitlyLocalAddress = "./repo@main";

getRemoteConfig.resetHistory();

await target
.withArgs(
explicitlyLocalAddress,
tmpDir,
SAMPLE_DOTCOM_API_DETAILS,
tmpDir,
)
.throws(t);

t.is(getRemoteConfig.callCount, 0);
});
},
);
Loading
Loading