diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index fcfc7c39..b4070118 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -16,6 +16,8 @@ jobs: needs: ruby-versions name: ${{ matrix.os }} ${{ matrix.ruby }} ${{ matrix.env }} runs-on: ${{ matrix.os }} + env: + BUNDLE_WITHOUT: release strategy: fail-fast: false matrix: diff --git a/.github/workflows/push_gem.yml b/.github/workflows/push_gem.yml new file mode 100644 index 00000000..cb4a260e --- /dev/null +++ b/.github/workflows/push_gem.yml @@ -0,0 +1,85 @@ +name: Publish + +on: + workflow_run: + workflows: [CI] + types: [completed] + +permissions: + contents: read + +jobs: + check: + runs-on: ubuntu-latest + outputs: + run_publish: ${{ steps.precheck.outputs.run_publish }} + + steps: + - uses: actions/checkout@v5 + + - name: Set up Ruby + uses: ruby/setup-ruby@v1 + with: + ruby-version: "3.4" + bundler-cache: true + + - id: precheck + name: Release precheck + run: bundle exec rake ci:check_release + + push: + needs: check + + if: | + needs.check.outputs.run_publish == 'true' && + github.repository == 'ruby/json' && + github.ref_name == github.event.repository.default_branch + runs-on: ubuntu-latest + + environment: + name: rubygems.org + url: https://rubygems.org/gems/json + + permissions: + contents: write + id-token: write + + strategy: + matrix: + ruby: ["ruby", "jruby"] + + steps: + - name: Harden Runner + uses: step-security/harden-runner@ec9f2d5744a09debf3a187a3f4f675c53b671911 # v2.13.0 + with: + egress-policy: audit + + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + + - name: Set up Ruby + uses: ruby/setup-ruby@eaecf785f6a34567a6d97f686bbb7bccc1ac1e5c # v1.237.0 + with: + ruby-version: ${{ matrix.ruby }} + bundler-cache: true + + # https://github.com/rubygems/rubygems/issues/5882 + - name: Install dependencies and build for JRuby + run: | + sudo apt install default-jdk maven + gem update --system + gem install ruby-maven rake-compiler --no-document + rake compile + if: matrix.ruby == 'jruby' + + - name: Install dependencies + run: bundle install --jobs 4 --retry 3 + + - name: Publish to RubyGems + uses: rubygems/release-gem@a25424ba2ba8b387abc8ef40807c2c85b96cbe32 # v1.1.1 + + - name: Create GitHub release + run: | + bundle exec rake ci:create_release + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + if: matrix.ruby != 'jruby' diff --git a/Gemfile b/Gemfile index 98956c7e..f93eed21 100644 --- a/Gemfile +++ b/Gemfile @@ -10,12 +10,17 @@ group :development do gem "test-unit" gem "test-unit-ruby-core" gem "all_images", "~> 0" unless RUBY_PLATFORM =~ /java/ +end + +group :release do + gem "net-http" + gem "uri" +end - if ENV['BENCHMARK'] - gem "benchmark-ips" - unless RUBY_PLATFORM =~ /java/ - gem "oj" - gem "rapidjson" - end +if ENV['BENCHMARK'] + gem "benchmark-ips" + unless RUBY_PLATFORM =~ /java/ + gem "oj" + gem "rapidjson" end end diff --git a/Rakefile b/Rakefile index 57b1d0ec..c43acbc6 100644 --- a/Rakefile +++ b/Rakefile @@ -12,6 +12,69 @@ PKG_VERSION = File.foreach(File.join(__dir__, "lib/json/version.rb")) do | /^\s*VERSION\s*=\s*'(.*)'/ =~ line and break $1 end rescue nil +module CI + extend self + + def gem_published?(name, version) + require 'net/https' + require 'uri' + uri = URI.parse("https://rubygems.org/api/v2/rubygems/#{name}/versions/#{version}.json") + Net::HTTP.get_response(uri).is_a?(Net::HTTPSuccess) + end + + def changelog(version) + changelog_lines = File.readlines(File.expand_path("CHANGES.md", __dir__)) + changelog_lines = changelog_lines.drop_while { |line| !(line.start_with?("### ") && line.include?("(#{version})")) } + if changelog_lines.empty? + return false + end + changelog_lines.shift + changelog_lines = changelog_lines.take_while { |line| !(line.start_with?("### ") ) } + changelog_lines.join + end + + def prerelease?(version) + !version.match?(/\A[\d.]+\z/) + end +end + +namespace :ci do + task :check_release do + unless PKG_VERSION + abort("Gem version couldn't be read") + end + + if CI.gem_published?("json", PKG_VERSION) + $stderr.puts "Version #{PKG_VERSION} was already released. Nothing to do." + exit 0 + end + + if changelog = CI.changelog(PKG_VERSION) + puts "Changelog:" + puts changelog + else + abort("Could not find version #{PKG_VERSION} in CHANGES.md") + end + + if ENV["GITHUB_OUTPUT"] + $stderr.puts "Triggering release" + File.open(ENV["GITHUB_OUTPUT"], "a+") do |f| + f.puts "run_publish=true" + end + end + end + + task :create_release do + tag = "v#{PKG_VERSION}" + args = [ + "--title", tag, + "--notes", changelog, + ] + args << "--prerelease" << "--latest=false" if CI.prerelease?(PKG_VERSION) + system("gh", "release", "create", tag, "--draft", *args) + end +end + JAVA_DIR = "java/src/json/ext" JAVA_RAGEL_PATH = "#{JAVA_DIR}/ParserConfig.rl" JAVA_PARSER_SRC = "#{JAVA_DIR}/ParserConfig.java"