Skip to content

Commit

Permalink
Added service: Azure DevOps, ref #44
Browse files Browse the repository at this point in the history
  • Loading branch information
inket committed Jun 15, 2019
1 parent 54faf1d commit 9e9c0ba
Show file tree
Hide file tree
Showing 5 changed files with 349 additions and 0 deletions.
143 changes: 143 additions & 0 deletions Scripts/generate_azure_devops_services.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
#!/usr/bin/swift

import Foundation

struct AzureDevOpsService {
let serviceName: String

var friendlyName: String {
let friendlyServiceName = serviceName.components(separatedBy: " ").map {
$0.capitalized(firstLetterOnly: true)
}.joined(separator: " ")

return "Azure DevOps \(friendlyServiceName)"
}

var className: String {
var sanitizedName = serviceName
sanitizedName = sanitizedName.replacingOccurrences(of: " & ", with: "And")
sanitizedName = sanitizedName.replacingOccurrences(of: "/", with: "")
sanitizedName = sanitizedName.replacingOccurrences(of: ":", with: "")
sanitizedName = sanitizedName.components(separatedBy: " ").map { $0.capitalized(firstLetterOnly: true) }.joined(separator: "")
return "AzureDevOps\(sanitizedName)"
}

var output: String {
return """
class \(className): AzureDevOps {
let name = "\(friendlyName)"
let serviceName = "\(serviceName)"
}
"""
}
}

extension String {
subscript(_ range: NSRange) -> String {
// Why we still have to do this shit in 2019 I don't know
let start = self.index(self.startIndex, offsetBy: range.lowerBound)
let end = self.index(self.startIndex, offsetBy: range.upperBound)
let subString = self[start..<end]
return String(subString)
}

func capitalized(firstLetterOnly: Bool) -> String {
return firstLetterOnly ? (prefix(1).capitalized + dropFirst()) : self
}
}

struct AzureDevOpsDataProviders: Codable {
struct ResponseData: Codable {
struct MetadataProvider: Codable {
let services: [[String: String]]

var serviceNames: [String] {
return services.compactMap { $0["id"] }
}
}

enum CodingKeys: String, CodingKey {
case metadataProvider = "ms.vss-status-web.public-status-metadata-data-provider"
}

let metadataProvider: MetadataProvider
}

let data: ResponseData
}

func envVariable(forKey key: String) -> String {
guard let variable = ProcessInfo.processInfo.environment[key] else {
print("error: Environment variable '\(key)' not set")
exit(1)
}

return variable
}

func discoverServices() -> [AzureDevOpsService] {
var result = [AzureDevOpsService]()

var dataResult: Data?

let semaphore = DispatchSemaphore(value: 0)
URLSession.shared.dataTask(with: URL(string: "https://status.dev.azure.com")!) { data, _, _ in
dataResult = data
semaphore.signal()
}.resume()

_ = semaphore.wait(timeout: .now() + .seconds(10))

guard let data = dataResult, var body = String(data: data, encoding: .utf8) else {
print("warning: Build script generate_azure_devops_services could not retrieve list of Azure DevOps services")
exit(0)
}

body = body.replacingOccurrences(of: "\n", with: "")

// swiftlint:disable:next force_try
let regex = try! NSRegularExpression(
pattern: "<script id=\"dataProviders\".*?>(.*?)</script>",
options: [.caseInsensitive, .dotMatchesLineSeparators]
)

let range = NSRange(location: 0, length: body.count)
regex.enumerateMatches(in: body, options: [], range: range) { textCheckingResult, _, _ in
guard let textCheckingResult = textCheckingResult, textCheckingResult.numberOfRanges == 2 else { return }

let json = body[textCheckingResult.range(at: 1)]
guard let decodedProviders = try? JSONDecoder().decode(AzureDevOpsDataProviders.self, from: json.data(using: .utf8)!) else {
print("warning: Build script generate_azure_devops_services could not retrieve list of Azure DevOps services")
exit(0)
}

decodedProviders.data.metadataProvider.serviceNames.forEach {
result.append(AzureDevOpsService(serviceName: $0))
}
}

return result
}

func main() {
let srcRoot = envVariable(forKey: "SRCROOT")
let outputPath = "\(srcRoot)/stts/Services/Generated/AzureDevOpsServices.swift"
let services = discoverServices()

let header = """
// This file is generated by generate_azure_devops_services.swift and should not be modified manually.
import Foundation
"""

let content = services.map { $0.output }.joined(separator: "\n\n")
let footer = ""

let output = [header, content, footer].joined(separator: "\n")

// swiftlint:disable:next force_try
try! output.write(toFile: outputPath, atomically: true, encoding: .utf8)
}

