We've configured Danger in our main repository to help us prevent some mistakes we saw happening in the past and to assist us during code review.
The purpose of this file is to document all the rules we wrote in our Dangerfile
, what they mean and how to react to them when they are triggered.
If you plan to add a new Danger rule:
- Please follow the naming convention of starting the functions implementing the rules with
check_
- Make sure you keep the main
Dangerfile
clean: the main file is supposed to only callcheck_*
functions defined in other files, not to contain actual rule implementations - Make sure you document the new rule here
For a more in-depth presentation about Danger and how it works, see these slides (private company shared Drive).
The Danger website also has a pretty detailed documentation (especially look at the links to list of Guides and the DSL reference at the very bottom of the page).
- Declared in:
danger-ci/danger.rb
- Function:
check_danger_config_changed
- Type: 📖 informative message
This rule simply reminds us to update this very documentation when the Danger configuration is changed (when any file in danger-ci/*
is modified), so that we keep the documentation in sync with the actual rules.
- Declared in:
danger-ci/pr_size.rb
- Function:
check_pr_size
- Type:
⚠️ warning
This rule warns us if the number of inserted lines in the PR is above 850.
ℹ️ Binary files are counted as "1 line changes" for the purpose of this rule, in order to count as changes to be reviewed but only count as 1 single change.
This means that the number of insertions/deletions reported by GitHub on your PR might slightly differ from the "number of lines" considered by this Danger rules if you have binary files in your PR.
Note: We have an informal limit of 800 lines for PRs, but since it's only informal, we decided to only make Danger put a message if we're more then 50 lines over that informal limit.
If this rule is triggered, an table is also added showing some stats (the table is hidden behind a disclosure triangle) about the number of changes per various categories of content (Feature Code, Test Code, pbxproj, Binary files, ...). Thoe goal of this table is to better understand how the code of the PR is distributed, hopefully giving the author and reviewers some ideas on how to split the PR if needed (e.g. one PR with just the code for the Builder separated from the PR adding the VM)
This rule is only a warning because we don't want it to block PRs, as there are some rare exceptions where we allow the limit to be exceeded, as long as it's justified by the author (e.g. a refactoring PR)
- Declared in:
danger-ci/pods.rb
- Function:
check_podfile_lock_committed
- Type: 🚫 failure
This rule is to alert us if we forgot to commit the changes made in Podfile.lock
. This can happen if:
- We modified the
Podfile
but forgot to dobundle exec pod install
afterwards - We modified the
Podfile
and ranpod install
but forgot to include thePodfile.lock
in the commit - We modified the
Podfile
once, ranpod install
and committed thePodfile.lock
changes for that first modification in one commit… but then later re-modified thePodfile
and forgot to commit the second change toPodfile.lock
(which means that the PR will contain changes inPodfile.lock
, but not the expected ones)
- Function:
check_dependencies_changed
- Type: 📖 informative message
This rule is just to inform (informative message, no error nor warning) when the PR contains changes in the Podfile.lock
, in order to raise awareness to reviewers about changes in dependencies.
The goal is to suggest them to take extra care in reviewing why we needed those changes in our dependencies and if they were properly justified.
- Declared in:
danger-ci/sdk.rb
- Function:
check_sdk_hashtag
- Type: 🚫 failure
This rule is to ensure that you identify PRs containing changes to any files in our SDKs by adding #SDK
to the PR title.
This applies to any changes done in files in the SDK/
and UI SDK/
folders – except for files related to tests.
Note that if the PR is already associated with ticket from one of the SDK board, and thus contains [SDK-xxx]
or [SDKS-xxx]
in its title, then #SDK
is implied and you don't have to add the hashtag explicitly.
The hashtag is only needed for Pull Requests addressing tickets from non-SDK boards but still touching the SDK files.
This is needed because of the Change Request Process (CRP) from our sSDLC requirement: any ticket touching code in the SDK needs to be included in the CRP ticket for next SDK release, and that hashtag will allow us to include those tickets automatically.
- Declared in:
danger-ci/pbxproj.rb
- Function:
check_unexpected_resource_files
- Type: 🚫 failure
This rule ensures that we didn't accidentally add some Xcode-specific files to a target's "Copy Resource Files" phase, as those files are only used by Xcode or for documentation or tests, but that shouldn't end up in the final framework or app.
This rule currently checks for *.xcconfig
, *.md
, *Info.plist
and any file under a __Snapshots__
directory and fail if they have been added to your target accidentally.
- Function:
check_absolute_paths
- Type: 🚫 failure (inline comments)
This rule ensures that we didn't accidentally reference files using absolute paths in our Xcode projects.
It will add inline comments on each lines in the pbxproj
where an absolute path was detected.
- Function:
check_null_references
- Type: 🚫 failure (+ inline comments as warnings)
During a merge of Xcode project gone bad, (null)
references can appear in the .pbxproj
file.
This rule will trigger when any (null)
references or Recovered References
got introduced in the pbxproj
that your PR touched. Additionally, it will also add inline comments to pinpoint the lines in your pbxproj
where those null references were found.
When that happens, we need to understand what went wrong during the pbxproj
merge and fix it properly (and manually) before we can merge the PR.
- Function:
check_orphan_uuids
- Type: 🚫 failure (+ inline comments as warnings)
During a merge of Xcode project gone bad, orphan UUIDs can appear in the .pbxproj
file.
Context: The pbxproj
format is such that it contains a list of file references (with an associated UUID) listing all the files that are in the pbxproj, then points to those references in the various parts of the pbxproj
(for example in the "Compile Sources" build phase part, to reference which files are included in that build phase). If a pbxproj
merge went wrong, sometimes the line declaring the file reference (and its UUID) could be deleted during the bad merge while other lines in the pbxproj referencing that UUID would still remain.
This rule will warn you if any part of the pbxproj references an UUID that got accidentally removed. (Note: you should see similar warnings when you run pod install
in your terminal and it warns about an unknown UUID)
When that happens, you need to figure out if the removal of the file was intended as part of your PR (and if so, fix the merge by also removing the lines pointing to that now-deleted file reference), or if the removal of the file from the pbxproj was unintented (and if so, restore it). You could do that by editing the pbxproj
manually, but if possible it's even better if you can fix it in Xcode (e.g. by removing the offending file from the project and add it again)
- Declared in:
danger-ci/feedbacks.rb
- Function:
check_feedbacks_in_viewmodels
- Type:
⚠️ warning
This rule analyses any *ViewModel.swift
file created or modified in the PR, and try to determine if any Feedback
static method was declared but not called.
This is typically to catch cases when you declare a new Feedback
in your code but forgot to then add it to the state machine.
This rule uses sourcekitten
to dump the structure of the Swift code. It uses it to finds all the static func
returning a Feedback
declared in your code, then searches for all the method calls in your code to see if that list contains calls to all the Feedback
methods declared. If it finds a static func … -> Feedback<…>
method that is never called, it emits a warning.
Note that this rule can have false positives in rare cases. Especially if you use constructs like obj.map(Self.whenBlah)
, it doesn't detect whenBlah
as a method call because it is encapsulated inside a map
. This is why this rule is only a warning.
(It still detects Feedbacks
called conditionally though – like if (cond) { feedbacks += Self.whenBlah() }
– and should still catch the most common cases of forgetting to add a newly-created Feedback
to the state machine)
- Declared in:
danger-ci/healthkit.rb
- Function:
check_healthkit
- Type: 🚫 failure
When configuring HealthKit on a target, either to enable it on a given app flavor or to disable it if we decide to remove the feature for a flavor or for a new target we cloned from an existing one, we need to configure it in multiple places in the project and target, and ensure those configurations are consistent.
If there are some inconsistencies in the way HealthKit is configured in the different places in a target, we will likely get rejected by Apple when submitting on the AppStore, especially because we could think that we disabled it but Apple will still find traces of it, or we enabled it but forgot to turn some flags on affecting some #if
in our Swift code depending on it. This is why this rule exists, to ensure everything is consistent and we don't get rejected last minute for HealthKit configuration issues.
Every time the Babylon.xcodeproj
file is modified, this rule will iterate on each target and each build config (Debug/Release) and for each will check the following places for the HealthKit setup:
- Is HealthKit enabled in the Entitlements files?
- Are the 2 keys
NSHealthShareUsageDescription
andNSHealthUpdateUsageDescription
both set in Info.plist? - Is
HEALTHKIT_INTEGRATION_AVAILABLE
flag turned on in Build Settings underSWIFT_ACTIVE_COMPILATION_CONDITIONS
? - Is
HealthKit.framework
linked with the target? - Is
BabylonHealthKitIntegrationSDK.framework
linked with target?
If the answer to these questions for a given target and build configuration are not all the same (not all true
nor all false
), this means that there is an inconsistency in the HealthKit setup for this target and build config.
In that case, for each target+config, the rule will report a failure, and also add a markdown table listing the state of the HealthKit setup (✅/❌) for each of those 5 setup places for that target+config.
See also this documentation in our private repo to learn how to configure HealthKit in our projects.
- Declared in:
danger-ci/swiftlint.rb
- Function:
check_swiftlint_violations
- Type:
⚠️ inline warning
This will report swiftlint violations as inline comments (warnings) in the Pull Request.
Only .swift
files that are part of the PR are linted by this rule; so only violations in files that were added/modified/renamed by the PR will be reported. This is to ensure that we don't introduce new violations, and that we fix existing violations on any file we touch or update.
- Declared in:
danger-ci/screenowner.rb
- Function:
check_screenowner_is_set
- Type:
⚠️ warning
This will report any View Models that are missing a screen owner as a warning in the Pull Request.
Only *ViewModel.swift
files that are part of the PR are linted by this rule; so only violations in files that were added/modified/renamed by the PR will be reported. This is to ensure that we don't introduce new violations, and that we fix existing violations on any file we touch or update. Similarly to missing feedbacks.
How to resolve: add the following definition to the affected View Model(s)
extension ExampleViewModel: ScreenAttributes {
var screenOwner: Squad? {
// set the appropriate squad here
}
}