-
Notifications
You must be signed in to change notification settings - Fork 15
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Base setup #3
Merged
Merged
Base setup #3
Changes from all commits
Commits
Show all changes
18 commits
Select commit
Hold shift + click to select a range
4a98c8a
Added Shell and OctoKit
AvdLee 3dbf7c3
Created a start for Git commands
AvdLee 8fdd8fe
Generating a changelog now from input parameters
AvdLee de8736d
Add verbose option and make the code look prettier
AvdLee 8ca34c8
Add an example in the readme
AvdLee a197194
Add function and tests to extract issue numbers from a string
Boris-Em 802c567
Merge pull request #2 from WeTransfer/feature/issue-extraction
Boris-Em 7478bc5
Cleaned up the whole project
AvdLee 2d027e1
Add a bunch of tests
AvdLee 3ae2b34
PullRequest testing now works as well
AvdLee 78c7025
Fetching issues is now tested
AvdLee 348c1dc
Add final tests
AvdLee aac895f
Add executable type
AvdLee 4ab445b
Update the readme
AvdLee 2d4fbea
Update Tests/ChangelogProducerTests/IssueResolverTests.swift
AvdLee 83ebda9
Add copyright headers
AvdLee 4af04b0
Merge branch 'feature/input-commands' of github.com:WeTransfer/Change…
AvdLee 1dc4171
Add Copyright headers
AvdLee File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,10 +1,36 @@ | ||
# ChangelogProducer | ||
A changelog generator written in Swift for GitHub repositories. | ||
|
||
### Installation using [Mint](https://github.com/yonaskolb/mint) | ||
You can install the Changelog Producer using Mint as follows: | ||
|
||
``` | ||
$ mint install WeTransfer/ChangelogProducer | ||
``` | ||
|
||
After that you can directly use it: | ||
|
||
```bash | ||
$ changelogproducer --help | ||
OVERVIEW: Create a changelog for GitHub repositories | ||
|
||
USAGE: ChangelogProducer <options> | ||
|
||
OPTIONS: | ||
--baseBranch, -b The base branch to compare with | ||
--sinceTag, -s The tag to use as a base | ||
--verbose Show extra logging for debugging purposes | ||
--help Display available options | ||
``` | ||
|
||
### Development | ||
- `cd` into the repository | ||
- run `swift package generate-xcodeproj` (Generates an Xcode project for development) | ||
- run `swift run` to test out any changes | ||
- Run the following command from the project you're using it for: | ||
|
||
```bash | ||
swift run --package-path ../ChangelogProducer/ ChangelogProducer -s 4.3.0b13951 -b develop --verbose | ||
``` | ||
|
||
### Useful resources | ||
- [Building a command line tool using the Swift Package Manager](https://www.swiftbysundell.com/articles/building-a-command-line-tool-using-the-swift-package-manager/) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
// | ||
// ChangelogBuilder.swift | ||
// ChangelogProducerCore | ||
// | ||
// Created by Antoine van der Lee on 16/01/2020. | ||
// Copyright © 2020 WeTransfer. All rights reserved. | ||
// | ||
|
||
import Foundation | ||
import OctoKit | ||
|
||
struct ChangelogBuilder { | ||
let items: [ChangelogItem] | ||
|
||
func build() -> String { | ||
return items | ||
.compactMap { $0.title } | ||
.filter { !$0.lowercased().contains("#trivial") } | ||
.map { "- \($0)" } | ||
.joined(separator: "\n") | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
// | ||
// ChangelogItemsFactory.swift | ||
// ChangelogProducerCore | ||
// | ||
// Created by Antoine van der Lee on 16/01/2020. | ||
// Copyright © 2020 WeTransfer. All rights reserved. | ||
// | ||
|
||
import Foundation | ||
import OctoKit | ||
|
||
struct ChangelogItemsFactory { | ||
let octoKit: Octokit | ||
let pullRequests: [PullRequest] | ||
let project: GITProject | ||
|
||
func items(using session: URLSession = URLSession.shared) -> [ChangelogItem] { | ||
return pullRequests.flatMap { pullRequest -> [ChangelogItem] in | ||
let issuesResolver = IssuesResolver(octoKit: octoKit, project: project, input: pullRequest) | ||
guard let resolvedIssues = issuesResolver.resolve(using: session), !resolvedIssues.isEmpty else { | ||
return [ChangelogItem(input: pullRequest, closedBy: pullRequest)] | ||
} | ||
return resolvedIssues.map { issue -> ChangelogItem in | ||
return ChangelogItem(input: issue, closedBy: pullRequest) | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,20 +1,67 @@ | ||
// | ||
// ChangelogProducer.swift | ||
// | ||
// ChangelogProducerCore | ||
// | ||
// Created by Antoine van der Lee on 10/01/2020. | ||
// Copyright © 2020 WeTransfer. All rights reserved. | ||
// | ||
|
||
import Foundation | ||
import OctoKit | ||
import SPMUtility | ||
|
||
public final class ChangelogProducer { | ||
private let arguments: [String] | ||
|
||
public init(arguments: [String] = CommandLine.arguments) { | ||
self.arguments = arguments | ||
enum Error: Swift.Error { | ||
case missingDangerToken | ||
} | ||
|
||
public func run() throws { | ||
print("Hello world") | ||
let octoKit: Octokit | ||
let base: Branch | ||
let latestRelease: Release | ||
let project: GITProject | ||
|
||
public init( | ||
environment: [String: String] = ProcessInfo.processInfo.environment, | ||
arguments: [String] = ProcessInfo.processInfo.arguments) throws { | ||
let parser = ArgumentParser(usage: "<options>", overview: "Create a changelog for GitHub repositories") | ||
let sinceTag = parser.add(option: "--sinceTag", shortName: "-s", kind: String.self, usage: "The tag to use as a base") | ||
let baseBranch = parser.add(option: "--baseBranch", shortName: "-b", kind: String.self, usage: "The base branch to compare with") | ||
let verbose = parser.add(option: "--verbose", kind: Bool.self, usage: "Show extra logging for debugging purposes") | ||
|
||
guard let gitHubAPIToken = environment["DANGER_GITHUB_API_TOKEN"] else { | ||
throw Error.missingDangerToken | ||
} | ||
|
||
let config = TokenConfiguration(gitHubAPIToken) | ||
octoKit = Octokit(config) | ||
|
||
// The first argument is always the executable, drop it | ||
let arguments = Array(arguments.dropFirst()) | ||
let parsedArguments = try parser.parse(arguments) | ||
|
||
Log.isVerbose = parsedArguments.get(verbose) ?? false | ||
|
||
if let tag = parsedArguments.get(sinceTag) { | ||
latestRelease = try Release(tag: tag) | ||
} else { | ||
latestRelease = try Release.latest() | ||
} | ||
base = parsedArguments.get(baseBranch) ?? "master" | ||
project = GITProject.current() | ||
} | ||
|
||
@discardableResult public func run(using session: URLSession = URLSession.shared) throws -> String { | ||
Log.debug("Latest release is \(latestRelease.tag)") | ||
|
||
let pullRequestsFetcher = PullRequestFetcher(octoKit: octoKit, base: base, project: project) | ||
let pullRequests = try pullRequestsFetcher.fetchAllAfter(latestRelease, using: session) | ||
let items = ChangelogItemsFactory(octoKit: octoKit, pullRequests: pullRequests, project: project).items(using: session) | ||
let changelog = ChangelogBuilder(items: items).build() | ||
|
||
Log.debug("Generated changelog:\n") | ||
Log.message(changelog) | ||
|
||
return changelog | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
// | ||
// Log.swift | ||
// ChangelogProducerCore | ||
// | ||
// Created by Antoine van der Lee on 10/01/2020. | ||
// Copyright © 2020 WeTransfer. All rights reserved. | ||
// | ||
|
||
import Foundation | ||
|
||
struct Log { | ||
static var isVerbose: Bool = false | ||
|
||
static func debug(_ message: Any) { | ||
guard isVerbose else { return } | ||
print(message) | ||
} | ||
|
||
static func message(_ message: Any) { | ||
print(message) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
// | ||
// Shell.swift | ||
// ChangelogProducerCore | ||
// | ||
// Created by Antoine van der Lee on 10/01/2020. | ||
// Copyright © 2020 WeTransfer. All rights reserved. | ||
// | ||
|
||
import Foundation | ||
|
||
extension Process { | ||
public func shell(command: String) -> String { | ||
launchPath = "/bin/bash" | ||
arguments = ["-c", command] | ||
|
||
let outputPipe = Pipe() | ||
standardOutput = outputPipe | ||
launch() | ||
|
||
let data = outputPipe.fileHandleForReading.readDataToEndOfFile() | ||
guard let outputData = String(data: data, encoding: String.Encoding.utf8) else { return "" } | ||
|
||
return outputData.reduce("") { (result, value) in | ||
return result + String(value) | ||
} | ||
} | ||
} | ||
|
||
protocol ShellExecuting { | ||
@discardableResult static func execute(_ command: String) -> String | ||
} | ||
|
||
private enum Shell: ShellExecuting { | ||
@discardableResult static func execute(_ command: String) -> String { | ||
return Process().shell(command: command) | ||
} | ||
} | ||
|
||
/// Adds a `shell` property which defaults to `Shell.self`. | ||
protocol ShellInjectable { } | ||
|
||
extension ShellInjectable { | ||
static var shell: ShellExecuting.Type { ShellInjector.shell } | ||
} | ||
|
||
enum ShellInjector { | ||
static var shell: ShellExecuting.Type = Shell.self | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
// | ||
// IssuesResolver.swift | ||
// ChangelogProducerCore | ||
// | ||
// Created by Antoine van der Lee on 10/01/2020. | ||
// Copyright © 2020 WeTransfer. All rights reserved. | ||
// | ||
|
||
import Foundation | ||
import OctoKit | ||
|
||
struct IssuesResolver { | ||
let octoKit: Octokit | ||
let project: GITProject | ||
let input: ChangelogInput | ||
|
||
func resolve(using session: URLSession = URLSession.shared) -> [Issue]? { | ||
guard let resolvedIssueNumbers = input.body?.resolvingIssues(), !resolvedIssueNumbers.isEmpty else { | ||
return nil | ||
} | ||
return issues(for: resolvedIssueNumbers, using: session) | ||
} | ||
|
||
private func issues(for issueNumbers: [Int], using session: URLSession) -> [Issue] { | ||
var issues: [Issue] = [] | ||
let dispatchGroup = DispatchGroup() | ||
for issueNumber in issueNumbers { | ||
dispatchGroup.enter() | ||
octoKit.issue(session, owner: project.organisation, repository: project.repository, number: issueNumber) { response in | ||
switch response { | ||
case .success(let issue): | ||
issues.append(issue) | ||
case .failure(let error): | ||
print("Fetching issue \(issueNumber) failed with \(error)") | ||
} | ||
dispatchGroup.leave() | ||
} | ||
} | ||
dispatchGroup.wait() | ||
return issues | ||
} | ||
} | ||
|
||
extension String { | ||
|
||
/// Extracts the resolved issues from a Pull Request body. | ||
func resolvingIssues() -> [Int] { | ||
var resolvedIssues = Set<Int>() | ||
|
||
let splits = split(separator: "#") | ||
|
||
let issueClosingKeywords = [ | ||
"close ", | ||
"closes ", | ||
"closed ", | ||
"fix ", | ||
"fixes ", | ||
"fixed ", | ||
"resolve ", | ||
"resolves ", | ||
"resolved " | ||
] | ||
|
||
for (index, split) in splits.enumerated() { | ||
let lowerCaseSplit = split.lowercased() | ||
|
||
for keyword in issueClosingKeywords { | ||
if lowerCaseSplit.hasSuffix(keyword) { | ||
guard index + 1 <= splits.count - 1 else { break } | ||
let nextSplit = splits[index + 1] | ||
|
||
let numberPrefixString = nextSplit.prefix { (character) -> Bool in | ||
return character.isNumber | ||
} | ||
|
||
if !numberPrefixString.isEmpty, let numberPrefix = Int(numberPrefixString.description) { | ||
resolvedIssues.insert(numberPrefix) | ||
break | ||
} else { | ||
continue | ||
} | ||
} | ||
} | ||
} | ||
|
||
return Array(resolvedIssues) | ||
} | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't the copyright be included in the files?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point, I'll add that!