diff --git a/.github/workflows/danger.yml b/.github/workflows/danger.yml
index 438ef9d..fe496a8 100644
--- a/.github/workflows/danger.yml
+++ b/.github/workflows/danger.yml
@@ -20,7 +20,7 @@ jobs:
- name: Setup Danger
run: |
- git clone https://github.com/MaatheusGois/DangerSwift && rm -rf DangerSwift/.git
+ git clone https://github.com/MaatheusGois/DangerSwift && rm -rf DangerSwift/.git Readme.md
mv DangerSwift/* .
- name: Test Stage
diff --git a/.swiftlint.yml b/.swiftlint.yml
new file mode 100644
index 0000000..0beddc5
--- /dev/null
+++ b/.swiftlint.yml
@@ -0,0 +1,98 @@
+included:
+ - Plugins
+ - Source
+ - Tests
+
+excluded:
+ - Tests
+
+analyzer_rules:
+ - unused_declaration
+ - unused_import
+
+opt_in_rules:
+ - all
+
+disabled_rules:
+ - anonymous_argument_in_multiline_closure
+ - anyobject_protocol
+ - closure_body_length
+ - conditional_returns_on_newline
+ - convenience_type
+ - discouraged_optional_collection
+ - explicit_acl
+ - explicit_enum_raw_value
+ - explicit_top_level_acl
+ - explicit_type_interface
+ - file_types_order
+ - final_test_case
+ - force_unwrapping
+ - function_default_parameter_at_end
+ - implicit_return
+ - implicitly_unwrapped_optional
+ - indentation_width
+ - inert_defer
+ - missing_docs
+ - multiline_arguments
+ - multiline_arguments_brackets
+ - multiline_function_chains
+ - multiline_literal_brackets
+ - multiline_parameters
+ - multiline_parameters_brackets
+ - no_extension_access_modifier
+ - no_fallthrough_only
+ - no_grouping_extension
+ - no_magic_numbers
+ - one_declaration_per_file
+ - prefer_nimble
+ - prefer_self_in_static_references
+ - prefixed_toplevel_constant
+ - redundant_self_in_closure
+ - required_deinit
+ - self_binding
+ - static_over_final_class
+ - shorthand_argument
+ - sorted_enum_cases
+ - strict_fileprivate
+ - switch_case_on_newline
+ - todo
+ - trailing_closure
+ - type_contents_order
+ - unused_capture_list
+ - vertical_whitespace_between_cases
+
+attributes:
+ always_on_line_above:
+ - "@ConfigurationElement"
+ - "@OptionGroup"
+ - "@RuleConfigurationDescriptionBuilder"
+
+identifier_name:
+ excluded:
+ - id
+large_tuple: 3
+
+number_separator:
+ minimum_length: 5
+
+file_name:
+ excluded:
+ - Exports.swift
+ - GeneratedTests.swift
+ - RuleConfigurationMacros.swift
+ - SwiftSyntax+SwiftLint.swift
+ - TestHelpers.swift
+
+unneeded_override:
+ affect_initializers: true
+
+balanced_xctest_lifecycle: &unit_test_configuration
+ test_parent_classes:
+ - SwiftLintTestCase
+ - XCTestCase
+
+empty_xctest_method: *unit_test_configuration
+single_test_class: *unit_test_configuration
+
+function_body_length: 60
+type_body_length: 400
diff --git a/Dangerfile.swift b/Dangerfile.swift
new file mode 100644
index 0000000..c2fe141
--- /dev/null
+++ b/Dangerfile.swift
@@ -0,0 +1,223 @@
+// MARK: Imports
+
+import Danger
+import DangerSwiftCoverage
+import DangerXCodeSummary
+import Foundation
+
+// MARK: Validate
+
+Validator.shared.validate()
+
+// MARK: Lint
+
+SwiftLint.lint(configFile: ".swiftlint.yml")
+
+// MARK: Validation rules
+
+internal class Validator {
+ // MARK: Lifecycle
+ // Private initializer and shared instance for Validator.
+
+ private init() {}
+ internal static let shared = Validator()
+ private var danger = Danger()
+
+ // MARK: Properties
+ // Properties related to PR details and changes.
+
+ private lazy var additions = danger.github.pullRequest.additions!
+ private lazy var deletions = danger.github.pullRequest.deletions!
+ private lazy var changedFiles = danger.github.pullRequest.changedFiles!
+
+ private lazy var modified = danger.git.modifiedFiles
+ private lazy var editedFiles = modified + danger.git.createdFiles
+ private lazy var prTitle = danger.github.pullRequest.title
+
+ private lazy var branchHeadName = danger.github.pullRequest.head.ref
+ private lazy var branchBaseName = danger.github.pullRequest.base.ref
+
+ // Methods
+ // Methods for various validation checks.
+
+ internal func validate() {
+ checkSize()
+ checkDescription()
+ checkUnitTest()
+ checkTitle()
+ checkAssignee()
+ checkModifiedFiles()
+ checkFails()
+
+ logResume()
+ }
+}
+
+internal class DescriptionValidator {
+ // MARK: Lifecycle
+ // Private initializer and shared instance for DescriptionValidator.
+
+ private init() {}
+ internal static let shared = DescriptionValidator()
+ private var danger = Danger()
+
+ // MARK: Properties
+ // Property to store the PR body.
+
+ private lazy var body = danger.github.pullRequest.body ?? ""
+
+ // Methods
+ // Method to validate PR description.
+
+ internal func validate() {
+ let message = "PR does not have a description. You must provide a description of the changes made."
+
+ guard !body.isEmpty else {
+ return fail(message)
+ }
+ }
+}
+
+internal class UnitTestValidator {
+ // MARK: Lifecycle
+ // Private initializer and shared instance for UnitTestValidator.
+
+ private init() {}
+ internal static let shared = UnitTestValidator()
+ private var danger = Danger()
+
+ // Methods
+ // Methods for unit test validation.
+
+ internal func validate() {
+ checkUnitTestSummary()
+ checkUnitTestCoverage()
+ }
+}
+
+// MARK: Validator Methods
+// Extension with methods for Validator class.
+
+fileprivate extension Validator {
+ func checkSize() {
+ if (additions + deletions) > ValidationRules.bigPRThreshold {
+ let message =
+ """
+ The size of the PR seems relatively large. \
+ If possible, in the future if the PR contains multiple changes, split each into a separate PR. \
+ This helps in faster and easier review.
+ """
+ warn(message)
+ }
+ }
+
+ func checkDescription() {
+ DescriptionValidator.shared.validate()
+ }
+
+ func checkUnitTest() {
+ UnitTestValidator.shared.validate()
+ }
+
+ func checkTitle() {
+ let result = prTitle.range(
+ of: #"\[[A-zÀ-ú0-9 ]*\][A-zÀ-ú0-9- ]+"#,
+ options: .regularExpression
+ ) != nil
+
+ if !result {
+ let message = "The PR title should be: [Feature or Flow] What flow was done"
+ warn(message)
+ }
+ }
+
+ func checkAssignee() {
+ if danger.github.pullRequest.assignee == nil {
+ warn("Please assign yourself to the PR.")
+ }
+ }
+
+ func checkModifiedFiles() {
+ if changedFiles > ValidationRules.maxChangedFiles {
+ let message =
+ """
+ PR contains too many changed files. If possible, next time try to split into smaller features.
+ """
+ warn(message)
+ }
+ }
+
+ func checkFails() {
+ if !danger.fails.isEmpty {
+ _ = danger.utils.exec("touch Danger-has-fails.swift")
+ }
+ }
+
+ func logResume() {
+ let overview =
+ """
+ The PR added \(additions) and removed \(deletions) lines. \(changedFiles) file(s) changed.
+ """
+
+ let seeOurDocumentation =
+ """
+ Example Link:
\
+ \
+ Link
+ """
+
+ message(seeOurDocumentation)
+ message(overview)
+ }
+}
+
+// MARK: Constants
+// Constants related to validation rules.
+
+private enum ValidationRules {
+ static let maxChangedFiles = 20
+ static let bigPRThreshold = 3000
+}
+
+// MARK: Extensions
+// Extension with additional file-related methods.
+
+fileprivate extension Danger.File {
+ var isInSources: Bool { hasPrefix("Sources/") }
+ var isInTests: Bool { hasPrefix("Tests/") }
+
+ var isSourceFile: Bool {
+ hasSuffix(".swift") || hasSuffix(".h") || hasSuffix(".m")
+ }
+
+ var isSwiftPackageDefintion: Bool {
+ hasPrefix("Package") && hasSuffix(".swift")
+ }
+
+ var isDangerfile: Bool {
+ self == "Dangerfile.swift"
+ }
+}
+
+// MARK: UnitTestValidator Methods
+// Extension with methods for UnitTestValidator class.
+
+fileprivate extension UnitTestValidator {
+ func checkUnitTestSummary() {
+ let file = "build/reports/errors.json"
+ if FileManager.default.fileExists(atPath: file) {
+ let summary = XCodeSummary(filePath: file) { result in
+ result.category != .warning
+ }
+ summary.report()
+ }
+ }
+
+ func checkUnitTestCoverage() {
+ Coverage.xcodeBuildCoverage(
+ .xcresultBundle("fastlane/test_output/Example.xcresult"),
+ minimumCoverage: 70,
+ excludedTargets: ["DangerSwiftCoverageTests.xctest"]
+ )
+ }
+}
diff --git a/Example.xcodeproj/project.pbxproj b/Example.xcodeproj/project.pbxproj
index 424c127..45cefb6 100644
--- a/Example.xcodeproj/project.pbxproj
+++ b/Example.xcodeproj/project.pbxproj
@@ -13,12 +13,11 @@
2E0B58C52BC046CE00049F34 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 2E0B58C42BC046CE00049F34 /* Assets.xcassets */; };
2E0B58C92BC046CE00049F34 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 2E0B58C82BC046CE00049F34 /* Preview Assets.xcassets */; };
2E0B58EC2BC0483C00049F34 /* ContentViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2E0B58EB2BC0483C00049F34 /* ContentViewModel.swift */; };
- 2EC7DFDA2C126860005E58DF /* ViewModel.Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2EC7DFC72C1267F1005E58DF /* ViewModel.Tests.swift */; };
- 2EC7DFDB2C126860005E58DF /* Tests+Helpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2EC7DFC82C1267F1005E58DF /* Tests+Helpers.swift */; };
+ 2EC7DFE42C12726D005E58DF /* Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2EC7DFE32C12726D005E58DF /* Tests.swift */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
- 2EC7DFD52C12685B005E58DF /* PBXContainerItemProxy */ = {
+ 2EC7DFE52C12726D005E58DF /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 2E0B58B32BC046CC00049F34 /* Project object */;
proxyType = 1;
@@ -36,9 +35,9 @@
2E0B58C62BC046CE00049F34 /* Example.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Example.entitlements; sourceTree = ""; };
2E0B58C82BC046CE00049F34 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = ""; };
2E0B58EB2BC0483C00049F34 /* ContentViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentViewModel.swift; sourceTree = ""; };
- 2EC7DFC72C1267F1005E58DF /* ViewModel.Tests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ViewModel.Tests.swift; sourceTree = ""; };
- 2EC7DFC82C1267F1005E58DF /* Tests+Helpers.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Tests+Helpers.swift"; sourceTree = ""; };
- 2EC7DFD12C12685B005E58DF /* Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = Tests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
+ 2EC7DFE12C12726D005E58DF /* Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = Tests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
+ 2EC7DFE32C12726D005E58DF /* Tests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Tests.swift; sourceTree = ""; };
+ 2EC7DFEA2C1272BA005E58DF /* Tests.xctestplan */ = {isa = PBXFileReference; lastKnownFileType = text; path = Tests.xctestplan; sourceTree = ""; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@@ -49,7 +48,7 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
- 2EC7DFCE2C12685B005E58DF /* Frameworks */ = {
+ 2EC7DFDE2C12726D005E58DF /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
@@ -63,7 +62,7 @@
isa = PBXGroup;
children = (
2E0B58BD2BC046CC00049F34 /* Example */,
- 2EC7DFD22C12685B005E58DF /* Tests */,
+ 2EC7DFE22C12726D005E58DF /* Tests */,
2E0B58BC2BC046CC00049F34 /* Products */,
);
sourceTree = "";
@@ -72,7 +71,7 @@
isa = PBXGroup;
children = (
2E0B58BB2BC046CC00049F34 /* Example.app */,
- 2EC7DFD12C12685B005E58DF /* Tests.xctest */,
+ 2EC7DFE12C12726D005E58DF /* Tests.xctest */,
);
name = Products;
sourceTree = "";
@@ -107,11 +106,11 @@
path = Content;
sourceTree = "";
};
- 2EC7DFD22C12685B005E58DF /* Tests */ = {
+ 2EC7DFE22C12726D005E58DF /* Tests */ = {
isa = PBXGroup;
children = (
- 2EC7DFC72C1267F1005E58DF /* ViewModel.Tests.swift */,
- 2EC7DFC82C1267F1005E58DF /* Tests+Helpers.swift */,
+ 2EC7DFEA2C1272BA005E58DF /* Tests.xctestplan */,
+ 2EC7DFE32C12726D005E58DF /* Tests.swift */,
);
path = Tests;
sourceTree = "";
@@ -136,22 +135,22 @@
productReference = 2E0B58BB2BC046CC00049F34 /* Example.app */;
productType = "com.apple.product-type.application";
};
- 2EC7DFD02C12685B005E58DF /* Tests */ = {
+ 2EC7DFE02C12726D005E58DF /* Tests */ = {
isa = PBXNativeTarget;
- buildConfigurationList = 2EC7DFD72C12685B005E58DF /* Build configuration list for PBXNativeTarget "Tests" */;
+ buildConfigurationList = 2EC7DFE72C12726D005E58DF /* Build configuration list for PBXNativeTarget "Tests" */;
buildPhases = (
- 2EC7DFCD2C12685B005E58DF /* Sources */,
- 2EC7DFCE2C12685B005E58DF /* Frameworks */,
- 2EC7DFCF2C12685B005E58DF /* Resources */,
+ 2EC7DFDD2C12726D005E58DF /* Sources */,
+ 2EC7DFDE2C12726D005E58DF /* Frameworks */,
+ 2EC7DFDF2C12726D005E58DF /* Resources */,
);
buildRules = (
);
dependencies = (
- 2EC7DFD62C12685B005E58DF /* PBXTargetDependency */,
+ 2EC7DFE62C12726D005E58DF /* PBXTargetDependency */,
);
name = Tests;
productName = Tests;
- productReference = 2EC7DFD12C12685B005E58DF /* Tests.xctest */;
+ productReference = 2EC7DFE12C12726D005E58DF /* Tests.xctest */;
productType = "com.apple.product-type.bundle.unit-test";
};
/* End PBXNativeTarget section */
@@ -167,7 +166,7 @@
2E0B58BA2BC046CC00049F34 = {
CreatedOnToolsVersion = 15.3;
};
- 2EC7DFD02C12685B005E58DF = {
+ 2EC7DFE02C12726D005E58DF = {
CreatedOnToolsVersion = 15.4;
TestTargetID = 2E0B58BA2BC046CC00049F34;
};
@@ -187,7 +186,7 @@
projectRoot = "";
targets = (
2E0B58BA2BC046CC00049F34 /* Example */,
- 2EC7DFD02C12685B005E58DF /* Tests */,
+ 2EC7DFE02C12726D005E58DF /* Tests */,
);
};
/* End PBXProject section */
@@ -202,7 +201,7 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
- 2EC7DFCF2C12685B005E58DF /* Resources */ = {
+ 2EC7DFDF2C12726D005E58DF /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
@@ -223,22 +222,21 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
- 2EC7DFCD2C12685B005E58DF /* Sources */ = {
+ 2EC7DFDD2C12726D005E58DF /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
- 2EC7DFDA2C126860005E58DF /* ViewModel.Tests.swift in Sources */,
- 2EC7DFDB2C126860005E58DF /* Tests+Helpers.swift in Sources */,
+ 2EC7DFE42C12726D005E58DF /* Tests.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin PBXTargetDependency section */
- 2EC7DFD62C12685B005E58DF /* PBXTargetDependency */ = {
+ 2EC7DFE62C12726D005E58DF /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = 2E0B58BA2BC046CC00049F34 /* Example */;
- targetProxy = 2EC7DFD52C12685B005E58DF /* PBXContainerItemProxy */;
+ targetProxy = 2EC7DFE52C12726D005E58DF /* PBXContainerItemProxy */;
};
/* End PBXTargetDependency section */
@@ -301,6 +299,7 @@
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
ONLY_ACTIVE_ARCH = YES;
+ SUPPORTED_PLATFORMS = "iphonesimulator iphoneos";
SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)";
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
};
@@ -357,6 +356,7 @@
MACOSX_DEPLOYMENT_TARGET = 13.0;
MTL_ENABLE_DEBUG_INFO = NO;
MTL_FAST_MATH = YES;
+ SUPPORTED_PLATFORMS = "iphonesimulator iphoneos";
SWIFT_COMPILATION_MODE = wholemodule;
};
name = Release;
@@ -366,9 +366,11 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
+ CODE_SIGN_IDENTITY = "-";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_ASSET_PATHS = "\"Example/Preview Content\"";
+ DEVELOPMENT_TEAM = "";
ENABLE_PREVIEWS = YES;
GENERATE_INFOPLIST_FILE = YES;
"INFOPLIST_KEY_UIApplicationSceneManifest_Generation[sdk=iphoneos*]" = YES;
@@ -388,12 +390,13 @@
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.maatheusgois.Example;
PRODUCT_NAME = "$(TARGET_NAME)";
+ PROVISIONING_PROFILE_SPECIFIER = "";
SDKROOT = auto;
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
SUPPORTS_MACCATALYST = NO;
SWIFT_EMIT_LOC_STRINGS = YES;
SWIFT_VERSION = 5.0;
- TARGETED_DEVICE_FAMILY = "1,2";
+ TARGETED_DEVICE_FAMILY = 1;
};
name = Debug;
};
@@ -402,9 +405,11 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
+ CODE_SIGN_IDENTITY = "-";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_ASSET_PATHS = "\"Example/Preview Content\"";
+ DEVELOPMENT_TEAM = "";
ENABLE_PREVIEWS = YES;
GENERATE_INFOPLIST_FILE = YES;
"INFOPLIST_KEY_UIApplicationSceneManifest_Generation[sdk=iphoneos*]" = YES;
@@ -424,53 +429,56 @@
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.maatheusgois.Example;
PRODUCT_NAME = "$(TARGET_NAME)";
+ PROVISIONING_PROFILE_SPECIFIER = "";
SDKROOT = auto;
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
SUPPORTS_MACCATALYST = NO;
SWIFT_EMIT_LOC_STRINGS = YES;
SWIFT_VERSION = 5.0;
- TARGETED_DEVICE_FAMILY = "1,2";
+ TARGETED_DEVICE_FAMILY = 1;
};
name = Release;
};
- 2EC7DFD82C12685B005E58DF /* Debug */ = {
+ 2EC7DFE82C12726D005E58DF /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
GENERATE_INFOPLIST_FILE = YES;
- IPHONEOS_DEPLOYMENT_TARGET = 17.5;
+ IPHONEOS_DEPLOYMENT_TARGET = 17.0;
MACOSX_DEPLOYMENT_TARGET = 14.0;
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.maatheusgois.Tests;
PRODUCT_NAME = "$(TARGET_NAME)";
SDKROOT = auto;
- SUPPORTED_PLATFORMS = "iphoneos iphonesimulator macosx";
+ SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
+ SUPPORTS_MACCATALYST = NO;
SWIFT_EMIT_LOC_STRINGS = NO;
SWIFT_VERSION = 5.0;
- TARGETED_DEVICE_FAMILY = "1,2";
+ TARGETED_DEVICE_FAMILY = 1;
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Example.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Example";
};
name = Debug;
};
- 2EC7DFD92C12685B005E58DF /* Release */ = {
+ 2EC7DFE92C12726D005E58DF /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
GENERATE_INFOPLIST_FILE = YES;
- IPHONEOS_DEPLOYMENT_TARGET = 17.5;
+ IPHONEOS_DEPLOYMENT_TARGET = 17.0;
MACOSX_DEPLOYMENT_TARGET = 14.0;
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.maatheusgois.Tests;
PRODUCT_NAME = "$(TARGET_NAME)";
SDKROOT = auto;
- SUPPORTED_PLATFORMS = "iphoneos iphonesimulator macosx";
+ SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
+ SUPPORTS_MACCATALYST = NO;
SWIFT_EMIT_LOC_STRINGS = NO;
SWIFT_VERSION = 5.0;
- TARGETED_DEVICE_FAMILY = "1,2";
+ TARGETED_DEVICE_FAMILY = 1;
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Example.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Example";
};
name = Release;
@@ -485,7 +493,7 @@
2E0B58E12BC046CF00049F34 /* Release */,
);
defaultConfigurationIsVisible = 0;
- defaultConfigurationName = Release;
+ defaultConfigurationName = Debug;
};
2E0B58E22BC046CF00049F34 /* Build configuration list for PBXNativeTarget "Example" */ = {
isa = XCConfigurationList;
@@ -494,16 +502,16 @@
2E0B58E42BC046CF00049F34 /* Release */,
);
defaultConfigurationIsVisible = 0;
- defaultConfigurationName = Release;
+ defaultConfigurationName = Debug;
};
- 2EC7DFD72C12685B005E58DF /* Build configuration list for PBXNativeTarget "Tests" */ = {
+ 2EC7DFE72C12726D005E58DF /* Build configuration list for PBXNativeTarget "Tests" */ = {
isa = XCConfigurationList;
buildConfigurations = (
- 2EC7DFD82C12685B005E58DF /* Debug */,
- 2EC7DFD92C12685B005E58DF /* Release */,
+ 2EC7DFE82C12726D005E58DF /* Debug */,
+ 2EC7DFE92C12726D005E58DF /* Release */,
);
defaultConfigurationIsVisible = 0;
- defaultConfigurationName = Release;
+ defaultConfigurationName = Debug;
};
/* End XCConfigurationList section */
};
diff --git a/Example.xcodeproj/project.xcworkspace/xcuserdata/goisma.xcuserdatad/UserInterfaceState.xcuserstate b/Example.xcodeproj/project.xcworkspace/xcuserdata/goisma.xcuserdatad/UserInterfaceState.xcuserstate
index a99c4c7..207f882 100644
Binary files a/Example.xcodeproj/project.xcworkspace/xcuserdata/goisma.xcuserdatad/UserInterfaceState.xcuserstate and b/Example.xcodeproj/project.xcworkspace/xcuserdata/goisma.xcuserdatad/UserInterfaceState.xcuserstate differ
diff --git a/Example.xcodeproj/xcshareddata/xcschemes/Example.xcscheme b/Example.xcodeproj/xcshareddata/xcschemes/Example.xcscheme
index 2ef4d6a..e7a6c0e 100644
--- a/Example.xcodeproj/xcshareddata/xcschemes/Example.xcscheme
+++ b/Example.xcodeproj/xcshareddata/xcschemes/Example.xcscheme
@@ -40,7 +40,7 @@
parallelizable = "YES">
@@ -51,18 +51,7 @@
parallelizable = "YES">
-
-
-
-
@@ -97,6 +86,15 @@
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
+
+
+
+
diff --git a/LICENCE b/LICENCE
new file mode 100644
index 0000000..b2225ff
--- /dev/null
+++ b/LICENCE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2024 MaatheusGois
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..fe59365
--- /dev/null
+++ b/README.md
@@ -0,0 +1,50 @@
+# DangerSwift Actions
+
+
+
+# How to setup the code in your repo
+
+## 1. Create the Secrets
+
+Create this:
+
+
+
+With this permission:
+
+
+
+### Environment
+
+`TOKEN`
+
+Named by the git of `GITHUB_TOKEN`
+
+### Repository secrets
+`DANGER_GITHUB_API_TOKEN`
+
+
+
+
+---
+
+## 2. Create or copy from the example to your github:
+
+- `.github/workflows/danger.yml`
+- `.swiftlint.yml`
+- `Dangerfile.swift`
+
+## 3. Contribute
+We welcome contributions to improve this project! To contribute, please follow these steps:
+
+1. Fork the repository.
+2. Create a new branch for your feature or bug fix.
+3. Make your changes and commit them.
+4. Push your changes to your forked repository.
+5. Open a pull request to the main repository.
+
+Please ensure that your code follows the project's coding conventions and includes appropriate tests.
+
+## 4. License
+This project is licensed under the MIT License. You can find the full license text in the [LICENSE](https://github.com/MaatheusGois/DangerSwiftExample/blob/main/LICENSE) file.
+
diff --git a/Tests/Tests+Helpers.swift b/Tests/Tests+Helpers.swift
deleted file mode 100644
index d71207e..0000000
--- a/Tests/Tests+Helpers.swift
+++ /dev/null
@@ -1,33 +0,0 @@
-//
-// Tests.Helpers.swift
-// Example
-//
-// Created by Matheus Gois on 05/04/24.
-//
-
-import XCTest
-import SwiftData
-@testable import Example
-
-protocol ViewModelTestable {
- init(
- modelContext: ModelContext
- )
-}
-
-extension XCTestCase {
- @MainActor func make(
- viewModel: T.Type
- ) throws -> T {
- let config = ModelConfiguration(
- isStoredInMemoryOnly: true
- )
- let container = try ModelContainer(
- for: Item.self,
- configurations: config
- )
- return T(
- modelContext: container.mainContext
- )
- }
-}
diff --git a/Tests/Tests.swift b/Tests/Tests.swift
index 6b1d5bd..c2e8039 100644
--- a/Tests/Tests.swift
+++ b/Tests/Tests.swift
@@ -6,30 +6,90 @@
//
import XCTest
+import SwiftData
+@testable import Example
-final class Tests: XCTestCase {
+extension ContentView.ViewModel: ViewModelTestable {}
- override func setUpWithError() throws {
- // Put setup code here. This method is called before the invocation of each test method in the class.
- }
+final class ViewModelTests: XCTestCase {
+ @MainActor func testAppStartsEmpty() throws {
+ // Given
+ let sut = try make(
+ viewModel: ContentView.ViewModel.self
+ )
- override func tearDownWithError() throws {
- // Put teardown code here. This method is called after the invocation of each test method in the class.
+ // When & Then
+ XCTAssertEqual(
+ sut.items.count,
+ 0,
+ "There should be 0 items when the app is first launched."
+ )
}
- func testExample() throws {
- // This is an example of a functional test case.
- // Use XCTAssert and related functions to verify your tests produce the correct results.
- // Any test you write for XCTest can be annotated as throws and async.
- // Mark your test throws to produce an unexpected failure when your test encounters an uncaught error.
- // Mark your test async to allow awaiting for asynchronous code to complete. Check the results with assertions afterwards.
+ @MainActor func testCreatingSamplesWorks() throws {
+ // Given
+ let sut = try make(
+ viewModel: ContentView.ViewModel.self
+ )
+
+ // When
+ sut.addItem()
+ sut.addItem()
+ sut.addItem()
+
+ // Then
+ XCTAssertEqual(
+ sut.items.count,
+ 3,
+ "There should be 3 items after adding sample data."
+ )
}
- func testPerformanceExample() throws {
- // This is an example of a performance test case.
- measure {
- // Put the code you want to measure the time of here.
- }
+ @MainActor func testCreaatingAndRemoving() throws {
+ // Given
+ let sut = try make(
+ viewModel: ContentView.ViewModel.self
+ )
+
+ // When
+ sut.addItem()
+ sut.addItem()
+ sut.deleteItems(
+ offsets: .init(
+ integer: 0
+ )
+ )
+
+ // Then
+ XCTAssertEqual(
+ sut.items.count,
+ 1,
+ "There should be 1 items after adding sample data."
+ )
}
+}
+
+// MARK: - Helpers
+protocol ViewModelTestable {
+ init(
+ modelContext: ModelContext
+ )
+}
+
+extension XCTestCase {
+ @MainActor func make(
+ viewModel: T.Type
+ ) throws -> T {
+ let config = ModelConfiguration(
+ isStoredInMemoryOnly: true
+ )
+ let container = try ModelContainer(
+ for: Item.self,
+ configurations: config
+ )
+ return T(
+ modelContext: container.mainContext
+ )
+ }
}
diff --git a/Tests/Tests.xctestplan b/Tests/Tests.xctestplan
new file mode 100644
index 0000000..1f4315e
--- /dev/null
+++ b/Tests/Tests.xctestplan
@@ -0,0 +1,25 @@
+{
+ "configurations" : [
+ {
+ "id" : "C1740AFA-F6BF-4690-8C40-DD3519A8467B",
+ "name" : "Configuration 1",
+ "options" : {
+
+ }
+ }
+ ],
+ "defaultOptions" : {
+ "testTimeoutsEnabled" : true
+ },
+ "testTargets" : [
+ {
+ "parallelizable" : true,
+ "target" : {
+ "containerPath" : "container:Example.xcodeproj",
+ "identifier" : "2EC7DFE02C12726D005E58DF",
+ "name" : "Tests"
+ }
+ }
+ ],
+ "version" : 1
+}
diff --git a/Tests/ViewModel.Tests.swift b/Tests/ViewModel.Tests.swift
deleted file mode 100644
index 9d2c77a..0000000
--- a/Tests/ViewModel.Tests.swift
+++ /dev/null
@@ -1,70 +0,0 @@
-//
-// Tests_CITests.swift
-// Example
-//
-// Created by Matheus Gois on 05/04/24.
-//
-
-import XCTest
-import SwiftData
-@testable import Example
-
-extension ContentView.ViewModel: ViewModelTestable {}
-
-final class ViewModelTests: XCTestCase {
- @MainActor func testAppStartsEmpty() throws {
- // Given
- let sut = try make(
- viewModel: ContentView.ViewModel.self
- )
-
- // When & Then
- XCTAssertEqual(
- sut.items.count,
- 0,
- "There should be 0 items when the app is first launched."
- )
- }
-
- @MainActor func testCreatingSamplesWorks() throws {
- // Given
- let sut = try make(
- viewModel: ContentView.ViewModel.self
- )
-
- // When
- sut.addItem()
- sut.addItem()
- sut.addItem()
-
- // Then
- XCTAssertEqual(
- sut.items.count,
- 3,
- "There should be 3 items after adding sample data."
- )
- }
-
- @MainActor func testCreaatingAndRemoving() throws {
- // Given
- let sut = try make(
- viewModel: ContentView.ViewModel.self
- )
-
- // When
- sut.addItem()
- sut.addItem()
- sut.deleteItems(
- offsets: .init(
- integer: 0
- )
- )
-
- // Then
- XCTAssertEqual(
- sut.items.count,
- 1,
- "There should be 1 items after adding sample data."
- )
- }
-}