You want to help us enable Skyscanner to create beautiful, coherent products at scale? That's awesome! ❤️
By contributing your code, you agree to license your contribution under the terms of the APLv2.
All files are released with the Apache 2.0 licence.
We use asdf to manage our language runtimes. This will be installed when you run ./fullsetup
. All dependency versions are managed in .tool-versions
Use the version of Xcode specified in our build pipeline, however the project should work with old versions of the same major.
- All new components are written in Swift
- We sparingly update Objective-c components and rather upgrade to Swift with UIKit or provide a SwiftUI version
Please follow the Swift Style Guide when writing Swift. Follow other conventions and patterns established in the source code already when the style-guide cannot help you. The goal is that the codebase should look like it was written by a single author.
Run the following commands from your terminal, these should be run from the root of the project.
./fullsetup
to install all dependenciesopen Example/Backpack.xcworkspace
to open the example project
If you want to add a new component, we will need the following:
- Design (Figma file)
- UIKit or SwiftUI component
- Accessibility
- Stories
- Tests (unit & snapshot)
- Documentation (Including main
REAMDE.md
)
Figma is the preferred format for non-technical folks. We’d appreciate if you could provide an exact match of your component in Figma format together with examples for each state e.g. disabled, expanded etc.
Make sure that when you contribute you are considering a UIKit and a SwiftUI version of your component. The UIKit component should live in the Backpack folder. A SwiftUI component needs to be located in Backpack-SwiftUI.
A component folder structure is setup as follows. Please take a look at the setup of existing components for examples.
- Backpack
- {ComponentName}
- Classes
- BPK{ComponentName.swift}
- {Any supporting swift files}
- README.md
- Classes
- {ComponentName}
For SwiftUI the root folder will be Backpack-SwiftUI
. The structure is otherwise the same.
All of our components must be accessible.
The easiest way to achieve this is to consider different accessibility needs in the design stage. We follow WCAG 2.2 AA as a guiding standard and apply this to all of our components.
At a mimimum you should make sure your component meets the following criteria:
- Colour contrast meets AA standard
- Required accessibility labels are passed to the component
- Screen readers can interact with the component
- The component can scale when the font-size increases
In SwiftUI, you must create at least one Accessibility snapshot that tests Dynamic Type, you can do this by adding a new test for your component. Below we included an example accessibility test.
func test_accessibility() {
let badge = BPKBadge("Test badge", icon: .accessibility)
assertA11ySnapshot(badge)
}
Each component needs to be visually documented in our example app. Make sure to add a new entry and showcase your component in each of its different states and variants.
Our components need to be well tested. We require all business logic to be covered by unit tests. The component and all of its types and states need to be captured in Snapshot tests. Please review existing components to learn how we set up these tests.
Our CI runs on Intel hardware, so you might find your snapshots failing when recording them with an M1 Mac. If you have access to an Intel Mac, you can run the tests locally on that machine to avoid this issue.
Otherwise, please create a commit on your pull request with Record snapshots
to trigger a Github Action that will re-record your snapshots.
Once your snapshots are generated, please manually verify that they are correct before merging your pull request.
See our design system documentation at skyscanner.design.
Please see the code review guidelines.
Testing
Tests can be run as usual from Xcode(Product -> Test or cmd+U). Snapshot tests should be run on the device specified for CI.
Documentation screenshots
The screenshots folder stores all of the screenshots we use on the documentation site. If you change the appearance of a component you must update the screenshots accordingly. To do this, run:
./scripts/take-screenshots
The script takes 10-15 minutes.
It's possible to take only a subset of the screenshots which greatly speeds up the process.
To do this follow the following steps:
- Update
Example/Backpack Screenshot/SwiftUIScreenshots
to capture screenshots of the new componenet. Please note that the screenshots will appear as they do in the component entry in (Stories)[https://github.com/Skyscanner/backpack-ios/blob/AlaaAmrAmin-patch-1/CONTRIBUTING.md#stories]. - In
Example/Backpack Screenshot/BackpackSnapshotTestCase.swift
change therunOnly
property per the guide in the comment. - Run the screenshots as above (using the
./scripts/take-screenshots
script) - Note that all other screenshots will be deleted in the process, so make sure you only commit the ones you generated not the deletions.
Snapshot testing
Snapshot tests are used to capture images of components under different configurations. When you add or change a snapshot test, test images will need to be recaptured on CI to ensure consistency. Create an empty commit to regenerate snapshots:
git commit --allow-empty -m "record snapshots"
If you want to test your snapshot tests locally change isRecording = false
to isRecording = true
in the relevant test file and re-run the tests on the device specified for CI. This will update the images on disk. Remember to revert isRecording
and the snapshot updates afterwards otherwise the tests will fail.
If you have any questions at all, don't hesitate to get in touch. We love to talk all things Backpack and we look forward to seeing your contribution!
Relative font
Our fonts can only be used by Skyscanner employees. If you don't work for Skyscanner don't worry - the Example app will still work just fine with iOS system font too!
To use our Skyscanner Relative
font-face in the example app do the following:
- Make sure you're connected to the VPN.
- If you've already done a
pod install
, deleteExample/Pods
. - Set the environment variable using
export BPK_USE_RELATIVE=1
. (Put this in your.bashrc
/.zshrc
for convenience.) - Setup the project as above.
During pod install, fonts will be downloaded and made available to the project automatically.
Upgrading Xcode / iOS
As new versions of Xcode and iOS are released, we have to upgrade both to stay up to date with the main Skyscanner app, as well as what travellers are using. Our aim is to run our main test suite and snapshot tests on the dominate iOS version in use by Skyscanner travellers. At the time of a new release we continue to run our test suite on the previous major version until the new release has reached sufficient volume and the main app has moved to testing on the new version.
- Change the value of
runs-on
inci.yml
. The new value should be on of the available environments in GitHub Actions. - Update the
BUILD_SDK
variable inRakefile
to the new build SDK we should use. - Update
correctMajorVersion
andcorrectMinorVersion
inBPKSnapshotTest
. - Update
expectedMajorVersion
andexpectedMinorVersion
inBPKSnapshotTest.swift
. - Run all snapshot tests.
- Review the failing snapshots thoroughly. Most likely, all snapshots will have changed, but the diffs should be miniscule and mostly to do with changes in Apple's fonts.
- Run all snapshot tests in record mode. At the time of writing this involves manually setting
recordMode
in every test case, we should have a better method than this, but alas we don't :( - Manually test the example app with the new version.
Want to run A/B experiments on features that entail changes to Backpack components? Continue reading below 👇
When is a component change considered experimental?
If the component or change you want to contribute to Backpack is not stable and it depends on the results of an experiment then it is considered experimental.
What do you need to do to mark a component or part of a component as experimental?
This will depend on what kind of change you are contributing.
Patch and minor changes
For patch and minor changes, you should use AppleDoc annotations. AppleDoc is a widely used and supported tool in the Swift ecosystem that allows developers to document their code. AppleDoc comments will be visible in Xcode.
Major
For major changes, you should create a new experimental V2 component. If the experiment is successful, the old component should be deprecated.
Any follow-up changes to experimental components will not be considered breaking.
When should documentation be created and published?
Each Bpk component has a corresponding README file which contains information about the component such as usage examples and API documentation. Our components' full documentation is at skyscanner.design. New experimental components should have a README file, but don’t need to be published to skyscanner.design. Make sure the README file reflects the component is experimental! When an experiment has run and is considered successful and so the change is stable, documentation can be published.
For changes to existing components, make sure the API documentation is updated to indicate if something is experimental.
Major changes will often require a migration guide. If an experiment is considered succesful, you should add a migration guide within the docs folder located in the respective component folder.
How long does experimentation code live in Backpack?
Experimentation code should be cleaned up at most 2 weeks after an experiment has completed. In the case of a successful experiment, annotations should be removed and documentation should be published. In the case of an unsuccessful experiment, the code should be removed altogether.
Examples
Here’s an end-to-end example on how to add an experimental prop to a Bpk component:
- Reach out to Koala with the proposed change
- Contribute code changes. Make sure the API table is updated too!
/// - Experiment: This property is experimental and subject to change. Use with caution
public var type: BPKChipType = .option {
didSet {
updateLookAndFeel()
}
}
- Released by Koala
- Adopt changes in project
- Run experiment
- if experiment is successful, publish documentation (only Koala members) and remove experimental code.
- if experiment is unsuccessful and further iterations are needed, repeat from step 2. Otherwise, remove experimental code. That’s all!
Backpack team only
To issue a new release:
- Publish draft release
The release workflow will also trigger our design docs publish. If successful, you should see your component changes at skyscanner.design.
Note: Don't forget that new components need to be added manually!