Deprecate yaml and json manifests (#190)

* Deprecate JSON and YAML manifests

* Add tests

* Deprecate JSON and YAML manifests
This commit is contained in:
Pedro Piñera Buendía 2018-12-27 22:52:33 +01:00 committed by GitHub
parent 9137e48f03
commit 330b7727d9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 149 additions and 112 deletions

View File

@ -16,6 +16,10 @@ Please, check out guidelines: https://keepachangelog.com/en/1.0.0/
- Danger https://github.com/tuist/tuist/pull/186 by @pepibumur.
### Deprecated
- JSON and YAML manifests https://github.com/tuist/tuist/pull/190 by @pepibumur.
## 0.10.2
### Fixed

View File

@ -0,0 +1,33 @@
import Foundation
/// Protocol that defines an interface to notify the user about features being deprecated
public protocol Deprecating {
/// Notifies the user about deprecations by printing a warning message.
///
/// - Parameters:
/// - deprecation: Feature that will be deprecated.
/// - suggestion: Suggestions for the user to migrate.
func notify(deprecation: String, suggestion: String)
}
public final class Deprecator: Deprecating {
/// Printer instance to output the warning to the users.
private let printer: Printing
/// Constructs a deprecator with a printer instance.
///
/// - Parameter printer: Printer instance to output the warning to the users.
public init(printer: Printing = Printer()) {
self.printer = printer
}
/// Notifies the user about deprecations by printing a warning message.
///
/// - Parameters:
/// - deprecation: Feature that will be deprecated.
/// - suggestion: Suggestions for the user to migrate.
public func notify(deprecation: String, suggestion: String) {
let message = "\(deprecation) will be deprecated in the next major release. Use \(suggestion) instead."
printer.print(deprecation: message)
}
}

View File

@ -10,6 +10,11 @@ public protocol Printing: AnyObject {
func print(error: Error)
func print(success: String)
func print(errorMessage: String)
/// Prints a deprecation message (yellow color)
///
/// - Parameter deprecation: Deprecation message.
func print(deprecation: String)
}
public class Printer: Printing {
@ -45,6 +50,16 @@ public class Printer: Printing {
writer.write("\n")
}
/// Prints a deprecation message (yellow color)
///
/// - Parameter deprecation: Deprecation message.
public func print(deprecation: String) {
let writer = InteractiveWriter.stdout
writer.write("Deprecated: ", inColor: .yellow, bold: true)
writer.write(deprecation, inColor: .yellow, bold: false)
writer.write("\n")
}
public func print(warning: String) {
let writer = InteractiveWriter.stdout
writer.write("⚠️ Warning: ", inColor: .yellow, bold: true)

View File

@ -0,0 +1,10 @@
import Foundation
import TuistCore
public final class MockDeprecator: Deprecating {
public var notifyArgs: [(deprecation: String, suggestion: String)] = []
public func notify(deprecation: String, suggestion: String) {
notifyArgs.append((deprecation: deprecation, suggestion: suggestion))
}
}

View File

@ -14,6 +14,7 @@ public final class MockPrinter: Printing {
public var printErrorMessageArgs: [String] = []
public var printSuccessArgs: [String] = []
public var printWarningArgs: [String] = []
public var printDeprecationArgs: [String] = []
public func print(_ text: String) {
printArgs.append(text)
@ -35,6 +36,11 @@ public final class MockPrinter: Printing {
standardOutput.append("\(warning)\n")
}
public func print(deprecation: String) {
printDeprecationArgs.append(deprecation)
standardOutput.append("\(deprecation)\n")
}
public func print(errorMessage: String) {
printErrorMessageArgs.append(errorMessage)
standardError.append("\(errorMessage)\n")

View File

@ -78,21 +78,35 @@ protocol GraphManifestLoading {
class GraphManifestLoader: GraphManifestLoading {
// MARK: - Attributes
let fileAggregator: FileAggregating
/// File handler to interact with the file system.
let fileHandler: FileHandling
/// Instance to run commands in the system.
let system: Systeming
/// Resource locator to look up Tuist-related resources.
let resourceLocator: ResourceLocating
/// Depreactor to notify about deprecations.
let deprecator: Deprecating
// MARK: - Init
init(fileAggregator: FileAggregating = FileAggregator(),
fileHandler: FileHandling = FileHandler(),
/// Initializes the manifest loader with its attributes.
///
/// - Parameters:
/// - fileHandler: File handler to interact with the file system.
/// - system: Instance to run commands in the system.
/// - resourceLocator: Resource locator to look up Tuist-related resources.
/// - deprecator: Depreactor to notify about deprecations.
init(fileHandler: FileHandling = FileHandler(),
system: Systeming = System(),
resourceLocator: ResourceLocating = ResourceLocator()) {
self.fileAggregator = fileAggregator
resourceLocator: ResourceLocating = ResourceLocator(),
deprecator: Deprecating = Deprecator()) {
self.fileHandler = fileHandler
self.system = system
self.resourceLocator = resourceLocator
self.deprecator = deprecator
}
func load(_ manifest: Manifest, path: AbsolutePath) throws -> JSON {
@ -100,8 +114,10 @@ class GraphManifestLoader: GraphManifestLoading {
if manifestPath.extension == "swift" {
return try loadSwiftManifest(path: manifestPath)
} else if manifestPath.extension == "json" {
deprecator.notify(deprecation: "JSON manifests", suggestion: "Swift manifests")
return try loadJSONManifest(path: manifestPath)
} else if manifestPath.extension == "yaml" || manifestPath.extension == "yml" {
deprecator.notify(deprecation: "YAML manifests", suggestion: "Swift manifests")
return try loadYamlManifest(path: manifestPath)
} else {
throw GraphManifestLoaderError.manifestNotFound(manifest, path)

View File

@ -1,44 +0,0 @@
import Basic
import Foundation
/// A file aggregator aggregates the content of multiple files.
protocol FileAggregating: AnyObject {
/// Aggreates the files at the given paths.
///
/// - Parameters:
/// - paths: paths whose content will be aggregated.
/// - into: path of the file where the contents will be aggregated into.
/// - Throws: an error if the aggregation fails.
func aggregate(_ paths: [AbsolutePath], into: AbsolutePath) throws
}
/// Default file aggreagtor.
final class FileAggregator: FileAggregating {
/// Aggreates the files at the given paths.
///
/// - Parameters:
/// - paths: paths whose content will be aggregated.
/// - into: path of the file where the contents will be aggregated into.
/// - Throws: an error if the aggregation fails.
func aggregate(_ paths: [AbsolutePath], into: AbsolutePath) throws {
var paths = paths
if paths.count == 0 { return }
let outputStream = OutputStream(toFileAtPath: into.asString, append: true)!
outputStream.open()
let first = paths.removeFirst()
try Data(contentsOf: URL(fileURLWithPath: first.asString)).write(into: outputStream)
try paths.forEach { path in
"\n".data(using: .utf8)!.write(into: outputStream)
try Data(contentsOf: URL(fileURLWithPath: path.asString)).write(into: outputStream)
}
outputStream.close()
}
}
fileprivate extension Data {
func write(into: OutputStream) {
_ = withUnsafeBytes {
into.write($0, maxLength: self.count)
}
}
}

View File

@ -0,0 +1,21 @@
import Foundation
import XCTest
@testable import TuistCore
@testable import TuistCoreTesting
final class DeprecatorTests: XCTestCase {
var printer: MockPrinter!
var subject: Deprecator!
override func setUp() {
super.setUp()
printer = MockPrinter()
subject = Deprecator(printer: printer)
}
func test_notify() {
subject.notify(deprecation: "foo", suggestion: "bar")
XCTAssertEqual(printer.printDeprecationArgs, ["foo will be deprecated in the next major release. Use bar instead."])
}
}

View File

@ -34,12 +34,15 @@ final class ManifestTests: XCTestCase {
final class GraphManifestLoaderTests: XCTestCase {
var fileHandler: MockFileHandler!
var deprecator: MockDeprecator!
var subject: GraphManifestLoader!
override func setUp() {
super.setUp()
fileHandler = try! MockFileHandler()
subject = GraphManifestLoader(fileHandler: fileHandler)
deprecator = MockDeprecator()
subject = GraphManifestLoader(fileHandler: fileHandler,
deprecator: deprecator)
}
func test_load_when_swift() throws {
@ -72,6 +75,9 @@ final class GraphManifestLoaderTests: XCTestCase {
let got = try subject.load(.project, path: fileHandler.currentPath)
XCTAssertEqual(try got.get("name") as String, "tuist")
XCTAssertEqual(deprecator.notifyArgs.count, 1)
XCTAssertEqual(deprecator.notifyArgs.first?.deprecation, "JSON manifests")
XCTAssertEqual(deprecator.notifyArgs.first?.suggestion, "Swift manifests")
}
func test_load_when_yaml() throws {
@ -87,6 +93,9 @@ final class GraphManifestLoaderTests: XCTestCase {
let got = try subject.load(.project, path: fileHandler.currentPath)
XCTAssertEqual(try got.get("name") as String, "tuist")
XCTAssertEqual(deprecator.notifyArgs.count, 1)
XCTAssertEqual(deprecator.notifyArgs.first?.deprecation, "YAML manifests")
XCTAssertEqual(deprecator.notifyArgs.first?.suggestion, "Swift manifests")
}
func test_load_when_yml() throws {

View File

@ -1,29 +0,0 @@
import Basic
import Foundation
@testable import TuistKit
import XCTest
final class FileAggregatorTests: XCTestCase {
var subject: FileAggregator!
override func setUp() {
super.setUp()
subject = FileAggregator()
}
func test_aggregate() throws {
let dir = try TemporaryDirectory(removeTreeOnDeinit: true)
let aPath = dir.path.appending(component: "a.swift")
let bPath = dir.path.appending(component: "b.swift")
try "a".write(toFile: aPath.asString,
atomically: true,
encoding: .utf8)
try "b".write(toFile: bPath.asString,
atomically: true,
encoding: .utf8)
let cPath = dir.path.appending(component: "c.swift")
try subject.aggregate([aPath, bPath], into: cPath)
let content = try String(contentsOf: URL(fileURLWithPath: cPath.asString))
XCTAssertEqual(content, "a\nb")
}
}

View File

@ -2,31 +2,31 @@ import ProjectDescription
let project = Project(name: "App",
up: [
/* Configures the environment for the project */
/* .homebrew(packages: ["swiftlint"]) */
/* Configures the environment for the project */
/* .homebrew(packages: ["swiftlint"]) */
],
targets: [
Target(name: "App",
platform: .iOS,
product: .app,
bundleId: "io.tuist.App",
infoPlist: "Info.plist",
sources: "Sources/**",
dependencies: [
/* Target dependencies can be defined here */
/* .framework(path: "framework") */
],
settings: Settings(base: ["CODE_SIGN_IDENTITY": "",
"CODE_SIGNING_REQUIRED": "NO"])),
Target(name: "AppTests",
platform: .iOS,
product: .unitTests,
bundleId: "io.tuist.AppTests",
infoPlist: "Tests.plist",
sources: "Tests/**",
dependencies: [
.target(name: "App")
],
settings: Settings(base: ["CODE_SIGN_IDENTITY": "",
"CODE_SIGNING_REQUIRED": "NO"]))
])
Target(name: "App",
platform: .iOS,
product: .app,
bundleId: "io.tuist.App",
infoPlist: "Info.plist",
sources: "Sources/**",
dependencies: [
/* Target dependencies can be defined here */
/* .framework(path: "framework") */
],
settings: Settings(base: ["CODE_SIGN_IDENTITY": "",
"CODE_SIGNING_REQUIRED": "NO"])),
Target(name: "AppTests",
platform: .iOS,
product: .unitTests,
bundleId: "io.tuist.AppTests",
infoPlist: "Tests.plist",
sources: "Tests/**",
dependencies: [
.target(name: "App"),
],
settings: Settings(base: ["CODE_SIGN_IDENTITY": "",
"CODE_SIGNING_REQUIRED": "NO"])),
])

View File

@ -2,10 +2,9 @@ import UIKit
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
func application(_: UIApplication, didFinishLaunchingWithOptions _: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
window = UIWindow(frame: UIScreen.main.bounds)
let viewController = UIViewController()
viewController.view.backgroundColor = .white
@ -13,5 +12,4 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
window?.makeKeyAndVisible()
return true
}
}
}

View File

@ -3,6 +3,4 @@ import XCTest
@testable import App
final class AppTests: XCTestCase {
}
final class AppTests: XCTestCase {}