Skip to content

Commit

Permalink
Fix Code Generation with GYB (#205)
Browse files Browse the repository at this point in the history
* ref: change 'Bash().capture' method to select either the stdout or stderr stream

* ref: require python3 to run 'gyb' and alert default to fatalError if python3 can't be found

* chore: adjust log message to print over multiple lines

* ref: better handle GYB error; rely on python2.7 instead of python3; and ensure 'testRender_noSecrets' is corrected

* chore: improve error handling

* chore: update swiftlint workflow

* fix: swiftlint warnings

* chore: update Readme

* chore: update danger gh action

* chore: rename danger build job

* chore: update danger gh action

* chore: remove Danger api token

* chore: temporarily disables danger

* fix: re-enable danger

---------

Co-authored-by: Gabriel Minucci <[email protected]>
  • Loading branch information
arthurpalves and GMinucci authored Dec 10, 2024
1 parent 13ea724 commit e6063f3
Show file tree
Hide file tree
Showing 22 changed files with 219 additions and 102 deletions.
9 changes: 5 additions & 4 deletions .github/workflows/danger-swift.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,10 @@ jobs:
danger-scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- uses: actions/checkout@v3
- name: Danger
uses: danger/[email protected]
uses: danger/[email protected]
with:
args: --failOnErrors --no-publish-check
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
DANGER_GITHUB_API_TOKEN: ${{ secrets.DANGER_GITHUB_API_TOKEN }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
14 changes: 10 additions & 4 deletions .github/workflows/swiftlint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,17 @@ name: SwiftLint
on:
pull_request:
types: [ opened, synchronize ]
paths:
- '.github/workflows/swiftlint.yml'
- '.swiftlint.yml'
- '**/*.swift'

jobs:
SwiftLint:
runs-on: macos-latest
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- name: Run SwiftLint
run: swiftlint lint --strict --reporter github-actions-logging
- uses: actions/checkout@v3
- name: GitHub Action for SwiftLint
uses: stanfordbdhg/action-swiftlint@v4
with:
args: --strict --reporter github-actions-logging
11 changes: 8 additions & 3 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,9 @@ let package = Package(
name: "danger-swift",
url: "https://github.com/danger/swift.git",
from: "3.5.0"
)
),
.package(
url: "https://github.com/SimplyDanny/SwiftLintPlugins")
],
targets: [
.target(
Expand All @@ -46,7 +48,8 @@ let package = Package(
"Yams",
"XcodeProj",
.product(name: "ArgumentParser", package: "swift-argument-parser"),
"Stencil"
"Stencil",
"SwiftLintPlugins"
]
),
.target(
Expand All @@ -57,7 +60,9 @@ let package = Package(
),
.testTarget(
name: "VariantsTests",
dependencies: ["Variants"]
dependencies: [
"Variants"
]
)
]
)
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,12 @@ This file is responsible for:

## Installation

### Dependencies

In order to generate the code from templates, Variants requires Python 2.7. We recommend configuring the python version using a version management tool such as Pyenv.

