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/rubocop.yml b/.github/workflows/rubocop.yml new file mode 100644 index 0000000..24098bc --- /dev/null +++ b/.github/workflows/rubocop.yml @@ -0,0 +1,26 @@ +name: RuboCop + +on: + push: + branches: [ master ] + pull_request: + branches: [ master ] + +permissions: + contents: read + +jobs: + test: + name: RuboCop + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + - name: Set up Ruby + uses: ruby/setup-ruby@v1 + with: + ruby-version: '3.4' + rubygems: latest + bundler-cache: true + - name: RuboCop + run: bundle exec rubocop -f github diff --git a/.github/workflows/ruby.yml b/.github/workflows/ruby.yml new file mode 100644 index 0000000..3338514 --- /dev/null +++ b/.github/workflows/ruby.yml @@ -0,0 +1,69 @@ +name: Ruby tests + +on: + push: + branches: [ master ] + pull_request: + branches: [ master ] + +permissions: + contents: read + +jobs: + test: + name: Ruby tests + runs-on: ubuntu-latest + + strategy: + matrix: + ruby-version: ['3.1', '3.2', '3.3', '3.4'] + gemfile: [as_7.1, as_7.2, as_8.0] + channel: [stable] + + include: + - ruby-version: '3.2' + gemfile: as_edge + channel: experimental + + - ruby-version: '3.3' + gemfile: as_edge + channel: experimental + + - ruby-version: '3.4' + gemfile: as_edge + channel: experimental + + - ruby-version: 'head' + gemfile: as_7.1 + channel: experimental + - ruby-version: 'head' + gemfile: as_7.2 + channel: experimental + - ruby-version: 'head' + gemfile: as_8.0 + channel: experimental + - ruby-version: 'head' + gemfile: as_edge + channel: experimental + + exclude: + - ruby-version: '3.1' + gemfile: as_8.0 + + - ruby-version: '3.4' + gemfile: as_7.0 + + env: + BUNDLE_GEMFILE: gemfiles/${{ matrix.gemfile }}.gemfile + + continue-on-error: ${{ matrix.channel != 'stable' }} + + steps: + - uses: actions/checkout@v4 + - name: Set up Ruby + uses: ruby/setup-ruby@v1 + with: + ruby-version: ${{ matrix.ruby-version }} + bundler-cache: true + - name: Run tests + run: bundle exec rake test diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ea58eba --- /dev/null +++ b/.gitignore @@ -0,0 +1,13 @@ +.byebug_history +/.bundle/ +/.yardoc +/coverage/ +/doc/ +/Gemfile.lock +/pkg/ +/spec/reports/ +/tmp/ +/_yardoc/ +Gemfile.lock +gemfiles/*.gemfile.lock +gemfiles/.bundle diff --git a/.rubocop.yml b/.rubocop.yml new file mode 100644 index 0000000..64a52b4 --- /dev/null +++ b/.rubocop.yml @@ -0,0 +1,28 @@ +require: + - rubocop-minitest + - rubocop-packaging + - rubocop-performance + - rubocop-rails + - rubocop-rake + +AllCops: + NewCops: enable + TargetRailsVersion: 7.1 + TargetRubyVersion: 3.1 + Exclude: + - .git/**/* + - .github/**/* + - bin/**/* + - gemfiles/**/* + - node_modules/**/* + - tmp/**/* + - vendor/**/* + +Layout/LineLength: + Enabled: false + +Style/ArgumentsForwarding: + Enabled: false + +Style/ClassAndModuleChildren: + Enabled: false diff --git a/Appraisals b/Appraisals new file mode 100644 index 0000000..fb4c3c2 --- /dev/null +++ b/Appraisals @@ -0,0 +1,21 @@ +# frozen_string_literal: true + +appraise 'as-7.1' do + gem 'activestorage', '~> 7.1.0' +end + +appraise 'as-7.2' do + gem 'activestorage', '~> 7.2.0' +end + +appraise 'as-8.0' do + gem 'activestorage', '~> 8.0.0' +end + +appraise 'as-edge' do + gem 'actionpack', git: 'https://github.com/rails/rails.git' + gem 'activejob', git: 'https://github.com/rails/rails.git' + gem 'activerecord', git: 'https://github.com/rails/rails.git' + gem 'activestorage', git: 'https://github.com/rails/rails.git' + gem 'activesupport', git: 'https://github.com/rails/rails.git' +end diff --git a/Gemfile b/Gemfile new file mode 100644 index 0000000..c961039 --- /dev/null +++ b/Gemfile @@ -0,0 +1,22 @@ +# frozen_string_literal: true + +source 'https://rubygems.org' + +# Specify your gem's dependencies in activestorage-colore.gemspec +gemspec + +gem 'appraisal' +gem 'bundler' +gem 'byebug' +gem 'pry' +gem 'rake' +gem 'simplecov' +gem 'webmock' +gem 'yard' + +gem 'rubocop', require: false +gem 'rubocop-minitest', require: false +gem 'rubocop-packaging', require: false +gem 'rubocop-performance', require: false +gem 'rubocop-rails', require: false +gem 'rubocop-rake', require: false diff --git a/Gemfile.lock b/Gemfile.lock new file mode 100644 index 0000000..d49cc6f --- /dev/null +++ b/Gemfile.lock @@ -0,0 +1,191 @@ +PATH + remote: . + specs: + activestorage-colore (2.0.0) + activestorage (>= 7.1) + +GEM + remote: https://rubygems.org/ + specs: + actionpack (8.0.1) + actionview (= 8.0.1) + activesupport (= 8.0.1) + nokogiri (>= 1.8.5) + rack (>= 2.2.4) + rack-session (>= 1.0.1) + rack-test (>= 0.6.3) + rails-dom-testing (~> 2.2) + rails-html-sanitizer (~> 1.6) + useragent (~> 0.16) + actionview (8.0.1) + activesupport (= 8.0.1) + builder (~> 3.1) + erubi (~> 1.11) + rails-dom-testing (~> 2.2) + rails-html-sanitizer (~> 1.6) + activejob (8.0.1) + activesupport (= 8.0.1) + globalid (>= 0.3.6) + activemodel (8.0.1) + activesupport (= 8.0.1) + activerecord (8.0.1) + activemodel (= 8.0.1) + activesupport (= 8.0.1) + timeout (>= 0.4.0) + activestorage (8.0.1) + actionpack (= 8.0.1) + activejob (= 8.0.1) + activerecord (= 8.0.1) + activesupport (= 8.0.1) + marcel (~> 1.0) + activesupport (8.0.1) + base64 + benchmark (>= 0.3) + bigdecimal + concurrent-ruby (~> 1.0, >= 1.3.1) + connection_pool (>= 2.2.5) + drb + i18n (>= 1.6, < 2) + logger (>= 1.4.2) + minitest (>= 5.1) + securerandom (>= 0.3) + tzinfo (~> 2.0, >= 2.0.5) + uri (>= 0.13.1) + addressable (2.8.7) + public_suffix (>= 2.0.2, < 7.0) + appraisal (2.5.0) + bundler + rake + thor (>= 0.14.0) + ast (2.4.2) + base64 (0.2.0) + benchmark (0.4.0) + bigdecimal (3.1.9) + builder (3.3.0) + byebug (11.1.3) + coderay (1.1.3) + concurrent-ruby (1.3.4) + connection_pool (2.5.0) + crack (1.0.0) + bigdecimal + rexml + crass (1.0.6) + docile (1.4.1) + drb (2.2.1) + erubi (1.13.1) + globalid (1.2.1) + activesupport (>= 6.1) + hashdiff (1.1.2) + i18n (1.14.6) + concurrent-ruby (~> 1.0) + json (2.9.1) + language_server-protocol (3.17.0.3) + logger (1.6.5) + loofah (2.24.0) + crass (~> 1.0.2) + nokogiri (>= 1.12.0) + marcel (1.0.4) + method_source (1.1.0) + mini_portile2 (2.8.8) + minitest (5.25.4) + nokogiri (1.18.1) + mini_portile2 (~> 2.8.2) + racc (~> 1.4) + parallel (1.26.3) + parser (3.3.6.0) + ast (~> 2.4.1) + racc + pry (0.15.2) + coderay (~> 1.1) + method_source (~> 1.0) + public_suffix (6.0.1) + racc (1.8.1) + rack (3.1.8) + rack-session (2.1.0) + base64 (>= 0.1.0) + rack (>= 3.0.0) + rack-test (2.2.0) + rack (>= 1.3) + rails-dom-testing (2.2.0) + activesupport (>= 5.0.0) + minitest + nokogiri (>= 1.6) + rails-html-sanitizer (1.6.2) + loofah (~> 2.21) + nokogiri (>= 1.15.7, != 1.16.7, != 1.16.6, != 1.16.5, != 1.16.4, != 1.16.3, != 1.16.2, != 1.16.1, != 1.16.0.rc1, != 1.16.0) + rainbow (3.1.1) + rake (13.2.1) + regexp_parser (2.10.0) + rexml (3.4.0) + rubocop (1.70.0) + json (~> 2.3) + language_server-protocol (>= 3.17.0) + parallel (~> 1.10) + parser (>= 3.3.0.2) + rainbow (>= 2.2.2, < 4.0) + regexp_parser (>= 2.9.3, < 3.0) + rubocop-ast (>= 1.36.2, < 2.0) + ruby-progressbar (~> 1.7) + unicode-display_width (>= 2.4.0, < 4.0) + rubocop-ast (1.37.0) + parser (>= 3.3.1.0) + rubocop-minitest (0.36.0) + rubocop (>= 1.61, < 2.0) + rubocop-ast (>= 1.31.1, < 2.0) + rubocop-packaging (0.5.2) + rubocop (>= 1.33, < 2.0) + rubocop-performance (1.23.1) + rubocop (>= 1.48.1, < 2.0) + rubocop-ast (>= 1.31.1, < 2.0) + rubocop-rails (2.28.0) + activesupport (>= 4.2.0) + rack (>= 1.1) + rubocop (>= 1.52.0, < 2.0) + rubocop-ast (>= 1.31.1, < 2.0) + rubocop-rake (0.6.0) + rubocop (~> 1.0) + ruby-progressbar (1.13.0) + securerandom (0.4.1) + simplecov (0.22.0) + docile (~> 1.1) + simplecov-html (~> 0.11) + simplecov_json_formatter (~> 0.1) + simplecov-html (0.13.1) + simplecov_json_formatter (0.1.4) + thor (1.3.2) + timeout (0.4.3) + tzinfo (2.0.6) + concurrent-ruby (~> 1.0) + unicode-display_width (3.1.3) + unicode-emoji (~> 4.0, >= 4.0.4) + unicode-emoji (4.0.4) + uri (1.0.2) + useragent (0.16.11) + webmock (3.24.0) + addressable (>= 2.8.0) + crack (>= 0.3.2) + hashdiff (>= 0.4.0, < 2.0.0) + yard (0.9.37) + +PLATFORMS + ruby + +DEPENDENCIES + activestorage-colore! + appraisal + bundler + byebug + pry + rake + rubocop + rubocop-minitest + rubocop-packaging + rubocop-performance + rubocop-rails + rubocop-rake + simplecov + webmock + yard + +BUNDLED WITH + 2.6.2 diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..2429292 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2020 Diego Rosario Brogna, 2025 IFAD + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..3e973a4 --- /dev/null +++ b/README.md @@ -0,0 +1,51 @@ +# Active Storage Colore Service + +[![Build Status](https://github.com/ifad/activestorage-colore/actions/workflows/ruby.yml/badge.svg)](https://github.com/ifad/activestorage-colore/actions) +[![RuboCop](https://github.com/ifad/activestorage-colore/actions/workflows/rubocop.yml/badge.svg)](https://github.com/ifad/activestorage-colore/actions/workflows/rubocop.yml) + +Active Storage Colore Service is a Ruby-based client for integrating with the [Colore](https://github.com/ifad/colore) service, which provides functionalities for managing and processing color-related data in Active Storage. + +## Installation + +Add this line to your application's Gemfile: + +```ruby +gem 'activestorage-colore' +``` + +And then execute: + +```sh +bundle install +``` + +## Usage + +To use Active Storage Colore Client, you need to configure it with your Colore service endpoint and any necessary authentication details. + +Here is an example of how to configure and use the client: + +```ruby +require 'activestorage-colore' + +# Configure the client +ActiveStorage::Colore.configure do |config| + config.endpoint = 'https://your-colore-service-endpoint' + config.api_key = 'your-api-key' +end + +# Example usage +color_data = ActiveStorage::Colore.process(image_path) +puts color_data +``` + +## Configuration + +Configuration options include: +- `endpoint`: The URL of your Colore service endpoint. +- `api_key`: Your API key for authenticating with the Colore service. + +## License + +This project is licensed under the MIT License - see the [LICENSE](LICENSE) file +for details. diff --git a/Rakefile b/Rakefile new file mode 100644 index 0000000..e30ffe1 --- /dev/null +++ b/Rakefile @@ -0,0 +1,18 @@ +# frozen_string_literal: true + +require 'rake' +require 'rake/testtask' +require 'rdoc/task' +require 'bundler/gem_tasks' +require 'rubocop/rake_task' + +RuboCop::RakeTask.new + +desc 'Default: run tests.' +task default: %i[test] + +Rake::TestTask.new(:test) do |t| + t.libs << 'lib' << 'test' + t.pattern = 'test/**/*_test.rb' + t.warning = false +end diff --git a/activestorage_colore.gemspec b/activestorage_colore.gemspec index 91e3e10..291bf80 100644 --- a/activestorage_colore.gemspec +++ b/activestorage_colore.gemspec @@ -1,12 +1,28 @@ -Gem::Specification.new do |s| - s.name = %q{activestorage-colore} - s.version = "1.0.0" - s.date = %q{2020-03-03} - s.summary = %q{activestorage service for Colore} - s.files = [ - "lib/active_storage/service/colore_service.rb" - ] - s.authors = ['Diego Rosario Brogna'] - s.email = 'd.brogna@ifad.org' - s.require_paths = ["lib"] -end \ No newline at end of file +# frozen_string_literal: true + +require File.expand_path('lib/activestorage/colore/version', __dir__) + +Gem::Specification.new do |spec| + spec.name = 'activestorage-colore' + spec.version = ActiveStorage::Colore::VERSION + spec.authors = ['Diego Rosario Brogna'] + spec.email = ['d.brogna@ifad.org'] + + spec.summary = 'Active Storage Colore Service' + spec.homepage = 'https://github.com/ifad/activestorage-colore' + spec.license = 'MIT' + + spec.files = Dir.glob('{LICENSE,README.md,lib/**/*.rb}', File::FNM_DOTMATCH) + spec.require_paths = ['lib'] + + spec.metadata = { + 'bug_tracker_uri' => 'https://github.com/ifad/activestorage-colore/issues', + 'homepage_uri' => 'https://github.com/ifad/activestorage-colore', + 'source_code_uri' => 'https://github.com/ifad/activestorage-colore', + 'rubygems_mfa_required' => 'true' + } + + spec.required_ruby_version = '>= 3.1' + + spec.add_dependency 'activestorage', '>= 7.1' +end diff --git a/gemfiles/as_7.1.gemfile b/gemfiles/as_7.1.gemfile new file mode 100644 index 0000000..5a1369f --- /dev/null +++ b/gemfiles/as_7.1.gemfile @@ -0,0 +1,21 @@ +# This file was generated by Appraisal + +source "https://rubygems.org" + +gem "appraisal" +gem "bundler" +gem "byebug" +gem "pry" +gem "rake" +gem "simplecov" +gem "webmock" +gem "yard" +gem "rubocop", require: false +gem "rubocop-minitest", require: false +gem "rubocop-packaging", require: false +gem "rubocop-performance", require: false +gem "rubocop-rails", require: false +gem "rubocop-rake", require: false +gem "activestorage", "~> 7.1.0" + +gemspec path: "../" diff --git a/gemfiles/as_7.2.gemfile b/gemfiles/as_7.2.gemfile new file mode 100644 index 0000000..c7d236c --- /dev/null +++ b/gemfiles/as_7.2.gemfile @@ -0,0 +1,21 @@ +# This file was generated by Appraisal + +source "https://rubygems.org" + +gem "appraisal" +gem "bundler" +gem "byebug" +gem "pry" +gem "rake" +gem "simplecov" +gem "webmock" +gem "yard" +gem "rubocop", require: false +gem "rubocop-minitest", require: false +gem "rubocop-packaging", require: false +gem "rubocop-performance", require: false +gem "rubocop-rails", require: false +gem "rubocop-rake", require: false +gem "activestorage", "~> 7.2.0" + +gemspec path: "../" diff --git a/gemfiles/as_8.0.gemfile b/gemfiles/as_8.0.gemfile new file mode 100644 index 0000000..cc1a791 --- /dev/null +++ b/gemfiles/as_8.0.gemfile @@ -0,0 +1,21 @@ +# This file was generated by Appraisal + +source "https://rubygems.org" + +gem "appraisal" +gem "bundler" +gem "byebug" +gem "pry" +gem "rake" +gem "simplecov" +gem "webmock" +gem "yard" +gem "rubocop", require: false +gem "rubocop-minitest", require: false +gem "rubocop-packaging", require: false +gem "rubocop-performance", require: false +gem "rubocop-rails", require: false +gem "rubocop-rake", require: false +gem "activestorage", "~> 8.0.0" + +gemspec path: "../" diff --git a/gemfiles/as_edge.gemfile b/gemfiles/as_edge.gemfile new file mode 100644 index 0000000..8a0c086 --- /dev/null +++ b/gemfiles/as_edge.gemfile @@ -0,0 +1,25 @@ +# This file was generated by Appraisal + +source "https://rubygems.org" + +gem "appraisal" +gem "bundler" +gem "byebug" +gem "pry" +gem "rake" +gem "simplecov" +gem "webmock" +gem "yard" +gem "rubocop", require: false +gem "rubocop-minitest", require: false +gem "rubocop-packaging", require: false +gem "rubocop-performance", require: false +gem "rubocop-rails", require: false +gem "rubocop-rake", require: false +gem "actionpack", git: "https://github.com/rails/rails.git" +gem "activejob", git: "https://github.com/rails/rails.git" +gem "activerecord", git: "https://github.com/rails/rails.git" +gem "activestorage", git: "https://github.com/rails/rails.git" +gem "activesupport", git: "https://github.com/rails/rails.git" + +gemspec path: "../" diff --git a/lib/active_storage/service/colore_service.rb b/lib/active_storage/service/colore_service.rb deleted file mode 100644 index 915695c..0000000 --- a/lib/active_storage/service/colore_service.rb +++ /dev/null @@ -1,68 +0,0 @@ -module ActiveStorage - class Service::ColoreService < Service - attr_reader :app, :colore_url - - def connection - options = {base_uri: colore_url, app: app} - ::Colore::Client.new(options) - end - - def initialize(app:, public: false, colore_url:, **options) - @app = app - @colore_url = colore_url - @public = true - end - - def upload(key, io, checksum: nil, **options) - connection.create_document({ - doc_id: key, - filename: filename, - content: io.read - }) - end - - def download(key) - connection.get_document({ doc_id: key, version: :current, filename: "file" }).body - end - - def download_chunk(key, range) - "" - end - - def delete(key) - connection.delete_document({ doc_id: key }) - end - - def exist?(key) - !download(key).blank? - end - - def url(key, **options) - instrument :url, key: key do |payload| - generated_url = - if public? - public_url(key, **options) - else - private_url(key, **options) - end - - payload[:url] = generated_url - - generated_url - end - end - - def public? - @public - end - - private - - def public_url(key, **options) - puts options - base = "#{colore_url}/document/#{app}/#{key}/current/#{options[:filename]}" - [base,options[:format]].compact.join(".") - end - - end -end \ No newline at end of file diff --git a/lib/activestorage/colore/version.rb b/lib/activestorage/colore/version.rb new file mode 100644 index 0000000..dd09e95 --- /dev/null +++ b/lib/activestorage/colore/version.rb @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +module ActiveStorage + module Colore + VERSION = '2.0.0' + end +end diff --git a/lib/activestorage/service/colore_service.rb b/lib/activestorage/service/colore_service.rb new file mode 100644 index 0000000..3bdd113 --- /dev/null +++ b/lib/activestorage/service/colore_service.rb @@ -0,0 +1,60 @@ +# frozen_string_literal: true + +module ActiveStorage + class Service + # = Active Storage \Colore \Service + # + # Wraps the Colore Client as an Active Storage service. + # See ActiveStorage::Service for the generic API documentation that applies to all services. + class ColoreService < Service + attr_reader :app, :client, :colore_url + + def initialize(app:, colore_url:, **) # rubocop:disable Lint/MissingSuper + @app = app + @colore_url = colore_url + @client = ::Colore::Client.new(base_uri: colore_url, app: app) + end + + def upload(key, io, **) + connection.create_document( + doc_id: key, + filename: filename, + content: io.read + ) + end + + def download(key) + client.get_document(doc_id: key, version: :current, filename: 'file').body + end + + def download_chunk(_key, _range) + '' + end + + def delete(key) + client.delete_document(doc_id: key) + end + + def exist?(key) + download(key).present? + end + + def url(key, **options) + instrument :url, key: key do |payload| + generated_url = public_url(key, **options) + + payload[:url] = generated_url + + generated_url + end + end + + private + + def public_url(key, **options) + base = "#{colore_url}/document/#{app}/#{key}/current/#{options[:filename]}" + [base, options[:format]].compact.join('.') + end + end + end +end diff --git a/test/activestorage/service/colore_service_test.rb b/test/activestorage/service/colore_service_test.rb new file mode 100644 index 0000000..6496a04 --- /dev/null +++ b/test/activestorage/service/colore_service_test.rb @@ -0,0 +1,10 @@ +# frozen_string_literal: true + +require 'test_helper' + +class ActiveStorage::Service::ColoreServiceTest < ActiveSupport::TestCase + # TODO: remove + def test_ok + assert true # rubocop:disable Minitest/UselessAssertion + end +end diff --git a/test/test_helper.rb b/test/test_helper.rb new file mode 100644 index 0000000..825bcb8 --- /dev/null +++ b/test/test_helper.rb @@ -0,0 +1,18 @@ +# frozen_string_literal: true + +# Configure Rails Environment +ENV['RAILS_ENV'] = 'test' + +require 'simplecov' + +SimpleCov.start do + add_filter %w[version.rb] +end + +require 'minitest/autorun' +require 'minitest/mock' + +require 'byebug' + +require 'active_storage' +require 'activestorage/service/colore_service'