diff --git a/Sources/AppStoreConnectCLI/Commands/TestFlight/BetaGroups/Sync/PullBetaGroupsCommand.swift b/Sources/AppStoreConnectCLI/Commands/TestFlight/BetaGroups/Sync/PullBetaGroupsCommand.swift index af817f44..b453f257 100644 --- a/Sources/AppStoreConnectCLI/Commands/TestFlight/BetaGroups/Sync/PullBetaGroupsCommand.swift +++ b/Sources/AppStoreConnectCLI/Commands/TestFlight/BetaGroups/Sync/PullBetaGroupsCommand.swift @@ -1,54 +1,29 @@ // Copyright 2020 Itty Bitty Apps Pty Ltd import ArgumentParser -import Foundation -import Files -import Yams -import CodableCSV struct PullBetaGroupsCommand: CommonParsableCommand { static var configuration = CommandConfiguration( commandName: "pull", - abstract: "Load or update local beta group config files from server." + abstract: "Pull down server beta groups, refresh local beta group config files" ) @OptionGroup() var common: CommonOptions - @Option(help: "Path to the Folder containing the information about beta groups. (default: ./config/betagroups)") - var outputPath: String? + @Option( + default: "./config/betagroups", + help: "Path to the Folder containing the information about beta groups. (default: './config/betagroups')" + ) var outputPath: String func run() throws { let service = try makeService() - let betaGroups: [(BetaGroup, [BetaTester])] = try service.pullBetaGroups() + let betaGroupWithTesters = try service.pullBetaGroups() - let folder = outputPath != nil - ? try Folder(path: outputPath!) - : try Folder(path: "./config").createSubfolder(named: "betagroups") - - try betaGroups.forEach { (group: BetaGroup, testers: [BetaTester]) in - - // desired output: app-name_group-name - let groupFileName = "\(group.app.name ?? "")_\(group.groupName ?? "grouo-name")" - .components(separatedBy: .whitespacesAndNewlines) - .joined() - .snakeCased() ?? "file_name" - - // desired output: app-name_group-name_beta-testers.csv - let testersFile = try folder - .createFile(named: "\(groupFileName)_beta-testers.csv") - - try testersFile.write(testers.renderAsCSV()) - - var group = group - group.testers = testersFile.path - - let groupFile = try folder.createFile(named: "\(groupFileName).yml") - - try groupFile.write(try YAMLEncoder().encode(group)) - } + try BetaGroupFolderManager(path: outputPath) + .save(groupsWithTesters: betaGroupWithTesters) } } diff --git a/Sources/AppStoreConnectCLI/Commands/TestFlight/BetaGroups/Sync/PushBetaGroupsCommand.swift b/Sources/AppStoreConnectCLI/Commands/TestFlight/BetaGroups/Sync/PushBetaGroupsCommand.swift index 690f827a..7079ca14 100644 --- a/Sources/AppStoreConnectCLI/Commands/TestFlight/BetaGroups/Sync/PushBetaGroupsCommand.swift +++ b/Sources/AppStoreConnectCLI/Commands/TestFlight/BetaGroups/Sync/PushBetaGroupsCommand.swift @@ -1,68 +1,84 @@ // Copyright 2020 Itty Bitty Apps Pty Ltd import ArgumentParser -import Foundation -import Files struct PushBetaGroupsCommand: CommonParsableCommand { static var configuration = CommandConfiguration( commandName: "push", - abstract: "TODO." + abstract: "Push local beta group config files to server, update server beta groups" ) @OptionGroup() var common: CommonOptions - @Flag(help: "TODO") + @Option( + default: "./config/betagroups", + help: "Path to the Folder containing the information about beta groups. (default: './config/betagroups')" + ) var inputPath: String + + @Flag(help: "Perform a dry run.") var dryRun: Bool func run() throws { let service = try makeService() + let folderManager = BetaGroupFolderManager(path: inputPath) let serverGroups = Set(try service.pullBetaGroups().map{ $0.betaGroup }) + let localGroups = Set(try folderManager.read()) + + let strategies = compareGroups( + localGroups: localGroups, + serverGroups: serverGroups + ) + + let renderer = Renderers.SyncResultRenderer() + + if dryRun { + renderer.render(strategies, isDryRun: true) + } else { + try strategies.forEach { (strategy: SyncStrategy) in + switch strategy { + case .create(let group): + _ = try service.createBetaGroup( + appBundleId: group.app.bundleId!, + groupName: group.groupName!, + publicLinkEnabled: group.publicLinkEnabled ?? false, + publicLinkLimit: group.publicLinkLimit + ) + case .delete(let group): + try service.deleteBetaGroup(with: group.id!) + case .update(let group): + try service.updateBetaGroup(betaGroup: group) + } + + renderer.render(strategy, isDryRun: false) + } - var localGroups = Set() - - for file in try Folder(path: "./config/betagroups").files { - if file.extension == "yml" { - let group = Readers - .FileReader(format: .yaml) - .read(filePath: file.path) + let betaGroupWithTesters = try service.pullBetaGroups() - localGroups.insert(group) - } + try folderManager.save(groupsWithTesters: betaGroupWithTesters) } + } + + func compareGroups(localGroups: Set, serverGroups: Set) -> [SyncStrategy] { + var strategies: [SyncStrategy] = [] let groupToCreate = localGroups.subtracting(serverGroups) let groupToDelete = serverGroups.subtracting(localGroups) - guard !dryRun else { - groupToCreate.forEach { - print("+\($0.groupName!)") + groupToDelete.forEach { group in + if !localGroups.contains(where: { group.id == $0.id }) { + strategies.append(.delete(group)) } - - groupToDelete.forEach { - print("-\($0.groupName!)") - } - return } - try groupToDelete.forEach { - try service.deleteBetaGroup(with: $0.id!) - print("➖ \($0.groupName!)") + groupToCreate.forEach { group in + serverGroups.contains(where: { group.id == $0.id }) + ? strategies.append(.update(group)) + : strategies.append(.create(group)) } - try groupToCreate.forEach { - _ = try service.createBetaGroup( - appBundleId: $0.app.bundleId!, - groupName: $0.groupName ?? "group name", - publicLinkEnabled: $0.publicLinkEnabled ?? false, - publicLinkLimit: $0.publicLinkLimit - ) - - print("➕ \($0.groupName!)") - } + return strategies } - }