native macOS codings agent orchestrator
6
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge pull request #140 from supabitapp/revert-repo-settings-global-default

Restore global-by-default repository settings persistence

authored by

khoi and committed by
GitHub
5ec94c88 e63fed1a

+55 -76
+26 -23
supacode/Features/Settings/BusinessLogic/RepositorySettingsKey.swift
··· 33 33 } 34 34 let path = repositorySettingsURL.path(percentEncoded: false) 35 35 SupaLogger("Settings").warning( 36 - "Unable to decode repository settings at \(path); migrating from global settings." 36 + "Unable to decode repository settings at \(path); falling back to global settings." 37 37 ) 38 38 } 39 39 40 40 @Shared(.settingsFile) var settingsFile: SettingsFile 41 - let migratedSettings = $settingsFile.withLock { settings in 42 - settings.repositories[repositoryID] ?? (context.initialValue ?? .default) 41 + let settings = $settingsFile.withLock { settings in 42 + if let existing = settings.repositories[repositoryID] { 43 + return existing 44 + } 45 + let defaults = context.initialValue ?? .default 46 + settings.repositories[repositoryID] = defaults 47 + return defaults 43 48 } 44 - do { 45 - let encoder = JSONEncoder() 46 - encoder.outputFormatting = [.prettyPrinted, .sortedKeys] 47 - let data = try encoder.encode(migratedSettings) 48 - try repositoryLocalSettingsStorage.save(data, repositorySettingsURL) 49 - } catch { 50 - let path = repositorySettingsURL.path(percentEncoded: false) 51 - SupaLogger("Settings").warning( 52 - "Unable to write migrated repository settings to \(path): \(error.localizedDescription)" 53 - ) 54 - } 55 - continuation.resume(returning: migratedSettings) 49 + continuation.resume(returning: settings) 56 50 } 57 51 58 52 func subscribe( ··· 69 63 ) { 70 64 @Dependency(\.repositoryLocalSettingsStorage) var repositoryLocalSettingsStorage 71 65 let repositorySettingsURL = SupacodePaths.repositorySettingsURL(for: rootURL) 72 - do { 73 - let encoder = JSONEncoder() 74 - encoder.outputFormatting = [.prettyPrinted, .sortedKeys] 75 - let data = try encoder.encode(value) 76 - try repositoryLocalSettingsStorage.save(data, repositorySettingsURL) 77 - continuation.resume() 78 - } catch { 79 - continuation.resume(throwing: error) 66 + if (try? repositoryLocalSettingsStorage.load(repositorySettingsURL)) != nil { 67 + do { 68 + let encoder = JSONEncoder() 69 + encoder.outputFormatting = [.prettyPrinted, .sortedKeys] 70 + let data = try encoder.encode(value) 71 + try repositoryLocalSettingsStorage.save(data, repositorySettingsURL) 72 + continuation.resume() 73 + } catch { 74 + continuation.resume(throwing: error) 75 + } 76 + return 80 77 } 78 + 79 + @Shared(.settingsFile) var settingsFile: SettingsFile 80 + $settingsFile.withLock { 81 + $0.repositories[repositoryID] = value 82 + } 83 + continuation.resume() 81 84 } 82 85 } 83 86
+29 -53
supacodeTests/RepositorySettingsKeyTests.swift
··· 14 14 #expect(!json.contains("worktreeBaseRef")) 15 15 } 16 16 17 - @Test(.dependencies) func loadCreatesDefaultAndMigratesToLocal() throws { 18 - let globalStorage = SettingsTestStorage() 19 - let localStorage = RepositoryLocalSettingsTestStorage() 17 + @Test(.dependencies) func loadCreatesDefaultAndPersists() throws { 18 + let storage = SettingsTestStorage() 20 19 let rootURL = URL(fileURLWithPath: "/tmp/repo") 21 - let settingsFileURL = URL(fileURLWithPath: "/tmp/supacode-settings-\(UUID().uuidString).json") 22 - let repositoryID = rootURL.standardizedFileURL.path(percentEncoded: false) 23 - let localURL = SupacodePaths.repositorySettingsURL(for: rootURL) 24 20 25 - let loaded = withDependencies { 26 - $0.settingsFileStorage = globalStorage.storage 27 - $0.settingsFileURL = settingsFileURL 28 - $0.repositoryLocalSettingsStorage = localStorage.storage 21 + let settings = withDependencies { 22 + $0.settingsFileStorage = storage.storage 29 23 } operation: { 30 24 @Shared(.repositorySettings(rootURL)) var repositorySettings: RepositorySettings 31 25 return repositorySettings 32 26 } 33 27 34 - #expect(loaded == .default) 28 + #expect(settings == RepositorySettings.default) 35 29 36 - let localData = try #require(localStorage.data(at: localURL)) 37 - let localDecoded = try JSONDecoder().decode(RepositorySettings.self, from: localData) 38 - #expect(localDecoded == .default) 39 - 40 - let globalSaved: SettingsFile = withDependencies { 41 - $0.settingsFileStorage = globalStorage.storage 42 - $0.settingsFileURL = settingsFileURL 43 - $0.repositoryLocalSettingsStorage = localStorage.storage 30 + let saved: SettingsFile = withDependencies { 31 + $0.settingsFileStorage = storage.storage 44 32 } operation: { 45 - @Shared(.settingsFile) var settingsFile: SettingsFile 46 - return settingsFile 33 + @Shared(.settingsFile) var settings: SettingsFile 34 + return settings 47 35 } 48 36 49 - #expect(globalSaved.repositories[repositoryID] == nil) 37 + #expect( 38 + saved.repositories[rootURL.path(percentEncoded: false)] == RepositorySettings.default 39 + ) 50 40 } 51 41 52 - @Test(.dependencies) func saveOverwritesExistingSettingsInLocalFile() throws { 53 - let globalStorage = SettingsTestStorage() 54 - let localStorage = RepositoryLocalSettingsTestStorage() 42 + @Test(.dependencies) func saveOverwritesExistingSettings() throws { 43 + let storage = SettingsTestStorage() 55 44 let rootURL = URL(fileURLWithPath: "/tmp/repo") 56 - let settingsFileURL = URL(fileURLWithPath: "/tmp/supacode-settings-\(UUID().uuidString).json") 57 - let localURL = SupacodePaths.repositorySettingsURL(for: rootURL) 58 - 59 - try localStorage.save(encode(.default), at: localURL) 60 45 61 46 var updated = RepositorySettings.default 62 47 updated.runScript = "echo updated" 63 48 64 49 withDependencies { 65 - $0.settingsFileStorage = globalStorage.storage 66 - $0.settingsFileURL = settingsFileURL 67 - $0.repositoryLocalSettingsStorage = localStorage.storage 50 + $0.settingsFileStorage = storage.storage 68 51 } operation: { 69 52 @Shared(.repositorySettings(rootURL)) var repositorySettings: RepositorySettings 70 53 $repositorySettings.withLock { ··· 72 55 } 73 56 } 74 57 75 - let localData = try #require(localStorage.data(at: localURL)) 76 - let localDecoded = try JSONDecoder().decode(RepositorySettings.self, from: localData) 77 - #expect(localDecoded == updated) 58 + let reloaded: SettingsFile = withDependencies { 59 + $0.settingsFileStorage = storage.storage 60 + } operation: { 61 + @Shared(.settingsFile) var settings: SettingsFile 62 + return settings 63 + } 64 + 65 + #expect(reloaded.repositories[rootURL.path(percentEncoded: false)] == updated) 78 66 } 79 67 80 68 @Test func decodeMissingArchiveScriptDefaultsToEmpty() throws { ··· 131 119 #expect(loaded == localSettings) 132 120 } 133 121 134 - @Test(.dependencies) func loadMigratesGlobalWhenLocalMissing() throws { 122 + @Test(.dependencies) func loadFallsBackToGlobalWhenLocalMissing() throws { 135 123 let globalStorage = SettingsTestStorage() 136 124 let localStorage = RepositoryLocalSettingsTestStorage() 137 125 let rootURL = URL(fileURLWithPath: "/tmp/repo") 138 126 let settingsFileURL = URL(fileURLWithPath: "/tmp/supacode-settings-\(UUID().uuidString).json") 139 127 let repositoryID = rootURL.standardizedFileURL.path(percentEncoded: false) 140 - let localURL = SupacodePaths.repositorySettingsURL(for: rootURL) 141 128 var globalSettings = RepositorySettings.default 142 129 globalSettings.runScript = "echo global" 143 130 ··· 162 149 } 163 150 164 151 #expect(loaded == globalSettings) 165 - 166 - let localData = try #require(localStorage.data(at: localURL)) 167 - let localDecoded = try JSONDecoder().decode(RepositorySettings.self, from: localData) 168 - #expect(localDecoded == globalSettings) 169 152 } 170 153 171 - @Test(.dependencies) func loadMigratesGlobalWhenLocalInvalid() throws { 154 + @Test(.dependencies) func loadFallsBackToGlobalWhenLocalInvalid() throws { 172 155 let globalStorage = SettingsTestStorage() 173 156 let localStorage = RepositoryLocalSettingsTestStorage() 174 157 let rootURL = URL(fileURLWithPath: "/tmp/repo") ··· 201 184 } 202 185 203 186 #expect(loaded == globalSettings) 204 - 205 - let localData = try #require(localStorage.data(at: localURL)) 206 - let localDecoded = try JSONDecoder().decode(RepositorySettings.self, from: localData) 207 - #expect(localDecoded == globalSettings) 208 187 } 209 188 210 189 @Test(.dependencies) func saveWritesLocalWhenLocalFileExists() throws { ··· 247 226 #expect(globalSaved.repositories[repositoryID] == nil) 248 227 } 249 228 250 - @Test(.dependencies) func saveWritesLocalWhenLocalFileMissing() throws { 229 + @Test(.dependencies) func saveWritesGlobalWhenLocalFileMissing() throws { 251 230 let globalStorage = SettingsTestStorage() 252 231 let localStorage = RepositoryLocalSettingsTestStorage() 253 232 let rootURL = URL(fileURLWithPath: "/tmp/repo") ··· 256 235 let localURL = SupacodePaths.repositorySettingsURL(for: rootURL) 257 236 258 237 var updated = RepositorySettings.default 259 - updated.runScript = "echo local" 238 + updated.runScript = "echo global" 260 239 261 240 withDependencies { 262 241 $0.settingsFileStorage = globalStorage.storage ··· 269 248 } 270 249 } 271 250 272 - let localData = try #require(localStorage.data(at: localURL)) 273 - let localDecoded = try JSONDecoder().decode(RepositorySettings.self, from: localData) 274 - #expect(localDecoded == updated) 275 - 276 251 let globalSaved: SettingsFile = withDependencies { 277 252 $0.settingsFileStorage = globalStorage.storage 278 253 $0.settingsFileURL = settingsFileURL ··· 282 257 return settingsFile 283 258 } 284 259 285 - #expect(globalSaved.repositories[repositoryID] == nil) 260 + #expect(globalSaved.repositories[repositoryID] == updated) 261 + #expect(localStorage.data(at: localURL) == nil) 286 262 } 287 263 288 264 private func encode(_ settings: RepositorySettings) throws -> Data {