Skip to content

Commit fb20a73

Browse files
Merge branch 'main' into error_handling
2 parents e4725c4 + f1d7d8b commit fb20a73

File tree

69 files changed

+544
-784
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

69 files changed

+544
-784
lines changed

.github/workflows/pull_request.yml

Lines changed: 68 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,71 @@
1-
name: Pull Request
1+
name: PR
22

33
on:
4-
pull_request:
5-
types: [opened, reopened, synchronize, ready_for_review]
6-
4+
pull_request:
5+
types: [opened, reopened, synchronize]
6+
77
jobs:
8-
call-reusable-pull-request-workflow:
9-
name: Checks
10-
uses: apple/swift-nio/.github/workflows/reusable_pull_request.yml@main
11-
with:
12-
benchmarks_linux_enabled: false
8+
soundness:
9+
name: Soundness
10+
uses: apple/swift-nio/.github/workflows/soundness.yml@main
11+
with:
12+
api_breakage_check_enabled: true
13+
broken_symlink_check_enabled: true
14+
docs_check_enabled: true
15+
format_check_enabled: true
16+
license_header_check_enabled: true
17+
license_header_check_project_name: "SwiftOpenAPIGenerator"
18+
shell_check_enabled: true
19+
unacceptable_language_check_enabled: true
20+
21+
unit-tests:
22+
name: Unit tests
23+
uses: apple/swift-nio/.github/workflows/unit_tests.yml@main
24+
with:
25+
linux_5_8_enabled: false
26+
linux_5_9_arguments_override: "--explicit-target-dependency-import-check error"
27+
linux_5_10_arguments_override: "--explicit-target-dependency-import-check error"
28+
linux_nightly_6_0_arguments_override: "--explicit-target-dependency-import-check error"
29+
linux_nightly_main_enabled: false
30+
31+
integration-test:
32+
name: Integration test
33+
uses: apple/swift-nio/.github/workflows/swift_matrix.yml@main
34+
with:
35+
name: "Integration test"
36+
matrix_linux_command: "apt-get update -yq && apt-get install -yq jq && SWIFT_OPENAPI_GENERATOR_REPO_URL=file://${GITHUB_WORKSPACE} ./scripts/run-integration-test.sh"
37+
matrix_linux_5_8_enabled: false
38+
matrix_linux_nightly_main_enabled: false
39+
40+
compatibility-test:
41+
name: Compatibility test
42+
runs-on: ubuntu-latest
43+
container:
44+
image: swift:latest
45+
steps:
46+
- name: Checkout repository
47+
uses: actions/checkout@v4
48+
with:
49+
persist-credentials: false
50+
- name: Run OpenAPI document compatibilty test
51+
env:
52+
SWIFT_OPENAPI_COMPATIBILITY_TEST_ENABLE: "true"
53+
SWIFT_OPENAPI_COMPATIBILITY_TEST_SKIP_BUILD: "true"
54+
SWIFT_OPENAPI_COMPATIBILITY_TEST_FILTER: OpenAPIGeneratorReferenceTests.CompatibilityTest
55+
SWIFT_OPENAPI_COMPATIBILITY_TEST_PARALLEL_CODEGEN: "true"
56+
SWIFT_OPENAPI_COMPATIBILITY_TEST_NUM_BUILD_JOBS: 1
57+
run: swift test --filter ${SWIFT_OPENAPI_COMPATIBILITY_TEST_FILTER}
58+
59+
example-packages:
60+
name: Example packages
61+
uses: apple/swift-nio/.github/workflows/swift_matrix.yml@main
62+
with:
63+
name: "Example packages"
64+
matrix_linux_command: "./scripts/test-examples.sh"
65+
matrix_linux_5_8_enabled: false
66+
matrix_linux_nightly_main_enabled: false
67+
68+
swift-6-language-mode:
69+
name: Swift 6 Language Mode
70+
uses: apple/swift-nio/.github/workflows/swift_6_language_mode.yml@main
71+
if: false # Disabled for now.

.github/workflows/scheduled.yml

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
name: Scheduled
2+
3+
on:
4+
schedule:
5+
- cron: "0 8,20 * * *"
6+
7+
jobs:
8+
unit-tests:
9+
name: Unit tests
10+
uses: apple/swift-nio/.github/workflows/unit_tests.yml@main
11+
with:
12+
linux_5_8_enabled: false
13+
linux_5_9_arguments_override: "--explicit-target-dependency-import-check error"
14+
linux_5_10_arguments_override: "--explicit-target-dependency-import-check error"
15+
linux_nightly_6_0_arguments_override: "--explicit-target-dependency-import-check error"
16+
linux_nightly_main_arguments_override: "--explicit-target-dependency-import-check error"
17+
18+
integration-test:
19+
name: Integration test
20+
uses: apple/swift-nio/.github/workflows/swift_matrix.yml@main
21+
with:
22+
name: "Integration test"
23+
matrix_linux_command: "apt-get update -yq && apt-get install -yq jq && SWIFT_OPENAPI_GENERATOR_REPO_URL=file://${GITHUB_WORKSPACE} ./scripts/run-integration-test.sh"
24+
matrix_linux_5_8_enabled: false
25+
26+
example-packages:
27+
name: Example packages
28+
uses: apple/swift-nio/.github/workflows/swift_matrix.yml@main
29+
with:
30+
name: "Example packages"
31+
matrix_linux_command: "./scripts/test-examples.sh"
32+
matrix_linux_5_8_enabled: false

.licenseignore

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
.gitignore
2+
.licenseignore
3+
.swiftformatignore
4+
.spi.yml
5+
.swift-format
6+
.github/*
7+
CODE_OF_CONDUCT.md
8+
CONTRIBUTING.md
9+
CONTRIBUTORS.txt
10+
LICENSE.txt
11+
NOTICE.txt
12+
Package.swift
13+
Package.resolved
14+
README.md
15+
SECURITY.md
16+
scripts/unacceptable-language.txt
17+
Tests/PetstoreConsumerTests/Generated
18+
Tests/OpenAPIGeneratorReferenceTests/Resources/ReferenceSources/*
19+
docker/*
20+
**/*.docc/*
21+
**/.gitignore
22+
**/Package.swift
23+
**/Package.resolved
24+
**/README.md
25+
**/openapi.yaml
26+
**/malformed-openapi.yaml
27+
**/openapi.yml
28+
**/petstore.yaml
29+
**/openapi-generator-config.yaml
30+
**/openapi-generator-config.yml
31+
**/docker-compose.yaml
32+
**/docker/*
33+
**/.dockerignore
34+
Plugins/OpenAPIGenerator/PluginsShared
35+
Plugins/OpenAPIGeneratorCommand/PluginsShared
36+
Examples/HelloWorldiOSClientAppExample/HelloWorldiOSClientApp.*
37+
Examples/HelloWorldiOSClientAppExample/HelloWorldiOSClientApp/Assets.xcassets/*
38+
Examples/HelloWorldiOSClientAppExample/HelloWorldiOSClientApp/Preview*
39+
Examples/**/Generated*
40+
**/Makefile
41+
**/*.html

.swiftformatignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
Tests/OpenAPIGeneratorReferenceTests/Resources
2+
Sources/swift-openapi-generator/Documentation.docc
3+
Examples/**/Generated/*
4+
Examples/**/GeneratedSources/*

CONTRIBUTING.md

Lines changed: 32 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -54,13 +54,40 @@ A good patch is:
5454
3. Documented, adding API documentation as needed to cover new functions and properties.
5555
4. Accompanied by a great commit message, using our commit message template.
5656

57-
### Run `./scripts/soundness.sh`
57+
### Run CI checks locally
5858

59-
The scripts directory contains a [soundness.sh script](https://github.com/apple/swift-openapi-generator/blob/main/scripts/soundness.sh)
60-
that enforces additional checks, like license headers and formatting style.
59+
You can run the Github Actions workflows locally using
60+
[act](https://github.com/nektos/act). To run all the jobs that run on a pull
61+
request, use the following command:
6162

62-
Please make sure to `./scripts/soundness.sh` before pushing a change upstream, otherwise it is likely the PR validation will fail
63-
on minor changes such as a missing `self.` or similar formatting issues.
63+
```
64+
% act pull_request
65+
```
66+
67+
To run just a single job, use `workflow_call -j <job>`, and specify the inputs
68+
the job expects. For example, to run just shellcheck:
69+
70+
```
71+
% act workflow_call -j soundness --input shell_check_enabled=true
72+
```
73+
74+
To bind-mount the working directory to the container, rather than a copy, use
75+
`--bind`. For example, to run just the formatting, and have the results
76+
reflected in your working directory:
77+
78+
```
79+
% act --bind workflow_call -j soundness --input format_check_enabled=true
80+
```
81+
82+
If you'd like `act` to always run with certain flags, these can be be placed in
83+
an `.actrc` file either in the current working directory or your home
84+
directory, for example:
85+
86+
```
87+
--container-architecture=linux/amd64
88+
--remote-name upstream
89+
--action-offline-mode
90+
```
6491

6592
For frequent contributors, we recommend adding the script as a [git pre-push hook](https://git-scm.com/book/en/v2/Customizing-Git-Git-Hooks), which you can do via executing the following command in the project root directory:
6693

Package.swift

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -62,9 +62,6 @@ let package = Package(
6262
// code.
6363
.package(url: "https://github.com/apple/swift-openapi-runtime", from: "1.3.2"),
6464
.package(url: "https://github.com/apple/swift-http-types", from: "1.0.2"),
65-
66-
// Build and preview docs
67-
.package(url: "https://github.com/apple/swift-docc-plugin", from: "1.3.0"),
6865
],
6966
targets: [
7067

@@ -114,6 +111,16 @@ let package = Package(
114111
swiftSettings: swiftSettings
115112
),
116113

114+
// Test Target for swift-openapi-generator
115+
.testTarget(
116+
name: "OpenAPIGeneratorTests",
117+
dependencies: [
118+
"swift-openapi-generator", .product(name: "ArgumentParser", package: "swift-argument-parser"),
119+
],
120+
resources: [.copy("Resources")],
121+
swiftSettings: swiftSettings
122+
),
123+
117124
// Generator CLI
118125
.executableTarget(
119126
name: "swift-openapi-generator",

Sources/_OpenAPIGeneratorCore/Diagnostics.swift

Lines changed: 49 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,33 @@ public protocol DiagnosticCollector {
165165

166166
/// Submits a diagnostic to the collector.
167167
/// - Parameter diagnostic: The diagnostic to submit.
168-
func emit(_ diagnostic: Diagnostic)
168+
/// - Throws: An error if the implementing type determines that one should be thrown.
169+
func emit(_ diagnostic: Diagnostic) throws
170+
}
171+
172+
/// A type that conforms to the `DiagnosticCollector` protocol.
173+
///
174+
/// It receives diagnostics and forwards them to an upstream `DiagnosticCollector`.
175+
///
176+
/// If a diagnostic with a severity of `.error` is emitted, this collector will throw the diagnostic as an error.
177+
public struct ErrorThrowingDiagnosticCollector: DiagnosticCollector {
178+
let upstream: any DiagnosticCollector
179+
180+
/// Initializes a new `ErrorThrowingDiagnosticCollector` with an upstream `DiagnosticCollector`.
181+
///
182+
/// The upstream collector is where this collector will forward all received diagnostics.
183+
///
184+
/// - Parameter upstream: The `DiagnosticCollector` to which this collector will forward diagnostics.
185+
public init(upstream: any DiagnosticCollector) { self.upstream = upstream }
186+
187+
/// Emits a diagnostic to the collector.
188+
///
189+
/// - Parameter diagnostic: The diagnostic to be submitted.
190+
/// - Throws: The diagnostic itself if its severity is `.error`.
191+
public func emit(_ diagnostic: Diagnostic) throws {
192+
try upstream.emit(diagnostic)
193+
if diagnostic.severity == .error { throw diagnostic }
194+
}
169195
}
170196

171197
extension DiagnosticCollector {
@@ -180,8 +206,9 @@ extension DiagnosticCollector {
180206
/// feature was detected.
181207
/// - context: A set of key-value pairs that help the user understand
182208
/// where the warning occurred.
183-
func emitUnsupported(_ feature: String, foundIn: String, context: [String: String] = [:]) {
184-
emit(Diagnostic.unsupported(feature, foundIn: foundIn, context: context))
209+
/// - Throws: This method will throw the diagnostic if the severity of the diagnostic is `.error`.
210+
func emitUnsupported(_ feature: String, foundIn: String, context: [String: String] = [:]) throws {
211+
try emit(Diagnostic.unsupported(feature, foundIn: foundIn, context: context))
185212
}
186213

187214
/// Emits a diagnostic for an unsupported schema found in the specified
@@ -193,9 +220,10 @@ extension DiagnosticCollector {
193220
/// schema was detected.
194221
/// - context: A set of key-value pairs that help the user understand
195222
/// where the warning occurred.
196-
func emitUnsupportedSchema(reason: String, schema: JSONSchema, foundIn: String, context: [String: String] = [:]) {
197-
emit(Diagnostic.unsupportedSchema(reason: reason, schema: schema, foundIn: foundIn, context: context))
198-
}
223+
/// - Throws: This method will throw the diagnostic if the severity of the diagnostic is `.error`.
224+
func emitUnsupportedSchema(reason: String, schema: JSONSchema, foundIn: String, context: [String: String] = [:])
225+
throws
226+
{ try emit(Diagnostic.unsupportedSchema(reason: reason, schema: schema, foundIn: foundIn, context: context)) }
199227

200228
/// Emits a diagnostic for an unsupported feature found in the specified
201229
/// type name.
@@ -206,8 +234,9 @@ extension DiagnosticCollector {
206234
/// - foundIn: The type name related to where the issue was detected.
207235
/// - context: A set of key-value pairs that help the user understand
208236
/// where the warning occurred.
209-
func emitUnsupported(_ feature: String, foundIn: TypeName, context: [String: String] = [:]) {
210-
emit(Diagnostic.unsupported(feature, foundIn: foundIn.description, context: context))
237+
/// - Throws: This method will throw the diagnostic if the severity of the diagnostic is `.error`.
238+
func emitUnsupported(_ feature: String, foundIn: TypeName, context: [String: String] = [:]) throws {
239+
try emit(Diagnostic.unsupported(feature, foundIn: foundIn.description, context: context))
211240
}
212241

213242
/// Emits a diagnostic for an unsupported feature found in the specified
@@ -222,9 +251,12 @@ extension DiagnosticCollector {
222251
/// feature was detected.
223252
/// - context: A set of key-value pairs that help the user understand
224253
/// where the warning occurred.
225-
func emitUnsupportedIfNotNil(_ test: Any?, _ feature: String, foundIn: String, context: [String: String] = [:]) {
254+
/// - Throws: This method will throw the diagnostic if the severity of the diagnostic is `.error`.
255+
func emitUnsupportedIfNotNil(_ test: Any?, _ feature: String, foundIn: String, context: [String: String] = [:])
256+
throws
257+
{
226258
if test == nil { return }
227-
emitUnsupported(feature, foundIn: foundIn, context: context)
259+
try emitUnsupported(feature, foundIn: foundIn, context: context)
228260
}
229261

230262
/// Emits a diagnostic for an unsupported feature found in the specified
@@ -239,14 +271,15 @@ extension DiagnosticCollector {
239271
/// feature was detected.
240272
/// - context: A set of key-value pairs that help the user understand
241273
/// where the warning occurred.
274+
/// - Throws: This method will throw the diagnostic if the severity of the diagnostic is `.error`.
242275
func emitUnsupportedIfNotEmpty<C: Collection>(
243276
_ test: C?,
244277
_ feature: String,
245278
foundIn: String,
246279
context: [String: String] = [:]
247-
) {
280+
) throws {
248281
guard let test = test, !test.isEmpty else { return }
249-
emitUnsupported(feature, foundIn: foundIn, context: context)
282+
try emitUnsupported(feature, foundIn: foundIn, context: context)
250283
}
251284

252285
/// Emits a diagnostic for an unsupported feature found in the specified
@@ -261,9 +294,11 @@ extension DiagnosticCollector {
261294
/// feature was detected.
262295
/// - context: A set of key-value pairs that help the user understand
263296
/// where the warning occurred.
264-
func emitUnsupportedIfTrue(_ test: Bool, _ feature: String, foundIn: String, context: [String: String] = [:]) {
297+
/// - Throws: This method will throw the diagnostic if the severity of the diagnostic is `.error`.
298+
func emitUnsupportedIfTrue(_ test: Bool, _ feature: String, foundIn: String, context: [String: String] = [:]) throws
299+
{
265300
if !test { return }
266-
emitUnsupported(feature, foundIn: foundIn, context: context)
301+
try emitUnsupported(feature, foundIn: foundIn, context: context)
267302
}
268303
}
269304

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the SwiftOpenAPIGenerator open source project
4+
//
5+
// Copyright (c) 2023 Apple Inc. and the SwiftOpenAPIGenerator project authors
6+
// Licensed under Apache License v2.0
7+
//
8+
// See LICENSE.txt for license information
9+
// See CONTRIBUTORS.txt for the list of SwiftOpenAPIGenerator project authors
10+
//
11+
// SPDX-License-Identifier: Apache-2.0
12+
//
13+
//===----------------------------------------------------------------------===//
14+
15+
import Foundation
16+
17+
/// Prepares a diagnostics collector.
18+
/// - Parameter outputPath: A file path where to persist the YAML file. If `nil`, diagnostics will be printed to stderr.
19+
/// - Returns: A tuple containing:
20+
/// - An instance of `DiagnosticCollector` conforming to `Sendable`.
21+
/// - A closure to finalize the diagnostics collection
22+
public func preparedDiagnosticsCollector(outputPath: URL?) -> (any DiagnosticCollector & Sendable, () throws -> Void) {
23+
let innerDiagnostics: any DiagnosticCollector & Sendable
24+
let finalizeDiagnostics: () throws -> Void
25+
26+
if let outputPath {
27+
let _diagnostics = _YamlFileDiagnosticsCollector(url: outputPath)
28+
finalizeDiagnostics = _diagnostics.finalize
29+
innerDiagnostics = _diagnostics
30+
} else {
31+
innerDiagnostics = StdErrPrintingDiagnosticCollector()
32+
finalizeDiagnostics = {}
33+
}
34+
let diagnostics = ErrorThrowingDiagnosticCollector(upstream: innerDiagnostics)
35+
return (diagnostics, finalizeDiagnostics)
36+
}

0 commit comments

Comments
 (0)