-
Notifications
You must be signed in to change notification settings - Fork 63
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Added service: Azure DevOps, ref #44
- Loading branch information
Showing
5 changed files
with
349 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) | ||
} | ||
} | ||
} |
Oops, something went wrong.