From 7ad9bc779b48e8ca6551483dc33d100805e06fea Mon Sep 17 00:00:00 2001 From: Ishita Sati Date: Fri, 20 Feb 2026 22:46:13 +0530 Subject: [PATCH] shared runner metadata changes by Ishita --- src/language.ts | 82 +++++++++++++++++++++++++++++++++------- src/package.ts | 27 +++++-------- src/test/package.spec.ts | 23 +++++++++++ 3 files changed, 101 insertions(+), 31 deletions(-) diff --git a/src/language.ts b/src/language.ts index ecb3edd..de048ba 100644 --- a/src/language.ts +++ b/src/language.ts @@ -5,14 +5,56 @@ */ +import { basename } from 'path'; import { LanguageId } from './deployment'; +export type Runner = 'nodejs' | 'python' | 'ruby' | 'csharp'; + +export interface RunnerInfo { + id: Runner; + languageId: LanguageId; + filePatterns: RegExp[]; + installCommand: string; + displayName: string; +} + +export const Runners: Record = { + nodejs: { + id: 'nodejs', + languageId: 'node', + filePatterns: [/^package\.json$/], + installCommand: 'npm install', + displayName: 'NPM' + }, + python: { + id: 'python', + languageId: 'py', + filePatterns: [/^requirements\.txt$/], + installCommand: 'pip install -r requirements.txt', + displayName: 'Pip' + }, + ruby: { + id: 'ruby', + languageId: 'rb', + filePatterns: [/^Gemfile$/], + installCommand: 'bundle install', + displayName: 'Gem' + }, + csharp: { + id: 'csharp', + languageId: 'cs', + filePatterns: [/^project\.json$/, /\.csproj$/], + installCommand: 'dotnet restore', + displayName: 'NuGet' + } +}; + interface Language { tag: string; // Tag which corresponds to language_id in metacall.json displayName: string; // Name for displaying the language hexColor: string; // Color for displaying the language related things fileExtRegex: RegExp; // Regex for selecting the metacall.json scripts field - runnerName?: string; // Id of the runner + runnerName?: Runner; // Id of the runner runnerFilesRegexes: RegExp[]; // Regex for generating the runners list } @@ -23,7 +65,7 @@ export const Languages: Record = { hexColor: '#953dac', fileExtRegex: /^cs$/, runnerName: 'csharp', - runnerFilesRegexes: [/^project\.json$/, /\.csproj$/] + runnerFilesRegexes: Runners.csharp.filePatterns }, py: { tag: 'py', @@ -31,7 +73,7 @@ export const Languages: Record = { hexColor: '#ffd43b', fileExtRegex: /^py$/, runnerName: 'python', - runnerFilesRegexes: [/^requirements\.txt$/] + runnerFilesRegexes: Runners.python.filePatterns }, rb: { tag: 'rb', @@ -39,7 +81,7 @@ export const Languages: Record = { hexColor: '#e53935', fileExtRegex: /^rb$/, runnerName: 'ruby', - runnerFilesRegexes: [/^Gemfile$/] + runnerFilesRegexes: Runners.ruby.filePatterns }, node: { tag: 'node', @@ -47,7 +89,7 @@ export const Languages: Record = { hexColor: '#3c873a', fileExtRegex: /^js$/, runnerName: 'nodejs', - runnerFilesRegexes: [/^package\.json$/] + runnerFilesRegexes: Runners.nodejs.filePatterns }, ts: { tag: 'ts', @@ -55,7 +97,7 @@ export const Languages: Record = { hexColor: '#007acc', fileExtRegex: /^(ts|tsx)$/, runnerName: 'nodejs', - runnerFilesRegexes: [/^package\.json$/] // TODO: Use tsconfig instead? + runnerFilesRegexes: Runners.nodejs.filePatterns }, file: { tag: 'file', @@ -94,12 +136,26 @@ export const DisplayNameToLanguageId: Record = Object.keys( ); export const RunnerToDisplayName = (runner: string): string => { - const displayNameMap: Record = { - nodejs: 'NPM', - python: 'Pip', - ruby: 'Gem', - csharp: 'NuGet' - }; + const match = Runners[runner as Runner]; + + return match ? match.displayName : 'Build'; +}; + +export const detectRunnersFromFiles = (files: string[]): Runner[] => { + const runners = new Set(); + + for (const file of files) { + const fileName = basename(file); + + for (const runner of Object.values(Runners)) { + for (const pattern of runner.filePatterns) { + if (pattern.exec(fileName)) { + runners.add(runner.id); + break; + } + } + } + } - return displayNameMap[runner] || 'Build'; + return Array.from(runners); }; diff --git a/src/package.ts b/src/package.ts index b77020a..9aaaeeb 100644 --- a/src/package.ts +++ b/src/package.ts @@ -15,7 +15,7 @@ import walk from 'ignore-walk'; import { basename, extname } from 'path'; import { LanguageId, MetaCallJSON } from './deployment'; -import { Languages } from './language'; +import { detectRunnersFromFiles, Languages, Runner } from './language'; export const findFilesPath = async ( path: string = process.cwd(), @@ -36,23 +36,14 @@ export const pathIsMetaCallJson = (path: string): boolean => export const findMetaCallJsons = (files: string[]): string[] => files.filter(pathIsMetaCallJson); -export const findRunners = (files: string[]): Set => { - const runners: Set = new Set(); - - for (const file of files) { - const fileName = basename(file); - for (const langId of Object.keys(Languages)) { - const lang = Languages[langId as LanguageId]; - for (const re of lang.runnerFilesRegexes) { - if (re.exec(fileName) && lang.runnerName) { - runners.add(lang.runnerName); - } - } - } - } +export const findRunners = (files: string[]): Set => + new Set(detectRunnersFromFiles(files)); - return runners; -}; +export const detectRunners = async ( + path: string = process.cwd(), + ignoreFiles: string[] = ['.gitignore'] +): Promise => + detectRunnersFromFiles(await findFilesPath(path, ignoreFiles)); export enum PackageError { Empty = 'No files found in the current folder', @@ -64,7 +55,7 @@ interface PackageDescriptor { error: PackageError; files: string[]; jsons: string[]; - runners: string[]; + runners: Runner[]; } const NullPackage: PackageDescriptor = { diff --git a/src/test/package.spec.ts b/src/test/package.spec.ts index 0777d7c..c2de87f 100644 --- a/src/test/package.spec.ts +++ b/src/test/package.spec.ts @@ -1,6 +1,7 @@ import { deepStrictEqual } from 'assert'; import { join } from 'path'; import { MetaCallJSON } from '../deployment'; +import { detectRunnersFromFiles, Runners } from '../language'; import { findFilesPath, findMetaCallJsons, @@ -127,6 +128,28 @@ describe('Unit Package', function () { deepStrictEqual(Array.from(findRunners(files)), expectedRunners); }); + it('detectRunnersFromFiles all', async () => { + const runnersPath = join(basePath, 'runners'); + const expectedRunners: string[] = [ + 'csharp', + 'ruby', + 'nodejs', + 'python' + ]; + const files = await findFilesPath(runnersPath); + deepStrictEqual(detectRunnersFromFiles(files), expectedRunners); + }); + + it('runners include install commands', () => { + deepStrictEqual(Runners.nodejs.installCommand, 'npm install'); + deepStrictEqual( + Runners.python.installCommand, + 'pip install -r requirements.txt' + ); + deepStrictEqual(Runners.ruby.installCommand, 'bundle install'); + deepStrictEqual(Runners.csharp.installCommand, 'dotnet restore'); + }); + it('generateJsonsFromFiles', async () => { const runnersPath = join(basePath, 'runners'); const files = await findFilesPath(runnersPath);