Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Future of SwifterSwift #967

Open
omaralbeik opened this issue Jun 27, 2021 · 7 comments
Open

Future of SwifterSwift #967

omaralbeik opened this issue Jun 27, 2021 · 7 comments
Assignees
Milestone

Comments

@omaralbeik
Copy link
Member

Future of SwifterSwift

First of all I want to thank you all for making SwifterSwift what it is today 🚀

Here are some insights from Github

  • 132 contributors!
  • 4000+ monthly repo visitors
  • 4500+ monthly clones
  • 500+ monthly visitors to swifterswift.com

For many of the 132 contributors (including me), SwifterSwift was the first open source contribution, how cool is that!

I wanted to share my vision for the project going forward and gather your feedback. Lets shape the future of SwifterSwift together!


Goals

Create a safe and welcoming environment for others to learn and grow through Open Source.

Unlike other open source projects, contributing to SwifterSwift does not require a deep knowledge of the code base, nor the history behind it, all you need is a Swift extension that you want to share with the community!

After your first pull request is merged, you will automatically receive an invitation to join the organization on Github, so you can show that nice "SwifterSwift" badge in your Github profile, but more importantly you're now one of us, you can review pull requests and drive the future of the project!

We want to make it even easier for everyone to contribute to the project by automating some of the confusing parts for new joiners, like adding a change log entry.

SwifterSwift was how I got to love open source, I personally learned tons and made many friends!

Experiment with Github Actions

Utilize Github Actions to automate monthly releases without having one of the team to trigger the process manually.

A few years ago -frankly when Swift 3 was released- we thought it is a good idea to sync SwifterSwift's version with Swift's versions

  • SwifterSwift v3 supports Swift 3
  • SwifterSwift v4 supports Swift 4
  • SwifterSwift v5 supports Swift 5
    ...

Now that Swift is reaching a level where the language is mature enough and its features are evolving slowly, we need a versioning system that gives us more flexibility releasing more versions.

CalVer is a promising option that will enable us to have fully automated monthly releases.

SwifterSwift v2021.06.01 the first release of June 2021
SwifterSwift v2021.06.02 the second release of June 2021
SwifterSwift v2021.10.01 the first release of October 2021

We can use Github Actions' scheduled events to release a new version every month without the need for any of the maintainer time to trigger the process or sign off the release.

swifterswift.com

Create a website where people can search for extensions and copy-paste them to their projects with ease.

An automated script will make sure the website is always up to date whenever a change is made is the main branch.

To make generating the website easier, some changes will be made to the current structure

Project folder structure
SwifterSwift
├─ Sources/
│  ├─ Int+Extensions.swift
│  ├─ String+Extensions.swift
│  ├─ UITableView+Extensions.swift
├─ Tests/
│  ├─ Int+Extensions_Tests.swift
│  ├─ String+Extensions_Tests.swift
│  ├─ UITableView+Extensions_Tests.swift
├─ Generated/
│  ├─ extensions.json (or some other format)

The Generated folder will contain files that the website uses to display its content. the CI regenerates them every time a change is made in the main branch.

Extensions in a .swift file should adhere to the following rules:

  1. A single extensions should declare the type it extends, and its dependencies, including import statements, #if checks, and a doc comment.
  2. A single extensions should always start with // start.ext and end with a // end.ext comments.
  3. Extensions CAN NOT depend on other extensions from the library, nor create any private classes, structs, or methods in the global scope, they should be self contained.

The CI will treat everything between // start.ext and // end.ext as a single unit creating a nice html page in swifterswift.com

It might be also possible to check extensions in isolation to make sure they don't have any cross dependencies.

Example String+Extensions.swift
// start.ext
public extension String {
    /// SwifterSwift: Check if string contains only letters.
    ///
    ///     "abc".isAlphabetic -> true
    ///     "123abc".isAlphabetic -> false
    ///
    var isAlphabetic: Bool { ... }
}
// end.ext

// start.ext
#if canImport(Foundation)
import Foundation
public extension String {
    /// SwifterSwift: CamelCase of string.
    ///
    ///     "sOme vAriable naMe".camelCased -> "someVariableName"
    ///
    var camelCased: String { ... }
}
#endif
// end.ext

