Official Package List Validator for Swift Package Index
Before each package is added to Swift Package Index, the package list must verified for correctness. These verifications come in two forms: the overall list and each package.
As far as the overall list, it must:
For each package to valid, it must:
Package.swift
fileThis application is useful for those, who are interested contributing their own package to the Swift Package Index or wish to contribute to this project.
There are two methods to run this application:
USAGE: swiftpmls <subcommand>
OPTIONS:
-h, --help Show help information.
SUBCOMMANDS:
all Verify every package in the JSON file.
mine Verify the package in the directory specified or the
current directory.
diff Verify only packages which are not contained in the
current master list.
Once you are able to run the application there are three subcommands available:
packages.json
specifiedpackages.json
specified which are not contained in the master packages.json
OVERVIEW: Verify the package in the directory specified or the current
directory.
USAGE: swiftpmls mine [<directory>]
ARGUMENTS:
<directory> The directory to verify if the Swift package is
valid.
OPTIONS:
-h, --help Show help information.
OVERVIEW: Verify only packages which are not contained in the current master
list.
USAGE: swiftpmls all [<path>]
ARGUMENTS:
<path> Path to the JSON file containing the repository list
(default: packages.json)
OPTIONS:
-h, --help Show help information.
As stated above the validator first verifies the overall list and then verifies each Package individually. When validating the overall list, each url must be valid, the list can not contain duplicates, and each repository must be in alphabetical order.
In order to verify the list, the packages.json
specified must be in a valid JSON format (i.e. Array of URLs). Therefore if the application cannot read the data at the path or use the JSONDecoder
to decode the file decoder.decode([URL].self, from: data)
, then the list will be deemed invalid.
Having decoded the packages.json
file, the next part of the process is validating the list overall.
In order to make sure the list does not contain duplicates based on various scheme/protocol and extension variations, a standard repository url format has been decided:
https://github.com/owner/repositoryName.git
If the url does not follow this format, the url is marked as invalid.
Therefore, make sure your package:
.git
extensionNext, each url must be in the correct alphabetical order. This is done by transforming each url to it's lowercase format and using the less than operator <
:
let sortedUrls = urls.sorted {
$0.absoluteString.lowercased() < $1.absoluteString.lowercased()
}
Once the sorted is completed, the application then compares the specified packages.json
with the sorted list. If there are any differences, the list is determined to be invalid.
Therefore, make sure your package:
In order to make sure each url is unique (i.e. no case variants), the application makes a lowercase absolute URL string from URL and counts instances for each lowercase url in the list:
URL(string: $0.element.absoluteString.lowercased())!
}.mapValues { $0.map { $0.offset } }.filter { $0.value.count > 1 }.keys)
This creates a list of URLs which more than one value. If there are URLs with duplicates, it is marked as invalid.
Therefore, make sure your package:
To determine whether a package is valid, it must contain a valid Package.swift in its default branch. This means the application needs to:
The first step in order to make sure a Swift package is valid is downloading the Package.swift
file of the package. What this means luckily, is that the application does not need to clone the entire repo. Based on the determined host of the repository, the application can transform the repository url to the raw url of the Package.swift of the repository. At this time, the validation tool only works with GitHub, however if you are using another support can be easily added. Therefore, with GitHub, we can use https://raw.githubusercontent.com
to determine the url of Package.swift
in the repository.
However, the missing part of the url is the default branch of the repository. Therefore, this is the larger challenge of the application.
Therefore, make sure your package:
By default, GitHub uses master
as the default branch of every repository. However there are many cases, where master
is not the default branch. Therefore the application needs to call the GitHub API to find that setting. However, in order to make sure the GitHub API Limit is not reached, there are few ways the application avoids this call:
Package.swift
in branch master
all
since that call be as many 3000 repositoriesIn order to allow the GitHub API call, the GITHUB_API_TOKEN
and GITHUB_API_USERNAME
must be as environment variables, such as:
GITHUB_API_TOKEN=abc123 GITHUB_API_USERNAME=username@github swiftpmls diff
If the url cannot be deciphered, the package is marked as invalid. Otherwise, the next step is downloading the Swift package.
Once the url is determined, the application downloads the Package.swift
file. Once the file is downloaded to a tempoary directory, the application runs swift pacakge dump-package
to get the structure of the Swift package.
A simplified Codable
version of the JSON dumped is decoded from standard output. If the dump reveals there is at least one valid product, then the package is valid.
Therefore, make sure your package:
Package.swift
is validUpdated to at least Swift version 4.0:
// swift-tools-version:4.0