Skip to content

Commit

Permalink
Merge pull request #64 from railwaymen/fix_cocopods_release
Browse files Browse the repository at this point in the history
Fix cocopods release
  • Loading branch information
Bartłomiej Świerad committed Nov 3, 2020
2 parents b3ed3c2 + c0d7e88 commit 7ab7d1d
Show file tree
Hide file tree
Showing 19 changed files with 425 additions and 35 deletions.
31 changes: 0 additions & 31 deletions .github/workflows/release.yml

This file was deleted.

1 change: 1 addition & 0 deletions .gitignore
Expand Up @@ -12,3 +12,4 @@ muter_logs
Pods
vendor
fastlane/report.xml
*.bak
6 changes: 6 additions & 0 deletions README.md
Expand Up @@ -241,6 +241,12 @@ If you would like Restler to do something else, create an issue with a feature r
4. Open the project in the folder `Restler-Example`. You can do it from the terminal: `open Restler-Example/Restler-Example.xcodeproj`
5. Run tests to be sure everything works properly.

### Releasing

1. Open the project root directory.
2. `cd Scripts/releaseTool`
3. `swift run ReleaseTool release ../..`

### Dependencies

#### Gems
Expand Down
4 changes: 2 additions & 2 deletions Restler.podspec
Expand Up @@ -19,12 +19,12 @@ Pod::Spec.new do |s|

# Core
s.subspec 'Core' do |ss|
ss.dependency 'RestlerCore'
ss.dependency 'RestlerCore', '~> 1.0.1'
end

# RxRestler
s.subspec 'Rx' do |ss|
ss.dependency 'Restler/Core'
ss.dependency 'RxRestler'
ss.dependency 'RxRestler', '~> 1.0.1'
end
end
2 changes: 1 addition & 1 deletion RxRestler.podspec
Expand Up @@ -16,6 +16,6 @@ Pod::Spec.new do |s|
s.swift_versions = '5.2'

s.source_files = 'Sources/RxRestler/**/*.swift'
s.dependency 'RestlerCore'
s.dependency 'RestlerCore', '~> 1.0.1'
s.dependency 'RxSwift', '~> 5.1.1'
end
2 changes: 1 addition & 1 deletion Scripts/pod_lib_lint.rb
Expand Up @@ -18,7 +18,7 @@ def usage()
--ignore-local-podspecs: list of podspecs that should not be added to
"--include-podspecs" list. If not specified, then all podspec
dependencies will be passed to "--include-podspecs".
Example: --ignore-local-podspecs=FirebaseInstanceID.podspec,GoogleDataTransport.podspec
Example: --ignore-local-podspecs=RxRestler.podspec
EOF
end