main()
14 changes: 14 additions & 0 deletions stts.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,9 @@
B271688A2291AEEE001E608C /* Asana.swift in Sources */ = {isa = PBXBuildFile; fileRef = B27168892291AEEE001E608C /* Asana.swift */; };
B276C8F41DD474200098B451 /* MBPopup.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B276C8F11DD474200098B451 /* MBPopup.framework */; };
B276C8F71DD4742D0098B451 /* MBPopup.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = B276C8F11DD474200098B451 /* MBPopup.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
B277BC9222B4BB5C000B55C3 /* AzureDevOps.swift in Sources */ = {isa = PBXBuildFile; fileRef = B277BC9122B4BB5C000B55C3 /* AzureDevOps.swift */; };
B277BC9422B4BB6D000B55C3 /* AzureDevOpsStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = B277BC9322B4BB6D000B55C3 /* AzureDevOpsStore.swift */; };
B277BC9822B4C16A000B55C3 /* AzureDevOpsServices.swift in Sources */ = {isa = PBXBuildFile; fileRef = B277BC9722B4C16A000B55C3 /* AzureDevOpsServices.swift */; };
B2841CEB20BA6207004AFDB7 /* SorryService.swift in Sources */ = {isa = PBXBuildFile; fileRef = B2841CEA20BA6207004AFDB7 /* SorryService.swift */; };
B2894CE420EEE2780009CCA3 /* Buildkite.swift in Sources */ = {isa = PBXBuildFile; fileRef = B2894CE320EEE2780009CCA3 /* Buildkite.swift */; };
B2898FD01DC7441D0005F58F /* StatusIndicator.swift in Sources */ = {isa = PBXBuildFile; fileRef = B2898FCF1DC7441D0005F58F /* StatusIndicator.swift */; };
Expand Down Expand Up @@ -275,6 +278,10 @@
B27090F0209F52EB0094C3D7 /* Stream.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Stream.swift; sourceTree = "<group>"; };
B27168892291AEEE001E608C /* Asana.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Asana.swift; sourceTree = "<group>"; };
B276C8F11DD474200098B451 /* MBPopup.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MBPopup.framework; path = Carthage/Build/Mac/MBPopup.framework; sourceTree = SOURCE_ROOT; };
B277BC9122B4BB5C000B55C3 /* AzureDevOps.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AzureDevOps.swift; sourceTree = "<group>"; };
B277BC9322B4BB6D000B55C3 /* AzureDevOpsStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AzureDevOpsStore.swift; sourceTree = "<group>"; };
B277BC9522B4BC6C000B55C3 /* generate_azure_devops_services.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = generate_azure_devops_services.swift; sourceTree = "<group>"; };
B277BC9722B4C16A000B55C3 /* AzureDevOpsServices.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AzureDevOpsServices.swift; sourceTree = "<group>"; };
B2841CEA20BA6207004AFDB7 /* SorryService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SorryService.swift; sourceTree = "<group>"; };
B2894CE320EEE2780009CCA3 /* Buildkite.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Buildkite.swift; sourceTree = "<group>"; };
B2898FCF1DC7441D0005F58F /* StatusIndicator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StatusIndicator.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -647,6 +654,7 @@
B2E70FD222B0650A000BCAD2 /* Scripts */ = {
isa = PBXGroup;
children = (
B277BC9522B4BC6C000B55C3 /* generate_azure_devops_services.swift */,
B2CEE5DC22B4A9900073C743 /* generate_azure_services.swift */,
B2E70FD622B066EC000BCAD2 /* generate_google_services.swift */,
B2E70FD322B0657F000BCAD2 /* generate_services_plist.sh */,
Expand All @@ -657,6 +665,7 @@
B2E70FDF22B0844F000BCAD2 /* Generated */ = {
isa = PBXGroup;
children = (
B277BC9722B4C16A000B55C3 /* AzureDevOpsServices.swift */,
B2CEE5DA22B4A97B0073C743 /* AzureServices.swift */,
B2E70FDC22B07FB0000BCAD2 /* FirebaseServices.swift */,
B2E70FD722B069BA000BCAD2 /* GoogleCloudPlatformServices.swift */,
Expand Down Expand Up @@ -699,6 +708,8 @@
isa = PBXGroup;
children = (
B2CEE5D622B49CB50073C743 /* Azure.swift */,
B277BC9122B4BB5C000B55C3 /* AzureDevOps.swift */,
B277BC9322B4BB6D000B55C3 /* AzureDevOpsStore.swift */,
B2CEE5D822B49CC80073C743 /* AzureStore.swift */,
B2BB19B920B8FEFD00A97A87 /* CachetService.swift */,
B2EB51CD1E7004A3001D6F78 /* ExanaService.swift */,
Expand Down Expand Up @@ -977,6 +988,7 @@
B2D2B6CF20870E700011723B /* StatusPage.swift in Sources */,
B28FF68B1E94761A005897A9 /* Codecov.swift in Sources */,
B256955A1E247C8C00FAE413 /* Cloudinary.swift in Sources */,
B277BC9822B4C16A000B55C3 /* AzureDevOpsServices.swift in Sources */,
B2DCE6902215992E001447D8 /* Apple.swift in Sources */,
B2F127A91E0B84B50035B20C /* Twilio.swift in Sources */,
B28E9FC01ED26A40006B89F1 /* Lob.swift in Sources */,
Expand Down Expand Up @@ -1019,6 +1031,7 @@
B299C8451DD046F20024D2E9 /* AmazonWebServices.swift in Sources */,
B256955B1E247C8C00FAE413 /* HipChat.swift in Sources */,
B299C8551DD051210024D2E9 /* EngineYard.swift in Sources */,
B277BC9222B4BB5C000B55C3 /* AzureDevOps.swift in Sources */,
B2C10F3C203646A7008E1E7D /* Gandi.swift in Sources */,
B21308561E55594E009FCF02 /* Quandl.swift in Sources */,
B22600311E1562E700EBDD40 /* MediaTemple.swift in Sources */,
Expand Down Expand Up @@ -1047,6 +1060,7 @@
B20699D2214E504F008670B0 /* Robinhood.swift in Sources */,
B22527F51E5BD0C70098E73D /* Contentful.swift in Sources */,
B24F91231E8B51A400A77460 /* Auth0.swift in Sources */,
B277BC9422B4BB6D000B55C3 /* AzureDevOpsStore.swift in Sources */,
B230CE7D21B95B5D00E2005D /* Wasabi.swift in Sources */,
2F65F490227A198400432E64 /* Recurly.swift in Sources */,
B2F34041222630F20055C96F /* CloudApp.swift in Sources */,
Expand Down
38 changes: 38 additions & 0 deletions stts/Services/Generated/AzureDevOpsServices.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// This file is generated by generate_azure_devops_services.swift and should not be modified manually.

import Foundation

class AzureDevOpsCoreServices: AzureDevOps {
let name = "Azure DevOps Core Services"
let serviceName = "Core services"
}

class AzureDevOpsBoards: AzureDevOps {
let name = "Azure DevOps Boards"
let serviceName = "Boards"
}

class AzureDevOpsRepos: AzureDevOps {
let name = "Azure DevOps Repos"
let serviceName = "Repos"
}

class AzureDevOpsPipelines: AzureDevOps {
let name = "Azure DevOps Pipelines"
let serviceName = "Pipelines"
}

class AzureDevOpsTestPlans: AzureDevOps {
let name = "Azure DevOps Test Plans"
let serviceName = "Test Plans"
}

class AzureDevOpsArtifacts: AzureDevOps {
let name = "Azure DevOps Artifacts"
let serviceName = "Artifacts"
}

class AzureDevOpsOtherServices: AzureDevOps {
let name = "Azure DevOps Other Services"
let serviceName = "Other services"
}
28 changes: 28 additions & 0 deletions stts/Services/Super/AzureDevOps.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
//
// AzureDevOpsDevOps.swift
// stts
//

import Foundation

typealias AzureDevOps = BaseAzureDevOps & RequiredServiceProperties & AzureDevOpsStoreService

class BaseAzureDevOps: BaseService {
private static var store = AzureDevOpsStore()

let url = URL(string: "https://status.dev.azure.com")!

override func updateStatus(callback: @escaping (BaseService) -> Void) {
guard let realSelf = self as? AzureDevOps else { fatalError("BaseAzureDevOps should not be used directly.") }

BaseAzureDevOps.store.loadStatus { [weak realSelf] in
guard let strongSelf = realSelf else { return }

let (status, message) = BaseAzureDevOps.store.status(for: strongSelf)
strongSelf.status = status
strongSelf.message = message

callback(strongSelf)
}
}
}
Loading

0 comments on commit 9e9c0ba

Please sign in to comment.