11import { Octokit } from 'octokit'
22import dotenv from 'dotenv'
33import PLazy from 'p-lazy'
4+ import fs from 'fs/promises'
5+ import path from 'path'
46dotenv . config ( )
57
68const octokit = new Octokit ( { auth : process . env . GITHUB_TOKEN } )
@@ -10,20 +12,30 @@ const {
1012} = await octokit . rest . users . getAuthenticated ( )
1113console . log ( 'Hello, %s' , login )
1214
13- const targetContentBase64 = PLazy . from ( async ( ) => {
14- const checkManifestExists = await octokit . rest . repos . getContent ( {
15- owner : 'bitfocus' ,
16- repo : 'companion-module-template-ts' ,
17- path : '.github/workflows/companion-module-checks.yaml' ,
18- } )
19- if ( ! checkManifestExists || checkManifestExists . status !== 200 ) {
20- throw new Error ( 'Failed to get template workflow' )
21- }
15+ function base64Encode ( str ) {
16+ return Buffer . from ( str , 'utf-8' ) . toString ( 'base64' )
17+ }
18+
19+ const targetWorkflowContentBase64 = PLazy . from ( async ( ) => {
20+ const utf8Content = await fs . readFile (
21+ path . join ( import . meta. dirname , './assets/companion-module-checks.yaml' ) ,
22+ 'utf-8'
23+ )
24+ return base64Encode ( utf8Content )
25+ } )
2226
23- const data = checkManifestExists . data . content
24- if ( ! data ) throw new Error ( 'Failed to get template workflow' )
27+ const targetIssueTemplateContentBase64 = PLazy . from ( async ( ) => {
28+ const [ bugFile , configFile , featureFile ] = await Promise . all ( [
29+ fs . readFile ( path . join ( import . meta. dirname , './assets/ISSUE_TEMPLATE/bug_report.yml' ) , 'utf-8' ) ,
30+ fs . readFile ( path . join ( import . meta. dirname , './assets/ISSUE_TEMPLATE/config.yml' ) , 'utf-8' ) ,
31+ fs . readFile ( path . join ( import . meta. dirname , './assets/ISSUE_TEMPLATE/feature_request.yml' ) , 'utf-8' ) ,
32+ ] )
2533
26- return data
34+ return {
35+ bugFile : base64Encode ( bugFile ) ,
36+ configFile : base64Encode ( configFile ) ,
37+ featureFile : base64Encode ( featureFile ) ,
38+ }
2739} )
2840
2941const errors = [ ]
@@ -34,8 +46,10 @@ const allRepos = await octokit.paginate(octokit.rest.repos.listForOrg, {
3446console . log ( 'found %d repos in org' , allRepos . length )
3547
3648for ( const repo of allRepos ) {
49+ if ( repo . archived ) continue
50+
3751 const repoName = repo . name
38- if ( ! repoName . startsWith ( 'companion-module-' ) ) {
52+ if ( ! repoName . startsWith ( 'companion-module-' ) && ! repoName . startsWith ( 'companion-surface-' ) ) {
3953 continue
4054 }
4155
@@ -69,14 +83,120 @@ for (const repo of allRepos) {
6983 owner : 'bitfocus' ,
7084 repo : repoName ,
7185 path : '.github/workflows/companion-module-checks.yaml' ,
72- content : await targetContentBase64 ,
86+ content : await targetWorkflowContentBase64 ,
7387 message : "chore: add 'Companion Module Checks' workflow" ,
7488 } )
7589 }
90+
91+ const issueTemplateSetManual = await octokit . rest . repos
92+ . getContent ( {
93+ owner : 'bitfocus' ,
94+ repo : repoName ,
95+ path : '.github/.companion-manual-issue-templates' ,
96+ } )
97+ . then ( ( ) => true )
98+ . catch ( ( e ) => ( e . status === 404 ? false : Promise . reject ( e ) ) )
99+ if ( issueTemplateSetManual ) {
100+ console . log ( `Skipping ${ repoName } : companion-manual-issue-templates flag set` )
101+ } else {
102+ // Check if the .github/ISSUE_TEMPLATE folder exists
103+ const issueTemplateFolderExists = await octokit . rest . repos
104+ . getContent ( {
105+ owner : 'bitfocus' ,
106+ repo : repoName ,
107+ path : '.github/ISSUE_TEMPLATE' ,
108+ } )
109+ . then ( ( ) => true )
110+ . catch ( ( e ) => ( e . status === 404 ? false : Promise . reject ( e ) ) )
111+ if ( issueTemplateFolderExists ) {
112+ console . log ( `Skipping ${ repoName } : ISSUE_TEMPLATE folder already exists` )
113+
114+ await octokit . rest . repos . createOrUpdateFileContents ( {
115+ owner : 'bitfocus' ,
116+ repo : repoName ,
117+ path : '.github/.companion-manual-issue-templates' ,
118+ content : base64Encode ( '\n' ) ,
119+ message : 'chore: add manual issue templates marker' ,
120+ } )
121+ } else {
122+ console . log ( `Creating ${ repoName } : ISSUE_TEMPLATE folder` )
123+
124+ const files = await targetIssueTemplateContentBase64
125+
126+ await updateMultipleFiles ( repoName , repo . default_branch , {
127+ '.github/ISSUE_TEMPLATE/bug_report.yml' : files . bugFile ,
128+ '.github/ISSUE_TEMPLATE/config.yml' : files . configFile ,
129+ '.github/ISSUE_TEMPLATE/feature_request.yml' : files . featureFile ,
130+ } )
131+ }
132+ }
76133 } catch ( e ) {
77134 console . error ( `Failed ${ repoName } : ${ e ?. message ?? e ?. toString ( ) ?? e } ` )
78135 errors . push ( e )
79136 }
80137}
81138
82139console . log ( 'All errors' , errors )
140+
141+ async function updateMultipleFiles ( repoName , defaultBranch , files ) {
142+ // Get reference to the default branch
143+ const { data : ref } = await octokit . rest . git . getRef ( {
144+ owner : 'bitfocus' ,
145+ repo : repoName ,
146+ ref : `heads/${ defaultBranch } ` ,
147+ } )
148+
149+ const baseSha = ref . object . sha
150+
151+ // Get the base tree
152+ const { data : baseCommit } = await octokit . rest . git . getCommit ( {
153+ owner : 'bitfocus' ,
154+ repo : repoName ,
155+ commit_sha : baseSha ,
156+ } )
157+
158+ // Create blobs for each file
159+ const blobs = await Promise . all (
160+ Object . entries ( files ) . map ( async ( [ path , content ] ) => {
161+ const { data : blob } = await octokit . rest . git . createBlob ( {
162+ owner : 'bitfocus' ,
163+ repo : repoName ,
164+ content,
165+ encoding : 'base64' ,
166+ } )
167+ return { path, sha : blob . sha }
168+ } )
169+ )
170+
171+ // Create a new tree
172+ const { data : newTree } = await octokit . rest . git . createTree ( {
173+ owner : 'bitfocus' ,
174+ repo : repoName ,
175+ base_tree : baseCommit . tree . sha ,
176+ tree : blobs . map ( ( { path, sha } ) => ( {
177+ path,
178+ mode : '100644' ,
179+ type : 'blob' ,
180+ sha,
181+ } ) ) ,
182+ } )
183+
184+ // Create a new commit
185+ const { data : newCommit } = await octokit . rest . git . createCommit ( {
186+ owner : 'bitfocus' ,
187+ repo : repoName ,
188+ message : 'chore: add issue templates' ,
189+ tree : newTree . sha ,
190+ parents : [ baseSha ] ,
191+ } )
192+
193+ // Update the reference
194+ await octokit . rest . git . updateRef ( {
195+ owner : 'bitfocus' ,
196+ repo : repoName ,
197+ ref : `heads/${ defaultBranch } ` ,
198+ sha : newCommit . sha ,
199+ } )
200+
201+ console . log ( `Updated ${ repoName } with ${ Object . keys ( files ) . length } files in a single commit` )
202+ }
0 commit comments