diff --git a/.github/ISSUE_TEMPLATE/Bug_report.md b/.github/ISSUE_TEMPLATE/Bug_report.md new file mode 100644 index 00000000..06efdcbd --- /dev/null +++ b/.github/ISSUE_TEMPLATE/Bug_report.md @@ -0,0 +1,31 @@ +--- +name: Bug report +about: Create a bug report + +--- + + + + +# Bug report + +**Current behavior:** + + +**Expected behavior:** + + +**Steps to reproduce current behavior:** + + + +* Client setup and the EWS operation call (the Ruby code you ran): + +* The SOAP request Viewpoint built (or just the part that's wrong): + +* The response you got back (body, and for a transport issue the status and headers): + +**System information:** + +* ruby version: +* viewpoint version: diff --git a/.github/ISSUE_TEMPLATE/Feature_request.md b/.github/ISSUE_TEMPLATE/Feature_request.md new file mode 100644 index 00000000..3ed4778d --- /dev/null +++ b/.github/ISSUE_TEMPLATE/Feature_request.md @@ -0,0 +1,26 @@ +--- +name: Feature request +about: Suggest a new feature for viewpoint + +--- + + + +## Feature request + + + +**Motivation for this feature:** + + + +**Proposed implementation:** + + + +**Would this introduce a breaking change?** + + + +**Are you willing to work on this yourself?** +yes diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 00000000..f3784843 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,12 @@ +**What kind of change is this?** + + + +**Did you add tests for your changes?** + +**Summary of changes** + + + + +**Other information** diff --git a/.github/dependabot.yml b/.github/dependabot.yml index f33a02cd..2db3eb4e 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -10,3 +10,5 @@ updates: directory: "/" schedule: interval: weekly + cooldown: + default-days: 7 diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 00000000..f7fa17d4 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,79 @@ +name: Ruby + +on: + - push + - pull_request + +permissions: + contents: read # checkout only, nothing else + +jobs: + audit: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false + - uses: ruby/setup-ruby@95ef2b042f9d7a56d8268cba8559e2842e2ad01b # v1.321.0 + with: + ruby-version: "3.4" + bundler-cache: true + - name: Audit dependencies + run: bundle exec bundle-audit check --update + - name: Audit Ruby runtime + # CVE-2026-41316 is an ERB flaw fixed in Ruby 4.0.3 and not yet backported. + # Ignored on affected rubies only. See: + # https://www.ruby-lang.org/en/news/2026/04/21/erb-cve-2026-41316/ + # https://github.com/advisories/GHSA-q339-8rmv-2mhv + run: | + ignore="" + if ruby -e 'exit 1 unless Gem::Version.new(RUBY_VERSION) < Gem::Version.new("4.0.3")'; then + ignore="--ignore CVE-2026-41316" + fi + bundle exec ruby-audit check $ignore + + zizmor: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false + - name: Audit workflows + uses: zizmorcore/zizmor-action@70fb788f84895a7701f5643d103d587e460b5c99 # v0.6.3 + with: + advanced-security: false # fail the build on findings instead of uploading SARIF + + lint: + # Advisory-only for the first pass: the legacy codebase has many + # pre-existing RuboCop offenses; a dedicated cleanup pass will follow. + continue-on-error: true + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false + - uses: ruby/setup-ruby@95ef2b042f9d7a56d8268cba8559e2842e2ad01b # v1.321.0 + with: + ruby-version: "3.4" + bundler-cache: true + - name: RuboCop + run: bundle exec rubocop --format github + + test: + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + os: [ubuntu-latest, windows-latest] + ruby: ['3.0', '3.1', '3.2', '3.3', '3.4', '4.0'] + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false + - name: Set up Ruby + uses: ruby/setup-ruby@95ef2b042f9d7a56d8268cba8559e2842e2ad01b # v1.321.0 + with: + ruby-version: ${{ matrix.ruby }} + bundler-cache: true # bundle installs and caches dependencies + - name: Run tests + run: bundle exec rspec diff --git a/.github/workflows/gem_push.yml b/.github/workflows/gem_push.yml new file mode 100644 index 00000000..ced701cd --- /dev/null +++ b/.github/workflows/gem_push.yml @@ -0,0 +1,22 @@ +name: Push gem +on: + release: + types: [published] +jobs: + push: + runs-on: ubuntu-latest + permissions: + id-token: write + contents: write + environment: release + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false + - uses: ruby/setup-ruby@95ef2b042f9d7a56d8268cba8559e2842e2ad01b # v1.321.0 + with: + ruby-version: "3" + bundler-cache: false + - name: Install dependencies + run: bundle install + - uses: rubygems/release-gem@7f9650160c1a4e7989fdc9855807bdbd421d8b6b # v1.4.1 diff --git a/.github/workflows/ruby.yml b/.github/workflows/ruby.yml deleted file mode 100644 index 1f7071a6..00000000 --- a/.github/workflows/ruby.yml +++ /dev/null @@ -1,33 +0,0 @@ -# This workflow uses actions that are not certified by GitHub. -# They are provided by a third-party and are governed by -# separate terms of service, privacy policy, and support -# documentation. -# This workflow will download a prebuilt Ruby version, install dependencies and run tests with Rake -# For more information see: https://github.com/marketplace/actions/setup-ruby-jruby-and-truffleruby - -name: Ruby - -on: - - push - - pull_request - -permissions: - contents: read - -jobs: - test: - - runs-on: ubuntu-latest - strategy: - matrix: - ruby-version: ['2.7', '3.0', '3.1', '3.2', '3.3'] - - steps: - - uses: actions/checkout@v4 - - name: Set up Ruby - uses: ruby/setup-ruby@v1 - with: - ruby-version: ${{ matrix.ruby-version }} - bundler-cache: true # runs 'bundle install' and caches installed gems automatically - - name: Run tests - run: bundle exec rspec diff --git a/.rubocop.yml b/.rubocop.yml new file mode 100644 index 00000000..0e7034c5 --- /dev/null +++ b/.rubocop.yml @@ -0,0 +1,22 @@ +AllCops: + TargetRubyVersion: 3.0 + SuggestExtensions: true + +Gemspec/RequireMFA: + Enabled: true + +Layout/FirstHashElementIndentation: + EnforcedStyle: consistent + +Layout/HashAlignment: + EnforcedHashRocketStyle: table + +RSpec/ContextWording: + Enabled: false + +Style/BlockDelimiters: + EnforcedStyle: semantic + +Style/HashSyntax: + EnforcedStyle: ruby19 + EnforcedShorthandSyntax: never diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 00000000..1a588142 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,3 @@ +# Changelog + +## [Unreleased] diff --git a/Gemfile b/Gemfile index 08385189..8159d7d2 100644 --- a/Gemfile +++ b/Gemfile @@ -7,4 +7,7 @@ group :development do gem 'rb-inotify', :require => false gem 'turn' gem "pry-nav" + gem 'rubocop', :require => false + gem "bundler-audit", "~> 0.9.3", require: false + gem "ruby_audit", "~> 3.1", require: false if RUBY_VERSION >= "3.1.0" end diff --git a/RELEASING.md b/RELEASING.md new file mode 100644 index 00000000..91020e80 --- /dev/null +++ b/RELEASING.md @@ -0,0 +1,19 @@ +_You'll need write access to the repository to create a release. Publishing is handled automatically via [trusted publishing](https://guides.rubygems.org/trusted-publishing/)._ + +## Cutting a release + +1. On your release branch (e.g. `main`, `v1.x`), edit [CHANGELOG.md](https://github.com/WinRb/Viewpoint/blob/main/CHANGELOG.md) to finalize the new version number and list of all changes. +2. Bump [VERSION](https://github.com/WinRb/Viewpoint/blob/main/VERSION) to the version you picked in previous step. +3. **Final check**: make sure all tests are green, and that `gem build viewpoint.gemspec` succeeds. If not, merge any fixes back to the release branch and go to step 1. +4. [Draft a new release](https://github.com/WinRb/Viewpoint/releases/new) on Github. + - In the "Choose a tag" field, type the version tag - e.g. `v1.2.1` - and select "Create new tag on publish". + - Use `v[version]` for the release title, and copy the changelog into the release notes. + - Click "Publish release". Github creates and pushes the tag, which triggers the release workflow. +5. Publishing to RubyGems.org is fully automated. The [Push gem workflow](https://github.com/WinRb/Viewpoint/actions/workflows/gem_push.yml) triggers on the published release and requires approval from a release manager via the `release` environment before credentials are issued. **Before approving**: confirm that CI is green on the release commit. Approve the deployment in the Actions UI and the gem will be built and pushed automatically. + +## Updating minimum ruby version + +- Update `required_ruby_version` in [viewpoint.gemspec](https://github.com/WinRb/Viewpoint/blob/main/viewpoint.gemspec) +- Update the test matrix in [ci.yml](https://github.com/WinRb/Viewpoint/blob/main/.github/workflows/ci.yml) +- Update [README](https://github.com/WinRb/Viewpoint/blob/main/README.md) with the correct support matrix +- Note the updated requirement in [CHANGELOG.md](https://github.com/WinRb/Viewpoint/blob/main/CHANGELOG.md) diff --git a/viewpoint.gemspec b/viewpoint.gemspec index e8cba073..b08783c8 100644 --- a/viewpoint.gemspec +++ b/viewpoint.gemspec @@ -29,4 +29,8 @@ Gem::Specification.new do |s| s.add_runtime_dependency 'logging' s.add_runtime_dependency 'syslog' s.add_runtime_dependency 'mutex_m' + # ostruct and base64 are bundled (not default) gems on modern Rubies; + # declare them so `require` keeps working under `bundle exec`. + s.add_runtime_dependency 'ostruct' + s.add_runtime_dependency 'base64' end