├── .gitignore
├── CHANGELOG.md
├── CODE_OF_CONDUCT.md
├── LICENSE
├── Playgrounds
└── XcodeServerSDK.playground
│ ├── Contents.swift
│ ├── Sources
│ └── SupportCode.swift
│ ├── contents.xcplayground
│ └── timeline.xctimeline
├── Podfile
├── Podfile.lock
├── README.md
├── XcodeServerSDK.podspec
├── XcodeServerSDK.xcodeproj
├── project.pbxproj
├── project.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ │ └── XcodeServerSDK.xccheckout
└── xcshareddata
│ └── xcschemes
│ └── XcodeServerSDK.xcscheme
├── XcodeServerSDK.xcworkspace
├── contents.xcworkspacedata
└── xcshareddata
│ └── XcodeServerSDK.xccheckout
├── XcodeServerSDK
├── API Routes
│ ├── XcodeServer+Auth.swift
│ ├── XcodeServer+Bot.swift
│ ├── XcodeServer+Device.swift
│ ├── XcodeServer+Integration.swift
│ ├── XcodeServer+LiveUpdates.swift
│ ├── XcodeServer+Miscs.swift
│ ├── XcodeServer+Platform.swift
│ ├── XcodeServer+Repository.swift
│ ├── XcodeServer+SCM.swift
│ └── XcodeServer+Toolchain.swift
├── Info.plist
├── Server Entities
│ ├── Bot.swift
│ ├── BotConfiguration.swift
│ ├── BotSchedule.swift
│ ├── Commit.swift
│ ├── Contributor.swift
│ ├── Device.swift
│ ├── DeviceSpecification.swift
│ ├── EmailConfiguration.swift
│ ├── File.swift
│ ├── Integration.swift
│ ├── IntegrationCommits.swift
│ ├── IntegrationIssue.swift
│ ├── IntegrationIssues.swift
│ ├── LiveUpdateMessage.swift
│ ├── Repository.swift
│ ├── SourceControlBlueprint.swift
│ ├── TestHierarchy.swift
│ ├── Toolchain.swift
│ ├── Trigger.swift
│ └── TriggerConditions.swift
├── Server Helpers
│ ├── CIServer.swift
│ ├── SocketIOHelper.swift
│ └── XcodeServerConstants.swift
├── XcodeServer.swift
├── XcodeServerConfig.swift
├── XcodeServerEndpoints.swift
├── XcodeServerEntity.swift
├── XcodeServerFactory.swift
└── XcodeServerSDK.h
├── XcodeServerSDKTests
├── BotConfigurationTests.swift
├── BotParsingTests.swift
├── Casettes
│ ├── bot_deletion.json
│ ├── get_devices.json
│ ├── get_integration.json
│ ├── get_integration_commits.json
│ ├── get_integration_issues.json
│ ├── get_platforms.json
│ ├── get_repositories.json
│ ├── get_toolchains.json
│ ├── hostname.json
│ └── osx_bot.json
├── ContributorTests.swift
├── Data
│ ├── create_ios_bot.json
│ ├── create_osx_bot.json
│ ├── create_watch_bot.json
│ ├── platforms.json
│ ├── scm_branches_request_no_fingerprint.json
│ ├── scm_branches_request_with_fingerprint.json
│ ├── scm_branches_response_error.json
│ └── scm_branches_response_success.json
├── DevicesTests.swift
├── FileTests.swift
├── Info.plist
├── IntegrationTests.swift
├── IssueTests.swift
├── LiveUpdatesTests.swift
├── MiscsTests.swift
├── PlatformTests.swift
├── RepositoryTests.swift
├── TestUtils.swift
├── ToolchainTests.swift
├── XcodeServerConfigTests.swift
├── XcodeServerEndpointsTests.swift
├── XcodeServerEntityTests.swift
└── XcodeServerTests.swift
└── fastlane
├── Fastfile
└── README.md
/.gitignore:
--------------------------------------------------------------------------------
1 | # Xcode
2 |
3 | ## Build generated
4 | build/
5 | .AppleDouble
6 | DerivedData
7 |
8 | # Icon must end with two \r
9 | Icon
10 |
11 |
12 | ## Various settings
13 | ._*
14 |
15 | # Files that might appear in the root of a volume
16 | .DocumentRevisions-V100
17 | .fseventsd
18 | .Spotlight-V100
19 | .TemporaryItems
20 | .Trashes
21 | .VolumeIcon.icns
22 |
23 | # Directories potentially created on remote AFP share
24 | .AppleDB
25 | .AppleDesktop
26 | Network Trash Folder
27 | Temporary Items
28 | .apdisk
29 |
30 |
31 | ### Xcode ###
32 | build/
33 | *.pbxuser
34 | !default.pbxuser
35 | *.mode1v3
36 | !default.mode1v3
37 | *.mode2v3
38 | !default.mode2v3
39 | *.perspectivev3
40 | !default.perspectivev3
41 | xcuserdata
42 |
43 | ## Other
44 | *.moved-aside
45 | DerivedData
46 | *.xcuserstate
47 |
48 | ## Obj-C/Swift specific
49 | *.hmap
50 | *.ipa
51 |
52 | # CocoaPods
53 | #
54 | # We recommend against adding the Pods directory to your .gitignore. However
55 | # you should judge for yourself, the pros and cons are mentioned at:
56 | # http://guides.cocoapods.org/using/using-cocoapods.html#should-i-ignore-the-pods-directory-in-source-control
57 | #
58 | Pods/
59 |
60 | # Carthage
61 | #
62 | # Add this line if you want to avoid checking in source code from Carthage dependencies.
63 | Carthage/Checkouts
64 |
65 | # project files should be checked into the repository, unless a significant
66 | # proportion of contributors will probably not be using SublimeText
67 | # *.sublime-project
68 |
69 | # sftp configuration file
70 | sftp-config.json
71 |
72 |
73 | ### AppCode ###
74 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm
75 |
76 | *.iml
77 |
78 | ## Directory-based project format:
79 | Carthage/Build
80 | # if you remove the above rule, at least ignore the following:
81 |
82 | # User-specific stuff:
83 | # .idea/workspace.xml
84 | # .idea/tasks.xml
85 | # .idea/dictionaries
86 |
87 | # Sensitive or high-churn files:
88 | # .idea/dataSources.ids
89 | # .idea/dataSources.xml
90 | # .idea/sqlDataSources.xml
91 | # .idea/dynamic.xml
92 | # .idea/uiDesigner.xml
93 |
94 | # Gradle:
95 | # .idea/gradle.xml
96 | # .idea/libraries
97 |
98 | # Mongo Explorer plugin:
99 | # .idea/mongoSettings.xml
100 |
101 | ## File-based project format:
102 | *.ipr
103 | *.iws
104 |
105 | ## Plugin-specific files:
106 |
107 | # IntelliJ
108 | /out/
109 |
110 | # mpeltonen/sbt-idea plugin
111 | .idea_modules/
112 |
113 | # JIRA plugin
114 | atlassian-ide-plugin.xml
115 |
116 | # Crashlytics plugin (for Android Studio and IntelliJ)
117 | com_crashlytics_export_strings.xml
118 | crashlytics.properties
119 | crashlytics-build.properties
120 |
121 | # fastlane
122 | fastlane/report.xml
123 | fastlane/test_output/
124 |
125 |
--------------------------------------------------------------------------------
/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | # Contributor Covenant Code of Conduct
2 |
3 | ## Our Pledge
4 |
5 | In the interest of fostering an open and welcoming environment, we as
6 | contributors and maintainers pledge to making participation in our project and
7 | our community a harassment-free experience for everyone, regardless of age, body
8 | size, disability, ethnicity, gender identity and expression, level of experience,
9 | nationality, personal appearance, race, religion, or sexual identity and
10 | orientation.
11 |
12 | ## Our Standards
13 |
14 | Examples of behavior that contributes to creating a positive environment
15 | include:
16 |
17 | * Using welcoming and inclusive language
18 | * Being respectful of differing viewpoints and experiences
19 | * Gracefully accepting constructive criticism
20 | * Focusing on what is best for the community
21 | * Showing empathy towards other community members
22 |
23 | Examples of unacceptable behavior by participants include:
24 |
25 | * The use of sexualized language or imagery and unwelcome sexual attention or
26 | advances
27 | * Trolling, insulting/derogatory comments, and personal or political attacks
28 | * Public or private harassment
29 | * Publishing others' private information, such as a physical or electronic
30 | address, without explicit permission
31 | * Other conduct which could reasonably be considered inappropriate in a
32 | professional setting
33 |
34 | ## Our Responsibilities
35 |
36 | Project maintainers are responsible for clarifying the standards of acceptable
37 | behavior and are expected to take appropriate and fair corrective action in
38 | response to any instances of unacceptable behavior.
39 |
40 | Project maintainers have the right and responsibility to remove, edit, or
41 | reject comments, commits, code, wiki edits, issues, and other contributions
42 | that are not aligned to this Code of Conduct, or to ban temporarily or
43 | permanently any contributor for other behaviors that they deem inappropriate,
44 | threatening, offensive, or harmful.
45 |
46 | ## Scope
47 |
48 | This Code of Conduct applies both within project spaces and in public spaces
49 | when an individual is representing the project or its community. Examples of
50 | representing a project or community include using an official project e-mail
51 | address, posting via an official social media account, or acting as an appointed
52 | representative at an online or offline event. Representation of a project may be
53 | further defined and clarified by project maintainers.
54 |
55 | ## Enforcement
56 |
57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be
58 | reported by contacting the project team at czechboy0@gmail.com. All
59 | complaints will be reviewed and investigated and will result in a response that
60 | is deemed necessary and appropriate to the circumstances. The project team is
61 | obligated to maintain confidentiality with regard to the reporter of an incident.
62 | Further details of specific enforcement policies may be posted separately.
63 |
64 | Project maintainers who do not follow or enforce the Code of Conduct in good
65 | faith may face temporary or permanent repercussions as determined by other
66 | members of the project's leadership.
67 |
68 | ## Attribution
69 |
70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
71 | available at [http://contributor-covenant.org/version/1/4][version]
72 |
73 | [homepage]: http://contributor-covenant.org
74 | [version]: http://contributor-covenant.org/version/1/4/
75 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2015 Honza Dvorsky
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
23 |
--------------------------------------------------------------------------------
/Playgrounds/XcodeServerSDK.playground/Contents.swift:
--------------------------------------------------------------------------------
1 | //: Playground - noun: a place where people can play
2 |
3 | import Foundation
4 | import XcodeServerSDK
5 | import XCPlayground
6 |
7 | let serverConfig = try! XcodeServerConfig(host: "https://127.0.0.1", user: "MacUser", password: "Secr3t")
8 |
9 | let server = XcodeServerFactory.server(serverConfig)
10 |
11 | server.getBots { (bots, error) -> () in
12 |
13 | print(error)
14 | print(bots)
15 | }
16 |
17 | XCPSetExecutionShouldContinueIndefinitely(true)
18 |
--------------------------------------------------------------------------------
/Playgrounds/XcodeServerSDK.playground/Sources/SupportCode.swift:
--------------------------------------------------------------------------------
1 | //
2 | // This file (and all other Swift source files in the Sources directory of this playground) will be precompiled into a framework which is automatically made available to TestOSX_Playground.playground.
3 | //
4 |
--------------------------------------------------------------------------------
/Playgrounds/XcodeServerSDK.playground/contents.xcplayground:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/Playgrounds/XcodeServerSDK.playground/timeline.xctimeline:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/Podfile:
--------------------------------------------------------------------------------
1 |
2 | use_frameworks!
3 |
4 | def utils
5 | pod 'BuildaUtils', '~> 0.3.2'
6 | end
7 |
8 | def tests
9 | pod 'DVR', :git => "https://github.com/czechboy0/DVR.git", :tag => "v0.0.5-czechboy0"
10 | # pod 'Nimble', '~> 3.1.0'
11 | pod 'Nimble', :git => "https://github.com/Quick/Nimble.git", :commit => "b9256b0bdecc4ef1f659b7663dcd3aab6f43fb5f"
12 | end
13 |
14 | target 'XcodeServerSDK' do
15 | utils
16 | end
17 |
18 | target 'XcodeServerSDKTests' do
19 | utils
20 | tests
21 | end
22 |
--------------------------------------------------------------------------------
/Podfile.lock:
--------------------------------------------------------------------------------
1 | PODS:
2 | - BuildaUtils (0.3.2):
3 | - SwiftSafe (~> 0.1)
4 | - DVR (0.0.4-czechboy0)
5 | - Nimble (3.1.0)
6 | - SwiftSafe (0.1)
7 |
8 | DEPENDENCIES:
9 | - BuildaUtils (~> 0.3.2)
10 | - DVR (from `https://github.com/czechboy0/DVR.git`, tag `v0.0.5-czechboy0`)
11 | - Nimble (from `https://github.com/Quick/Nimble.git`, commit `b9256b0bdecc4ef1f659b7663dcd3aab6f43fb5f`)
12 |
13 | EXTERNAL SOURCES:
14 | DVR:
15 | :git: https://github.com/czechboy0/DVR.git
16 | :tag: v0.0.5-czechboy0
17 | Nimble:
18 | :commit: b9256b0bdecc4ef1f659b7663dcd3aab6f43fb5f
19 | :git: https://github.com/Quick/Nimble.git
20 |
21 | CHECKOUT OPTIONS:
22 | DVR:
23 | :git: https://github.com/czechboy0/DVR.git
24 | :tag: v0.0.5-czechboy0
25 | Nimble:
26 | :commit: b9256b0bdecc4ef1f659b7663dcd3aab6f43fb5f
27 | :git: https://github.com/Quick/Nimble.git
28 |
29 | SPEC CHECKSUMS:
30 | BuildaUtils: 1c6bf3a28948c3aae242171abf2474cd4746a2d1
31 | DVR: 386f347071f55f3f9105239db6764483009ec875
32 | Nimble: eb2a9b164b9a3f16df6581c692a0bfced7d072a4
33 | SwiftSafe: 77ffd12b02678790bec1ef56a2d14ec5036f1fd6
34 |
35 | PODFILE CHECKSUM: 2d0c8056afb549d3590407decab7568949826dc2
36 |
37 | COCOAPODS: 1.0.1
38 |
--------------------------------------------------------------------------------
/XcodeServerSDK.podspec:
--------------------------------------------------------------------------------
1 | Pod::Spec.new do |s|
2 |
3 | s.name = "XcodeServerSDK"
4 | s.version = "0.7.1"
5 | s.summary = "Access Xcode Server API with native Swift objects."
6 |
7 | s.homepage = "https://github.com/czechboy0/XcodeServerSDK"
8 | s.license = { :type => "MIT", :file => "LICENSE" }
9 |
10 | s.author = { "Honza Dvorsky" => "honzadvorsky.com" }
11 | s.social_media_url = "http://twitter.com/czechboy0"
12 |
13 | s.ios.deployment_target = "8.0"
14 | s.osx.deployment_target = "10.10"
15 | s.watchos.deployment_target = "2.0"
16 | s.tvos.deployment_target = "9.0"
17 |
18 | s.source = { :git => "https://github.com/czechboy0/XcodeServerSDK.git", :tag => "v#{s.version}" }
19 |
20 | s.source_files = "XcodeServerSDK/**/*.{swift}"
21 |
22 | # load the dependencies from the podfile for target ekgclient
23 | podfile_deps = Podfile.from_file(Dir["Podfile"].first).target_definitions["XcodeServerSDK"].dependencies
24 | podfile_deps.each do |dep|
25 | s.dependency dep.name, dep.requirement.to_s
26 | end
27 |
28 | end
29 |
--------------------------------------------------------------------------------
/XcodeServerSDK.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/XcodeServerSDK.xcodeproj/project.xcworkspace/xcshareddata/XcodeServerSDK.xccheckout:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDESourceControlProjectFavoriteDictionaryKey
6 |
7 | IDESourceControlProjectIdentifier
8 | 1D9650B0-8D54-46C2-BCB1-C46BB6D63901
9 | IDESourceControlProjectName
10 | XcodeServerSDK
11 | IDESourceControlProjectOriginsDictionary
12 |
13 | A36AEFA3F9FF1F738E92F0C497C14977DCE02B97
14 | github.com:czechboy0/XcodeServerSDK.git
15 |
16 | IDESourceControlProjectPath
17 | XcodeServerSDK.xcodeproj
18 | IDESourceControlProjectRelativeInstallPathDictionary
19 |
20 | A36AEFA3F9FF1F738E92F0C497C14977DCE02B97
21 | ../..
22 |
23 | IDESourceControlProjectURL
24 | github.com:czechboy0/XcodeServerSDK.git
25 | IDESourceControlProjectVersion
26 | 111
27 | IDESourceControlProjectWCCIdentifier
28 | A36AEFA3F9FF1F738E92F0C497C14977DCE02B97
29 | IDESourceControlProjectWCConfigurations
30 |
31 |
32 | IDESourceControlRepositoryExtensionIdentifierKey
33 | public.vcs.git
34 | IDESourceControlWCCIdentifierKey
35 | A36AEFA3F9FF1F738E92F0C497C14977DCE02B97
36 | IDESourceControlWCCName
37 | XcodeServerSDK
38 |
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/XcodeServerSDK.xcodeproj/xcshareddata/xcschemes/XcodeServerSDK.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
31 |
32 |
34 |
40 |
41 |
42 |
43 |
44 |
50 |
51 |
52 |
53 |
54 |
55 |
65 |
66 |
72 |
73 |
74 |
75 |
76 |
77 |
83 |
84 |
90 |
91 |
92 |
93 |
95 |
96 |
99 |
100 |
101 |
--------------------------------------------------------------------------------
/XcodeServerSDK.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/XcodeServerSDK.xcworkspace/xcshareddata/XcodeServerSDK.xccheckout:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDESourceControlProjectFavoriteDictionaryKey
6 |
7 | IDESourceControlProjectIdentifier
8 | 26859E05-0D4F-4F4D-BD1E-10E0E64B6B5B
9 | IDESourceControlProjectName
10 | XcodeServerSDK
11 | IDESourceControlProjectOriginsDictionary
12 |
13 | A36AEFA3F9FF1F738E92F0C497C14977DCE02B97
14 | github.com:czechboy0/XcodeServerSDK.git
15 |
16 | IDESourceControlProjectPath
17 | XcodeServerSDK.xcworkspace
18 | IDESourceControlProjectRelativeInstallPathDictionary
19 |
20 | A36AEFA3F9FF1F738E92F0C497C14977DCE02B97
21 | ..
22 |
23 | IDESourceControlProjectURL
24 | github.com:czechboy0/XcodeServerSDK.git
25 | IDESourceControlProjectVersion
26 | 111
27 | IDESourceControlProjectWCCIdentifier
28 | A36AEFA3F9FF1F738E92F0C497C14977DCE02B97
29 | IDESourceControlProjectWCConfigurations
30 |
31 |
32 | IDESourceControlRepositoryExtensionIdentifierKey
33 | public.vcs.git
34 | IDESourceControlWCCIdentifierKey
35 | A36AEFA3F9FF1F738E92F0C497C14977DCE02B97
36 | IDESourceControlWCCName
37 | XcodeServerSDK
38 |
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/XcodeServerSDK/API Routes/XcodeServer+Auth.swift:
--------------------------------------------------------------------------------
1 | //
2 | // XcodeServer+Auth.swift
3 | // XcodeServerSDK
4 | //
5 | // Created by Mateusz Zając on 30.06.2015.
6 | // Copyright © 2015 Honza Dvorsky. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import BuildaUtils
11 |
12 | // MARK: - XcodeSever API Routes for Authorization
13 | extension XcodeServer {
14 |
15 | // MARK: Sign in/Sign out
16 |
17 | /**
18 | XCS API call for user sign in.
19 |
20 | - parameter success: Indicates whether sign in was successful.
21 | - parameter error: Error indicating failure of sign in.
22 | */
23 | public final func login(completion: (success: Bool, error: NSError?) -> ()) {
24 |
25 | self.sendRequestWithMethod(.POST, endpoint: .Login, params: nil, query: nil, body: nil) { (response, body, error) -> () in
26 |
27 | if error != nil {
28 | completion(success: false, error: error)
29 | return
30 | }
31 |
32 | if let response = response {
33 | if response.statusCode == 204 {
34 | completion(success: true, error: nil)
35 | } else {
36 | completion(success: false, error: Error.withInfo("Wrong status code: \(response.statusCode)"))
37 | }
38 | return
39 | }
40 | completion(success: false, error: Error.withInfo("Nil response"))
41 | }
42 | }
43 |
44 | /**
45 | XCS API call for user sign out.
46 |
47 | - parameter success: Indicates whether sign out was successful.
48 | - parameter error: Error indicating failure of sign out.
49 | */
50 | public final func logout(completion: (success: Bool, error: NSError?) -> ()) {
51 |
52 | self.sendRequestWithMethod(.POST, endpoint: .Logout, params: nil, query: nil, body: nil) { (response, body, error) -> () in
53 |
54 | if error != nil {
55 | completion(success: false, error: error)
56 | return
57 | }
58 |
59 | if let response = response {
60 | if response.statusCode == 204 {
61 | completion(success: true, error: nil)
62 | } else {
63 | completion(success: false, error: Error.withInfo("Wrong status code: \(response.statusCode)"))
64 | }
65 | return
66 | }
67 | completion(success: false, error: Error.withInfo("Nil response"))
68 | }
69 | }
70 |
71 | // MARK: User access verification
72 |
73 | /**
74 | XCS API call to verify if logged in user can create bots.
75 |
76 | - parameter canCreateBots: Indicator of bot creation accessibility.
77 | - parameter error: Optional error.
78 | */
79 | public final func getUserCanCreateBots(completion: (canCreateBots: Bool, error: NSError?) -> ()) {
80 |
81 | self.sendRequestWithMethod(.GET, endpoint: .UserCanCreateBots, params: nil, query: nil, body: nil) { (response, body, error) -> () in
82 |
83 | if let error = error {
84 | completion(canCreateBots: false, error: error)
85 | return
86 | }
87 |
88 | if let body = body as? NSDictionary {
89 | if let canCreateBots = body["result"] as? Bool where canCreateBots == true {
90 | completion(canCreateBots: true, error: nil)
91 | } else {
92 | completion(canCreateBots: false, error: Error.withInfo("Specified user cannot create bots"))
93 | }
94 | } else {
95 | completion(canCreateBots: false, error: Error.withInfo("Wrong body \(body)"))
96 | }
97 | }
98 | }
99 |
100 | /**
101 | Checks whether the current user has the rights to create bots and perform other similar "write" actions.
102 | Xcode Server offers two tiers of users, ones for reading only ("viewers") and others for management.
103 | Here we check the current user can manage XCS, which is useful for projects like Buildasaur.
104 |
105 | - parameter success: Indicates if user can create bots.
106 | - parameter error: Error if something went wrong.
107 | */
108 | public final func verifyXCSUserCanCreateBots(completion: (success: Bool, error: NSError?) -> ()) {
109 |
110 | //the way we check availability is first by logging out (does nothing if not logged in) and then
111 | //calling getUserCanCreateBots, which, if necessary, automatically authenticates with Basic auth before resolving to true or false in JSON.
112 |
113 | self.logout { (success, error) -> () in
114 |
115 | if let error = error {
116 | completion(success: false, error: error)
117 | return
118 | }
119 |
120 | self.getUserCanCreateBots { (canCreateBots, error) -> () in
121 |
122 | if let error = error {
123 | completion(success: false, error: error)
124 | return
125 | }
126 |
127 | completion(success: canCreateBots, error: nil)
128 | }
129 | }
130 | }
131 |
132 | }
--------------------------------------------------------------------------------
/XcodeServerSDK/API Routes/XcodeServer+Device.swift:
--------------------------------------------------------------------------------
1 | //
2 | // XcodeServer+Device.swift
3 | // XcodeServerSDK
4 | //
5 | // Created by Mateusz Zając on 01/07/15.
6 | // Copyright © 2015 Honza Dvorsky. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import BuildaUtils
11 |
12 | // MARK: - XcodeSever API Routes for Devices management
13 | extension XcodeServer {
14 |
15 | /**
16 | XCS API call for retrieving all registered devices on OS X Server.
17 |
18 | - parameter devices: Optional array of available devices.
19 | - parameter error: Optional error indicating that something went wrong.
20 | */
21 | public final func getDevices(completion: (devices: [Device]?, error: NSError?) -> ()) {
22 |
23 | self.sendRequestWithMethod(.GET, endpoint: .Devices, params: nil, query: nil, body: nil) { (response, body, error) -> () in
24 |
25 | if error != nil {
26 | completion(devices: nil, error: error)
27 | return
28 | }
29 |
30 | if let array = (body as? NSDictionary)?["results"] as? NSArray {
31 | let (result, error): ([Device]?, NSError?) = unthrow {
32 | return try XcodeServerArray(array)
33 | }
34 | completion(devices: result, error: error)
35 | } else {
36 | completion(devices: nil, error: Error.withInfo("Wrong body \(body)"))
37 | }
38 | }
39 | }
40 |
41 | }
42 |
--------------------------------------------------------------------------------
/XcodeServerSDK/API Routes/XcodeServer+LiveUpdates.swift:
--------------------------------------------------------------------------------
1 | //
2 | // XcodeServer+LiveUpdates.swift
3 | // XcodeServerSDK
4 | //
5 | // Created by Honza Dvorsky on 25/09/2015.
6 | // Copyright © 2015 Honza Dvorsky. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import BuildaUtils
11 |
12 | // MARK: - XcodeSever API Routes for Live Updates
13 | extension XcodeServer {
14 |
15 | public typealias MessageHandler = (messages: [LiveUpdateMessage]) -> ()
16 | public typealias StopHandler = () -> ()
17 | public typealias ErrorHandler = (error: ErrorType) -> ()
18 |
19 | private class LiveUpdateState {
20 | var task: NSURLSessionTask?
21 | var messageHandler: MessageHandler?
22 | var errorHandler: ErrorHandler?
23 | var pollId: String?
24 | var terminated: Bool = false
25 |
26 | func cancel() {
27 | self.task?.cancel()
28 | self.task = nil
29 | self.terminated = true
30 | }
31 |
32 | func error(error: ErrorType) {
33 | self.cancel()
34 | self.errorHandler?(error: error)
35 | }
36 |
37 | deinit {
38 | self.cancel()
39 | }
40 | }
41 |
42 | /**
43 | * Returns StopHandler - call it when you want to stop receiving updates.
44 | */
45 | public func startListeningForLiveUpdates(message: MessageHandler, error: ErrorHandler? = nil) -> StopHandler {
46 |
47 | let state = LiveUpdateState()
48 | state.errorHandler = error
49 | state.messageHandler = message
50 | self.startPolling(state)
51 | return {
52 | state.cancel()
53 | }
54 | }
55 |
56 | private func queryWithTimestamp() -> [String: String] {
57 | let timestamp = Int(NSDate().timeIntervalSince1970)*1000
58 | return [
59 | "t": "\(timestamp)"
60 | ]
61 | }
62 |
63 | private func sendRequest(state: LiveUpdateState, params: [String: String]?, completion: (message: String) -> ()) {
64 |
65 | let query = queryWithTimestamp()
66 | let task = self.sendRequestWithMethod(.GET, endpoint: .LiveUpdates, params: params, query: query, body: nil, portOverride: 443) {
67 | (response, body, error) -> () in
68 |
69 | if let error = error {
70 | state.error(error)
71 | return
72 | }
73 |
74 | guard let message = body as? String else {
75 | let e = Error.withInfo("Wrong body: \(body)")
76 | state.error(e)
77 | return
78 | }
79 |
80 | completion(message: message)
81 | }
82 | state.task = task
83 | }
84 |
85 | private func startPolling(state: LiveUpdateState) {
86 |
87 | self.sendRequest(state, params: nil) { [weak self] (message) -> () in
88 | self?.processInitialResponse(message, state: state)
89 | }
90 | }
91 |
92 | private func processInitialResponse(initial: String, state: LiveUpdateState) {
93 | if let pollId = initial.componentsSeparatedByString(":").first {
94 | state.pollId = pollId
95 | self.poll(state)
96 | } else {
97 | state.error(Error.withInfo("Unexpected initial poll message: \(initial)"))
98 | }
99 | }
100 |
101 | private func poll(state: LiveUpdateState) {
102 | precondition(state.pollId != nil)
103 | let params = [
104 | "poll_id": state.pollId!
105 | ]
106 |
107 | self.sendRequest(state, params: params) { [weak self] (message) -> () in
108 |
109 | let packets = SocketIOHelper.parsePackets(message)
110 |
111 | do {
112 | try self?.handlePackets(packets, state: state)
113 | } catch {
114 | state.error(error)
115 | }
116 | }
117 | }
118 |
119 | private func handlePackets(packets: [SocketIOPacket], state: LiveUpdateState) throws {
120 |
121 | //check for errors
122 | if let lastPacket = packets.last where lastPacket.type == .Error {
123 | let (_, advice) = lastPacket.parseError()
124 | if
125 | let advice = advice,
126 | case .Reconnect = advice {
127 | //reconnect!
128 | self.startPolling(state)
129 | return
130 | }
131 | print("Unrecognized socket.io error: \(lastPacket.stringPayload)")
132 | }
133 |
134 | //we good?
135 | let events = packets.filter { $0.type == .Event }
136 | let validEvents = events.filter { $0.jsonPayload != nil }
137 | let messages = try validEvents.map { try LiveUpdateMessage(json: $0.jsonPayload!) }
138 | if messages.count > 0 {
139 | state.messageHandler?(messages: messages)
140 | }
141 | if !state.terminated {
142 | self.poll(state)
143 | }
144 | }
145 | }
146 |
147 |
--------------------------------------------------------------------------------
/XcodeServerSDK/API Routes/XcodeServer+Miscs.swift:
--------------------------------------------------------------------------------
1 | //
2 | // XcodeServer+Miscs.swift
3 | // XcodeServerSDK
4 | //
5 | // Created by Honza Dvorsky on 10/10/15.
6 | // Copyright © 2015 Honza Dvorsky. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | import BuildaUtils
12 |
13 | // MARK: - Miscellaneous XcodeSever API Routes
14 | extension XcodeServer {
15 |
16 | /**
17 | XCS API call for retrieving its canonical hostname.
18 | */
19 | public final func getHostname(completion: (hostname: String?, error: NSError?) -> ()) {
20 |
21 | self.sendRequestWithMethod(.GET, endpoint: .Hostname, params: nil, query: nil, body: nil) { (response, body, error) -> () in
22 |
23 | if error != nil {
24 | completion(hostname: nil, error: error)
25 | return
26 | }
27 |
28 | if let hostname = (body as? NSDictionary)?["hostname"] as? String {
29 | completion(hostname: hostname, error: nil)
30 | } else {
31 | completion(hostname: nil, error: Error.withInfo("Wrong body \(body)"))
32 | }
33 | }
34 | }
35 |
36 | }
37 |
38 |
--------------------------------------------------------------------------------
/XcodeServerSDK/API Routes/XcodeServer+Platform.swift:
--------------------------------------------------------------------------------
1 | //
2 | // XcodeServer+Platform.swift
3 | // XcodeServerSDK
4 | //
5 | // Created by Mateusz Zając on 01/07/15.
6 | // Copyright © 2015 Honza Dvorsky. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import BuildaUtils
11 |
12 | // MARK: - XcodeSever API Routes for Platform management
13 | extension XcodeServer {
14 |
15 | /**
16 | XCS API method for getting available testing platforms on OS X Server.
17 |
18 | - parameter platforms: Optional array of platforms.
19 | - parameter error: Optional error indicating some problems.
20 | */
21 | public final func getPlatforms(completion: (platforms: [DevicePlatform]?, error: NSError?) -> ()) {
22 |
23 | self.sendRequestWithMethod(.GET, endpoint: .Platforms, params: nil, query: nil, body: nil) { (response, body, error) -> () in
24 |
25 | if error != nil {
26 | completion(platforms: nil, error: error)
27 | return
28 | }
29 |
30 | if let array = (body as? NSDictionary)?["results"] as? NSArray {
31 | let (result, error): ([DevicePlatform]?, NSError?) = unthrow {
32 | return try XcodeServerArray(array)
33 | }
34 | completion(platforms: result, error: error)
35 | } else {
36 | completion(platforms: nil, error: Error.withInfo("Wrong body \(body)"))
37 | }
38 | }
39 | }
40 |
41 | }
42 |
--------------------------------------------------------------------------------
/XcodeServerSDK/API Routes/XcodeServer+Repository.swift:
--------------------------------------------------------------------------------
1 | //
2 | // XcodeServer+Repository.swift
3 | // XcodeServerSDK
4 | //
5 | // Created by Mateusz Zając on 30.06.2015.
6 | // Copyright © 2015 Honza Dvorsky. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import BuildaUtils
11 |
12 | // MARK: - // MARK: - XcodeSever API Routes for Repositories management
13 | extension XcodeServer {
14 |
15 | /**
16 | XCS API call for getting all repositories stored on Xcode Server.
17 |
18 | - parameter repositories: Optional array of repositories.
19 | - parameter error: Optional error
20 | */
21 | public final func getRepositories(completion: (repositories: [Repository]?, error: NSError?) -> ()) {
22 |
23 | self.sendRequestWithMethod(.GET, endpoint: .Repositories, params: nil, query: nil, body: nil) { (response, body, error) -> () in
24 | guard error == nil else {
25 | completion(repositories: nil, error: error)
26 | return
27 | }
28 |
29 | guard let repositoriesBody = (body as? NSDictionary)?["results"] as? NSArray else {
30 | completion(repositories: nil, error: Error.withInfo("Wrong body \(body)"))
31 | return
32 | }
33 |
34 | let (result, error): ([Repository]?, NSError?) = unthrow {
35 | return try XcodeServerArray(repositoriesBody)
36 | }
37 | completion(repositories: result, error: error)
38 | }
39 | }
40 |
41 | /**
42 | Enum with response from creation of repository.
43 |
44 | - RepositoryAlreadyExists: Repository with this name already exists on OS X Server.
45 | - NilResponse: Self explanatory.
46 | - CorruptedJSON: JSON you've used to create repository.
47 | - WrongStatusCode: Something wrong with HHTP status.
48 | - Error: There was an error during netwotk activity.
49 | - Success: Repository was successfully created 🎉
50 | */
51 | public enum CreateRepositoryResponse {
52 | case RepositoryAlreadyExists
53 | case NilResponse
54 | case CorruptedJSON
55 | case WrongStatusCode(Int)
56 | case Error(ErrorType)
57 | case Success(Repository)
58 | }
59 |
60 | /**
61 | XCS API call for creating new repository on configured Xcode Server.
62 |
63 | - parameter repository: Repository object.
64 | - parameter repository: Optional object of created repository.
65 | - parameter error: Optional error.
66 | */
67 | public final func createRepository(repository: Repository, completion: (response: CreateRepositoryResponse) -> ()) {
68 | let body = repository.dictionarify()
69 |
70 | self.sendRequestWithMethod(.POST, endpoint: .Repositories, params: nil, query: nil, body: body) { (response, body, error) -> () in
71 | if let error = error {
72 | completion(response: XcodeServer.CreateRepositoryResponse.Error(error))
73 | return
74 | }
75 |
76 | guard let response = response else {
77 | completion(response: XcodeServer.CreateRepositoryResponse.NilResponse)
78 | return
79 | }
80 |
81 | guard let repositoryBody = body as? NSDictionary where response.statusCode == 204 else {
82 | switch response.statusCode {
83 | case 200:
84 | completion(response: XcodeServer.CreateRepositoryResponse.CorruptedJSON)
85 | case 409:
86 | completion(response: XcodeServer.CreateRepositoryResponse.RepositoryAlreadyExists)
87 | default:
88 | completion(response: XcodeServer.CreateRepositoryResponse.WrongStatusCode(response.statusCode))
89 | }
90 |
91 | return
92 | }
93 |
94 | let (result, error): (Repository?, NSError?) = unthrow {
95 | return try Repository(json: repositoryBody)
96 | }
97 | if let error = error {
98 | completion(response: .Error(error))
99 | } else {
100 | completion(response: .Success(result!))
101 | }
102 | }
103 | }
104 |
105 | }
106 |
--------------------------------------------------------------------------------
/XcodeServerSDK/API Routes/XcodeServer+SCM.swift:
--------------------------------------------------------------------------------
1 | //
2 | // XcodeServer+SCM.swift
3 | // XcodeServerSDK
4 | //
5 | // Created by Mateusz Zając on 01.07.2015.
6 | // Copyright © 2015 Honza Dvorsky. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import BuildaUtils
11 |
12 | // MARK: - XcodeSever API Routes for Source Control Management
13 | extension XcodeServer {
14 |
15 | /**
16 | Verifies that the blueprint contains valid Git credentials and that the blueprint contains a valid
17 | server certificate fingerprint for client <-> XCS communication.
18 |
19 | - parameter blueprint: SC blueprint which should be verified.
20 | - parameter response: SCM response.
21 | */
22 | public final func verifyGitCredentialsFromBlueprint(blueprint: SourceControlBlueprint, completion: (response: SCMBranchesResponse) -> ()) {
23 |
24 | //just a proxy with a more explicit name
25 | self.postSCMBranchesWithBlueprint(blueprint, completion: completion)
26 | }
27 |
28 | // MARK: Helpers
29 |
30 | /**
31 | Enum for Source Control Management responses.
32 |
33 | - Error: Error.
34 | - SSHFingerprintFailedToVerify: Couldn't verify SSH fingerprint.
35 | - Success: Verification was successful.
36 | */
37 | public enum SCMBranchesResponse {
38 | case Error(ErrorType)
39 | case SSHFingerprintFailedToVerify(fingerprint: String, repository: String)
40 |
41 | //the valid blueprint will have the right certificateFingerprint
42 | case Success(branches: [(name: String, isPrimary: Bool)], validBlueprint: SourceControlBlueprint)
43 | }
44 |
45 | final func postSCMBranchesWithBlueprint(blueprint: SourceControlBlueprint, completion: (response: SCMBranchesResponse) -> ()) {
46 |
47 | let blueprintDict = blueprint.dictionarifyRemoteAndCredentials()
48 |
49 | self.sendRequestWithMethod(.POST, endpoint: .SCM_Branches, params: nil, query: nil, body: blueprintDict) { (response, body, error) -> () in
50 |
51 | if let error = error {
52 | completion(response: XcodeServer.SCMBranchesResponse.Error(error))
53 | return
54 | }
55 |
56 | guard let responseObject = body as? NSDictionary else {
57 | let e = Error.withInfo("Wrong body: \(body)")
58 | completion(response: XcodeServer.SCMBranchesResponse.Error(e))
59 | return
60 | }
61 |
62 | //take the primary repository's key. XCS officially supports multiple checkouts (submodules)
63 | let primaryRepoId = blueprint.projectWCCIdentifier
64 |
65 | //communication worked, now let's see what we got
66 | //check for errors first
67 | if
68 | let repoErrors = responseObject["repositoryErrors"] as? [NSDictionary],
69 | let repoErrorWrap = repoErrors.findFirst({ $0["repository"] as? String == primaryRepoId }),
70 | let repoError = repoErrorWrap["error"] as? NSDictionary
71 | where repoErrors.count > 0 {
72 |
73 | if let code = repoError["code"] as? Int {
74 |
75 | //ok, we got an error. do we recognize it?
76 | switch code {
77 | case -1004:
78 | //ok, this is failed fingerprint validation
79 | //pull out the new fingerprint and complete.
80 | if let fingerprint = repoError["fingerprint"] as? String {
81 |
82 | //optionally offer to resolve this issue by adopting the new fingerprint
83 | if self.config.automaticallyTrustSelfSignedCertificates {
84 |
85 | blueprint.certificateFingerprint = fingerprint
86 | self.postSCMBranchesWithBlueprint(blueprint, completion: completion)
87 | return
88 |
89 | } else {
90 | completion(response: XcodeServer.SCMBranchesResponse.SSHFingerprintFailedToVerify(fingerprint: fingerprint, repository: primaryRepoId))
91 | }
92 |
93 | } else {
94 | completion(response: XcodeServer.SCMBranchesResponse.Error(Error.withInfo("No fingerprint provided in error \(repoError)")))
95 | }
96 |
97 | default:
98 | completion(response: XcodeServer.SCMBranchesResponse.Error(Error.withInfo("Unrecognized error: \(repoError)")))
99 | }
100 | } else {
101 | completion(response: XcodeServer.SCMBranchesResponse.Error(Error.withInfo("No code provided in error \(repoError)")))
102 | }
103 | return
104 | }
105 |
106 | //cool, no errors. now try to parse branches!
107 | guard
108 | let branchesAllRepos = responseObject["branches"] as? NSDictionary,
109 | let branches = branchesAllRepos[primaryRepoId] as? NSArray else {
110 |
111 | completion(response: XcodeServer.SCMBranchesResponse.Error(Error.withInfo("No branches provided for our primary repo id: \(primaryRepoId).")))
112 | return
113 | }
114 |
115 | //cool, we gots ourselves some branches, let's parse 'em
116 | let parsedBranches = branches.map({ (name: $0["name"] as! String, isPrimary: $0["primary"] as! Bool) })
117 | completion(response: XcodeServer.SCMBranchesResponse.Success(branches: parsedBranches, validBlueprint: blueprint))
118 | }
119 | }
120 |
121 | }
--------------------------------------------------------------------------------
/XcodeServerSDK/API Routes/XcodeServer+Toolchain.swift:
--------------------------------------------------------------------------------
1 | //
2 | // XcodeServer+Toolchain.swift
3 | // XcodeServerSDK
4 | //
5 | // Created by Laurent Gaches on 21/04/16.
6 | // Copyright © 2016 Laurent Gaches. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import BuildaUtils
11 |
12 | // MARK: - Toolchain XcodeSever API Routes
13 | extension XcodeServer {
14 |
15 | /**
16 | XCS API call for getting all available toolchains.
17 |
18 | - parameter toolchains: Optional array of available toolchains.
19 | - parameter error: Optional error.
20 | */
21 | public final func getToolchains(completion: (toolchains: [Toolchain]?,error: NSError?) -> ()) {
22 | self.sendRequestWithMethod(.GET, endpoint: .Toolchains, params: nil, query: nil, body: nil) { (response, body, error) in
23 | if error != nil {
24 | completion(toolchains: nil, error: error)
25 | return
26 | }
27 |
28 | if let body = (body as? NSDictionary)?["results"] as? NSArray {
29 | let (result, error): ([Toolchain]?, NSError?) = unthrow { _ in
30 | return try XcodeServerArray(body)
31 | }
32 | completion(toolchains: result, error: error)
33 | } else {
34 | completion(toolchains: nil, error: Error.withInfo("Wrong body \(body)"))
35 | }
36 | }
37 | }
38 | }
--------------------------------------------------------------------------------
/XcodeServerSDK/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | FMWK
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | $(CURRENT_PROJECT_VERSION)
23 | NSHumanReadableCopyright
24 | Copyright © 2015 Honza Dvorsky. All rights reserved.
25 | NSPrincipalClass
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/XcodeServerSDK/Server Entities/Bot.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Bot.swift
3 | // Buildasaur
4 | //
5 | // Created by Honza Dvorsky on 14/12/2014.
6 | // Copyright (c) 2014 Honza Dvorsky. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | public class Bot : XcodeServerEntity {
12 |
13 | public let name: String
14 | public let configuration: BotConfiguration
15 | public let integrationsCount: Int
16 |
17 | public required init(json: NSDictionary) throws {
18 |
19 | self.name = try json.stringForKey("name")
20 | self.configuration = try BotConfiguration(json: try json.dictionaryForKey("configuration"))
21 | self.integrationsCount = json.optionalIntForKey("integration_counter") ?? 0
22 |
23 | try super.init(json: json)
24 | }
25 |
26 | /**
27 | * Creating bots on the server. Needs dictionary representation.
28 | */
29 | public init(name: String, configuration: BotConfiguration) {
30 |
31 | self.name = name
32 | self.configuration = configuration
33 | self.integrationsCount = 0
34 |
35 | super.init()
36 | }
37 |
38 | public override func dictionarify() -> NSDictionary {
39 |
40 | let dictionary = NSMutableDictionary()
41 |
42 | //name
43 | dictionary["name"] = self.name
44 |
45 | //configuration
46 | dictionary["configuration"] = self.configuration.dictionarify()
47 |
48 | //others
49 | dictionary["type"] = 1 //magic more
50 | dictionary["requiresUpgrade"] = false
51 | dictionary["group"] = [
52 | "name": NSUUID().UUIDString
53 | ]
54 |
55 | return dictionary
56 | }
57 |
58 |
59 | }
60 |
61 | extension Bot : CustomStringConvertible {
62 | public var description : String {
63 | get {
64 | return "[Bot \(self.name)]"
65 | }
66 | }
67 | }
68 |
69 |
70 |
--------------------------------------------------------------------------------
/XcodeServerSDK/Server Entities/BotSchedule.swift:
--------------------------------------------------------------------------------
1 | //
2 | // BotSchedule.swift
3 | // XcodeServerSDK
4 | //
5 | // Created by Mateusz Zając on 13.06.2015.
6 | // Copyright © 2015 Honza Dvorsky. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | public class BotSchedule : XcodeServerEntity {
12 |
13 | public enum Schedule : Int {
14 |
15 | case Periodical = 1
16 | case Commit
17 | case Manual
18 |
19 | public func toString() -> String {
20 | switch self {
21 | case .Periodical:
22 | return "Periodical"
23 | case .Commit:
24 | return "On Commit"
25 | case .Manual:
26 | return "Manual"
27 | }
28 | }
29 | }
30 |
31 | public enum Period : Int {
32 | case Hourly = 1
33 | case Daily
34 | case Weekly
35 | }
36 |
37 | public enum Day : Int {
38 | case Monday = 1
39 | case Tuesday
40 | case Wednesday
41 | case Thursday
42 | case Friday
43 | case Saturday
44 | case Sunday
45 | }
46 |
47 | public let schedule: Schedule!
48 |
49 | public let period: Period?
50 |
51 | public let day: Day!
52 | public let hours: Int!
53 | public let minutes: Int!
54 |
55 | public required init(json: NSDictionary) throws {
56 |
57 | let schedule = Schedule(rawValue: try json.intForKey("scheduleType"))!
58 | self.schedule = schedule
59 |
60 | if schedule == .Periodical {
61 |
62 | let period = Period(rawValue: try json.intForKey("periodicScheduleInterval"))!
63 | self.period = period
64 |
65 | let minutes = json.optionalIntForKey("minutesAfterHourToIntegrate")
66 | let hours = json.optionalIntForKey("hourOfIntegration")
67 |
68 | switch period {
69 | case .Hourly:
70 | self.minutes = minutes!
71 | self.hours = nil
72 | self.day = nil
73 | case .Daily:
74 | self.minutes = minutes!
75 | self.hours = hours!
76 | self.day = nil
77 | case .Weekly:
78 | self.minutes = minutes!
79 | self.hours = hours!
80 | self.day = Day(rawValue: try json.intForKey("weeklyScheduleDay"))
81 | }
82 | } else {
83 | self.period = nil
84 | self.minutes = nil
85 | self.hours = nil
86 | self.day = nil
87 | }
88 |
89 | try super.init(json: json)
90 | }
91 |
92 | private init(schedule: Schedule, period: Period?, day: Day?, hours: Int?, minutes: Int?) {
93 |
94 | self.schedule = schedule
95 | self.period = period
96 | self.day = day
97 | self.hours = hours
98 | self.minutes = minutes
99 |
100 | super.init()
101 | }
102 |
103 | public class func manualBotSchedule() -> BotSchedule {
104 | return BotSchedule(schedule: .Manual, period: nil, day: nil, hours: nil, minutes: nil)
105 | }
106 |
107 | public class func commitBotSchedule() -> BotSchedule {
108 | return BotSchedule(schedule: .Commit, period: nil, day: nil, hours: nil, minutes: nil)
109 | }
110 |
111 | public override func dictionarify() -> NSDictionary {
112 |
113 | let dictionary = NSMutableDictionary()
114 |
115 | dictionary["scheduleType"] = self.schedule.rawValue
116 | dictionary["periodicScheduleInterval"] = self.period?.rawValue ?? 0
117 | dictionary["weeklyScheduleDay"] = self.day?.rawValue ?? 0
118 | dictionary["hourOfIntegration"] = self.hours ?? 0
119 | dictionary["minutesAfterHourToIntegrate"] = self.minutes ?? 0
120 |
121 | return dictionary
122 | }
123 |
124 | }
--------------------------------------------------------------------------------
/XcodeServerSDK/Server Entities/Commit.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Commit.swift
3 | // XcodeServerSDK
4 | //
5 | // Created by Mateusz Zając on 21/07/15.
6 | // Copyright © 2015 Honza Dvorsky. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | public class Commit: XcodeServerEntity {
12 |
13 | public let hash: String
14 | public let filePaths: [File]
15 | public let message: String?
16 | public let date: NSDate
17 | public let repositoryID: String
18 | public let contributor: Contributor
19 |
20 | // MARK: Initializers
21 | public required init(json: NSDictionary) throws {
22 | self.hash = try json.stringForKey("XCSCommitHash")
23 | self.filePaths = try json.arrayForKey("XCSCommitCommitChangeFilePaths").map { try File(json: $0) }
24 | self.message = json.optionalStringForKey("XCSCommitMessage")
25 | self.date = try json.dateForKey("XCSCommitTimestamp")
26 | self.repositoryID = try json.stringForKey("XCSBlueprintRepositoryID")
27 | self.contributor = try Contributor(json: try json.dictionaryForKey("XCSCommitContributor"))
28 |
29 | try super.init(json: json)
30 | }
31 |
32 | }
--------------------------------------------------------------------------------
/XcodeServerSDK/Server Entities/Contributor.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Contributor.swift
3 | // XcodeServerSDK
4 | //
5 | // Created by Mateusz Zając on 21/07/15.
6 | // Copyright © 2015 Honza Dvorsky. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | // MARK: Constants
12 | let kContributorName = "XCSContributorName"
13 | let kContributorDisplayName = "XCSContributorDisplayName"
14 | let kContributorEmails = "XCSContributorEmails"
15 |
16 | public class Contributor: XcodeServerEntity {
17 |
18 | public let name: String
19 | public let displayName: String
20 | public let emails: [String]
21 |
22 | public required init(json: NSDictionary) throws {
23 | self.name = try json.stringForKey(kContributorName)
24 | self.displayName = try json.stringForKey(kContributorDisplayName)
25 | self.emails = try json.arrayForKey(kContributorEmails)
26 |
27 | try super.init(json: json)
28 | }
29 |
30 | public override func dictionarify() -> NSDictionary {
31 | return [
32 | kContributorName: self.name,
33 | kContributorDisplayName: self.displayName,
34 | kContributorEmails: self.emails
35 | ]
36 | }
37 |
38 | public func description() -> String {
39 | return "\(displayName) [\(emails[0])]"
40 | }
41 |
42 | }
--------------------------------------------------------------------------------
/XcodeServerSDK/Server Entities/Device.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Device.swift
3 | // Buildasaur
4 | //
5 | // Created by Honza Dvorsky on 15/03/2015.
6 | // Copyright (c) 2015 Honza Dvorsky. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import BuildaUtils
11 |
12 | public class Device : XcodeServerEntity {
13 |
14 | public let osVersion: String
15 | public let connected: Bool
16 | public let simulator: Bool
17 | public let modelCode: String? // Enum?
18 | public let deviceType: String? // Enum?
19 | public let modelName: String?
20 | public let deviceECID: String?
21 | public let modelUTI: String?
22 | public let activeProxiedDevice: Device?
23 | public let trusted: Bool
24 | public let name: String
25 | public let supported: Bool
26 | public let processor: String?
27 | public let identifier: String
28 | public let enabledForDevelopment: Bool
29 | public let serialNumber: String?
30 | public let platform: DevicePlatform.PlatformType
31 | public let architecture: String // Enum?
32 | public let isServer: Bool
33 | public let retina: Bool
34 |
35 | public required init(json: NSDictionary) throws {
36 |
37 | self.connected = try json.boolForKey("connected")
38 | self.osVersion = try json.stringForKey("osVersion")
39 | self.simulator = try json.boolForKey("simulator")
40 | self.modelCode = json.optionalStringForKey("modelCode")
41 | self.deviceType = json.optionalStringForKey("deviceType")
42 | self.modelName = json.optionalStringForKey("modelName")
43 | self.deviceECID = json.optionalStringForKey("deviceECID")
44 | self.modelUTI = json.optionalStringForKey("modelUTI")
45 | if let proxyDevice = json.optionalDictionaryForKey("activeProxiedDevice") {
46 | self.activeProxiedDevice = try Device(json: proxyDevice)
47 | } else {
48 | self.activeProxiedDevice = nil
49 | }
50 | self.trusted = json.optionalBoolForKey("trusted") ?? false
51 | self.name = try json.stringForKey("name")
52 | self.supported = try json.boolForKey("supported")
53 | self.processor = json.optionalStringForKey("processor")
54 | self.identifier = try json.stringForKey("identifier")
55 | self.enabledForDevelopment = try json.boolForKey("enabledForDevelopment")
56 | self.serialNumber = json.optionalStringForKey("serialNumber")
57 | self.platform = DevicePlatform.PlatformType(rawValue: try json.stringForKey("platformIdentifier")) ?? .Unknown
58 | self.architecture = try json.stringForKey("architecture")
59 |
60 | //for some reason which is not yet clear to me (probably old/new XcS versions), sometimes
61 | //the key is "server" and sometimes "isServer". this just picks up the present one.
62 | self.isServer = json.optionalBoolForKey("server") ?? json.optionalBoolForKey("isServer") ?? false
63 | self.retina = try json.boolForKey("retina")
64 |
65 | try super.init(json: json)
66 | }
67 |
68 | public override func dictionarify() -> NSDictionary {
69 |
70 | return [
71 | "device_id": self.id
72 | ]
73 | }
74 |
75 | }
76 |
--------------------------------------------------------------------------------
/XcodeServerSDK/Server Entities/EmailConfiguration.swift:
--------------------------------------------------------------------------------
1 | //
2 | // EmailConfiguration.swift
3 | // XcodeServerSDK
4 | //
5 | // Created by Mateusz Zając on 13.06.2015.
6 | // Copyright © 2015 Honza Dvorsky. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | public class EmailConfiguration : XcodeServerEntity {
12 |
13 | public let additionalRecipients: [String]
14 | public let emailCommitters: Bool
15 | public let includeCommitMessages: Bool
16 | public let includeIssueDetails: Bool
17 |
18 | public init(additionalRecipients: [String], emailCommitters: Bool, includeCommitMessages: Bool, includeIssueDetails: Bool) {
19 |
20 | self.additionalRecipients = additionalRecipients
21 | self.emailCommitters = emailCommitters
22 | self.includeCommitMessages = includeCommitMessages
23 | self.includeIssueDetails = includeIssueDetails
24 |
25 | super.init()
26 | }
27 |
28 | public override func dictionarify() -> NSDictionary {
29 |
30 | let dict = NSMutableDictionary()
31 |
32 | dict["emailCommitters"] = self.emailCommitters
33 | dict["includeCommitMessages"] = self.includeCommitMessages
34 | dict["includeIssueDetails"] = self.includeIssueDetails
35 | dict["additionalRecipients"] = self.additionalRecipients
36 |
37 | return dict
38 | }
39 |
40 | public required init(json: NSDictionary) throws {
41 |
42 | self.emailCommitters = try json.boolForKey("emailCommitters")
43 | self.includeCommitMessages = try json.boolForKey("includeCommitMessages")
44 | self.includeIssueDetails = try json.boolForKey("includeIssueDetails")
45 | self.additionalRecipients = try json.arrayForKey("additionalRecipients")
46 |
47 | try super.init(json: json)
48 | }
49 | }
--------------------------------------------------------------------------------
/XcodeServerSDK/Server Entities/File.swift:
--------------------------------------------------------------------------------
1 | //
2 | // File.swift
3 | // XcodeServerSDK
4 | //
5 | // Created by Mateusz Zając on 21/07/15.
6 | // Copyright © 2015 Honza Dvorsky. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | public class File: XcodeServerEntity {
12 |
13 | public let status: FileStatus
14 | public let filePath: String
15 |
16 | public init(filePath: String, status: FileStatus) {
17 | self.filePath = filePath
18 | self.status = status
19 |
20 | super.init()
21 | }
22 |
23 | public required init(json: NSDictionary) throws {
24 | self.filePath = try json.stringForKey("filePath")
25 | self.status = FileStatus(rawValue: try json.intForKey("status")) ?? .Other
26 |
27 | try super.init(json: json)
28 | }
29 |
30 | public override func dictionarify() -> NSDictionary {
31 | return [
32 | "status": self.status.rawValue,
33 | "filePath": self.filePath
34 | ]
35 | }
36 |
37 | }
38 |
39 | /**
40 | * Enum which describes file statuses.
41 | */
42 | public enum FileStatus: Int {
43 | case Added = 1
44 | case Deleted = 2
45 | case Modified = 4
46 | case Moved = 8192
47 | case Other
48 | }
--------------------------------------------------------------------------------
/XcodeServerSDK/Server Entities/Integration.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Integration.swift
3 | // Buildasaur
4 | //
5 | // Created by Honza Dvorsky on 15/12/2014.
6 | // Copyright (c) 2014 Honza Dvorsky. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | public class Integration : XcodeServerEntity {
12 |
13 | //usually available during the whole integration's lifecycle
14 | public let queuedDate: NSDate
15 | public let shouldClean: Bool
16 | public let currentStep: Step!
17 | public let number: Int
18 |
19 | //usually available only after the integration has finished
20 | public let successStreak: Int?
21 | public let startedDate: NSDate?
22 | public let endedTime: NSDate?
23 | public let duration: NSTimeInterval?
24 | public let result: Result?
25 | public let buildResultSummary: BuildResultSummary?
26 | public let testedDevices: [Device]?
27 | public let testHierarchy: TestHierarchy?
28 | public let assets: NSDictionary? //TODO: add typed array with parsing
29 | public let blueprint: SourceControlBlueprint?
30 |
31 | //new keys
32 | public let expectedCompletionDate: NSDate?
33 |
34 | public enum Step : String {
35 | case Unknown = ""
36 | case Pending = "pending"
37 | case Preparing = "preparing"
38 | case Checkout = "checkout"
39 | case BeforeTriggers = "before-triggers"
40 | case Building = "building"
41 | case Testing = "testing"
42 | case Archiving = "archiving"
43 | case Processing = "processing"
44 | case AfterTriggers = "after-triggers"
45 | case Uploading = "uploading"
46 | case Completed = "completed"
47 | }
48 |
49 | public enum Result : String {
50 | case Unknown = "unknown"
51 | case Succeeded = "succeeded"
52 | case BuildErrors = "build-errors"
53 | case TestFailures = "test-failures"
54 | case Warnings = "warnings"
55 | case AnalyzerWarnings = "analyzer-warnings"
56 | case BuildFailed = "build-failed"
57 | case CheckoutError = "checkout-error"
58 | case InternalError = "internal-error"
59 | case InternalCheckoutError = "internal-checkout-error"
60 | case InternalBuildError = "internal-build-error"
61 | case InternalProcessingError = "internal-processing-error"
62 | case Canceled = "canceled"
63 | case TriggerError = "trigger-error"
64 | }
65 |
66 | public required init(json: NSDictionary) throws {
67 |
68 | self.queuedDate = try json.dateForKey("queuedDate")
69 | self.startedDate = json.optionalDateForKey("startedTime")
70 | self.endedTime = json.optionalDateForKey("endedTime")
71 | self.duration = json.optionalDoubleForKey("duration")
72 | self.shouldClean = try json.boolForKey("shouldClean")
73 | self.currentStep = Step(rawValue: try json.stringForKey("currentStep")) ?? .Unknown
74 | self.number = try json.intForKey("number")
75 | self.successStreak = try json.intForKey("success_streak")
76 | self.expectedCompletionDate = json.optionalDateForKey("expectedCompletionDate")
77 |
78 | if let raw = json.optionalStringForKey("result") {
79 | self.result = Result(rawValue: raw)
80 | } else {
81 | self.result = nil
82 | }
83 |
84 | if let raw = json.optionalDictionaryForKey("buildResultSummary") {
85 | self.buildResultSummary = try BuildResultSummary(json: raw)
86 | } else {
87 | self.buildResultSummary = nil
88 | }
89 |
90 | if let testedDevices = json.optionalArrayForKey("testedDevices") {
91 | self.testedDevices = try XcodeServerArray(testedDevices)
92 | } else {
93 | self.testedDevices = nil
94 | }
95 |
96 | if let testHierarchy = json.optionalDictionaryForKey("testHierarchy") where testHierarchy.count > 0 {
97 | self.testHierarchy = try TestHierarchy(json: testHierarchy)
98 | } else {
99 | self.testHierarchy = nil
100 | }
101 |
102 | self.assets = json.optionalDictionaryForKey("assets")
103 |
104 | if let blueprint = json.optionalDictionaryForKey("revisionBlueprint") {
105 | self.blueprint = try SourceControlBlueprint(json: blueprint)
106 | } else {
107 | self.blueprint = nil
108 | }
109 |
110 | try super.init(json: json)
111 | }
112 | }
113 |
114 | public class BuildResultSummary : XcodeServerEntity {
115 |
116 | public let analyzerWarningCount: Int
117 | public let testFailureCount: Int
118 | public let testsChange: Int
119 | public let errorCount: Int
120 | public let testsCount: Int
121 | public let testFailureChange: Int
122 | public let warningChange: Int
123 | public let regressedPerfTestCount: Int
124 | public let warningCount: Int
125 | public let errorChange: Int
126 | public let improvedPerfTestCount: Int
127 | public let analyzerWarningChange: Int
128 | public let codeCoveragePercentage: Int
129 | public let codeCoveragePercentageDelta: Int
130 |
131 | public required init(json: NSDictionary) throws {
132 |
133 | self.analyzerWarningCount = try json.intForKey("analyzerWarningCount")
134 | self.testFailureCount = try json.intForKey("testFailureCount")
135 | self.testsChange = try json.intForKey("testsChange")
136 | self.errorCount = try json.intForKey("errorCount")
137 | self.testsCount = try json.intForKey("testsCount")
138 | self.testFailureChange = try json.intForKey("testFailureChange")
139 | self.warningChange = try json.intForKey("warningChange")
140 | self.regressedPerfTestCount = try json.intForKey("regressedPerfTestCount")
141 | self.warningCount = try json.intForKey("warningCount")
142 | self.errorChange = try json.intForKey("errorChange")
143 | self.improvedPerfTestCount = try json.intForKey("improvedPerfTestCount")
144 | self.analyzerWarningChange = try json.intForKey("analyzerWarningChange")
145 | self.codeCoveragePercentage = json.optionalIntForKey("codeCoveragePercentage") ?? 0
146 | self.codeCoveragePercentageDelta = json.optionalIntForKey("codeCoveragePercentageDelta") ?? 0
147 |
148 | try super.init(json: json)
149 | }
150 |
151 | }
152 |
153 | extension Integration : Hashable {
154 |
155 | public var hashValue: Int {
156 | get {
157 | return self.number
158 | }
159 | }
160 | }
161 |
162 | public func ==(lhs: Integration, rhs: Integration) -> Bool {
163 | return lhs.number == rhs.number
164 | }
165 |
166 |
167 |
--------------------------------------------------------------------------------
/XcodeServerSDK/Server Entities/IntegrationCommits.swift:
--------------------------------------------------------------------------------
1 | //
2 | // IntegrationCommits.swift
3 | // XcodeServerSDK
4 | //
5 | // Created by Mateusz Zając on 23/07/15.
6 | // Copyright © 2015 Honza Dvorsky. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import BuildaUtils
11 |
12 | public class IntegrationCommits: XcodeServerEntity {
13 |
14 | public let integration: String
15 | public let botTinyID: String
16 | public let botID: String
17 | public let commits: [String: [Commit]]
18 | public let endedTimeDate: NSDate?
19 |
20 | public required init(json: NSDictionary) throws {
21 | self.integration = try json.stringForKey("integration")
22 | self.botTinyID = try json.stringForKey("botTinyID")
23 | self.botID = try json.stringForKey("botID")
24 | self.commits = try IntegrationCommits.populateCommits(try json.dictionaryForKey("commits"))
25 | self.endedTimeDate = IntegrationCommits.parseDate(try json.arrayForKey("endedTimeDate"))
26 |
27 | try super.init(json: json)
28 | }
29 |
30 | /**
31 | Method for populating commits property with data from JSON dictionary.
32 |
33 | - parameter json: JSON dictionary with blueprints and commits for each one.
34 |
35 | - returns: Dictionary of parsed Commit objects.
36 | */
37 | class func populateCommits(json: NSDictionary) throws -> [String: [Commit]] {
38 | var resultsDictionary: [String: [Commit]] = Dictionary()
39 |
40 | for (key, value) in json {
41 | guard let blueprintID = key as? String, let commitsArray = value as? [NSDictionary] else {
42 | Log.error("Couldn't parse key \(key) and value \(value)")
43 | continue
44 | }
45 |
46 | resultsDictionary[blueprintID] = try commitsArray.map { try Commit(json: $0) }
47 | }
48 |
49 | return resultsDictionary
50 | }
51 |
52 | /**
53 | Parser for data objects which comes in form of array.
54 |
55 | - parameter array: Array with date components.
56 |
57 | - returns: Optional parsed date to the format used by Xcode Server.
58 | */
59 | class func parseDate(array: NSArray) -> NSDate? {
60 | guard let dateArray = array as? [Int] else {
61 | Log.error("Couldn't parse XCS date array")
62 | return nil
63 | }
64 |
65 | do {
66 | let stringDate = try dateArray.dateString()
67 |
68 | guard let date = NSDate.dateFromXCSString(stringDate) else {
69 | Log.error("Formatter couldn't parse date")
70 | return nil
71 | }
72 |
73 | return date
74 | } catch DateParsingError.WrongNumberOfElements(let elements) {
75 | Log.error("Couldn't parse date as Array has \(elements) elements")
76 | } catch {
77 | Log.error("Something went wrong while parsing date")
78 | }
79 |
80 | return nil
81 | }
82 |
83 | }
--------------------------------------------------------------------------------
/XcodeServerSDK/Server Entities/IntegrationIssue.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Issue.swift
3 | // XcodeServerSDK
4 | //
5 | // Created by Mateusz Zając on 04.08.2015.
6 | // Copyright © 2015 Honza Dvorsky. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | public class IntegrationIssue: XcodeServerEntity {
12 |
13 | public enum IssueType: String {
14 | case BuildServiceError = "buildServiceError"
15 | case BuildServiceWarning = "buildServiceWarning"
16 | case TriggerError = "triggerError"
17 | case Error = "error"
18 | case Warning = "warning"
19 | case TestFailure = "testFailure"
20 | case AnalyzerWarning = "analyzerWarning"
21 | }
22 |
23 | public enum IssueStatus: Int {
24 | case Fresh = 0
25 | case Unresolved
26 | case Resolved
27 | case Silenced
28 | }
29 |
30 | /// Payload is holding whole Dictionary of the Issue
31 | public let payload: NSDictionary
32 |
33 | public let message: String?
34 | public let type: IssueType
35 | public let issueType: String
36 | public let commits: [Commit]
37 | public let integrationID: String
38 | public let age: Int
39 | public let status: IssueStatus
40 |
41 | // MARK: Initialization
42 | public required init(json: NSDictionary) throws {
43 | self.payload = json.copy() as? NSDictionary ?? NSDictionary()
44 |
45 | self.message = json.optionalStringForKey("message")
46 | self.type = try IssueType(rawValue: json.stringForKey("type"))!
47 | self.issueType = try json.stringForKey("issueType")
48 | self.commits = try json.arrayForKey("commits").map { try Commit(json: $0) }
49 | self.integrationID = try json.stringForKey("integrationID")
50 | self.age = try json.intForKey("age")
51 | self.status = IssueStatus(rawValue: try json.intForKey("status"))!
52 |
53 | try super.init(json: json)
54 | }
55 |
56 | }
--------------------------------------------------------------------------------
/XcodeServerSDK/Server Entities/IntegrationIssues.swift:
--------------------------------------------------------------------------------
1 | //
2 | // IntegrationIssues.swift
3 | // XcodeServerSDK
4 | //
5 | // Created by Mateusz Zając on 12.08.2015.
6 | // Copyright © 2015 Honza Dvorsky. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import BuildaUtils
11 |
12 | public class IntegrationIssues: XcodeServerEntity {
13 |
14 | public let buildServiceErrors: [IntegrationIssue]
15 | public let buildServiceWarnings: [IntegrationIssue]
16 | public let triggerErrors: [IntegrationIssue]
17 | public let errors: [IntegrationIssue]
18 | public let warnings: [IntegrationIssue]
19 | public let testFailures: [IntegrationIssue]
20 | public let analyzerWarnings: [IntegrationIssue]
21 |
22 | // MARK: Initialization
23 |
24 | public required init(json: NSDictionary) throws {
25 | self.buildServiceErrors = try json.arrayForKey("buildServiceErrors").map { try IntegrationIssue(json: $0) }
26 | self.buildServiceWarnings = try json.arrayForKey("buildServiceWarnings").map { try IntegrationIssue(json: $0) }
27 | self.triggerErrors = try json.arrayForKey("triggerErrors").map { try IntegrationIssue(json: $0) }
28 |
29 | // Nested issues
30 | self.errors = try json
31 | .dictionaryForKey("errors")
32 | .allValues
33 | .filter { $0.count != 0 }
34 | .flatMap {
35 | try ($0 as! NSArray).map { try IntegrationIssue(json: $0 as! NSDictionary) }
36 | }
37 | self.warnings = try json
38 | .dictionaryForKey("warnings")
39 | .allValues
40 | .filter { $0.count != 0 }
41 | .flatMap {
42 | try ($0 as! NSArray).map { try IntegrationIssue(json: $0 as! NSDictionary) }
43 | }
44 | self.testFailures = try json
45 | .dictionaryForKey("testFailures")
46 | .allValues
47 | .filter { $0.count != 0 }
48 | .flatMap {
49 | try ($0 as! NSArray).map { try IntegrationIssue(json: $0 as! NSDictionary) }
50 | }
51 | self.analyzerWarnings = try json
52 | .dictionaryForKey("analyzerWarnings")
53 | .allValues
54 | .filter { $0.count != 0 }
55 | .flatMap {
56 | try ($0 as! NSArray).map { try IntegrationIssue(json: $0 as! NSDictionary) }
57 | }
58 |
59 | try super.init(json: json)
60 | }
61 |
62 | }
--------------------------------------------------------------------------------
/XcodeServerSDK/Server Entities/LiveUpdateMessage.swift:
--------------------------------------------------------------------------------
1 | //
2 | // LiveUpdateMessage.swift
3 | // XcodeServerSDK
4 | //
5 | // Created by Honza Dvorsky on 26/09/2015.
6 | // Copyright © 2015 Honza Dvorsky. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | public class LiveUpdateMessage: XcodeServerEntity {
12 |
13 | public enum MessageType: String {
14 |
15 | //bots
16 | case BotCreated = "botCreated"
17 | case BotUpdated = "botUpdated"
18 | case BotRemoved = "botRemoved"
19 |
20 | //devices
21 | case DeviceCreated = "deviceCreated"
22 | case DeviceUpdated = "deviceUpdated"
23 | case DeviceRemoved = "deviceRemoved"
24 |
25 | //integrations
26 | case PendingIntegrations = "pendingIntegrations"
27 | case IntegrationCreated = "integrationCreated"
28 | case IntegrationStatus = "integrationStatus"
29 | case IntegrationCanceled = "cancelIntegration"
30 | case IntegrationRemoved = "integrationRemoved"
31 | case AdvisoryIntegrationStatus = "advisoryIntegrationStatus"
32 |
33 | //repositories
34 | case ListRepositories = "listRepositories"
35 | case CreateRepository = "createRepository"
36 |
37 | //boilerplate
38 | case Ping = "ping"
39 | case Pong = "pong"
40 | case ACLUpdated = "aclUpdated"
41 | case RequestPortalSync = "requestPortalSync"
42 |
43 | case Unknown = ""
44 | }
45 |
46 | public let type: MessageType
47 | public let message: String?
48 | public let progress: Double?
49 | public let integrationId: String?
50 | public let botId: String?
51 | public let result: Integration.Result?
52 | public let currentStep: Integration.Step?
53 |
54 | required public init(json: NSDictionary) throws {
55 |
56 | let typeString = json.optionalStringForKey("name") ?? ""
57 |
58 | self.type = MessageType(rawValue: typeString) ?? .Unknown
59 |
60 | let args = (json["args"] as? NSArray)?[0] as? NSDictionary
61 |
62 | self.message = args?["message"] as? String
63 | self.progress = args?["percentage"] as? Double
64 | self.integrationId = args?["_id"] as? String
65 | self.botId = args?["botId"] as? String
66 |
67 | if
68 | let resultString = args?["result"] as? String,
69 | let result = Integration.Result(rawValue: resultString) {
70 | self.result = result
71 | } else {
72 | self.result = nil
73 | }
74 | if
75 | let stepString = args?["currentStep"] as? String,
76 | let step = Integration.Step(rawValue: stepString) {
77 | self.currentStep = step
78 | } else {
79 | self.currentStep = nil
80 | }
81 |
82 | try super.init(json: json)
83 | }
84 |
85 | }
86 |
87 | extension LiveUpdateMessage: CustomStringConvertible {
88 |
89 | public var description: String {
90 |
91 | let empty = "" //fixed in Swift 2.1
92 |
93 | let nonNilComps = [
94 | self.message,
95 | "\(self.progress?.description ?? empty)",
96 | self.result?.rawValue,
97 | self.currentStep?.rawValue
98 | ]
99 | .filter { $0 != nil }
100 | .map { $0! }
101 | .filter { $0.characters.count > 0 }
102 | .map { "\"\($0)\"" }
103 |
104 | let str = nonNilComps.joinWithSeparator(", ")
105 | return "LiveUpdateMessage \"\(self.type)\", \(str)"
106 | }
107 | }
108 |
--------------------------------------------------------------------------------
/XcodeServerSDK/Server Entities/Repository.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Repository.swift
3 | // XcodeServerSDK
4 | //
5 | // Created by Mateusz Zając on 28.06.2015.
6 | // Copyright © 2015 Honza Dvorsky. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | public class Repository: XcodeServerEntity {
12 |
13 | /**
14 | Enumeration describing HTTP access to the repository
15 |
16 | - None: No users are not allowed to read or write
17 | - LoggedIn: Logged in users are allowed to read and write
18 | */
19 | public enum HTTPAccessType: Int {
20 |
21 | case None = 0
22 | case LoggedIn
23 |
24 | public func toString() -> String {
25 | switch self {
26 | case .None:
27 | return "No users are not allowed to read or write"
28 | case .LoggedIn:
29 | return "Logged in users are allowed to read and write"
30 | }
31 | }
32 |
33 | }
34 |
35 | /**
36 | Enumeration describing HTTPS access to the repository
37 |
38 | - SelectedReadWrite: Only selected users can read and/or write
39 | - LoggedInReadSelectedWrite: Only selected users can write but all logged in can read
40 | - LoggedInReadWrite: All logged in users can read and write
41 | */
42 | public enum SSHAccessType: Int {
43 |
44 | case SelectedReadWrite = 0
45 | case LoggedInReadSelectedWrite
46 | case LoggedInReadWrite
47 |
48 | public func toString() -> String {
49 | switch self {
50 | case .SelectedReadWrite:
51 | return "Only selected users can read and/or write"
52 | case .LoggedInReadSelectedWrite:
53 | return "Only selected users can write but all logged in can read"
54 | case .LoggedInReadWrite:
55 | return "All logged in users can read and write"
56 | }
57 | }
58 |
59 | }
60 |
61 | public let name: String
62 | public var httpAccess: HTTPAccessType = HTTPAccessType.None
63 | // XCS's defualt if SelectedReadWrite but if you don't provide
64 | // array of IDs, nobody will have access to the repository
65 | public var sshAccess: SSHAccessType = SSHAccessType.LoggedInReadWrite
66 | public var writeAccessExternalIds: [String] = []
67 | public var readAccessExternalIds: [String] = []
68 |
69 | /**
70 | Designated initializer.
71 |
72 | - parameter name: Name of the repository.
73 | - parameter httpsAccess: HTTPS access type for the users.
74 | - parameter sshAccess: SSH access type for the users.
75 | - parameter writeAccessExternalIds: ID of users allowed to write to the repository.
76 | - parameter readAccessExternalIds: ID of users allowed to read from the repository.
77 |
78 | - returns: Initialized repository struct.
79 | */
80 | public init(name: String, httpAccess: HTTPAccessType?, sshAccess: SSHAccessType?, writeAccessExternalIds: [String]?, readAccessExternalIds: [String]?) {
81 | self.name = name
82 |
83 | if let httpAccess = httpAccess {
84 | self.httpAccess = httpAccess
85 | }
86 |
87 | if let sshAccess = sshAccess {
88 | self.sshAccess = sshAccess
89 | }
90 |
91 | if let writeIDs = writeAccessExternalIds {
92 | self.writeAccessExternalIds = writeIDs
93 | }
94 |
95 | if let readIDs = readAccessExternalIds {
96 | self.readAccessExternalIds = readIDs
97 | }
98 |
99 | super.init()
100 | }
101 |
102 | /**
103 | Convenience initializer.
104 | This initializer will only allow you to provie name and will create a
105 | deault repository with values set to:
106 | - **HTTP Access** - No user is allowed to read/write to repository
107 | - **SSH Access** - Only selected users are allowed to read/write to repository
108 | - **Empty arrays** of write and rad external IDs
109 |
110 | - parameter name: Name of the repository.
111 |
112 | - returns: Initialized default repository wwith provided name
113 | */
114 | public convenience init(name: String) {
115 | self.init(name: name, httpAccess: nil, sshAccess: nil, writeAccessExternalIds: nil, readAccessExternalIds: nil)
116 | }
117 |
118 | /**
119 | Repository constructor from JSON object.
120 |
121 | - parameter json: JSON dictionary representing repository.
122 |
123 | - returns: Initialized repository struct.
124 | */
125 | public required init(json: NSDictionary) throws {
126 | self.name = try json.stringForKey("name")
127 |
128 | self.httpAccess = HTTPAccessType(rawValue: try json.intForKey("httpAccessType"))!
129 | self.sshAccess = SSHAccessType(rawValue: try json.intForKey("posixPermissions"))!
130 |
131 | self.writeAccessExternalIds = try json.arrayForKey("writeAccessExternalIDs")
132 | self.readAccessExternalIds = try json.arrayForKey("readAccessExternalIDs")
133 |
134 | try super.init(json: json)
135 | }
136 |
137 | /**
138 | Method for returning object in form of Dictionary.
139 |
140 | - returns: Dictionary representing JSON value of Repository object.
141 | */
142 | public override func dictionarify() -> NSMutableDictionary {
143 | let dict = NSMutableDictionary()
144 |
145 | dict["name"] = self.name
146 | dict["httpAccessType"] = self.httpAccess.rawValue
147 | dict["posixPermissions"] = self.sshAccess.rawValue
148 | dict["writeAccessExternalIDs"] = self.writeAccessExternalIds
149 | dict["readAccessExternalIDs"] = self.readAccessExternalIds
150 |
151 | return dict
152 | }
153 |
154 | }
--------------------------------------------------------------------------------
/XcodeServerSDK/Server Entities/TestHierarchy.swift:
--------------------------------------------------------------------------------
1 | //
2 | // TestHierarchy.swift
3 | // XcodeServerSDK
4 | //
5 | // Created by Honza Dvorsky on 15/07/2015.
6 | // Copyright © 2015 Honza Dvorsky. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | let TestResultAggregateKey = "_xcsAggrDeviceStatus"
12 |
13 | public class TestHierarchy : XcodeServerEntity {
14 |
15 | typealias TestResult = [String: Double]
16 | typealias AggregateResult = TestResult
17 |
18 | enum TestMethod {
19 | case Method(TestResult)
20 | case Aggregate(AggregateResult)
21 | }
22 |
23 | enum TestClass {
24 | case Class([String: TestMethod])
25 | case Aggregate(AggregateResult)
26 | }
27 |
28 | typealias TestTarget = [String: TestClass]
29 | typealias TestData = [String: TestTarget]
30 |
31 | let testData: TestData
32 |
33 | /*
34 | the json looks like this:
35 | {
36 | //target
37 | "XcodeServerSDKTest": {
38 |
39 | //class
40 | "BotParsingTests": {
41 |
42 | //method
43 | "testParseOSXBot()": {
44 |
45 | //device -> number (bool)
46 | "12345-67890": 1,
47 | "09876-54321": 0
48 | },
49 | "testShared()": {
50 | "12345-67890": 1,
51 | "09876-54321": 1
52 | }
53 | "_xcsAggrDeviceStatus": {
54 | "12345-67890": 1,
55 | "09876-54321": 0
56 | }
57 | },
58 | "_xcsAggrDeviceStatus": {
59 | "12345-67890": 1,
60 | "09876-54321": 0
61 | }
62 | }
63 | }
64 |
65 | As a class and a method, there's always another key-value pair, with key "_xcsAggrDeviceStatus",
66 | which is the aggregated status, so that you don't have to iterate through all tests to figure it out yourself. 1 if all are 1, 0 otherwise.
67 | */
68 |
69 | public required init(json: NSDictionary) throws {
70 |
71 | //TODO: come up with useful things to parse
72 | //TODO: add search capabilities, aggregate generation etc
73 |
74 | self.testData = TestHierarchy.pullData(json)
75 |
76 | try super.init(json: json)
77 | }
78 |
79 | class func pullData(json: NSDictionary) -> TestData {
80 |
81 | var data = TestData()
82 |
83 | for (_targetName, _targetData) in json {
84 | let targetName = _targetName as! String
85 | let targetData = _targetData as! NSDictionary
86 | data[targetName] = pullTarget(targetName, targetData: targetData)
87 | }
88 |
89 | return data
90 | }
91 |
92 | class func pullTarget(targetName: String, targetData: NSDictionary) -> TestTarget {
93 |
94 | var target = TestTarget()
95 |
96 | for (_className, _classData) in targetData {
97 | let className = _className as! String
98 | let classData = _classData as! NSDictionary
99 | target[className] = pullClass(className, classData: classData)
100 | }
101 |
102 | return target
103 | }
104 |
105 | class func pullClass(className: String, classData: NSDictionary) -> TestClass {
106 |
107 | let classy: TestClass
108 | if className == TestResultAggregateKey {
109 | classy = TestClass.Aggregate(classData as! AggregateResult)
110 | } else {
111 |
112 | var newData = [String: TestMethod]()
113 |
114 | for (_methodName, _methodData) in classData {
115 | let methodName = _methodName as! String
116 | let methodData = _methodData as! NSDictionary
117 | newData[methodName] = pullMethod(methodName, methodData: methodData)
118 | }
119 |
120 | classy = TestClass.Class(newData)
121 | }
122 | return classy
123 | }
124 |
125 | class func pullMethod(methodName: String, methodData: NSDictionary) -> TestMethod {
126 |
127 | let method: TestMethod
128 | if methodName == TestResultAggregateKey {
129 | method = TestMethod.Aggregate(methodData as! AggregateResult)
130 | } else {
131 | method = TestMethod.Method(methodData as! TestResult)
132 | }
133 | return method
134 | }
135 | }
136 |
--------------------------------------------------------------------------------
/XcodeServerSDK/Server Entities/Toolchain.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Toolchain.swift
3 | // XcodeServerSDK
4 | //
5 | // Created by Laurent Gaches on 21/04/16.
6 | // Copyright © 2016 Laurent Gaches. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | public class Toolchain: XcodeServerEntity {
12 |
13 | public let displayName: String
14 | public let path: String
15 | public let signatureVerified: Bool
16 |
17 | public required init(json: NSDictionary) throws {
18 |
19 | self.displayName = try json.stringForKey("displayName")
20 | self.path = try json.stringForKey("path")
21 | self.signatureVerified = try json.boolForKey("signatureVerified")
22 |
23 | try super.init(json: json)
24 | }
25 | }
--------------------------------------------------------------------------------
/XcodeServerSDK/Server Entities/Trigger.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Trigger.swift
3 | // XcodeServerSDK
4 | //
5 | // Created by Mateusz Zając on 13.06.2015.
6 | // Copyright © 2015 Honza Dvorsky. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import BuildaUtils
11 |
12 | public struct TriggerConfig: XcodeRead, XcodeWrite {
13 |
14 | public let id: RefType
15 |
16 | public enum Phase: Int {
17 | case Prebuild = 1
18 | case Postbuild
19 |
20 | public func toString() -> String {
21 | switch self {
22 | case .Prebuild:
23 | return "Run Before the Build"
24 | case .Postbuild:
25 | return "Run After the Build"
26 | }
27 | }
28 | }
29 |
30 | public enum Kind: Int {
31 | case RunScript = 1
32 | case EmailNotification
33 |
34 | public func toString() -> String {
35 | switch self {
36 | case .RunScript:
37 | return "Run Script"
38 | case .EmailNotification:
39 | return "Send Email"
40 | }
41 | }
42 | }
43 |
44 | public var phase: Phase
45 | public var kind: Kind
46 | public var scriptBody: String
47 | public var name: String
48 | public var conditions: TriggerConditions?
49 | public var emailConfiguration: EmailConfiguration?
50 |
51 | //creates a default trigger config
52 | public init() {
53 | self.phase = .Prebuild
54 | self.kind = .RunScript
55 | self.scriptBody = "cd *\n"
56 | self.name = ""
57 | self.conditions = nil
58 | self.emailConfiguration = nil
59 | self.id = Ref.new()
60 | }
61 |
62 | public init?(phase: Phase, kind: Kind, scriptBody: String?, name: String?,
63 | conditions: TriggerConditions?, emailConfiguration: EmailConfiguration?, id: RefType? = Ref.new()) {
64 |
65 | self.phase = phase
66 | self.kind = kind
67 | self.scriptBody = scriptBody ?? ""
68 | self.name = name ?? kind.toString()
69 | self.conditions = conditions
70 | self.emailConfiguration = emailConfiguration
71 | self.id = id ?? Ref.new()
72 |
73 | //post build triggers must have conditions
74 | if phase == Phase.Postbuild {
75 | if conditions == nil {
76 | return nil
77 | }
78 | }
79 |
80 | //email type must have a configuration
81 | if kind == Kind.EmailNotification {
82 | if emailConfiguration == nil {
83 | return nil
84 | }
85 | }
86 | }
87 |
88 | public init(json: NSDictionary) throws {
89 |
90 | let phase = Phase(rawValue: try json.intForKey("phase"))!
91 | self.phase = phase
92 | if let conditionsJSON = json.optionalDictionaryForKey("conditions") where phase == .Postbuild {
93 | //also parse conditions
94 | self.conditions = try TriggerConditions(json: conditionsJSON)
95 | } else {
96 | self.conditions = nil
97 | }
98 |
99 | let kind = Kind(rawValue: try json.intForKey("type"))!
100 | self.kind = kind
101 | if let configurationJSON = json.optionalDictionaryForKey("emailConfiguration") where kind == .EmailNotification {
102 | //also parse email config
103 | self.emailConfiguration = try EmailConfiguration(json: configurationJSON)
104 | } else {
105 | self.emailConfiguration = nil
106 | }
107 |
108 | self.name = try json.stringForKey("name")
109 | self.scriptBody = try json.stringForKey("scriptBody")
110 |
111 | self.id = json.optionalStringForKey("id") ?? Ref.new()
112 | }
113 |
114 | public func dictionarify() -> NSDictionary {
115 |
116 | let dict = NSMutableDictionary()
117 |
118 | dict["id"] = self.id
119 | dict["phase"] = self.phase.rawValue
120 | dict["type"] = self.kind.rawValue
121 | dict["scriptBody"] = self.scriptBody
122 | dict["name"] = self.name
123 | dict.optionallyAddValueForKey(self.conditions?.dictionarify(), key: "conditions")
124 | dict.optionallyAddValueForKey(self.emailConfiguration?.dictionarify(), key: "emailConfiguration")
125 |
126 | return dict
127 | }
128 | }
129 |
130 | public class Trigger : XcodeServerEntity {
131 |
132 | public let config: TriggerConfig
133 |
134 | public init(config: TriggerConfig) {
135 | self.config = config
136 | super.init()
137 | }
138 |
139 | required public init(json: NSDictionary) throws {
140 |
141 | self.config = try TriggerConfig(json: json)
142 | try super.init(json: json)
143 | }
144 |
145 | public override func dictionarify() -> NSDictionary {
146 | let dict = self.config.dictionarify()
147 | return dict
148 | }
149 | }
150 |
151 |
152 |
153 |
154 |
--------------------------------------------------------------------------------
/XcodeServerSDK/Server Entities/TriggerConditions.swift:
--------------------------------------------------------------------------------
1 | //
2 | // TriggerConditions.swift
3 | // XcodeServerSDK
4 | //
5 | // Created by Mateusz Zając on 13.06.2015.
6 | // Copyright © 2015 Honza Dvorsky. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | public class TriggerConditions : XcodeServerEntity {
12 |
13 | public let status: Int
14 | public let onAnalyzerWarnings: Bool
15 | public let onBuildErrors: Bool
16 | public let onFailingTests: Bool
17 | public let onInternalErrors: Bool
18 | public let onSuccess: Bool
19 | public let onWarnings: Bool
20 |
21 | public init(status: Int = 2, onAnalyzerWarnings: Bool, onBuildErrors: Bool, onFailingTests: Bool, onInternalErrors: Bool, onSuccess: Bool, onWarnings: Bool) {
22 |
23 | self.status = status
24 | self.onAnalyzerWarnings = onAnalyzerWarnings
25 | self.onBuildErrors = onBuildErrors
26 | self.onFailingTests = onFailingTests
27 | self.onInternalErrors = onInternalErrors
28 | self.onSuccess = onSuccess
29 | self.onWarnings = onWarnings
30 |
31 | super.init()
32 | }
33 |
34 | public override func dictionarify() -> NSDictionary {
35 |
36 | let dict = NSMutableDictionary()
37 |
38 | dict["status"] = self.status
39 | dict["onAnalyzerWarnings"] = self.onAnalyzerWarnings
40 | dict["onBuildErrors"] = self.onBuildErrors
41 | dict["onFailingTests"] = self.onFailingTests
42 | dict["onInternalErrors"] = self.onInternalErrors
43 | dict["onSuccess"] = self.onSuccess
44 | dict["onWarnings"] = self.onWarnings
45 |
46 | return dict
47 | }
48 |
49 | public required init(json: NSDictionary) throws {
50 |
51 | self.status = json.optionalIntForKey("status") ?? 2
52 | self.onAnalyzerWarnings = try json.boolForKey("onAnalyzerWarnings")
53 | self.onBuildErrors = try json.boolForKey("onBuildErrors")
54 | self.onFailingTests = try json.boolForKey("onFailingTests")
55 |
56 | //not present in Xcode 8 anymore, make it optional & default to false
57 | let internalErrors = try? json.boolForKey("onInternalErrors")
58 | self.onInternalErrors = internalErrors ?? false
59 | self.onSuccess = try json.boolForKey("onSuccess")
60 | self.onWarnings = try json.boolForKey("onWarnings")
61 |
62 | try super.init(json: json)
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/XcodeServerSDK/Server Helpers/CIServer.swift:
--------------------------------------------------------------------------------
1 | //
2 | // CIServer.swift
3 | // Buildasaur
4 | //
5 | // Created by Honza Dvorsky on 14/12/2014.
6 | // Copyright (c) 2014 Honza Dvorsky. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import BuildaUtils
11 |
12 | public class CIServer : HTTPServer {
13 |
14 | }
15 |
16 |
--------------------------------------------------------------------------------
/XcodeServerSDK/Server Helpers/SocketIOHelper.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SocketIOHelper.swift
3 | // XcodeServerSDK
4 | //
5 | // Created by Honza Dvorsky on 27/09/2015.
6 | // Copyright © 2015 Honza Dvorsky. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | /*
12 | inspired by: /Applications/Xcode.app/Contents/Developer/usr/share/xcs/xcsd/node_modules/socket.io/lib/parser.js
13 | also helped: https://github.com/Crphang/Roadents/blob/df59d10bd102f04962e933f9a477066ea0c84da7/socket.IO-objc-master/SocketIOTransportXHR.m
14 | */
15 |
16 | public struct SocketIOPacket {
17 |
18 | public enum PacketType: Int {
19 | case Disconnect = 0
20 | case Connect = 1
21 | case Heartbeat = 2
22 | case Message = 3
23 | case JSON = 4
24 | case Event = 5
25 | case Ack = 6
26 | case Error = 7
27 | case Noop = 8
28 | }
29 |
30 | public enum ErrorReason: Int {
31 | case TransportNotSupported = 0
32 | case ClientNotHandshaken = 1
33 | case Unauthorized = 2
34 | }
35 |
36 | public enum ErrorAdvice: Int {
37 | case Reconnect = 0
38 | }
39 |
40 | private let dataString: String
41 | public let type: PacketType
42 | public let stringPayload: String
43 | public var jsonPayload: NSDictionary? {
44 | guard let data = self.stringPayload.dataUsingEncoding(NSUTF8StringEncoding) else { return nil }
45 | let obj = try? NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions())
46 | let dict = obj as? NSDictionary
47 | return dict
48 | }
49 |
50 | public init?(data: String) {
51 | self.dataString = data
52 | guard let comps = SocketIOPacket.parseComps(data) else { return nil }
53 | (self.type, self.stringPayload) = comps
54 | }
55 |
56 | private static func countInitialColons(data: String) -> Int {
57 | var initialColonsCount = 0
58 | for i in data.characters {
59 | if i == ":" {
60 | initialColonsCount += 1
61 | } else {
62 | if initialColonsCount > 0 {
63 | break
64 | }
65 | }
66 | }
67 | return initialColonsCount
68 | }
69 |
70 | private static func parseComps(data: String) -> (type: PacketType, stringPayload: String)? {
71 |
72 | //find the initial sequence of colons and count them, to know how to split the packet
73 | let initialColonsCount = self.countInitialColons(data)
74 | let splitter = String(count: initialColonsCount, repeatedValue: Character(":"))
75 |
76 | let comps = data
77 | .componentsSeparatedByString(splitter)
78 | .filter { $0.characters.count > 0 }
79 | guard comps.count > 0 else { return nil }
80 | guard
81 | let typeString = comps.first,
82 | let typeInt = Int(typeString),
83 | let type = PacketType(rawValue: typeInt)
84 | else { return nil }
85 | let stringPayload = comps.count == 1 ? "" : (comps.last ?? "")
86 | return (type, stringPayload)
87 | }
88 |
89 | //e.g. "7:::1+0"
90 | public func parseError() -> (reason: ErrorReason?, advice: ErrorAdvice?) {
91 | let comps = self.stringPayload.componentsSeparatedByString("+")
92 | let reasonString = comps.first ?? ""
93 | let reasonInt = Int(reasonString) ?? -1
94 | let adviceString = comps.count == 2 ? comps.last! : ""
95 | let adviceInt = Int(adviceString) ?? -1
96 | let reason = ErrorReason(rawValue: reasonInt)
97 | let advice = ErrorAdvice(rawValue: adviceInt)
98 | return (reason, advice)
99 | }
100 | }
101 |
102 | public class SocketIOHelper {
103 |
104 | public static func parsePackets(message: String) -> [SocketIOPacket] {
105 |
106 | let packetStrings = self.parsePacketStrings(message)
107 | let packets = packetStrings.map { SocketIOPacket(data: $0) }.filter { $0 != nil }.map { $0! }
108 | return packets
109 | }
110 |
111 | private static func parsePacketStrings(message: String) -> [String] {
112 |
113 | // Sometimes Socket.IO "batches" up messages in one packet, so we have to split them.
114 | // "Batched" format is:
115 | // �[packet_0 length]�[packet_0]�[packet_1 length]�[packet_1]�[packet_n length]�[packet_n]
116 | let splitChar = "\u{fffd}"
117 | guard message.hasPrefix(splitChar) else { return [message] }
118 |
119 | let comps = message
120 | .substringFromIndex(message.startIndex.advancedBy(1))
121 | .componentsSeparatedByString(splitChar)
122 | .filter { $0.componentsSeparatedByString(":::").count > 1 }
123 | return comps
124 | }
125 | }
126 |
--------------------------------------------------------------------------------
/XcodeServerSDK/Server Helpers/XcodeServerConstants.swift:
--------------------------------------------------------------------------------
1 | //
2 | // XcodeServerConstants.swift
3 | // Buildasaur
4 | //
5 | // Created by Honza Dvorsky on 11/01/2015.
6 | // Copyright (c) 2015 Honza Dvorsky. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | //blueprint
12 | let XcodeBlueprintLocationsKey = "DVTSourceControlWorkspaceBlueprintLocationsKey" //dictionary
13 | let XcodeBlueprintPrimaryRemoteRepositoryKey = "DVTSourceControlWorkspaceBlueprintPrimaryRemoteRepositoryKey" //string
14 | let XcodeRepositoryAuthenticationStrategiesKey = "DVTSourceControlWorkspaceBlueprintRemoteRepositoryAuthenticationStrategiesKey" //dictionary
15 | let XcodeBlueprintWorkingCopyStatesKey = "DVTSourceControlWorkspaceBlueprintWorkingCopyStatesKey" //dictionary
16 | let XcodeBlueprintIdentifierKey = "DVTSourceControlWorkspaceBlueprintIdentifierKey" //string
17 | let XcodeBlueprintNameKey = "DVTSourceControlWorkspaceBlueprintNameKey" //string
18 | let XcodeBlueprintVersion = "DVTSourceControlWorkspaceBlueprintVersion" //number
19 | let XcodeBlueprintRelativePathToProjectKey = "DVTSourceControlWorkspaceBlueprintRelativePathToProjectKey" //string
20 | let XcodeBlueprintWorkingCopyPathsKey = "DVTSourceControlWorkspaceBlueprintWorkingCopyPathsKey" //dictionary
21 | let XcodeBlueprintRemoteRepositoriesKey = "DVTSourceControlWorkspaceBlueprintRemoteRepositoriesKey" //array
22 |
23 |
24 | //locations
25 | let XcodeBranchIdentifierKey = "DVTSourceControlBranchIdentifierKey"
26 | let XcodeLocationRevisionKey = "DVTSourceControlLocationRevisionKey"
27 | let XcodeBranchOptionsKey = "DVTSourceControlBranchOptionsKey"
28 | let XcodeBlueprintLocationTypeKey = "DVTSourceControlWorkspaceBlueprintLocationTypeKey"
29 | let XcodeBlueprintRemoteRepositoryURLKey = "DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey"
30 | let XcodeBlueprintRemoteRepositorySystemKey = "DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey"
31 | let XcodeBlueprintRemoteRepositoryIdentifierKey = "DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey"
32 | let XcodeBlueprintRemoteRepositoryCertFingerprintKey = "DVTSourceControlWorkspaceBlueprintRemoteRepositoryTrustedCertFingerprintKey"
33 | let XcodeBlueprintRemoteRepositoryTrustSelfSignedCertKey = "DVTSourceControlWorkspaceBlueprintRemoteRepositoryTrustSelfSignedCertKey"
34 |
35 | //repo
36 | let XcodeRepoUsernameKey = "DVTSourceControlWorkspaceBlueprintRemoteRepositoryUsernameKey"
37 | let XcodeRepoAuthenticationStrategiesKey = "DVTSourceControlWorkspaceBlueprintRemoteRepositoryAuthenticationStrategiesKey"
38 | let XcodeRepoAuthenticationTypeKey = "DVTSourceControlWorkspaceBlueprintRemoteRepositoryAuthenticationTypeKey"
39 | let XcodeRepoPublicKeyDataKey = "DVTSourceControlWorkspaceBlueprintRemoteRepositoryPublicKeyDataKey"
40 | let XcodeRepoPasswordKey = "DVTSourceControlWorkspaceBlueprintRemoteRepositoryPasswordKey"
41 |
42 | let XcodeRepoSSHKeysAuthenticationStrategy = "DVTSourceControlSSHKeysAuthenticationStrategy"
--------------------------------------------------------------------------------
/XcodeServerSDK/XcodeServer.swift:
--------------------------------------------------------------------------------
1 | //
2 | // XcodeServer.swift
3 | // Buildasaur
4 | //
5 | // Created by Honza Dvorsky on 14/12/2014.
6 | // Copyright (c) 2014 Honza Dvorsky. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import BuildaUtils
11 |
12 | // MARK: XcodeServer Class
13 | public class XcodeServer : CIServer {
14 |
15 | public var config: XcodeServerConfig
16 | let endpoints: XcodeServerEndpoints
17 |
18 | public var availabilityState: AvailabilityCheckState = .Unchecked
19 |
20 | public init(config: XcodeServerConfig, endpoints: XcodeServerEndpoints) {
21 |
22 | self.config = config
23 | self.endpoints = endpoints
24 |
25 | super.init()
26 |
27 | let sessionConfig = NSURLSessionConfiguration.defaultSessionConfiguration()
28 | let delegate: NSURLSessionDelegate = self
29 | let queue = NSOperationQueue.mainQueue()
30 | let session = NSURLSession(configuration: sessionConfig, delegate: delegate, delegateQueue: queue)
31 | self.http.session = session
32 | }
33 | }
34 |
35 | // MARK: NSURLSession delegate implementation
36 | extension XcodeServer : NSURLSessionDelegate {
37 |
38 | var credential: NSURLCredential? {
39 |
40 | if
41 | let user = self.config.user,
42 | let password = self.config.password {
43 | return NSURLCredential(user: user, password: password, persistence: NSURLCredentialPersistence.None)
44 | }
45 | return nil
46 | }
47 |
48 | public func URLSession(session: NSURLSession, didReceiveChallenge challenge: NSURLAuthenticationChallenge, completionHandler: (NSURLSessionAuthChallengeDisposition, NSURLCredential?) -> Void) {
49 |
50 | var disposition: NSURLSessionAuthChallengeDisposition = .PerformDefaultHandling
51 | var credential: NSURLCredential?
52 |
53 | if challenge.previousFailureCount > 0 {
54 | disposition = .CancelAuthenticationChallenge
55 | } else {
56 |
57 | switch challenge.protectionSpace.authenticationMethod {
58 |
59 | case NSURLAuthenticationMethodServerTrust:
60 | credential = NSURLCredential(forTrust: challenge.protectionSpace.serverTrust!)
61 | default:
62 | credential = self.credential ?? session.configuration.URLCredentialStorage?.defaultCredentialForProtectionSpace(challenge.protectionSpace)
63 | }
64 |
65 | if credential != nil {
66 | disposition = .UseCredential
67 | }
68 | }
69 |
70 | completionHandler(disposition, credential)
71 | }
72 | }
73 |
74 | // MARK: Header constants
75 | let Headers_APIVersion = "X-XCSAPIVersion"
76 | let VerifiedAPIVersions: Set = [6, 7, 9, 10] //will change with time, this codebase supports these versions
77 |
78 | // MARK: XcodeServer API methods
79 | public extension XcodeServer {
80 |
81 | private func verifyAPIVersion(response: NSHTTPURLResponse) -> NSError? {
82 |
83 | guard let headers = response.allHeaderFields as? [String: AnyObject] else {
84 | return Error.withInfo("No headers provided in response")
85 | }
86 |
87 | let apiVersionString = (headers[Headers_APIVersion] as? String) ?? "-1"
88 | let apiVersion = Int(apiVersionString)
89 |
90 | if let apiVersion = apiVersion where
91 | apiVersion > 0 && !VerifiedAPIVersions.contains(apiVersion) {
92 | var common = "Version mismatch: response from API version \(apiVersion), but we only verified versions \(VerifiedAPIVersions). "
93 |
94 | let maxVersion = VerifiedAPIVersions.sort().last!
95 | if apiVersion > maxVersion {
96 | Log.info("You're using a newer Xcode Server than we've verified (\(apiVersion), last verified is \(maxVersion)). Please visit https://github.com/czechboy0/XcodeServerSDK to check whether there's a new version of the SDK for it. If not, please file an issue in the XcodeServerSDK repository. The requests are still going through, however we haven't verified this API version, so here be dragons.")
97 | } else {
98 | common += "You're using an old Xcode Server which we don't support any more. Please look for an older version of the SDK at https://github.com/czechboy0/XcodeServerSDK or consider upgrading your Xcode Server to the current version."
99 | return Error.withInfo(common)
100 | }
101 | }
102 |
103 | //all good
104 | return nil
105 | }
106 |
107 | /**
108 | Internal usage generic method for sending HTTP requests.
109 |
110 | - parameter method: HTTP method.
111 | - parameter endpoint: API endpoint.
112 | - parameter params: URL paramaters.
113 | - parameter query: URL query.
114 | - parameter body: POST method request body.
115 | - parameter completion: Completion.
116 | */
117 | internal func sendRequestWithMethod(method: HTTP.Method, endpoint: XcodeServerEndpoints.Endpoint, params: [String: String]?, query: [String: String]?, body: NSDictionary?, portOverride: Int? = nil, completion: HTTP.Completion) -> NSURLSessionTask? {
118 | if let request = self.endpoints.createRequest(method, endpoint: endpoint, params: params, query: query, body: body, portOverride: portOverride) {
119 |
120 | return self.http.sendRequest(request, completion: { (response, body, error) -> () in
121 |
122 | //TODO: fix hack, make completion always return optionals
123 | let resp: NSHTTPURLResponse? = response
124 |
125 | guard let r = resp else {
126 | let e = error ?? Error.withInfo("Nil response")
127 | completion(response: nil, body: body, error: e)
128 | return
129 | }
130 |
131 | if let versionError = self.verifyAPIVersion(r) {
132 | completion(response: response, body: body, error: versionError)
133 | return
134 | }
135 |
136 | if case (200...299) = r.statusCode {
137 | //pass on
138 | completion(response: response, body: body, error: error)
139 | } else {
140 | //see if we haven't received a XCS failure in headers
141 | if let xcsStatusMessage = r.allHeaderFields["X-XCSResponse-Status-Message"] as? String {
142 | let e = Error.withInfo(xcsStatusMessage)
143 | completion(response: response, body: body, error: e)
144 | } else {
145 | completion(response: response, body: body, error: error)
146 | }
147 | }
148 | })
149 |
150 | } else {
151 | completion(response: nil, body: nil, error: Error.withInfo("Couldn't create Request"))
152 | return nil
153 | }
154 | }
155 |
156 | }
157 |
158 |
--------------------------------------------------------------------------------
/XcodeServerSDK/XcodeServerConfig.swift:
--------------------------------------------------------------------------------
1 | //
2 | // XcodeServerConfig.swift
3 | // XcodeServerSDK
4 | //
5 | // Created by Mateusz Zając on 13.06.2015.
6 | // Copyright © 2015 Honza Dvorsky. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import BuildaUtils
11 |
12 | /// Posible errors thrown by `XcodeServerConfig`
13 | public enum ConfigurationErrors : ErrorType {
14 | /// Thrown when no host was provided
15 | case NoHostProvided
16 | /// Thrown when an invalid host is provided (host is returned)
17 | case InvalidHostProvided(String)
18 | /// Thrown when a host is provided with an invalid scheme (explanation message returned)
19 | case InvalidSchemeProvided(String)
20 | /// Thrown when only one of (username, password) is provided, which is not valid
21 | case InvalidCredentialsProvided
22 | }
23 |
24 | private struct Keys {
25 | static let Host = "host"
26 | static let User = "user"
27 | static let Password = "password"
28 | static let Id = "id"
29 | }
30 |
31 | public struct XcodeServerConfig : JSONSerializable {
32 |
33 | public let id: RefType
34 | public var host: String
35 | public var user: String?
36 | public var password: String?
37 |
38 | public let port: Int = 20343
39 |
40 | //if set to false, fails if server certificate is not trusted yet
41 | public let automaticallyTrustSelfSignedCertificates: Bool = true
42 |
43 | public func jsonify() -> NSDictionary {
44 | let dict = NSMutableDictionary()
45 | dict[Keys.Id] = self.id
46 | dict[Keys.Host] = self.host
47 | dict.optionallyAddValueForKey(self.user, key: Keys.User)
48 | return dict
49 | }
50 |
51 | //creates a new default config
52 | public init() {
53 | self.id = Ref.new()
54 | self.host = ""
55 | self.user = nil
56 | self.password = nil
57 | }
58 |
59 | /**
60 | Initializes a server configuration with the provided host.
61 | - parameter host: `Xcode` server host.
62 | - paramater user: Username that will be used to authenticate against the `host` provided.
63 | Can be `nil`.
64 |
65 | - parameter password: Password that will be used to authenticate against the `host` provided.
66 | Can be `nil`.
67 |
68 | - returns: A fully initialized `XcodeServerConfig` instance.
69 |
70 | - throws:
71 | - `NoHostProvided`: When the host string is empty.
72 | - `InvalidHostProvided`: When the host provided doesn't produce a valid `URL`
73 | - `InvalidSchemeProvided`: When the provided scheme is not `HTTPS`
74 | */
75 | public init(host _host: String, user: String? = nil, password: String? = nil, id: RefType? = nil) throws {
76 |
77 | var host = _host
78 |
79 | guard !host.isEmpty else {
80 | throw ConfigurationErrors.NoHostProvided
81 | }
82 |
83 | guard let url = NSURL(string: host) else {
84 | throw ConfigurationErrors.InvalidHostProvided(host)
85 | }
86 |
87 | guard url.scheme.isEmpty || url.scheme == "https" else {
88 | let errMsg = "Xcode Server generally uses https, please double check your hostname"
89 | Log.error(errMsg)
90 | throw ConfigurationErrors.InvalidSchemeProvided(errMsg)
91 | }
92 |
93 | // validate if host is a valid URL
94 | if url.scheme.isEmpty {
95 | // exted host with https scheme
96 | host = "https://" + host
97 | }
98 |
99 | self.host = host
100 | self.user = user
101 | self.password = password
102 | self.id = id ?? Ref.new()
103 | }
104 |
105 | /**
106 | Initializes a server configuration with the provided `json`.
107 | - parameter json: `NSDictionary` containing the `XcodeServerConfig` «configuration».
108 |
109 | - returns: A fully initialized `XcodeServerConfig` instance.
110 |
111 | - throws:
112 | - `NoHostProvided`: When no `host` key was found on the provided `json` dictionary.
113 | - `InvalidHostProvided`: When the host provided doesn't produce a valid `URL`
114 | - `InvalidSchemeProvided`: When the provided scheme is not `HTTPS`
115 | */
116 | public init(json: NSDictionary) throws {
117 |
118 | guard let host = json.optionalStringForKey(Keys.Host) else {
119 | throw ConfigurationErrors.NoHostProvided
120 | }
121 |
122 | let user = json.optionalStringForKey(Keys.User)
123 | let password = json.optionalStringForKey(Keys.Password)
124 | let id = json.optionalStringForKey(Keys.Id)
125 | try self.init(host: host, user: user, password: password, id: id)
126 | }
127 | }
--------------------------------------------------------------------------------
/XcodeServerSDK/XcodeServerEndpoints.swift:
--------------------------------------------------------------------------------
1 | //
2 | // XcodeServerEndpoints.swift
3 | // Buildasaur
4 | //
5 | // Created by Honza Dvorsky on 14/12/2014.
6 | // Copyright (c) 2014 Honza Dvorsky. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import BuildaUtils
11 |
12 | public class XcodeServerEndpoints {
13 |
14 | enum Endpoint {
15 | case Bots
16 | case CancelIntegration
17 | case Commits
18 | case Devices
19 | case Hostname
20 | case Integrations
21 | case Issues
22 | case LiveUpdates
23 | case Login
24 | case Logout
25 | case Platforms
26 | case Repositories
27 | case SCM_Branches
28 | case UserCanCreateBots
29 | case Versions
30 | case Toolchains
31 | }
32 |
33 | let serverConfig: XcodeServerConfig
34 |
35 | /**
36 | Designated initializer.
37 |
38 | - parameter serverConfig: Object of XcodeServerConfig class
39 |
40 | - returns: Initialized object of XcodeServer endpoints
41 | */
42 | public init(serverConfig: XcodeServerConfig) {
43 | self.serverConfig = serverConfig
44 | }
45 |
46 | func endpointURL(endpoint: Endpoint, params: [String: String]? = nil) -> String {
47 |
48 | let base = "/api"
49 |
50 | switch endpoint {
51 |
52 | case .Bots:
53 |
54 | let bots = "\(base)/bots"
55 | if let bot = params?["bot"] {
56 | let bot = "\(bots)/\(bot)"
57 | if
58 | let rev = params?["rev"],
59 | let method = params?["method"] where method == "DELETE"
60 | {
61 | let rev = "\(bot)/\(rev)"
62 | return rev
63 | }
64 | return bot
65 | }
66 | return bots
67 |
68 | case .Integrations:
69 |
70 | if let _ = params?["bot"] {
71 | //gets a list of integrations for this bot
72 | let bots = self.endpointURL(.Bots, params: params)
73 | return "\(bots)/integrations"
74 | }
75 |
76 | let integrations = "\(base)/integrations"
77 | if let integration = params?["integration"] {
78 |
79 | let oneIntegration = "\(integrations)/\(integration)"
80 | return oneIntegration
81 | }
82 | return integrations
83 |
84 | case .CancelIntegration:
85 |
86 | let integration = self.endpointURL(.Integrations, params: params)
87 | let cancel = "\(integration)/cancel"
88 | return cancel
89 |
90 | case .Devices:
91 |
92 | let devices = "\(base)/devices"
93 | return devices
94 |
95 | case .UserCanCreateBots:
96 |
97 | let users = "\(base)/auth/isBotCreator"
98 | return users
99 |
100 | case .Login:
101 |
102 | let login = "\(base)/auth/login"
103 | return login
104 |
105 | case .Logout:
106 |
107 | let logout = "\(base)/auth/logout"
108 | return logout
109 |
110 | case .Platforms:
111 |
112 | let platforms = "\(base)/platforms"
113 | return platforms
114 |
115 | case .SCM_Branches:
116 |
117 | let branches = "\(base)/scm/branches"
118 | return branches
119 |
120 | case .Repositories:
121 |
122 | let repositories = "\(base)/repositories"
123 | return repositories
124 |
125 | case .Commits:
126 |
127 | let integration = self.endpointURL(.Integrations, params: params)
128 | let commits = "\(integration)/commits"
129 | return commits
130 |
131 | case .Issues:
132 |
133 | let integration = self.endpointURL(.Integrations, params: params)
134 | let issues = "\(integration)/issues"
135 | return issues
136 |
137 | case .LiveUpdates:
138 |
139 | let base = "/xcode/internal/socket.io/1"
140 | if let pollId = params?["poll_id"] {
141 | return "\(base)/xhr-polling/\(pollId)"
142 | }
143 | return base
144 |
145 | case .Hostname:
146 |
147 | let hostname = "\(base)/hostname"
148 | return hostname
149 |
150 | case .Versions:
151 | let versions = "\(base)/versions"
152 | return versions
153 |
154 | case .Toolchains:
155 | let toolchains = "\(base)/toolchains"
156 | return toolchains
157 | }
158 | }
159 |
160 | /**
161 | Builder method for URlrequests based on input parameters.
162 |
163 | - parameter method: HTTP method used for request (GET, POST etc.)
164 | - parameter endpoint: Endpoint object
165 | - parameter params: URL params (default is nil)
166 | - parameter query: Query parameters (default is nil)
167 | - parameter body: Request's body (default is nil)
168 | - parameter doBasicAuth: Requirement of authorization (default is true)
169 |
170 | - returns: NSMutableRequest or nil if wrong URL was provided
171 | */
172 | func createRequest(method: HTTP.Method, endpoint: Endpoint, params: [String : String]? = nil, query: [String : String]? = nil, body: NSDictionary? = nil, doBasicAuth auth: Bool = true, portOverride: Int? = nil) -> NSMutableURLRequest? {
173 | var allParams = [
174 | "method": method.rawValue
175 | ]
176 |
177 | //merge the two params
178 | if let params = params {
179 | for (key, value) in params {
180 | allParams[key] = value
181 | }
182 | }
183 |
184 | let port = portOverride ?? self.serverConfig.port
185 | let endpointURL = self.endpointURL(endpoint, params: allParams)
186 | let queryString = HTTP.stringForQuery(query)
187 | let wholePath = "\(self.serverConfig.host):\(port)\(endpointURL)\(queryString)"
188 |
189 | guard let url = NSURL(string: wholePath) else {
190 | return nil
191 | }
192 |
193 | let request = NSMutableURLRequest(URL: url)
194 |
195 | request.HTTPMethod = method.rawValue
196 |
197 | if auth {
198 | //add authorization header
199 | let user = self.serverConfig.user ?? ""
200 | let password = self.serverConfig.password ?? ""
201 | let plainString = "\(user):\(password)" as NSString
202 | let plainData = plainString.dataUsingEncoding(NSUTF8StringEncoding)
203 | let base64String = plainData?.base64EncodedStringWithOptions(NSDataBase64EncodingOptions(rawValue: 0))
204 | request.setValue("Basic \(base64String!)", forHTTPHeaderField: "Authorization")
205 | }
206 |
207 | if let body = body {
208 | do {
209 | let data = try NSJSONSerialization.dataWithJSONObject(body, options: .PrettyPrinted)
210 | request.HTTPBody = data
211 | request.setValue("application/json", forHTTPHeaderField: "Content-Type")
212 | } catch {
213 | let error = error as NSError
214 | Log.error("Parsing error \(error.description)")
215 | return nil
216 | }
217 | }
218 |
219 | return request
220 | }
221 |
222 | }
223 |
--------------------------------------------------------------------------------
/XcodeServerSDK/XcodeServerEntity.swift:
--------------------------------------------------------------------------------
1 | //
2 | // XcodeServerEntity.swift
3 | // Buildasaur
4 | //
5 | // Created by Honza Dvorsky on 14/12/2014.
6 | // Copyright (c) 2014 Honza Dvorsky. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | public protocol XcodeRead {
12 | init(json: NSDictionary) throws
13 | }
14 |
15 | public protocol XcodeWrite {
16 | func dictionarify() -> NSDictionary
17 | }
18 |
19 | public class XcodeServerEntity : XcodeRead, XcodeWrite {
20 |
21 | public let id: String!
22 | public let rev: String!
23 | public let tinyID: String!
24 | public let docType: String!
25 |
26 | //when created from json, let's save the original data here.
27 | public let originalJSON: NSDictionary?
28 |
29 | //initializer which takes a dictionary and fills in values for recognized keys
30 | public required init(json: NSDictionary) throws {
31 |
32 | self.id = json.optionalStringForKey("_id")
33 | self.rev = json.optionalStringForKey("_rev")
34 | self.tinyID = json.optionalStringForKey("tinyID")
35 | self.docType = json.optionalStringForKey("doc_type")
36 | self.originalJSON = json.copy() as? NSDictionary
37 | }
38 |
39 | public init() {
40 | self.id = nil
41 | self.rev = nil
42 | self.tinyID = nil
43 | self.docType = nil
44 | self.originalJSON = nil
45 | }
46 |
47 | public func dictionarify() -> NSDictionary {
48 | assertionFailure("Must be overriden by subclasses that wish to dictionarify their data")
49 | return NSDictionary()
50 | }
51 |
52 | public class func optional(json: NSDictionary?) throws -> T? {
53 | if let json = json {
54 | return try T(json: json)
55 | }
56 | return nil
57 | }
58 | }
59 |
60 | //parse an array of dictionaries into an array of parsed entities
61 | public func XcodeServerArray(jsonArray: NSArray) throws -> [T] {
62 |
63 | let array = jsonArray as! [NSDictionary]
64 | let parsed = try array.map { (json: NSDictionary) -> (T) in
65 | return try T(json: json)
66 | }
67 | return parsed
68 | }
69 |
70 |
--------------------------------------------------------------------------------
/XcodeServerSDK/XcodeServerFactory.swift:
--------------------------------------------------------------------------------
1 | //
2 | // XcodeServerFactory.swift
3 | // Buildasaur
4 | //
5 | // Created by Honza Dvorsky on 14/12/2014.
6 | // Copyright (c) 2014 Honza Dvorsky. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | public class XcodeServerFactory {
12 |
13 | public class func server(config: XcodeServerConfig) -> XcodeServer {
14 |
15 | let endpoints = XcodeServerEndpoints(serverConfig: config)
16 | let server = XcodeServer(config: config, endpoints: endpoints)
17 |
18 | return server
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/XcodeServerSDK/XcodeServerSDK.h:
--------------------------------------------------------------------------------
1 | //
2 | // XcodeServerSDK.h
3 | // XcodeServerSDK
4 | //
5 | // Created by Honza Dvorsky on 11/06/2015.
6 | // Copyright (c) 2015 Honza Dvorsky. All rights reserved.
7 | //
8 |
9 | @import Foundation;
10 |
11 | //! Project version number for XcodeServerSDK.
12 | FOUNDATION_EXPORT double XcodeServerSDKVersionNumber;
13 |
14 | //! Project version string for XcodeServerSDK.
15 | FOUNDATION_EXPORT const unsigned char XcodeServerSDKVersionString[];
16 |
17 | // In this header, you should import all the public headers of your framework using statements like #import
--------------------------------------------------------------------------------
/XcodeServerSDKTests/BotConfigurationTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // BotConfigurationTests.swift
3 | // XcodeServerSDK
4 | //
5 | // Created by Mateusz Zając on 24.06.2015.
6 | // Copyright © 2015 Honza Dvorsky. All rights reserved.
7 | //
8 |
9 | import XCTest
10 | import XcodeServerSDK
11 |
12 | class BotConfigurationTests: XCTestCase {
13 |
14 | func testCleaningPolicyToString() {
15 | var policy: BotConfiguration.CleaningPolicy
16 |
17 | policy = .Never
18 | XCTAssertEqual(policy.toString(), "Never")
19 |
20 | policy = .Always
21 | XCTAssertEqual(policy.toString(), "Always")
22 |
23 | policy = .Once_a_Day
24 | XCTAssertEqual(policy.toString(), "Once a day (first build)")
25 |
26 | policy = .Once_a_Week
27 | XCTAssertEqual(policy.toString(), "Once a week (first build)")
28 | }
29 |
30 | func testDeviceFilterToString() {
31 |
32 | var filter: DeviceFilter.FilterType
33 |
34 | filter = .AllAvailableDevicesAndSimulators
35 | XCTAssertEqual(filter.toString(), "All Available Devices and Simulators")
36 |
37 | filter = .AllDevices
38 | XCTAssertEqual(filter.toString(), "All Devices")
39 |
40 | filter = .AllSimulators
41 | XCTAssertEqual(filter.toString(), "All Simulators")
42 |
43 | filter = .SelectedDevicesAndSimulators
44 | XCTAssertEqual(filter.toString(), "Selected Devices and Simulators")
45 | }
46 |
47 | func testAvailableFiltersForPlatform() {
48 |
49 | XCTAssertEqual(DeviceFilter.FilterType.availableFiltersForPlatform(.iOS), [
50 | .AllAvailableDevicesAndSimulators,
51 | .AllDevices,
52 | .AllSimulators,
53 | .SelectedDevicesAndSimulators
54 | ])
55 |
56 | XCTAssertEqual(DeviceFilter.FilterType.availableFiltersForPlatform(.OSX), [
57 | .AllAvailableDevicesAndSimulators
58 | ])
59 |
60 | XCTAssertEqual(DeviceFilter.FilterType.availableFiltersForPlatform(.watchOS), [
61 | .AllAvailableDevicesAndSimulators
62 | ])
63 | }
64 |
65 | }
66 |
--------------------------------------------------------------------------------
/XcodeServerSDKTests/BotParsingTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // BotParsingTests.swift
3 | // XcodeServerSDK
4 | //
5 | // Created by Honza Dvorsky on 17/06/15.
6 | // Copyright (c) 2015 Honza Dvorsky. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import XCTest
11 | import XcodeServerSDK
12 |
13 | class BotParsingTests: XCTestCase {
14 |
15 | //MARK: shared stuff
16 |
17 | func testParseOSXBot() {
18 |
19 | let exp = self.expectationWithDescription("Network")
20 | let server = self.getRecordingXcodeServer("osx_bot")
21 |
22 | server.getBot("963bc95f1c1a56f69f3392b4aa03302f") { (bots, error) in
23 | exp.fulfill()
24 | }
25 |
26 | self.waitForExpectationsWithTimeout(10, handler: nil)
27 | }
28 |
29 | func testShared() throws {
30 |
31 | let bot = try self.botInCassetteWithName("osx_bot")
32 |
33 | XCTAssertEqual(bot.id, "963bc95f1c1a56f69f3392b4aa03302f")
34 | XCTAssertEqual(bot.rev, "10-117b73f201ea103229a2e8cd26a01845")
35 | XCTAssertEqual(bot.tinyID, "4807518")
36 | }
37 |
38 | //MARK: bot
39 |
40 | func testDeleteBot() {
41 |
42 | let exp = self.expectationWithDescription("Network")
43 | let server = self.getRecordingXcodeServer("bot_deletion")
44 |
45 | server.deleteBot("5f79bd4f6eb05c645336606cc790ccd7", revision: "5-4939a8253e8243107a0d4733490fd36e") { (success, error) in
46 | XCTAssertNil(error)
47 | XCTAssertTrue(success)
48 | exp.fulfill()
49 | }
50 | self.waitForExpectationsWithTimeout(10, handler: nil)
51 | }
52 |
53 | // func testBots() {
54 | //
55 | // let exp = self.expectationWithDescription("Network")
56 | // let config = try! XcodeServerConfig(host: "192.168.1.64")
57 | // let server = XcodeServerFactory.server(config)
58 | // server.getBots { (bots, error) -> () in
59 | // exp.fulfill()
60 | // }
61 | // self.waitForExpectationsWithTimeout(10, handler: nil)
62 | // }
63 | // func testBot() {
64 | //
65 | // let bot = self.botInFileWithName("bot_mac_xcode6")
66 | //
67 | // XCTAssertEqual(bot.name, "Builda Archiver")
68 | // XCTAssertEqual(bot.integrationsCount, 7)
69 | // }
70 | //
71 | // //MARK: configuration
72 | // func testConfiguration() {
73 | //
74 | // let configuration = self.configurationFromBotWithName("bot_mac_xcode6")
75 | //
76 | // XCTAssertEqual(configuration.test, true)
77 | // XCTAssertEqual(configuration.analyze, true)
78 | // XCTAssertEqual(configuration.archive, true)
79 | // XCTAssertEqual(configuration.schemeName, "Buildasaur")
80 | // }
81 |
82 | //MARK: cleaning policy
83 | // func testCleanPolicy() {
84 | // //TODO: will be a whole set of tests, add all possible cases
85 | // }
86 | //
87 | // //MARK: test schedule
88 | // func testSchedule() {
89 | // //TODO: will be a whole set of tests, add all possible cases
90 | // }
91 | //
92 | // //MARK: blueprint (good luck with this one)
93 | // func testBlueprint() {
94 | // //TODO: will be a whole set of tests, add all possible cases
95 | // }
96 | //
97 | // //MARK: destination type
98 | // func testDestinationType() {
99 | // //TODO: will be a whole set of tests, add all possible cases
100 | // }
101 | //
102 | // //MARK: triggers
103 | // func testTriggers() {
104 | // //TODO: will be a whole set of tests, add all possible cases
105 | // }
106 | //
107 | // //MARK: testing device ids (on both Xcode 6 and 7 formats!!!)
108 | // func testTestingDeviceIds() {
109 | // //TODO: will be a whole set of tests, add all possible cases
110 | // }
111 | }
112 |
113 |
114 |
115 |
116 |
117 |
--------------------------------------------------------------------------------
/XcodeServerSDKTests/Casettes/bot_deletion.json:
--------------------------------------------------------------------------------
1 | {
2 | "interactions" : [
3 | {
4 | "recorded_at" : 1437766154.706348,
5 | "response" : {
6 | "body" : "",
7 | "body_format" : "base64_string",
8 | "status" : 204,
9 | "url" : "https:\/\/127.0.0.1:20343\/api\/bots\/5f79bd4f6eb05c645336606cc790ccd7\/5-4939a8253e8243107a0d4733490fd36e",
10 | "headers" : {
11 | "Etag" : "W\/\"a-b541a50d\"",
12 | "X-XCSAPIVersion" : "6",
13 | "X-XCSResponse-Status-Title" : "No Content",
14 | "Keep-Alive" : "timeout=5; max=100",
15 | "Connection" : "keep-alive",
16 | "Date" : "Fri, 24 Jul 2015 19:29:13 GMT"
17 | }
18 | },
19 | "request" : {
20 | "method" : "DELETE",
21 | "url" : "https:\/\/127.0.0.1:20343\/api\/bots\/5f79bd4f6eb05c645336606cc790ccd7\/5-4939a8253e8243107a0d4733490fd36e",
22 | "headers" : {
23 | "Authorization" : "Basic saGVzdGskbfluOfdsfmJJleWbGRz"
24 | }
25 | }
26 | }
27 | ],
28 | "name" : "bot_deletion"
29 | }
--------------------------------------------------------------------------------
/XcodeServerSDKTests/Casettes/get_platforms.json:
--------------------------------------------------------------------------------
1 | {
2 | "interactions" : [
3 | {
4 | "recorded_at" : 1436788154.310033,
5 | "response" : {
6 | "body" : {
7 | "count" : 3,
8 | "results" : [
9 | {
10 | "_id" : "1ad0e8785cacca73d980cdb236002dc6",
11 | "displayName" : "OS X",
12 | "_rev" : "3-4fab2e1d78397a4b10b23493de9e333c",
13 | "tinyID" : "67F229A",
14 | "identifier" : "com.apple.platform.macosx",
15 | "buildNumber" : "15A216g",
16 | "version" : "1.1",
17 | "doc_type" : "platform"
18 | },
19 | {
20 | "_id" : "1ad0e8785cacca73d980cdb236002f3d",
21 | "displayName" : "Watch OS",
22 | "_rev" : "3-ed75f59aab9305de47f062a3349deb91",
23 | "tinyID" : "87C0EB5",
24 | "simulatorIdentifier" : "com.apple.platform.watchsimulator",
25 | "identifier" : "com.apple.platform.watchos",
26 | "buildNumber" : "13S5293f",
27 | "version" : "2.0",
28 | "doc_type" : "platform"
29 | },
30 | {
31 | "_id" : "1ad0e8785cacca73d980cdb236003378",
32 | "displayName" : "iOS",
33 | "_rev" : "3-e059eb79237844f062c28ea5a723aa06",
34 | "tinyID" : "80A6C18",
35 | "simulatorIdentifier" : "com.apple.platform.iphonesimulator",
36 | "identifier" : "com.apple.platform.iphoneos",
37 | "buildNumber" : "13A4293g",
38 | "version" : "9.0",
39 | "doc_type" : "platform"
40 | }
41 | ]
42 | },
43 | "body_format" : "json",
44 | "status" : 200,
45 | "url" : "https:\/\/127.0.0.1:20343\/api\/platforms",
46 | "headers" : {
47 | "X-XCSResultsList" : "true",
48 | "Content-Type" : "application\/json",
49 | "Connection" : "keep-alive",
50 | "Transfer-Encoding" : "Identity",
51 | "Date" : "Mon, 13 Jul 2015 11:49:14 GMT",
52 | "Content-Encoding" : "gzip",
53 | "X-XCSResponse-Status-Title" : "OK",
54 | "Keep-Alive" : "timeout=5; max=100",
55 | "X-XCSAPIVersion" : "6",
56 | "Vary" : "Accept-Encoding"
57 | }
58 | },
59 | "request" : {
60 | "method" : "GET",
61 | "url" : "https:\/\/127.0.0.1:20343\/api\/platforms",
62 | "headers" : {
63 | "Authorization" : "Basic SUNhbkNyZWF0ZUJvdHM6c3VwZXJTZWNyM3Q="
64 | }
65 | }
66 | }
67 | ],
68 | "name" : "get_platforms"
69 | }
--------------------------------------------------------------------------------
/XcodeServerSDKTests/Casettes/get_repositories.json:
--------------------------------------------------------------------------------
1 | {
2 | "interactions" : [
3 | {
4 | "recorded_at" : 1435837811.718786,
5 | "response" : {
6 | "body" : {
7 | "count" : 2,
8 | "results" : [
9 | {
10 | "posixPermissions" : 2,
11 | "httpAccessType" : 1,
12 | "writeAccessExternalIDs" : [
13 |
14 | ],
15 | "readAccessExternalIDs" : [
16 |
17 | ],
18 | "name" : "Test1"
19 | },
20 | {
21 | "posixPermissions" : 0,
22 | "httpAccessType" : 1,
23 | "writeAccessExternalIDs" : [
24 | "ABCDEFAB-CDEF-ABCD-EFAB-CDEF00000050",
25 | "D024C308-CEBE-4E72-BE40-E1E4115F38F9"
26 | ],
27 | "readAccessExternalIDs" : [
28 |
29 | ],
30 | "name" : "Test2"
31 | }
32 | ]
33 | },
34 | "body_format" : "json",
35 | "status" : 200,
36 | "url" : "https:\/\/127.0.0.1:20343\/api\/repositories",
37 | "headers" : {
38 | "X-XCSResultsList" : "true",
39 | "Set-Cookie" : "session=s%3A7X-FU2POL2F2HJ7gUU3MnPWarkx-zGmg.xW86z02rn7PdQgUzaZYkixSBKrGoi5bCinPpIN3MKs0; Path=\/; Expires=Fri, 03 Jul 2015 11:50:11 GMT; HttpOnly; Secure",
40 | "Content-Type" : "application\/json",
41 | "Connection" : "keep-alive",
42 | "Transfer-Encoding" : "Identity",
43 | "Date" : "Thu, 02 Jul 2015 11:50:11 GMT",
44 | "Content-Encoding" : "gzip",
45 | "X-XCSResponse-Status-Title" : "OK",
46 | "Keep-Alive" : "timeout=5; max=100",
47 | "X-XCSAPIVersion" : "6",
48 | "Vary" : "Accept-Encoding"
49 | }
50 | },
51 | "request" : {
52 | "method" : "GET",
53 | "url" : "https:\/\/127.0.0.1:20343\/api\/repositories",
54 | "headers" : {
55 | "Authorization" : "Basic SUNhbkNyZWF0ZUJvdHM6c3VwZXJTZWNyM3Q="
56 | }
57 | }
58 | }
59 | ],
60 | "name" : "get_repositories"
61 | }
--------------------------------------------------------------------------------
/XcodeServerSDKTests/Casettes/get_toolchains.json:
--------------------------------------------------------------------------------
1 | {
2 | "interactions" : [
3 | {
4 | "recorded_at" : 1436788154.310033,
5 | "response" : {
6 | "body" : {
7 | "count" : 2,
8 | "results" : [
9 | {
10 | "_id":"ed7790b0905576627eda64fcf600ae9f",
11 | "_rev":"3-bcc83acf9c184e22a5d1b66700d38dd9",
12 | "path":"/Library/Developer/Toolchains/swift-DEVELOPMENT-SNAPSHOT-2016-04-12-a.xctoolchain",
13 | "displayName":"Xcode Swift DEVELOPMENT Snapshot 2016-04-12 (a)",
14 | "identifier":"org.swift.3020160412a",
15 | "signatureVerified":true,
16 | "doc_type":"toolchain",
17 | "tinyID":"D759F95"
18 | },
19 | {
20 | "_id":"ed7790b0905576627eda64fcf6036a67",
21 | "_rev":"3-57e317f69d7decb33c706274c811ec9b",
22 | "path":"/Library/Developer/Toolchains/swift-2.2.1-SNAPSHOT-2016-04-12-a.xctoolchain",
23 | "displayName":"Xcode Swift 2.2.1 Snapshot 2016-04-12 (a)",
24 | "identifier":"org.swift.22120160412a",
25 | "signatureVerified":true,
26 | "doc_type":"toolchain",
27 | "tinyID":"48A44E8"
28 | }
29 | ]
30 | },
31 | "body_format" : "json",
32 | "status" : 200,
33 | "url" : "https:\/\/127.0.0.1:20343\/api\/toolchains",
34 | "headers" : {
35 | "X-XCSResultsList" : "true",
36 | "Content-Type" : "application\/json",
37 | "Connection" : "keep-alive",
38 | "Transfer-Encoding" : "Identity",
39 | "Date" : "Mon, 13 Jul 2015 11:49:14 GMT",
40 | "Content-Encoding" : "gzip",
41 | "X-XCSResponse-Status-Title" : "OK",
42 | "Keep-Alive" : "timeout=5; max=100",
43 | "X-XCSAPIVersion" : "6",
44 | "Vary" : "Accept-Encoding"
45 | }
46 | },
47 | "request" : {
48 | "method" : "GET",
49 | "url" : "https:\/\/127.0.0.1:20343\/api\/toolchains",
50 | "headers" : {
51 | "Authorization" : "Basic SUNhbkNyZWF0ZUJvdHM6c3VwZXJTZWNyM3Q="
52 | }
53 | }
54 | }
55 | ],
56 | "name" : "get_toolchains"
57 | }
--------------------------------------------------------------------------------
/XcodeServerSDKTests/Casettes/hostname.json:
--------------------------------------------------------------------------------
1 | {
2 | "interactions" : [
3 | {
4 | "recorded_at" : 1444476701.622059,
5 | "response" : {
6 | "body" : {
7 | "hostname" : "honzadvysmbpr14.home"
8 | },
9 | "body_format" : "json",
10 | "status" : 200,
11 | "url" : "https:\/\/127.0.0.1:20343\/api\/hostname",
12 | "headers" : {
13 | "Connection" : "keep-alive",
14 | "Content-Type" : "application\/json",
15 | "Set-Cookie" : "session=s%3AnnpNukOtB_DB3TD6HtlEZRfDSuFAvk8_.XWcOAW2wfgWTaQXWtfc%2BSGIhWI75cUJLiSdCw6vYHEM; Path=\/; Expires=Sun, 11 Oct 2015 11:31:41 GMT; HttpOnly; Secure",
16 | "Transfer-Encoding" : "Identity",
17 | "Date" : "Sat, 10 Oct 2015 11:31:41 GMT",
18 | "Content-Encoding" : "gzip",
19 | "Keep-Alive" : "timeout=5; max=100",
20 | "X-XCSAPIVersion" : "6",
21 | "Vary" : "Accept-Encoding"
22 | }
23 | },
24 | "request" : {
25 | "method" : "GET",
26 | "url" : "https:\/\/127.0.0.1:20343\/api\/hostname",
27 | "headers" : {
28 | "Authorization" : "Basic SUNhbkNyZWF0ZUJvdHM6c3VwZXJTZWNyM3Q="
29 | }
30 | }
31 | }
32 | ],
33 | "name" : "hostname"
34 | }
--------------------------------------------------------------------------------
/XcodeServerSDKTests/ContributorTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ContributorTests.swift
3 | // XcodeServerSDK
4 | //
5 | // Created by Mateusz Zając on 21/07/15.
6 | // Copyright © 2015 Honza Dvorsky. All rights reserved.
7 | //
8 |
9 | import XCTest
10 | @testable import XcodeServerSDK
11 |
12 | class ContributorTests: XCTestCase {
13 |
14 | let singleEmailContributor = [
15 | kContributorName: "Foo Bar",
16 | kContributorDisplayName: "Foo",
17 | kContributorEmails: [
18 | "foo@bar.com"
19 | ]
20 | ]
21 |
22 | let multiEmailContributor = [
23 | kContributorName: "Baz Bar",
24 | kContributorDisplayName: "Baz",
25 | kContributorEmails: [
26 | "baz@bar.com",
27 | "baz@example.com"
28 | ]
29 | ]
30 |
31 | var singleEmail: Contributor!
32 | var multiEmail: Contributor!
33 |
34 | override func setUp() {
35 | super.setUp()
36 |
37 | singleEmail = try! Contributor(json: singleEmailContributor)
38 | multiEmail = try! Contributor(json: multiEmailContributor)
39 | }
40 |
41 | // MARK: Test cases
42 | func testInitialization() {
43 | XCTAssertEqual(singleEmail.name, "Foo Bar")
44 | XCTAssertEqual(singleEmail.emails.count, 1)
45 |
46 | XCTAssertEqual(multiEmail.name, "Baz Bar")
47 | XCTAssertEqual(multiEmail.emails.count, 2)
48 | }
49 |
50 | // MARK: Dictionarify
51 | func testDictionarify() {
52 | XCTAssertEqual(singleEmail.dictionarify(), singleEmailContributor)
53 | XCTAssertEqual(multiEmail.dictionarify(), multiEmailContributor)
54 | }
55 |
56 | func testDescription() {
57 | XCTAssertEqual(multiEmail.description(), "Baz [baz@bar.com]")
58 | }
59 |
60 | }
61 |
--------------------------------------------------------------------------------
/XcodeServerSDKTests/Data/create_ios_bot.json:
--------------------------------------------------------------------------------
1 | {
2 | "group": {
3 | "name": "E4F21264-9C46-4B10-8613-244E48958233"
4 | },
5 | "configuration": {
6 | "builtFromClean": 0,
7 | "periodicScheduleInterval": 1,
8 | "codeCoveragePreference": 2,
9 | "performsTestAction": true,
10 | "triggers": [],
11 | "performsAnalyzeAction": true,
12 | "schemeName": "XcodeServerSDK - iOS",
13 | "exportsProductFromArchive": true,
14 | "testingDeviceIDs": [],
15 | "deviceSpecification": {
16 | "filters": [
17 | {
18 | "platform": {
19 | "_id": "a85553a5b26a7c1a4998f3b237000da9",
20 | "displayName": "iOS",
21 | "_rev": "12-162b2b9d57b73b66724426eea53bfcaf",
22 | "simulatorIdentifier": "com.apple.platform.iphonesimulator",
23 | "identifier": "com.apple.platform.iphoneos",
24 | "buildNumber": "13A4280e",
25 | "version": "9.0"
26 | },
27 | "filterType": 0,
28 | "architectureType": 0
29 | }
30 | ],
31 | "deviceIdentifiers": []
32 | },
33 | "weeklyScheduleDay": 0,
34 | "minutesAfterHourToIntegrate": 0,
35 | "scheduleType": 1,
36 | "hourOfIntegration": 0,
37 | "performsArchiveAction": true,
38 | "sourceControlBlueprint": {
39 | "DVTSourceControlWorkspaceBlueprintLocationsKey": {
40 | "A36AEFA3F9FF1F738E92F0C497C14977DCE02B97": {
41 | "DVTSourceControlBranchIdentifierKey": "hd/tested_devices_xcode_7",
42 | "DVTSourceControlBranchOptionsKey": 156,
43 | "DVTSourceControlWorkspaceBlueprintLocationTypeKey": "DVTSourceControlBranch"
44 | }
45 | },
46 | "DVTSourceControlWorkspaceBlueprintPrimaryRemoteRepositoryKey": "A36AEFA3F9FF1F738E92F0C497C14977DCE02B97",
47 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoryAuthenticationStrategiesKey": {
48 | "A36AEFA3F9FF1F738E92F0C497C14977DCE02B97": {
49 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoryUsernameKey": "git",
50 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoryAuthenticationStrategiesKey": "MY_PRIVATE_KEY",
51 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoryAuthenticationTypeKey": "DVTSourceControlSSHKeysAuthenticationStrategy",
52 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoryPublicKeyDataKey": "c3NoLXJzYSBBQUFBQjNOemFDMXljMkVBQUFBREFRQUJBQUFCQVFETUlyMHIyK3pt\r\nZ2JIajhBcnczRDQzZ0N5WURMc3p6ZWtIdTZZK0FKd29xZC8venFXU1FqamxlMkRt\r\nSmFueXNORnRhbFU3U005M2dtYXEzYTI4YjM3aWZnRmMrMXlhSDRNOC9EUk1yaHRR\r\ndk9JSEhYcWNzeUpwU0RWRkl3YjVxRm5LblNGaW96NGdSTkV0R1VOWWdCVTNYNHRs\r\nQzNMQkV1RmZhdS9RVXZZOEY5NmdMS3BGMTF0ZHdaanlDREN5ZWtIT2JaeWU2RS9R\r\nelRKZXppWjF5RXdHcXdvS3Q1NlpoZ1JHNG5yRHMwaEU2dDYxUG90WkdiMEpSbVRm\r\nYThFM05Mckp5ZklreS9DK2hpQ2tsSmZRelZndGk2MWtwMDJuZFN1ODlHK3dBY0xJ\r\nUjJ2Qzk2TndWRW9pZG1MTnN0bXlrMlhEbG1jVzB2Z0ZHVmptNWx2ZkljWVYgaG9u\r\nemFAc3dpZnRrZXkubmV0Cg==",
53 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoryPasswordKey": ""
54 | }
55 | },
56 | "DVTSourceControlWorkspaceBlueprintWorkingCopyStatesKey": {
57 | "A36AEFA3F9FF1F738E92F0C497C14977DCE02B97": 0
58 | },
59 | "DVTSourceControlWorkspaceBlueprintIdentifierKey": "B67842EF-128D-4AB7-A3C7-7E560085550A",
60 | "DVTSourceControlWorkspaceBlueprintWorkingCopyPathsKey": {
61 | "A36AEFA3F9FF1F738E92F0C497C14977DCE02B97": "XcodeServerSDK/"
62 | },
63 | "DVTSourceControlWorkspaceBlueprintNameKey": "XcodeServerSDK",
64 | "DVTSourceControlWorkspaceBlueprintVersion": 203,
65 | "DVTSourceControlWorkspaceBlueprintRelativePathToProjectKey": "XcodeServerSDK.xcworkspace",
66 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoriesKey": [
67 | {
68 | "DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey": "com.apple.dt.Xcode.sourcecontrol.Git",
69 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey": "git@github.com:czechboy0/XcodeServerSDK.git",
70 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoryTrustedCertFingerprintKey": "1627ACA576282D36631B564DEBDFA648",
71 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey": "A36AEFA3F9FF1F738E92F0C497C14977DCE02B97",
72 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoryTrustSelfSignedCertKey": true
73 | }
74 | ]
75 | },
76 | "testingDestinationType": 0
77 | },
78 | "requiresUpgrade": false,
79 | "name": "Default iOS Bot",
80 | "type": 1
81 | }
--------------------------------------------------------------------------------
/XcodeServerSDKTests/Data/create_osx_bot.json:
--------------------------------------------------------------------------------
1 | {
2 | "group": {
3 | "name": "2FDD3BEB-D750-47EE-B386-07EA9BABA98B"
4 | },
5 | "configuration": {
6 | "builtFromClean": 0,
7 | "periodicScheduleInterval": 1,
8 | "codeCoveragePreference": 2,
9 | "performsTestAction": true,
10 | "triggers": [
11 | {
12 | "phase": 1,
13 | "scriptBody": "echo \"Run before\"",
14 | "type": 1,
15 | "name": "Run Script"
16 | },
17 | {
18 | "phase": 2,
19 | "scriptBody": "echo \"Run after\"",
20 | "type": 1,
21 | "name": "Run Script",
22 | "conditions": {
23 | "status": 2,
24 | "onWarnings": true,
25 | "onBuildErrors": true,
26 | "onInternalErrors": true,
27 | "onAnalyzerWarnings": true,
28 | "onFailingTests": true,
29 | "onSuccess": true
30 | }
31 | },
32 | {
33 | "phase": 2,
34 | "scriptBody": "",
35 | "type": 2,
36 | "name": "Send Email Notification",
37 | "conditions": {
38 | "status": 2,
39 | "onWarnings": true,
40 | "onBuildErrors": true,
41 | "onInternalErrors": true,
42 | "onAnalyzerWarnings": true,
43 | "onFailingTests": true,
44 | "onSuccess": false
45 | },
46 | "emailConfiguration": {
47 | "includeCommitMessages": true,
48 | "additionalRecipients": [
49 | "email@committers.yo"
50 | ],
51 | "emailCommitters": true,
52 | "scmOptions": {
53 | "A36AEFA3F9FF1F738E92F0C497C14977DCE02B97": true
54 | },
55 | "includeIssueDetails": true
56 | }
57 | }
58 | ],
59 | "performsAnalyzeAction": true,
60 | "schemeName": "XcodeServerSDK - OS X",
61 | "exportsProductFromArchive": true,
62 | "testingDeviceIDs": [],
63 | "deviceSpecification": {
64 | "filters": [
65 | {
66 | "platform": {
67 | "buildNumber": "15A204f",
68 | "_id": "a85553a5b26a7c1a4998f3b237000b18",
69 | "_rev": "12-b005bffe3337cfe101fd597c300b0208",
70 | "displayName": "OS X",
71 | "identifier": "com.apple.platform.macosx",
72 | "version": "1.1"
73 | },
74 | "filterType": 0,
75 | "architectureType": 1
76 | }
77 | ],
78 | "deviceIdentifiers": []
79 | },
80 | "weeklyScheduleDay": 0,
81 | "minutesAfterHourToIntegrate": 0,
82 | "scheduleType": 1,
83 | "hourOfIntegration": 0,
84 | "performsArchiveAction": true,
85 | "sourceControlBlueprint": {
86 | "DVTSourceControlWorkspaceBlueprintLocationsKey": {
87 | "A36AEFA3F9FF1F738E92F0C497C14977DCE02B97": {
88 | "DVTSourceControlBranchIdentifierKey": "hd/tested_devices_xcode_7",
89 | "DVTSourceControlBranchOptionsKey": 156,
90 | "DVTSourceControlWorkspaceBlueprintLocationTypeKey": "DVTSourceControlBranch"
91 | }
92 | },
93 | "DVTSourceControlWorkspaceBlueprintPrimaryRemoteRepositoryKey": "A36AEFA3F9FF1F738E92F0C497C14977DCE02B97",
94 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoryAuthenticationStrategiesKey": {
95 | "A36AEFA3F9FF1F738E92F0C497C14977DCE02B97": {
96 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoryUsernameKey": "git",
97 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoryAuthenticationStrategiesKey": "MY_PRIVATE_KEY",
98 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoryAuthenticationTypeKey": "DVTSourceControlSSHKeysAuthenticationStrategy",
99 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoryPublicKeyDataKey": "c3NoLXJzYSBBQUFBQjNOemFDMXljMkVBQUFBREFRQUJBQUFCQVFETUlyMHIyK3pt\r\nZ2JIajhBcnczRDQzZ0N5WURMc3p6ZWtIdTZZK0FKd29xZC8venFXU1FqamxlMkRt\r\nSmFueXNORnRhbFU3U005M2dtYXEzYTI4YjM3aWZnRmMrMXlhSDRNOC9EUk1yaHRR\r\ndk9JSEhYcWNzeUpwU0RWRkl3YjVxRm5LblNGaW96NGdSTkV0R1VOWWdCVTNYNHRs\r\nQzNMQkV1RmZhdS9RVXZZOEY5NmdMS3BGMTF0ZHdaanlDREN5ZWtIT2JaeWU2RS9R\r\nelRKZXppWjF5RXdHcXdvS3Q1NlpoZ1JHNG5yRHMwaEU2dDYxUG90WkdiMEpSbVRm\r\nYThFM05Mckp5ZklreS9DK2hpQ2tsSmZRelZndGk2MWtwMDJuZFN1ODlHK3dBY0xJ\r\nUjJ2Qzk2TndWRW9pZG1MTnN0bXlrMlhEbG1jVzB2Z0ZHVmptNWx2ZkljWVYgaG9u\r\nemFAc3dpZnRrZXkubmV0Cg==",
100 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoryPasswordKey": ""
101 | }
102 | },
103 | "DVTSourceControlWorkspaceBlueprintWorkingCopyStatesKey": {
104 | "A36AEFA3F9FF1F738E92F0C497C14977DCE02B97": 0
105 | },
106 | "DVTSourceControlWorkspaceBlueprintIdentifierKey": "04531A78-B36E-4E1E-B304-92BD53E2E173",
107 | "DVTSourceControlWorkspaceBlueprintWorkingCopyPathsKey": {
108 | "A36AEFA3F9FF1F738E92F0C497C14977DCE02B97": "XcodeServerSDK/"
109 | },
110 | "DVTSourceControlWorkspaceBlueprintNameKey": "XcodeServerSDK",
111 | "DVTSourceControlWorkspaceBlueprintVersion": 203,
112 | "DVTSourceControlWorkspaceBlueprintRelativePathToProjectKey": "XcodeServerSDK.xcworkspace",
113 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoriesKey": [
114 | {
115 | "DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey": "com.apple.dt.Xcode.sourcecontrol.Git",
116 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey": "git@github.com:czechboy0/XcodeServerSDK.git",
117 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoryTrustedCertFingerprintKey": "1627ACA576282D36631B564DEBDFA648",
118 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey": "A36AEFA3F9FF1F738E92F0C497C14977DCE02B97",
119 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoryTrustSelfSignedCertKey": true
120 | }
121 | ]
122 | },
123 | "testingDestinationType": 7
124 | },
125 | "requiresUpgrade": false,
126 | "name": "Default OS X Bot",
127 | "type": 1
128 | }
--------------------------------------------------------------------------------
/XcodeServerSDKTests/Data/create_watch_bot.json:
--------------------------------------------------------------------------------
1 | {
2 | "group": {
3 | "name": "77F7F792-7D3B-499E-9D3B-FE10858AF8E3"
4 | },
5 | "configuration": {
6 | "builtFromClean": 0,
7 | "periodicScheduleInterval": 1,
8 | "codeCoveragePreference": 2,
9 | "performsTestAction": false,
10 | "triggers": [],
11 | "performsAnalyzeAction": true,
12 | "schemeName": "XcodeServerSDK - watchOS",
13 | "exportsProductFromArchive": true,
14 | "testingDeviceIDs": [],
15 | "deviceSpecification": {
16 | "filters": [
17 | {
18 | "platform": {
19 | "_id": "a85553a5b26a7c1a4998f3b237000c7d",
20 | "displayName": "watchOS",
21 | "_rev": "12-58b9b255374d71f362f830256dfa65e4",
22 | "simulatorIdentifier": "com.apple.platform.watchsimulator",
23 | "identifier": "com.apple.platform.watchos",
24 | "buildNumber": "13S5255c",
25 | "version": "2.0"
26 | },
27 | "filterType": 0,
28 | "architectureType": 0
29 | }
30 | ],
31 | "deviceIdentifiers": []
32 | },
33 | "weeklyScheduleDay": 0,
34 | "minutesAfterHourToIntegrate": 0,
35 | "scheduleType": 1,
36 | "hourOfIntegration": 0,
37 | "performsArchiveAction": true,
38 | "sourceControlBlueprint": {
39 | "DVTSourceControlWorkspaceBlueprintLocationsKey": {
40 | "A36AEFA3F9FF1F738E92F0C497C14977DCE02B97": {
41 | "DVTSourceControlBranchIdentifierKey": "hd/tested_devices_xcode_7",
42 | "DVTSourceControlBranchOptionsKey": 156,
43 | "DVTSourceControlWorkspaceBlueprintLocationTypeKey": "DVTSourceControlBranch"
44 | }
45 | },
46 | "DVTSourceControlWorkspaceBlueprintPrimaryRemoteRepositoryKey": "A36AEFA3F9FF1F738E92F0C497C14977DCE02B97",
47 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoryAuthenticationStrategiesKey": {
48 | "A36AEFA3F9FF1F738E92F0C497C14977DCE02B97": {
49 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoryUsernameKey": "git",
50 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoryAuthenticationStrategiesKey": "MY_PRIVATE_KEY",
51 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoryAuthenticationTypeKey": "DVTSourceControlSSHKeysAuthenticationStrategy",
52 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoryPublicKeyDataKey": "c3NoLXJzYSBBQUFBQjNOemFDMXljMkVBQUFBREFRQUJBQUFCQVFETUlyMHIyK3pt\r\nZ2JIajhBcnczRDQzZ0N5WURMc3p6ZWtIdTZZK0FKd29xZC8venFXU1FqamxlMkRt\r\nSmFueXNORnRhbFU3U005M2dtYXEzYTI4YjM3aWZnRmMrMXlhSDRNOC9EUk1yaHRR\r\ndk9JSEhYcWNzeUpwU0RWRkl3YjVxRm5LblNGaW96NGdSTkV0R1VOWWdCVTNYNHRs\r\nQzNMQkV1RmZhdS9RVXZZOEY5NmdMS3BGMTF0ZHdaanlDREN5ZWtIT2JaeWU2RS9R\r\nelRKZXppWjF5RXdHcXdvS3Q1NlpoZ1JHNG5yRHMwaEU2dDYxUG90WkdiMEpSbVRm\r\nYThFM05Mckp5ZklreS9DK2hpQ2tsSmZRelZndGk2MWtwMDJuZFN1ODlHK3dBY0xJ\r\nUjJ2Qzk2TndWRW9pZG1MTnN0bXlrMlhEbG1jVzB2Z0ZHVmptNWx2ZkljWVYgaG9u\r\nemFAc3dpZnRrZXkubmV0Cg==",
53 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoryPasswordKey": ""
54 | }
55 | },
56 | "DVTSourceControlWorkspaceBlueprintWorkingCopyStatesKey": {
57 | "A36AEFA3F9FF1F738E92F0C497C14977DCE02B97": 0
58 | },
59 | "DVTSourceControlWorkspaceBlueprintIdentifierKey": "D11746DF-6E40-49FF-9AAB-8FF4BFCF0082",
60 | "DVTSourceControlWorkspaceBlueprintWorkingCopyPathsKey": {
61 | "A36AEFA3F9FF1F738E92F0C497C14977DCE02B97": "XcodeServerSDK/"
62 | },
63 | "DVTSourceControlWorkspaceBlueprintNameKey": "XcodeServerSDK",
64 | "DVTSourceControlWorkspaceBlueprintVersion": 203,
65 | "DVTSourceControlWorkspaceBlueprintRelativePathToProjectKey": "XcodeServerSDK.xcworkspace",
66 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoriesKey": [
67 | {
68 | "DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey": "com.apple.dt.Xcode.sourcecontrol.Git",
69 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey": "git@github.com:czechboy0/XcodeServerSDK.git",
70 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoryTrustedCertFingerprintKey": "1627ACA576282D36631B564DEBDFA648",
71 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey": "A36AEFA3F9FF1F738E92F0C497C14977DCE02B97",
72 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoryTrustSelfSignedCertKey": true
73 | }
74 | ]
75 | },
76 | "testingDestinationType": 0
77 | },
78 | "requiresUpgrade": false,
79 | "name": "Default Watch Bot",
80 | "type": 1
81 | }
82 |
--------------------------------------------------------------------------------
/XcodeServerSDKTests/Data/platforms.json:
--------------------------------------------------------------------------------
1 | {
2 | "count": 3,
3 | "results": [
4 | {
5 | "_id": "a85553a5b26a7c1a4998f3b237000b18",
6 | "_rev": "12-b005bffe3337cfe101fd597c300b0208",
7 | "buildNumber": "15A204f",
8 | "displayName": "OS X",
9 | "identifier": "com.apple.platform.macosx",
10 | "version": "1.1",
11 | "doc_type": "platform",
12 | "tinyID": "0224D30"
13 | },
14 | {
15 | "_id": "a85553a5b26a7c1a4998f3b237000c7d",
16 | "_rev": "12-58b9b255374d71f362f830256dfa65e4",
17 | "buildNumber": "13S5255c",
18 | "simulatorIdentifier": "com.apple.platform.watchsimulator",
19 | "displayName": "watchOS",
20 | "identifier": "com.apple.platform.watchos",
21 | "version": "2.0",
22 | "doc_type": "platform",
23 | "tinyID": "BA84EFD"
24 | },
25 | {
26 | "_id": "a85553a5b26a7c1a4998f3b237000da9",
27 | "_rev": "12-162b2b9d57b73b66724426eea53bfcaf",
28 | "buildNumber": "13A4280e",
29 | "simulatorIdentifier": "com.apple.platform.iphonesimulator",
30 | "displayName": "iOS",
31 | "identifier": "com.apple.platform.iphoneos",
32 | "version": "9.0",
33 | "doc_type": "platform",
34 | "tinyID": "0273BAD"
35 | }
36 | ]
37 | }
--------------------------------------------------------------------------------
/XcodeServerSDKTests/Data/scm_branches_request_no_fingerprint.json:
--------------------------------------------------------------------------------
1 | {
2 | "DVTSourceControlWorkspaceBlueprintLocationsKey": {
3 | "A36AEFA3F9FF1F738E92F0C497C14977DCE02B97": {
4 | "DVTSourceControlBranchIdentifierKey": "hd/tested_devices_xcode_7",
5 | "DVTSourceControlBranchOptionsKey": 220,
6 | "DVTSourceControlWorkspaceBlueprintLocationTypeKey": "DVTSourceControlBranch"
7 | }
8 | },
9 | "DVTSourceControlWorkspaceBlueprintPrimaryRemoteRepositoryKey": "A36AEFA3F9FF1F738E92F0C497C14977DCE02B97",
10 | "DVTSourceControlWorkspaceBlueprintWorkingCopyRepositoryLocationsKey": {},
11 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoryAuthenticationStrategiesKey": {
12 | "A36AEFA3F9FF1F738E92F0C497C14977DCE02B97": {
13 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoryUsernameKey": "git",
14 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoryAuthenticationStrategiesKey": "THIS_IS_MY_SECRET_PRIVATE_KEY_MUHAHA",
15 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoryAuthenticationTypeKey": "DVTSourceControlSSHKeysAuthenticationStrategy",
16 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoryPublicKeyDataKey": "c3NoLXJzYSBBQUFBQjNOemFDMXljMkVBQUFBREFRQUJBQUFCQVFETUlyMHIyK3pt\r\nZ2JIajhBcnczRDQzZ0N5WURMc3p6ZWtIdTZZK0FKd29xZC8venFXU1FqamxlMkRt\r\nSmFueXNORnRhbFU3U005M2dtYXEzYTI4YjM3aWZnRmMrMXlhSDRNOC9EUk1yaHRR\r\ndk9JSEhYcWNzeUpwU0RWRkl3YjVxRm5LblNGaW96NGdSTkV0R1VOWWdCVTNYNHRs\r\nQzNMQkV1RmZhdS9RVXZZOEY5NmdMS3BGMTF0ZHdaanlDREN5ZWtIT2JaeWU2RS9R\r\nelRKZXppWjF5RXdHcXdvS3Q1NlpoZ1JHNG5yRHMwaEU2dDYxUG90WkdiMEpSbVRm\r\nYThFM05Mckp5ZklreS9DK2hpQ2tsSmZRelZndGk2MWtwMDJuZFN1ODlHK3dBY0xJ\r\nUjJ2Qzk2TndWRW9pZG1MTnN0bXlrMlhEbG1jVzB2Z0ZHVmptNWx2ZkljWVYgaG9u\r\nemFAc3dpZnRrZXkubmV0Cg==",
17 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoryPasswordKey": ""
18 | }
19 | },
20 | "DVTSourceControlWorkspaceBlueprintWorkingCopyStatesKey": {
21 | "A36AEFA3F9FF1F738E92F0C497C14977DCE02B97": 0
22 | },
23 | "DVTSourceControlWorkspaceBlueprintIdentifierKey": "9520BFD3-FFF2-455B-B838-00306AAE916A",
24 | "DVTSourceControlWorkspaceBlueprintWorkingCopyPathsKey": {
25 | "A36AEFA3F9FF1F738E92F0C497C14977DCE02B97": "XcodeServerSDK/"
26 | },
27 | "DVTSourceControlWorkspaceBlueprintNameKey": "XcodeServerSDK",
28 | "DVTSourceControlWorkspaceBlueprintVersion": 203,
29 | "DVTSourceControlWorkspaceBlueprintRelativePathToProjectKey": "XcodeServerSDK.xcworkspace",
30 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoriesKey": [
31 | {
32 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey": "git@github.com:czechboy0/XcodeServerSDK.git",
33 | "DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey": "com.apple.dt.Xcode.sourcecontrol.Git",
34 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey": "A36AEFA3F9FF1F738E92F0C497C14977DCE02B97"
35 | }
36 | ]
37 | }
--------------------------------------------------------------------------------
/XcodeServerSDKTests/Data/scm_branches_request_with_fingerprint.json:
--------------------------------------------------------------------------------
1 | {
2 | "DVTSourceControlWorkspaceBlueprintLocationsKey": {
3 | "A36AEFA3F9FF1F738E92F0C497C14977DCE02B97": {
4 | "DVTSourceControlBranchIdentifierKey": "hd/tested_devices_xcode_7",
5 | "DVTSourceControlBranchOptionsKey": 220,
6 | "DVTSourceControlWorkspaceBlueprintLocationTypeKey": "DVTSourceControlBranch"
7 | }
8 | },
9 | "DVTSourceControlWorkspaceBlueprintPrimaryRemoteRepositoryKey": "A36AEFA3F9FF1F738E92F0C497C14977DCE02B97",
10 | "DVTSourceControlWorkspaceBlueprintWorkingCopyRepositoryLocationsKey": {},
11 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoryAuthenticationStrategiesKey": {
12 | "A36AEFA3F9FF1F738E92F0C497C14977DCE02B97": {
13 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoryUsernameKey": "git",
14 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoryAuthenticationStrategiesKey": "THIS_IS_MY_SECRET_PRIVATE_KEY_MUHAHA",
15 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoryAuthenticationTypeKey": "DVTSourceControlSSHKeysAuthenticationStrategy",
16 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoryPublicKeyDataKey": "c3NoLXJzYSBBQUFBQjNOemFDMXljMkVBQUFBREFRQUJBQUFCQVFETUlyMHIyK3pt\r\nZ2JIajhBcnczRDQzZ0N5WURMc3p6ZWtIdTZZK0FKd29xZC8venFXU1FqamxlMkRt\r\nSmFueXNORnRhbFU3U005M2dtYXEzYTI4YjM3aWZnRmMrMXlhSDRNOC9EUk1yaHRR\r\ndk9JSEhYcWNzeUpwU0RWRkl3YjVxRm5LblNGaW96NGdSTkV0R1VOWWdCVTNYNHRs\r\nQzNMQkV1RmZhdS9RVXZZOEY5NmdMS3BGMTF0ZHdaanlDREN5ZWtIT2JaeWU2RS9R\r\nelRKZXppWjF5RXdHcXdvS3Q1NlpoZ1JHNG5yRHMwaEU2dDYxUG90WkdiMEpSbVRm\r\nYThFM05Mckp5ZklreS9DK2hpQ2tsSmZRelZndGk2MWtwMDJuZFN1ODlHK3dBY0xJ\r\nUjJ2Qzk2TndWRW9pZG1MTnN0bXlrMlhEbG1jVzB2Z0ZHVmptNWx2ZkljWVYgaG9u\r\nemFAc3dpZnRrZXkubmV0Cg==",
17 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoryPasswordKey": ""
18 | }
19 | },
20 | "DVTSourceControlWorkspaceBlueprintWorkingCopyStatesKey": {
21 | "A36AEFA3F9FF1F738E92F0C497C14977DCE02B97": 0
22 | },
23 | "DVTSourceControlWorkspaceBlueprintIdentifierKey": "9520BFD3-FFF2-455B-B838-00306AAE916A",
24 | "DVTSourceControlWorkspaceBlueprintWorkingCopyPathsKey": {
25 | "A36AEFA3F9FF1F738E92F0C497C14977DCE02B97": "XcodeServerSDK/"
26 | },
27 | "DVTSourceControlWorkspaceBlueprintNameKey": "XcodeServerSDK",
28 | "DVTSourceControlWorkspaceBlueprintVersion": 203,
29 | "DVTSourceControlWorkspaceBlueprintRelativePathToProjectKey": "XcodeServerSDK.xcworkspace",
30 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoriesKey": [
31 | {
32 | "DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey": "com.apple.dt.Xcode.sourcecontrol.Git",
33 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey": "git@github.com:czechboy0/XcodeServerSDK.git",
34 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoryTrustedCertFingerprintKey": "1627ACA576282D36631B564DEBDFA648",
35 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey": "A36AEFA3F9FF1F738E92F0C497C14977DCE02B97",
36 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoryTrustSelfSignedCertKey": true
37 | }
38 | ]
39 | }
--------------------------------------------------------------------------------
/XcodeServerSDKTests/Data/scm_branches_response_error.json:
--------------------------------------------------------------------------------
1 | {
2 | "repositoryErrors": [
3 | {
4 | "error": {
5 | "code": -1004,
6 | "message": "The server SSH fingerprint failed to verify.",
7 | "underlyingError": "",
8 | "domain": "com.apple.dt.SourceControlErrorDomain",
9 | "fingerprint": "1627ACA576282D36631B564DEBDFA648"
10 | },
11 | "repository": "A36AEFA3F9FF1F738E92F0C497C14977DCE02B97"
12 | }
13 | ]
14 | }
--------------------------------------------------------------------------------
/XcodeServerSDKTests/Data/scm_branches_response_success.json:
--------------------------------------------------------------------------------
1 | {
2 | "branches": {
3 | "A36AEFA3F9FF1F738E92F0C497C14977DCE02B97": [
4 | {
5 | "name": "buildasaur",
6 | "primary": false
7 | },
8 | {
9 | "name": "hd/tested_devices_xcode_7",
10 | "primary": false
11 | },
12 | {
13 | "name": "master",
14 | "primary": false
15 | },
16 | {
17 | "name": "swift-2",
18 | "primary": true
19 | }
20 | ]
21 | }
22 | }
--------------------------------------------------------------------------------
/XcodeServerSDKTests/DevicesTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DevicesTests.swift
3 | // XcodeServerSDK
4 | //
5 | // Created by Mateusz Zając on 13/07/15.
6 | // Copyright © 2015 Honza Dvorsky. All rights reserved.
7 | //
8 |
9 | import XCTest
10 | import XcodeServerSDK
11 |
12 | class DevicesTests: XCTestCase {
13 |
14 | let macMini = try! Device(json: [
15 | "osVersion" : "10.11",
16 | "connected" : true,
17 | "simulator" : false,
18 | "modelCode" : "Macmini6,1",
19 | "deviceType" : "com.apple.mac",
20 | "modelName" : "Mac mini",
21 | "_id" : "1ad0e8785cacca73d980cdb23600383e",
22 | "modelUTI" : "com.apple.macmini-unibody-no-optical",
23 | "doc_type" : "device",
24 | "trusted" : true,
25 | "name" : "bozenka",
26 | "supported" : true,
27 | "processor" : "2,5 GHz Intel Core i5",
28 | "identifier" : "FFFFFFFF-0F3C-5893-AF8A-D9CFF068B82C-x86_64",
29 | "enabledForDevelopment" : true,
30 | "serialNumber" : "C07JT7H5DWYL",
31 | "platformIdentifier" : "com.apple.platform.macosx",
32 | "_rev" : "3-6a49ba8135f3f4ddcbaefe1b469f479c",
33 | "architecture" : "x86_64",
34 | "retina" : false,
35 | "isServer" : true,
36 | "tinyID" : "7DCD98A"
37 | ])
38 |
39 | func testDictionarify() {
40 | let expected = [ "device_id": "1ad0e8785cacca73d980cdb23600383e" ]
41 | XCTAssertEqual(macMini.dictionarify(), expected)
42 | }
43 |
44 | func testGetDevices() {
45 | let expectation = self.expectationWithDescription("Get Devices")
46 | let server = self.getRecordingXcodeServer("get_devices")
47 |
48 | server.getDevices { (devices, error) -> () in
49 | XCTAssertNil(error)
50 | XCTAssertNotNil(devices)
51 |
52 | if let devices = devices {
53 | XCTAssertEqual(devices.count, 15, "There should be 15 devices")
54 | XCTAssertEqual(devices.filter { $0.platform == DevicePlatform.PlatformType.iOS }.count, 2, "There should be 2 real iPhones")
55 | XCTAssertEqual(devices.filter { $0.platform == DevicePlatform.PlatformType.OSX }.count, 2, "There should be 2 real Macs")
56 | XCTAssertEqual(devices.filter { $0.platform == DevicePlatform.PlatformType.iOS_Simulator }.count, 9, "There should be 9 iOS simulators")
57 | XCTAssertEqual(devices.filter { $0.platform == DevicePlatform.PlatformType.watchOS_Simulator }.count, 2, "There should be 2 watchOS simulators")
58 | XCTAssertEqual(devices.filter { $0.activeProxiedDevice != nil }.count, 2, "There should be 2 active proxied devices (watchOS)")
59 | }
60 |
61 | expectation.fulfill()
62 | }
63 |
64 | self.waitForExpectationsWithTimeout(10.0, handler: nil)
65 | }
66 |
67 | }
68 |
--------------------------------------------------------------------------------
/XcodeServerSDKTests/FileTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // FileTests.swift
3 | // XcodeServerSDK
4 | //
5 | // Created by Mateusz Zając on 22/07/15.
6 | // Copyright © 2015 Honza Dvorsky. All rights reserved.
7 | //
8 |
9 | import XCTest
10 | @testable import XcodeServerSDK
11 |
12 | class FileTests: XCTestCase {
13 |
14 | let sampleAdded = [
15 | "status": 1,
16 | "filePath": "File1.swift"
17 | ]
18 |
19 | let sampleOther = [
20 | "status": 1024,
21 | "filePath": "File2.swift"
22 | ]
23 |
24 | // MARK: Initialization
25 | func testDictionaryInit() throws {
26 | var file = try File(json: sampleAdded)
27 |
28 | XCTAssertEqual(file.filePath, "File1.swift")
29 | XCTAssertEqual(file.status, FileStatus.Added)
30 |
31 | file = try File(json: sampleOther)
32 |
33 | XCTAssertEqual(file.filePath, "File2.swift")
34 | XCTAssertEqual(file.status, FileStatus.Other)
35 | }
36 |
37 | func testInit() {
38 | let file = File(filePath: "File1.swift", status: .Added)
39 |
40 | XCTAssertEqual(file.filePath, "File1.swift")
41 | XCTAssertEqual(file.status, FileStatus.Added)
42 | }
43 |
44 | // MARK: Dictioninarifying
45 | func testDictionarify() throws {
46 | let file = try File(json: sampleAdded)
47 |
48 | XCTAssertEqual(file.dictionarify(), sampleAdded)
49 | }
50 |
51 | }
52 |
--------------------------------------------------------------------------------
/XcodeServerSDKTests/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | BNDL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1
23 |
24 |
25 |
--------------------------------------------------------------------------------
/XcodeServerSDKTests/IntegrationTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // IntegrationTests.swift
3 | // XcodeServerSDK
4 | //
5 | // Created by Honza Dvorsky on 17/07/2015.
6 | // Copyright © 2015 Honza Dvorsky. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import XcodeServerSDK
11 | import XCTest
12 | import Nimble
13 |
14 | class IntegrationTests: XCTestCase {
15 |
16 | func test_GetIntegration() {
17 |
18 | let server = self.getRecordingXcodeServer("get_integration")
19 | var done = false
20 | server.getIntegration("ad2fac04895bd1bb06c1d50e3400fd35") { (integration, error) in
21 | expect(error).to(beNil())
22 | expect(integration).toNot(beNil())
23 | done = true
24 | }
25 | expect(done).toEventually(beTrue())
26 | }
27 |
28 | // MARK: Commits
29 |
30 | var expectedDate: NSDate = {
31 | let formatter = NSDateFormatter()
32 | formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSZZZZ"
33 |
34 | return formatter.dateFromString("2015-07-24T09:40:58.462Z")!
35 | }()
36 |
37 | func testGetIntegrationCommits() {
38 |
39 | var done = false
40 | let server = self.getRecordingXcodeServer("get_integration_commits")
41 | server.getIntegrationCommits("56ad016e2e3993ca0b8ed276050150e8") {
42 |
43 | (integrationCommits, error) in
44 |
45 | expect(error).to(beNil())
46 | guard let integrationCommits = integrationCommits,
47 | let expectationDate = integrationCommits.endedTimeDate,
48 | let commits = integrationCommits.commits["A36AEFA3F9FF1F738E92F0C497C14977DCE02B97"] else {
49 | fail("Integration commits are empty")
50 | return
51 | }
52 |
53 | expect(expectationDate) == self.expectedDate
54 | expect(commits.count) == 6
55 |
56 | let commiters = Set(commits.map { $0.contributor.name })
57 | expect(commiters.count) == 2
58 |
59 | done = true
60 | }
61 |
62 | expect(done).toEventually(beTrue())
63 | }
64 |
65 | // MARK: Issues
66 |
67 | func testGetIntegrationIssues() {
68 |
69 | var done = false
70 | let server = self.getRecordingXcodeServer("get_integration_issues")
71 | server.getIntegrationIssues("960f6989b4c7289433ff04db71033d28") { (integrationIssues, error) -> () in
72 |
73 | expect(error).to(beNil())
74 |
75 | guard let issues = integrationIssues else {
76 | fail("Integration issues should be present")
77 | return
78 | }
79 |
80 | expect(issues.errors.count) == 1
81 |
82 | let expectation = issues.warnings.filter { $0.status == .Fresh }
83 | expect(expectation.count) == 2
84 | expect(issues.analyzerWarnings.isEmpty).to(beTrue())
85 |
86 | done = true
87 | }
88 |
89 | expect(done).toEventually(beTrue())
90 | }
91 |
92 | }
93 |
--------------------------------------------------------------------------------
/XcodeServerSDKTests/IssueTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // IssueTests.swift
3 | // XcodeServerSDK
4 | //
5 | // Created by Mateusz Zając on 05.08.2015.
6 | // Copyright © 2015 Honza Dvorsky. All rights reserved.
7 | //
8 |
9 | import XCTest
10 | @testable import XcodeServerSDK
11 |
12 | class IssueTests: XCTestCase {
13 |
14 | let buildServiceError = try! IntegrationIssue(json: [
15 | "_id": "99e84a22b20df344df2217d5e4186094",
16 | "_rev": "3-0cf0b25e995f1a050617d3c5824007f7",
17 | "message": "This integration was canceled.",
18 | "type": "buildServiceError",
19 | "issueType": "Build Service Error",
20 | "commits": [],
21 | "integrationID": "99e84a22b20df344df2217d5e4183bce",
22 | "age": 0,
23 | "status": 0
24 | ])
25 |
26 | let errorWithCommits = try! IntegrationIssue(json: [
27 | "_id": "99e84a22b20df344df2217d5e413f43e",
28 | "_rev": "3-7dfc0aa57a8119c025cd2d86143589f2",
29 | "message": "Expected declaration",
30 | "type": "error",
31 | "issueType": "Swift Compiler Error",
32 | "commits": [
33 | [
34 | "XCSCommitCommitChangeFilePaths": [
35 | [
36 | "status": 4,
37 | "filePath": "XcodeServerSDK/Server Entities/Bot.swift"
38 | ],
39 | [
40 | "status": 4,
41 | "filePath": "XcodeServerSDK/Server Entities/Trigger.swift"
42 | ]
43 | ],
44 | "XCSCommitMessage": "Break regular code\n",
45 | "XCSBlueprintRepositoryID": "A36AEFA3F9FF1F738E92F0C497C14977DCE02B97",
46 | "XCSCommitContributor": [
47 | "XCSContributorEmails": [
48 | "example@example.com"
49 | ],
50 | "XCSContributorName": "tester",
51 | "XCSContributorDisplayName": "tester"
52 | ],
53 | "XCSCommitHash": "1a37d7ce39297ad822626fc2061a1ba343aed343",
54 | "XCSCommitTimestamp": "2015-08-03T08:23:17.000Z"
55 | ]
56 | ],
57 | "target": "XcodeServerSDK - OS X",
58 | "documentFilePath": "XcodeServerSDK/XcodeServerSDK/Server Entities/Bot.swift",
59 | "documentLocationData": "YnBsaXN0MDDUAQIDBAUGIyRYJHZlcnNpb25YJG9iamVjdHNZJGFyY2hpdmVyVCR0b3ASAAGGoKQHCBobVSRudWxs2gkKCwwNDg8QERITFBQVFhcYGRgVW2RvY3VtZW50VVJMXxAUc3RhcnRpbmdDb2x1bW5OdW1iZXJfEBJlbmRpbmdDb2x1bW5OdW1iZXJfEBFjaGFyYWN0ZXJSYW5nZUxlbl8QEGxvY2F0aW9uRW5jb2RpbmdWJGNsYXNzXxAQZW5kaW5nTGluZU51bWJlcll0aW1lc3RhbXBfEBJzdGFydGluZ0xpbmVOdW1iZXJfEBFjaGFyYWN0ZXJSYW5nZUxvY4ACEAQQABABgAMQHIAAXxCbZmlsZTovLy9MaWJyYXJ5L0RldmVsb3Blci9YY29kZVNlcnZlci9JbnRlZ3JhdGlvbnMvQ2FjaGVzLzk5ZTg0YTIyYjIwZGYzNDRkZjIyMTdkNWU0MDNmM2U0L1NvdXJjZS9YY29kZVNlcnZlclNESy9YY29kZVNlcnZlclNESy9TZXJ2ZXIlMjBFbnRpdGllcy9Cb3Quc3dpZnTSHB0eH1okY2xhc3NuYW1lWCRjbGFzc2VzXxAXRFZUVGV4dERvY3VtZW50TG9jYXRpb26jICEiXxAXRFZUVGV4dERvY3VtZW50TG9jYXRpb25fEBNEVlREb2N1bWVudExvY2F0aW9uWE5TT2JqZWN0XxAPTlNLZXllZEFyY2hpdmVy0SUmVHJvb3SAAQAIABEAGgAjAC0AMgA3ADwAQgBXAGMAegCPAKMAtgC9ANAA2gDvAQMBBQEHAQkBCwENAQ8BEQGvAbQBvwHIAeIB5gIAAhYCHwIxAjQCOQAAAAAAAAIBAAAAAAAAACcAAAAAAAAAAAAAAAAAAAI7",
60 | "lineNumber": 29,
61 | "integrationID": "99e84a22b20df344df2217d5e413adf7",
62 | "age": 0,
63 | "status": 0
64 | ])
65 |
66 | // MARK: Test cases
67 | func testJSONInitialization() {
68 | // Shouldn't be nil
69 | XCTAssertNotNil(buildServiceError)
70 | XCTAssertNotNil(errorWithCommits)
71 |
72 | // Check types
73 | XCTAssertEqual(buildServiceError.type, IntegrationIssue.IssueType.BuildServiceError)
74 | XCTAssertEqual(errorWithCommits.type, IntegrationIssue.IssueType.Error)
75 | }
76 |
77 | func testPayload() {
78 | XCTAssertEqual(buildServiceError.payload.allKeys.count, 9)
79 | XCTAssertEqual(errorWithCommits.payload.allKeys.count, 13)
80 |
81 | // Check if Error payload contain line number
82 | let expectation = errorWithCommits.payload["lineNumber"] as! Int
83 | XCTAssertEqual(expectation, 29)
84 | }
85 |
86 | func testCommitsArray() {
87 | // Build Service Error doesn't have commits
88 | XCTAssertTrue(buildServiceError.commits.isEmpty)
89 |
90 | // Error, on the other hand, has one...
91 | XCTAssertEqual(errorWithCommits.commits.count, 1)
92 | XCTAssertEqual(errorWithCommits.commits.first!.filePaths.count, 2)
93 | XCTAssertEqual(errorWithCommits.commits.first!.contributor.name, "tester")
94 | }
95 |
96 | }
97 |
--------------------------------------------------------------------------------
/XcodeServerSDKTests/LiveUpdatesTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // LiveUpdatesTests.swift
3 | // XcodeServerSDK
4 | //
5 | // Created by Honza Dvorsky on 27/09/2015.
6 | // Copyright © 2015 Honza Dvorsky. All rights reserved.
7 | //
8 |
9 | import XCTest
10 | import Foundation
11 | @testable import XcodeServerSDK
12 | import Nimble
13 |
14 | class LiveUpdatesTests: XCTestCase {
15 |
16 | func testParsing_ConnectPacket() {
17 |
18 | let message = "1::"
19 | let packets: [SocketIOPacket] = SocketIOHelper.parsePackets(message)
20 | expect(packets.count) == 1
21 | let packet = packets.first!
22 | expect(packet.type) == SocketIOPacket.PacketType.Connect
23 | expect(packet.jsonPayload).to(beNil())
24 | expect(packet.stringPayload) == ""
25 | }
26 |
27 | func testParsing_ErrorPacket() {
28 | let message = "7:::1+0"
29 | let packets: [SocketIOPacket] = SocketIOHelper.parsePackets(message)
30 | expect(packets.count) == 1
31 | let packet = packets.first!
32 | expect(packet.type) == SocketIOPacket.PacketType.Error
33 | let (reason, advice) = packet.parseError()
34 | expect(reason) == SocketIOPacket.ErrorReason.ClientNotHandshaken
35 | expect(advice) == SocketIOPacket.ErrorAdvice.Reconnect
36 | }
37 |
38 | func testParsing_SingleEventMessage() throws {
39 |
40 | let message = "5:::{\"name\":\"advisoryIntegrationStatus\",\"args\":[{\"message\":\"BuildaKit : Linking\",\"_id\":\"07a63fae4ff2d5a37eee830be556d143\",\"percentage\":0.7578125,\"botId\":\"07a63fae4ff2d5a37eee830be50c502a\"},null]}"
41 | let packets: [SocketIOPacket] = SocketIOHelper.parsePackets(message)
42 | expect(packets.count) == 1
43 | let packet = packets.first!
44 | expect(packet.jsonPayload).toNot(beNil())
45 | let msg = try LiveUpdateMessage(json: packet.jsonPayload!)
46 | expect(msg.type) == LiveUpdateMessage.MessageType.AdvisoryIntegrationStatus
47 | expect(msg.message) == "BuildaKit : Linking"
48 | expect(msg.integrationId) == "07a63fae4ff2d5a37eee830be556d143"
49 | expect(msg.progress) == 0.7578125
50 | expect(msg.botId) == "07a63fae4ff2d5a37eee830be50c502a"
51 | }
52 |
53 | func testParsing_MultipleEventMessages() throws {
54 | let message = "�205�5:::{\"name\":\"advisoryIntegrationStatus\",\"args\":[{\"message\":\"Buildasaur : Linking\",\"_id\":\"07a63fae4ff2d5a37eee830be556d143\",\"percentage\":0.8392857360839844,\"botId\":\"07a63fae4ff2d5a37eee830be50c502a\"},null]}�218�5:::{\"name\":\"advisoryIntegrationStatus\",\"args\":[{\"message\":\"Buildasaur : Copying 1 of 3 files\",\"_id\":\"07a63fae4ff2d5a37eee830be556d143\",\"percentage\":0.8571428680419921,\"botId\":\"07a63fae4ff2d5a37eee830be50c502a\"},null]}�218�5:::{\"name\":\"advisoryIntegrationStatus\",\"args\":[{\"message\":\"Buildasaur : Copying 2 of 3 files\",\"_id\":\"07a63fae4ff2d5a37eee830be556d143\",\"percentage\":0.8607142639160156,\"botId\":\"07a63fae4ff2d5a37eee830be50c502a\"},null]}�228�5:::{\"name\":\"advisoryIntegrationStatus\",\"args\":[{\"message\":\"BuildaUtils : Compiling Swift source files\",\"_id\":\"07a63fae4ff2d5a37eee830be556d143\",\"percentage\":0.05511363506317139,\"botId\":\"07a63fae4ff2d5a37eee830be50c502a\"},null]}"
55 | let packets: [SocketIOPacket] = SocketIOHelper.parsePackets(message)
56 | expect(packets.count) == 4
57 | for packet in packets {
58 | expect(packet.jsonPayload).toNot(beNil())
59 | let msg = try LiveUpdateMessage(json: packet.jsonPayload!)
60 | expect(msg.type) == LiveUpdateMessage.MessageType.AdvisoryIntegrationStatus
61 | }
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/XcodeServerSDKTests/MiscsTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // MiscsTests.swift
3 | // XcodeServerSDK
4 | //
5 | // Created by Honza Dvorsky on 10/10/15.
6 | // Copyright © 2015 Honza Dvorsky. All rights reserved.
7 | //
8 |
9 | import XCTest
10 | import Foundation
11 | @testable import XcodeServerSDK
12 | import Nimble
13 |
14 | class MiscsTests: XCTestCase {
15 |
16 | func testHostname_Success() {
17 |
18 | let server = self.getRecordingXcodeServer("hostname")
19 | var done = false
20 |
21 | server.getHostname { (hostname, error) -> () in
22 | expect(error).to(beNil())
23 | expect(hostname) == "honzadvysmbpr14.home"
24 | done = true
25 | }
26 |
27 | expect(done).toEventually(beTrue())
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/XcodeServerSDKTests/PlatformTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // PlatformTests.swift
3 | // XcodeServerSDK
4 | //
5 | // Created by Mateusz Zając on 13/07/15.
6 | // Copyright © 2015 Honza Dvorsky. All rights reserved.
7 | //
8 |
9 | import XCTest
10 | import XcodeServerSDK
11 |
12 | class PlatformTests: XCTestCase {
13 |
14 | func testGetPlatforms() {
15 | let expectation = self.expectationWithDescription("Get Platforms")
16 | let server = self.getRecordingXcodeServer("get_platforms")
17 |
18 | server.getPlatforms { (platforms, error) -> () in
19 | XCTAssertNil(error)
20 | XCTAssertNotNil(platforms)
21 |
22 | if let platforms = platforms {
23 | XCTAssertEqual(platforms.count, 3, "There should be 3 platforms (watchOS, iOS and OS X)")
24 |
25 | let displayNames = platforms.map { $0.displayName }
26 | XCTAssertTrue(displayNames.contains("Watch OS"))
27 | XCTAssertTrue(displayNames.contains("iOS"))
28 | XCTAssertTrue(displayNames.contains("OS X"))
29 | }
30 |
31 | expectation.fulfill()
32 | }
33 |
34 | self.waitForExpectationsWithTimeout(10.0, handler: nil)
35 | }
36 |
37 | }
38 |
--------------------------------------------------------------------------------
/XcodeServerSDKTests/RepositoryTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Repository.swift
3 | // XcodeServerSDK
4 | //
5 | // Created by Mateusz Zając on 28.06.2015.
6 | // Copyright © 2015 Honza Dvorsky. All rights reserved.
7 | //
8 |
9 | import XCTest
10 | import XcodeServerSDK
11 |
12 | class RepositoryTests: XCTestCase {
13 |
14 | let json = [
15 | "readAccessExternalIDs": [],
16 | "writeAccessExternalIDs": [
17 | "FDF283F5-B9C3-4B43-9000-EF6A54934D4E",
18 | "ABCDEFAB-CDEF-ABCD-EFAB-CDEF00000050"
19 | ],
20 | "name": "Test",
21 | "posixPermissions": 1,
22 | "httpAccessType": 1
23 | ]
24 |
25 | // MARK: Initialization
26 | func testInit() throws {
27 | let repo = try Repository(json: json)
28 |
29 | XCTAssertEqual(repo.name, "Test")
30 | XCTAssertEqual(repo.httpAccess, Repository.HTTPAccessType.LoggedIn)
31 | XCTAssertEqual(repo.sshAccess, Repository.SSHAccessType.LoggedInReadSelectedWrite)
32 | XCTAssertEqual(repo.writeAccessExternalIds, [ "FDF283F5-B9C3-4B43-9000-EF6A54934D4E", "ABCDEFAB-CDEF-ABCD-EFAB-CDEF00000050" ])
33 | XCTAssertEqual(repo.readAccessExternalIds, [])
34 | }
35 |
36 | func testManualInit() {
37 | let repo = Repository(name: "Test", httpAccess: .LoggedIn, sshAccess: .LoggedInReadSelectedWrite, writeAccessExternalIds: [ "FDF283F5-B9C3-4B43-9000-EF6A54934D4E", "ABCDEFAB-CDEF-ABCD-EFAB-CDEF00000050" ], readAccessExternalIds: [])
38 |
39 | XCTAssertEqual(repo.name, "Test")
40 | XCTAssertEqual(repo.httpAccess, Repository.HTTPAccessType.LoggedIn)
41 | XCTAssertEqual(repo.sshAccess, Repository.SSHAccessType.LoggedInReadSelectedWrite)
42 | XCTAssertEqual(repo.writeAccessExternalIds, [ "FDF283F5-B9C3-4B43-9000-EF6A54934D4E", "ABCDEFAB-CDEF-ABCD-EFAB-CDEF00000050" ])
43 | XCTAssertEqual(repo.readAccessExternalIds, [])
44 | }
45 |
46 | func testConvenienceInit() {
47 | let repo = Repository(name: "Test")
48 |
49 | XCTAssertEqual(repo.name, "Test")
50 | XCTAssertEqual(repo.httpAccess, Repository.HTTPAccessType.None)
51 | XCTAssertEqual(repo.sshAccess, Repository.SSHAccessType.LoggedInReadWrite)
52 | XCTAssertEqual(repo.writeAccessExternalIds, [])
53 | XCTAssertEqual(repo.readAccessExternalIds, [])
54 | }
55 |
56 | // MARK: JSONifying
57 | func testDictionarify() {
58 | let repo = Repository(name: "Test", httpAccess: .LoggedIn, sshAccess: .LoggedInReadSelectedWrite, writeAccessExternalIds: [ "FDF283F5-B9C3-4B43-9000-EF6A54934D4E", "ABCDEFAB-CDEF-ABCD-EFAB-CDEF00000050" ], readAccessExternalIds: [])
59 |
60 | XCTAssertEqual(repo.dictionarify(), json)
61 | }
62 |
63 | // MARK: Enum tests
64 | func testHTTPEnum() {
65 | var httpEnum = Repository.HTTPAccessType.None
66 | XCTAssertEqual(httpEnum.toString(), "No users are not allowed to read or write")
67 |
68 | httpEnum = .LoggedIn
69 | XCTAssertEqual(httpEnum.toString(), "Logged in users are allowed to read and write")
70 | }
71 |
72 | func testSSHEnum() {
73 | var sshEnum = Repository.SSHAccessType.SelectedReadWrite
74 | XCTAssertEqual(sshEnum.toString(), "Only selected users can read and/or write")
75 |
76 | sshEnum = .LoggedInReadSelectedWrite
77 | XCTAssertEqual(sshEnum.toString(), "Only selected users can write but all logged in can read")
78 |
79 | sshEnum = .LoggedInReadWrite
80 | XCTAssertEqual(sshEnum.toString(), "All logged in users can read and write")
81 | }
82 |
83 | // MARK: API Routes tests
84 | func testGetRepositories() {
85 | let expectation = self.expectationWithDescription("Get Repositories")
86 | let server = self.getRecordingXcodeServer("get_repositories")
87 |
88 | server.getRepositories() { (repositories, error) in
89 | XCTAssertNil(error, "Error should be nil")
90 | XCTAssertNotNil(repositories, "Repositories shouldn't be nil")
91 |
92 | if let repos = repositories {
93 | XCTAssertEqual(repos.count, 2, "There should be two repositories available")
94 |
95 | let reposNames = Set(repos.map { $0.name })
96 | let reposSSHAccess = Set(repos.map { $0.sshAccess.rawValue })
97 | let writeAccessExternalIDs = Set(repos.flatMap { $0.writeAccessExternalIds })
98 |
99 | for (index, _) in repos.enumerate() {
100 | XCTAssertTrue(reposNames.contains("Test\(index + 1)"))
101 | XCTAssertTrue(reposSSHAccess.elementsEqual(Set([2, 0])))
102 | XCTAssertTrue(writeAccessExternalIDs.elementsEqual(Set([ "ABCDEFAB-CDEF-ABCD-EFAB-CDEF00000050", "D024C308-CEBE-4E72-BE40-E1E4115F38F9" ])))
103 | }
104 | }
105 |
106 | expectation.fulfill()
107 | }
108 |
109 | self.waitForExpectationsWithTimeout(10.0, handler: nil)
110 | }
111 |
112 | }
113 |
--------------------------------------------------------------------------------
/XcodeServerSDKTests/TestUtils.swift:
--------------------------------------------------------------------------------
1 | //
2 | // TestUtils.swift
3 | // XcodeServerSDK
4 | //
5 | // Created by Honza Dvorsky on 17/06/15.
6 | // Copyright (c) 2015 Honza Dvorsky. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import XCTest
11 | import XcodeServerSDK
12 | import DVR
13 |
14 | struct StringError: ErrorType {
15 |
16 | let description: String
17 | let _domain: String = ""
18 | let _code: Int = 0
19 |
20 | init(_ description: String) {
21 | self.description = description
22 | }
23 | }
24 |
25 | extension XCTestCase {
26 |
27 | func getRecordingXcodeServer(cassetteName: String) -> XcodeServer {
28 |
29 | let config = try! XcodeServerConfig(
30 | host: "https://127.0.0.1",
31 | user: "ICanCreateBots",
32 | password: "superSecr3t")
33 | return self.getRecordingXcodeServerWithConfig(config, cassetteName: cassetteName)
34 | }
35 |
36 | func getRecordingXcodeServerWithConfig(config: XcodeServerConfig, cassetteName: String) -> XcodeServer
37 | {
38 | let server = XcodeServerFactory.server(config)
39 | let backingSession = server.http.session
40 |
41 | let session = DVR.Session(cassetteName: cassetteName, testBundle: NSBundle(forClass: self.classForCoder), backingSession: backingSession)
42 | server.http.session = session
43 |
44 | return server
45 | }
46 | }
47 |
48 | // MARK: Mock JSON helper methods
49 | extension XCTestCase {
50 |
51 | func stringAtPath(path: String) -> String {
52 | return try! NSString(contentsOfFile: (path as NSString).stringByExpandingTildeInPath, encoding: NSUTF8StringEncoding) as String
53 | }
54 |
55 | func loadJSONResponseFromCassetteWithName(name: String) -> NSDictionary {
56 |
57 | let dictionary = self.loadJSONWithName(name)
58 |
59 | let interactions = dictionary["interactions"] as! [NSDictionary]
60 | let response = interactions.first!["response"] as! NSDictionary
61 |
62 | //make sure it's json
63 | assert(response["body_format"] as! String == "json")
64 |
65 | //get the response data out
66 | let body = response["body"] as! NSDictionary
67 | return body
68 | }
69 |
70 | func loadJSONWithName(name: String) -> NSDictionary {
71 |
72 | let bundle = NSBundle(forClass: BotParsingTests.classForCoder())
73 | do {
74 |
75 | if let url = bundle.URLForResource(name, withExtension: "json") {
76 |
77 | let data = try NSData(contentsOfURL: url, options: NSDataReadingOptions())
78 | if let json = try NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions()) as? NSDictionary {
79 | return json
80 | }
81 |
82 | } else {
83 | throw StringError("File with name \(name) not found in the bundle")
84 | }
85 |
86 | } catch {
87 | XCTFail("Error reading file with name \(name), error: \(error)")
88 | }
89 | return NSDictionary()
90 | }
91 |
92 | func botInCassetteWithName(name: String) throws -> Bot {
93 | let json = self.loadJSONResponseFromCassetteWithName(name)
94 | let bot = try Bot(json: json)
95 | return bot
96 | }
97 |
98 | func botInFileWithName(name: String) throws -> Bot {
99 | let json = self.loadJSONWithName(name)
100 | let bot = try Bot(json: json)
101 | return bot
102 | }
103 |
104 | func configurationFromBotWithName(name: String) throws -> BotConfiguration {
105 | let bot = try self.botInFileWithName(name)
106 | let configuration = bot.configuration
107 | return configuration
108 | }
109 | }
110 |
111 | // MARK: Exception assertions
112 | // Based on: https://forums.developer.apple.com/thread/5824
113 | extension XCTestCase {
114 | /**
115 | Replacement method for XCTAssertThrowsError which isn't currently supported.
116 |
117 | - parameter message: Message which should be displayed
118 | - parameter file: File in which assertion happened
119 | - parameter line: Line in which assertion happened
120 | - parameter block: Block of code against which assertion should be matched
121 | */
122 | func XCTempAssertThrowsError(message: String = "", file: StaticString = #file, line: UInt = #line, _ block: () throws -> ()) {
123 | do {
124 | try block()
125 |
126 | let msg = (message == "") ? "Tested block did not throw error as expected." : message
127 | XCTFail(msg, file: file, line: line)
128 | } catch {}
129 | }
130 |
131 | /**
132 | Replacement method for XCTAssertThrowsSpecificError which isn't currently supported.
133 |
134 | - parameter kind: ErrorType which is expected to be thrown from block
135 | - parameter message: Message which should be displayed
136 | - parameter file: File in which assertion happened
137 | - parameter line: Line in which assertion happened
138 | - parameter block: Block of code against which assertion should be matched
139 | */
140 | func XCTempAssertThrowsSpecificError(kind: ErrorType, _ message: String = "", file: StaticString = #file, line: UInt = #line, _ block: () throws -> ()) {
141 | do {
142 | try block()
143 |
144 | let msg = (message == "") ? "Tested block did not throw expected \(kind) error." : message
145 | XCTFail(msg, file: file, line: line)
146 | } catch let error as NSError {
147 | let expected = kind as NSError
148 | if ((error.domain != expected.domain) || (error.code != expected.code)) {
149 | let msg = (message == "") ? "Tested block threw \(error), not expected \(kind) error." : message
150 | XCTFail(msg, file: file, line: line)
151 | }
152 | }
153 | }
154 |
155 | /**
156 | Replacement method for XCTAssertNoThrowsError which isn't currently supported.
157 |
158 | - parameter message: Message which should be displayed
159 | - parameter file: File in which assertion happened
160 | - parameter line: Line in which assertion happened
161 | - parameter block: Block of code against which assertion should be matched
162 | */
163 | func XCTempAssertNoThrowError(message: String = "", file: StaticString = #file, line: UInt = #line, _ block: () throws -> ()) {
164 | do {
165 | try block()
166 | } catch {
167 | let msg = (message == "") ? "Tested block threw unexpected error." : message
168 | XCTFail(msg, file: file, line: line)
169 | }
170 | }
171 |
172 | /**
173 | Replacement method for XCTAssertNoThrowsSpecificError which isn't currently supported.
174 |
175 | - parameter kind: ErrorType which isn't expected to be thrown from block
176 | - parameter message: Message which should be displayed
177 | - parameter file: File in which assertion happened
178 | - parameter line: Line in which assertion happened
179 | - parameter block: Block of code against which assertion should be matched
180 | */
181 | func XCTempAssertNoThrowSpecificError(kind: ErrorType, _ message: String = "", file: StaticString = #file, line: UInt = #line, _ block: () throws -> ()) {
182 | do {
183 | try block()
184 | } catch let error as NSError {
185 | let unwanted = kind as NSError
186 | if ((error.domain == unwanted.domain) && (error.code == unwanted.code)) {
187 | let msg = (message == "") ? "Tested block threw unexpected \(kind) error." : message
188 | XCTFail(msg, file: file, line: line)
189 | }
190 | }
191 | }
192 | }
--------------------------------------------------------------------------------
/XcodeServerSDKTests/ToolchainTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ToolchainTests.swift
3 | // XcodeServerSDK
4 | //
5 | // Created by Laurent Gaches on 21/04/16.
6 | // Copyright © 2016 Laurent Gaches. All rights reserved.
7 | //
8 |
9 | import XCTest
10 | import XcodeServerSDK
11 |
12 | class ToolchainTest: XCTestCase {
13 |
14 | func testGetToolchains() {
15 | let expectation = self.expectationWithDescription("Get Toolchains")
16 | let server = self.getRecordingXcodeServer("get_toolchains")
17 |
18 | server.getToolchains { (toolchains, error) -> () in
19 | XCTAssertNil(error)
20 | XCTAssertNotNil(toolchains)
21 |
22 | if let toolchains = toolchains {
23 | XCTAssertEqual(toolchains.count, 2, "There should be 2 toolchains")
24 |
25 | let displayNames = toolchains.map { $0.displayName }
26 | XCTAssertTrue(displayNames.contains("Xcode Swift 2.2.1 Snapshot 2016-04-12 (a)"))
27 | XCTAssertTrue(displayNames.contains("Xcode Swift DEVELOPMENT Snapshot 2016-04-12 (a)"))
28 |
29 | }
30 |
31 | expectation.fulfill()
32 | }
33 |
34 | self.waitForExpectationsWithTimeout(10.0, handler: nil)
35 | }
36 | }
--------------------------------------------------------------------------------
/XcodeServerSDKTests/XcodeServerConfigTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // XcodeServerConfigTests.swift
3 | // XcodeServerSDK
4 | //
5 | // Created by Mateusz Zając on 20/06/15.
6 | // Copyright © 2015 Honza Dvorsky. All rights reserved.
7 | //
8 |
9 | import XCTest
10 | import XcodeServerSDK
11 |
12 | class XcodeServerConfigTests: XCTestCase {
13 |
14 | // MARK: Initialization testing
15 | func testManualInit() {
16 | XCTempAssertNoThrowError("Failed to initialize the server configuration") {
17 | let config = try XcodeServerConfig(host: "127.0.0.1", user: "ICanCreateBots", password: "superSecr3t")
18 |
19 | XCTAssertEqual(config.host, "https://127.0.0.1", "Should create proper host address")
20 | XCTAssertEqual(config.user!, "ICanCreateBots")
21 | XCTAssertEqual(config.password!, "superSecr3t")
22 | }
23 | }
24 |
25 | func testInvalidHostProvidingForManualInit() {
26 | XCTempAssertThrowsSpecificError(ConfigurationErrors.InvalidHostProvided("Invalid host name provided, please double check your host name")) {
27 | _ = try XcodeServerConfig(host: "<>127.0.0.1", user: "ICanCreateBots", password: "superSecr3t")
28 | }
29 | }
30 |
31 | func testDictionaryInit() {
32 | XCTempAssertNoThrowError("Failed to initialize the server configuration") {
33 | let json = [
34 | "host": "https://127.0.0.1",
35 | "user": "ICanCreateBots",
36 | "password": "superSecr3t"
37 | ]
38 |
39 | let config = try XcodeServerConfig(json: json)
40 |
41 | XCTAssertEqual(config.host, "https://127.0.0.1", "Should create proper host address")
42 | XCTAssertEqual(config.user!, "ICanCreateBots")
43 | XCTAssertEqual(config.password!, "superSecr3t")
44 | }
45 | }
46 |
47 | func testInvalidDictionaryInit() {
48 | let json = [
49 | "user": "ICanCreateBots",
50 | "password": "superSecr3t"
51 | ]
52 |
53 | XCTempAssertThrowsSpecificError(ConfigurationErrors.NoHostProvided) {
54 | _ = try XcodeServerConfig(json: json)
55 | }
56 | }
57 |
58 | func testInvalidSchemeProvided() {
59 | XCTempAssertThrowsSpecificError(ConfigurationErrors.InvalidSchemeProvided("Xcode Server generally uses https, please double check your hostname")) {
60 | _ = try XcodeServerConfig(host: "http://127.0.0.1")
61 | }
62 | }
63 |
64 | // MARK: Returning JSON
65 | func testJsonify() {
66 | XCTempAssertNoThrowError("Failed to initialize the server configuration") {
67 | let config = try XcodeServerConfig(host: "127.0.0.1", user: "ICanCreateBots", password: "superSecr3t", id: "12345")
68 | let expected = [
69 | "host": "https://127.0.0.1",
70 | "user": "ICanCreateBots",
71 | "id": "12345"
72 | ]
73 |
74 | XCTAssertEqual(config.jsonify(), expected)
75 | }
76 | }
77 |
78 | //just to have a perf test
79 | func testPerformance() {
80 | self.measureBlock { () -> Void in
81 | _ = try! XcodeServerConfig(host: "127.0.0.1", user: "ICanCreateBots", password: "superSecr3t")
82 | }
83 | }
84 |
85 | }
86 |
--------------------------------------------------------------------------------
/XcodeServerSDKTests/XcodeServerEntityTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // XcodeServerEntityTests.swift
3 | // XcodeServerSDK
4 | //
5 | // Created by Mateusz Zając on 20/06/15.
6 | // Copyright © 2015 Honza Dvorsky. All rights reserved.
7 | //
8 |
9 | import XCTest
10 | import XcodeServerSDK
11 |
12 | class XcodeServerEntityTests: XCTestCase {
13 |
14 | // MARK: No arguments init
15 | func testInit() {
16 | let defaultEntity = XcodeServerEntity()
17 |
18 | XCTAssertNil(defaultEntity.id, "ID should be nil")
19 | XCTAssertNil(defaultEntity.rev, "Rev should be nil")
20 | XCTAssertNil(defaultEntity.tinyID, "Tiny ID should be nil")
21 | }
22 |
23 | func testDictionarify() {
24 | // let defaultEntity = XcodeServerEntity()
25 |
26 | // Unable to test assertions in Swift...
27 | // XCTAssertNotNil(defaultEntity.dictionarify(), "Should return empty NSDictionary")
28 | }
29 |
30 | }
31 |
--------------------------------------------------------------------------------
/XcodeServerSDKTests/XcodeServerTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // XcodeServerTests.swift
3 | // XcodeServerSDKTests
4 | //
5 | // Created by Honza Dvorsky on 11/06/2015.
6 | // Copyright (c) 2015 Honza Dvorsky. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import XCTest
11 | @testable import XcodeServerSDK
12 |
13 | class XcodeServerTests: XCTestCase {
14 |
15 | var server: XcodeServer!
16 |
17 | override func setUp() {
18 | super.setUp()
19 | do {
20 | let config = try XcodeServerConfig(
21 | host: "https://127.0.0.1",
22 | user: "ICanCreateBots",
23 | password: "superSecr3t")
24 | self.server = XcodeServerFactory.server(config)
25 | } catch {
26 | XCTFail("Failed to initialize the server configuration: \(error)")
27 | }
28 | }
29 |
30 | func testServerCreation() {
31 | XCTAssertNotNil(self.server)
32 | }
33 |
34 | // MARK: Creadentials tests
35 |
36 | func testCredentials() {
37 | let user = server.credential?.user
38 | let pass = server.credential?.password
39 |
40 | XCTAssertEqual(user!, "ICanCreateBots")
41 | XCTAssertEqual(pass!, "superSecr3t")
42 | }
43 |
44 | func testNoUserCredentials() {
45 | let noUserConfig = try! XcodeServerConfig(host: "https://127.0.0.1")
46 | let server = XcodeServerFactory.server(noUserConfig)
47 |
48 | XCTAssertNil(server.credential)
49 | }
50 |
51 | func DEV_testLiveUpdates() {
52 |
53 | let exp = self.expectationWithDescription("Network")
54 | let stopHandler = self.server.startListeningForLiveUpdates({ (messages: [LiveUpdateMessage]) -> () in
55 | print(messages)
56 | })
57 |
58 | let delayTime = dispatch_time(DISPATCH_TIME_NOW, Int64(5000 * Double(NSEC_PER_SEC)))
59 | dispatch_after(delayTime, dispatch_get_main_queue(), { () -> Void in
60 | print("stopping")
61 | stopHandler()
62 | exp.fulfill()
63 | })
64 | self.waitForExpectationsWithTimeout(1000) { (_) -> Void in
65 | stopHandler()
66 | }
67 | }
68 |
69 | func DEV_testLive_GetBots() {
70 |
71 | let exp = self.expectationWithDescription("Network")
72 | self.server.getBots { (bots, error) in
73 | exp.fulfill()
74 | }
75 | self.waitForExpectationsWithTimeout(10, handler: nil)
76 | }
77 |
78 | func DEV_testLive_FetchAndRecordBot() {
79 |
80 | let exp = self.expectationWithDescription("Network")
81 | let server = self.getRecordingXcodeServer("test_bot")
82 |
83 | server.getBots { (bots, error) in
84 | exp.fulfill()
85 | }
86 |
87 | self.waitForExpectationsWithTimeout(10, handler: nil)
88 | }
89 |
90 | func DEV_testLive_BotCreation() {
91 |
92 | let exp = self.expectationWithDescription("wait")
93 |
94 | let privateKey = self.stringAtPath("~/.ssh/id_rsa")
95 | let publicKey = self.stringAtPath("~/.ssh/id_rsa.pub")
96 |
97 | let blueprint = SourceControlBlueprint(branch: "swift-2", projectWCCIdentifier: "A36AEFA3F9FF1F738E92F0C497C14977DCE02B97", wCCName: "XcodeServerSDK", projectName: "XcodeServerSDK", projectURL: "git@github.com:czechboy0/XcodeServerSDK.git", projectPath: "XcodeServerSDK.xcworkspace", publicSSHKey: publicKey, privateSSHKey: privateKey, sshPassphrase: nil, certificateFingerprint: nil)
98 |
99 | let scriptBody = "cd XcodeServerSDK; /usr/local/bin/carthage update --no-build"
100 | let scriptTrigger = Trigger(config: TriggerConfig(phase: .Prebuild, kind: .RunScript, scriptBody: scriptBody, name: "Carthage", conditions: nil, emailConfiguration: nil)!)
101 |
102 | let devices = [
103 | "a85553a5b26a7c1a4998f3b237005ac7",
104 | "a85553a5b26a7c1a4998f3b237004afd"
105 | ]
106 | let deviceSpec = DeviceSpecification.iOS(.SelectedDevicesAndSimulators, deviceIdentifiers: devices)
107 | let config = BotConfiguration(builtFromClean: BotConfiguration.CleaningPolicy.Once_a_Day, codeCoveragePreference: .UseSchemeSetting, buildConfiguration: .UseSchemeSetting, analyze: true, test: true, archive: true, exportsProductFromArchive: true, schemeName: "XcodeServerSDK - iOS", schedule: BotSchedule.commitBotSchedule(), triggers: [scriptTrigger], deviceSpecification: deviceSpec, sourceControlBlueprint: blueprint)
108 |
109 | let bot = Bot(name: "TestBot From XcodeServerSDK", configuration: config)
110 |
111 | self.server.createBot(bot) { (response) -> () in
112 |
113 | print("")
114 | switch response {
115 | case .Success(let newBot):
116 |
117 | self.server.postIntegration(newBot.id) { (integration, error) -> () in
118 |
119 | print("")
120 | exp.fulfill()
121 | }
122 |
123 | default: break
124 | }
125 | }
126 |
127 | self.waitForExpectationsWithTimeout(1000, handler: nil)
128 | }
129 | }
130 |
131 |
132 |
133 |
134 |
--------------------------------------------------------------------------------
/fastlane/Fastfile:
--------------------------------------------------------------------------------
1 | # Customise this file, documentation can be found here:
2 | # https://github.com/KrauseFx/fastlane/tree/master/docs
3 | # All available actions: https://github.com/KrauseFx/fastlane/blob/master/docs/Actions.md
4 | # can also be listed using the `fastlane actions` command
5 |
6 | # If you want to automatically update fastlane if a new version is available:
7 | update_fastlane
8 |
9 | # This is the minimum version number required.
10 | # Update this, if you use features of a newer version
11 | fastlane_version "1.24.0"
12 |
13 | # -----------
14 |
15 | def project_name
16 | "XcodeServerSDK"
17 | end
18 |
19 | def project_github_name
20 | "czechboy0/#{project_name}"
21 | end
22 |
23 | def release_branch
24 | "master"
25 | end
26 |
27 | # -----------
28 |
29 | lane :prebuild do
30 | cocoapods
31 | end
32 |
33 | lane :release do
34 |
35 | # prep the local state
36 | ensure_git_status_clean
37 | ensure_git_branch(branch: release_branch)
38 | git_pull
39 |
40 | # lint podspec first
41 | sh "cd .. && pod lib lint"
42 |
43 | # regen the changelog and open it
44 | sh "cd .. && github_changelog_generator -t $GITHUB_TOKEN && subl CHANGELOG.md"
45 |
46 | # assume version from the podspec
47 | version = read_podspec['source']['tag']
48 |
49 | # ask for info
50 | title = prompt(text: 'Release Title: ')
51 | description = prompt(text: "Release changelog: ",
52 | multi_line_end_keyword: "END")
53 |
54 | # create a new release on GitHub
55 | repo_url = project_github_name
56 | ENV["FL_GITHUB_RELEASE_API_TOKEN"] = ENV["GITHUB_TOKEN"]
57 | release = set_github_release(
58 | repository_name: repo_url,
59 | commitish: release_branch,
60 | name: [version, title].join(" - "),
61 | tag_name: version,
62 | description: description,
63 | is_draft: false,
64 | is_prerelease: false
65 | )
66 |
67 | # release podspec to cocoapods
68 | sh "cd .. && pod trunk push"
69 |
70 | # notify us on slack
71 | # slack(
72 | # slack_url: ENV['SLACK_RELEASES_URL'],
73 | # message: "Successfully released [#{project_name} #{version}](#{release['html_url']}) :rocket:",
74 | # payload: {
75 | # "New" => release['body']
76 | # }
77 | # )
78 |
79 | # regenerate changelog to get it committed
80 | sh "cd .. && github_changelog_generator -t $GITHUB_TOKEN"
81 | sh "cd .. && git commit -am \"changelog\" && git push"
82 |
83 | end
84 |
85 |
--------------------------------------------------------------------------------
/fastlane/README.md:
--------------------------------------------------------------------------------
1 | fastlane documentation
2 | ================
3 | # Installation
4 | ```
5 | sudo gem install fastlane
6 | ```
7 | # Available Actions
8 | ### prebuild
9 | ```
10 | fastlane prebuild
11 | ```
12 |
13 | ### release
14 | ```
15 | fastlane release
16 | ```
17 |
18 |
19 | ----
20 |
21 | This README.md is auto-generated and will be re-generated every time [fastlane](https://fastlane.tools) is run.
22 | More information about fastlane can be found on [https://fastlane.tools](https://fastlane.tools).
23 | The documentation of fastlane can be found on [GitHub](https://github.com/fastlane/fastlane/tree/master/fastlane).
--------------------------------------------------------------------------------