mirror of
https://github.com/abhigyanpatwari/GitNexus.git
synced 2026-10-05 02:43:32 +00:00
fix(ci-setup): pin generated workflows and Cursor MCP to the wizard version
Generated automation used `npx gitnexus@latest`, which silently pulls whatever was last published — a non-reproducible single point of failure for every consumer's CI. Read the wizard's own version from gitnexus/package.json (the setup.ts MCP_PINNED_REF pattern; read in ci-setup.ts where ../../package.json resolves correctly, threaded via CiSetupOptions to avoid a generateFiles signature churn) and pin the GitHub Actions + Azure pipeline analyze steps and the persisted Cursor stdio MCP launch to `gitnexus@<version>`. The human-facing manual re-index commands in GITNEXUS.md intentionally stay `@latest`, matching setup.ts's "READMEs may use latest, persisted configs are pinned" rule. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
317bb3b4ea
commit
b05e71c644
5 changed files with 39 additions and 3 deletions
|
|
@ -12,12 +12,21 @@
|
|||
|
||||
import fs from 'fs/promises';
|
||||
import path from 'path';
|
||||
import { createRequire } from 'module';
|
||||
import { detectEnvironment, checkPortAvailable } from './ci-setup/detect.js';
|
||||
import { resolveOptions } from './ci-setup/prompts.js';
|
||||
import { generateFiles } from './ci-setup/templates.js';
|
||||
import type { CiSetupOptions, CiSetupResult, GeneratedFile } from './ci-setup/types.js';
|
||||
import type { CiSystem, DeployTarget, AuthMode, BranchStrategy } from './ci-setup/types.js';
|
||||
|
||||
// Pin generated automation/config to the wizard's own version (mirrors setup.ts).
|
||||
// Read here (src/cli/, where ../../package.json resolves to gitnexus/package.json);
|
||||
// do NOT read it from templates.ts, which is one level deeper.
|
||||
const moduleRequire = createRequire(import.meta.url);
|
||||
const pkgJson = moduleRequire('../../package.json') as { version?: unknown };
|
||||
const GITNEXUS_VERSION =
|
||||
typeof pkgJson.version === 'string' && pkgJson.version ? pkgJson.version : 'latest';
|
||||
|
||||
const CI_SYSTEMS: readonly CiSystem[] = ['github-actions', 'azure-devops', 'both'];
|
||||
const DEPLOY_TARGETS: readonly DeployTarget[] = ['docker', 'azure-container-app', 'both'];
|
||||
const AUTH_MODES: readonly AuthMode[] = ['token', 'none'];
|
||||
|
|
@ -95,6 +104,7 @@ export const ciSetupCommand = async (options?: {
|
|||
if (options?.apply !== undefined) partial.apply = options.apply;
|
||||
if (options?.yes !== undefined) partial.yes = options.yes;
|
||||
if (options?.outputDir) partial.outputDir = options.outputDir;
|
||||
partial.version = GITNEXUS_VERSION;
|
||||
|
||||
// Default: dry-run when neither --dry-run nor --apply is given
|
||||
if (!partial.dryRun && !partial.apply) {
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ export async function resolveOptions(
|
|||
apply: partial.apply ?? false,
|
||||
yes: partial.yes ?? false,
|
||||
outputDir: partial.outputDir ?? detect.gitRoot ?? process.cwd(),
|
||||
version: partial.version ?? 'latest',
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@ jobs:
|
|||
node-version: '22'
|
||||
|
||||
- name: Analyze repository
|
||||
run: npx gitnexus@latest analyze --skills
|
||||
run: npx gitnexus@${opts.version} analyze --skills
|
||||
|
||||
- name: Upload index artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
|
|
@ -113,7 +113,7 @@ steps:
|
|||
versionSpec: '22.x'
|
||||
displayName: 'Set up Node.js 22'
|
||||
|
||||
- script: npx gitnexus@latest analyze --skills
|
||||
- script: npx gitnexus@${opts.version} analyze --skills
|
||||
displayName: 'Analyze repository'
|
||||
|
||||
- task: PublishPipelineArtifact@1
|
||||
|
|
@ -389,7 +389,7 @@ Add to \`~/.cursor/mcp.json\` under \`mcpServers\`:
|
|||
\`\`\`json
|
||||
"gitnexus": {
|
||||
"command": "npx",
|
||||
"args": ["-y", "gitnexus@latest", "mcp"],
|
||||
"args": ["-y", "gitnexus@${opts.version}", "mcp"],
|
||||
"env": {}
|
||||
}
|
||||
\`\`\`
|
||||
|
|
|
|||
|
|
@ -13,6 +13,8 @@ export interface CiSetupOptions {
|
|||
apply: boolean;
|
||||
yes: boolean;
|
||||
outputDir: string;
|
||||
/** gitnexus version the generated automation/config should pin to. */
|
||||
version: string;
|
||||
}
|
||||
|
||||
export interface DetectResult {
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ function makeOpts(overrides?: Partial<CiSetupOptions>): CiSetupOptions {
|
|||
apply: false,
|
||||
yes: false,
|
||||
outputDir: '/repo',
|
||||
version: '9.9.9',
|
||||
...overrides,
|
||||
};
|
||||
}
|
||||
|
|
@ -85,6 +86,28 @@ describe('GITNEXUS.md / workflow accuracy (U8)', () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('version pinning (U9)', () => {
|
||||
it('pins the GitHub Actions workflow analyze step to the wizard version', () => {
|
||||
const files = generateFiles(makeOpts({ version: '9.9.9' }), DEFAULT_DETECT);
|
||||
const wf = files.find((f) => f.relativePath === '.github/workflows/gitnexus-ci.yml');
|
||||
expect(wf?.content).toContain('gitnexus@9.9.9 analyze');
|
||||
expect(wf?.content).not.toContain('gitnexus@latest');
|
||||
});
|
||||
|
||||
it('pins the Azure pipeline analyze step', () => {
|
||||
const files = generateFiles(makeOpts({ version: '9.9.9', ci: 'azure-devops' }), DEFAULT_DETECT);
|
||||
const az = files.find((f) => f.relativePath === 'azure-pipelines-gitnexus.yml');
|
||||
expect(az?.content).toContain('gitnexus@9.9.9 analyze');
|
||||
expect(az?.content).not.toContain('gitnexus@latest');
|
||||
});
|
||||
|
||||
it('pins the Cursor MCP launch but leaves manual re-index commands at @latest', () => {
|
||||
const md = gitnexusMd({ version: '9.9.9' });
|
||||
expect(md).toContain('"gitnexus@9.9.9"'); // persisted Cursor stdio config — pinned
|
||||
expect(md).toContain('npx gitnexus@latest analyze'); // human-run re-index — intentionally unpinned
|
||||
});
|
||||
});
|
||||
|
||||
describe('generateFiles', () => {
|
||||
describe('GitHub Actions workflow', () => {
|
||||
it('generates with correct port in healthcheck', () => {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue