@@ -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+
173319export default router ;
0 commit comments