metaractor 3.0.1 → 3.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d8b28e07d981c3224d3e209a34961e685de8859e7bec198c8f64ac08456219e7
4
- data.tar.gz: d2ea3446b24661a347bb38087df37b6208ce62a742f7a7edfd2332a7137e1acd
3
+ metadata.gz: 3a84ca8402879e172bd7dfb5cd494b41de2639e85080b3052c503a68d4406234
4
+ data.tar.gz: 6db8d581e34cb71fcbf27bcb590978d31301b7ad232fc478e31d7d9fae213eff
5
5
  SHA512:
6
- metadata.gz: 61e4852078088812a0a53b33601d555aa8a2bdd3b5d50f56bd96c8c50729f45aa7a788eb305f82bb747f973bfde421c2904385c35a4428687bd7f9621ab382e3
7
- data.tar.gz: 2cd047d8213c8c4197395545ab4f1b448aea33c6985f0ec0dc6901a66d923195be2ac510e0a73ee414643200d22b5d5b8c88da90ce53cb22d7cb9f35b825beaa
6
+ metadata.gz: 364eb4ae9ddcf5a836ea876ecece48013c16b20b4a82a354c4e277d954df3cb828ba8252d48b3302dbd597f908f6c52a73909124cb3101a2e6a6b69e2f97afc6
7
+ data.tar.gz: dd45bf611c8edfafadc6fce753f682f429803082157a66f5c9c92e3a2daa7981d98483a65fd88bd73a5bf55c8cfd83edc92692e48e58186631fdf2a38397bf67
@@ -0,0 +1,93 @@
1
+ env:
2
+ BUILDKITE_PLUGIN_DOCKER_CACHE_S3_BUCKET: "outstand-buildkite-cache"
3
+ # BUILDKITE_PLUGIN_DOCKER_CACHE_VOLUME_DEBUG: "true"
4
+ BUILDKITE_PLUGIN_DOCKER_COMPOSE_SHELL: "false"
5
+ # BUILDKITE_PLUGIN_DOCKER_COMPOSE_UPLOAD_CONTAINER_LOGS: "always"
6
+ BUILDKITE_PLUGIN_DOCKER_COMPOSE_PULL_RETRIES: 5
7
+ BUILDKITE_PLUGIN_DOCKER_COMPOSE_PUSH_RETRIES: 5
8
+ PLUGIN_DOCKER_COMPOSE_VERSION: "03d746fbf5171b217b732ff7d8a3e417d664df1c"
9
+ PLUGIN_DOCKER_CACHE_VERSION: "50ecc80f736a4a3a0ab1f5990e58ae8e536c85e1"
10
+ WORKSPACE_DIR: "${BUILDKITE_BUILD_CHECKOUT_PATH}"
11
+
12
+ steps:
13
+ - label: ":docker: Build"
14
+ key: build
15
+ plugins:
16
+ - seek-oss/aws-sm#v2.3.1:
17
+ env:
18
+ DOCKER_LOGIN_PASSWORD: "/buildkite/docker_password"
19
+
20
+ - docker-login#v2.1.0:
21
+ username: outstandci
22
+ retries: 2
23
+
24
+ - ecr#v2.5.0:
25
+ login: true
26
+ region: "us-east-1"
27
+
28
+ - https://github.com/outstand/docker-compose-buildkite-plugin.git#${PLUGIN_DOCKER_COMPOSE_VERSION}:
29
+ build: metaractor
30
+ image-repository: 786715713882.dkr.ecr.us-east-1.amazonaws.com/ci-images
31
+ config:
32
+ - compose.yml
33
+
34
+ - label: ":bundler: :rubygems:"
35
+ key: bundle_install
36
+ command: bundle install
37
+ depends_on: build
38
+ plugins:
39
+ - seek-oss/aws-sm#v2.3.1:
40
+ env:
41
+ DOCKER_LOGIN_PASSWORD: "/buildkite/docker_password"
42
+
43
+ - docker-login#v2.1.0:
44
+ username: outstandci
45
+ retries: 2
46
+
47
+ - ecr#v2.5.0:
48
+ login: true
49
+ region: "us-east-1"
50
+
51
+ - https://github.com/outstand/docker-compose-buildkite-plugin.git#${PLUGIN_DOCKER_COMPOSE_VERSION}:
52
+ run: metaractor
53
+ dependencies: false
54
+ config:
55
+ - compose.yml
56
+
57
+ - https://github.com/outstand/docker-cache-buildkite-plugin.git#${PLUGIN_DOCKER_CACHE_VERSION}:
58
+ name: bundler-cache
59
+ keys:
60
+ - v1-bundler-cache-{{ arch }}-{{ checksum "metaractor.gemspec" }}-{{ checksum "Gemfile" }}
61
+ - v1-bundler-cache-{{ arch }}-
62
+ save: true
63
+ volumes:
64
+ - bundler-data
65
+
66
+ - label: ":ruby: Specs"
67
+ command: rspec spec
68
+ depends_on: bundle_install
69
+ plugins:
70
+ - seek-oss/aws-sm#v2.3.1:
71
+ env:
72
+ DOCKER_LOGIN_PASSWORD: "/buildkite/docker_password"
73
+
74
+ - docker-login#v2.1.0:
75
+ username: outstandci
76
+ retries: 2
77
+
78
+ - ecr#v2.5.0:
79
+ login: true
80
+ region: "us-east-1"
81
+
82
+ - https://github.com/outstand/docker-compose-buildkite-plugin.git#${PLUGIN_DOCKER_COMPOSE_VERSION}:
83
+ run: metaractor
84
+ config:
85
+ - compose.yml
86
+
87
+ - https://github.com/outstand/docker-cache-buildkite-plugin.git#${PLUGIN_DOCKER_CACHE_VERSION}:
88
+ name: bundler-cache
89
+ keys:
90
+ - v1-bundler-cache-{{ arch }}-{{ checksum "metaractor.gemspec" }}-{{ checksum "Gemfile" }}
91
+ - v1-bundler-cache-{{ arch }}-
92
+ volumes:
93
+ - bundler-data
data/.rspec CHANGED
@@ -1,2 +1,4 @@
1
1
  --color
