diff --git a/.github/workflows/pr-build.yml b/.github/workflows/pr-build.yml index 20bbc0d4..4eabd25a 100644 --- a/.github/workflows/pr-build.yml +++ b/.github/workflows/pr-build.yml @@ -8,12 +8,8 @@ jobs: build: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - - name: Download bootstrap file - run: wget https://raw.githubusercontent.com/progit/progit2-pub/master/bootstrap.sh - - name: Run bootstrap - run: sh bootstrap.sh - name: Set up Ruby uses: ruby/setup-ruby@v1 with: @@ -21,4 +17,4 @@ jobs: bundler-cache: true # runs 'bundle install' and caches installed gems automatically - name: Build book - run: bundle exec rake book:build_action + run: bundle exec rake book:build diff --git a/.github/workflows/release-on-merge.yml b/.github/workflows/release-on-merge.yml index 3c877b87..7efabb3d 100644 --- a/.github/workflows/release-on-merge.yml +++ b/.github/workflows/release-on-merge.yml @@ -8,13 +8,9 @@ jobs: release: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 with: fetch-depth: 0 - - name: get bootstrap file - run: wget https://raw.githubusercontent.com/progit/progit2-pub/master/bootstrap.sh - - name: run bootstrap - run: sh bootstrap.sh - name: Compute tag name id: compute-tag run: | @@ -31,7 +27,7 @@ jobs: bundler-cache: true # runs 'bundle install' and caches installed gems automatically - name: Build release assets - run: bundle exec rake book:build_action + run: bundle exec rake book:build_build - name: Create release uses: ncipollo/release-action@v1 @@ -39,4 +35,4 @@ jobs: token: ${{ secrets.GITHUB_TOKEN }} tag: ${{ steps.compute-tag.outputs.tagname }} commit: ${{ steps.compute-tag.outputs.branch }} - artifacts: './progit.epub,./progit.mobi,./progit.pdf,./progit.html' + artifacts: './progit.epub,./progit.fb2.zip,./progit.mobi,./progit.pdf,./progit.html' diff --git a/.gitignore b/.gitignore index 724ad441..1d6d2e34 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,7 @@ progit.html progit.pdf progit.pdfmarks progit.epub +progit.fb2.zip progit-kf8.epub progit.mobi contributors.txt diff --git a/Gemfile b/Gemfile index b569101b..751a5956 100644 --- a/Gemfile +++ b/Gemfile @@ -1,22 +1,23 @@ source 'https://rubygems.org' +gem 'ffi', '1.16.3' gem 'rake' -gem 'asciidoctor', '1.5.6.2' +gem 'asciidoctor', '2.0.12' gem 'json' gem 'awesome_print' -gem 'ttfunk', '= 1.5.1' -gem 'asciidoctor-epub3', '1.5.0.alpha.9' +gem 'ttfunk', '1.5.1' +gem 'asciidoctor-fb2' +gem 'asciidoctor-epub3', '1.5.0.alpha.11' gem 'asciidoctor-pdf', '1.5.0.alpha.16' gem 'asciidoctor-pdf-cjk', '~> 0.1.3' -gem 'asciidoctor-pdf-cjk-kai_gen_gothic', '~> 0.1.1' +gem 'asciidoctor-pdf-cjk-kai_gen_gothic', github: 'Sherry520/asciidoctor-pdf-cjk-kai_gen_gothic' gem 'coderay' gem 'pygments.rb' gem 'thread_safe' gem 'epubcheck-ruby' -gem 'kindlegen' +gem 'html-proofer' -gem 'octokit' -gem 'github_changelog_generator', github: 'Furtif/github-changelog-generator' +gem 'kindlegen', '3.1.1' diff --git a/Rakefile b/Rakefile index 9cbfebc1..cb01f185 100644 --- a/Rakefile +++ b/Rakefile @@ -1,7 +1,3 @@ -# coding: utf-8 -require 'octokit' -require 'github_changelog_generator' - def exec_or_raise(command) puts `#{command}` if (! $?.success?) @@ -9,242 +5,169 @@ def exec_or_raise(command) end end -module GitHubChangelogGenerator - - #OPTIONS = %w[ user project token date_format output - # bug_prefix enhancement_prefix issue_prefix - # header merge_prefix issues - # add_issues_wo_labels add_pr_wo_labels - # pulls filter_issues_by_milestone author - # unreleased_only unreleased unreleased_label - # compare_link include_labels exclude_labels - # bug_labels enhancement_labels - # between_tags exclude_tags exclude_tags_regex since_tag max_issues - # github_site github_endpoint simple_list - # future_release release_branch verbose release_url - # base configure_sections add_sections] - - def get_log(&task_block) - options = Parser.default_options - yield(options) if task_block - - options[:user],options[:project] = ENV['TRAVIS_REPO_SLUG'].split('/') - options[:token] = ENV['GITHUB_API_TOKEN'] - options[:unreleased] = false - - generator = Generator.new options - generator.compound_changelog - end - - module_function :get_log -end - namespace :book do - desc 'build basic book formats' - task :build do - puts "Generating contributors list" - exec_or_raise("git shortlog -s --all $translation_origin | grep -v -E '(Straub|Chacon)' | cut -f 2- | sort | column -c 110 > book/contributors.txt") + # Download asciidoctor-pdf-cjk-kai_gen_gothic + exec_or_raise("asciidoctor-pdf-cjk-kai_gen_gothic-install") - # detect if the deployment is using glob - travis = File.read(".travis.yml") - version_string = ENV['TRAVIS_TAG'] || '0' - if travis.match(/file_glob/) - progit_v = "progit_v#{version_string}" - else - progit_v = "progit" - end - text = File.read('progit.asc') - new_contents = text.gsub("$$VERSION$$", version_string).gsub("$$DATE$$", Time.now.strftime("%Y-%m-%d")) - File.open("#{progit_v}.asc", "w") {|file| file.puts new_contents } - - puts "Converting to HTML..." - exec_or_raise("bundle exec asciidoctor #{progit_v}.asc") - puts " -- HTML output at #{progit_v}.html" - - puts "Converting to EPub..." - exec_or_raise("bundle exec asciidoctor-epub3 #{progit_v}.asc") - puts " -- Epub output at #{progit_v}.epub" - - exec_or_raise("epubcheck #{progit_v}.epub") - - puts "Converting to Mobi (kf8)..." - exec_or_raise("bundle exec asciidoctor-epub3 -a ebook-format=kf8 #{progit_v}.asc") - # remove the fake epub that would shadow the really one - exec_or_raise("rm progit*kf8.epub") - puts " -- Mobi output at #{progit_v}.mobi" - - repo = ENV['TRAVIS_REPO_SLUG'] - puts "Converting to PDF... (this one takes a while)" - if (repo == "progit/progit2-zh") - exec_or_raise("asciidoctor-pdf-cjk-kai_gen_gothic-install") - exec_or_raise("bundle exec asciidoctor-pdf -r asciidoctor-pdf-cjk -r asciidoctor-pdf-cjk-kai_gen_gothic -a pdf-style=KaiGenGothicCN #{progit_v}.asc") - elsif (repo == "progit/progit2-ja") - exec_or_raise("asciidoctor-pdf-cjk-kai_gen_gothic-install") - exec_or_raise("bundle exec asciidoctor-pdf -r asciidoctor-pdf-cjk -r asciidoctor-pdf-cjk-kai_gen_gothic -a pdf-style=KaiGenGothicJP #{progit_v}.asc") - elsif (repo == "progit/progit2-zh-tw") - exec_or_raise("asciidoctor-pdf-cjk-kai_gen_gothic-install") - exec_or_raise("bundle exec asciidoctor-pdf -r asciidoctor-pdf-cjk -r asciidoctor-pdf-cjk-kai_gen_gothic -a pdf-style=KaiGenGothicTW #{progit_v}.asc") - elsif (repo == "progit/progit2-ko") - exec_or_raise("asciidoctor-pdf-cjk-kai_gen_gothic-install") - exec_or_raise("bundle exec asciidoctor-pdf -r asciidoctor-pdf-cjk -r asciidoctor-pdf-cjk-kai_gen_gothic -a pdf-style=KaiGenGothicKR #{progit_v}.asc") + # Variables referenced for build + version_string = `git describe --tags --abbrev=0`.chomp + if version_string.empty? + version_string = '0' + else + versions = version_string.split('.') + version_string = versions[0] + '.' + versions[1] + '.' + versions[2].to_i.next.to_s + end + date_string = Time.now.strftime('%Y-%m-%d') + header_hash = `git rev-parse --short HEAD`.strip + + # Check language + repo = File.basename(`git rev-parse --show-toplevel`.chomp) + lang_match = repo.match(/progit2-([a-z-]*)/) + if lang_match + lang = lang_match[1] + else + lang = "en" + end + + begin + if lang == "zh" + params = "-r asciidoctor-pdf-cjk -r asciidoctor-pdf-cjk-kai_gen_gothic -a pdf-style=KaiGenGothicCN --attribute revnumber='#{version_string}' --attribute revdate='#{date_string}' --attribute lang='#{lang}'" + elsif lang == "zh-tw" + params = "-r asciidoctor-pdf-cjk -r asciidoctor-pdf-cjk-kai_gen_gothic -a pdf-style=KaiGenGothicTW --attribute revnumber='#{version_string}' --attribute revdate='#{date_string}' --attribute lang='#{lang}'" + elsif lang == "ja" + params = "-r asciidoctor-pdf-cjk -r asciidoctor-pdf-cjk-kai_gen_gothic -a pdf-style=KaiGenGothicJP --attribute revnumber='#{version_string}' --attribute revdate='#{date_string}' --attribute lang='#{lang}'" + elsif lang == "ko" + params = "-r asciidoctor-pdf-cjk -r asciidoctor-pdf-cjk-kai_gen_gothic -a pdf-style=KaiGenGothicKR --attribute revnumber='#{version_string}' --attribute revdate='#{date_string}' --attribute lang='#{lang}'" else - exec_or_raise("bundle exec asciidoctor-pdf #{progit_v}.asc 2>/dev/null") + params = "--attribute revnumber='#{version_string}' --attribute revdate='#{date_string}'" end - puts " -- PDF output at #{progit_v}.pdf" + rescue => e + puts e.message + puts 'Error when checking repo language(ignored)' end - desc 'tag the repo with the latest version' - task :tag do - api_token = ENV['GITHUB_API_TOKEN'] - if ((api_token) && (ENV['TRAVIS_PULL_REQUEST'] == 'false')) - repo = ENV['TRAVIS_REPO_SLUG'] - @octokit = Octokit::Client.new(:access_token => api_token) - begin - last_version=@octokit.latest_release(repo).tag_name - rescue - last_version="2.1.-1" - end - new_patchlevel= last_version.split('.')[-1].to_i + 1 - new_version="2.1.#{new_patchlevel}" - if (ENV['TRAVIS_BRANCH']=='master') - obj = @octokit.create_tag(repo, new_version, "Version " + new_version, - ENV['TRAVIS_COMMIT'], 'commit', - 'Automatic build', 'automatic@no-domain.org', - Time.now.utc.iso8601) - begin - @octokit.create_ref(repo, "tags/#{new_version}", obj.sha) - rescue - p "the ref already exists ???" - end - p "Created tag #{last_version}" - elsif (ENV['TRAVIS_TAG']) - version = ENV['TRAVIS_TAG'] - changelog = GitHubChangelogGenerator.get_log do |config| - config[:since_tag] = last_version - end - credit_line = "\\* *This Change Log was automatically generated by [github_changelog_generator](https://github.com/skywinder/Github-Changelog-Generator)*" - changelog.gsub!(credit_line, "") - @octokit.create_release(repo, new_version, {:name => "v#{new_version}", :body => changelog}) - p "Created release #{new_version}" + # Check contributors list + # This checks commit hash stored in the header of list against current HEAD + def check_contrib + if File.exist?('book/contributors.txt') + current_head_hash = `git rev-parse --short HEAD`.strip + header = `head -n 1 book/contributors.txt`.strip + # Match regex, then coerce resulting array to string by join + header_hash = header.scan(/[a-f0-9]{7,}/).join + + if header_hash == current_head_hash + puts "Hash on header of contributors list (#{header_hash}) matches the current HEAD (#{current_head_hash})" else - p 'This only runs on a commit to master' + puts "Hash on header of contributors list (#{header_hash}) does not match the current HEAD (#{current_head_hash}), refreshing" + sh "rm book/contributors.txt" + # Reenable and invoke task again + Rake::Task['book/contributors.txt'].reenable + Rake::Task['book/contributors.txt'].invoke end - else - p 'No interaction with GitHub' end end - desc 'convert book to asciidoctor compatibility' - task:convert do - `cp -aR ../progit2/images .` - `sed -i -e 's!/images/!!' .gitignore` - `git add images` - `git rm -r book/*/images` - - chapters = [ - ["01", "introduction" ], - ["02", "git-basics" ], - ["03", "git-branching" ], - ["04", "git-server" ], - ["05", "distributed-git" ], - ["06", "github" ], - ["07", "git-tools" ], - ["08", "customizing-git" ], - ["09", "git-and-other-scms" ], - ["10", "git-internals" ], - ["A", "git-in-other-environments" ], - ["B", "embedding-git" ], - ["C", "git-commands" ] - ] - - crossrefs = {} - chapters.each { | num, title | - if num =~ /[ABC]/ - chap = "#{num}-#{title}" - else - chap = "ch#{num}-#{title}" - end - Dir[File.join ["book","#{num}-#{title}" , "sections","*.asc"]].map { |filename| - File.read(filename).scan(/\[\[(.*?)\]\]/) - }.flatten.each { |ref| - crossrefs[ref] = "#{chap}" - } - } - - headrefs = {} - chapters.each { | num, title | - if num =~ /[ABC]/ - chap = "#{num}-#{title}" - else - chap = "ch#{num}-#{title}" - end - Dir[File.join ["book","#{num}-#{title}", "*.asc"]].map { |filename| - File.read(filename).scan(/\[\[([_a-z0-9]*?)\]\]/) - }.flatten.each { |ref| - headrefs[ref] = "#{chap}" - } - } - - # transform all internal cross refs - chapters.each { | num, title | - if num =~ /[ABC]/ - chap = "#{num}-#{title}" - else - chap = "ch#{num}-#{title}" - end - files = Dir[File.join ["book","#{num}-#{title}" , "sections","*.asc"]] + - Dir[File.join ["book","#{num}-#{title}" ,"1-*.asc"]] - p files - files.each { |filename| - content = File.read(filename) - new_contents = content.gsub(/\[\[([_a-z0-9]*?)\]\]/, '[[r\1]]').gsub( - "→", "→").gsub(/<<([_a-z0-9]*?)>>/) { |match| - ch = crossrefs[$1] - h = headrefs[$1] - # p " #{match} -> #{ch}, #{h}" - if ch - # if local do not add the file - if ch==chap - "<>" - else - "<<#{ch}#r#{$1}>>" - end - elsif h - if h==chap - "<<#{chap}>>" - else - "<<#{h}##{h}>>" - end - else - p "could not match xref #{$1}" - "<<#{$1}>>" - end - } - File.open(filename, "w") {|file| file.puts new_contents } - } - } - - chapters.each { | num, title | - if num =~ /[ABC]/ - chap = "#{num}-#{title}" - else - chap = "ch#{num}-#{title}" - end - Dir[File.join ["book","#{num}-#{title}" ,"1*.asc"]].map { |filename| - content = File.read (filename) - new_contents = content.gsub(/include::(.*?)asc/) {|match| - "include::book/#{num}-#{title}/#{$1}asc"} - `git rm -f #{filename}` - File.open("#{chap}.asc", "w") {|file| - file.puts "[##{chap}]\n" - file.puts new_contents } - `git add "#{chap}.asc"` - } - } + desc 'build basic book formats' + task :build => [:build_html, :build_epub, :build_fb2, :build_mobi, :build_pdf] do + begin + # Run check + Rake::Task['book:check'].invoke + + # Rescue to ignore checking errors + rescue => e + puts e.message + puts 'Error when checking books (ignored)' + end end -end + desc 'build basic book formats (for ci)' + task :ci => [:build_html, :build_epub, :build_fb2, :build_mobi, :build_pdf] do + # Run check, but don't ignore any errors + Rake::Task['book:check'].invoke + end + + desc 'generate contributors list' + file 'book/contributors.txt' do + puts 'Generating contributors list' + sh "echo 'Contributors as of #{header_hash}:\n' > book/contributors.txt" + sh "git shortlog -s HEAD | grep -v -E '(Straub|Chacon|dependabot)' | cut -f 2- | sort | column -c 120 >> book/contributors.txt" + end + desc 'build HTML format' + task :build_html => 'book/contributors.txt' do + check_contrib() + + puts 'Converting to HTML...' + sh "bundle exec asciidoctor #{params} -a data-uri progit.asc" + puts ' -- HTML output at progit.html' + + end + + desc 'build Epub format' + task :build_epub => 'book/contributors.txt' do + check_contrib() + + puts 'Converting to EPub...' + sh "bundle exec asciidoctor-epub3 #{params} progit.asc" + puts ' -- Epub output at progit.epub' + + end + + desc 'build FB2 format' + task :build_fb2 => 'book/contributors.txt' do + check_contrib() + + puts 'Converting to FB2...' + sh "bundle exec asciidoctor-fb2 #{params} progit.asc" + puts ' -- FB2 output at progit.fb2.zip' + + end + + desc 'build Mobi format' + task :build_mobi => 'book/contributors.txt' do + check_contrib() + + puts "Converting to Mobi (kf8)..." + sh "bundle exec asciidoctor-epub3 #{params} -a ebook-format=kf8 progit.asc" + puts " -- Mobi output at progit.mobi" + end + + desc 'build PDF format' + task :build_pdf => 'book/contributors.txt' do + check_contrib() + + puts 'Converting to PDF... (this one takes a while)' + sh "bundle exec asciidoctor-pdf #{params} progit.asc 2>/dev/null" + puts ' -- PDF output at progit.pdf' + end + + desc 'Check generated books' + task :check => [:build_html, :build_epub] do + puts 'Checking generated books' + + sh "htmlproofer progit.html" + sh "epubcheck progit.epub" + end + + desc 'Clean all generated files' + task :clean do + begin + puts 'Removing generated files' + + FileList['book/contributors.txt', 'progit.html', 'progit-kf8.epub', 'progit.epub', 'progit.fb2.zip', 'progit.mobi', 'progit.pdf'].each do |file| + rm file + + # Rescue if file not found + rescue Errno::ENOENT => e + begin + puts e.message + puts 'Error removing files (ignored)' + end + end + end + end + +end task :default => "book:build"