@@ -6,21 +6,57 @@ import Foundation
66import Cocoa
77
88import AsyncSwiftGit // @bdewey
9- import OctoKit // /Users/pete/dev/octokit.swift
9+ import OctoKit // nerdishbynature/octokit.swift == main
10+
11+ let createPRs = false
12+
13+ guard CommandLine . arguments. count == 3 else {
14+ print ( " usage: sync.swift <pull-request-title> <branch-name> " )
15+ exit ( 1 )
16+ }
17+ let pullRequestName = CommandLine . arguments [ 1 ] // example: "LOOP-4688 DIY Sync"
18+ let syncBranch = CommandLine . arguments [ 2 ] // example: "ps/LOOP-4688/diy-sync"
19+
20+ enum EnvError : Error {
21+ case missing( String )
22+ }
23+
24+ func getEnv( _ name: String ) throws -> String {
25+ guard let value = ProcessInfo . processInfo. environment [ name] else {
26+ throw EnvError . missing ( name)
27+ }
28+ return value
29+ }
30+
31+ let ghUsername = try getEnv ( " GH_USERNAME " )
32+ let ghToken = try getEnv ( " GH_TOKEN " )
33+ let ghCommitterName = try getEnv ( " GH_COMMITTER_NAME " )
34+ let ghCommitterEmail = try getEnv ( " GH_COMMITTER_EMAIL " )
1035
1136struct Project {
1237 let project : String
1338 let branch : String
39+ let subdir : String
1440
15- init ( _ project: String , _ branch: String ) {
41+ init ( _ project: String , _ branch: String , _ subdir : String = " " ) {
1642 self . project = project
1743 self . branch = branch
44+ self . subdir = subdir
45+ }
46+
47+ var path : String {
48+ if subdir. isEmpty {
49+ return project
50+ } else {
51+ return subdir + " / " + project
52+ }
1853 }
1954}
2055
2156let projects = [
2257 Project ( " Loop " , " dev " ) ,
2358 Project ( " LoopKit " , " dev " ) ,
59+ Project ( " TidepoolService " , " dev " ) ,
2460 Project ( " CGMBLEKit " , " dev " ) ,
2561 Project ( " dexcom-share-client-swift " , " dev " ) ,
2662 Project ( " RileyLinkKit " , " dev " ) ,
@@ -32,49 +68,31 @@ let projects = [
3268 Project ( " NightscoutRemoteCGM " , " dev " ) ,
3369 Project ( " LoopSupport " , " dev " ) ,
3470 Project ( " G7SensorKit " , " main " ) ,
35- Project ( " TidepoolService " , " dev " ) ,
36- Project ( " TidepoolKit " , " dev " ) ,
3771 Project ( " OmniKit " , " main " ) ,
38- Project ( " MinimedKit " , " main " )
72+ Project ( " MinimedKit " , " main " ) ,
73+ Project ( " LibreTransmitter " , " main " )
3974]
4075
4176let fm = FileManager . default
4277let loopkit = URL ( string: " https://github.com/LoopKit " ) !
4378let tidepool = URL ( string: " https://github.com/tidepool-org " ) !
44- let syncBranch = " tidepool-sync "
4579let incomingRemote = " tidepool "
4680
47- enum EnvError : Error {
48- case missing( String )
49- }
50-
51- func getEnv( _ name: String ) throws -> String {
52- guard let value = ProcessInfo . processInfo. environment [ name] else {
53- throw EnvError . missing ( name)
54- }
55- return value
56- }
57-
58- let ghUsername = try getEnv ( " GH_USERNAME " )
59- let ghToken = try getEnv ( " GH_TOKEN " )
60- let ghCommitterName = try getEnv ( " GH_COMMITTER_NAME " )
61- let ghCommitterEmail = try getEnv ( " GH_COMMITTER_EMAIL " )
62-
6381let octokit = Octokit ( TokenConfiguration ( ghToken) )
6482
6583let credentials = Credentials . plaintext ( username: ghUsername, password: ghToken)
6684let signature = try ! Signature ( name: ghCommitterName, email: ghCommitterEmail)
6785
6886for project in projects {
69- let dest = URL ( string: fm. currentDirectoryPath) !. appendingPathComponent ( project. project )
87+ let dest = URL ( string: fm. currentDirectoryPath) !. appendingPathComponent ( project. path )
7088 let repository : AsyncSwiftGit . Repository
71- if !fm. fileExists ( atPath: project . project ) {
89+ if !fm. fileExists ( atPath: dest . path ) {
7290 print ( " Cloning \( project. project) " )
7391 let url = loopkit. appendingPathComponent ( project. project)
7492 repository = try await Repository . clone ( from: url, to: dest)
7593 print ( " Cloned \( project. project) " )
7694 } else {
77- print ( " Already Exists: \( project. project ) " )
95+ print ( " Already Exists: \( project. path ) " )
7896 repository = try Repository ( openAt: dest)
7997 }
8098
@@ -95,11 +113,10 @@ for project in projects {
95113 // Merge changes from tidepool to diy
96114 try await repository. merge ( revisionSpecification: " \( incomingRemote) / \( project. branch) " , signature: signature)
97115
98- let ( ahead, behind) = try repository. commitsAheadBehind ( other: " origin/ \( project. branch) " )
99- print ( " Ahead = \( ahead) " )
100- print ( " Behind = \( behind) " )
116+ let originTree = try repository. lookupTree ( for: " origin/ \( project. branch) " )
117+ let diff = try repository. diff ( originTree, repository. headTree)
101118
102- guard ahead > 0 else {
119+ guard diff . count > 0 else {
103120 print ( " No incoming changes; skipping PR creation. " )
104121 try await repository. checkout ( revspec: project. branch)
105122 continue
@@ -110,55 +127,24 @@ for project in projects {
110127 print ( " Pushing \( refspec) to \( project. project) " )
111128 try await repository. push ( remoteName: " origin " , refspecs: [ refspec] , credentials: credentials)
112129
113- // Make sure a PR exists, or create it
114- let prs = try await octokit. listPullRequests ( owner: " LoopKit " , repo: project. project, base: project. branch, head: " LoopKit:tidepool-sync " )
115- let pr : PullRequest
116- if prs. count == 0 {
117- pr = try await octokit. createPullRequest ( owner: " LoopKit " , repo: project. project, title: " Tidepool Sync " , head: " LoopKit: " + syncBranch, base: project. branch, body: " " )
118- print ( " PR = \( pr) " )
119- } else {
120- pr = prs. first!
121- }
122- if let url = pr. htmlURL {
123- if NSWorkspace . shared. open ( url) {
124- print ( " default browser was successfully opened " )
125-
126- }
127- }
130+ if createPRs {
131+ // Make sure a PR exists, or create it
132+
133+ let prs = try await octokit. pullRequests ( owner: " LoopKit " , repository: project. project, base: project. branch, head: " LoopKit: " + syncBranch)
134+ let pr : PullRequest
135+ if prs. count == 0 {
136+ pr = try await octokit. createPullRequest ( owner: " LoopKit " , repo: project. project, title: pullRequestName, head: " LoopKit: " + syncBranch, base: project. branch, body: " " )
137+ print ( " PR = \( pr) " )
138+ } else {
139+ pr = prs. first!
140+ }
141+ if let url = pr. htmlURL {
142+ if NSWorkspace . shared. open ( url) {
143+ print ( " default browser was successfully opened " )
144+ }
145+ }
146+ } else {
147+ print ( " Skipping PR creation " )
148+ }
128149}
129150
130- extension Octokit {
131- func createPullRequest( owner: String ,
132- repo: String ,
133- title: String ,
134- head: String ,
135- headRepo: String ? = nil ,
136- base: String ,
137- body: String ? = nil ,
138- maintainerCanModify: Bool ? = nil ,
139- draft: Bool ? = nil ) async throws -> PullRequest
140- {
141- return try await withCheckedThrowingContinuation { continuation in
142- octokit. createPullRequest ( owner: owner, repo: repo, title: title, head: head, headRepo: headRepo, base: base, body: body, maintainerCanModify: maintainerCanModify, draft: draft)
143- { response in
144- continuation. resume ( with: response)
145- }
146- }
147- }
148-
149- func listPullRequests( owner: String ,
150- repo: String ,
151- base: String ? = nil ,
152- head: String ? = nil ,
153- state: Openness = . open,
154- sort: SortType = . created,
155- direction: SortDirection = . desc) async throws -> [ PullRequest ]
156- {
157- return try await withCheckedThrowingContinuation { continuation in
158- octokit. pullRequests ( owner: owner, repository: repo, base: base, head: head, state: state, sort: sort, direction: direction)
159- { response in
160- continuation. resume ( with: response)
161- }
162- }
163- }
164- }
0 commit comments