Skip to content

Commit a3f86f1

Browse files
committed
Use release rss to check for update
1 parent 78c5052 commit a3f86f1

File tree

3 files changed

+83
-85
lines changed

3 files changed

+83
-85
lines changed

Copilot for Xcode.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved

Lines changed: 9 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Core/Package.swift

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ let package = Package(
3434
.package(url: "https://github.com/apple/swift-async-algorithms", from: "0.1.0"),
3535
.package(url: "https://github.com/raspu/Highlightr", from: "2.1.0"),
3636
.package(url: "https://github.com/JohnSundell/Splash", from: "0.1.0"),
37+
.package(url: "https://github.com/nmdias/FeedKit", from: "9.1.2"),
3738
],
3839
targets: [
3940
.target(name: "CGEventObserver"),
@@ -116,7 +117,10 @@ let package = Package(
116117
"Splash",
117118
]
118119
),
119-
.target(name: "UpdateChecker", dependencies: ["Logger"]),
120+
.target(
121+
name: "UpdateChecker",
122+
dependencies: ["Logger", .product(name: "FeedKit", package: "FeedKit")]
123+
),
120124
.target(name: "AXExtension"),
121125
.target(name: "Logger"),
122126
]
Lines changed: 69 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,9 @@
11
import AppKit
2+
import FeedKit
23
import Foundation
34
import Logger
45
import SwiftUI
56

6-
struct Release: Codable {
7-
let tag_name: String?
8-
let html_url: String?
9-
let body: String?
10-
let published_at: String?
11-
}
12-
137
let skippedUpdateVersionKey = "skippedUpdateVersion"
148

159
public struct UpdateChecker {
@@ -19,94 +13,85 @@ public struct UpdateChecker {
1913

2014
public init() {}
2115

22-
public func checkForUpdate() async {
23-
let url =
24-
URL(string: "https://api.github.com/repos/intitni/CopilotForXcode/releases/latest")!
25-
do {
26-
var request = URLRequest(url: url)
27-
let token = (Bundle.main.infoDictionary?["GITHUB_TOKEN"] as? String) ?? ""
28-
if !token.isEmpty {
29-
request.setValue("Bearer \(token)", forHTTPHeaderField: "Authorization")
16+
public func checkForUpdate() {
17+
let url = URL(string: "https://github.com/intitni/CopilotForXcode/releases.atom")!
18+
let parser = FeedParser(URL: url)
19+
parser.parseAsync { result in
20+
switch result {
21+
case let .success(.atom(feed)):
22+
if let entry = feed.entries?.first(where: {
23+
guard let title = $0.title else { return false }
24+
return !title.contains("-")
25+
}) {
26+
self.alertIfUpdateAvailable(entry)
27+
}
28+
case let .failure(error):
29+
Logger.updateChecker.error(error)
30+
default: break
3031
}
31-
request.setValue("application/vnd.github+json", forHTTPHeaderField: "Accept")
32-
request.setValue("X-GitHub-Api-Version", forHTTPHeaderField: "2022-11-28")
33-
34-
let (data, _) = try await URLSession.shared.data(for: request)
35-
let decoder = JSONDecoder()
36-
let release = try decoder.decode(Release.self, from: data)
37-
guard let version = release.tag_name,
38-
version != skippedUpdateVersion,
39-
version != Bundle.main
40-
.infoDictionary?["CFBundleShortVersionString"] as? String
41-
else { return }
32+
}
33+
}
4234

43-
Task { @MainActor in
44-
let alert = NSAlert()
45-
alert.messageText = "Copilot for Xcode \(version) is available!"
46-
alert.informativeText = "Would you like to visit the release page?"
47-
let view = NSHostingView(
48-
rootView:
49-
AccessoryView(releaseNote: release.body)
50-
)
51-
view.frame = .init(origin: .zero, size: .init(width: 400, height: 200))
52-
alert.accessoryView = view
35+
func alertIfUpdateAvailable(_ entry: AtomFeedEntry) {
36+
guard let version = entry.title,
37+
let currentVersion = Bundle.main
38+
.infoDictionary?["CFBundleShortVersionString"] as? String,
39+
version != skippedUpdateVersion,
40+
version.compare(currentVersion, options: .numeric) == .orderedDescending
41+
else { return }
5342

54-
alert.addButton(withTitle: "Visit Release Page")
55-
alert.addButton(withTitle: "Skip This Version")
56-
alert.addButton(withTitle: "Cancel")
57-
alert.alertStyle = .informational
58-
let screenFrame = NSScreen.main?.frame ?? .zero
59-
let window = NSWindow(
60-
contentRect: .init(
61-
x: screenFrame.midX,
62-
y: screenFrame.midY,
63-
width: 1,
64-
height: 1
65-
),
66-
styleMask: .borderless,
67-
backing: .buffered,
68-
defer: true
69-
)
70-
window.level = .floating
71-
window.isReleasedWhenClosed = false
72-
alert.beginSheetModal(for: window) { [window] response in
73-
switch response {
74-
case .alertFirstButtonReturn:
75-
if let url = URL(string: release.html_url ?? "") {
76-
NSWorkspace.shared.open(url)
77-
}
78-
case .alertSecondButtonReturn:
79-
UserDefaults.standard.set(version, forKey: skippedUpdateVersionKey)
80-
default:
81-
break
82-
}
83-
window.close()
84-
}
85-
}
86-
} catch {
87-
Logger.updateChecker.error(error)
43+
Task { @MainActor in
44+
let screenFrame = NSScreen.main?.frame ?? .zero
45+
let window = NSWindow(
46+
contentRect: .init(
47+
x: screenFrame.midX,
48+
y: screenFrame.midY + 200,
49+
width: 500,
50+
height: 500
51+
),
52+
styleMask: .borderless,
53+
backing: .buffered,
54+
defer: true
55+
)
56+
window.level = .floating
57+
window.isReleasedWhenClosed = false
58+
window.contentViewController = NSHostingController(
59+
rootView: AlertView(entry: entry, window: window)
60+
)
61+
window.makeKeyAndOrderFront(nil)
8862
}
8963
}
9064
}
9165

92-
struct AccessoryView: View {
93-
let releaseNote: String?
66+
struct AlertView: View {
67+
let entry: AtomFeedEntry
68+
let window: NSWindow
9469

9570
var body: some View {
96-
if let releaseNote {
97-
ScrollView {
98-
Text(releaseNote)
99-
.padding()
100-
101-
Spacer()
71+
let version = entry.title ?? "0.0.0"
72+
Color.clear.alert(
73+
"Copilot for Xcode \(version) is available!",
74+
isPresented: .constant(true)
75+
) {
76+
Button {
77+
if let url = URL(string: entry.links?.first?.attributes?.href ?? "") {
78+
NSWorkspace.shared.open(url)
79+
}
80+
window.close()
81+
} label: {
82+
Text("Visit Release Page")
10283
}
103-
.background(Color(nsColor: .textBackgroundColor))
104-
.overlay {
105-
Rectangle()
106-
.stroke(Color(nsColor: .separatorColor), style: .init(lineWidth: 2))
84+
85+
Button {
86+
UserDefaults.standard.set(version, forKey: skippedUpdateVersionKey)
87+
window.close()
88+
} label: {
89+
Text("Skip This Version")
10790
}
108-
} else {
109-
EmptyView()
91+
92+
Button { window.close() } label: { Text("Cancel") }
93+
} message: {
94+
Text("Would you like to visit the release page?")
11095
}
11196
}
11297
}

0 commit comments

Comments
 (0)