Skip to main content
Glama
nrwl

Nx MCP Server

Official
by nrwl
get-recent-cipe-data.ts5.39 kB
import { CIPEInfo, CIPEInfoError } from '@nx-console/shared-types'; import { execSync } from 'child_process'; import { isNxCloudUsed } from './is-nx-cloud-used'; import { Logger, httpRequest, HttpError } from '@nx-console/shared-utils'; import { getNxCloudUrl } from './cloud-ids'; import { nxCloudAuthHeaders } from './nx-cloud-auth-headers'; const CACHE_TTL_MS = 5000; // 5 seconds let lastFetchTimestamp = 0; let cachedWorkspacePath: string | null = null; let cachedResult: { info?: CIPEInfo[]; error?: CIPEInfoError; workspaceUrl?: string; } | null = null; export async function getRecentCIPEData( workspacePath: string, logger: Logger, ): Promise<{ info?: CIPEInfo[]; error?: CIPEInfoError; workspaceUrl?: string; }> { const now = Date.now(); if (!(await isNxCloudUsed(workspacePath, logger))) { return { error: { type: 'other', message: 'Nx Cloud is not used in this workspace', }, }; } if ( cachedResult && now - lastFetchTimestamp < CACHE_TTL_MS && cachedWorkspacePath === workspacePath ) { logger.log('Returning cached CIPE data'); return cachedResult; } const branches = getRecentlyCommittedGitBranches(workspacePath); const data = JSON.stringify({ branches: branches.map((branch) => branch.name), }); const nxCloudUrl = await getNxCloudUrl(workspacePath); const url = `${nxCloudUrl}/nx-cloud/nx-console/ci-pipeline-executions`; const headers: any = { 'Content-Type': 'application/json', ...(await nxCloudAuthHeaders(workspacePath)), }; logger.log(`Making recent CIPE request`); try { const response = await httpRequest({ type: 'POST', url, headers, data, timeout: 5000, }); const responseData = JSON.parse(response.responseText) as { ciPipelineExecutions: CIPEInfo[]; workspaceUrl: string; }; const result = { info: responseData.ciPipelineExecutions, workspaceUrl: responseData.workspaceUrl, }; cachedResult = result; cachedWorkspacePath = workspacePath; lastFetchTimestamp = Date.now(); logger.debug?.( `Recent CIPE data fetched successfully: ${JSON.stringify(result)}`, ); return result; } catch (e) { // HttpError with 401 status = authentication error if (e instanceof HttpError && e.status === 401) { logger.log(`Authentication error: ${e.responseText}`); return { error: { type: 'authentication', message: e.responseText, }, }; } // Non-HttpError from fetch = network error (connection refused, timeout, etc.) if (!(e instanceof HttpError)) { const errorMessage = e instanceof Error ? e.message : String(e); logger.log(`Network error: ${errorMessage}`); return { error: { type: 'network', message: errorMessage, }, }; } // Other HttpError statuses = other errors logger.log(`Error: ${e.status} ${e.responseText}`); return { error: { type: 'other', message: e.responseText, }, }; } } function getRecentlyCommittedGitBranches( workspacePath: string, ): { name: string; time: string }[] { try { const localUserEmail = execSync('git config user.email').toString().trim(); const oneWeekAgo = new Date( Date.now() - 60 * 60 * 24 * 7 * 1000, ).toISOString(); const ignoredBranches = getIgnoredBranches(workspacePath); const res = execSync( 'git for-each-ref --count=10 --sort=-committerdate refs/heads/ --format="%(refname) - %(committerdate:iso-strict) - %(authoremail)"', { cwd: workspacePath, }, ).toString(); const branches = res .split('\n') .filter((line) => line.trim() !== '') .map((line) => { const [refname, time, email] = line .split(' - ') .map((item) => item.trim()); return { name: refname.replace('refs/heads/', ''), time, email: email, }; }) .filter((item) => { return ( item.email.includes(localUserEmail) && item.time >= oneWeekAgo && !ignoredBranches.includes(item.name) ); }); return branches; } catch (e) { return []; } } export function getIgnoredBranches(workspacePath: string): string[] { const ignoredBranches = [ 'main', 'master', 'trunk', 'next', 'dev', 'development', 'stable', 'canary', ]; // Check refs/remotes/origin/HEAD try { const originHead = execSync('git symbolic-ref refs/remotes/origin/HEAD', { cwd: workspacePath, stdio: 'pipe', }) .toString() .trim() .replace('refs/remotes/origin/', ''); if (originHead && !ignoredBranches.includes(originHead)) { ignoredBranches.push(originHead); } } catch (e) { // ignore } // Check refs/remotes/upstream/HEAD try { const upstreamHead = execSync( 'git symbolic-ref refs/remotes/upstream/HEAD', { cwd: workspacePath, stdio: 'pipe', }, ) .toString() .trim() .replace('refs/remotes/upstream/', ''); if (upstreamHead && !ignoredBranches.includes(upstreamHead)) { ignoredBranches.push(upstreamHead); } } catch (e) { // ignore } return ignoredBranches; }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/nrwl/nx-console'

If you have feedback or need assistance with the MCP directory API, please join our Discord server