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

Move Generated Client to separate module #486

Open
wants to merge 21 commits into
base: trunk
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
5cd8d77
Reconfigure OpenAPI generation to output a Swift Package, simplify do…
andrewdmontgomery Oct 4, 2024
110ebc2
Setup local package dependency
andrewdmontgomery Oct 4, 2024
68fd36e
Export OpenAPI types
andrewdmontgomery Oct 4, 2024
667a429
Refactor openapi-generator call
andrewdmontgomery Oct 8, 2024
707bd37
Update generated client
andrewdmontgomery Oct 8, 2024
32f8dd8
Rename OpenAPIClient --> GravatarOpenAPIClient
andrewdmontgomery Oct 8, 2024
283a10f
Match iOS deployment targets for all podspecs
andrewdmontgomery Oct 8, 2024
944c5d6
Update Makefile generation of GravatarOpenAPIClient.podspec
andrewdmontgomery Oct 8, 2024
3c19a1e
Revert project.yml version
andrewdmontgomery Oct 8, 2024
024e041
Stop ignoring the `openapi-generator` directory, since we don't need …
andrewdmontgomery Oct 8, 2024
6e3d2a4
Move GravatarOpenAPIClient into module (without third-party dep)
andrewdmontgomery Oct 9, 2024
84eeb1f
Stop tracking some files
andrewdmontgomery Oct 9, 2024
01c459f
Removes unnecessary `install-and-generate` Makefile task
andrewdmontgomery Oct 10, 2024
9c5b7e4
Update GravatarOpenAPIClient.podspec with path to module
andrewdmontgomery Oct 10, 2024
0b6d4dc
Update the validate-pods.sh script to check the new podspec
andrewdmontgomery Oct 10, 2024
c6a8e96
Update pipeline to publish the new podspec
andrewdmontgomery Oct 10, 2024
d28429d
Update Demo project Package.resolved
andrewdmontgomery Oct 10, 2024
90810ab
Merge branch 'release/3.0.0' into andrewdmontgomery/OpenAPI-with-SPM
andrewdmontgomery Oct 10, 2024
e1e7191
Regenerate SetEmailAvatarRequest
andrewdmontgomery Oct 10, 2024
93446f7
Fix typo in `generate` Makefile command
andrewdmontgomery Oct 10, 2024
b3b9f4c
Update .openapi-generator-ignore to generate only `Models` dir
andrewdmontgomery Oct 10, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .buildkite/commands/validate-pods.sh
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,6 @@ validate_podspec --allow-warnings Gravatar.podspec

echo "--- :cocoapods: Validate GravatarUI.podspec"
validate_podspec --allow-warnings GravatarUI.podspec

echo "--- :cocoapods: Validate GravatarOpenAPIClient.podspec"
validate_podspec --allow-warnings GravatarOpenAPIClient.podspec
1 change: 1 addition & 0 deletions .buildkite/pipeline.yml
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ steps:
command: |
.buildkite/commands/publish-pod.sh "Gravatar.podspec"
.buildkite/commands/publish-pod.sh "GravatarUI.podspec"
.buildkite/commands/publish-pod.sh "GravatarOpenAPIClient.podspec"
plugins: [$CI_TOOLKIT]
depends_on:
- "test"
Expand Down
11 changes: 10 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,18 @@ fastlane/README.md
fastlane/report.xml
fastlane/test_output

# OpenAPI
openapi/GravatarOpenAPIClient/
!openapi/GravatarOpenAPIClient/.openapi-generator/
!openapi/GravatarOpenAPIClient/.openapi-generator-ignore
!openapi/GravatarOpenAPIClient/docs/
!openapi/GravatarOpenAPIClient/GravatarOpenAPIClient.podspec
!openapi/GravatarOpenAPIClient/Package.swift
!openapi/GravatarOpenAPIClient/project.yml
!openapi/GravatarOpenAPIClient/README.md

# SwiftGen (part of wpmreleasetoolkit)
vendor/swiftgen

