@@ -3,6 +3,8 @@ package validator
33import (
44 "fmt"
55 "mona-actions/gh-migration-validator/internal/api"
6+ "sync"
7+ "time"
68
79 "github.com/pterm/pterm"
810 "github.com/spf13/viper"
@@ -48,169 +50,195 @@ func New(githubAPI *api.GitHubAPI) *MigrationValidator {
4850// ValidateMigration performs the migration validation logic and returns results
4951func (mv * MigrationValidator ) ValidateMigration (sourceOwner , sourceRepo , targetOwner , targetRepo string ) ([]ValidationResult , error ) {
5052 fmt .Println ("Starting migration validation..." )
53+ fmt .Printf ("Source: %s/%s | Target: %s/%s\n " , sourceOwner , sourceRepo , targetOwner , targetRepo )
5154
52- // Retrieve source repository data
53- if err := mv .RetrieveSource (sourceOwner , sourceRepo ); err != nil {
54- return nil , fmt .Errorf ("failed to retrieve source data: %w" , err )
55- }
55+ // Create a multi printer. This allows multiple spinners to print simultaneously.
56+ multi := pterm .DefaultMultiPrinter
57+
58+ // Create spinners for source and target with separate writers from the multi printer
59+ sourceSpinner , _ := pterm .DefaultSpinner .WithWriter (multi .NewWriter ()).Start (fmt .Sprintf ("Preparing to retrieve data from %s/%s..." , sourceOwner , sourceRepo ))
60+ targetSpinner , _ := pterm .DefaultSpinner .WithWriter (multi .NewWriter ()).Start (fmt .Sprintf ("Preparing to retrieve data from %s/%s..." , targetOwner , targetRepo ))
61+
62+ // Start the multi printer
63+ multi .Start ()
64+
65+ // Use WaitGroup to wait for both goroutines to complete
66+ var wg sync.WaitGroup
67+ var sourceErr , targetErr error
68+
69+ // Channel to synchronize goroutines
70+ wg .Add (2 )
71+
72+ // Retrieve source repository data in a goroutine
73+ go func () {
74+ defer wg .Done ()
75+ sourceErr = mv .retrieveSource (sourceOwner , sourceRepo , sourceSpinner )
76+ }()
5677
57- // Retrieve target repository data
58- if err := mv .RetrieveTarget (targetOwner , targetRepo ); err != nil {
59- return nil , fmt .Errorf ("failed to retrieve target data: %w" , err )
78+ // Retrieve target repository data in a goroutine
79+ go func () {
80+ defer wg .Done ()
81+ targetErr = mv .retrieveTarget (targetOwner , targetRepo , targetSpinner )
82+ }()
83+
84+ // Wait for both goroutines to complete
85+ wg .Wait ()
86+
87+ // Stop the multi printer
88+ multi .Stop ()
89+
90+ // Check for errors from both operations
91+ if sourceErr != nil {
92+ return nil , fmt .Errorf ("failed to retrieve source data: %w" , sourceErr )
93+ }
94+ if targetErr != nil {
95+ return nil , fmt .Errorf ("failed to retrieve target data: %w" , targetErr )
6096 }
6197
6298 // Compare and validate the data
6399 fmt .Println ("\n Validating migration data..." )
64- results := mv .ValidateRepositoryData ()
100+ results := mv .validateRepositoryData ()
65101
66102 fmt .Println ("Migration validation completed!" )
67103 return results , nil
68104}
69105
70- // RetrieveSource retrieves all repository data from the source repository
71- func (mv * MigrationValidator ) RetrieveSource (owner , name string ) error {
72- fmt . Printf ( "Retrieving data from source repository: %s/%s \n " , owner , name )
106+ // retrieveSource retrieves all repository data from the source repository
107+ func (mv * MigrationValidator ) retrieveSource (owner , name string , spinner * pterm. SpinnerPrinter ) error {
108+ startTime := time . Now ( )
73109
74110 mv .SourceData .Owner = owner
75111 mv .SourceData .Name = name
76112
77113 // Get issue count
78- spinner , _ := pterm . DefaultSpinner . Start ("Fetching issues..." )
114+ spinner . UpdateText ( fmt . Sprintf ("Fetching issues from %s/%s ..." , owner , name ) )
79115 issues , err := mv .api .GetIssueCount (api .SourceClient , owner , name )
80116 if err != nil {
81- spinner .Fail ("Failed to fetch issues" )
117+ spinner .Fail (fmt . Sprintf ( "Failed to fetch issues from %s/%s" , owner , name ) )
82118 return fmt .Errorf ("failed to get source issue count: %w" , err )
83119 }
84120 mv .SourceData .Issues = issues
85- spinner .Success ("Issues fetched successfully" )
86121
87122 // Get PR counts
88- spinner , _ = pterm . DefaultSpinner . Start ("Fetching pull requests..." )
123+ spinner . UpdateText ( fmt . Sprintf ("Fetching pull requests from %s/%s ..." , owner , name ) )
89124 prCounts , err := mv .api .GetPRCounts (api .SourceClient , owner , name )
90125 if err != nil {
91- spinner .Fail ("Failed to fetch pull requests" )
126+ spinner .Fail (fmt . Sprintf ( "Failed to fetch pull requests from %s/%s" , owner , name ) )
92127 return fmt .Errorf ("failed to get source PR counts: %w" , err )
93128 }
94129 mv .SourceData .PRs = prCounts
95- spinner .Success ("Pull requests fetched successfully" )
96130
97131 // Get tag count
98- spinner , _ = pterm . DefaultSpinner . Start ("Fetching tags..." )
132+ spinner . UpdateText ( fmt . Sprintf ("Fetching tags from %s/%s ..." , owner , name ) )
99133 tags , err := mv .api .GetTagCount (api .SourceClient , owner , name )
100134 if err != nil {
101- spinner .Fail ("Failed to fetch tags" )
135+ spinner .Fail (fmt . Sprintf ( "Failed to fetch tags from %s/%s" , owner , name ) )
102136 return fmt .Errorf ("failed to get source tag count: %w" , err )
103137 }
104138 mv .SourceData .Tags = tags
105- spinner .Success ("Tags fetched successfully" )
106139
107140 // Get release count
108- spinner , _ = pterm . DefaultSpinner . Start ("Fetching releases..." )
141+ spinner . UpdateText ( fmt . Sprintf ("Fetching releases from %s/%s ..." , owner , name ) )
109142 releases , err := mv .api .GetReleaseCount (api .SourceClient , owner , name )
110143 if err != nil {
111- spinner .Fail ("Failed to fetch releases" )
144+ spinner .Fail (fmt . Sprintf ( "Failed to fetch releases from %s/%s" , owner , name ) )
112145 return fmt .Errorf ("failed to get source release count: %w" , err )
113146 }
114147 mv .SourceData .Releases = releases
115- spinner .Success ("Releases fetched successfully" )
116148
117149 // Get commit count
118- spinner , _ = pterm . DefaultSpinner . Start ("Fetching commit count..." )
150+ spinner . UpdateText ( fmt . Sprintf ("Fetching commit count from %s/%s ..." , owner , name ) )
119151 commitCount , err := mv .api .GetCommitCount (api .SourceClient , owner , name )
120152 if err != nil {
121- spinner .Fail ("Failed to fetch commit count" )
153+ spinner .Fail (fmt . Sprintf ( "Failed to fetch commit count from %s/%s" , owner , name ) )
122154 return fmt .Errorf ("failed to get source commit count: %w" , err )
123155 }
124156 mv .SourceData .CommitCount = commitCount
125- spinner .Success ("Commit count fetched successfully" )
126157
127158 // Get latest commit hash
128- spinner , _ = pterm . DefaultSpinner . Start ("Fetching latest commit hash..." )
159+ spinner . UpdateText ( fmt . Sprintf ("Fetching latest commit hash from %s/%s ..." , owner , name ) )
129160 latestCommitSHA , err := mv .api .GetLatestCommitHash (api .SourceClient , owner , name )
130161 if err != nil {
131- spinner .Fail ("Failed to fetch latest commit hash" )
162+ spinner .Fail (fmt . Sprintf ( "Failed to fetch latest commit hash from %s/%s" , owner , name ) )
132163 return fmt .Errorf ("failed to get source latest commit hash: %w" , err )
133164 }
134165 mv .SourceData .LatestCommitSHA = latestCommitSHA
135- spinner .Success ("Latest commit hash fetched successfully" )
136166
137- fmt .Printf ("Source data retrieved successfully!\n " )
167+ duration := time .Since (startTime )
168+ spinner .Success (fmt .Sprintf ("%s/%s retrieved successfully (%v)" , owner , name , duration ))
169+
138170 return nil
139171}
140172
141- // RetrieveTarget retrieves all repository data from the target repository
142- func (mv * MigrationValidator ) RetrieveTarget (owner , name string ) error {
143- fmt . Printf ( "Retrieving data from target repository: %s/%s \n " , owner , name )
173+ // retrieveTarget retrieves all repository data from the target repository
174+ func (mv * MigrationValidator ) retrieveTarget (owner , name string , spinner * pterm. SpinnerPrinter ) error {
175+ startTime := time . Now ( )
144176
145177 mv .TargetData .Owner = owner
146178 mv .TargetData .Name = name
147179
148180 // Get issue count
149- spinner , _ := pterm . DefaultSpinner . Start ("Fetching issues..." )
181+ spinner . UpdateText ( fmt . Sprintf ("Fetching issues from %s/%s ..." , owner , name ) )
150182 issues , err := mv .api .GetIssueCount (api .TargetClient , owner , name )
151183 if err != nil {
152- spinner .Fail ("Failed to fetch issues" )
184+ spinner .Fail (fmt . Sprintf ( "Failed to fetch issues from %s/%s" , owner , name ) )
153185 return fmt .Errorf ("failed to get target issue count: %w" , err )
154186 }
155187 mv .TargetData .Issues = issues
156- spinner .Success ("Issues fetched successfully" )
157188
158189 // Get PR counts
159- spinner , _ = pterm . DefaultSpinner . Start ("Fetching pull requests..." )
190+ spinner . UpdateText ( fmt . Sprintf ("Fetching pull requests from %s/%s ..." , owner , name ) )
160191 prCounts , err := mv .api .GetPRCounts (api .TargetClient , owner , name )
161192 if err != nil {
162- spinner .Fail ("Failed to fetch pull requests" )
193+ spinner .Fail (fmt . Sprintf ( "Failed to fetch pull requests from %s/%s" , owner , name ) )
163194 return fmt .Errorf ("failed to get target PR counts: %w" , err )
164195 }
165196 mv .TargetData .PRs = prCounts
166- spinner .Success ("Pull requests fetched successfully" )
167197
168198 // Get tag count
169- spinner , _ = pterm . DefaultSpinner . Start ("Fetching tags..." )
199+ spinner . UpdateText ( fmt . Sprintf ("Fetching tags from %s/%s ..." , owner , name ) )
170200 tags , err := mv .api .GetTagCount (api .TargetClient , owner , name )
171201 if err != nil {
172- spinner .Fail ("Failed to fetch tags" )
202+ spinner .Fail (fmt . Sprintf ( "Failed to fetch tags from %s/%s" , owner , name ) )
173203 return fmt .Errorf ("failed to get target tag count: %w" , err )
174204 }
175205 mv .TargetData .Tags = tags
176- spinner .Success ("Tags fetched successfully" )
177206
178207 // Get release count
179- spinner , _ = pterm . DefaultSpinner . Start ("Fetching releases..." )
208+ spinner . UpdateText ( fmt . Sprintf ("Fetching releases from %s/%s ..." , owner , name ) )
180209 releases , err := mv .api .GetReleaseCount (api .TargetClient , owner , name )
181210 if err != nil {
182- spinner .Fail ("Failed to fetch releases" )
211+ spinner .Fail (fmt . Sprintf ( "Failed to fetch releases from %s/%s" , owner , name ) )
183212 return fmt .Errorf ("failed to get target release count: %w" , err )
184213 }
185214 mv .TargetData .Releases = releases
186- spinner .Success ("Releases fetched successfully" )
187215
188216 // Get commit count
189- spinner , _ = pterm . DefaultSpinner . Start ("Fetching commit count..." )
217+ spinner . UpdateText ( fmt . Sprintf ("Fetching commit count from %s/%s ..." , owner , name ) )
190218 commitCount , err := mv .api .GetCommitCount (api .TargetClient , owner , name )
191219 if err != nil {
192- spinner .Fail ("Failed to fetch commit count" )
220+ spinner .Fail (fmt . Sprintf ( "Failed to fetch commit count from %s/%s" , owner , name ) )
193221 return fmt .Errorf ("failed to get target commit count: %w" , err )
194222 }
195223 mv .TargetData .CommitCount = commitCount
196- spinner .Success ("Commit count fetched successfully" )
197224
198225 // Get latest commit hash
199- spinner , _ = pterm . DefaultSpinner . Start ("Fetching latest commit hash..." )
226+ spinner . UpdateText ( fmt . Sprintf ("Fetching latest commit hash from %s/%s ..." , owner , name ) )
200227 latestCommitSHA , err := mv .api .GetLatestCommitHash (api .TargetClient , owner , name )
201228 if err != nil {
202- spinner .Fail ("Failed to fetch latest commit hash" )
229+ spinner .Fail (fmt . Sprintf ( "Failed to fetch latest commit hash from %s/%s" , owner , name ) )
203230 return fmt .Errorf ("failed to get target latest commit hash: %w" , err )
204231 }
205232 mv .TargetData .LatestCommitSHA = latestCommitSHA
206- spinner .Success ("Latest commit hash fetched successfully" )
207233
208- fmt .Printf ("Target data retrieved successfully!\n " )
234+ duration := time .Since (startTime )
235+ spinner .Success (fmt .Sprintf ("%s/%s retrieved successfully (%v)" , owner , name , duration ))
236+
209237 return nil
210238}
211239
212- // ValidateRepositoryData compares source and target repository data and returns validation results
213- func (mv * MigrationValidator ) ValidateRepositoryData () []ValidationResult {
240+ // validateRepositoryData compares source and target repository data and returns validation results
241+ func (mv * MigrationValidator ) validateRepositoryData () []ValidationResult {
214242 fmt .Println ("Comparing repository data..." )
215243
216244 var results []ValidationResult
@@ -437,12 +465,12 @@ func (mv *MigrationValidator) PrintValidationResults(results []ValidationResult)
437465
438466 fmt .Println () // Add spacing
439467 if viper .GetBool ("MARKDOWN_TABLE" ) {
440- mv .PrintMarkdownTable (results )
468+ mv .printMarkdownTable (results )
441469 }
442470}
443471
444- // PrintMarkdownTable prints a markdown-formatted table for easy copy/paste
445- func (mv * MigrationValidator ) PrintMarkdownTable (results []ValidationResult ) {
472+ // printMarkdownTable prints a markdown-formatted table for easy copy/paste
473+ func (mv * MigrationValidator ) printMarkdownTable (results []ValidationResult ) {
446474 pterm .DefaultSection .Println ("📋 Markdown Table (Copy-Paste Ready)" )
447475
448476 fmt .Println ("```markdown" )
0 commit comments