-
Notifications
You must be signed in to change notification settings - Fork 48
Use swift.org API for getting releases and some snapshot toolchains #153
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
Conversation
…napshot toolchains
Bump versions in update tests to versions that amazon linux 2 has tagged releases
@swift-ci test macOS |
The macOS CI passes the tests, but there's the persistent environmental problem that reports an overall failure.
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In general looks good, I've a couple of questions and minor edit requests
|
||
Note that listing available snapshots is currently unsupported. It will be introduced in a future release. | ||
Note that listing available snapshots before 6.0 is unsupported. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I assumed this is because the data isn't available at the moment. Could this change?
Sources/Swiftly/ListAvailable.swift
Outdated
print("----------------------------") | ||
for toolchain in toolchains where toolchain.isStableRelease() { | ||
for toolchain in toolchains { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good call don't need to separate these two lists
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The output of swiftly list
separates them still, so I think it would be a good idea to be consistent with that. Regardless of that, they were originally separated in part because snapshots are released on a (nearly?) daily basis, so they would always dominate the output here, and I'd imagine that most users are looking for available releases anyways. So I'd support continuing to list these separately.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This else only gets invoked in the absence of a selector, which defaults to all of the releases, since every snapshot build for every branch would be overwhelming and probably not very useful.
I can retain the "release" toolchains label to make it clear that these are only releases, but the where clause shouldn't be necessary here.
@@ -22,6 +22,100 @@ private func makeRequest(url: String) -> HTTPClientRequest { | |||
return request | |||
} | |||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it worthwhile breaking out the swift.org data and parsing into a separate file?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm on the fence about this.
It feels like the swift.org metadata is a foundational use of the swiftly http client, so why not just put the code there? On the other hand, because of the GitHub fallback there's some asymmetry now because it's in another source file. But, there's also a feeling that the fallback may go away someday, so that could be why it is separate.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As I see it there is the client and the usage of the client which are two different things
Sources/SwiftlyCore/HTTPClient.swift
Outdated
@@ -88,21 +207,91 @@ public struct SwiftlyHTTPClient { | |||
return release | |||
} | |||
|
|||
return try await self.mapGitHubTags(limit: limit, filterMap: filterMap) { page in | |||
try await self.getReleases(page: page) | |||
guard !swiftOrgFiltered.isEmpty else { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this really necessary?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed, this is not needed. I'll remove it.
Sources/Swiftly/ListAvailable.swift
Outdated
print("----------------------------") | ||
for toolchain in toolchains where toolchain.isStableRelease() { | ||
for toolchain in toolchains { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The output of swiftly list
separates them still, so I think it would be a good idea to be consistent with that. Regardless of that, they were originally separated in part because snapshots are released on a (nearly?) daily basis, so they would always dominate the output here, and I'd imagine that most users are looking for available releases anyways. So I'd support continuing to list these separately.
Sources/SwiftlyCore/HTTPClient.swift
Outdated
return if let limit = limit { | ||
Array(finalSnapshotToolchains[0..<limit]) | ||
} else { | ||
finalSnapshotToolchains |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We have several variables for the snapshots, but I think we only really need swiftOrgFiltered
. Can we drop finalSnapshotToolchains
and snapshotToolchains
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm looking into making this simpler and easier to follow.
@swift-ci test macOS |
The macOS CI passed the xctests despite reporting an overall failure:
|
@patrickfreed @adam-fowler how do these latest changes look? Any remaining issues? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Overall looks good, super excited to see swiftly using official APIs now. I have a bunch of smaller, mostly style suggestions. Feel free to merge after addressing without waiting for another round of feedback from me.
*A filter to use when listing toolchains.* | ||
|
||
|
||
The toolchain selector determines which toolchains to list. If no selector is provided, all available toolchains will be listed: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should note here that only release toolchains will be listed.
.map(ToolchainVersion.stable) | ||
.filter { selector?.matches(toolchain: $0) ?? true } | ||
tc = try await SwiftlyCore.httpClient.getSnapshotToolchains(platform: config.platform, branch: branch).map { ToolchainVersion.snapshot($0) } | ||
default: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Rather than using default
here, can we explicitly check for .release
? It reads a bit clearer that way.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, I've changed this to add explicit stable/latest case, and a default to catch no selector provided.
let arch = if a == nil { | ||
#if arch(x86_64) | ||
"x86_64" | ||
#elseif arch(arm64) | ||
"aarch64" | ||
#else | ||
#error("Unsupported processor architecture") | ||
#endif |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we do this in a few places, can we extract this to a method/computed variable on Platform
? I think it would also be good to define an enum for it so we don't have to rely on magic strings here and elsewhere.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This pattern is isolated to two places at the moment, mostly isolated to path/filename calculation and internal swift org metadata. It might be possible to isolate all of it in the HTTPClient, or an HTTPClient+SwiftOrg.
There are some problems with pulling this out into a global enum at the Platform level. In macOS, the arch isn't used at all because of the universal binaries/packages. Also, there is some disagreement between the naming of the 64-bit arm architecture. In some places. it's "arm64" while others is "aarch64." It doesn't feel like an enum could be universally defined across OSes and cases without being a leaky abstraction.
I feel that in Swift it's quite common to put these kinds of macros (os/arch) at the place where they are needed as long as it isn't excessive and it can maintain locality of change when/if the logic changes. For now, it's only these two places: HTTPClient, and Install.
PlatformDefinition.macOS, | ||
PlatformDefinition.ubuntu2204, | ||
PlatformDefinition.ubuntu2004, | ||
// PlatformDefinition.ubuntu1804, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why commented out?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ubuntu 18.04 doesn't have toolchains available for the releases that we are testing here. I'll update the comment to explain.
Sources/SwiftlyCore/HTTPClient.swift
Outdated
let branchLabel = switch branch { | ||
case .main: | ||
"main" | ||
case let .release(major, minor): | ||
"\(major).\(minor)" | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
branch.name
gives us this.
Sources/SwiftlyCore/HTTPClient.swift
Outdated
let swiftOrgReleases: [SwiftOrgRelease] = try await self.getFromJSON(url: url, type: [SwiftOrgRelease].self) | ||
|
||
var swiftOrgFiltered: [ToolchainVersion.StableRelease] = swiftOrgReleases.compactMap { swiftOrgRelease in | ||
if platform.name != "xcode" { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"xcode"
-> PlatformDefinition.xcode.name
} | ||
} | ||
|
||
guard let version = try? ToolchainVersion(parsing: swiftOrgRelease.stableName), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if parsing fails, I think we'd want to let the user know about it in some way, either just by throwing here (which I think is fine, since we should never fail parsing swift.org results) or logging.
Sources/SwiftlyCore/HTTPClient.swift
Outdated
"\(major).\(minor)" | ||
} | ||
|
||
let platformName = if platform.name == "xcode" { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"xcode"
-> PlatformDefinition.xcode.name
, also below.
Sources/SwiftlyCore/HTTPClient.swift
Outdated
|
||
/// platformName is a mapping from the 'name' field of the swift.org platform object | ||
/// to swiftly's PlatformDefinition name. | ||
var platformName: String { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To better align with this var's usage/documentation, it might be better to just return the matching PlatformDefinition
or nil
if it isn't supported. That way we can rely on the PlatformDefinition
constants as the single source of supported platform names, and we also don't need to define constants for platforms we don't support. If we go that direction, renaming this something like asPlatformDefinition
or something might make sense.
If we don't change this in that way, then I think at least renaming it to canonicalPlatformName
or swiftlyPlatformName
communicates the difference between the other name
field a bit better. We'd also want to use the PlatformDefinition
name constants here as well.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, this is a really nice pattern here. We can return the constants defined in PlatformDefinition for platforms that swiftly supports, and manually constructed PlatformDefinitions for the ones that it doesn't, which can provide enough metadata to represent what the swift.org API is producing. For yet unknown (to swiftly) swift.org platforms, then it's just nil until this code adds a representation for it.
} | ||
|
||
let platformName = if platform.name == "xcode" { | ||
"macos" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the inconsistency between these swift.org APIs and swift.org's download URLs here is a bit odd. Is there any chance the API would be updated to use "xcode" like the downloads do so we can avoid needing to adjust for it here?
This question also applies for the non-macOS platform names. It'd be nice if e.g. ubuntu1804
were used rather than the pretty name.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@shahmishal here is some feedback regarding the swift.org API. There are some inconsistencies between the new API and the toolchain download URL's / filenames. We're working around these for now in swiftly, but perhaps this can be made a little more ergonomic for other consumers of the API.
Use PlatformDefinition constants for cases of swiftly supported platforms Construct PlatformDefinitions for known swift.org platforms that are not supported by swiftly Use branch.name for snapshot url construction Update command-line reference documentation of list-available for the case of no selector
@swift-ci test macOS |
See issue #149
Using the new swift.org API is more accurate than the GitHub API, also it isn't subject to the same rate limits. Use the swift.org API instead of the GitHub API for fetching metadata about the released swift toolchains, and the newer swift branches for the snapshots.
However, there is currently no metadata for snapshots on older branches than 6.0 or main. In this case use the GitHub API to get the metadata, but only for
swiftly install
and not theswiftly list-available
commands, since the latter is very expensive when using the GitHub API.