Skip to content

Support auto-detecting Actions workflows #3009

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

Merged
merged 3 commits into from
Aug 7, 2025
Merged
Show file tree
Hide file tree
Changes from 2 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
42 changes: 34 additions & 8 deletions lib/config-utils.js

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

2 changes: 1 addition & 1 deletion lib/config-utils.js.map

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions lib/config-utils.test.js

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

2 changes: 1 addition & 1 deletion lib/config-utils.test.js.map

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions src/config-utils.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1159,6 +1159,7 @@ const mockRepositoryNwo = parseRepositoryNwo("owner/repo");
codeQL,
args.languagesInput,
mockRepositoryNwo,
".",
mockLogger,
);

Expand All @@ -1171,6 +1172,7 @@ const mockRepositoryNwo = parseRepositoryNwo("owner/repo");
codeQL,
args.languagesInput,
mockRepositoryNwo,
".",
mockLogger,
),
{ message: args.expectedError },
Expand Down
44 changes: 41 additions & 3 deletions src/config-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -321,11 +321,35 @@ export async function getSupportedLanguageMap(
return supportedLanguages;
}

const baseWorkflowsPath = ".github/workflows";

/**
* Determines if there exists a `.github/workflows` directory with at least
* one file in it, which we use as an indicator that there are Actions
* workflows in the workspace. This doesn't perfectly detect whether there
* are actually workflows, but should be a good approximation.
*
* Alternatively, we could check specifically for yaml files, or call the
* API to check if it knows about workflows.
*
* @returns True if the non-empty directory exists, false if not.
*/
export function hasActionsWorkflows(sourceRoot: string): boolean {
const workflowsPath = path.resolve(sourceRoot, baseWorkflowsPath);
const stats = fs.lstatSync(workflowsPath);
return (
stats !== undefined &&
stats.isDirectory() &&
fs.readdirSync(workflowsPath).length > 0
);
}

/**
* Gets the set of languages in the current repository.
*/
export async function getRawLanguagesInRepo(
repository: RepositoryNwo,
sourceRoot: string,
logger: Logger,
): Promise<string[]> {
logger.debug(`GitHub repo ${repository.owner} ${repository.repo}`);
Expand All @@ -335,9 +359,18 @@ export async function getRawLanguagesInRepo(
});

logger.debug(`Languages API response: ${JSON.stringify(response)}`);
return Object.keys(response.data as Record<string, number>).map((language) =>
language.trim().toLowerCase(),
const result = Object.keys(response.data as Record<string, number>).map(
(language) => language.trim().toLowerCase(),
);

if (hasActionsWorkflows(sourceRoot)) {
logger.debug(`Found a .github/workflows directory`);
result.push("actions");
}

logger.debug(`Raw languages in repository: ${result.join(", ")}`);

return result;
}

/**
Expand All @@ -354,12 +387,14 @@ export async function getLanguages(
codeql: CodeQL,
languagesInput: string | undefined,
repository: RepositoryNwo,
sourceRoot: string,
logger: Logger,
): Promise<Language[]> {
// Obtain languages without filtering them.
const { rawLanguages, autodetected } = await getRawLanguages(
languagesInput,
repository,
sourceRoot,
logger,
);

Expand Down Expand Up @@ -420,6 +455,7 @@ export function getRawLanguagesNoAutodetect(
export async function getRawLanguages(
languagesInput: string | undefined,
repository: RepositoryNwo,
sourceRoot: string,
logger: Logger,
): Promise<{
rawLanguages: string[];
Expand All @@ -432,7 +468,7 @@ export async function getRawLanguages(
}
// Otherwise, autodetect languages in the repository.
return {
rawLanguages: await getRawLanguagesInRepo(repository, logger),
rawLanguages: await getRawLanguagesInRepo(repository, sourceRoot, logger),
autodetected: true,
};
}
Expand Down Expand Up @@ -481,6 +517,7 @@ export async function getDefaultConfig({
repository,
tempDir,
codeql,
sourceRoot,
githubVersion,
features,
logger,
Expand All @@ -489,6 +526,7 @@ export async function getDefaultConfig({
codeql,
languagesInput,
repository,
sourceRoot,
logger,
);

Expand Down
Loading