diff --git a/README.md b/README.md index 87740cc..3a1912a 100644 --- a/README.md +++ b/README.md @@ -30,9 +30,14 @@ GitHub Changelog Generator ![GitHub Logo](../master/images/logo.jpg) Since you don't have to fill your `CHANGELOG.md` manually now: just run the script, relax and take a cup of :coffee: before your next release! :tada: ### *What’s the point of a change log?* + To make it easier for users and contributors to see precisely what notable changes have been made between each release (or version) of the project. + ### *Why should I care?* -Because software tools are for people. If you don’t care, why are you contributing to open source? Surely, there must be a kernel (ha!) of care somewhere in that lovely little brain of yours. + +Because software tools are for _people_. "Changelogs make it easier for users and +contributors to see precisely what notable changes have been made between each +release (or version) of the project." :arrow_right: *[http://keepachangelog.com](http://keepachangelog.com)* @@ -71,32 +76,31 @@ See also Troubleshooting. ## Usage -**It's really simple!** -- If your **`git remote`** `origin` refers to your GitHub repo, just go to your project folder and run: +- Run this: - github_changelog_generator - -- Or, run this from anywhere: `github_changelog_generator -u github_username -p github_project` `github_changelog_generator github_username/github_project` -- If you are running it against a repository on a Github Enterprise install, you must specify *both* `--github-site` and `--github-api` command line options: +- For Github Enterprise repos, specify *both* `--github-site` and `--github-api` options: github_changelog_generator --github-site="https://github.yoursite.com" \ --github-api="https://github.yoursite.com/api/v3/" -This generates a changelog to the `CHANGELOG.md` file, with pretty markdown formatting. +This generates a `CHANGELOG.md`, with pretty Markdown formatting. ### Params + Type `github_changelog_generator --help` for details. For more details about params, read the Wiki page: [**Advanced change log generation examples**](https://github.com/skywinder/github-changelog-generator/wiki/Advanced-change-log-generation-examples) ### Params File + In your project root, you can put a params file named `.github_changelog_generator` to override default params: Example: + ``` unreleased=false future-release=5.0.0 @@ -106,6 +110,7 @@ since-tag=1.0.0 ### GitHub token GitHub only allows 50 unauthenticated requests per hour. + Therefore, it's recommended to run this script with authentication by using a **token**. Here's how: @@ -143,7 +148,7 @@ If you have a `HISTORY.md` file in your project, it will automatically be picked You love `rake`? We do, too! So, we've made it even easier for you: we've provided a `rake` task library for your changelog generation. -Just put something like this in your `Rakefile`: +Configure the task in your `Rakefile`: ```ruby require 'github_changelog_generator/task' @@ -154,11 +159,14 @@ GitHubChangelogGenerator::RakeTask.new :changelog do |config| end ``` -All command line options can be passed to the `rake` task as `config` parameters. And since you're naming the `rake` task yourself, you can create as many as you want. +All command-line options can be passed to the `rake` task as `config` +parameters. And since you're naming the `rake` task yourself, you can create +as many as you want. You can look for params names from the [parser source code (#setup_parser)](https://github.com/skywinder/github-changelog-generator/blob/master/lib/github_changelog_generator/parser.rb). For example, to translate the bugs label to Portuguese, instead of setting `config.bugs_label`, you have to set `config.bug_prefix`, and so on. ## Features and advantages of this project + - Generate canonical, neat change log file, followed by [basic change log guidelines](http://keepachangelog.com) :gem: - Optionally generate **Unreleased** changes (closed issues that have not released yet) :dizzy: - **GitHub Enterprise support** via command line options! :factory: @@ -179,12 +187,14 @@ You can look for params names from the [parser source code (#setup_parser)](http ### Alternatives + Here is a [wikipage list of alternatives](https://github.com/skywinder/Github-Changelog-Generator/wiki/Alternatives) that I found. But none satisfied my requirements. *If you know other projects, feel free to edit this Wiki page!* ### Projects using this library + Here's a [wikipage list of projects](https://github.com/skywinder/Github-Changelog-Generator/wiki/Projects-using-Github-Changelog-Generator). If you've used this project in a live app, please let me know! Nothing makes me happier than seeing someone else take my work and go wild with it. diff --git a/lib/github_changelog_generator/options.rb b/lib/github_changelog_generator/options.rb index 0370df5..4938793 100644 --- a/lib/github_changelog_generator/options.rb +++ b/lib/github_changelog_generator/options.rb @@ -26,7 +26,6 @@ module GitHubChangelogGenerator filter_issues_by_milestone frontmatter future_release - git_remote github_endpoint github_site header diff --git a/lib/github_changelog_generator/parser.rb b/lib/github_changelog_generator/parser.rb index dd0c1ba..0b363bb 100755 --- a/lib/github_changelog_generator/parser.rb +++ b/lib/github_changelog_generator/parser.rb @@ -19,8 +19,6 @@ module GitHubChangelogGenerator abort [e, parser].join("\n") end - fetch_user_and_project(options) - abort(parser.banner) unless options[:user] && options[:project] print_options(options) @@ -220,114 +218,8 @@ module GitHubChangelogGenerator issue_prefix: "**Closed issues:**", bug_prefix: "**Fixed bugs:**", enhancement_prefix: "**Implemented enhancements:**", - git_remote: "origin", http_cache: true ) end - - # If `:user` or `:project` not set in options, try setting them - # Valid unnamed parameters: - # 1) in 1 param: repo_name/project - # 2) in 2 params: repo name project - def self.fetch_user_and_project(options) - if options[:user].nil? || options[:project].nil? - user, project = user_and_project_from_git(options, ARGV[0], ARGV[1]) - options[:user] ||= user - options[:project] ||= project - end - end - - # Sets `:user` and `:project` in `options` from CLI arguments or `git remote` - # @param [String] arg0 first argument in cli - # @param [String] arg1 second argument in cli - # @return [Array] user and project, or nil if unsuccessful - def self.user_and_project_from_git(options, arg0 = nil, arg1 = nil) - user, project = user_project_from_option(arg0, arg1, options[:github_site]) - unless user && project - if ENV["RUBYLIB"] =~ /ruby-debug-ide/ - user = "skywinder" - project = "changelog_test" - else - remote = `git config --get remote.#{options[:git_remote]}.url` - user, project = user_project_from_remote(remote) - end - end - - [user, project] - end - - # Returns GitHub username and project from CLI arguments - # - # @param arg0 [String] This parameter takes two forms: Either a full - # GitHub URL, or a 'username/projectname', or - # simply a GitHub username - # @param arg1 [String] If arg0 is given as a username, - # then arg1 can given as a projectname - # @param github_site [String] Domain name of GitHub site - # - # @return [Array, nil] user and project, or nil if unsuccessful - def self.user_project_from_option(arg0, arg1, github_site) - user = nil - project = nil - github_site ||= "github.com" - if arg0 && !arg1 - # this match should parse strings such "https://github.com/skywinder/Github-Changelog-Generator" or - # "skywinder/Github-Changelog-Generator" to user and name - match = /(?:.+#{Regexp.escape(github_site)}\/)?(.+)\/(.+)/.match(arg0) - - begin - param = match[2].nil? - rescue StandardError - puts "Can't detect user and name from first parameter: '#{arg0}' -> exit'" - return - end - if param - return - else - user = match[1] - project = match[2] - end - end - [user, project] - end - - # These patterns match these formats: - # - # ``` - # origin git@github.com:skywinder/Github-Changelog-Generator.git (fetch) - # git@github.com:skywinder/Github-Changelog-Generator.git - # ``` - # - # and - # - # ``` - # origin https://github.com/skywinder/ChangelogMerger (fetch) - # https://github.com/skywinder/ChangelogMerger - # ``` - GIT_REMOTE_PATTERNS = [ - /.*(?:[:\/])(?(?:-|\w|\.)*)\/(?(?:-|\w|\.)*)(?:\.git).*/, - /.*\/(?(?:-|\w|\.)*)\/(?(?:-|\w|\.)*).*/ - ] - - # Returns GitHub username and project from git remote output - # - # @param git_remote_output [String] Output of git remote command - # - # @return [Array] user and project - def self.user_project_from_remote(git_remote_output) - user = nil - project = nil - GIT_REMOTE_PATTERNS.each do |git_remote_pattern| - git_remote_pattern =~ git_remote_output - - if Regexp.last_match - user = Regexp.last_match(:user) - project = Regexp.last_match(:project) - break - end - end - - [user, project] - end end end diff --git a/lib/github_changelog_generator/task.rb b/lib/github_changelog_generator/task.rb index c9dfd6e..cfaa756 100644 --- a/lib/github_changelog_generator/task.rb +++ b/lib/github_changelog_generator/task.rb @@ -48,13 +48,11 @@ module GitHubChangelogGenerator # mimick parse_options options = Parser.default_options - Parser.fetch_user_and_project(options) - OPTIONS.each do |o| v = instance_variable_get("@#{o}") options[o.to_sym] = v unless v.nil? end - + abort "user and project are required." unless options[:user] && options[:project] generator = Generator.new options log = generator.compound_changelog diff --git a/spec/unit/options_spec.rb b/spec/unit/options_spec.rb index 56acde6..c026b32 100644 --- a/spec/unit/options_spec.rb +++ b/spec/unit/options_spec.rb @@ -12,7 +12,7 @@ RSpec.describe GitHubChangelogGenerator::Options do it "raises an error" do expect do described_class.new( - git_remote: "origin", + project: "rails", strength: "super-strength", wisdom: "deep" ) @@ -22,13 +22,13 @@ RSpec.describe GitHubChangelogGenerator::Options do end describe "#[]=(key, value)" do - let(:options) { described_class.new(git_remote: "origin") } + let(:options) { described_class.new(project: "rails") } context "with known options" do it "sets the option value" do expect do - options[:git_remote] = "in the cloud" - end.to change { options[:git_remote] }.to "in the cloud" + options[:project] = "trails" + end.to change { options[:project] }.to "trails" end end diff --git a/spec/unit/parser_spec.rb b/spec/unit/parser_spec.rb index e90900b..de376cf 100644 --- a/spec/unit/parser_spec.rb +++ b/spec/unit/parser_spec.rb @@ -1,83 +1,4 @@ # frozen_string_literal: true describe GitHubChangelogGenerator::Parser do - describe ".user_project_from_remote" do - context "when remote is type 1" do - subject { GitHubChangelogGenerator::Parser.user_project_from_remote("origin https://github.com/skywinder/ActionSheetPicker-3.0 (fetch)") } - it { is_expected.to be_a(Array) } - it { is_expected.to match_array(["skywinder", "ActionSheetPicker-3.0"]) } - end - context "when remote is type 2" do - subject { GitHubChangelogGenerator::Parser.user_project_from_remote("https://github.com/skywinder/ActionSheetPicker-3.0") } - it { is_expected.to be_a(Array) } - it { is_expected.to match_array(["skywinder", "ActionSheetPicker-3.0"]) } - end - context "when remote is type 3" do - subject { GitHubChangelogGenerator::Parser.user_project_from_remote("https://github.com/skywinder/ActionSheetPicker-3.0") } - it { is_expected.to be_a(Array) } - it { is_expected.to match_array(["skywinder", "ActionSheetPicker-3.0"]) } - end - context "when remote is type 4" do - subject { GitHubChangelogGenerator::Parser.user_project_from_remote("origin git@github.com:skywinder/ActionSheetPicker-3.0.git (fetch)") } - it { is_expected.to be_a(Array) } - it { is_expected.to match_array(["skywinder", "ActionSheetPicker-3.0"]) } - end - context "when remote is invalid" do - subject { GitHubChangelogGenerator::Parser.user_project_from_remote("some invalid text") } - it { is_expected.to be_a(Array) } - it { is_expected.to match_array([nil, nil]) } - end - end - describe ".user_project_from_option" do - context "when option is invalid" do - it("should return nil") { expect(GitHubChangelogGenerator::Parser.user_project_from_option("blah", nil, nil)).to be_nil } - end - - context "when option is valid" do - subject { GitHubChangelogGenerator::Parser.user_project_from_option("skywinder/ActionSheetPicker-3.0", nil, nil) } - it { is_expected.to be_a(Array) } - it { is_expected.to match_array(["skywinder", "ActionSheetPicker-3.0"]) } - end - context "when option nil" do - subject { GitHubChangelogGenerator::Parser.user_project_from_option(nil, nil, nil) } - it { is_expected.to be_a(Array) } - it { is_expected.to match_array([nil, nil]) } - end - context "when site is nil" do - subject { GitHubChangelogGenerator::Parser.user_project_from_option("skywinder/ActionSheetPicker-3.0", nil, nil) } - it { is_expected.to be_a(Array) } - it { is_expected.to match_array(["skywinder", "ActionSheetPicker-3.0"]) } - end - context "when site is valid" do - subject { GitHubChangelogGenerator::Parser.user_project_from_option("skywinder/ActionSheetPicker-3.0", nil, "https://codeclimate.com") } - it { is_expected.to be_a(Array) } - it { is_expected.to match_array(["skywinder", "ActionSheetPicker-3.0"]) } - end - context "when second arg is not nil" do - subject { GitHubChangelogGenerator::Parser.user_project_from_option("skywinder/ActionSheetPicker-3.0", "blah", nil) } - it { is_expected.to be_a(Array) } - it { is_expected.to match_array([nil, nil]) } - end - context "when all args is not nil" do - subject { GitHubChangelogGenerator::Parser.user_project_from_option("skywinder/ActionSheetPicker-3.0", "blah", "https://codeclimate.com") } - it { is_expected.to be_a(Array) } - it { is_expected.to match_array([nil, nil]) } - end - end - describe ".fetch_user_and_project" do - before do - stub_const("ARGV", ["https://github.com/skywinder/github-changelog-generator"]) - end - - context do - let(:valid_user) { "initialized_user" } - let(:options) { { user: valid_user } } - let(:options_before_change) { options.dup } - it "should leave user unchanged" do - expect { GitHubChangelogGenerator::Parser.fetch_user_and_project(options) }.to change { options } - .from(options_before_change) - .to(options_before_change.merge(project: "github-changelog-generator")) - end - end - end end