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