Skip to content

Commit

Permalink
Merge branch 'release/0.7.0' into versions
Browse files Browse the repository at this point in the history
  • Loading branch information
Jeehut committed May 17, 2020
2 parents dfaab8f + 90b123e commit ccbceea
Show file tree
Hide file tree
Showing 13 changed files with 242 additions and 38 deletions.
102 changes: 102 additions & 0 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
name: CI

on:
push:
branches: [main, versions]
pull_request:
branches: [main]

jobs:
anylint:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v2

- name: Export latest tool versions
run: |
latest_version() {
curl --silent "https://api.github.com/repos/$1/releases/latest" | grep '"tag_name":' | sed -E 's/.*"([^"]+)".*/\1/'
}
echo "::set-env name=ANYLINT_LATEST_VERSION::$( latest_version Flinesoft/AnyLint )"
echo "::set-env name=SWIFT_SH_LATEST_VERSION::$( latest_version mxcl/swift-sh )"
- name: AnyLint Cache
uses: actions/cache@v1
id: anylint-cache
with:
path: anylint-cache
key: ${{ runner.os }}-v1-anylint-${{ env.ANYLINT_LATEST_VERSION }}-swift-sh-${{ env.SWIFT_SH_LATEST_VERSION }}

- name: Copy from cache
if: steps.anylint-cache.outputs.cache-hit
run: |
sudo cp -f anylint-cache/anylint /usr/local/bin/anylint
sudo cp -f anylint-cache/swift-sh /usr/local/bin/swift-sh
- name: Install AnyLint
if: steps.anylint-cache.outputs.cache-hit != 'true'
run: |
git clone https://github.com/Flinesoft/AnyLint.git
cd AnyLint
swift build -c release
sudo cp -f .build/release/anylint /usr/local/bin/anylint
- name: Install swift-sh
if: steps.anylint-cache.outputs.cache-hit != 'true'
run: |
git clone https://github.com/mxcl/swift-sh.git
cd swift-sh
swift build -c release
sudo cp -f .build/release/swift-sh /usr/local/bin/swift-sh
- name: Copy to cache
if: steps.anylint-cache.outputs.cache-hit != 'true'
run: |
mkdir -p anylint-cache
cp -f /usr/local/bin/anylint anylint-cache/anylint
cp -f /usr/local/bin/swift-sh anylint-cache/swift-sh
- name: Cleanup checkouts
run: rm -rf AnyLint && rm -rf swift-sh

- name: Run AnyLint
run: anylint

swiftlint:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v2

- name: Run SwiftLint
uses: norio-nomura/[email protected]
with:
args: --strict

test-linux:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v2

- name: Run tests
run: swift test -v


test-macos:
runs-on: macos-latest

steps:
- uses: actions/checkout@v2

- name: Run tests
run: swift test -v --enable-code-coverage