2
2
  --require spec_helper
3
+ --format progress
4
+ --format RSpec::Buildkite::AnnotationFormatter
data/Deskfile ADDED
@@ -0,0 +1,3 @@
1
+ rspec() {
2
+ docker compose run --rm metaractor rspec "$@"
3
+ }
data/Dockerfile CHANGED
@@ -1,30 +1,78 @@
1
- FROM ruby:2.6.5-alpine
1
+ FROM outstand/su-exec:latest as su-exec
2
+ FROM outstand/fixuid as fixuid
3
+
4
+ FROM ruby:2.7.6-bullseye
2
5
  LABEL maintainer="Ryan Schlesinger <ryan@outstand.com>"
3
6
 
4
- RUN addgroup -g 1000 -S metaractor && \
5
- adduser -u 1000 -S -s /bin/ash -G metaractor metaractor && \
6
- apk add --no-cache \
7
- ca-certificates \
8
- tini \
9
- su-exec \
10
- build-base \
11
- git \
12
- openssh
7
+ SHELL ["/bin/bash", "-o", "pipefail", "-c"]
8
+ ENV DEBIAN_FRONTEND=noninteractive
9
+
10
+ RUN set -eux; \
11
+ \
12
+ groupadd -g 1000 metaractor && \
13
+ useradd -u 1000 -g metaractor -ms /bin/bash metaractor && \
14
+ \
15
+ apt-get update -y; \
16
+ apt-get install -y \
17
+ ca-certificates \
18
+ curl \
19
+ git \
20
+ build-essential \
21
+ tini \
22
+ ; \
23
+ apt-get clean; \
24
+ rm -f /var/lib/apt/lists/*_*
25
+
26
+ # install su-exec
27
+ COPY --from=su-exec /sbin/su-exec /sbin/su-exec
13
28
 
14
- ENV BUNDLER_VERSION 2.1.4
15
- RUN gem install bundler -v ${BUNDLER_VERSION} -i /usr/local/lib/ruby/gems/$(ls /usr/local/lib/ruby/gems) --force
29
+ # install fixuid
30
+ COPY --from=fixuid /usr/local/bin/fixuid /usr/local/bin/fixuid
31
+ RUN set -eux; \
32
+ \
33
+ chmod 4755 /usr/local/bin/fixuid; \
34
+ USER=metaractor; \
35
+ GROUP=metaractor; \
36
+ mkdir -p /etc/fixuid; \
37
+ printf "user: $USER\ngroup: $GROUP\n" > /etc/fixuid/config.yml
38
+
39
+ ENV BUNDLER_VERSION 2.3.20
40
+ ENV GITHUB_CLI_VERSION 2.14.4
41
+ ENV GITHUB_CLI_CHECKSUM b0073fdcc07d1de5a19a1a782c7ad9f593f991da06a809ea39f0b6148869aa96
42
+ RUN set -eux; \
43
+ \
44
+ mkdir -p /tmp/build; \
45
+ cd /tmp/build; \
46
+ \
47
+ gem install bundler -v ${BUNDLER_VERSION} -i /usr/local/lib/ruby/gems/$(ls /usr/local/lib/ruby/gems) --force; \
48
+ curl -fsSL https://github.com/cli/cli/releases/download/v${GITHUB_CLI_VERSION}/gh_${GITHUB_CLI_VERSION}_linux_amd64.deb -o gh_${GITHUB_CLI_VERSION}_linux_amd64.deb; \
49
+ echo "${GITHUB_CLI_CHECKSUM} gh_${GITHUB_CLI_VERSION}_linux_amd64.deb" | sha256sum --check; \
50
+ apt-get update -y; \
51
+ apt-get install -y --no-install-recommends \
52
+ ./gh_${GITHUB_CLI_VERSION}_linux_amd64.deb \
53
+ ; \
54
+ apt-get clean; \
55
+ rm -f /var/lib/apt/lists/*_*; \
56
+ rm -rf /tmp/build
57
+
58
+ COPY brew-shim /usr/bin/brew
16
59
 
17
60
  WORKDIR /metaractor
18
- RUN chown -R metaractor:metaractor /metaractor
61
+ RUN set -eux; \
62
+ \
63
+ chown -R metaractor:metaractor /metaractor
64
+
19
65
  USER metaractor
20
66
 
21
67
  COPY --chown=metaractor:metaractor Gemfile metaractor.gemspec /metaractor/
22
68
  COPY --chown=metaractor:metaractor lib/metaractor/version.rb /metaractor/lib/metaractor/
23
- RUN git config --global push.default simple
69
+ RUN set -eux; \
70
+ \
71
+ git config --global push.default simple
24
72
  COPY --chown=metaractor:metaractor . /metaractor/
25
73
 
26
74
  USER root
27
75
  COPY docker-entrypoint.sh /docker-entrypoint.sh
28
76
 
29
- ENTRYPOINT ["/sbin/tini", "-g", "--", "/docker-entrypoint.sh"]
77
+ ENTRYPOINT ["/usr/bin/tini", "-g", "--", "/docker-entrypoint.sh"]
30
78
  CMD ["rspec", "spec"]
data/Gemfile CHANGED
@@ -1,5 +1,4 @@
1
1
  source 'https://rubygems.org'
2
2
 
3
3
  gemspec
4
- gem 'pry-byebug'
5
- gem 'awesome_print'
4
+ gem 'rspec-buildkite', github: 'outstand/rspec-buildkite', branch: 'error-output'
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # Metaractor
1
+ # Metaractor [![Build status](https://badge.buildkite.com/70063a5154eb7366b8b7fd65a875c5f64301bc60f6d29a2ad7.svg)](https://buildkite.com/outstand/metaractor)
2
2
  Adds parameter validation and error control to [interactor](https://github.com/collectiveidea/interactor).
3
3
 
4
4
  ## Installation
@@ -103,6 +103,24 @@ This works with `allow_blank` and can also be anything that responds to `#call`.
103
103
  parameter :role, allow_blank: true, default: -> { context.default_role }
104
104
  ```
105
105
 
106
+ #### Typecasting/Coersion
107
+ You can supply Metaractor with a callable that will typecast incoming parameters:
108
+ ```ruby
109
+ optional :needs_to_be_a_string, type: ->(value) { value.to_s }
110
+ ```
111
+
112
+ You can also configure Metaractor with named types and use them:
113
+ ```ruby
114
+ Metaractor.configure do |config|
115
+ config.register_type(:boolean, ->(value) { ActiveModel::Type::Boolean.new.cast(value) })
116
+ end
117
+ ```
118
+ ```ruby
119
+ required :is_awesome, type: :boolean
120
+ ```
121
+
122
+ **Note**: Typecasters will _not_ be called on `nil` values.
123
+
106
124
  ### Custom Validation
107
125
  Metaractor supports doing custom validation before any user supplied before_hooks run.
108
126
  ```ruby
data/brew-shim ADDED
@@ -0,0 +1,10 @@
1
+ #!/bin/bash
2
+
3
+ set -euo pipefail
4
+
5
+ # Docker host has the following git config:
6
+ # helper = !$(brew --prefix)/bin/gh auth git-credential
7
+ #
8
+ # We're going to lie inside the container so we can find the local gh
9
+
10
+ echo "/usr"
@@ -1,24 +1,35 @@
1
- version: '3.6'
2
1
  services:
3
2
  metaractor:
4
3
  build: .
5
4
  image: outstand/metaractor:dev
6
5
  stdin_open: true
7
6
  tty: true
7
+ environment:
8
+ FIXUID:
9
+ FIXGID:
10
+ BUILDKITE:
11
+ BUILDKITE_BUILD_URL:
12
+ BUILDKITE_JOB_ID:
13
+ BUILDKITE_AGENT_ACCESS_TOKEN:
8
14
  volumes:
9
15
  - bundler-data:/usr/local/bundle
10
16
  - .:/metaractor
17
+
11
18
  release:
12
19
  image: outstand/metaractor:dev
13
20
  stdin_open: true
14
21
  tty: true
15
22
  command: rake release
23
+ environment:
24
+ FIXUID:
25
+ FIXGID:
16
26
  volumes:
17
27
  - bundler-data:/usr/local/bundle
18
28
  - ~/.gitconfig:/home/metaractor/.gitconfig
19
29
  - ~/.gitconfig.user:/home/metaractor/.gitconfig.user
20
- - ~/.ssh/id_rsa:/home/metaractor/.ssh/id_rsa
21
- - ~/.gem:/home/metaractor/.gem
30
+ - ~/.config/gh/hosts.yml:/home/metaractor/.config/gh/hosts.yml
31
+ - ~/.local/share/gem/credentials:/home/metaractor/.local/share/gem/credentials
32
+ - ~/.local/share/gem/credentials:/home/metaractor/.gem/credentials
22
33
 
23
34
  volumes:
24
35
  bundler-data:
data/docker-entrypoint.sh CHANGED
@@ -1,5 +1,20 @@
1
- #!/bin/sh
2
- set -e
1
+ #!/bin/bash
2
+
3
+ set -euo pipefail
4
+
5
+ su-exec ${FIXUID:?Missing FIXUID var}:${FIXGID:?Missing FIXGID var} fixuid
6
+
7
+ chown_dir() {
8
+ dir=$1
9
+ if [[ -d ${dir} ]] && [[ "$(stat -c %u:%g ${dir})" != "${FIXUID}:${FIXGID}" ]]; then
10
+ echo chown $dir
11
+ chown metaractor:metaractor $dir
12
+ fi
13
+ }
14
+
15
+ chown_dir /usr/local/bundle
16
+ chown_dir /home/metaractor/.local/share/gem
17
+ chown_dir /home/metaractor/.gem
3
18
 
4
19
  if [ "$(which "$1")" = '' ]; then
5
20
  if [ "$(ls -A /usr/local/bundle/bin)" = '' ]; then
@@ -14,7 +29,7 @@ if [ "$1" = 'bundle' ]; then
14
29
  elif ls /usr/local/bundle/bin | grep -q "\b$1\b"; then
15
30
  set -- su-exec metaractor bundle exec "$@"
16
31
 
17
- su-exec metaractor ash -c 'bundle check || bundle install'
32
+ su-exec metaractor bash -c 'bundle check || bundle install'
18
33
  fi
19
34
 
20
35
  exec "$@"
@@ -71,18 +71,19 @@ module Metaractor
71
71
 
72
72
  def add(error: {}, errors: {}, object: nil)
73
73
  trees = []
74
- [error, errors].each do |h|
74
+ [error, errors].each do |h|
75
75
  tree = nil
76
76
  if h.is_a? Metaractor::Errors
77
77
  tree = Sycamore::Tree.from(h.instance_variable_get(:@tree))
78
78
  else
79
- tree = Sycamore::Tree.from(h)
79
+ tree = Sycamore::Tree.from(normalize_error_hash(h))
80
80
  end
81
81
 
82
82
  unless tree.empty?
83
- if tree.nodes.any? {|node| tree.strict_leaf?(node) }
83
+ if tree.nodes.any? { |node| tree.strict_leaf?(node) }
84
84
  raise ArgumentError, "Invalid hash!"
85
85
  end
86
+
86
87
  trees << tree
87
88
  end
88
89
  end
@@ -220,5 +221,34 @@ module Metaractor
220
221
  end
221
222
  end
222
223
 
224
+ def normalize_error_hash(hash)
225
+ deep_transform_values_in_object(hash, &method(:transform_delegator))
226
+ end
227
+
228
+ def transform_delegator(value)
229
+ if value.is_a?(Delegator)
230
+ if value.respond_to?(:to_hash)
231
+ deep_transform_values_in_object(value.to_hash, &method(:transform_delegator))
232
+ elsif value.respond_to?(:to_a)
233
+ deep_transform_values_in_object(value.to_a, &method(:transform_delegator))
234
+ else
235
+ value
236
+ end
237
+ else
238
+ value
239
+ end
240
+ end
241
+
242
+ # Lifted from Rails
243
+ def deep_transform_values_in_object(object, &block)
244
+ case object
245
+ when Hash
246
+ object.transform_values { |value| deep_transform_values_in_object(value, &block) }
247
+ when Array
248
+ object.map { |e| deep_transform_values_in_object(e, &block) }
249
+ else
250
+ yield(object)
251
+ end
252
+ end
223
253
  end
224
254
  end
@@ -14,6 +14,7 @@ module Metaractor
14
14
  before :remove_blank_values
15
15
  before :apply_defaults
16
16
  before :validate_required_parameters
17
+ before :apply_types
17
18
  end
18
19
  end
19
20
 
@@ -37,6 +38,10 @@ module Metaractor
37
38
  @options[key]
38
39
  end
39
40
 
41
+ def has_key?(key)
42
+ @options.has_key?(key)
43
+ end
44
+
40
45
  def dig(name, *names)
41
46
  @options.dig(name, *names)
42
47
  end
@@ -142,7 +147,7 @@ module Metaractor
142
147
 
143
148
  def apply_defaults
144
149
  parameters.each do |name, parameter|
145
- next unless parameter[:default]
150
+ next unless parameter.has_key?(:default)
146
151
 
147
152
  unless context.has_key?(name)
148
153
  context[name] = _parameter_default(name)
@@ -160,6 +165,23 @@ module Metaractor
160
165
  end
161
166
  end
162
167
 
168
+ def apply_types
169
+ parameters.each do |name, parameter|
170
+ next unless parameter[:type]
171
+
172
+ if context.has_key?(name) && context[name] != nil
173
+ callable = parameter[:type]
174
+
175
+ if callable.is_a?(Symbol)
176
+ callable = Metaractor.types[callable]
177
+ raise ArgumentError, "No such type: #{parameter[:type]}" if callable.nil?
178
+ end
179
+
180
+ context[name] = callable.call(context[name])
181
+ end
182
+ end
183
+ end
184
+
163
185
  def validate_required_parameters
164
186
  context.errors ||= []
165
187
 
@@ -1,3 +1,3 @@
1
1
  module Metaractor
2
- VERSION = "3.0.1"
2
+ VERSION = "3.2.0"
3
3
  end
data/lib/metaractor.rb CHANGED
@@ -77,4 +77,16 @@ module Metaractor
77
77
  def self.hash_formatter=(callable)
78
78
  @hash_formatter = callable
79
79
  end
80
+
81
+ def self.types
82
+ @types ||= {}
83
+ end
84
+
85
+ def self.register_type(type, callable)
86
+ types[type] = callable
87
+ end
88
+
89
+ def self.clear_types!
90
+ @types = {}
91
+ end
80
92
  end
data/metaractor.gemspec CHANGED
@@ -11,7 +11,10 @@ Gem::Specification.new do |spec|
11
11
  spec.email = ['ryan@outstand.com']
12
12
 
13
13
  spec.summary = %q{Adds parameter validation and error control to interactor}
14
- spec.homepage = 'https://github.com/outstand/metaractor'
14
+ spec.metadata = {
15
+ "homepage_uri" => "https://github.com/outstand/metaractor",
16
+ "source_code_uri" => "https://github.com/outstand/metaractor"
17
+ }
15
18
 
16
19
  spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
17
20
  spec.bindir = 'exe'
@@ -27,4 +30,5 @@ Gem::Specification.new do |spec|
27
30
  spec.add_development_dependency 'rspec', '~> 3.9'
28
31
  spec.add_development_dependency 'awesome_print', '~> 1.8'
29
32
  spec.add_development_dependency 'pry-byebug', '~> 3.9'
33
+ spec.add_development_dependency 'activemodel', '~> 6.1'
30
34
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: metaractor
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.0.1
4
+ version: 3.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ryan Schlesinger
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-05-21 00:00:00.000000000 Z
11
+ date: 2022-08-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: interactor
@@ -122,6 +122,20 @@ dependencies:
122
122
  - - "~>"
123
123
  - !ruby/object:Gem::Version
124
124
  version: '3.9'
125
+ - !ruby/object:Gem::Dependency
126
+ name: activemodel
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - "~>"
130
+ - !ruby/object:Gem::Version
131
+ version: '6.1'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - "~>"
137
+ - !ruby/object:Gem::Version
138
+ version: '6.1'
125
139
  description:
126
140
  email:
127
141
  - ryan@outstand.com
@@ -129,14 +143,17 @@ executables: []
129
143
  extensions: []
130
144
  extra_rdoc_files: []
131
145
  files:
146
+ - ".buildkite/pipeline.yml"
132
147
  - ".gitignore"
133
148
  - ".rspec"
149
+ - Deskfile
134
150
  - Dockerfile
135
151
  - Gemfile
136
152
  - LICENSE
137
153
  - README.md
138
154
  - Rakefile
139
- - docker-compose.yml
155
+ - brew-shim
156
+ - compose.yml
140
157
  - docker-entrypoint.sh
141
158
  - lib/metaractor.rb
142
159
  - lib/metaractor/chain_failures.rb
@@ -153,10 +170,12 @@ files:
153
170
  - lib/metaractor/spec.rb
154
171
  - lib/metaractor/version.rb
155
172
  - metaractor.gemspec
156
- homepage: https://github.com/outstand/metaractor
173
+ homepage:
157
174
  licenses:
158
175
  - Apache-2.0
159
- metadata: {}
176
+ metadata:
177
+ homepage_uri: https://github.com/outstand/metaractor
178
+ source_code_uri: https://github.com/outstand/metaractor
160
179
  post_install_message:
161
180
  rdoc_options: []
162
181
  require_paths:
@@ -172,7 +191,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
172
191
  - !ruby/object:Gem::Version
173
192
  version: '0'
174
193
  requirements: []
175
- rubygems_version: 3.0.3
194
+ rubygems_version: 3.1.6
176
195
  signing_key:
177
196
  specification_version: 4
178
197
  summary: Adds parameter validation and error control to interactor