# Other
openapi-generator/
Demo/Demo/Secrets.swift
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"originHash" : "89aad130e119d7a4b1dea1ad42b23e52b29cf016999eed5d14af43b0dc276ac1",
"originHash" : "bf24fbca0585c9e7707869442e833d48e8fbe49f5e904fe58370244d9f54521e",
"pins" : [
{
"identity" : "swift-snapshot-testing",
Expand Down
3 changes: 2 additions & 1 deletion Gravatar.podspec
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,11 @@ Pod::Spec.new do |s|

s.swift_versions = Gravatar::SWIFT_VERSIONS

ios_deployment_target = '15.0'
ios_deployment_target = Gravatar::IOS_DEPLOYMENT_TARGET

s.ios.deployment_target = ios_deployment_target

s.dependency 'GravatarOpenAPIClient', s.version.to_s
Copy link
Contributor

Choose a reason for hiding this comment

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

AFAIU, GravatarOpenAPIClient's version is Gravatar's version. This makes me wonder what happens when the specs change and we re-generate GravatarOpenAPIClient. When I use the new models in Gravatar what should i set here so that cocoapods also builds fine in CI...

s.source_files = 'Sources/Gravatar/**/*.swift'
s.resource_bundles = {
'Gravatar' => ['Sources/Gravatar/Resources/*.plist']
Expand Down
23 changes: 23 additions & 0 deletions GravatarOpenAPIClient.podspec
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# frozen_string_literal: true

require_relative 'version'

Pod::Spec.new do |s|
s.name = 'GravatarOpenAPIClient'
s.summary = 'A Gravatar OpenAPI Client'
s.version = Gravatar::VERSION

s.swift_versions = Gravatar::SWIFT_VERSIONS

# Match the deployment target of Gravatar in order to satisfy `pod lib lint`
s.ios.deployment_target = Gravatar::IOS_DEPLOYMENT_TARGET

s.homepage = 'https://gravatar.com'
s.license = { type: 'Mozilla Public License v2', file: 'LICENSE.md' }
s.authors = 'Automattic, Inc.'
s.source = { :git => 'https://github.com/Automattic/Gravatar-SDK-iOS.git', :tag => s.version.to_s }

s.documentation_url = 'https://automattic.github.io/Gravatar-SDK-iOS/gravatar'

s.source_files = 'Sources/GravatarOpenAPIClient/**/*.swift'
end
2 changes: 1 addition & 1 deletion GravatarUI.podspec
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ Pod::Spec.new do |s|

s.swift_versions = Gravatar::SWIFT_VERSIONS

ios_deployment_target = '15.0'
ios_deployment_target = Gravatar::IOS_DEPLOYMENT_TARGET
s.ios.deployment_target = ios_deployment_target

s.source_files = 'Sources/GravatarUI/**/*.swift'
Expand Down
53 changes: 27 additions & 26 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,15 @@ SWIFTFORMAT_CACHE = ~/Library/Caches/com.charcoaldesign.swiftformat
OPENAPI_GENERATOR_GIT_URL ?= https://github.com/openapitools/openapi-generator
OPENAPI_GENERATOR_GIT_TAG ?= v7.5.0
OPENAPI_GENERATOR_CLONE_DIR ?= $(CURRENT_MAKEFILE_DIR)/openapi-generator

OPENAPI_PROJECT_NAME ?= GravatarOpenAPIClient
OPENAPI_DIR ?= $(CURRENT_MAKEFILE_DIR)/$(OPENAPI_REL_DIR)
OPENAPI_REL_DIR ?= openapi
OPENAPI_GENERATED_DIR ?= $(CURRENT_MAKEFILE_DIR)/openapi/$(OPENAPI_PROJECT_NAME)
OPENAPI_CLIENT_PROPERTIES ?= projectName=$(OPENAPI_PROJECT_NAME),useSPMFileStructure=true

OPENAPI_YAML_PATH ?= $(CURRENT_MAKEFILE_DIR)/openapi/spec.yaml
MODEL_TEMPLATE_PATH ?= $(CURRENT_MAKEFILE_DIR)/openapi
OUTPUT_DIRECTORY ?= $(CURRENT_MAKEFILE_DIR)/Sources/Gravatar/OpenApi/Generated

# Derived values (don't change these).
CURRENT_MAKEFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST)))
Expand Down Expand Up @@ -94,7 +100,7 @@ validate-pod: bundle-install
xcrun simctl list >> /dev/null
bundle exec pod lib lint \
--include-podspecs="*.podspec" \
--verbose --fail-fast
--verbose --fail-fast --allow-warnings

