diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 0000000..1bb915b --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1 @@ +* @DripEmail/developers diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..ca79ca5 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,6 @@ +version: 2 +updates: + - package-ecosystem: github-actions + directory: / + schedule: + interval: weekly diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 57a18fe..ab88833 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -4,6 +4,14 @@ on: push: branches: [main] pull_request: + workflow_call: + +permissions: + contents: read + +concurrency: + group: ci-${{ github.ref }} + cancel-in-progress: ${{ github.event_name == 'pull_request' }} jobs: test: @@ -11,10 +19,12 @@ jobs: strategy: fail-fast: false matrix: - ruby: ["3.1", "3.2", "3.3", "3.4"] + ruby: ["3.2", "3.3", "3.4", "4.0"] steps: - - uses: actions/checkout@v4 - - uses: ruby/setup-ruby@v1 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false + - uses: ruby/setup-ruby@14594264cd68ce8a2345dd349bc3d138a4ef85c8 # v1.327.0 with: ruby-version: ${{ matrix.ruby }} bundler-cache: true @@ -28,8 +38,28 @@ jobs: nix: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 - - uses: DeterminateSystems/determinate-nix-action@v3 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false + - uses: DeterminateSystems/determinate-nix-action@d0c908e6cbe9f89f36ed8205a3ab6f092636916a # v3.23.1 - run: nix develop --command bundle install - run: nix develop --command bundle exec rake test - run: nix develop --command bundle exec rubocop + + workflows: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false + - uses: DeterminateSystems/determinate-nix-action@d0c908e6cbe9f89f36ed8205a3ab6f092636916a # v3.23.1 + - run: nix develop --command actionlint + - run: nix develop --command zizmor --offline .github/workflows + + ci-ok: + if: always() + needs: [test, nix, workflows] + runs-on: ubuntu-latest + steps: + - if: contains(needs.*.result, 'failure') || contains(needs.*.result, 'cancelled') || contains(needs.*.result, 'skipped') + run: exit 1 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..2136d82 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,73 @@ +name: Release + +on: + push: + tags: ["v*"] + +permissions: {} + +concurrency: + group: release-${{ github.ref }} + cancel-in-progress: false + +jobs: + test: + uses: ./.github/workflows/ci.yml + permissions: + contents: read + + release: + needs: test + runs-on: ubuntu-latest + environment: release + permissions: + contents: write + id-token: write + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + fetch-depth: 0 + persist-credentials: false + - uses: ruby/setup-ruby@14594264cd68ce8a2345dd349bc3d138a4ef85c8 # v1.327.0 + with: + ruby-version: "3.4" + - run: bundle install + + - name: Verify tagged commit is on main + run: | + if ! git merge-base --is-ancestor "${GITHUB_SHA}" origin/main; then + echo "tag ${GITHUB_REF_NAME} (${GITHUB_SHA}) is not on main" >&2 + exit 1 + fi + + - name: Verify tag matches Drip::VERSION + run: | + version="$(bundle exec ruby -Ilib -e 'require "drip/version"; print Drip::VERSION')" + if [ "${GITHUB_REF_NAME}" != "v${version}" ]; then + echo "tag ${GITHUB_REF_NAME} does not match Drip::VERSION v${version}" >&2 + exit 1 + fi + + - name: Extract release notes from CHANGELOG.md + run: | + version="${GITHUB_REF_NAME#v}" + awk -v v="$version" ' + /^## \[/ { in_section = index($0, "## [" v "]") == 1; next } + in_section { print } + ' CHANGELOG.md > "${RUNNER_TEMP}/release-notes.md" + if ! grep -q '[^[:space:]]' "${RUNNER_TEMP}/release-notes.md"; then + echo "no CHANGELOG.md section found for ${version}" >&2 + exit 1 + fi + + - uses: rubygems/release-gem@7f9650160c1a4e7989fdc9855807bdbd421d8b6b # v1.4.1 + + - name: Create GitHub release + env: + GH_TOKEN: ${{ github.token }} + run: | + gh release create "${GITHUB_REF_NAME}" pkg/*.gem \ + --repo "${GITHUB_REPOSITORY}" \ + --title "${GITHUB_REF_NAME}" \ + --notes-file "${RUNNER_TEMP}/release-notes.md" \ + --verify-tag diff --git a/.rubocop.yml b/.rubocop.yml index 3d7de94..e49c468 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -4,7 +4,7 @@ plugins: inherit_from: .rubocop_todo.yml AllCops: - TargetRubyVersion: '3.1' + TargetRubyVersion: '3.2' NewCops: enable Exclude: - 'test/fixtures/**/*' diff --git a/CHANGELOG.md b/CHANGELOG.md index 81cb252..e79827b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,7 +8,11 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. [main]: https://github.com/DripEmail/drip-ruby/compare/v3.5.0...HEAD -- Your contribution here! +### Changed +- Raised `required_ruby_version` to `>= 3.2`; Ruby 3.1 is no longer supported. +- CI runs the test suite on Ruby 3.2, 3.3, 3.4, and 4.0. +- Releases are published from GitHub Actions when a `v*` tag on `main` is + pushed, after the CI suite passes. ## [3.5.0] - 2026-07-10 diff --git a/README.md b/README.md index b660979..4d03639 100644 --- a/README.md +++ b/README.md @@ -235,3 +235,14 @@ subscriber.email 3. Commit your changes (`git commit -am 'Add some feature'`) 4. Push to the branch (`git push origin my-new-feature`) 5. Create a new Pull Request + +## Releasing + +1. Set `Drip::VERSION` in `lib/drip/version.rb`. +2. Move the `[Unreleased]` entries in `CHANGELOG.md` under a new `## [x.y.z] - YYYY-MM-DD` heading. +3. Merge to `main`. +4. From an up-to-date `main`, tag and push: `git tag -a vX.Y.Z -m vX.Y.Z && git push origin vX.Y.Z`. + +Pushing the tag triggers `.github/workflows/release.yml`, which checks that the +tag matches `Drip::VERSION`, publishes the gem to RubyGems, and creates the +GitHub release with the matching `CHANGELOG.md` section as its notes. diff --git a/drip-ruby.gemspec b/drip-ruby.gemspec index 26450ce..956f321 100644 --- a/drip-ruby.gemspec +++ b/drip-ruby.gemspec @@ -18,7 +18,7 @@ Gem::Specification.new do |spec| spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) } spec.require_paths = ["lib"] - spec.required_ruby_version = '>= 3.1' + spec.required_ruby_version = '>= 3.2' spec.metadata['rubygems_mfa_required'] = 'true' end diff --git a/flake.nix b/flake.nix index 6593936..b679f49 100644 --- a/flake.nix +++ b/flake.nix @@ -14,10 +14,20 @@ { devShells.default = pkgs.mkShell { packages = [ - pkgs.ruby_3_3 + pkgs.actionlint + pkgs.bash-completion + pkgs.bashInteractive pkgs.bundler + pkgs.curl + pkgs.gh + pkgs.git + pkgs.jq pkgs.libyaml + pkgs.pinact pkgs.pkg-config + pkgs.ruby_3_3 + pkgs.shellcheck + pkgs.zizmor ]; shellHook = '' diff --git a/lib/drip/client.rb b/lib/drip/client.rb index 85c900f..1e17438 100644 --- a/lib/drip/client.rb +++ b/lib/drip/client.rb @@ -67,9 +67,9 @@ def initialize(options = {}) yield(@config) if block_given? end - def generate_resource(key, *args) + def generate_resource(key, *) warn "[DEPRECATED] Drip::Client#generate_resource is deprecated and will be removed in a future version" - private_generate_resource(key, *args) + private_generate_resource(key, *) end def content_type