@@ -3,6 +3,7 @@ import * as core from '@actions/core'
33import { graphql } from '@octokit/graphql'
44import { execSync } from 'child_process'
55import { Octokit } from '@octokit/rest'
6+ import * as fs from 'fs'
67
78// Get config
89const GH_USERNAME = core . getInput ( 'GH_USERNAME' )
@@ -66,7 +67,10 @@ async function fetchSponsoredProfiles(): Promise<SponsoredProfile[]> {
6667 }
6768}
6869
69- async function commitIfNotDuplicate ( commitMessage : string ) {
70+ async function commitIfNotDuplicate (
71+ commitMessage : string ,
72+ fileUpdate ?: { path : string ; content : string }
73+ ) : Promise < void > {
7074 const { data : commits } = await octokit . repos . listCommits ( {
7175 owner : GH_USERNAME ,
7276 repo : GH_USERNAME ,
@@ -78,42 +82,97 @@ async function commitIfNotDuplicate(commitMessage: string) {
7882 )
7983
8084 if ( ! duplicateCommit ) {
81- // Commit the changes
85+ if ( fileUpdate ) {
86+ fs . writeFileSync ( fileUpdate . path , fileUpdate . content , 'utf8' )
87+ execSync ( `git add ${ fileUpdate . path } ` )
88+ }
8289 execSync ( `git config --global user.name "${ COMMIT_NAME } "` )
8390 execSync ( `git config --global user.email "${ COMMIT_EMAIL } "` )
8491 execSync ( `git commit --allow-empty -m "${ commitMessage } "` )
8592 execSync ( 'git push' )
8693 } else {
87- core . setFailed ( `Duplicate commit found : ${ commitMessage } `)
94+ core . info ( `Skipping duplicate commit : ${ commitMessage } `)
8895 }
8996}
9097
98+ async function updateReadme ( profiles : SponsoredProfile [ ] ) : Promise < void > {
99+ const allowReadmeUpdate = core . getInput ( 'allow-add-to-readme' ) === 'true'
100+ if ( ! allowReadmeUpdate ) return
101+
102+ if ( ! Array . isArray ( profiles ) ) {
103+ throw new Error ( 'Invalid profiles data' )
104+ }
105+
106+ const readmePath = 'README.md'
107+ const startMarker = '<!-- SPONSORSHIP-DATA:START -->'
108+ const endMarker = '<!-- SPONSORSHIP-DATA:END -->'
109+
110+ let readmeContent = ''
111+ try {
112+ readmeContent = fs . readFileSync ( readmePath , 'utf8' )
113+ } catch ( error ) {
114+ if ( ( error as NodeJS . ErrnoException ) . code === 'ENOENT' ) {
115+ core . warning ( 'README.md not found, creating new file' )
116+ } else {
117+ throw new Error ( `Failed to read README.md: ${ error } ` )
118+ }
119+ }
120+
121+ const sponsorshipData = profiles
122+ . map ( ( p ) => `- @${ p . sponsorLogin } : ${ p . sponsorshipAmount } ${ p . currency } ` )
123+ . join ( '\n' )
124+
125+ const newContent = `${ startMarker } \n${ sponsorshipData } \n${ endMarker } `
126+
127+ if ( readmeContent ) {
128+ const startIndex = readmeContent . indexOf ( startMarker )
129+ const endIndex = readmeContent . indexOf ( endMarker ) + endMarker . length
130+
131+ if ( startIndex === - 1 || endIndex === - 1 ) {
132+ core . info ( 'Markers not found, appending content to README' )
133+ readmeContent = `${ readmeContent } \n\n${ newContent } `
134+ } else if ( endIndex <= startIndex ) {
135+ throw new Error ( 'Invalid marker positions in README.md' )
136+ } else {
137+ readmeContent =
138+ readmeContent . substring ( 0 , startIndex ) +
139+ newContent +
140+ readmeContent . substring ( endIndex )
141+ }
142+ } else {
143+ readmeContent = newContent
144+ }
145+
146+ await commitIfNotDuplicate ( `Update README with sponsorship data` , {
147+ path : readmePath ,
148+ content : readmeContent
149+ } )
150+ }
151+
91152/**
92153 * The main function for the action.
93154 *
94155 * @returns Resolves when the action is complete.
95156 */
157+
96158export async function run ( ) : Promise < void > {
97159 try {
98160 const ms : string = core . getInput ( 'milliseconds' )
161+ const profiles = await fetchSponsoredProfiles ( )
162+ await updateReadme ( profiles )
99163
100- // Debug logs are only output if the `ACTIONS_STEP_DEBUG` secret is true
101164 core . debug ( `Waiting ${ ms } milliseconds ...` )
165+ core . debug ( `number of profiles fetched: ${ profiles . length } ` )
102166
103- // Log the current timestamp, wait, then log the new timestamp
104- fetchSponsoredProfiles ( ) . then ( ( data ) => {
105- core . debug ( `number of profiles fetched: ${ data . length } ` )
106- const currentDate = new Date ( )
107- const month = currentDate . toLocaleString ( 'default' , { month : 'long' } )
108- const year = currentDate . getFullYear ( )
167+ const currentDate = new Date ( )
168+ const month = currentDate . toLocaleString ( 'default' , { month : 'long' } )
169+ const year = currentDate . getFullYear ( )
109170
110- data . forEach ( async ( profile ) => {
111- core . debug ( `Sponsor: ${ profile . sponsorLogin } ` )
112- const commitMessage = `${ profile . sponsorshipAmount } ${ profile . currency } paid to @${ profile . sponsorLogin } for ${ month } ${ year } to support open source.`
113-
114- await commitIfNotDuplicate ( commitMessage )
115- } )
116- } )
171+ for ( const profile of profiles ) {
172+ core . debug ( `Sponsor: ${ profile . sponsorLogin } ` )
173+ const commitMessage = `${ profile . sponsorshipAmount } ${ profile . currency } paid to @${ profile . sponsorLogin } for ${ month } ${ year } to support open source.`
174+ await commitIfNotDuplicate ( commitMessage )
175+ }
117176 } catch ( error ) {
118177 // Fail the workflow run if an error occurs
119178 if ( error instanceof Error ) core . setFailed ( error . message )
0 commit comments