// start.ext
#if canImport(Foundation) && canImport(UIKit)
import Foundation
import UIKit
public extension String {
    /// SwifterSwift: Add color to string.
    ///
    /// - Parameter color: text color.
    /// - Returns: a NSAttributedString versions of string colored with given color.
    func colored(with color: UIColor) -> NSAttributedString { ... }
}
#endif
// end.ext

El Plan

1. Gather feedback

@SwifterSwift/contributors, Please help us by adding thoughts or any concerns you have here 😊

2. Create a PoC for swifterswift.com

Use a small set of the extensions to create a PoC for the website and gather feedback about the website.

3. Check extensions individually

Check extensions and make sure they adhere to the the standards, this might create some breaking changes, as we will remove some enums and structs that sneaked into the library overtime.

4. CI changes

Update our CI scripts

5. First automated release

It would be very nice to have everything ready before october, to welcome many new joiners during Hacktober fest.

@thisIsTheFoxe
Copy link
Member

thisIsTheFoxe commented Jun 27, 2021

Ayy, what a nice post. And I can confirm, SwifterSwift helped me a lot too, it's such an awesome project, thank you <3

The plan looks great. I didn't fully dive into it yet, but apparently DocC is a thing since WWDC21. Don't know how stable it is yet or all the features it has / will have, but might be worth checking out :)

@jevonmao
Copy link
Contributor

While the automatically month release is a very useful and excellent idea, I still have concerns as to how semantic versioning will be enforced. Then, manual interference with the releases are still unavoidable because maintainers need to decide whether it's a patch, minor, or major feature.

Also, would sufficient updates and changes justify a new version released every month? What if a ton of changes were made in January, but almost no change was made in February?

@jevonmao
Copy link
Contributor

nor create any private classes, structs, or methods in the global scope

So are SwifterSwift extensions allowed to create classes and structs not in the global scope, but within the extension itself?

@freak4pc
Copy link
Contributor

freak4pc commented Jun 27, 2021

I think it's mostly easy to make it automatic-ish.

You could enforce a flag/label on each PR that a contributor must mark to say if it's a breaking change or not and then make a decision based on whether or not the past 30 days included a label with breaking (major), additive (minor) or bug fix (patch).

You could make this even more automatic by using something like SourceKitten to figure out if the diff of a PR includes such changes and automatically label the PR accordingly.

@omaralbeik
Copy link
Member Author

nor create any private classes, structs, or methods in the global scope

So are SwifterSwift extensions allowed to create classes and structs not in the global scope, but within the extension itself?

Types should be avoided in general, but basically, they should not be created outside your extension, here are two examples

Allowed

extension String {
    func test() -> String {
        struct Test {
            let word: String
        }
        return Test(word: "Hello").word
    }
}

Not allowed

extension String {
    struct Test {
        let word: String
    }
    func test() -> String {
        return Test(word: "Hello").word
    }
}

@omaralbeik
Copy link
Member Author

I think it's mostly easy to make it automatic-ish.

You could enforce a flag/label on each PR that a contributor must mark to say if it's a breaking change or not and then make a decision based on whether or not the past 30 days included a label with breaking (major), additive (minor) or bug fix (patch).

You could make this even more automatic by using something like SourceKitten to figure out if the diff of a PR includes such changes and automatically label the PR accordingly.

I like the idea of PR flagging, but I'm worried this will make things a bit more difficult for new contributors.

As for SourceKitten, I think it will be a bit challenging with many edge cases, this could be its own project 😄

@omaralbeik
Copy link
Member Author

While the automatically month release is a very useful and excellent idea, I still have concerns as to how semantic versioning will be enforced. Then, manual interference with the releases are still unavoidable because maintainers need to decide whether it's a patch, minor, or major feature.

Also, would sufficient updates and changes justify a new version released every month? What if a ton of changes were made in January, but almost no change was made in February?

Well, that is the whole reason behind moving to CalVer + the new website!

We're saying: SwifterSwift is more like a snippet's library, if you want to use it as a dependency (not sure it is a good idea btw 😅 ) you might want to fix the version

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

No branches or pull requests

4 participants