Skip to content

Commit

Permalink
add first plugin
Browse files Browse the repository at this point in the history
  • Loading branch information
beagleknight committed Dec 3, 2024
1 parent 3ef969a commit 1ae7bd3
Show file tree
Hide file tree
Showing 7 changed files with 122 additions and 102 deletions.
13 changes: 13 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,16 @@
- [ ] global cache commiter + git
- [ ] initial generate
- [ ] lock file

## Plugins

- [ ] shadowdog-local-cache
- [ ] shadowdog-remote-cache (minio, aws)
- [ ] shadowdog-rake
- [ ] shadowdog-git

const shadowDogRake(tasks: Task[]): Task[]

## [{ command: "bundle exec rake hola"}, { command: "bundle exec rake adeu"}, { command: "echo 'hola'"}]

[{ command: "bundle exec rake hola adeu"}, { command: "echo 'hola'"}]
27 changes: 26 additions & 1 deletion shadowdog.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
{
"$schema": "./src/config/schema.json",
"plugins": [
"shadowdog-rake"
],
"cache": {
"enabled": true
"enabled": false
},
"watchers": [
{
Expand All @@ -16,6 +19,28 @@
"command": "npm run build-schema"
}
]
},
{
"files": ["file1"],
"commands": [
{
"artifacts": [{ "output": "artifact1" }],
"command": "echo task1"
}
]
},
{
"files": ["file23"],
"commands": [
{
"artifacts": [{ "output": "artifact2" }],
"command": "echo task2"
},
{
"artifacts": [{ "output": "artifact3" }],
"command": "echo task3"
}
]
}
]
}
16 changes: 6 additions & 10 deletions src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { logMessage } from './utils'
import { z } from 'zod'
import chalk from 'chalk'

const CommandTypeEnum = z.enum(['shell', 'rake'])
const PluginTypeEnum = z.enum(['shadowdog-rake'])

