update message
This commit is contained in:
parent
cb0b7a04ca
commit
9e6e7e3550
@ -19,6 +19,7 @@ import {
|
|||||||
validateMinVersion,
|
validateMinVersion,
|
||||||
isVersionCompatible,
|
isVersionCompatible,
|
||||||
checkPackageHasContent,
|
checkPackageHasContent,
|
||||||
|
checkPackageHasContentWithContext,
|
||||||
validateRealpathInsideRoot,
|
validateRealpathInsideRoot,
|
||||||
resolvePackConfigPath,
|
resolvePackConfigPath,
|
||||||
} from '../../features/ensemble/takt-pack-config.js';
|
} from '../../features/ensemble/takt-pack-config.js';
|
||||||
@ -247,6 +248,14 @@ describe('checkPackageHasContent', () => {
|
|||||||
expect(() => checkPackageHasContent(tempDir)).toThrow();
|
expect(() => checkPackageHasContent(tempDir)).toThrow();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should include manifest/path/hint details in contextual error', () => {
|
||||||
|
const manifestPath = join(tempDir, '.takt', 'takt-package.yaml');
|
||||||
|
expect(() => checkPackageHasContentWithContext(tempDir, {
|
||||||
|
manifestPath,
|
||||||
|
configuredPath: '.',
|
||||||
|
})).toThrow(/path: \.takt/);
|
||||||
|
});
|
||||||
|
|
||||||
it('should not throw when only faceted/ exists', () => {
|
it('should not throw when only faceted/ exists', () => {
|
||||||
// Given: package with faceted/ only
|
// Given: package with faceted/ only
|
||||||
mkdirSync(join(tempDir, 'faceted'), { recursive: true });
|
mkdirSync(join(tempDir, 'faceted'), { recursive: true });
|
||||||
|
|||||||
@ -10,6 +10,7 @@ import { mkdirSync, copyFileSync, existsSync, readFileSync, writeFileSync, rmSyn
|
|||||||
import { join, dirname } from 'node:path';
|
import { join, dirname } from 'node:path';
|
||||||
import { tmpdir } from 'node:os';
|
import { tmpdir } from 'node:os';
|
||||||
import { execFileSync } from 'node:child_process';
|
import { execFileSync } from 'node:child_process';
|
||||||
|
import { createRequire } from 'node:module';
|
||||||
import { stringify as stringifyYaml } from 'yaml';
|
import { stringify as stringifyYaml } from 'yaml';
|
||||||
import { getEnsemblePackageDir } from '../../infra/config/paths.js';
|
import { getEnsemblePackageDir } from '../../infra/config/paths.js';
|
||||||
import { parseGithubSpec } from '../../features/ensemble/github-spec.js';
|
import { parseGithubSpec } from '../../features/ensemble/github-spec.js';
|
||||||
@ -18,7 +19,7 @@ import {
|
|||||||
validateTaktPackPath,
|
validateTaktPackPath,
|
||||||
validateMinVersion,
|
validateMinVersion,
|
||||||
isVersionCompatible,
|
isVersionCompatible,
|
||||||
checkPackageHasContent,
|
checkPackageHasContentWithContext,
|
||||||
validateRealpathInsideRoot,
|
validateRealpathInsideRoot,
|
||||||
resolvePackConfigPath,
|
resolvePackConfigPath,
|
||||||
} from '../../features/ensemble/takt-pack-config.js';
|
} from '../../features/ensemble/takt-pack-config.js';
|
||||||
@ -33,7 +34,7 @@ import { confirm } from '../../shared/prompt/index.js';
|
|||||||
import { info, success } from '../../shared/ui/index.js';
|
import { info, success } from '../../shared/ui/index.js';
|
||||||
import { createLogger, getErrorMessage } from '../../shared/utils/index.js';
|
import { createLogger, getErrorMessage } from '../../shared/utils/index.js';
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
const require = createRequire(import.meta.url);
|
||||||
const { version: TAKT_VERSION } = require('../../../package.json') as { version: string };
|
const { version: TAKT_VERSION } = require('../../../package.json') as { version: string };
|
||||||
|
|
||||||
const log = createLogger('ensemble-add');
|
const log = createLogger('ensemble-add');
|
||||||
@ -63,16 +64,15 @@ export async function ensembleAddCommand(spec: string): Promise<void> {
|
|||||||
mkdirSync(tmpExtractDir, { recursive: true });
|
mkdirSync(tmpExtractDir, { recursive: true });
|
||||||
|
|
||||||
info(`📦 ${owner}/${repo} @${ref} をダウンロード中...`);
|
info(`📦 ${owner}/${repo} @${ref} をダウンロード中...`);
|
||||||
execFileSync(
|
const tarballBuffer = execFileSync(
|
||||||
'gh',
|
'gh',
|
||||||
[
|
[
|
||||||
'api',
|
'api',
|
||||||
`/repos/${owner}/${repo}/tarball/${ref}`,
|
`/repos/${owner}/${repo}/tarball/${ref}`,
|
||||||
'--header', 'Accept: application/octet-stream',
|
|
||||||
'--output', tmpTarPath,
|
|
||||||
],
|
],
|
||||||
{ stdio: ['inherit', 'pipe', 'pipe'] },
|
{ stdio: ['inherit', 'pipe', 'pipe'] },
|
||||||
);
|
);
|
||||||
|
writeFileSync(tmpTarPath, tarballBuffer);
|
||||||
|
|
||||||
const tarVerboseList = execFileSync('tar', ['tvzf', tmpTarPath], {
|
const tarVerboseList = execFileSync('tar', ['tvzf', tmpTarPath], {
|
||||||
encoding: 'utf-8',
|
encoding: 'utf-8',
|
||||||
@ -112,7 +112,10 @@ export async function ensembleAddCommand(spec: string): Promise<void> {
|
|||||||
|
|
||||||
validateRealpathInsideRoot(packageRoot, tmpExtractDir);
|
validateRealpathInsideRoot(packageRoot, tmpExtractDir);
|
||||||
|
|
||||||
checkPackageHasContent(packageRoot);
|
checkPackageHasContentWithContext(packageRoot, {
|
||||||
|
manifestPath: packConfigPath,
|
||||||
|
configuredPath: config.path,
|
||||||
|
});
|
||||||
|
|
||||||
const targets = collectCopyTargets(packageRoot);
|
const targets = collectCopyTargets(packageRoot);
|
||||||
const facetFiles = targets.filter(t => t.relativePath.startsWith('faceted/'));
|
const facetFiles = targets.filter(t => t.relativePath.startsWith('faceted/'));
|
||||||
|
|||||||
@ -23,6 +23,11 @@ export interface TaktPackConfig {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface PackageContentCheckContext {
|
||||||
|
manifestPath?: string;
|
||||||
|
configuredPath?: string;
|
||||||
|
}
|
||||||
|
|
||||||
const SEMVER_PATTERN = /^\d+\.\d+\.\d+$/;
|
const SEMVER_PATTERN = /^\d+\.\d+\.\d+$/;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -113,6 +118,41 @@ export function checkPackageHasContent(packageRoot: string): void {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check package content and include user-facing diagnostics when empty.
|
||||||
|
*
|
||||||
|
* Adds manifest/configured-path details and a practical hint for nested layouts
|
||||||
|
* (e.g. when actual content is under ".takt/" but path remains ".").
|
||||||
|
*/
|
||||||
|
export function checkPackageHasContentWithContext(
|
||||||
|
packageRoot: string,
|
||||||
|
context: PackageContentCheckContext,
|
||||||
|
): void {
|
||||||
|
const hasFaceted = existsSync(join(packageRoot, 'faceted'));
|
||||||
|
const hasPieces = existsSync(join(packageRoot, 'pieces'));
|
||||||
|
if (hasFaceted || hasPieces) return;
|
||||||
|
|
||||||
|
const checkedFaceted = join(packageRoot, 'faceted');
|
||||||
|
const checkedPieces = join(packageRoot, 'pieces');
|
||||||
|
const configuredPath = context.configuredPath ?? '.';
|
||||||
|
const manifestPath = context.manifestPath ?? '(unknown)';
|
||||||
|
const hint = configuredPath === '.'
|
||||||
|
? `hint: If your package content is under ".takt/", set "path: .takt" in ${TAKT_PACKAGE_MANIFEST_FILENAME}.`
|
||||||
|
: `hint: Verify "path: ${configuredPath}" points to a directory containing faceted/ or pieces/.`;
|
||||||
|
|
||||||
|
throw new Error(
|
||||||
|
[
|
||||||
|
'Package content not found.',
|
||||||
|
`manifest: ${manifestPath}`,
|
||||||
|
`configured path: ${configuredPath}`,
|
||||||
|
`resolved package root: ${packageRoot}`,
|
||||||
|
`checked: ${checkedFaceted}`,
|
||||||
|
`checked: ${checkedPieces}`,
|
||||||
|
hint,
|
||||||
|
].join('\n'),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Resolve the path to takt-package.yaml within an extracted tarball directory.
|
* Resolve the path to takt-package.yaml within an extracted tarball directory.
|
||||||
*
|
*
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user