Skip to content

Add Package.swift#71

Merged
crazytonyli merged 5 commits intodevelopfrom
swift-package
Nov 9, 2022
Merged

Add Package.swift#71
crazytonyli merged 5 commits intodevelopfrom
swift-package

Conversation

@crazytonyli
Copy link
Contributor

@crazytonyli crazytonyli commented Nov 2, 2022

Not just adding a Package.swift file, this PR also proposes a structure that potentially can be shared among all our shared libraries.

Development

During development, we should treat the library as a Swift package. There are two ways to develop the Swift package in Xcode:

  • Open Package.swift directly in Xcode. From here, we can build and test the package. One thing missing from this approach is we can't see UI produced by the library, like the icons in this repo. So, it's quite common to have a demo or example project to showcase the library:
  • Create a demo/example project and import the library as a local package(Xcode -> File -> Add Packages... -> Add Local). The demo project has an app target where we can see the component in the library. The demo/example project may also be a good place to host UI tests.

Both approaches work, they don't conflict with each other. I don't see there is any need of recommending one over the other. But we may want to add steps in CI to ensure the demo/example app continues to build.

Distribution

The library can be imported as a Swift package and a CocoaPods pod. But since we no longer use the library's podspec file during development, we could easily overlook CocoaPods integration. One way to prevent this issue is adding "test spec" to the podspec so that the pod lib lint step in CI not only validates if the podspec can be imported as a pod but also tests its functionality—kinda like how you can build and test targets in a Swift Package.

I want to highlight one thing. Since CocoaPods and SPM package the library differently, especially on the resource bundles, we'll need to make sure there is test coverage around loading resource bundles.

Summary

To summarize all above, here are list of things that we should do in our libraries.

  • Add test_spec to the podspec file. The test spec should have the same test cases that are declared in Package.swift.
  • If the library has resources (images, assets, localization, etc.), make sure there is test coverage for them.
  • Validate both Swift Package and podspec file in CI. A validate_swift_package script is added in this PR, which should serve the same purpose as validate_podspec and should be moved to the buildkite plugin repo.
  • No xcworkspace or xcodeproj in the library's root directory. So that the xcodebuild command line picks up the Package.swift file, not the workspace or project file(*).
  • When needed, create a directory and place the demo/example Xcode project there. Import the Swift Package into the demo/example project by navigating Xcode -> File -> Add Packages... -> Add Local -> Choose the repo's root directory.
  • Ignore two files in the git repo: Package.resolved and .swiftpm directory. I don't think we should not pin the library's dependencies (if there is any) to certain versions during development. Update: Check in Package.resolved to pin the dependencies used during development—similar to how we check in Podfile.lock.

(*) xcodebuild has this very strange behavior when dealing with Package.swift. To make the command run tests in the Package.swift, we need to run the command in the directory of Package.swift, without passing -workspace nor -project option. Suppose there is an xcworkspace or xcodeproject in the Package.swift directory, they will use them instead of the Package.swift file—there is no equivalent of -workspace MyApp.workspace for Swift Package.


  • I have considered if this change warrants release notes and have added them to the appropriate section in the CHANGELOG.md if necessary.

@crazytonyli crazytonyli requested a review from a team November 2, 2022 08:45
Copy link
Contributor

@mokagio mokagio left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Requesting changes because of the generated file issue.

Other than that, I love what you've done and where the proposal is going.


One suggestion: What do you think of calling the folder where the demo project lives Demo/ instead of GridIconsDemo/? I think a generic name might help us in the future if we need some standardized setup or automation.

This repo doesn't follow the recommended (?) SPM folder structure, but in repos that do, calling it Demo/ would also look consistent:

Demo/
Sources/
Tests/

One question, regarding Package.resolved:

I don't think we should not pin the library's dependencies (if there is any) to certain versions during development.

Why not?

Comment on lines +11 to +13
# For some reason this fixes a failure in `lib lint`
# https://github.com/Automattic/buildkite-ci/issues/7
xcrun simctl list >> /dev/null
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need this given we don't call bundle exec pod lib lint from this script?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch! I copied the build_and_test_pod script but didn't noticed the comment. We probably don't need this extra command, I'll remove it for now and can always add it back if anything goes wrong.

Comment on lines +29 to +31
s.test_spec do |test|
test.source_files = ['Gridicons/GridiconsTests/**/*.{swift}']
end
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TIL about test_spec.

Super neat, we should adopt it everywhere as we migrate to SPM.

For reference, here are the CI logs that show the tests running.

// When loaded through CocoaPods, assets reside in a separate resource bundle
bundle = assetBundle
}
#endif
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm afraid there's more work to be done on this particular file.

If I run the command that bundle exec rake gen runs, /path/to/project/Gridicons-iOS/vendor/swiftgen/bin/swiftgen xcassets -p Gridicons.stencil Gridicons/Gridicons/Gridicons.xcassets > Gridicons/Gridicons/GridiconsGenerated.swift, these changes are reverted.

I never worked with SwiftGen or Stencils. I assume it should be a straightforward matter of updating the template but I don't know for sure.

I wrote "run the command..." because the rake task itself fails for me with:

