Skip to content

Commit d13d3b4

Browse files
committed
implement pipeline_version endpoint / rollback feature
1 parent 41a88ea commit d13d3b4

File tree

1 file changed

+150
-4
lines changed

1 file changed

+150
-4
lines changed

server/routes/pipelineCommit.js

Lines changed: 150 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -121,14 +121,12 @@ router.get('/pipeline_history', requireSession, async (req, res) => {
121121
if (!repoFullName) {
122122
return res
123123
.status(400)
124-
.json({ error: 'repoFUllName query param is required' });
124+
.json({ error: 'repoFullName query param is required' });
125125
}
126126

127127
const userId = req.user?.user_id;
128128
if (!userId) {
129-
return res
130-
.status(400)
131-
.json({ error: 'userId session missing or invalid' });
129+
return res.status(401).json({ error: 'User session missing or invalid' });
132130
}
133131

134132
const branchName = branch || 'main';
@@ -170,4 +168,152 @@ router.get('/pipeline_history', requireSession, async (req, res) => {
170168
}
171169
});
172170

171+
/**
172+
* POST /mcp/v1/pipeline_rollback
173+
* Body:
174+
* { "versionId": "<pipeline_versions.id>" }
175+
*
176+
* Restores an older YAML version from pipeline_versions by:
177+
* - fetching the yaml for that version
178+
* - re-committing it to GitHub at workflow_path on branch
179+
* - logging a deployment_logs row with action='pipeline_rollback'
180+
* - saving a new pipeline_versions entry with source='pipeline_rollback'
181+
*/
182+
183+
router.post('/pipeline_rollback', requireSession, async (req, res) => {
184+
try {
185+
const { versionId } = req.body || {};
186+
if (!versionId) {
187+
return res
188+
.status(400)
189+
.json({ error: 'Missing versionId from request body' });
190+
}
191+
192+
const userId = req.user?.user_id;
193+
if (!userId) {
194+
return res.status(401).json({ error: 'User session missing or invalid' });
195+
}
196+
197+
// Look up the pipeline version we want to restore
198+
199+
const versionResult = await query(
200+
`
201+
select
202+
id,
203+
user_id,
204+
repo_full_name,
205+
branch,
206+
workflow_path,
207+
yaml,
208+
yaml_hash,
209+
source,
210+
created_at
211+
from pipeline_versions
212+
where id = $1
213+
limit 1;
214+
`,
215+
[versionId]
216+
);
217+
218+
if (!versionResult.rowCount || !versionResult.rows.length) {
219+
return res
220+
.status(404)
221+
.json({ error: 'Pipeline version not found for give versionId' });
222+
}
223+
224+
const version = versionResult.rows[0];
225+
const {
226+
repo_full_name: repoFullName,
227+
branch,
228+
workflow_path: workflowPath,
229+
yaml,
230+
} = version;
231+
232+
// Get github token for this user
233+
const token = await getGithubAccessTokenForUser(userId);
234+
if (!token) {
235+
return res
236+
.status(401)
237+
.json({ error: 'Missing GitHub token for this user' });
238+
}
239+
240+
const [owner, repo] = (repoFullName || '').split('/');
241+
if (!owner || !repo) {
242+
return res
243+
.status(400)
244+
.json({ error: `Invalid repo_full_name on version ${versionId}` });
245+
}
246+
247+
//Re-commit the yaml file to GitHub (overwrite current workflow)
248+
const githubResult = await upsertWorkflowFile({
249+
token,
250+
owner,
251+
repo,
252+
path: workflowPath,
253+
content: yaml,
254+
branch,
255+
message: `Rollback pipeline to version ${versionId}`,
256+
});
257+
258+
// Log into deployment_log as a pipeline_rollback
259+
const deploymentResult = await query(
260+
`
261+
INSERT INTO deployment_logs
262+
(user_id, provider, repo_full_name, environment, branch, action,
263+
status, started_at, summary, metadata)
264+
VALUES ($1, $2, $3, $4, $5, $6,
265+
'success', NOW(), $7, $8::jsonb)
266+
returning *;
267+
`,
268+
[
269+
userId,
270+
'github_actions',
271+
repoFullName,
272+
'global',
273+
branch,
274+
'pipeline_rollback',
275+
`Rolled back pipeline to version ${versionId}`,
276+
JSON.stringify({
277+
workflow_path: workflowPath,
278+
branch,
279+
version_id: versionId,
280+
commit_sha: githubResult?.commit?.sha || null,
281+
commit_url: githubResult?.commit?.html_url || null,
282+
source: 'pipeline_rollback',
283+
}),
284+
]
285+
);
286+
287+
const deployment = deploymentResult.rows[0];
288+
289+
// Save a new pipelone_versions entry representing this rollback operation
290+
await savePipelineVersion({
291+
userId,
292+
repoFullName,
293+
branch,
294+
workflowPath,
295+
yaml,
296+
source: 'pipeline_rollback',
297+
});
298+
299+
return res.status(201).json({
300+
ok: true,
301+
message: 'Pipeline rolled back successfully',
302+
data: {
303+
github: githubResult,
304+
deployment,
305+
},
306+
});
307+
} catch (err) {
308+
console.error('[pipeline_rollback] error:', err);
309+
const status = err.status || 500;
310+
return res
311+
.status(status)
312+
.json({
313+
error: err.message || 'Failed to rollback pipeline',
314+
details: err.details || undefined,
315+
});
316+
}
317+
});
318+
173319
export default router;

0 commit comments

Comments
 (0)