update-example-snapshots:
for filePath in ./Sources/GravatarUI/GravatarUI.docc/Resources/ProfileExamples/*; \
Expand All @@ -104,24 +110,19 @@ update-example-snapshots:
cd ./Sources/GravatarUI/GravatarUI.docc/Resources/ProfileExamples && \
for filePath in *; do name=$${filePath%.*}; mv $$filePath $${name//-dark/~dark}@2x$${filePath#$$name}; done

install-and-generate: $(OPENAPI_GENERATOR_CLONE_DIR) # Clones and setup the openapi-generator.
"$(OPENAPI_GENERATOR_CLONE_DIR)"/run-in-docker.sh mvn package
make generate

generate: $(OUTPUT_DIRECTORY) # Generates the open-api model
cp "$(OPENAPI_YAML_PATH)" "$(OPENAPI_GENERATOR_CLONE_DIR)"/openapi.yaml
mkdir -p "$(OPENAPI_GENERATOR_CLONE_DIR)"/templates
cp "$(MODEL_TEMPLATE_PATH)"/*.mustache "$(OPENAPI_GENERATOR_CLONE_DIR)"/templates/
rm -rf "$(OPENAPI_GENERATOR_CLONE_DIR)"/generated/OpenAPIClient/Classes/OpenAPIs/Models/*
"$(OPENAPI_GENERATOR_CLONE_DIR)"/run-in-docker.sh generate -i openapi.yaml \
--global-property models \
-t templates \
-g swift5 \
-o ./generated \
-p packageName=Gravatar \
--additional-properties=useJsonEncodable=false,readonlyProperties=true && \
rsync -av --delete "$(OPENAPI_GENERATOR_CLONE_DIR)"/generated/OpenAPIClient/Classes/OpenAPIs/Models/ "$(OUTPUT_DIRECTORY)/" && \
make swiftformat && \
generate: $(OPENAPI_GENERATED_DIR) # Generates the open-api model
rm -rf "$(OPENAPI_GENERATED_DIR)"/* && \
docker run --rm \
-v $(OPENAPI_DIR):/local openapitools/openapi-generator-cli:"$(OPENAPI_GENERATOR_GIT_TAG)" generate \
-i /local/openapi.yaml \
-o /local/GravatarOpenAPIClient \
-t /local/templates \
-g swift5 \
-p packageName=Gravatar \
--additional-properties=useJsonEncodable=false,readonlyProperties=true,$(OPENAPI_CLIENT_PROPERTIES) && \
rsync -av --delete "$(OPENAPI_GENERATED_DIR)/Sources/$(OPENAPI_PROJECT_NAME)/" "$(CURRENT_MAKEFILE_DIR)/Sources/$(OPENAPI_PROJECT_NAME)/" && \
cp -fp "$(OPENAPI_GENERATED_DIR)/$(OPENAPI_PROJECT_NAME).podspec" "$(CURRENT_MAKEFILE_DIR)/" && \
make swiftformat && \
echo "DONE! 🎉"

generate-strings: bundle-install
Expand All @@ -131,22 +132,22 @@ download-strings: bundle-install
bundle exec fastlane download_localized_strings

clean-generated: # Delete the output directory used for generated sources.
@echo 'Delete entire directory: $(OUTPUT_DIRECTORY)? [y/N] ' && read ans && [ $${ans:-N} = y ] || (echo "Aborted"; exit 1)
rm -rf "$(OUTPUT_DIRECTORY)"
@echo 'Delete entire directory: $(OPENAPI_GENERATED_DIR)? [y/N] ' && read ans && [ $${ans:-N} = y ] || (echo "Aborted"; exit 1)
rm -rf "$(OPENAPI_GENERATED_DIR)"

clean: # Clean everything, including the checkout of swift-openapi-generator.
clean: # Clean everything
@echo 'Delete checkout of openapi-generator $(OPENAPI_GENERATOR_CLONE_DIR)? [y/N] ' && read ans && [ $${ans:-N} = y ] || (echo "Aborted"; exit 1)
rm -rf "$(OPENAPI_GENERATOR_CLONE_DIR)"
rm -rf "$(OPENAPI_GENERATOR_CLONE_DIR)/*"


dump: # Dump all derived values used by the Makefile.
@echo "CURRENT_MAKEFILE_PATH = $(CURRENT_MAKEFILE_PATH)"
@echo "CURRENT_MAKEFILE_DIR = $(CURRENT_MAKEFILE_DIR)"
@echo "OPENAPI_GENERATED_DIR = $(OPENAPI_GENERATED_DIR)"
@echo "OPENAPI_GENERATOR_GIT_URL = $(OPENAPI_GENERATOR_GIT_URL)"
@echo "OPENAPI_GENERATOR_GIT_TAG = $(OPENAPI_GENERATOR_GIT_TAG)"
@echo "OPENAPI_GENERATOR_CLONE_DIR = $(OPENAPI_GENERATOR_CLONE_DIR)"
@echo "OPENAPI_YAML_PATH = $(OPENAPI_YAML_PATH)"
@echo "OUTPUT_DIRECTORY = $(OUTPUT_DIRECTORY)"

$(OPENAPI_GENERATOR_CLONE_DIR):
git \
Expand All @@ -157,5 +158,5 @@ $(OPENAPI_GENERATOR_CLONE_DIR):
"$(OPENAPI_GENERATOR_GIT_URL)" \
$@

$(OUTPUT_DIRECTORY):
$(OPENAPI_GENERATED_DIR):
mkdir -p "$@"
2 changes: 1 addition & 1 deletion Package.resolved
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"originHash" : "2d82ed06a27431c1da79790f8b215b8abf6d2a7397f42f02e364c7a92f86a5ab",
"originHash" : "ce90f93a035f7d411d81060dce4cdc6d5bcbe81fce7d7260084532fa492ff797",
"pins" : [
{
"identity" : "swift-snapshot-testing",
Expand Down
9 changes: 8 additions & 1 deletion Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,14 @@ let package = Package(
dependencies: [
.package(url: "https://github.com/nicklockwood/SwiftFormat", from: "0.54.0"),
.package(url: "https://github.com/pointfreeco/swift-snapshot-testing", from: "1.8.1"),
.package(url: "https://github.com/SimplyDanny/SwiftLintPlugins", exact: "0.56.2"),
.package(url: "https://github.com/SimplyDanny/SwiftLintPlugins", exact: "0.56.2")
],
targets: [
// Targets are the basic building blocks of a package, defining a module or a test suite.
// Targets can depend on other targets in this package and products from dependencies.
.target(
name: "Gravatar",
dependencies: ["GravatarOpenAPIClient"],
resources: [.process("Resources")],
swiftSettings: [
.enableExperimentalFeature("StrictConcurrency")
Expand Down Expand Up @@ -72,6 +73,12 @@ let package = Package(
swiftSettings: [
.enableExperimentalFeature("StrictConcurrency")
]
),
.target(
name: "GravatarOpenAPIClient",
swiftSettings: [
.enableExperimentalFeature("StrictConcurrency")
]
)
]
)
23 changes: 23 additions & 0 deletions Sources/Gravatar/OpenAPIExports.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import GravatarOpenAPIClient

// MARK: OpenAPI Models: Public

public typealias CryptoWalletAddress = GravatarOpenAPIClient.CryptoWalletAddress
public typealias GalleryImage = GravatarOpenAPIClient.GalleryImage
public typealias Interest = GravatarOpenAPIClient.Interest
public typealias Language = GravatarOpenAPIClient.Language
public typealias Link = GravatarOpenAPIClient.Link
public typealias Profile = GravatarOpenAPIClient.Profile
public typealias ProfileContactInfo = GravatarOpenAPIClient.ProfileContactInfo
public typealias ProfilePayments = GravatarOpenAPIClient.ProfilePayments
public typealias VerifiedAccount = GravatarOpenAPIClient.VerifiedAccount

// MARK: - OpenAPI Models: Package

package typealias Avatar = GravatarOpenAPIClient.Avatar

// MARK: - OpenAPI Models: Internal

typealias AssociatedResponse = GravatarOpenAPIClient.AssociatedResponse
typealias ModelError = GravatarOpenAPIClient.ModelError
typealias SetEmailAvatarRequest = GravatarOpenAPIClient.SetEmailAvatarRequest
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import Foundation

struct AssociatedResponse: Codable, Hashable, Sendable {
public struct AssociatedResponse: Codable, Hashable, Sendable {
/// Whether the entity is associated with the account.
private(set) var associated: Bool
public private(set) var associated: Bool

init(associated: Bool) {
self.associated = associated
Expand All @@ -14,7 +14,7 @@ struct AssociatedResponse: Codable, Hashable, Sendable {

// Encodable protocol methods

func encode(to encoder: Encoder) throws {
public func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(associated, forKey: .associated)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,28 +2,28 @@ import Foundation

/// An avatar that the user has already uploaded to their Gravatar account.
///
package struct Avatar: Codable, Hashable, Sendable {
package enum Rating: String, Codable, CaseIterable, Sendable {
public struct Avatar: Codable, Hashable, Sendable {
Copy link
Contributor

@pinarol pinarol Oct 14, 2024

Choose a reason for hiding this comment

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

Is there maybe a way to keep package ? I think the initial intention was to not open these because we would then need to reflect the changes to the version number. AFAIK there's nothing that prevents a 3rd party to import GravatarOpenAPIClient so i guess the question is, are we ready to maintain a 3rd public package with semantic versioning?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

AFAIK there's nothing that prevents a 3rd party to import GravatarOpenAPIClient

This is a good question. My understanding of Swift Packages (which turned out to be incomplete) was that only modules that are exposed as libraries (via .library() in products: [...] in the Package.swift) would be available to third parties who integrate this Package.

And since this would not expose the generated client as a .library(), then my thinking went, it would not be available to third parties via our SDK.

But as it turns out, it isn't quite that simple. It's true that by not listing it as a .library(), the GravatarOpenAPIClient library is NOT available to be added to targets:
image
image

But since Gravatar imports the GravatarOpenAPIClient module, the public types in that module are implicitly exposed – and importable – to third parties who import the Gravatar library, even though they cannot add the underlying library.

As a result, you are right. If we could retain those package access controls, these types wouldn't be importable. And therefore, this whole approach doesn't address the original problem: how can we hide the types that don't need to be public?

so i guess the question is, are we ready to maintain a 3rd public package with semantic versioning?
That's the question. I think we aren't yet ready for that.

For one, as we discussed separately, as it currently stands, the versioning of this OpenAPIClient will need to be independent of the version of the SDK. This is because:

  • By default, all types in the OpenAPIClient are public, so any change to them will affect the API
  • But changes to the OpenAPIClient don't necessarily affect the SDK API

I think there are two directions we can take this:

  1. Publish a fully public GravatarOpenAPIClient, with its own versioning (and likely its own repository)
    • Add that as a dependency of our SDK
  2. Produce a version of the GravatarOpenAPIClient with more granular access controls
    • Include that as a separate, integrated module with our SDK, like in this PR
    • Or just embed it as we currently do

Both options will require some effort, and will introduce some complexity. But I think option 2 probably serves the needs of the SDK more directly:

  • If someone really wants their own GravatarOpenAPIClient, they can make their own quite easily. So maintaining one doesn't useful.
  • Integrating a fully public version into our SDK can be confusing since we don't need or use most of what gets generated

public enum Rating: String, Codable, CaseIterable, Sendable {
case g = "G"
case pg = "PG"
case r = "R"
case x = "X"
}

/// Unique identifier for the image.
package private(set) var imageId: String
public private(set) var imageId: String
/// Image URL
package private(set) var imageUrl: String
public private(set) var imageUrl: String
/// Rating associated with the image.
package private(set) var rating: Rating
public private(set) var rating: Rating
/// Date and time when the image was last updated.
package private(set) var updatedDate: Date
public private(set) var updatedDate: Date
/// Alternative text description of the image.
package private(set) var altText: String
public private(set) var altText: String
/// Whether the image is currently selected as the provided selected email's avatar.
package private(set) var selected: Bool?
public private(set) var selected: Bool?

package init(imageId: String, imageUrl: String, rating: Rating, updatedDate: Date, altText: String, selected: Bool? = nil) {
init(imageId: String, imageUrl: String, rating: Rating, updatedDate: Date, altText: String, selected: Bool? = nil) {
self.imageId = imageId
self.imageUrl = imageUrl
self.rating = rating
Expand All @@ -43,7 +43,7 @@ package struct Avatar: Codable, Hashable, Sendable {

// Encodable protocol methods

package func encode(to encoder: Encoder) throws {
public func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(imageId, forKey: .imageId)
try container.encode(imageUrl, forKey: .imageUrl)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@ import Foundation

/// An error response from the API.
///
struct ModelError: Codable, Hashable, Sendable {
public struct ModelError: Codable, Hashable, Sendable {
/// The error message
private(set) var error: String
public private(set) var error: String
/// The error code for the error message
private(set) var code: String?
public private(set) var code: String?

init(error: String, code: String? = nil) {
self.error = error
Expand All @@ -20,7 +20,7 @@ struct ModelError: Codable, Hashable, Sendable {

// Encodable protocol methods

func encode(to encoder: Encoder) throws {
public func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(error, forKey: .error)
try container.encodeIfPresent(code, forKey: .code)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import Foundation

struct SetEmailAvatarRequest: Codable, Hashable, Sendable {
public struct SetEmailAvatarRequest: Codable, Hashable, Sendable {
/// The email SHA256 hash to set the avatar for.
private(set) var emailHash: String
public private(set) var emailHash: String

init(emailHash: String) {
self.emailHash = emailHash
Expand All @@ -14,7 +14,7 @@ struct SetEmailAvatarRequest: Codable, Hashable, Sendable {

// Encodable protocol methods

func encode(to encoder: Encoder) throws {
public func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(emailHash, forKey: .emailHash)
}
Expand Down
30 changes: 30 additions & 0 deletions openapi/GravatarOpenAPIClient/.openapi-generator-ignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# OpenAPI Generator Ignore
# Generated by openapi-generator https://github.com/openapitools/openapi-generator

# Use this file to prevent files from being overwritten by the generator.
# The patterns follow closely to .gitignore or .dockerignore.

# As an example, the C# client generator defines ApiClient.cs.
# You can make changes and tell OpenAPI Generator to ignore just this file by uncommenting the following line:
#ApiClient.cs

# You can match any string of characters against a directory, file or extension with a single asterisk (*):
#foo/*/qux
# The above matches foo/bar/qux and foo/baz/qux, but not foo/bar/baz/qux

# You can recursively match patterns against a directory, file or extension with a double asterisk (**):
#foo/**/qux
# This matches foo/bar/qux, foo/baz/qux, and foo/bar/baz/qux

# You can also negate patterns with an exclamation (!).
# For example, you can ignore all files in a docs folder with the file extension .md:
#docs/*.md
# Then explicitly reverse the ignore rule for a single file:
#!docs/README.md

.gitignore
.swiftformat
Cartfile
git_push.sh
Sources/GravatarOpenAPIClient/
!Sources/GravatarOpenAPIClient/Models/
Loading