Skip to content

Commit

Permalink
Merge branch 'main' into fix/template-path-resolution
Browse files Browse the repository at this point in the history
  • Loading branch information
t1mmen authored Jan 6, 2025
2 parents a159cee + 73b9e74 commit 508de0f
Show file tree
Hide file tree
Showing 7 changed files with 64 additions and 13 deletions.
5 changes: 5 additions & 0 deletions .changeset/spicy-singers-unite.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@t1mmen/srtd": patch
---

Attempt to identify "root of project", so srtd can be run from subdirectories as well.
27 changes: 19 additions & 8 deletions src/commands/register.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import Branding from '../components/Branding.js';
import Quittable from '../components/Quittable.js';
import { COLOR_ERROR, COLOR_SUCCESS, COLOR_WARNING } from '../components/customTheme.js';
import { useTemplateState } from '../hooks/useTemplateState.js';
import { findProjectRoot } from '../utils/findProjectRoot.js';
import { registerTemplate } from '../utils/registerTemplate.js';

// Support both array of filenames as arguments and interactive selection
Expand Down Expand Up @@ -45,15 +46,23 @@ export default function Register({ args: templateArgs }: Props) {
let successCount = 0;
let failCount = 0;

for (const path of templates) {
try {
await registerTemplate(path, process.cwd());
successCount++;
} catch {
failCount++;
try {
const projectRoot = await findProjectRoot();
for (const path of templates) {
try {
await registerTemplate(path, projectRoot);
successCount++;
} catch (err) {
console.error(err);
failCount++;
}
}
} catch (err) {
if (err instanceof Error) {
setErrorMessage(err.message);
}
process.exit(1);
}

if (failCount > 0) {
setErrorMessage(`Failed to register ${failCount} template(s).`);
}
Expand Down Expand Up @@ -122,7 +131,9 @@ export default function Register({ args: templateArgs }: Props) {
<Box gap={2}>
{options.length === 0 ? (
<Box flexDirection="column">
<Text color={COLOR_WARNING}>{figures.warning} No templates found</Text>
<Text color={COLOR_WARNING}>
{figures.warning} No templates {!showAll && 'unregistered'} found
</Text>
{!showAll && !!items.length && (
<Text dimColor>{figures.info} Press r to show registered templates</Text>
)}
Expand Down
6 changes: 4 additions & 2 deletions src/hooks/useTemplateManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { useEffect, useMemo, useRef, useState } from 'react';
import { TemplateManager } from '../lib/templateManager.js';
import type { TemplateStatus } from '../types.js';
import { getConfig } from '../utils/config.js';
import { findProjectRoot } from '../utils/findProjectRoot.js';

export type TemplateUpdate = {
type: 'applied' | 'changed' | 'error';
Expand All @@ -26,7 +27,7 @@ export interface UseTemplateManager {
templateDir?: string;
}

export function useTemplateManager(cwd: string = process.cwd()): UseTemplateManager {
export function useTemplateManager(baseDir?: string): UseTemplateManager {
const [templates, setTemplates] = useState<TemplateStatus[]>([]);
const [updates, setUpdates] = useState<TemplateUpdate[]>([]);
const [errors, setErrors] = useState<Map<string, string>>(new Map());
Expand Down Expand Up @@ -66,6 +67,7 @@ export function useTemplateManager(cwd: string = process.cwd()): UseTemplateMana

async function init() {
try {
const cwd = baseDir || (await findProjectRoot());
const config = await getConfig(cwd);
setTemplateDir(config.templateDir);

Expand Down Expand Up @@ -162,7 +164,7 @@ export function useTemplateManager(cwd: string = process.cwd()): UseTemplateMana
mounted = false;
managerRef.current?.[Symbol.dispose]();
};
}, [cwd]);
}, [baseDir]);

return {
templates: sortedTemplates,
Expand Down
4 changes: 3 additions & 1 deletion src/hooks/useTemplateProcessor.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { useEffect, useRef, useState } from 'react';
import { TemplateManager } from '../lib/templateManager.js';
import type { ProcessedTemplateResult } from '../types.js';
import { findProjectRoot } from '../utils/findProjectRoot.js';

interface ProcessorOptions {
force?: boolean;
Expand All @@ -25,7 +26,8 @@ export function useTemplateProcessor(options: ProcessorOptions) {

async function doProcessing() {
try {
using manager = await TemplateManager.create(process.cwd(), { silent: true });
const projectRoot = await findProjectRoot();
using manager = await TemplateManager.create(projectRoot, { silent: true });
const result = await manager.processTemplates(options);
setResult(result);
setIsProcessing(false);
Expand Down
3 changes: 2 additions & 1 deletion src/hooks/useTemplateState.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import { useEffect, useState } from 'react';
import { TemplateManager } from '../lib/templateManager.js';
import type { TemplateStatus } from '../types.js';
import { findProjectRoot } from '../utils/findProjectRoot.js';

export function useTemplateState() {
const [loading, setLoading] = useState(true);
Expand All @@ -11,7 +12,7 @@ export function useTemplateState() {
useEffect(() => {
async function fetchStatus() {
try {
const baseDir = process.cwd();
const baseDir = await findProjectRoot();
const manager = await TemplateManager.create(baseDir);
const templates = await manager.findTemplates();
const statuses = await Promise.all(templates.map(t => manager.getTemplateStatus(t)));
Expand Down
28 changes: 28 additions & 0 deletions src/utils/findProjectRoot.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import path from 'node:path';
import { fileExists } from './fileExists.js';

async function isProjectDir(dir: string): Promise<boolean> {
// Check for srtd config files
if (await fileExists(path.join(dir, 'srtd.config.json'))) return true;

// Check for package.json
if (await fileExists(path.join(dir, 'package.json'))) return true;

// Check for supabase directory
if (await fileExists(path.join(dir, 'supabase'))) return true;

return false;
}

export async function findProjectRoot(startDir?: string): Promise<string> {
let currentDir = startDir || process.cwd();

while (currentDir !== path.parse(currentDir).root) {
if (await isProjectDir(currentDir)) {
return currentDir;
}
currentDir = path.dirname(currentDir);
}

throw new Error('Could not find project root. Are you in a Supabase project directory?');
}
4 changes: 3 additions & 1 deletion src/utils/registerTemplate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,12 @@ import { loadBuildLog } from './loadBuildLog.js';
import { saveBuildLog } from './saveBuildLog.js';

export async function registerTemplate(templatePath: string, baseDir: string): Promise<void> {
const config = await getConfig();

Check failure on line 10 in src/utils/registerTemplate.ts

View workflow job for this annotation

GitHub Actions / test (20.x)

Cannot find name 'getConfig'. Did you mean 'config'?

const pathsToTry = [
path.resolve(templatePath),
path.resolve(baseDir, templatePath),
path.join(baseDir, templatePath)
path.join(baseDir, templatePath),
];

let resolvedPath: string | null = null;
Expand Down

0 comments on commit 508de0f

Please sign in to comment.