88use Moox \Monorepo \Contracts \GitHubClientInterface ;
99use Moox \Monorepo \DataTransferObjects \PackageInfo ;
1010use Moox \Monorepo \Services \DevlinkService ;
11+ use function Moox \Prompts \multiselect ;
12+ use function Moox \Prompts \progress ;
13+ use function Moox \Prompts \table ;
1114
1215class CreateMissingRepositoriesCommand extends Command
1316{
1417 protected $ signature = 'monorepo:create-missing
1518 {--public : Only create missing public repositories}
1619 {--private : Only create missing private repositories}
1720 {--force : Skip confirmation prompts}
18- {--interactive : Ask for confirmation before creating each repository}
1921 {--dry-run : Show what would be created without making changes}
2022 {--skip-devlink : Skip updating devlink configuration} ' ;
2123
@@ -75,13 +77,17 @@ public function handle(): int
7577 return 0 ;
7678 }
7779
78- // Ask for confirmation
80+ // Let user select which repositories to create
7981 if (! $ this ->option ('force ' )) {
80- if (! $ this ->confirm ("Create {$ missingPackages ->count ()} missing repositories? " , true )) {
81- $ this ->info ('Operation cancelled. ' );
82+ $ selectedPackages = $ this ->selectPackagesToCreate ($ missingPackages );
83+
84+ if ($ selectedPackages ->isEmpty ()) {
85+ $ this ->info ('No repositories selected. Operation cancelled. ' );
8286
8387 return 0 ;
8488 }
89+
90+ $ missingPackages = $ selectedPackages ;
8591 }
8692
8793 // Create repositories
@@ -163,7 +169,7 @@ private function displayMissingPackages(Collection $missingPackages): void
163169 ];
164170 })->toArray ();
165171
166- $ this -> table (
172+ table (
167173 ['Package Name ' , 'Type ' , 'Stability ' , 'Description ' ],
168174 $ tableData
169175 );
@@ -175,62 +181,62 @@ private function displayMissingPackages(Collection $missingPackages): void
175181 $ this ->line ('' );
176182 }
177183
184+ private function selectPackagesToCreate (Collection $ missingPackages ): Collection
185+ {
186+ // Build choice options with package details and create a mapping
187+ $ choiceToPackage = [];
188+ $ choices = $ missingPackages ->map (function ($ package ) use (&$ choiceToPackage ) {
189+ $ type = $ package ->visibility === 'public ' ? '🔓 ' : '🔒 ' ;
190+ $ description = $ package ->description ? ' - ' . substr ($ package ->description , 0 , 50 ) : '' ;
191+ $ choice = "{$ type } {$ package ->name } ( {$ package ->visibility }) {$ description }" ;
192+
193+ // Store mapping for easy lookup
194+ $ choiceToPackage [$ choice ] = $ package ;
195+
196+ return $ choice ;
197+ })->toArray ();
198+
199+ // Add "Select all" option at the beginning
200+ $ selectAllOption = '✅ Select all ' ;
201+ array_unshift ($ choices , $ selectAllOption );
202+
203+ $ selected = multiselect (
204+ label: 'Which repositories would you like to create? ' ,
205+ options: $ choices ,
206+ default: [],
207+ required: false ,
208+ hint: 'Use SPACE to select, ENTER to confirm '
209+ );
210+
211+ // If "Select all" was chosen, return all packages
212+ if (in_array ($ selectAllOption , $ selected )) {
213+ return $ missingPackages ;
214+ }
215+
216+ // Map selected choices back to packages using the mapping
217+ $ selectedPackages = collect ($ selected )
218+ ->map (function ($ choice ) use ($ choiceToPackage ) {
219+ return $ choiceToPackage [$ choice ] ?? null ;
220+ })
221+ ->filter ();
222+
223+ return $ selectedPackages ;
224+ }
225+
178226 private function createRepositories (Collection $ missingPackages , string $ organization ): int
179227 {
180228 $ this ->info ('🚀 Creating missing repositories... ' );
181229 $ this ->line ('' );
182230
183231 $ created = 0 ;
184232 $ failed = 0 ;
185- $ skipped = 0 ;
186233 $ devlinkUpdated = 0 ;
187234
188- if ($ this ->option ('interactive ' )) {
189- // Interactive mode - ask for each repository
190- foreach ($ missingPackages as $ index => $ package ) {
191- $ this ->line ('Repository ' .($ index + 1 ).'/ ' .$ missingPackages ->count ().": {$ package ->name }" );
192- $ this ->line (" Type: {$ package ->visibility }" );
193- $ this ->line (" Stability: {$ package ->stability }" );
194- $ this ->line (' Description: ' .($ package ->description ?: '— ' ));
195-
196- if ($ this ->confirm ("Create repository for {$ package ->name }? " , true )) {
197- try {
198- $ this ->createSingleRepository ($ package , $ organization );
199- $ created ++;
200- $ this ->info (" ✅ Created: {$ package ->name }" );
201-
202- // Update devlink configuration
203- if (! $ this ->option ('skip-devlink ' )) {
204- try {
205- $ this ->updateDevlinkConfig ($ package );
206- $ devlinkUpdated ++;
207- $ this ->info (" 🔗 Added to devlink config: {$ package ->name }" );
208- } catch (\Exception $ e ) {
209- $ this ->warn (" ⚠️ Failed to update devlink config for {$ package ->name }: {$ e ->getMessage ()}" );
210- }
211- }
212-
213- // Small delay to avoid rate limiting
214- usleep (100000 ); // 0.1 seconds
215- } catch (\Exception $ e ) {
216- $ failed ++;
217- $ this ->error (" ❌ Failed to create {$ package ->name }: {$ e ->getMessage ()}" );
218- }
219- } else {
220- $ skipped ++;
221- $ this ->line (" ⏭️ Skipped: {$ package ->name }" );
222- }
223-
224- $ this ->line ('' );
225- }
226- } else {
227- // Batch mode with progress bar
228- $ progressBar = $ this ->output ->createProgressBar ($ missingPackages ->count ());
229- $ progressBar ->start ();
230-
231- foreach ($ missingPackages as $ package ) {
232- $ progressBar ->advance ();
233-
235+ // Use Prompts progress bar
236+ progress (
237+ label: 'Creating repositories... ' ,
238+ steps: $ missingPackages ,
239+ callback: function ($ package ) use ($ organization , &$ created , &$ failed , &$ devlinkUpdated ) {
234240 try {
235241 $ this ->createSingleRepository ($ package , $ organization );
236242 $ created ++;
@@ -253,11 +259,9 @@ private function createRepositories(Collection $missingPackages, string $organiz
253259 $ this ->line ('' );
254260 $ this ->error ("Failed to create repository for {$ package ->name }: {$ e ->getMessage ()}" );
255261 }
256- }
257-
258- $ progressBar ->finish ();
259- $ this ->line ('' );
260- }
262+ },
263+ hint: 'Creating repositories and updating devlink config '
264+ );
261265
262266 $ this ->line ('' );
263267
@@ -274,18 +278,11 @@ private function createRepositories(Collection $missingPackages, string $organiz
274278 $ this ->warn ("⚠️ Failed to create {$ failed } repositories " );
275279 }
276280
277- if ($ skipped > 0 ) {
278- $ this ->line ("⏭️ Skipped {$ skipped } repositories " );
279- }
280-
281281 $ this ->line ('' );
282282 $ this ->info ('📊 Summary: ' );
283283 $ this ->line ("Total packages processed: {$ missingPackages ->count ()}" );
284284 $ this ->line ("Repositories created: {$ created }" );
285285 $ this ->line ("Devlink config updated: {$ devlinkUpdated }" );
286- if ($ skipped > 0 ) {
287- $ this ->line ("Repositories skipped: {$ skipped }" );
288- }
289286 $ this ->line ("Failed creations: {$ failed }" );
290287
291288 if ($ created > 0 ) {
0 commit comments