-
Notifications
You must be signed in to change notification settings - Fork 19
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
25 changed files
with
782 additions
and
8 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
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
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
14 changes: 14 additions & 0 deletions
14
TophatExtensions/TophatBitriseExtension/API/ArtifactListElementResponseModel.swift
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,14 @@ | ||
// | ||
// ArtifactListElementResponseModel.swift | ||
// Tophat | ||
// | ||
// Created by Lukas Romsicki on 2024-11-28. | ||
// Copyright © 2024 Shopify. All rights reserved. | ||
// | ||
|
||
import Foundation | ||
|
||
struct ArtifactListElementResponseModel: Codable { | ||
var slug: String | ||
var title: String | ||
} |
13 changes: 13 additions & 0 deletions
13
TophatExtensions/TophatBitriseExtension/API/ArtifactListResponseModel.swift
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,13 @@ | ||
// | ||
// ArtifactListResponseModel.swift | ||
// Tophat | ||
// | ||
// Created by Lukas Romsicki on 2024-11-28. | ||
// Copyright © 2024 Shopify. All rights reserved. | ||
// | ||
|
||
import Foundation | ||
|
||
struct ArtifactListResponseModel: Codable { | ||
var data: [ArtifactListElementResponseModel] | ||
} |
29 changes: 29 additions & 0 deletions
29
TophatExtensions/TophatBitriseExtension/API/ArtifactResponseItemModel.swift
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,29 @@ | ||
// | ||
// ArtifactResponseItemModel.swift | ||
// Tophat | ||
// | ||
// Created by Lukas Romsicki on 2024-11-28. | ||
// Copyright © 2024 Shopify. All rights reserved. | ||
// | ||
|
||
import Foundation | ||
|
||
struct ArtifactResponseItemModel: Codable { | ||
var artifactType: String | ||
var expiringDownloadURL: URL | ||
var fileSizeBytes: Int | ||
var isPublicPageEnabled: Bool | ||
var publicInstallPageURL: String | ||
var slug: String | ||
var title: String | ||
|
||
enum CodingKeys: String, CodingKey { | ||
case artifactType = "artifact_type" | ||
case expiringDownloadURL = "expiring_download_url" | ||
case fileSizeBytes = "file_size_bytes" | ||
case isPublicPageEnabled = "is_public_page_enabled" | ||
case publicInstallPageURL = "public_install_page_url" | ||
case slug | ||
case title | ||
} | ||
} |
13 changes: 13 additions & 0 deletions
13
TophatExtensions/TophatBitriseExtension/API/ArtifactShowResponseModel.swift
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,13 @@ | ||
// | ||
// ArtifactShowResponseModel.swift | ||
// Tophat | ||
// | ||
// Created by Lukas Romsicki on 2024-11-28. | ||
// Copyright © 2024 Shopify. All rights reserved. | ||
// | ||
|
||
import Foundation | ||
|
||
struct ArtifactShowResponseModel: Codable { | ||
var data: ArtifactResponseItemModel | ||
} |
13 changes: 13 additions & 0 deletions
13
TophatExtensions/TophatBitriseExtension/API/BuildListResponseModel.swift
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,13 @@ | ||
// | ||
// BuildListResponseModel.swift | ||
// Tophat | ||
// | ||
// Created by Lukas Romsicki on 2024-11-28. | ||
// Copyright © 2024 Shopify. All rights reserved. | ||
// | ||
|
||
import Foundation | ||
|
||
struct BuildListResponseModel: Codable { | ||
var data: [BuildResponseItemModel] | ||
} |
13 changes: 13 additions & 0 deletions
13
TophatExtensions/TophatBitriseExtension/API/BuildResponseItemModel.swift
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,13 @@ | ||
// | ||
// BuildResponseItemModel.swift | ||
// Tophat | ||
// | ||
// Created by Lukas Romsicki on 2024-11-28. | ||
// Copyright © 2024 Shopify. All rights reserved. | ||
// | ||
|
||
import Foundation | ||
|
||
struct BuildResponseItemModel: Codable { | ||
var slug: String | ||
} |
36 changes: 36 additions & 0 deletions
36
TophatExtensions/TophatBitriseExtension/Artifact Providers/ArtifactProvider+Bitrise.swift
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,36 @@ | ||
// | ||
// ArtifactProvider+ValidateBitriseResponse.swift | ||
// Tophat | ||
// | ||
// Created by Lukas Romsicki on 2024-11-28. | ||
// Copyright © 2024 Shopify. All rights reserved. | ||
// | ||
|
||
import Foundation | ||
import TophatKit | ||
|
||
extension ArtifactProvider { | ||
func makeAuthenticatedURLRequest(url: URL, token: String) -> URLRequest { | ||
var request = URLRequest(url: url) | ||
request.setValue(token, forHTTPHeaderField: "Authorization") | ||
request.setValue("application/json", forHTTPHeaderField: "Accept") | ||
return request | ||
} | ||
|
||
func validateBitriseResponse(response: URLResponse) throws { | ||
guard let artifactHTTPResponse = response as? HTTPURLResponse else { | ||
throw BitriseArtifactProviderError.unexpected | ||
} | ||
|
||
guard artifactHTTPResponse.statusCode == 200 else { | ||
switch artifactHTTPResponse.statusCode { | ||
case 401: | ||
throw BitriseArtifactProviderError.unauthorized | ||
case 404: | ||
throw BitriseArtifactProviderError.notFound | ||
default: | ||
throw BitriseArtifactProviderError.unexpected | ||
} | ||
} | ||
} | ||
} |
70 changes: 70 additions & 0 deletions
70
TophatExtensions/TophatBitriseExtension/Artifact Providers/BasicArtifactProvider.swift
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,70 @@ | ||
// | ||
// BasicArtifactProvider.swift | ||
// Tophat | ||
// | ||
// Created by Lukas Romsicki on 2024-11-28. | ||
// Copyright © 2024 Shopify. All rights reserved. | ||
// | ||
|
||
import Foundation | ||
import TophatKit | ||
|
||
struct BasicArtifactProvider: ArtifactProvider { | ||
@SecureStorage(Constants.keychainPersonalAccessTokenKey) var personalAccessToken: String? | ||
|
||
static let id = "bitrise" | ||
static let title: LocalizedStringResource = "Bitrise" | ||
|
||
@Parameter(key: "app_slug", title: "App Slug") | ||
var appSlug: String | ||
|
||
@Parameter(key: "build_slug", title: "Build Slug") | ||
var buildSlug: String | ||
|
||
@Parameter(key: "artifact_slug", title: "Artifact Slug") | ||
var artifactSlug: String | ||
|
||
private var url: URL { | ||
URL(string: "https://api.bitrise.io/v0.1")! | ||
.appending(path: "apps") | ||
.appending(path: appSlug) | ||
.appending(path: "builds") | ||
.appending(path: buildSlug) | ||
.appending(path: "artifacts") | ||
.appending(path: artifactSlug) | ||
} | ||
|
||
func retrieve() async throws -> some ArtifactProviderResult { | ||
guard let personalAccessToken, !personalAccessToken.isEmpty else { | ||
throw BitriseArtifactProviderError.accessTokenNotSet | ||
} | ||
|
||
// Fetch artifact details. | ||
|
||
let artifactRequest = makeAuthenticatedURLRequest(url: url, token: personalAccessToken) | ||
let (artifactResponseData, artifactResponse) = try await URLSession.shared.data(for: artifactRequest) | ||
try validateBitriseResponse(response: artifactResponse) | ||
|
||
let artifactShowResponse = try JSONDecoder().decode(ArtifactShowResponseModel.self, from: artifactResponseData) | ||
|
||
// Download artifact. | ||
|
||
let destinationDirectoryURL: URL = .temporaryDirectory.appending(path: UUID().uuidString) | ||
try FileManager.default.createDirectory(at: destinationDirectoryURL, withIntermediateDirectories: true) | ||
|
||
let (downloadedFileURL, nextResponse) = try await URLSession.shared.download( | ||
from: artifactShowResponse.data.expiringDownloadURL | ||
) | ||
|
||
let destinationURL = destinationDirectoryURL | ||
.appending(component: nextResponse.suggestedFilename ?? downloadedFileURL.lastPathComponent) | ||
|
||
try FileManager.default.moveItem(at: downloadedFileURL, to: destinationURL) | ||
|
||
return .result(localURL: destinationURL) | ||
} | ||
|
||
func cleanUp(localURL: URL) async throws { | ||
try FileManager.default.removeItem(at: localURL) | ||
} | ||
} |
48 changes: 48 additions & 0 deletions
48
...atExtensions/TophatBitriseExtension/Artifact Providers/BitriseArtifactProviderError.swift
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,48 @@ | ||
// | ||
// BitriseArtifactProviderError.swift | ||
// Tophat | ||
// | ||
// Created by Lukas Romsicki on 2024-11-28. | ||
// Copyright © 2024 Shopify. All rights reserved. | ||
// | ||
|
||
import Foundation | ||
|
||
enum BitriseArtifactProviderError: Error { | ||
case accessTokenNotSet | ||
case unauthorized | ||
case notFound | ||
case unexpected | ||
} | ||
|
||
extension BitriseArtifactProviderError: LocalizedError { | ||
var errorDescription: String? { | ||
"Failed to download artifact" | ||
} | ||
|
||
var failureReason: String? { | ||
switch self { | ||
case .accessTokenNotSet: | ||
"A Bitrise personal access token has not been specified." | ||
case .unauthorized: | ||
"The access token used to authenticate with Bitrise is invalid." | ||
case .notFound: | ||
"The requested artifact was not found. It may have expired." | ||
case .unexpected: | ||
"An unexpected error has occurred." | ||
} | ||
} | ||
|
||
var recoverySuggestion: String? { | ||
switch self { | ||
case .accessTokenNotSet: | ||
"Go to Tophat Settings → Extensions → Bitrise to add a token." | ||
case .unauthorized: | ||
"Go to Tophat Settings → Extensions → Bitrise to update the token." | ||
case .notFound: | ||
nil | ||
case .unexpected: | ||
"Try again later." | ||
} | ||
} | ||
} |
Oops, something went wrong.