For details on how to install and use it check the [Pyenv repo](https://github.com/pyenv/pyenv).

### On Github Actions CI

See [Switching Variants on CI](docs/GITHUB_ACTION.md) for a better understanding and examples.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ class AndroidProject: Project {
try gradleFactory.createScript(with: configuration, variant: defaultVariant)
}

// swiftlint:disable function_body_length
// swiftlint:disable:next function_body_length
private func setupFastlane(with configuration: AndroidConfiguration, skip: Bool) {
if skip {
Logger.shared.logInfo("Skipped Fastlane setup", item: "")
Expand Down Expand Up @@ -183,7 +183,6 @@ class AndroidProject: Project {
}
}
}
// swiftlint:enable function_body_length

private func storeFastlaneParams(for variant: AndroidVariant, configuration: AndroidConfiguration) throws {
var customProperties: [CustomProperty] = (variant.custom ?? []) + (configuration.custom ?? [])
Expand Down
7 changes: 3 additions & 4 deletions Sources/VariantsCore/Custom Types/Project/iOSProject.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@
// Created by Balazs Toth
//

// swiftlint:disable type_name

import Foundation
import ArgumentParser
import PathKit

// swiftlint:disable type_name

class iOSProject: Project {
init(
specHelper: SpecHelper,
Expand Down Expand Up @@ -140,7 +140,7 @@ class iOSProject: Project {
}
}

// swiftlint:disable function_body_length
// swiftlint:disable:next function_body_length
private func setupFastlane(with configuration: iOSConfiguration, skip: Bool) {
if skip {
Logger.shared.logInfo("Skipped Fastlane setup", item: "")
Expand Down Expand Up @@ -225,7 +225,6 @@ class iOSProject: Project {
}
}
}
// swiftlint:enable function_body_length

private func storeFastlaneParams(_ properties: [CustomProperty]) throws {
let fastlaneProperties = properties.filter { $0.destination == .fastlane }
Expand Down
94 changes: 60 additions & 34 deletions Sources/VariantsCore/Factory/iOS/VariantsFileFactory.swift
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ class VariantsFileFactory {
"secrets": secrets,
"configurationValues": configurationValues
] as [String: Any]

let environment = Environment(loader: FileSystemLoader(paths: [variantsGybTemplatePath.absolute()]))
let rendered = try environment.renderTemplate(name: StaticPath.Template.variantsSwiftGybFileName,
context: context)
Expand All @@ -53,41 +52,68 @@ class VariantsFileFactory {
}

private func write(_ data: Data, using folder: Path = Path("/tmp/")) throws {
if folder.isDirectory, folder.exists {
let variantsGybFile = try folder.safeJoin(path: Path(StaticPath.Xcode.variantsGybFileName))

// Only proceed to write to file if such doesn't yet exist
// Or does exist and 'isWritable'
guard !variantsGybFile.exists
|| variantsGybFile.isWritable else {
throw TemplateDoesNotExist(templateNames: [folder.string])
}

// Write to file
try variantsGybFile.write(data)

if
try UtilsDirectory().path.exists,
let gybExecutablePath = try? UtilsDirectory().path.safeJoin(path: "gyb"),
let fileContent = try? variantsGybFile.read(),
fileContent == data {

try Bash(gybExecutablePath.absolute().description,
arguments:
"--line-directive",
"",
"-o",
"Variants.swift",
variantsGybFile.absolute().description
).run()

logger.logInfo("⚙️ ", item: """
'\(variantsGybFile.parent().abbreviate().string)/Variants.swift' has been generated with success
""", color: .green)
}
} else {
guard folder.isDirectory, folder.exists else {
throw TemplateDoesNotExist(templateNames: [folder.string])
}

let variantsGybFile = try folder.safeJoin(path: Path(StaticPath.Xcode.variantsGybFileName))
// Only proceed to write to file if such doesn't yet exist
// Or does exist and 'isWritable'
guard !variantsGybFile.exists || variantsGybFile.isWritable else {
throw TemplateDoesNotExist(templateNames: [folder.string])
}

try variantsGybFile.write(data)
guard
try UtilsDirectory().path.exists,
let gybExecutablePath = try? UtilsDirectory().path.safeJoin(path: "gyb"),
let fileContent = try? variantsGybFile.read(),
fileContent == data
else { return }

let gybStdErr = try Bash(gybExecutablePath.absolute().description,
arguments:
"--line-directive",
"",
"-o",
"Variants.swift",
variantsGybFile.absolute().description
).capture(stream: .stderr)
let variantsFilePath = "\(variantsGybFile.parent().abbreviate().string)/Variants.swift"
handleGybErrors(message: gybStdErr, variantsFilePath: variantsFilePath)
logger.logInfo("⚙️ ", item: "'\(variantsFilePath)' has been generated with success", color: .green)
}

private func handleGybErrors(message: String?, variantsFilePath: String) {
guard let message, !message.isEmpty else { return }

switch message {
case _ where message.contains("env: python2.7: No such file or directory"):
logger.logFatal(item:
"""
We're unable to find a 'python2.7' executable.
Install 'python2.7' or ensure it's in your executables path and try running this Variants command again.
Tip:
* Install pyenv (brew install pyenv)
* Install python2.7 (pyenv install python2.7)
* Add "$(pyenv root)/shims" to your PATH
""")
case _ where message.contains("for chunk in chunks(encode(os.environ.get("):
logger.logFatal(item:
"""
We're unable to create 'Variants.Secrets' in '\(variantsFilePath)'.
Ensure that custom config values whose `env: true` are actually environment variables.
""")
case _ where message.contains("pyenv: python2.7: command not found"):
logger.logFatal(item:
"""
Looks like you have pyenv installed but the current configured version is not correct.
Please, select the latest build of python 2.7 as local version.
For example: `pyenv local 2.7`
""")
default:
logger.logFatal(item: message as Any)
}
}

let logger: Logger
Expand Down
30 changes: 22 additions & 8 deletions Sources/VariantsCore/Helpers/Bash.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,11 @@ struct Bash {
var command: String
var arguments: [String]

enum Stream {
case stdout
case stderr
}

init(_ command: String, arguments: String...) {
self.command = command
self.arguments = arguments
Expand All @@ -20,12 +25,12 @@ struct Bash {
_ = try capture()
}

func capture() throws -> String? {
func capture(stream: Stream = .stdout) throws -> String? {
guard var bashCommand = try execute(command: "/bin/bash", arguments: ["-l", "-c", "which \(command)"]) else {
throw RuntimeError("\(command) not found")
}
bashCommand = bashCommand.trimmingCharacters(in: NSCharacterSet.whitespacesAndNewlines)
if let output = try execute(command: bashCommand, arguments: arguments) {
if let output = try execute(command: bashCommand, arguments: arguments, stream: stream) {
// `dropLast()` is required as the output always contains a new line (`\n`) at the end.
return String(output.dropLast())
}
Expand All @@ -34,11 +39,13 @@ struct Bash {

// MARK: - Private

private func execute(command: String, arguments: [String] = []) throws -> String? {
private func execute(command: String, arguments: [String] = [], stream: Stream = .stdout) throws -> String? {
let process = Process()
let pipe = Pipe()
let stdoutPipe = Pipe()
let stderrPipe = Pipe()
process.arguments = arguments
process.standardOutput = pipe
process.standardOutput = stdoutPipe
process.standardError = stderrPipe

if #available(OSX 10.13, *) {
process.executableURL = URL(fileURLWithPath: command)
Expand All @@ -48,8 +55,15 @@ struct Bash {
process.launch()
}

let data = pipe.fileHandleForReading.readDataToEndOfFile()
let output = String(data: data, encoding: .utf8)
return output
switch stream {
case .stdout:
let stdoutData = stdoutPipe.fileHandleForReading.readDataToEndOfFile()
let stdout = String(data: stdoutData, encoding: .utf8)
return stdout
case .stderr:
let stderrData = stderrPipe.fileHandleForReading.readDataToEndOfFile()
let stderr = String(data: stderrData, encoding: .utf8)
return stderr
}
}
}
4 changes: 2 additions & 2 deletions Sources/VariantsCore/Helpers/SpecHelper.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@
// Created by Arthur Alves
//

// swiftlint:disable type_name

import Foundation
import PathKit

// swiftlint:disable type_name

enum iOSProjectKey: String, CaseIterable {
case project = "PROJECT"
case target = "TARGET"
Expand Down
4 changes: 2 additions & 2 deletions Sources/VariantsCore/Schemas/iOS/iOSConfiguration.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@
// Created by Arthur Alves
//

import Foundation

// swiftlint:disable type_name

import Foundation

internal extension CodingUserInfoKey {
static let bundleID = CodingUserInfoKey(rawValue: "bundle_id")!
}
Expand Down
4 changes: 2 additions & 2 deletions Sources/VariantsCore/Schemas/iOS/iOSSigning.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@
// Created by Arthur Alves
//

import Foundation

// swiftlint:disable type_name

import Foundation

struct iOSSigning: Codable {
let teamName: String?
let teamID: String?
Expand Down
4 changes: 2 additions & 2 deletions Sources/VariantsCore/Schemas/iOS/iOSTarget.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@
// Created by Arthur Alves
//

import Foundation

// swiftlint:disable type_name

import Foundation

public typealias NamedTarget = (key: String, value: iOSTarget)

public struct iOSTarget: Codable {
Expand Down
4 changes: 2 additions & 2 deletions Sources/VariantsCore/Schemas/iOS/iOSVariant.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@
// Created by Arthur Alves
//

import Foundation

// swiftlint:disable type_name

import Foundation

public struct iOSVariant: Variant {
let name: String
let versionName: String
Expand Down
Loading

0 comments on commit e6063f3

Please sign in to comment.