1+ import { Octokit } from "@octokit/rest" ;
2+ import { execSync } from "child_process" ;
3+
4+ const GITHUB_TOKEN = process . env . GITHUB_TOKEN ;
5+ const REPO_OWNER = process . env . GITHUB_REPOSITORY_OWNER || "owner" ;
6+ const REPO_NAME = process . env . GITHUB_REPOSITORY ?. split ( "/" ) [ 1 ] || "cppdoc" ;
7+
8+ if ( ! GITHUB_TOKEN ) {
9+ console . error ( "Missing GITHUB_TOKEN" ) ;
10+ process . exit ( 1 ) ;
11+ }
12+
13+ const octokit = new Octokit ( { auth : GITHUB_TOKEN } ) ;
14+
15+ async function getAllOpenPRs ( ) {
16+ const prs = [ ] ;
17+ let page = 1 ;
18+ const perPage = 100 ;
19+
20+ while ( true ) {
21+ const { data } = await octokit . pulls . list ( {
22+ owner : REPO_OWNER ,
23+ repo : REPO_NAME ,
24+ state : "open" ,
25+ per_page : perPage ,
26+ page,
27+ } ) ;
28+ if ( data . length === 0 ) break ;
29+ prs . push ( ...data ) ;
30+ if ( data . length < perPage ) break ;
31+ page ++ ;
32+ }
33+
34+ console . log ( `Found ${ prs . length } open PRs` ) ;
35+ return prs ;
36+ }
37+
38+ async function getAllBranches ( ) {
39+ const branches = [ ] ;
40+ let page = 1 ;
41+ const perPage = 100 ;
42+
43+ while ( true ) {
44+ const { data } = await octokit . repos . listBranches ( {
45+ owner : REPO_OWNER ,
46+ repo : REPO_NAME ,
47+ per_page : perPage ,
48+ page,
49+ } ) ;
50+ if ( data . length === 0 ) break ;
51+ branches . push ( ...data ) ;
52+ if ( data . length < perPage ) break ;
53+ page ++ ;
54+ }
55+
56+ console . log ( `Found ${ branches . length } branches` ) ;
57+ return branches ;
58+ }
59+
60+ function filterMigrateBranches ( branches : { name : string } [ ] ) {
61+ return branches . filter ( ( b ) => b . name . startsWith ( "migrate/" ) ) ;
62+ }
63+
64+ async function deleteBranch ( branchName : string ) {
65+ try {
66+ await octokit . git . deleteRef ( {
67+ owner : REPO_OWNER ,
68+ repo : REPO_NAME ,
69+ ref : `heads/${ branchName } ` ,
70+ } ) ;
71+ console . log ( `Deleted remote branch ${ branchName } ` ) ;
72+ } catch ( error ) {
73+ console . error ( `Failed to delete branch ${ branchName } :` , error ) ;
74+ }
75+ }
76+
77+ async function main ( ) {
78+ console . log ( "Starting cleanup of migrate branches without open PRs..." ) ;
79+
80+ const [ prs , branches ] = await Promise . all ( [
81+ getAllOpenPRs ( ) ,
82+ getAllBranches ( ) ,
83+ ] ) ;
84+
85+ const prBranchNames = new Set ( prs . map ( ( pr ) => pr . head . ref ) ) ;
86+ console . log ( "PR branches:" , Array . from ( prBranchNames ) ) ;
87+
88+ const migrateBranches = filterMigrateBranches ( branches ) ;
89+ console . log ( "Migrate branches:" , migrateBranches . map ( b => b . name ) ) ;
90+
91+ const toDelete = migrateBranches . filter ( b => ! prBranchNames . has ( b . name ) ) ;
92+ console . log ( `Found ${ toDelete . length } branches to delete:` ) ;
93+ toDelete . forEach ( b => console . log ( ` - ${ b . name } ` ) ) ;
94+
95+ if ( toDelete . length === 0 ) {
96+ console . log ( "No branches to delete." ) ;
97+ return ;
98+ }
99+
100+ for ( const branch of toDelete ) {
101+ await deleteBranch ( branch . name ) ;
102+ }
103+
104+ console . log ( "Cleanup completed." ) ;
105+ }
106+
107+ main ( ) . catch ( ( err ) => {
108+ console . error ( err ) ;
109+ process . exit ( 1 ) ;
110+ } ) ;
0 commit comments