Skip to content

Commit

Permalink
Merge pull request #176 from czechboy0/hd/xcode_deep_links
Browse files Browse the repository at this point in the history
Deep links into Xcode from GitHub comments
  • Loading branch information
czechboy0 committed Oct 14, 2015
2 parents 00e03c2 + 7f048c5 commit 1fd3edf
Show file tree
Hide file tree
Showing 6 changed files with 98 additions and 49 deletions.
55 changes: 40 additions & 15 deletions BuildaKit/SyncPairResolver.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ public class SyncPairResolver {
commit: String,
issue: Issue?,
bot: Bot,
hostname: String,
integrations: [Integration]) -> SyncPair.Actions {

var integrationsToCancel: [Integration] = []
Expand Down Expand Up @@ -114,12 +115,17 @@ public class SyncPairResolver {
$0.currentStep == .Completed
}

let link = { (integration: Integration) -> String in
SyncPairResolver.linkToServer(hostname, bot: bot, integration: integration)
}

//resolve to a status
let actions = self.resolveCommitStatusFromLatestIntegrations(
commit,
issue: issue,
pending: latestPendingIntegration,
running: runningIntegration,
link: link,
completed: completedIntegrations)

//merge in nested actions
Expand Down Expand Up @@ -186,22 +192,35 @@ public class SyncPairResolver {
return sortedHeadCommitIntegrations
}

class func linkToServer(hostname: String, bot: Bot, integration: Integration) -> String {

//unfortunately, since github doesn't allow non-https links anywhere, we
//must proxy through Satellite (https://github.com/czechboy0/satellite)
//all it does is it redirects to the desired xcbot://... url, which in
//turn opens Xcode on the integration page. all good!

// let link = "xcbot://\(hostname)/botID/\(bot.id)/integrationID/\(integration.id)"
let link = "https://stlt.herokuapp.com/v1/xcs_deeplink/\(hostname)/\(bot.id)/\(integration.id)"
return link
}

func resolveCommitStatusFromLatestIntegrations(
commit: String,
issue: Issue?,
pending: Integration?,
running: Integration?,
link: (Integration) -> String,
completed: Set<Integration>) -> SyncPair.Actions {

let statusWithComment: HDGitHubXCBotSyncer.GitHubStatusAndComment
var integrationsToCancel: [Integration] = []

//if there's any pending integration, we're ["Pending" - Waiting in the queue]
if let _ = pending {
if let pending = pending {

//TODO: show how many builds are ahead in the queue and estimate when it will be
//started and when finished? (there is an average running time on each bot, it should be easy)
let status = HDGitHubXCBotSyncer.createStatusFromState(.Pending, description: "Build waiting in the queue...")
let status = HDGitHubXCBotSyncer.createStatusFromState(.Pending, description: "Build waiting in the queue...", targetUrl: link(pending))
statusWithComment = (status: status, comment: nil)

//also, cancel the running integration, if it's there any
Expand All @@ -216,7 +235,7 @@ public class SyncPairResolver {
//there is a running integration.
//TODO: estimate, based on the average running time of this bot and on the started timestamp, when it will finish. add that to the description.
let currentStepString = running.currentStep.rawValue
let status = HDGitHubXCBotSyncer.createStatusFromState(.Pending, description: "Integration step: \(currentStepString)...")
let status = HDGitHubXCBotSyncer.createStatusFromState(.Pending, description: "Integration step: \(currentStepString)...", targetUrl: link(running))
statusWithComment = (status: status, comment: nil)

} else {
Expand All @@ -225,12 +244,12 @@ public class SyncPairResolver {
if completed.count > 0 {

//we have some completed integrations
statusWithComment = self.resolveStatusFromCompletedIntegrations(completed)
statusWithComment = self.resolveStatusFromCompletedIntegrations(completed, link: link)

} else {
//this shouldn't happen.
Log.error("LOGIC ERROR! This shouldn't happen, there are no completed integrations!")
let status = HDGitHubXCBotSyncer.createStatusFromState(.Error, description: "* UNKNOWN STATE, Builda ERROR *")
let status = HDGitHubXCBotSyncer.createStatusFromState(.Error, description: "* UNKNOWN STATE, Builda ERROR *", targetUrl: nil)
statusWithComment = (status: status, "Builda error, unknown state!")
}
}
Expand All @@ -255,7 +274,9 @@ public class SyncPairResolver {
}

func resolveStatusFromCompletedIntegrations(
integrations: Set<Integration>) -> HDGitHubXCBotSyncer.GitHubStatusAndComment {
integrations: Set<Integration>,
link: (Integration) -> String
) -> HDGitHubXCBotSyncer.GitHubStatusAndComment {

//get integrations sorted by number
let sortedDesc = Array(integrations).sort { $0.number > $1.number }
Expand All @@ -272,9 +293,10 @@ public class SyncPairResolver {
}
}).first {

var lines = HDGitHubXCBotSyncer.baseCommentLinesFromIntegration(passingIntegration)
let linkToIntegration = link(passingIntegration)
var lines = HDGitHubXCBotSyncer.baseCommentLinesFromIntegration(passingIntegration, link: linkToIntegration)

let status = HDGitHubXCBotSyncer.createStatusFromState(.Success, description: "Build passed!")
let status = HDGitHubXCBotSyncer.createStatusFromState(.Success, description: "Build passed!", targetUrl: linkToIntegration)

let summary = passingIntegration.buildResultSummary!
if passingIntegration.result == .Succeeded {
Expand Down Expand Up @@ -302,8 +324,9 @@ public class SyncPairResolver {
$0.result! == Integration.Result.TestFailures
}).first {

var lines = HDGitHubXCBotSyncer.baseCommentLinesFromIntegration(testFailingIntegration)
let status = HDGitHubXCBotSyncer.createStatusFromState(.Failure, description: "Build failed tests!")
let linkToIntegration = link(testFailingIntegration)
var lines = HDGitHubXCBotSyncer.baseCommentLinesFromIntegration(testFailingIntegration, link: linkToIntegration)
let status = HDGitHubXCBotSyncer.createStatusFromState(.Failure, description: "Build failed tests!", targetUrl: linkToIntegration)
let summary = testFailingIntegration.buildResultSummary!
let testFailureCount = summary.testFailureCount
lines.append(resultString + "**Build failed \(testFailureCount) " + "test".pluralizeStringIfNecessary(testFailureCount) + "** out of \(summary.testsCount)")
Expand All @@ -315,9 +338,10 @@ public class SyncPairResolver {
$0.result! != Integration.Result.Canceled
}).first {

var lines = HDGitHubXCBotSyncer.baseCommentLinesFromIntegration(erroredIntegration)
let linkToIntegration = link(erroredIntegration)
var lines = HDGitHubXCBotSyncer.baseCommentLinesFromIntegration(erroredIntegration, link: linkToIntegration)
let errorCount: Int = erroredIntegration.buildResultSummary?.errorCount ?? -1
let status = HDGitHubXCBotSyncer.createStatusFromState(.Error, description: "Build error!")
let status = HDGitHubXCBotSyncer.createStatusFromState(.Error, description: "Build error!", targetUrl: linkToIntegration)
lines.append(resultString + "**\(errorCount) " + "error".pluralizeStringIfNecessary(errorCount) + ", failing state: \(erroredIntegration.result!.rawValue)**")
return self.statusAndCommentFromLines(lines, status: status)
}
Expand All @@ -327,16 +351,17 @@ public class SyncPairResolver {
$0.result! == Integration.Result.Canceled
}).first {

var lines = HDGitHubXCBotSyncer.baseCommentLinesFromIntegration(canceledIntegration)
let status = HDGitHubXCBotSyncer.createStatusFromState(.Error, description: "Build canceled!")
let linkToIntegration = link(canceledIntegration)
var lines = HDGitHubXCBotSyncer.baseCommentLinesFromIntegration(canceledIntegration, link: linkToIntegration)
let status = HDGitHubXCBotSyncer.createStatusFromState(.Error, description: "Build canceled!", targetUrl: linkToIntegration)

//TODO: find out who canceled it and add it to the comment?
lines.append("Build was **manually canceled**.")
return self.statusAndCommentFromLines(lines, status: status)
}

//hmm no idea, if we got all the way here. just leave it with no state.
let status = HDGitHubXCBotSyncer.createStatusFromState(.NoState, description: nil)
let status = HDGitHubXCBotSyncer.createStatusFromState(.NoState, description: nil, targetUrl: nil)
return (status: status, comment: nil)
}
}
35 changes: 22 additions & 13 deletions BuildaKit/SyncPair_Branch_Bot.swift
Original file line number Diff line number Diff line change
Expand Up @@ -42,24 +42,33 @@ public class SyncPair_Branch_Bot: SyncPair {
let headCommit = self.branch.commit.sha
let issue: Issue? = nil //TODO: only pull/create if we're failing

self.getIntegrations(bot, completion: { (integrations, error) -> () in
self.syncer.xcodeServer.getHostname { (hostname, error) -> () in

if let error = error {
completion(error: error)
return
}

let actions = self.resolver.resolveActionsForCommitAndIssueWithBotIntegrations(
headCommit,
issue: issue,
bot: bot,
integrations: integrations)

//in case of branches, we also (optionally) want to add functionality for creating an issue if the branch starts failing and updating with comments the same way we do with PRs.
//also, when the build is finally successful on the branch, the issue will be automatically closed.
//TODO: add this functionality here and add it as another action available from a sync pair

self.performActions(actions, completion: completion)
})
self.getIntegrations(bot, completion: { (integrations, error) -> () in

if let error = error {
completion(error: error)
return
}

let actions = self.resolver.resolveActionsForCommitAndIssueWithBotIntegrations(
headCommit,
issue: issue,
bot: bot,
hostname: hostname!,
integrations: integrations)

//in case of branches, we also (optionally) want to add functionality for creating an issue if the branch starts failing and updating with comments the same way we do with PRs.
//also, when the build is finally successful on the branch, the issue will be automatically closed.
//TODO: add this functionality here and add it as another action available from a sync pair

self.performActions(actions, completion: completion)
})
}
}
}
25 changes: 17 additions & 8 deletions BuildaKit/SyncPair_PR_Bot.swift
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ public class SyncPair_PR_Bot: SyncPair {
let pr = self.pr
let headCommit = pr.head.sha
let issue = pr

self.getIntegrations(bot, completion: { (integrations, error) -> () in

if let error = error {
Expand All @@ -61,19 +61,28 @@ public class SyncPair_PR_Bot: SyncPair {

if isEnabled {

let actions = self.resolver.resolveActionsForCommitAndIssueWithBotIntegrations(
headCommit,
issue: issue,
bot: bot,
integrations: integrations)
self.performActions(actions, completion: completion)
self.syncer.xcodeServer.getHostname { (hostname, error) -> () in

if let error = error {
completion(error: error)
return
}

let actions = self.resolver.resolveActionsForCommitAndIssueWithBotIntegrations(
headCommit,
issue: issue,
bot: bot,
hostname: hostname!,
integrations: integrations)
self.performActions(actions, completion: completion)
}

} else {

//not enabled, make sure the PR reflects that and the instructions are clear
Log.verbose("Bot \(bot.name) is not yet enabled, ignoring...")

let status = HDGitHubXCBotSyncer.createStatusFromState(.Pending, description: "Waiting for \"lttm\" to start testing")
let status = HDGitHubXCBotSyncer.createStatusFromState(.Pending, description: "Waiting for \"lttm\" to start testing", targetUrl: nil)
let notYetEnabled: HDGitHubXCBotSyncer.GitHubStatusAndComment = (status: status, comment: nil)
syncer.updateCommitStatusIfNecessary(notYetEnabled, commit: headCommit, issue: pr, completion: completion)
}
Expand Down
10 changes: 8 additions & 2 deletions BuildaKit/SyncerBotUtils.swift
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,17 @@ extension HDGitHubXCBotSyncer {
}
}

class func baseCommentLinesFromIntegration(integration: Integration) -> [String] {
class func baseCommentLinesFromIntegration(integration: Integration, link: String?) -> [String] {

var lines = [String]()

lines.append("Result of Integration **\(integration.number)**")
var integrationText = "Integration \(integration.number)"
if let link = link {
//linkify
integrationText = "[\(integrationText)](\(link))"
}

lines.append("Result of \(integrationText)")
lines.append("---")

if let duration = self.formattedDurationOfIntegration(integration) {
Expand Down
6 changes: 3 additions & 3 deletions BuildaKit/SyncerGitHubUtils.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,11 @@ import BuildaUtils

extension HDGitHubXCBotSyncer {

class func createStatusFromState(state: Status.State, description: String?) -> Status {
class func createStatusFromState(state: Status.State, description: String?, targetUrl: String?) -> Status {

//TODO: add useful targetUrl and potentially have multiple contexts to show multiple stats on the PR
//TODO: potentially have multiple contexts to show multiple stats on the PR
let context = "Buildasaur"
return Status(state: state, description: description, targetUrl: nil, context: context)
return Status(state: state, description: description, targetUrl: targetUrl, context: context)
}

func updateCommitStatusIfNecessary(
Expand Down
Loading

0 comments on commit 1fd3edf

Please sign in to comment.