Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

update: CLI defaults #2673

Merged
merged 10 commits into from
Nov 17, 2022
2 changes: 1 addition & 1 deletion .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ commands:
name: CocoaPods - Install
- run:
working_directory: Tests/CodegenCLITests/pod-install-test/
command: ./Pods/Apollo/apollo-ios-cli init --schema-name NewTestSchema
command: ./Pods/Apollo/apollo-ios-cli init --schema-name NewTestSchema --module-type other
name: CocoaPods - CLI Test (init)
- run:
working_directory: Tests/CodegenCLITests/pod-install-test/
Expand Down
4 changes: 2 additions & 2 deletions Apollo.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -6627,8 +6627,8 @@
isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/apple/swift-argument-parser.git";
requirement = {
kind = upToNextMinorVersion;
minimumVersion = 1.1.3;
kind = upToNextMajorVersion;
minimumVersion = 1.2.0;
};
};
E6E4209026A7DF4200B82624 /* XCRemoteSwiftPackageReference "InflectorKit" */ = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,8 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/apple/swift-argument-parser.git",
"state" : {
"revision" : "df9ee6676cd5b3bf5b330ec7568a5644f547201b",
"version" : "1.1.3"
"revision" : "fddd1c00396eed152c45a46bea9f47b98e59301d",
"version" : "1.2.0"
}
},
{
Expand Down
4 changes: 2 additions & 2 deletions Package.resolved
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/apple/swift-argument-parser.git",
"state" : {
"revision" : "df9ee6676cd5b3bf5b330ec7568a5644f547201b",
"version" : "1.1.3"
"revision" : "fddd1c00396eed152c45a46bea9f47b98e59301d",
"version" : "1.2.0"
}
},
{
Expand Down
2 changes: 1 addition & 1 deletion Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ let package = Package(
.upToNextMajor(from: "1.0.0")),
.package(
url: "https://github.com/apple/swift-argument-parser.git",
.upToNextMajor(from: "1.1.2")),
.upToNextMajor(from: "1.2.0")),
],
targets: [
.target(
Expand Down
5 changes: 2 additions & 3 deletions Sources/ApolloCodegenLib/ApolloCodegenConfiguration.swift
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ public struct ApolloCodegenConfiguration: Codable, Equatable {

/// Default property values
public struct Default {
public static let operations: OperationsFileOutput = .relative(subpath: nil)
public static let operations: OperationsFileOutput = .inSchemaModule
calvincestari marked this conversation as resolved.
Show resolved Hide resolved
public static let testMocks: TestMockFileOutput = .none
public static let operationIdentifiersPath: String? = nil
}
Expand Down Expand Up @@ -226,8 +226,7 @@ public struct ApolloCodegenConfiguration: Codable, Equatable {
public struct SchemaTypesFileOutput: Codable, Equatable {
/// Local path where the generated schema types files should be stored.
public let path: String
/// Automation to ease the integration of the generated schema types file with compatible
/// dependency managers.
/// How to package the schema types for dependency management.
public let moduleType: ModuleType

/// Designated initializer.
Expand Down
96 changes: 84 additions & 12 deletions Sources/CodegenCLI/Commands/Initialize.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,26 @@ public struct Initialize: ParsableCommand {
name: [.long, .customShort("n")],
help: "Name used to scope the generated schema type files."
)
var schemaName: String = ""
AnthonyMDev marked this conversation as resolved.
Show resolved Hide resolved
var schemaName: String

@Option(
name: [.long, .customShort("m")],
help: """
How to package the schema types for dependency management. Possible types: \
\(ModuleTypeExpressibleByArgument.allValueStrings.joined(separator: ", ")).
AnthonyMDev marked this conversation as resolved.
Show resolved Hide resolved
"""
)
var moduleType: ModuleTypeExpressibleByArgument

@Option(
name: [.long, .customShort("t")],
help: """
Name of the target in which the schema types files will be manually embedded. This is \
required for the \"embeddedInTarget\" module type and will be ignored for all other module \
types.
"""
)
var targetName: String? = nil

@Option(
name: .shortAndLong,
Expand Down Expand Up @@ -45,8 +64,21 @@ public struct Initialize: ParsableCommand {
public init() { }

public func validate() throws {
guard !schemaName.isEmpty else {
throw ValidationError("Schema name is missing, use the --schema-name option to specify.")
guard !schemaName.trimmingCharacters(in: .whitespaces).isEmpty else {
throw ValidationError("--schema-name value cannot be empty.")
}

let targetNameValiationError = ValidationError("""
Target name is required when using \"embeddedInTarget\" module type. Use --target-name \
to specify.
"""
)

switch (moduleType, targetName?.isEmpty) {
case (.embeddedInTarget, nil), (.embeddedInTarget, true):
throw targetNameValiationError
calvincestari marked this conversation as resolved.
Show resolved Hide resolved
default:
break;
}
}

Expand All @@ -56,8 +88,11 @@ public struct Initialize: ParsableCommand {

func _run(fileManager: ApolloFileManager = .default, output: OutputClosure? = nil) throws {
let encoded = try ApolloCodegenConfiguration
.minimalJSON(schemaName: schemaName)
.asData()
.minimalJSON(
schemaName: schemaName,
moduleType: moduleType,
targetName: targetName
).asData()

if print {
try print(data: encoded, output: output)
Expand Down Expand Up @@ -119,22 +154,50 @@ public struct Initialize: ParsableCommand {
// MARK: - Internal extensions

extension ApolloCodegenConfiguration {
static func minimalJSON(schemaName: String) -> String {
static func minimalJSON(
schemaName: String,
moduleType: ModuleTypeExpressibleByArgument,
targetName: String?
) -> String {
#if COCOAPODS
minimalJSON(schemaName: schemaName, supportCocoaPods: true)
minimalJSON(
schemaName: schemaName,
supportCocoaPods: true,
moduleType: moduleType,
targetName: targetName
)
#else
minimalJSON(schemaName: schemaName, supportCocoaPods: false)
minimalJSON(
schemaName: schemaName,
supportCocoaPods: false,
moduleType: moduleType,
targetName: targetName
)
#endif
}

static func minimalJSON(schemaName: String, supportCocoaPods: Bool) -> String {
static func minimalJSON(
schemaName: String,
supportCocoaPods: Bool,
moduleType: ModuleTypeExpressibleByArgument,
targetName: String?
) -> String {
let cocoaPodsOption = supportCocoaPods ? """

"options" : {
"cocoapodsCompatibleImportStatements" : true
},
""" : ""

let moduleTarget: String = {
guard let targetName = targetName else { return "}" }

return """
"name" : "\(targetName)"
}
"""
}()

return """
{
"schemaName" : "\(schemaName)",\(cocoaPodsOption)
Expand All @@ -154,16 +217,25 @@ extension ApolloCodegenConfiguration {
"schemaTypes" : {
"path" : "./\(schemaName)",
"moduleType" : {
\(supportCocoaPods ? "\"other\"" : "\"swiftPackageManager\"") : {
}
"\(moduleType)" : {
\(moduleTarget)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I could be wrong, but this looks like the indentation is off, and that it may be missing a }? Not sure. Do we have unit tests for this? (I have another comment in the InitializeTests asking about testing this as well.)

Copy link
Member Author

@calvincestari calvincestari Nov 17, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The JSON is correct, otherwise none of the decoding from the return string of minimalJSON into an ApolloCodegenConfiguration instance would succeed.

The indentation is also correct, it looks odd because of where \(moduleTarget) is on line 221. If that was indented two more to 'look' correct, then 194 would need to move two backwards.

}
},
"operations" : {
"relative" : {
"inSchemaModule" : {
}
}
}
}
"""
}
}

/// A custom enum that matches ApolloCodegenConfiguration.SchemaTypesFileOutput.ModuleType, but
/// specifically without associated values so that it can conform to ExpressibleByArgument and be
/// parsed from the command line.
enum ModuleTypeExpressibleByArgument: String, ExpressibleByArgument, CaseIterable {
case embeddedInTarget
case swiftPackageManager
case other
}
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ class ApolloCodegenConfigurationTests: XCTestCase {

// then
expect(output.operationIdentifiersPath).to(beNil())
expect(output.operations).to(equal(.relative(subpath: nil)))
expect(output.operations).to(equal(.inSchemaModule))
}

func test__initializer__givenMinimalApolloCodegenConfiguration_buildsCorrectDefaults() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -261,12 +261,12 @@ class InputObjectTemplateTests: XCTestCase {
intField: GraphQLNullable<Int> = nil,
boolField: GraphQLNullable<Bool> = nil,
floatField: GraphQLNullable<Double> = nil,
customScalarField: GraphQLNullable<TestSchema.CustomScalar> = nil,
lowercaseCustomScalarField: GraphQLNullable<TestSchema.LowercaseCustomScalar> = nil,
enumField: GraphQLNullable<GraphQLEnum<TestSchema.EnumType>> = nil,
lowercaseEnumField: GraphQLNullable<GraphQLEnum<TestSchema.LowercaseEnumType>> = nil,
inputField: GraphQLNullable<TestSchema.InnerInputObject> = nil,
lowercaseInputField: GraphQLNullable<TestSchema.LowercaseInnerInputObject> = nil,
customScalarField: GraphQLNullable<CustomScalar> = nil,
calvincestari marked this conversation as resolved.
Show resolved Hide resolved
lowercaseCustomScalarField: GraphQLNullable<LowercaseCustomScalar> = nil,
enumField: GraphQLNullable<GraphQLEnum<EnumType>> = nil,
lowercaseEnumField: GraphQLNullable<GraphQLEnum<LowercaseEnumType>> = nil,
inputField: GraphQLNullable<InnerInputObject> = nil,
lowercaseInputField: GraphQLNullable<LowercaseInnerInputObject> = nil,
listField: GraphQLNullable<[String?]> = nil
) {
__data = InputDict([
Expand Down Expand Up @@ -304,32 +304,32 @@ class InputObjectTemplateTests: XCTestCase {
set { __data["floatField"] = newValue }
}

public var customScalarField: GraphQLNullable<TestSchema.CustomScalar> {
public var customScalarField: GraphQLNullable<CustomScalar> {
get { __data["customScalarField"] }
set { __data["customScalarField"] = newValue }
}

public var lowercaseCustomScalarField: GraphQLNullable<TestSchema.LowercaseCustomScalar> {
public var lowercaseCustomScalarField: GraphQLNullable<LowercaseCustomScalar> {
get { __data["lowercaseCustomScalarField"] }
set { __data["lowercaseCustomScalarField"] = newValue }
}

public var enumField: GraphQLNullable<GraphQLEnum<TestSchema.EnumType>> {
public var enumField: GraphQLNullable<GraphQLEnum<EnumType>> {
get { __data["enumField"] }
set { __data["enumField"] = newValue }
}

public var lowercaseEnumField: GraphQLNullable<GraphQLEnum<TestSchema.LowercaseEnumType>> {
public var lowercaseEnumField: GraphQLNullable<GraphQLEnum<LowercaseEnumType>> {
get { __data["lowercaseEnumField"] }
set { __data["lowercaseEnumField"] = newValue }
}

public var inputField: GraphQLNullable<TestSchema.InnerInputObject> {
public var inputField: GraphQLNullable<InnerInputObject> {
get { __data["inputField"] }
set { __data["inputField"] = newValue }
}

public var lowercaseInputField: GraphQLNullable<TestSchema.LowercaseInnerInputObject> {
public var lowercaseInputField: GraphQLNullable<LowercaseInnerInputObject> {
get { __data["lowercaseInputField"] }
set { __data["lowercaseInputField"] = newValue }
}
Expand Down Expand Up @@ -749,21 +749,22 @@ class InputObjectTemplateTests: XCTestCase {
func test__render__given_NullableListOfNullableEnum_NoDefault__generates_NullableParameter_OptionalItem_InitializerNilDefault() throws {
// given
buildSubject(fields: [
GraphQLInputField.mock("nullableListNullableItem",
type: .list(.enum(.mock(name: "EnumValue"))),
defaultValue: nil)
GraphQLInputField.mock(
"nullableListNullableItem",
type: .list(.enum(.mock(name: "EnumValue"))),
defaultValue: nil)
])

let expected = """
public init(
nullableListNullableItem: GraphQLNullable<[GraphQLEnum<TestSchema.EnumValue>?]> = nil
nullableListNullableItem: GraphQLNullable<[GraphQLEnum<EnumValue>?]> = nil
) {
__data = InputDict([
"nullableListNullableItem": nullableListNullableItem
])
}

public var nullableListNullableItem: GraphQLNullable<[GraphQLEnum<TestSchema.EnumValue>?]> {
public var nullableListNullableItem: GraphQLNullable<[GraphQLEnum<EnumValue>?]> {
"""

// when
Expand Down Expand Up @@ -2042,7 +2043,10 @@ class InputObjectTemplateTests: XCTestCase {
"nullableListNullableItem",
type: .list(.enum(.mock(name: "EnumValue"))),
defaultValue: nil)],
config: .mock(schemaName: "testschema")
config: .mock(
schemaName: "testschema",
output: .mock(operations: .relative(subpath: nil))
)
)

let expected = """
Expand Down Expand Up @@ -2071,7 +2075,10 @@ class InputObjectTemplateTests: XCTestCase {
"nullableListNullableItem",
type: .list(.enum(.mock(name: "EnumValue"))),
defaultValue: nil)],
config: .mock(schemaName: "TESTSCHEMA")
config: .mock(
schemaName: "TESTSCHEMA",
output: .mock(operations: .relative(subpath: nil))
)
)

let expected = """
Expand Down Expand Up @@ -2100,7 +2107,10 @@ class InputObjectTemplateTests: XCTestCase {
"nullableListNullableItem",
type: .list(.enum(.mock(name: "EnumValue"))),
defaultValue: nil)],
config: .mock(schemaName: "TestSchema")
config: .mock(
schemaName: "TestSchema",
output: .mock(operations: .relative(subpath: nil))
)
calvincestari marked this conversation as resolved.
Show resolved Hide resolved
)

let expected = """
Expand Down
Loading