Per provider (github|gitlab|gitea) a project override stored in ~/.config/openchamber/projects/<projectId>.json under gitProviders wins over the global settings.json value (precedence: project override > global > built-in default). Server forge routes resolve the override per request directory (worktree-aware via git-common-dir + containment + path fallback, 60s TTL cache); the override host is also accepted for remote parsing and client detection. New GET/PUT /api/projects/:projectId/git-providers route; client openchamberConfig preserves the server-owned gitProviders key; Projects page gains a Git provider API base URLs section; detection store hydrates per-project overrides (memory-only, server-authoritative).
50 lines
1.9 KiB
JavaScript
50 lines
1.9 KiB
JavaScript
import { getProjectGitProviders, saveProjectGitProviders } from './project-config.js';
|
|
|
|
const asNonEmptyString = (value) => {
|
|
if (typeof value !== 'string') {
|
|
return null;
|
|
}
|
|
const trimmed = value.trim();
|
|
return trimmed.length > 0 ? trimmed : null;
|
|
};
|
|
|
|
const parseProjectId = (req) => asNonEmptyString(req?.params?.projectId);
|
|
|
|
const isPlainObject = (value) =>
|
|
value !== null && value !== undefined && typeof value === 'object' && !Array.isArray(value);
|
|
|
|
export function registerGitProviderRoutes(app) {
|
|
app.get('/api/projects/:projectId/git-providers', async (req, res) => {
|
|
const projectId = parseProjectId(req);
|
|
if (!projectId) {
|
|
return res.status(400).json({ error: 'projectId is required' });
|
|
}
|
|
try {
|
|
return res.json({ gitProviders: getProjectGitProviders(projectId) });
|
|
} catch (error) {
|
|
console.error('[GitProviders] failed to load project git providers:', error);
|
|
return res.status(500).json({ error: 'Failed to load project git providers' });
|
|
}
|
|
});
|
|
|
|
app.put('/api/projects/:projectId/git-providers', async (req, res) => {
|
|
const projectId = parseProjectId(req);
|
|
if (!projectId) {
|
|
return res.status(400).json({ error: 'projectId is required' });
|
|
}
|
|
if (!isPlainObject(req.body) || !isPlainObject(req.body.gitProviders)) {
|
|
return res.status(400).json({ error: 'gitProviders payload is required' });
|
|
}
|
|
try {
|
|
const saved = await saveProjectGitProviders(projectId, req.body.gitProviders);
|
|
return res.json({ gitProviders: saved });
|
|
} catch (error) {
|
|
const message = error instanceof Error ? error.message : 'Failed to save project git providers';
|
|
const statusCode = message.toLowerCase().includes('unsupported characters') ? 400 : 500;
|
|
if (statusCode === 500) {
|
|
console.error('[GitProviders] failed to save project git providers:', error);
|
|
}
|
|
return res.status(statusCode).json({ error: message });
|
|
}
|
|
});
|
|
} |