Expand Down
5 changes: 5 additions & 0 deletions Scripts/releaseTool/.gitignore
@@ -0,0 +1,5 @@
.DS_Store
/.build
/Packages
/*.xcodeproj
xcuserdata/

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

25 changes: 25 additions & 0 deletions Scripts/releaseTool/Package.resolved
@@ -0,0 +1,25 @@
{
"object": {
"pins": [
{
"package": "console-kit",
"repositoryURL": "https://github.com/vapor/console-kit.git",
"state": {
"branch": null,
"revision": "7454e839bc5ae0e75c3946d2613e442fd342fe6b",
"version": "4.2.4"
}
},
{
"package": "swift-log",
"repositoryURL": "https://github.com/apple/swift-log.git",
"state": {
"branch": null,
"revision": "173f567a2dfec11d74588eea82cecea555bdc0bc",
"version": "1.4.0"
}
}
]
},
"version": 1
}
19 changes: 19 additions & 0 deletions Scripts/releaseTool/Package.swift
@@ -0,0 +1,19 @@
// swift-tools-version:5.3
import PackageDescription

let package = Package(
name: "ReleaseTool",
platforms: [
.macOS(.v10_15),
],
dependencies: [
.package(url: "https://github.com/vapor/console-kit.git", .upToNextMajor(from: "4.2.4")),
],
targets: [
.target(
name: "ReleaseTool",
dependencies: [
.product(name: "ConsoleKit", package: "console-kit")
]),
]
)
3 changes: 3 additions & 0 deletions Scripts/releaseTool/README.md
@@ -0,0 +1,3 @@
# ReleaseTool

A description of this package.
@@ -0,0 +1,45 @@
import ConsoleKit
import Foundation

final class ReleaseCommand: Command {

struct Signature: CommandSignature {
@Flag(
name: "dry-run",
help: "Prints all commands without calling them. Useful for testing.")
var dryRun: Bool

@Argument(
name: "git-root",
help: "A root directory of the project repository.")
var gitRoot: String

init() {}
}

var help: String {
"A command to release the Restler framework to CocoaPods trunk."
}

func run(using context: CommandContext, signature: Signature) throws {
let executor = Executor(dryRun: signature.dryRun)
let gitRoot = URL(fileURLWithPath: signature.gitRoot)
context.console.info(gitRoot.path)
let manifest = Manifest.shared

context.console.info("Changing versions in podspecs...")
PodspecVersionManager(
manifest: manifest,
gitRoot: gitRoot,
executor: executor,
dryRun: signature.dryRun)
.updateVersions()

context.console.info("Pushing pods to trunk...")
PodspecPusher(
manifest: manifest,
executor: executor,
gitRoot: gitRoot)
.pushToTrunk()
}
}
46 changes: 46 additions & 0 deletions Scripts/releaseTool/Sources/ReleaseTool/Doers/Executor.swift
@@ -0,0 +1,46 @@
import Foundation

final class Executor {
let dryRun: Bool

// MARK: - Initialization
init(dryRun: Bool) {
self.dryRun = dryRun
}

// MARK: - Internal
@discardableResult
func execute(_ command: [String], workingDir: URL? = nil) -> Int32 {
let command = command.joined(separator: " ")
return execute(command, workingDir: workingDir)
}

@discardableResult
func execute(_ command: String, workingDir: URL? = nil) -> Int32 {
console.info(command)
guard !self.dryRun else { return 0 }
let task = createTask(forCommand: command, workingDir: workingDir)
return run(task: task)
}
}

// MARK: - Private
extension Executor {
private func createTask(forCommand command: String, workingDir: URL?) -> Process {
let task = Process()
task.executableURL = URL(fileURLWithPath: "/usr/bin/env")
task.arguments = command.split(separator: " ").map { String($0) }
if let workingDir = workingDir {
task.currentDirectoryURL = workingDir
task.currentDirectoryPath = workingDir.path
}
return task
}

private func run(task: Process) -> Int32 {
task.launch()
task.waitUntilExit()
return task.terminationStatus
}
}

108 changes: 108 additions & 0 deletions Scripts/releaseTool/Sources/ReleaseTool/Doers/FileReader.swift
@@ -0,0 +1,108 @@
import Foundation

final class FileReader {
private let fileURL: URL
private let dryRun: Bool
private let fileManager: FileManager = .init()

// MARK: - Initialization
init(
fileURL: URL,
dryRun: Bool
) {
self.fileURL = fileURL
self.dryRun = dryRun

guard dryRun else { return }
console.info("FileReader: \(fileURL.path)")
}

// MARK: - Internal
func replaceAll(regex: String, with text: String) {
guard var content = readFile() else { return }
var newContent = content
repeat {
content = newContent
newContent = replace(firstRegex: regex, with: text, in: content)
} while content != newContent
writeToFile(text: newContent)
}

func replace(firstRegex: String, with text: String) {
guard var content = readFile() else { return }
content = replace(firstRegex: firstRegex, with: text, in: content)
writeToFile(text: content)
}

func writeToFile(text: String?) {
if fileExists() {
removeFile()
}
createFile(content: text)
}

func readFile() -> String? {
readString(encoding: .utf8)
}

func removeFile() {
guard !dryRun else {
console.info("removeFile")
return
}
do {
try fileManager.removeItem(at: fileURL)
} catch {
fatalError("File removing error: \(error)")
}
}

func fileExists() -> Bool {
return fileManager.fileExists(atPath: fileURL.path)
}

func copy(to: URL) {
guard !dryRun else {
console.info("copyTo: \(to.path)")
return
}
do {
if fileManager.fileExists(atPath: to.path) {
try fileManager.removeItem(at: to)
}
try fileManager.copyItem(at: fileURL, to: to)
} catch {
fatalError("Error occured while copying file: \(error)")
}
}
}

// MARK: - Private
extension FileReader {
private func replace(firstRegex: String, with newText: String, in content: String) -> String {
guard let regexRange = content.range(of: firstRegex, options: .regularExpression) else { return content }
var newContent = content
newContent.removeSubrange(regexRange)
newContent.insert(contentsOf: newText, at: regexRange.lowerBound)
return newContent
}

private func createFile(content: String?) {
guard !dryRun else {
console.info("writeToFile: \(text ?? "<nil>")")
return
}
fileManager.createFile(
atPath: fileURL.path,
contents: content?.data(using: .utf8))
}

private func readString(encoding: String.Encoding) -> String? {
guard let data = readData() else { return nil }
return String(data: data, encoding: encoding)
}

private func readData() -> Data? {
fileManager.contents(atPath: fileURL.path)
}
}
27 changes: 27 additions & 0 deletions Scripts/releaseTool/Sources/ReleaseTool/Doers/PodspecPusher.swift
@@ -0,0 +1,27 @@
import Foundation

final class PodspecPusher {
private let manifest: Manifest
private let executor: Executor
private let gitRoot: URL

// MARK: - Initialization
init(
manifest: Manifest,
executor: Executor,
gitRoot: URL
) {
self.manifest = manifest
self.executor = executor
self.gitRoot = gitRoot
}

// MARK: - Internal
func pushToTrunk() {
manifest.pods.filter(\.releasing).forEach { pod in
let warningsOK = pod.allowWarnings ? "--allow-warnings" : ""
let command: String = "pod trunk push --skip-tests --synchronous \(warningsOK) \(pod.name).podspec"
executor.execute(command, workingDir: gitRoot)
}
}
}

0 comments on commit 7ab7d1d

Please sign in to comment.