export const configSchema = z
.object({
Expand All @@ -14,17 +14,16 @@ export const configSchema = z
.optional()
.default(2000)
.describe('The time in milliseconds to wait before running the command after a file change.'),
rake: z
.object({
command: z.string().default('bundle exec rake').describe('The command to run rake tasks'),
})
.optional()
.describe('Rake configuration'),
defaultIgnoredFiles: z
.array(z.string().describe('File path or glob'))
.optional()
.default(['.git', '**/node_modules'])
.describe('Default ignored files when watching files'),
plugins: z
.array(PluginTypeEnum.describe('Plugin name'))
.optional()
.default([])
.describe('List of plugins to use'),
cache: z
.object({
enabled: z.boolean().describe('Whether to enable caching or not'),
Expand Down Expand Up @@ -83,9 +82,6 @@ export const configSchema = z
z
.object({
command: z.string().describe('The command to run when a file changes'),
type: CommandTypeEnum.optional()
.default(CommandTypeEnum.enum.shell)
.describe('The type of command to run'),
artifacts: z
.array(
z
Expand Down
28 changes: 10 additions & 18 deletions src/config/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,6 @@
"default": 2000,
"description": "The time in milliseconds to wait before running the command after a file change."
},
"rake": {
"type": "object",
"properties": {
"command": {
"type": "string",
"default": "bundle exec rake",
"description": "The command to run rake tasks"
}
},
"additionalProperties": false,
"description": "Rake configuration"
},
"defaultIgnoredFiles": {
"type": "array",
"items": {
Expand All @@ -31,6 +19,16 @@
"default": [".git", "**/node_modules"],
"description": "Default ignored files when watching files"
},
"plugins": {
"type": "array",
"items": {
"type": "string",
"enum": ["shadowdog-rake"],
"description": "Plugin name"
},
"default": [],
"description": "List of plugins to use"
},
"cache": {
"type": "object",
"properties": {
Expand Down Expand Up @@ -125,12 +123,6 @@
"type": "string",
"description": "The command to run when a file changes"
},
"type": {
"type": "string",
"enum": ["shell", "rake"],
"default": "shell",
"description": "The type of command to run"
},
"artifacts": {
"type": "array",
"items": {
Expand Down
5 changes: 1 addition & 4 deletions src/daemon.ts
Original file line number Diff line number Diff line change
Expand Up @@ -141,10 +141,7 @@ const setupWatchers = (config: ConfigFile, socketPath: string, client: Client |

try {
await runTask({
command:
commandConfig.type === 'rake'
? `${config.rake?.command} ${commandConfig.command}`
: commandConfig.command,
command: commandConfig.command,
workingDirectory: process.cwd(),
filePath,
onSpawn: (task) => {
Expand Down
88 changes: 19 additions & 69 deletions src/generate.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,18 @@
import fs from 'fs-extra'

import { WatcherConfig, loadConfig, ConfigFile, CommandConfig } from './config'
import { WatcherConfig, loadConfig, ConfigFile } from './config'
import { runTask } from './tasks'
import { computeCache, restoreCache, saveCache } from './cache'
import { createClient } from './global-cache'
import type { DependencyObject } from './dependencyGraph'
import { DependencyGraph } from './dependencyGraph'
import { logMessage } from './utils'
import { Client } from 'minio'
import { middleware as shadowdogRake } from './plugins/shadowdog-rake'

const PLUGINS_MAP = {
'shadowdog-rake': shadowdogRake,
} as const

interface WatcherInDependencyGraphFormat extends DependencyObject {
watcher: WatcherConfig
Expand Down Expand Up @@ -48,11 +53,6 @@ const selectWatchersToRun = async (
client: Client | null,
tag?: string,
): Promise<WatcherConfig[]> => {
// Prune commands that don't generate artifacts
watchers.forEach((watcher) => {
watcher.commands = watcher.commands.filter((command) => command.artifacts?.length)
})

// Prune commands not matching the current tag if any
if (tag) {
watchers.forEach((watcher) => {
Expand Down Expand Up @@ -93,56 +93,6 @@ const selectWatchersToRun = async (
return watchers.filter((watcher) => watcher.commands.length)
}

interface CommandRunnerConfig {
workingDirectory: string
command: string
configs: {
commandConfig: CommandConfig
watcherConfig: WatcherConfig
}[]
}

interface CommandWithTheirWatcher {
commandConfig: CommandConfig
watcherConfig: WatcherConfig
}

const aggregateCommands = (generalConfig: ConfigFile, commands: CommandWithTheirWatcher[]) => {
const results: CommandRunnerConfig[] = []
const rakeTasks: CommandWithTheirWatcher[] = []

commands.forEach((command) => {
if (command.commandConfig.type === 'rake') {
rakeTasks.push(command)
} else {
results.push({
workingDirectory: process.cwd(),
command: command.commandConfig.command,
configs: [
{
commandConfig: command.commandConfig,
watcherConfig: command.watcherConfig,
},
],
})
}
})

if (rakeTasks.length) {
const rakeCommand = `${generalConfig.rake?.command} ${rakeTasks
.map((rakeTask) => rakeTask.commandConfig.command)
.join(' ')}`

results.push({
workingDirectory: process.cwd(),
command: rakeCommand,
configs: rakeTasks,
})
}

return results
}

const processLayer = async (
watcherConfigs: WatcherConfig[],
config: ConfigFile,
Expand All @@ -155,15 +105,13 @@ const processLayer = async (
})),
)

const aggregatedCommands = aggregateCommands(config, commandsToRun)

const promises = aggregatedCommands.map(async ({ workingDirectory, command, configs }) => {
await runTask({
workingDirectory: workingDirectory,
command: command,
})
return Promise.all(
commandsToRun.map(async ({ watcherConfig, commandConfig }) => {
await runTask({
workingDirectory: process.cwd(),
command: commandConfig.command,
})

for (const { watcherConfig, commandConfig } of configs) {
const currentCacheKey = config.cache.enabled
? computeCache(
config,
Expand All @@ -173,14 +121,13 @@ const processLayer = async (
: ''

await saveCache(config, commandConfig, currentCacheKey, client)
}
})

return Promise.all(promises)
}),
)
}

export const generate = async (configFilePath: string, tag?: string) => {
const config = loadConfig(configFilePath)
const plugins = config.plugins.map((pluginName) => PLUGINS_MAP[pluginName])

fs.mkdirpSync(config.cache.path)

Expand All @@ -192,7 +139,10 @@ export const generate = async (configFilePath: string, tag?: string) => {

for (const [i, watcherConfigs] of sortedWatchers.entries()) {
logMessage(`🎛️ Running layer ${i + 1} of ${sortedWatchers.length}:`)
const activeWatchers = await selectWatchersToRun(watcherConfigs, config, client, tag)
const activeWatchers = plugins.reduce(
(watchers, plugin) => plugin(watchers),
await selectWatchersToRun(watcherConfigs, config, client, tag),
)
await processLayer(activeWatchers, config, client)
}
}
47 changes: 47 additions & 0 deletions src/plugins/shadowdog-rake.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { WatcherConfig } from '../config'

const RAKE_COMMAND_REGEX = /^bundle exec rake (.*)$/

export const middleware = (activeWatchers: WatcherConfig[]) => {
const groupedWatchers = activeWatchers.reduce<{
rake: WatcherConfig[]
nonRake: WatcherConfig[]
}>(
(acc, watcher) => {
const isRakeWatcher = watcher.commands.some((c) => c.command.match(RAKE_COMMAND_REGEX))

if (isRakeWatcher) {
acc.rake.push(watcher)
} else {
acc.nonRake.push(watcher)
}

return acc
},
{ rake: [], nonRake: [] },
)

const rakeTasks = groupedWatchers.rake.flatMap((watcher) =>
watcher.commands.map((c) => c.command.match(RAKE_COMMAND_REGEX)![1]),
)

if (rakeTasks.length === 0) {
return groupedWatchers.nonRake
}

return [
...groupedWatchers.nonRake,
{
enabled: true,
files: groupedWatchers.rake.flatMap((watcher) => watcher.files),
commands: [
{
artifacts: groupedWatchers.rake.flatMap((watcher) =>
watcher.commands.flatMap((c) => c.artifacts ?? []),
),
command: `bundle exec rake ${rakeTasks.join(' ')}`,
},
],
},
]
}

0 comments on commit 1ae7bd3

Please sign in to comment.