- name: Report Code Coverage
run: |
xcrun llvm-cov export -format="lcov" .build/debug/${PACKAGE_NAME}PackageTests.xctest/Contents/MacOS/${PACKAGE_NAME}PackageTests -instr-profile .build/debug/codecov/default.profdata > coverage.lcov
bash <(curl -Ls https://coverage.codacy.com/get.sh) report -r coverage.lcov
env:
PACKAGE_NAME: AnyLint
CODACY_PROJECT_TOKEN: ${{ secrets.CODACY_PROJECT_TOKEN }}
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,15 @@ If needed, pluralize to `Tasks`, `PRs` or `Authors` and list multiple entries se
### Security
- None.

## [0.7.0] - 2020-05-18
### Added
- A new AnyLint custom check was added to ensure `AnyLint` fails when `LinuxMain.swift` isn't up-to-date, useful as a git pre-commit hook.
Author: [Cihat Gündüz](https://github.com/Jeehut) | PR: [#28](https://github.com/Flinesoft/AnyLint/pull/28)
### Changed
- When a given `autoCorrectReplacement` on the `checkFileContents` method leads to no changes, the matched string of the given `regex` is considered to be already correct, thus no violation is reported anymore.
Issue: [#26](https://github.com/Flinesoft/AnyLint/issues/26) | PR: [#28](https://github.com/Flinesoft/AnyLint/pull/28) | Author: [Cihat Gündüz](https://github.com/Jeehut)
- A CI pipeline using GitHub Actions was setup, which is much faster as it runs multiple tasks in parallel than Bitrise.
Author: [Cihat Gündüz](https://github.com/Jeehut)

## [0.6.3] - 2020-05-07
### Added
Expand Down
2 changes: 1 addition & 1 deletion Formula/anylint.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
class Anylint < Formula
desc "Lint anything by combining the power of Swift & regular expressions"
homepage "https://github.com/Flinesoft/AnyLint"
url "https://github.com/Flinesoft/AnyLint.git", :tag => "0.6.2", :revision => "8a99c3428a6595e3b03da9b3816c5fc301fc7ea0"
url "https://github.com/Flinesoft/AnyLint.git", :tag => "0.6.3", :revision => "dfaab8f498e683431d3e0b28585127486e2e73a7"
head "https://github.com/Flinesoft/AnyLint.git"

depends_on :xcode => ["11.4", :build]
Expand Down
2 changes: 1 addition & 1 deletion Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import PackageDescription
let package = Package(
name: "AnyLint",
products: [
.library(name: "AnyLint", targets: ["AnyLint"]),
.library(name: "AnyLint", targets: ["AnyLint", "Utility"]),
.executable(name: "anylint", targets: ["AnyLintCLI"]),
],
dependencies: [
Expand Down
56 changes: 36 additions & 20 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@
</p>

<p align="center">
<a href="https://app.bitrise.io/app/b2708c16ab236ff8">
<img src="https://app.bitrise.io/app/b2708c16ab236ff8/status.svg?token=PuELIpLj_V11GkcIztEgGQ&branch=main"
alt="Build Status">
<a href="https://github.com/Flinesoft/AnyLint/actions?query=branch%3Amain">
<img src="https://github.com/Flinesoft/AnyLint/workflows/CI/badge.svg"
alt="CI">
</a>
<a href="https://www.codacy.com/gh/Flinesoft/AnyLint">
<img src="https://api.codacy.com/project/badge/Grade/c881ee12938145d3bfd398eff1571228"
Expand All @@ -17,8 +17,8 @@
alt="Coverage"/>
</a>
<a href="https://github.com/Flinesoft/AnyLint/releases">
<img src="https://img.shields.io/badge/Version-0.6.3-blue.svg"
alt="Version: 0.6.3">
<img src="https://img.shields.io/badge/Version-0.7.0-blue.svg"
alt="Version: 0.7.0">
</a>
<a href="https://github.com/Flinesoft/AnyLint/blob/main/LICENSE">
<img src="https://img.shields.io/badge/License-MIT-lightgrey.svg"
Expand Down Expand Up @@ -184,7 +184,7 @@ Many parameters in the above mentioned lint check methods are of `Regex` type. A
let regexWithOptions: Regex = ["key": #"foo|bar"#, "num": "[0-9]+", #"\"#: "im"] // => /(?<key>foo|bar)(?<num>[0-9]+)/im
```

Note that we recommend using [raw strings](https://www.hackingwithswift.com/articles/162/how-to-use-raw-strings-in-swift) (`#"foo"#` instead of `"foo"`) for all regexes to get rid of double escaping backslashes (e.g. `\\s` becomes `\s`). This also allows for testing regexes in online regex editors like [Rubular](https://rubular.com/) first and then copy & pasting from them without any additional escaping.
Note that we recommend using [raw strings](https://www.hackingwithswift.com/articles/162/how-to-use-raw-strings-in-swift) (`#"foo"#` instead of `"foo"`) for all regexes to get rid of double escaping backslashes (e.g. `\\s` becomes `\s`). This also allows for testing regexes in online regex editors like [Rubular](https://rubular.com/) first and then copy & pasting from them without any additional escaping (except for `{` & `}`, replace with `\{` & `\}`).

<details>
<summary>Regex Options</summary>
Expand Down Expand Up @@ -380,31 +380,47 @@ AnyLint allows you to do any kind of lint checks (thus its name) as it gives you

Note that the `Violation` type just holds some additional information on the file, matched string, location in the file and applied autocorrection and that all these fields are optional. It is a simple struct used by the AnyLint reporter for more detailed output, no logic attached. The only required field is the `CheckInfo` object which caused the violation.

If you want to use regexes in your custom code, you can learn more about how you can match strings with a `Regex` object on [the HandySwift docs](https://github.com/Flinesoft/AnyLint/blob/main/Sources/Utility/Regex.swift) (the project, the class was taken from) or read the [code documentation comments](https://github.com/Flinesoft/AnyLint/blob/main/Sources/Utility/Regex.swift).
If you want to use regexes in your custom code, you can learn more about how you can match strings with a `Regex` object on [the HandySwift docs](https://github.com/Flinesoft/HandySwift#regex) (the project, the class was taken from) or read the [code documentation comments](https://github.com/Flinesoft/AnyLint/blob/main/Sources/Utility/Regex.swift).

When using the `customCheck`, you might want to also include some Swift packages for [easier file handling](https://github.com/JohnSundell/Files) or [running shell commands](https://github.com/JohnSundell/ShellOut). You can do so by adding them at the top of the file like so:

> TODO: Improve the below code example with something more useful & realistic.
```swift
#!/usr/local/bin/swift-sh
import AnyLint // @Flinesoft
import Files // @JohnSundell
import ShellOut // @JohnSundell

Lint.logSummaryAndExit(arguments: CommandLine.arguments) {
// MARK: echo
try Lint.customCheck(checkInfo: "Echo: Always say hello to the world.") { checkInfo in
var violations: [Violation] = []
// MARK: - Variables
let projectName: String = "AnyLint"

// use ShellOut package
let output = try shellOut(to: "echo", arguments: ["Hello world"])
// ...
// MARK: - Checks
// MARK: LinuxMainUpToDate
try Lint.customCheck(checkInfo: "LinuxMainUpToDate: The tests in Tests/LinuxMain.swift should be up-to-date.") { checkInfo in
var violations: [Violation] = []

// use Files package
try Folder(path: "MyFolder").files.forEach { file in
// ...
violations.append(Violation(checkInfo: checkInfo))
let linuxMainFilePath = "Tests/LinuxMain.swift"
let linuxMainContentsBeforeRegeneration = try! String(contentsOfFile: linuxMainFilePath)

let sourceryDirPath = ".sourcery"
try! shellOut(to: "sourcery", arguments: ["--sources", "Tests/\(projectName)Tests", "--templates", "\(sourceryDirPath)/LinuxMain.stencil", "--output", sourceryDirPath])

let generatedLinuxMainFilePath = "\(sourceryDirPath)/LinuxMain.generated.swift"
let linuxMainContentsAfterRegeneration = try! String(contentsOfFile: generatedLinuxMainFilePath)

// move generated file to LinuxMain path to update its contents
try! shellOut(to: "mv", arguments: [generatedLinuxMainFilePath, linuxMainFilePath])

if linuxMainContentsBeforeRegeneration != linuxMainContentsAfterRegeneration {
violations.append(
Violation(
checkInfo: checkInfo,
filePath: linuxMainFilePath,
appliedAutoCorrection: AutoCorrection(
before: linuxMainContentsBeforeRegeneration,
after: linuxMainContentsAfterRegeneration
)
)
)
}

return violations
Expand Down
15 changes: 10 additions & 5 deletions Sources/AnyLint/Checkers/FileContentsChecker.swift
Original file line number Diff line number Diff line change
Expand Up @@ -41,16 +41,21 @@ extension FileContentsChecker: Checker {
continue
}

let appliedAutoCorrection: AutoCorrection? = {
let autoCorrection: AutoCorrection? = {
guard let autoCorrectReplacement = autoCorrectReplacement else { return nil }

let newMatchString = regex.replaceAllCaptures(in: match.string, with: autoCorrectReplacement)
newFileContents.replaceSubrange(match.range, with: newMatchString)

return AutoCorrection(before: match.string, after: newMatchString)
}()

if appliedAutoCorrection != nil {
if let autoCorrection = autoCorrection {
guard match.string != autoCorrection.after else {
// can skip auto-correction & violation reporting because auto-correct replacement is equal to matched string
continue
}

// apply auto correction
newFileContents.replaceSubrange(match.range, with: autoCorrection.after)
log.message("Applied autocorrection for last match ...", level: .debug)
}

Expand All @@ -61,7 +66,7 @@ extension FileContentsChecker: Checker {
filePath: filePath,
matchedString: match.string,
locationInfo: locationInfo,
appliedAutoCorrection: appliedAutoCorrection
appliedAutoCorrection: autoCorrection
)
)
}
Expand Down
2 changes: 1 addition & 1 deletion Sources/Utility/Constants.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ public var log = Logger(outputType: .console)
/// Constants to reference across the project.
public enum Constants {
/// The current tool version string. Conforms to SemVer 2.0.
public static let currentVersion: String = "0.6.3"
public static let currentVersion: String = "0.7.0"

/// The name of this tool.
public static let toolName: String = "AnyLint"
Expand Down
8 changes: 2 additions & 6 deletions Sources/Utility/Extensions/StringExt.swift
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,8 @@ extension String {

/// Returns the parent directory path.
public var parentDirectoryPath: String {
guard let url = URL(string: self) else {
log.message("Could not convert path '\(self)' to type URL.", level: .error)
log.exit(status: .failure)
return "" // only reachable in unit tests
}

let url = URL(fileURLWithPath: self)
guard url.pathComponents.count > 1 else { return fileManager.currentDirectoryPath }
return url.deletingLastPathComponent().absoluteString
}

Expand Down
2 changes: 1 addition & 1 deletion Sources/Utility/Regex.swift
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,7 @@ extension Regex.Options: CustomStringConvertible {

extension Regex.Options: Equatable, Hashable {
public static func == (lhs: Regex.Options, rhs: Regex.Options) -> Bool {
return lhs.rawValue == rhs.rawValue
lhs.rawValue == rhs.rawValue
}

public func hash(into hasher: inout Hasher) {
Expand Down
29 changes: 29 additions & 0 deletions Tests/AnyLintTests/Checkers/FileContentsCheckerTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -117,4 +117,33 @@ final class FileContentsCheckerTests: XCTestCase {
XCTAssertEqual(violations[5].locationInfo!.charInLine, 1)
}
}

func testSkipIfEqualsToAutocorrectReplacement() {
let temporaryFiles: [TemporaryFile] = [
(subpath: "Sources/Hello.swift", contents: "let x = 5\nvar y = 10"),
(subpath: "Sources/World.swift", contents: "let x =5\nvar y= 10"),
]

withTemporaryFiles(temporaryFiles) { filePathsToCheck in
let checkInfo = CheckInfo(id: "Whitespacing", hint: "Always add a single whitespace around '='.", severity: .warning)
let violations = try FileContentsChecker(
checkInfo: checkInfo,
regex: #"(let|var) (\w+)\s*=\s*(\w+)"#,
filePathsToCheck: filePathsToCheck,
autoCorrectReplacement: "$1 $2 = $3"
).performCheck()

XCTAssertEqual(violations.count, 2)

XCTAssertEqual(violations[0].checkInfo, checkInfo)
XCTAssertEqual(violations[0].filePath, "\(tempDir)/Sources/World.swift")
XCTAssertEqual(violations[0].locationInfo!.line, 1)
XCTAssertEqual(violations[0].locationInfo!.charInLine, 1)

XCTAssertEqual(violations[1].checkInfo, checkInfo)
XCTAssertEqual(violations[1].filePath, "\(tempDir)/Sources/World.swift")
XCTAssertEqual(violations[1].locationInfo!.line, 2)
XCTAssertEqual(violations[1].locationInfo!.charInLine, 1)
}
}
}
2 changes: 1 addition & 1 deletion Tests/AnyLintTests/FilesSearchTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ final class FilesSearchTests: XCTestCase {
within: FileManager.default.currentDirectoryPath,
includeFilters: [try Regex("\(tempDir)/.*")],
excludeFilters: []
)
).sorted()
XCTAssertEqual(includeFilterFilePaths, ["\(tempDir)/Sources/Hello.swift", "\(tempDir)/Sources/World.swift"])

let excludeFilterFilePaths = FilesSearch.shared.allFiles(
Expand Down
5 changes: 3 additions & 2 deletions Tests/LinuxMain.swift
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Generated using Sourcery 0.17.0 — https://github.com/krzysztofzablocki/Sourcery
// Generated using Sourcery 0.18.0 — https://github.com/krzysztofzablocki/Sourcery
// DO NOT EDIT

@testable import AnyLintTests
Expand Down Expand Up @@ -29,7 +29,8 @@ extension FileContentsCheckerTests {
static var allTests: [(String, (FileContentsCheckerTests) -> () throws -> Void)] = [
("testPerformCheck", testPerformCheck),
("testSkipInFile", testSkipInFile),
("testSkipHere", testSkipHere)
("testSkipHere", testSkipHere),
("testSkipIfEqualsToAutocorrectReplacement", testSkipIfEqualsToAutocorrectReplacement)
]
}

Expand Down
Loading

0 comments on commit ccbceea

Please sign in to comment.