Skip to content

Commit 970a562

Browse files
committed
Add Swift 5 suppoort & migrate to new API
1 parent c8e1b66 commit 970a562

35 files changed

+2909
-6273
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,5 @@
33
/build
44
/Packages
55
/*.xcodeproj
6+
/.swiftpm
7+
.swift-version

.travis.yml

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,13 @@
11
language: generic
2-
sudo: required
32
dist: trusty
4-
osx_image: xcode9
3+
osx_image: xcode11.4
54
os:
65
- linux
76
- osx
87
env:
9-
- SWIFT_VERSION=4.0
10-
- SWIFT_VERSION=4.1
8+
- SWIFT_VERSION=5.1
119
install:
12-
- eval "$(curl -sL https://swiftenv.fuller.li/en/latest/install.sh)"
10+
- if [ "$TRAVIS_OS_NAME" = "linux" ]; then eval "$(curl -sL https://swiftenv.fuller.li/en/latest/install.sh)" ; fi
1311
script:
1412
- set -o pipefail
1513
- swift test --filter TravisClientTests.JSONTests

Package.resolved

Lines changed: 40 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Package.swift

Lines changed: 39 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,56 @@
1-
// swift-tools-version:4.0
1+
// swift-tools-version:5.1
22
// The swift-tools-version declares the minimum version of Swift required to build this package.
33

44
import PackageDescription
55

66
let package = Package(
7-
name: "TravisClient",
7+
name: "swift-travis",
8+
platforms: [
9+
.macOS(.v10_13), .iOS(.v11), .tvOS(.v11),
10+
],
811
products: [
12+
.library(
13+
name: "TravisNIO",
14+
targets: ["TravisNIO"]
15+
),
916
.library(
1017
name: "TravisClient",
11-
targets: ["TravisClient"]),
18+
targets: ["TravisClient"]
19+
),
20+
.library(
21+
name: "TravisV3Core",
22+
targets: ["TravisV3Core"]
23+
),
24+
.executable(name: "travis-cli", targets: ["CLI"]),
1225
],
1326
dependencies: [
14-
.package(url: "https://github.com/antitypical/Result", from: "3.0.0"),
27+
.package(url: "https://github.com/iainsmith/async-http-client.git", .branch("master")),
28+
.package(url: "https://github.com/apple/swift-argument-parser", from: "0.0.1"),
1529
],
1630
targets: [
1731
.target(
1832
name: "TravisClient",
19-
dependencies: ["Result"]),
33+
dependencies: ["TravisV3Core"]
34+
),
35+
.target(
36+
name: "TravisNIO",
37+
dependencies: [
38+
.product(name: "AsyncHTTPClient", package: "async-http-client"),
39+
"TravisV3Core",
40+
]
41+
),
42+
.target(name: "TravisV3Core", dependencies: []),
43+
.target(
44+
name: "CLI",
45+
dependencies: [
46+
"TravisNIO",
47+
.product(name: "ArgumentParser", package: "swift-argument-parser"),
48+
]
49+
),
2050
.testTarget(
2151
name: "TravisClientTests",
22-
dependencies: ["TravisClient"]),
23-
]
52+
dependencies: ["TravisClient"]
53+
),
54+
],
55+
swiftLanguageVersions: [.v5]
2456
)

README.md

Lines changed: 100 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,47 +1,71 @@
1-
# TravisClient
1+
# swift-travis
22

3-
A Travis v3 API client for Swift 4.x
3+
A Swift interface to the travis-ci v3 API. Supports [travis-ci.org](https://travis-ci.org), [travis-ci.com](https://travis-ci.com) & on premise deployments.
44

55
[![Build Status](https://travis-ci.org/iainsmith/TravisClient.svg?branch=master)](https://travis-ci.org/iainsmith/TravisClient) | [Read the docs](https://iainsmith.github.io/TravisClient/index.html)
66

77
## Installation
88

9-
* Install with cocoapods: `pod 'TravisClient'`
10-
* Install with SPM `.package(url: "https://github.com/IainSmith/TravisClient", from: "0.2.0"),`
9+
* Install with SPM `.package(url: "https://github.com/iainsmith/swift-travis", from: "0.3.0"),`
10+
* The swift-travis package has the following 3 libraries you can use in your application.
1111

12-
### Quick Usage
12+
| Use-case | interface | target |
13+
|---|---|---|
14+
| iOS & Mac apps | URLSession | `.product(name: "TravisClient", package: "swift-travis")`|
15+
| CLI & Server APPs | EventLoopFuture | `.product(name: "TravisClientNIO", package: "swift-travis")` |
16+
| Build your own package | Codable structs | `.product(name: "TravisV3Core", package: "swift-travis")` |
17+
18+
### Quick example
1319

1420
```swift
1521
import TravisClient
1622

17-
let key: String = "YOUR_TRAVIS_API_KEY"
23+
let key: String = ProcessInfo().environment["TRAVIS_TOKEN]"!
1824
let client = TravisClient(token: key, host: .org)
1925

20-
client.activeBuilds { (result: Result<Meta<[Build]>, TravisError>) in
21-
/// In swift 4.1 you can subscript directly into the Result
22-
let activeBuildCount: Int? = result[\[Build].count]
23-
let firstBuildPRTitle: String? = result[\.first?.pullRequestTitle]
26+
client.userBuilds(query: query) { result in
27+
switch result {
28+
case let .success(builds):
29+
builds.count
30+
builds.first?.pullRequestTitle
31+
case let .failure(error):
32+
// error handling
33+
}
2434
}
2535
```
2636

37+
### Swift NIO examples
38+
39+
```swift
40+
import TravisClientNIO
41+
42+
let key: String = ProcessInfo().environment["TRAVIS_TOKEN]"!
43+
let client = TravisClient(token: key, host: .org) // You can also pass an `EventLoopGroup`
44+
45+
let builds = try client.builds(forRepository: repo).wait()
46+
print(builds.count)
47+
print(builds.first?.pullRequestTitle)
48+
```
49+
2750
## Travis API Concepts.
2851

29-
[Read the Travis API documentation](https://developer.travis-ci.com/gettingstarted) for much more detail. TravisClient follows the same naming conventions & concepts from the official api documentation.
52+
The api mirrors the names & concepts from the official [Travis API documentation](https://developer.travis-ci.com/gettingstarted).
3053

3154
#### Minimal vs Standard Representation.
3255

3356
Each model object has two representations. A standard representation that includes all the attributes and a minimal representation that includes some attributes.
3457

3558
```swift
3659
public struct MinimalJob: Codable, Minimal {
37-
public let id: Int
60+
public typealias Full = Job
61+
public let id: Int
3862
}
3963

4064
public struct Job: Codable {
41-
public let id: Int
42-
public let number: String
43-
public let state: String
44-
// 10 other properties
65+
public let id: Int
66+
public let number: String
67+
public let state: String
68+
// 10 other properties
4569
}
4670
```
4771

@@ -54,45 +78,76 @@ let build: Meta<Build>
5478
let minimalJob: Embed<MinimalJob> = build.jobs.first! // don't do this in production code
5579

5680
client.follow(embed: minimalJob) { fullJob in
57-
print(fullJob[\.state])
81+
print(fullJob.state)
5882
}
5983
```
6084

61-
## Usage
85+
##### Modelling the hypermedia API
86+
87+
The Travis v3 API uses a custom hypermedia API spec, that is [described on their website](https://developer.travis-ci.com/hypermedia#hypermedia). The `TravisV3Core` targets has a generic `Metadata<Object>` struct.
6288

6389
```swift
64-
import TravisClient
90+
@dynamicMemberLookup
91+
public struct Metadata<Object: Codable>: Codable {
92+
public let type: String
93+
public let path: String
94+
public let pagination: Pagination<Object>?
95+
public let object: Object
96+
}
6597

66-
let key: String = "YOUR_TRAVIS_API_KEY"
67-
let client = TravisClient(token: key, host: .org)
98+
let builds: Metadata<[Build]>
99+
// dynamicMemberLookup means we can often use Metadata<[Build]> as [Build]
100+
builds.count == builds.object.count
101+
```
68102

69-
client.activeBuilds { (result: Result<Meta<[Build]>, TravisError>) in
103+
Metadata<Object> gives us direct access to the `Pagination` data and the underlying `Object` through dynamicMemberLookup.
70104

71-
#if swift(>=4.1)
72-
/// In swift 4.1 you can subscript directly into the Result
73-
let activeBuildCount: Int? = result[\Build.id]
74-
#else
75-
/// In swift 4.0 you need to subscript into the optional value of a result.
76-
let resultBuildNumber: Int? = result.value?[\.id]
77-
#endif
105+
The travis API often nests resources which is modelled with the `Embed<Object>` struct.
78106

107+
```swift
108+
@dynamicMemberLookup
109+
public struct Embed<Object: Codable>: Codable {
110+
public let type: String
111+
public let path: String?
112+
public let object: Object
113+
}
114+
115+
struct Build {
116+
public let repository: Embed<MinimalRepository>
117+
public let branch: Embed<MinimalBranch>
118+
public let commit: Embed<MinimalCommit>
119+
}
120+
121+
let build: Metadata<Build>
122+
let branchName: String = build.branch.name
123+
```
124+
125+
##### Links
126+
* You can call `client.follow(page:)` to load the a page of results from the paginated API
127+
* Similarly you can all `client.follow(embed:)` to fetch the Full version of a MinimalResource. e.g `MinimalBranch` -> `Branch`.
128+
129+
130+
```swift
131+
import TravisClient
132+
133+
client.activeBuilds { (result: Result<MetaData<[Build]>, TravisError>) in
79134

80135
/// You can also switch over the result
81136
switch result {
82-
case success(let builds: Meta<[Build]>):
137+
case success(let builds: MetaData<[Build]>)
83138
// Find the number of active builds
84-
builds[\.count])
139+
builds.count
85140

86141
// Find the jobs associated with this build
87-
guard let job: Embed<MinimalJob> = jobs[\.first] else { return }
142+
guard let job: Embed<MinimalJob> = jobs.first else { return }
88143

89-
// Each API call returns one resource that has a 'standard representation' full object in this case supports hyper media so you can easily load the full object in a second request.
90-
client.follow(job) { (jobResult: Meta<Job>) in
144+
// Each API call returns one resource that has a 'standard representation' full object in this case supports hyper media so you can easily load the full object in a second request.
145+
client.follow(embed: job) { (jobResult: Result<MetaData<Job>>) in
91146
print(jobResult)
92147
}
93148

94149
// Or follow a paginated request
95-
client.follow(builds.pagination?.next) { nextPage in
150+
client.follow(page: builds.pagination.next) { nextPage in
96151
print(nextPage)
97152
}
98153

@@ -107,17 +162,24 @@ client.activeBuilds { (result: Result<Meta<[Build]>, TravisError>) in
107162

108163
```sh
109164
# JSON parsing tests
110-
> swift test --filter TravisClientTests.JSONTests
165+
> swift test
111166

112-
# Hit the travis.org API
167+
# Hit the travis.org API
113168
> TRAVIS_TOKEN=YOUR_TOKEN_HERE swift test
114169
```
115170

171+
The Integration tests only run if you have a `TRAVIS_TOKEN` environment variable set. This uses `XCTSkipIf` which requires Xcode 11.
172+
173+
## Supported swift versions
174+
175+
If you are using Swift 5.1 or newer you can use the latest release
176+
If you need support for Swift 4.2 or older use version `0.2.0`
177+
116178
## TODO
117179

118180
* [x] Support paginated requests
119181
* [x] Add User Model
120182
* [x] Add Simple Query parameters
121183
* [ ] Add Stages Model
122184
* [ ] Add more typed sort parameters
123-
* [ ] Support Type safe Eager Loading.
185+
* [ ] Support Type safe Eager Loading.

0 commit comments

Comments
 (0)