rake aborted!
ArgumentError: wrong first argument
/Users/gio/Developer/a8c/Gridicons-iOS/Rakefile:65:in `swiftgen'
/Users/gio/Developer/a8c/Gridicons-iOS/Rakefile:55:in `block in <top (required)>'
/Users/gio/Developer/a8c/Gridicons-iOS/vendor/bundle/ruby/2.7.0/gems/rake-13.0.1/exe/rake:27:in `<top (required)>'
/Users/gio/.rbenv/versions/2.7.4/bin/bundle:23:in `load'
/Users/gio/.rbenv/versions/2.7.4/bin/bundle:23:in `<main>'

I think the two things are unrelated.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed in e11f08d


let package = Package(
name: "Gridicons",
platforms: [.iOS(.v11)],
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think all our apps support iOS 13 and above, with the possibility of bumping to iOS 14. Still, iOS 11 is the minimum supported by Xcode 14 so I think this is the best value to use 👍

That is, unless we find some code improvements that might require an higher SDK, but those ought to be saved for a dedicated PR anyway.

run_tests(
package_path: '.',
scheme: 'Gridicons',
devices: ['iPhone 11'],
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Out of scope for this PR, but iPhone 11 is not available out of the box with Xcode 14 (that's something I didn't notice when upgrading CI, sorry about that).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated in 7d85bb3 😃

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🙇‍♂️

platform :ios do
desc 'Builds the project and runs tests'
desc 'Builds the Swift package and runs tests'
lane :test do
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This fails for me locally with

[06:08:50]: ▸ xcodebuild: error: The workspace named "Gridicons" does not contain a scheme named "Gridicons". The "-list" option can be used to find the names of the schemes in the workspace.

However, it works in CI 🤔 I wonder what the difference is between the two setups. The only thing I can think of is Intel vs Apple Silicon, but that doesn't sound related to a scheme not being found.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This lanes works on my M1 mac though. Any chance you have a xcodeproj or xcworkspace file at your root directory?

@crazytonyli
Copy link
Contributor Author

@mokagio I actually changed my mind regarding the Package.resolved file. We probably should check in this file, like how we check in the Podfile.lock file.

@crazytonyli
Copy link
Contributor Author

This repo doesn't follow the recommended (?) SPM folder structure

My plan for now is keeping the existing folder structure, for two reasons

  1. Package.swift DSL should be flexible enough to support any random folder structure.
  2. Not renaming folders and files makes git blame easier.

@mokagio
Copy link
Contributor

mokagio commented Nov 8, 2022

This repo doesn't follow the recommended (?) SPM folder structure

My plan for now is keeping the existing folder structure, for two reasons

  1. Package.swift DSL should be flexible enough to support any random folder structure.
  2. Not renaming folders and files makes git blame easier.

@crazytonyli fair enough. I don't feel strongly about the file names. Well, actually... A part of me really wishes we had Sources/ Tests/ Demo/ across repos because it would look neat and homogeneous, but I'm not aware of any practical benefit that would make development easier if we did that 😄

Doing a blanket rename is a straightforward operation that we can do anytime in the future if a good reason for it comes up, so no worries 👍


I was curious about the git blame behavior and pushed a branch with renames and checked the blame on GitHub. It seems to follow renames alright. Example, I renamed the whole Gridicons/Gridicons/ folder to Sources/ and checked one file:

image

Copy link
Contributor

@mokagio mokagio left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

:shipit: thank you for following up promptly and for fixing the Rake task.

I tried it again locally and there was no diff 🎉

image

@AliSoftware
Copy link
Contributor

AliSoftware commented Nov 8, 2022

I was curious about the git blame behavior and pushed a branch with renames and checked the blame on GitHub. It seems to follow renames alright. Example, I renamed the whole Gridicons/Gridicons/ folder to Sources/ and checked one file:

Yes, git blame follow full-file renames (i.e. if you just renamed a file in a commit without also changing some of its content at the same time) pretty well automatically. If you made both a rename and a content change, you can still get git blame follow those by using -C / -M options, that just makes the blame command a bit slower.

The origin of lines is automatically followed across whole-file renames (currently there is no option to turn the rename-following off). To follow lines moved from one file to another, or to follow lines that were copied and pasted from another file, etc., see the -C and -M options.
Source: https://www.git-scm.com/docs/git-blame

So if we wanted to reorganize the files to follow SPM filesystem structure conventions, that wouldn't cause any trouble with git blame at least.

@crazytonyli
Copy link
Contributor Author

@AliSoftware I can't remember the exact issue, but I had troubles with git blame option, maybe I wasn't using them correctly.

For easier PR review, I can create a follow up PR to follow SPM's convention, what do you all think?

@AliSoftware
Copy link
Contributor

Yeah if you want to try that doing so in a separate PR would be a good way to go imho.

I wonder if it makes a difference to git blame if you used git mv (vs mv + git add) to rename/move the files… 🤔 I don't think so but to worth checking?

@mokagio
Copy link
Contributor

mokagio commented Nov 9, 2022

For easier PR review, I can create a follow up PR to follow SPM's convention, what do you all think?

Sounds good to me. I am not too worried about adhering to the Sources/ Tests/ structure. It can happen later, if at all.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants