diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..995846d --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,21 @@ +name: ci +on: + push: + branches: ["main"] + pull_request: + branches: ["main"] +jobs: + lint: + runs-on: ubuntu-latest + container: swift:6.1 + steps: + - uses: actions/checkout@v4 + - run: swift format lint -rsp . + yamllint: + runs-on: ubuntu-latest + container: alpine:3.21 + steps: + - uses: actions/checkout@v4 + - run: apk update && apk add yamllint + - run: yamllint --version + - run: yamllint --strict --config-file .yamllint.yml . diff --git a/.swift-format b/.swift-format new file mode 100644 index 0000000..c203695 --- /dev/null +++ b/.swift-format @@ -0,0 +1,79 @@ +{ + "fileScopedDeclarationPrivacy" : { + "accessLevel" : "private" + }, + "indentConditionalCompilationBlocks" : true, + "indentSwitchCaseLabels" : false, + "indentation" : { + "spaces" : 4 + }, + "lineBreakAroundMultilineExpressionChainComponents" : true, + "lineBreakBeforeControlFlowKeywords" : false, + "lineBreakBeforeEachArgument" : true, + "lineBreakBeforeEachGenericRequirement" : true, + "lineBreakBetweenDeclarationAttributes" : false, + "lineLength" : 120, + "maximumBlankLines" : 1, + "multiElementCollectionTrailingCommas" : true, + "noAssignmentInExpressions" : { + "allowedFunctions" : [ + "XCTAssertNoThrow" + ] + }, + "prioritizeKeepingFunctionOutputTogether" : true, + "reflowMultilineStringLiterals" : { + "never" : { + + } + }, + "respectsExistingLineBreaks" : true, + "rules" : { + "AllPublicDeclarationsHaveDocumentation" : false, + "AlwaysUseLiteralForEmptyCollectionInit" : true, + "AlwaysUseLowerCamelCase" : true, + "AmbiguousTrailingClosureOverload" : true, + "AvoidRetroactiveConformances" : false, + "BeginDocumentationCommentWithOneLineSummary" : true, + "DoNotUseSemicolons" : true, + "DontRepeatTypeInStaticProperties" : true, + "FileScopedDeclarationPrivacy" : true, + "FullyIndirectEnum" : true, + "GroupNumericLiterals" : true, + "IdentifiersMustBeASCII" : true, + "NeverForceUnwrap" : false, + "NeverUseForceTry" : true, + "NeverUseImplicitlyUnwrappedOptionals" : true, + "NoAccessLevelOnExtensionDeclaration" : true, + "NoAssignmentInExpressions" : true, + "NoBlockComments" : true, + "NoCasesWithOnlyFallthrough" : true, + "NoEmptyLinesOpeningClosingBraces" : true, + "NoEmptyTrailingClosureParentheses" : true, + "NoLabelsInCasePatterns" : true, + "NoLeadingUnderscores" : true, + "NoParensAroundConditions" : true, + "NoPlaygroundLiterals" : true, + "NoVoidReturnOnFunctionSignature" : true, + "OmitExplicitReturns" : true, + "OneCasePerLine" : true, + "OneVariableDeclarationPerLine" : true, + "OnlyOneTrailingClosureArgument" : true, + "OrderedImports" : true, + "ReplaceForEachWithForLoop" : true, + "ReturnVoidInsteadOfEmptyTuple" : true, + "TypeNamesShouldBeCapitalized" : true, + "UseEarlyExits" : true, + "UseExplicitNilCheckInConditions" : true, + "UseLetInEveryBoundCaseVariable" : true, + "UseShorthandTypeNames" : true, + "UseSingleLinePropertyGetter" : true, + "UseSynthesizedInitializer" : true, + "UseTripleSlashForDocumentationComments" : true, + "UseWhereClausesInForLoops" : true, + "ValidateDocumentationComments" : true + }, + "spacesAroundRangeFormationOperators" : false, + "spacesBeforeEndOfLineComments" : 2, + "tabWidth" : 4, + "version" : 1 +} diff --git a/.yamllint.yml b/.yamllint.yml new file mode 100644 index 0000000..74e1046 --- /dev/null +++ b/.yamllint.yml @@ -0,0 +1,7 @@ +extends: default + +rules: + line-length: false + document-start: false + truthy: + check-keys: false diff --git a/DNSecure/DNSecureApp.swift b/DNSecure/DNSecureApp.swift index 2ccd33b..383cbfd 100644 --- a/DNSecure/DNSecureApp.swift +++ b/DNSecure/DNSecureApp.swift @@ -5,8 +5,8 @@ // Created by Kenta Kubo on 7/1/20. // -import os.log import SwiftUI +import os.log let logger = Logger() diff --git a/DNSecure/Extensions/NEOnDemandRuleInterfaceType+CustomStringConvertible.swift b/DNSecure/Extensions/NEOnDemandRuleInterfaceType+CustomStringConvertible.swift index fba75cc..e720a8b 100644 --- a/DNSecure/Extensions/NEOnDemandRuleInterfaceType+CustomStringConvertible.swift +++ b/DNSecure/Extensions/NEOnDemandRuleInterfaceType+CustomStringConvertible.swift @@ -13,14 +13,14 @@ extension NEOnDemandRuleInterfaceType: @retroactive CustomStringConvertible { case .any: return "Any" #if os(macOS) - case .ethernet: - return "Ethernet" + case .ethernet: + return "Ethernet" #endif case .wiFi: return "Wi-Fi" #if os(iOS) - case .cellular: - return "Cellular" + case .cellular: + return "Cellular" #endif default: return "Unknown" diff --git a/DNSecure/Models/Presets.swift b/DNSecure/Models/Presets.swift index 25092b7..785016b 100644 --- a/DNSecure/Models/Presets.swift +++ b/DNSecure/Models/Presets.swift @@ -126,7 +126,7 @@ enum Presets { configuration: .dnsOverTLS( DoTConfiguration( servers: [ - "116.202.176.26", + "116.202.176.26" ], serverName: "dot.libredns.gr" ) @@ -137,7 +137,7 @@ enum Presets { configuration: .dnsOverHTTPS( DoHConfiguration( servers: [ - "116.202.176.26", + "116.202.176.26" ], serverURL: URL(string: "https://doh.libredns.gr/dns-query") ) @@ -148,7 +148,7 @@ enum Presets { configuration: .dnsOverHTTPS( DoHConfiguration( servers: [ - "116.202.176.26", + "116.202.176.26" ], serverURL: URL(string: "https://doh.libredns.gr/ads") ) diff --git a/DNSecure/Models/Resolver.swift b/DNSecure/Models/Resolver.swift index 547bd4f..56b7e8c 100644 --- a/DNSecure/Models/Resolver.swift +++ b/DNSecure/Models/Resolver.swift @@ -48,9 +48,9 @@ enum Configuration { func toDNSSettings() -> NEDNSSettings { switch self { - case let .dnsOverTLS(configuration): + case .dnsOverTLS(let configuration): return configuration.toDNSSettings() - case let .dnsOverHTTPS(configuration): + case .dnsOverHTTPS(let configuration): return configuration.toDNSSettings() } } @@ -87,10 +87,10 @@ extension Configuration: Codable { var container = encoder.container(keyedBy: Self.CodingKeys.self) switch self { - case let .dnsOverTLS(configuration): + case .dnsOverTLS(let configuration): try container.encode(Self.Base.dnsOverTLS, forKey: .base) try container.encode(configuration, forKey: .dotConfiguration) - case let .dnsOverHTTPS(configuration): + case .dnsOverHTTPS(let configuration): try container.encode(Self.Base.dnsOverHTTPS, forKey: .base) try container.encode(configuration, forKey: .dohConfiguration) } @@ -200,10 +200,11 @@ extension Resolver: Codable { self.id = try container.decode(UUID.self, forKey: .id) self.name = try container.decode(String.self, forKey: .name) self.configuration = try container.decode(Configuration.self, forKey: .configuration) - self.onDemandRules = try container.decodeIfPresent( - [OnDemandRule].self, - forKey: .onDemandRules - ) ?? [] + self.onDemandRules = + try container.decodeIfPresent( + [OnDemandRule].self, + forKey: .onDemandRules + ) ?? [] } } @@ -218,7 +219,7 @@ extension Resolvers { extension Resolvers: @retroactive RawRepresentable { public init?(rawValue: String) { guard let data = rawValue.data(using: .utf8), - let result = try? JSONDecoder().decode(Self.self, from: data) + let result = try? JSONDecoder().decode(Self.self, from: data) else { return nil } @@ -227,7 +228,7 @@ extension Resolvers: @retroactive RawRepresentable { public var rawValue: String { guard let data = try? JSONEncoder().encode(self), - let result = String(data: data, encoding: .utf8) + let result = String(data: data, encoding: .utf8) else { return "[]" } diff --git a/DNSecure/Views/ContentView.swift b/DNSecure/Views/ContentView.swift index 6e129c8..ed4e0d2 100644 --- a/DNSecure/Views/ContentView.swift +++ b/DNSecure/Views/ContentView.swift @@ -90,8 +90,10 @@ struct ContentView { manager.onDemandRules = server.onDemandRules.toNEOnDemandRules() manager.saveToPreferences { saveError in if let saveError = saveError as NSError? { - guard saveError.domain != "NEConfigurationErrorDomain" - || saveError.code != 9 else { + guard + saveError.domain != "NEConfigurationErrorDomain" + || saveError.code != 9 + else { // Nothing was changed return } @@ -187,8 +189,9 @@ extension ContentView: View { // FIXME: This is a workaround for self.$severs[i]. // That cannot save settings as soon as it is modified. guard let id = self.usedID, - let uuid = UUID(uuidString: id), - let server = self.servers.find(by: uuid) else { + let uuid = UUID(uuidString: id), + let server = self.servers.find(by: uuid) + else { return } self.saveSettings(of: server) @@ -263,8 +266,9 @@ extension ContentView: View { // FIXME: This is a workaround for self.$severs[i]. // That cannot save settings as soon as it is modified. guard let id = self.usedID, - let uuid = UUID(uuidString: id), - let server = self.servers.find(by: uuid) else { + let uuid = UUID(uuidString: id), + let server = self.servers.find(by: uuid) + else { return } self.saveSettings(of: server) diff --git a/DNSecure/Views/RestorationView.swift b/DNSecure/Views/RestorationView.swift index 1eb6b3b..d2a4e43 100644 --- a/DNSecure/Views/RestorationView.swift +++ b/DNSecure/Views/RestorationView.swift @@ -11,7 +11,7 @@ struct RestorationView { @Environment(\.dismiss) private var dismiss @State private var selection = Set() @State private var keyword = "" - let onAdd: (Set) -> () + let onAdd: (Set) -> Void private var servers: Resolvers { guard !self.keyword.isEmpty else { return Presets.servers } diff --git a/DNSecure/Views/RuleView.swift b/DNSecure/Views/RuleView.swift index c7e3c2b..009eb99 100644 --- a/DNSecure/Views/RuleView.swift +++ b/DNSecure/Views/RuleView.swift @@ -36,7 +36,9 @@ extension RuleView: View { } header: { Text("Interface Type Match") } footer: { - Text("If the current primary network interface is of this type and all of the other conditions in the rule match, then the rule matches.") + Text( + "If the current primary network interface is of this type and all of the other conditions in the rule match, then the rule matches." + ) } if self.rule.interfaceType.ssidIsUsed { @@ -65,7 +67,9 @@ extension RuleView: View { Text("SSID Match") } } footer: { - Text("If the Service Set Identifier (SSID) of the current primary connected network matches one of the strings in this array and all of the other conditions in the rule match, then the rule matches.") + Text( + "If the Service Set Identifier (SSID) of the current primary connected network matches one of the strings in this array and all of the other conditions in the rule match, then the rule matches." + ) } } @@ -92,7 +96,9 @@ extension RuleView: View { Text("DNS Search Domain Match") } } footer: { - Text("If the current default search domain is equal to one of the strings in this array and all of the other conditions in the rule match, then the rule matches.") + Text( + "If the current default search domain is equal to one of the strings in this array and all of the other conditions in the rule match, then the rule matches." + ) } Section { @@ -118,7 +124,9 @@ extension RuleView: View { Text("DNS Server Address Match") } } footer: { - Text("If each of the current default DNS servers is equal to one of the strings in this array and all of the other conditions in the rule match, then the rule matches.") + Text( + "If each of the current default DNS servers is equal to one of the strings in this array and all of the other conditions in the rule match, then the rule matches." + ) } Section { @@ -132,7 +140,9 @@ extension RuleView: View { } header: { Text("Probe URL Match") } footer: { - Text("If a request sent to this URL results in a HTTP 200 OK response and all of the other conditions in the rule match, then the rule matches. If you don't want to use this rule, leave it empty.") + Text( + "If a request sent to this URL results in a HTTP 200 OK response and all of the other conditions in the rule match, then the rule matches. If you don't want to use this rule, leave it empty." + ) } } .navigationTitle(self.rule.name) diff --git a/DNSecureTests/DNSecureTests.swift b/DNSecureTests/DNSecureTests.swift index 92fb5d4..ddcb59b 100644 --- a/DNSecureTests/DNSecureTests.swift +++ b/DNSecureTests/DNSecureTests.swift @@ -6,10 +6,10 @@ // import XCTest + @testable import DNSecure class DNSecureTests: XCTestCase { - override func setUpWithError() throws { // Put setup code here. This method is called before the invocation of each test method in the class. } @@ -29,5 +29,4 @@ class DNSecureTests: XCTestCase { // Put the code you want to measure the time of here. } } - } diff --git a/DNSecureUITests/DNSecureUITests.swift b/DNSecureUITests/DNSecureUITests.swift index 914ad16..2eba5b7 100644 --- a/DNSecureUITests/DNSecureUITests.swift +++ b/DNSecureUITests/DNSecureUITests.swift @@ -8,7 +8,6 @@ import XCTest class DNSecureUITests: XCTestCase { - override func setUpWithError() throws { // Put setup code here. This method is called before the invocation of each test method in the class. diff --git a/Package.swift b/Package.swift index d7f024a..fc85293 100644 --- a/Package.swift +++ b/Package.swift @@ -4,8 +4,8 @@ // This file is automatically generated. // Do not edit it by hand because the contents will be replaced. -import PackageDescription import AppleProductTypes +import PackageDescription let package = Package( name: "DNSecure", @@ -24,13 +24,13 @@ let package = Package( accentColor: .asset("AccentColor"), supportedDeviceFamilies: [ .pad, - .phone + .phone, ], supportedInterfaceOrientations: [ .portrait, .landscapeRight, .landscapeLeft, - .portraitUpsideDown(.when(deviceFamilies: [.pad])) + .portraitUpsideDown(.when(deviceFamilies: [.pad])), ], appCategory: .utilities ) @@ -46,6 +46,6 @@ let package = Package( "DNSecure" ], path: "DNSecureTests" - ) + ), ] )