Skip to content
53 changes: 49 additions & 4 deletions Package.resolved

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

16 changes: 13 additions & 3 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import PackageDescription
let package = Package(
name: "appstoreconnect-cli",
platforms: [
.macOS(.v10_15)
.macOS(.v12)
],
products: [
.executable(
Expand Down Expand Up @@ -38,7 +38,15 @@ let package = Package(
.package(
url: "https://github.com/dehesa/CodableCSV.git",
from: "0.5.5"
)
),
.package(
url: "https://github.com/MortenGregersen/Bagbutik.git",
from: "2.0.0"
),
.package(
url: "https://github.com/JohnSundell/CollectionConcurrencyKit.git",
from: "0.2.0"
),
],
targets: [
// Targets are the basic building blocks of a package. A target can define a module or a test suite.
Expand All @@ -59,10 +67,12 @@ let package = Package(
.target(name: "Model"),
.target(name: "FileSystem"),
.product(name: "AppStoreConnect-Swift-SDK", package: "AppStoreConnect-Swift-SDK"),
.product(name: "Bagbutik", package: "Bagbutik"),
.product(name: "Yams", package: "Yams"),
.product(name: "ArgumentParser", package: "swift-argument-parser"),
.product(name: "SwiftyTextTable", package: "SwiftyTextTable"),
.product(name: "CodableCSV", package: "CodableCSV")
.product(name: "CodableCSV", package: "CodableCSV"),
.product(name: "CollectionConcurrencyKit", package: "CollectionConcurrencyKit"),
]
),
.testTarget(
Expand Down
2 changes: 1 addition & 1 deletion Sources/AppStoreConnectCLI/AppStoreConnectCLI.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import ArgumentParser
import Foundation

public struct AppStoreConnectCLI: ParsableCommand {
public struct AppStoreConnectCLI: AsyncParsableCommand {
public static var configuration = CommandConfiguration(
commandName: "asc",
abstract: "A utility for interacting with the AppStore Connect API.",
Expand Down
10 changes: 7 additions & 3 deletions Sources/AppStoreConnectCLI/Arguments/APIKeyID.swift
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,13 @@ struct APIKeyID: EnvironmentLoadableArgument {
}

func load() throws -> String {
try loadPEM()
.components(separatedBy: .newlines)
.filter { $0.hasSuffix("PRIVATE KEY-----") == false }
.joined()
}

func loadPEM() throws -> String {

// TODO: validate the format of the env var content
// TODO: validate format of file is correct (if found)
Expand All @@ -43,8 +50,5 @@ struct APIKeyID: EnvironmentLoadableArgument {
}

return apiKeyFileContent
.components(separatedBy: .newlines)
.filter { $0.hasSuffix("PRIVATE KEY-----") == false }
.joined()
}
}
4 changes: 2 additions & 2 deletions Sources/AppStoreConnectCLI/Arguments/UserInfoArguments.swift
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
// Copyright 2020 Itty Bitty Apps Pty Ltd

import ArgumentParser
import AppStoreConnect_Swift_SDK
import Foundation
import Model

struct UserInfoArguments: ParsableArguments {
@Option(
parsing: .upToNextOption,
help: "Assigned user roles that determine the user's access to sections of App Store Connect and tasks they can perform. \(UserRole.allCases)"
)
var roles: [UserRole] = []
var roles: [Model.UserRole] = []

@Flag(help: "Indicates that a user has access to all apps available to the team.")
var allAppsVisible = false
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import ArgumentParser
import Foundation

struct BundleIdsCommand: ParsableCommand {
struct BundleIdsCommand: AsyncParsableCommand {
static var configuration = CommandConfiguration(
commandName: "bundle-ids",
abstract: "Manage the bundle IDs that uniquely identify your apps.",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Copyright 2020 Itty Bitty Apps Pty Ltd

import AppStoreConnect_Swift_SDK
import ArgumentParser
import Bagbutik
import Combine
import Foundation

Expand All @@ -18,9 +18,17 @@ struct DeleteBundleIdCommand: CommonParsableCommand {
@Argument(help: "The reverse-DNS bundle ID identifier to delete. Must be unique. (eg. com.example.app)")
var identifier: String

func run() throws {
let service = try makeService()
func run() async throws {
let service = try BagbutikService(authOptions: common.authOptions)
let bundleId = try await ReadBundleIdOperation(
service: service,
options: .init(bundleId: identifier)
)
.execute()

try service.deleteBundleId(bundleId: identifier)
try await DeleteBundleIdOperation(
service: service,
options: .init(resourceId: bundleId.id))
.execute()
}
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
// Copyright 2020 Itty Bitty Apps Pty Ltd

import AppStoreConnect_Swift_SDK
import ArgumentParser
import Model

struct ListBundleIdsCommand: CommonParsableCommand {
typealias Platform = ListBundleIdsOperation.Options.Platform

public static var configuration = CommandConfiguration(
commandName: "list",
abstract: "Find and list bundle IDs that are registered to your team."
Expand All @@ -26,24 +28,27 @@ struct ListBundleIdsCommand: CommonParsableCommand {

@Option(
parsing: .upToNextOption,
help: "Filter the results by platform (\(Platform.allCases.description))."
help: ArgumentHelp("Filter the results by platform. One of \(Platform.allValueStrings.formatted(.list(type: .or)))."),
completion: .list(Platform.allValueStrings)
)
var filterPlatform: [String] = []
var filterPlatform: [Platform] = []

@Option(parsing: .upToNextOption, help: "Filter the results by seed ID")
var filterSeedId: [String] = []

func run() throws {
let service = try makeService()

let bundleIds = try service.listBundleIds(
identifiers: filterIdentifier,
names: filterName,
platforms: filterPlatform,
seedIds: filterSeedId,
limit: limit
func run() async throws {
try await ListBundleIdsOperation(
service: .init(authOptions: common.authOptions),
options: .init(
identifiers: filterIdentifier,
names: filterName,
platforms: filterPlatform,
seedIds: filterSeedId,
limit: limit
)
)

bundleIds.render(options: common.outputOptions)
.execute()
.map { Model.BundleId($0) }
.render(options: common.outputOptions)
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Copyright 2020 Itty Bitty Apps Pty Ltd

import AppStoreConnect_Swift_SDK
import ArgumentParser
import Bagbutik
import Combine
import Foundation
import struct Model.BundleId
Expand All @@ -22,12 +22,22 @@ struct ModifyBundleIdCommand: CommonParsableCommand {
@Argument(help: "The new name for the bundle identifier.")
var name: String

func run() throws {
let service = try makeService()

let bundleId = try service
.modifyBundleIdInformation(bundleId: identifier, name: name)

bundleId.render(options: common.outputOptions)
func run() async throws {
let service = try BagbutikService(authOptions: common.authOptions)
let bundleId = try await ReadBundleIdOperation(
service: service,
options: .init(bundleId: identifier)
)
.execute()

let result = Model.BundleId(
try await ModifyBundleIdOperation(
service: service,
options: .init(resourceId: bundleId.id, name: name)
)
.execute()
)

result.render(options: common.outputOptions)
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Copyright 2020 Itty Bitty Apps Pty Ltd

import AppStoreConnect_Swift_SDK
import ArgumentParser
import Bagbutik
import Combine
import Foundation
import struct Model.BundleId
Expand All @@ -18,11 +18,15 @@ struct ReadBundleIdCommand: CommonParsableCommand {
@Argument(help: "The reverse-DNS bundle ID identifier to read. Must be unique. (eg. com.example.app)")
var identifier: String

func run() throws {
let service = try makeService()

let bundleId = try service.readBundleIdInformation(bundleId: identifier)

bundleId.render(options: common.outputOptions)
func run() async throws {
let result = Model.BundleId(
try await ReadBundleIdOperation(
service: .init(authOptions: common.authOptions),
options: .init(bundleId: identifier)
)
.execute()
)

result.render(options: common.outputOptions)
}
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
// Copyright 2020 Itty Bitty Apps Pty Ltd

import AppStoreConnect_Swift_SDK
import Bagbutik
import ArgumentParser
import Foundation
import struct Model.BundleId

struct RegisterBundleIdCommand: CommonParsableCommand {

typealias Platform = Bagbutik.BundleIdPlatform

public static var configuration = CommandConfiguration(
commandName: "register",
abstract: "Register a new bundle ID for app development."
Expand All @@ -20,18 +23,22 @@ struct RegisterBundleIdCommand: CommonParsableCommand {
@Argument(help: "The new name for the bundle identifier.")
var name: String

@Option(help: "The platform of the bundle identifier \(BundleIdPlatform.allCases).")
var platform: BundleIdPlatform = .universal

func run() throws {
let service = try makeService()

let request = APIEndpoint.registerNewBundleId(id: identifier, name: name, platform: platform)

let bundleId = try service.request(request)
.map(BundleId.init)
.await()

bundleId.render(options: common.outputOptions)
@Option(
help: "The platform of the bundle identifier. One of \(Platform.allValueStrings.formatted(.list(type: .or))).",
completion: .list(Platform.allValueStrings)
)
var platform: Platform = .universal

func run() async throws {

let result = Model.BundleId(
try await RegisterBundleIdOperation(
service: .init(authOptions: common.authOptions),
options: .init(bundleId: identifier, name: name, platform: platform)
)
.execute()
)

result.render(options: common.outputOptions)
}
}
Loading