From aff2693c608e6ef89f3e512f3a7daea366d88307 Mon Sep 17 00:00:00 2001 From: "M. Peter" Date: Mon, 16 Jun 2025 14:29:38 +0200 Subject: [PATCH 1/7] removed box-id specific actions and moved it into repo box-id/workflow_engine_actions --- CHANGELOG.md | 10 +- README.md | 65 +++++++++++++ config.env.skeleton | 2 - config/runtime.exs | 4 - lib/actions/api.ex | 111 ----------------------- lib/actions/document_ai.ex | 135 --------------------------- lib/workflow_engine.ex | 4 +- mix.exs | 2 +- test/actions/api_test.exs | 146 ------------------------------ test/actions/document_ai_test.exs | 55 ----------- workflow_language.md | 20 ---- 11 files changed, 76 insertions(+), 478 deletions(-) delete mode 100644 config.env.skeleton delete mode 100644 lib/actions/api.ex delete mode 100644 lib/actions/document_ai.ex delete mode 100644 test/actions/api_test.exs delete mode 100644 test/actions/document_ai_test.exs diff --git a/CHANGELOG.md b/CHANGELOG.md index f3ca409..b02ad0c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 Unreleased changes will be displayed here upon implementation. +## [2.0.0] - 2025-06-16 + +### Breaking Changes + +- The BOX-ID internal actions `api` and `document_ai` have been moved to a separate repository. + Use the `http` action with the appropriate endpoint instead. + ## [1.1.1] - 2025-05-22 ### Fixed @@ -31,6 +38,7 @@ Unreleased changes will be displayed here upon implementation. - Support for Req 0.3.x (Note that, unrelated to the changes in this library, a warning will be logged on every request if used together with Finch >= 0.17) -[unreleased]: https://github.com/box-id/workflow_engine/compare/1.1.1...HEAD +[unreleased]: https://github.com/box-id/workflow_engine/compare/2.0.0...HEAD +[2.0.0]: https://github.com/box-id/workflow_engine/releases/tag/2.0.0 [1.1.0]: https://github.com/box-id/workflow_engine/releases/tag/1.1.0 [1.1.1]: https://github.com/box-id/workflow_engine/releases/tag/1.1.1 diff --git a/README.md b/README.md index e295a58..8a47f01 100644 --- a/README.md +++ b/README.md @@ -27,6 +27,71 @@ def deps do end ``` +## Extending Workflow Engine +To extend Workflow Engine with custom actions, implement the `WorkflowEngine.Action` behaviour. + +This is a minimal example of a custom action that multiplies a value by a given factor and stores the result in the workflow state: +```elixir +defmodule MyApp.FooAction do + @behaviour WorkflowEngine.Action + + @impl true + def execute(workflow_state, %{"type" => "multiply"} = step) do + # Implement your action logic here + + multiply_by = get_required(step, "multiply_by") + source_key = get_required(step, "source_key") + + value = Map.get(workflow_state, source_key, 1) + + new_state = + Map.put(workflow_state, "multiply_result", value * multiply_by) + + {:ok, {new_state, nil}} + + + rescue + # Wrap all error messages & add current state + e in WorkflowEngine.Error -> + reraise WorkflowEngine.Error, + [message: "FooAction: " <> e.message, state: state], + __STACKTRACE__ + end + + defp get_required(step, key) do + case Map.fetch(step, key) do + {:ok, value} when not is_nil(value) -> + value + + _ -> + raise WorkflowEngine.Error, + message: "Missing required step parameter \"#{key}\"." + end + end +end +``` + +Then, setup the action in a customized module that implements the `WorkflowEngine`: + +```elixir +defmodule MyAppNamespace.WorkflowEngine do + def evaluate(workflow, opts \\ []) do + state = %WorkflowEngine.State{ + vars: Keyword.fetch!(opts, :vars), + actions: %{ + "multiply" => MyApp.FooAction, + } + } + WorkflowEngine.evaluate(state, workflow) + end +end + +### WorkflowEngine.State Attributes + +- `vars`: A map of variables that can be used in the workflow. +- `json_logic_mod`: The module implementing the JSON Logic evaluation logic. +- `actions`: A map of action types to their respective modules. This allows you to define custom actions that can be used in workflows. + ## Error Handling Since workflows are dynamic (and potentially user-provided), Workflow Engine and its actions need diff --git a/config.env.skeleton b/config.env.skeleton deleted file mode 100644 index 4f14da1..0000000 --- a/config.env.skeleton +++ /dev/null @@ -1,2 +0,0 @@ -DOCUMENT_AI_API_ENDPOINT=https://.cognitiveservices.azure.com -DOCUMENT_AI_API_KEY=abcd1234 diff --git a/config/runtime.exs b/config/runtime.exs index a9a14e4..5b588b4 100644 --- a/config/runtime.exs +++ b/config/runtime.exs @@ -3,8 +3,4 @@ import ConfigHelpers if config_env() == :test do config :bxdk, MQTT, enabled: false - - config :workflow_engine, WorkflowEngine.Actions.DocumentAi, - api_key: get_env("WORKFLOW_DOCUMENT_AI_API_KEY", ""), - endpoint: get_env("WORKFLOW_DOCUMENT_AI_API_ENDPOINT", "") end diff --git a/lib/actions/api.ex b/lib/actions/api.ex deleted file mode 100644 index b5ac9b5..0000000 --- a/lib/actions/api.ex +++ /dev/null @@ -1,111 +0,0 @@ -defmodule WorkflowEngine.Actions.Api do - @moduledoc """ - Executes a request against the internal API using BXDK. - """ - use OK.Pipe - - @behaviour WorkflowEngine.Action - - alias WorkflowEngine.State - - @impl WorkflowEngine.Action - def execute(state, %{"type" => "api"} = step) do - module = get_module(step) - function = get_function(step) - args = get_args(step, state) - - try do - Kernel.apply(module, function, args) - |> case do - {:error, reason} -> - {:error, reason} - - {:ok, result} -> - {:ok, {state, result}} - - # Streams aren't returned as result types by BXDK - stream when is_function(stream, 2) or is_struct(stream, Stream) -> - {:ok, {state, stream}} - end - rescue - UndefinedFunctionError -> - arity = Enum.count(args) - - reraise WorkflowEngine.Error, - [ - message: - "Function #{module}.#{function}/#{arity} doesn't exist. (Arity counted from resolved args: #{Jason.encode!(args)})" - ], - __STACKTRACE__ - end - rescue - # Wrap all error messages & add current state - e in WorkflowEngine.Error -> - reraise WorkflowEngine.Error, - [message: "ApiAction: " <> e.message, state: state], - __STACKTRACE__ - end - - defp get_required(step, key) do - case Map.fetch(step, key) do - {:ok, value} when not is_nil(value) -> - value - - _ -> - raise WorkflowEngine.Error, - message: "Missing required step parameter \"#{key}\"." - end - end - - defp get_module(step) do - entity = - step - |> get_required("entity") - |> Macro.camelize() - - try do - Module.safe_concat(BXDK, entity) - rescue - ArgumentError -> - reraise WorkflowEngine.Error, - [message: "BXDK entity \"#{entity}\" doesn't exist."], - __STACKTRACE__ - end - |> verify_bxdk_api_module() - end - - defp verify_bxdk_api_module(module) do - if BXDK.api_module?(module) do - module - else - raise WorkflowEngine.Error, - message: "Module \"#{module}\" is not a valid BXDK API module." - end - end - - defp get_function(step) do - operation = get_required(step, "operation") - - try do - String.to_existing_atom(operation) - rescue - ArgumentError -> - reraise WorkflowEngine.Error, - [message: "Function \"#{operation}\" doesn't exist."], - __STACKTRACE__ - end - end - - defp get_args(step, state) do - args_logic = get_required(step, "args") - args = State.run_json_logic(state, args_logic) - - unless is_list(args) do - raise WorkflowEngine.Error, - message: "Args logic must return a list. Result: #{inspect(args)}", - state: state - end - - args - end -end diff --git a/lib/actions/document_ai.ex b/lib/actions/document_ai.ex deleted file mode 100644 index c807ce3..0000000 --- a/lib/actions/document_ai.ex +++ /dev/null @@ -1,135 +0,0 @@ -defmodule WorkflowEngine.Actions.DocumentAi do - @doc """ - Executes a request against the Azure Document AI API. - """ - - use OK.Pipe - - @behaviour WorkflowEngine.Action - - require Logger - - alias WorkflowEngine.State - - @default_document_ai_api_version "2023-07-31" - - def execute(state, %{"type" => "document_ai"} = step) do - with {:ok, model_id} <- get_property(state, step, "model_id"), - {:ok, document_url} <- get_property(state, step, "document_url"), - api_key <- get_env(:api_key), - endpoint = get_env(:endpoint), - {:ok, api_version} <- - get_property(state, step, "api_version", @default_document_ai_api_version), - {:ok, request} <- - request_document_analysis(api_key, endpoint, model_id, document_url, api_version), - {:ok, operation_location} <- get_operation_location(request), - {:ok, result} <- - request_analyzed_results(api_key, operation_location, System.os_time(:millisecond)) do - document = List.first(result["analyzeResult"]["documents"]) - - payload = %{ - "document" => document, - "confidence" => document["confidence"], - "analyze_result_url" => operation_location - } - - {:ok, {state, payload}} - else - {:error, reason} -> - Logger.warning("DocumentAiAction: #{inspect(reason)}") - {:error, reason} - end - end - - defp get_env(atom) do - Application.get_env(:workflow_engine, WorkflowEngine.Actions.DocumentAi) - |> Keyword.fetch!(atom) - end - - defp get_property(state, step, property, default \\ nil) do - case Map.get(step, property, default) do - nil -> - {:error, "#{property} is required"} - - value when is_binary(value) -> - OK.wrap(value) - - value when is_map(value) or is_list(value) -> - State.run_json_logic(state, value) - |> OK.required("JsonLogic could not resolve property: #{property}") - |> OK.wrap() - - _ -> - {:error, "#{property} must be a string"} - end - end - - defp request_document_analysis(api_key, endpoint, model_id, document_url, api_version) do - Req.new( - method: "POST", - url: endpoint <> "/formrecognizer/documentModels/#{model_id}:analyze", - json: %{"urlSource" => document_url}, - headers: %{ - "Ocp-Apim-Subscription-Key" => api_key - }, - params: %{ - "api-version" => api_version - } - ) - |> Req.request() - end - - defp get_operation_location(%{headers: headers}) do - with {"operation-location", value} <- List.keyfind(headers, "operation-location", 0) do - {:ok, value} - else - _ -> - {:error, "Operation location not found in headers"} - end - end - - defp request_analyzed_results(api_key, operation_location, initial_call_ts) do - with {:ok, :continue} <- compare_ts(initial_call_ts), - {:ok, %{status: 200} = result} <- - Req.get( - operation_location, - headers: %{ - "Ocp-Apim-Subscription-Key" => api_key - } - ) do - # INFO: the DocumentAI platform returns a 200 status code even if the operation is not - # completed but in progress, so we retry until the status is "succeeded" or the operation - # times out - # Documentation: https://learn.microsoft.com/en-us/rest/api/aiservices/document-models/get-analyze-result - - case result.body["status"] do - "succeeded" -> - {:ok, result.body} - - "running" -> - Process.sleep(1000) - request_analyzed_results(api_key, operation_location, initial_call_ts) - - "notStarted" -> - Process.sleep(1000) - request_analyzed_results(api_key, operation_location, initial_call_ts) - - "failed" -> - {:error, "Operation failed"} - - _ -> - {:error, "Unknown status" <> result.body["status"]} - end - else - error -> - Logger.error("DocumentAiAction failed: #{inspect(error)}") - {:error, error} - end - end - - defp compare_ts(initial_call_ts) do - if System.os_time(:millisecond) > initial_call_ts + :timer.seconds(10), - do: {:error, "Operation timed out"}, - else: {:ok, :continue} - end -end diff --git a/lib/workflow_engine.ex b/lib/workflow_engine.ex index 6c0fef2..7a52135 100644 --- a/lib/workflow_engine.ex +++ b/lib/workflow_engine.ex @@ -6,9 +6,7 @@ defmodule WorkflowEngine do @builtin_actions %{ "http" => Actions.Http, - "api" => Actions.Api, - "parse_csv" => Actions.ParseCsv, - "document_ai" => Actions.DocumentAi + "parse_csv" => Actions.ParseCsv } @spec evaluate(map(), keyword() | map()) :: {:error, any} | {:ok, State.t()} diff --git a/mix.exs b/mix.exs index d669281..9253cfc 100644 --- a/mix.exs +++ b/mix.exs @@ -4,7 +4,7 @@ defmodule WorkflowEngine.MixProject do def project do [ app: :workflow_engine, - version: "1.1.1", + version: "2.0.0", elixir: "~> 1.14", start_permanent: Mix.env() == :prod, deps: deps(), diff --git a/test/actions/api_test.exs b/test/actions/api_test.exs deleted file mode 100644 index 7f77105..0000000 --- a/test/actions/api_test.exs +++ /dev/null @@ -1,146 +0,0 @@ -defmodule WorkflowEngine.Actions.ApiTest do - use ExUnit.Case, async: true - use OK.Pipe - - import Mox - - setup :verify_on_exit! - - describe "API Action - Call Validation" do - test "fails when missing entity parameter" do - {:error, error} = - build_workflow(nil, "create", []) - |> WorkflowEngine.evaluate() - - assert error.recoverable == false - assert error.message =~ "Missing required step parameter \"entity\"" - end - - test "fails when given nonexistent 'entity' param" do - {:error, error} = - build_workflow("nonexistent", "create", []) - |> WorkflowEngine.evaluate() - - assert error.recoverable == false - assert error.message =~ "doesn't exist" - end - - test "fails when given non-entity api module" do - {:error, error} = - build_workflow("internal_api", "get", []) - |> WorkflowEngine.evaluate() - - assert error.recoverable == false - assert error.message =~ "not a valid BXDK API module" - end - - test "fails when missing 'operation' param" do - {:error, error} = - build_workflow("tags", nil, []) - |> WorkflowEngine.evaluate() - - assert error.recoverable == false - assert error.message =~ "Missing required step parameter \"operation\"" - end - - test "fails when given nonexistent function" do - {:error, error} = - build_workflow("tags", "incarcerate", []) - |> WorkflowEngine.evaluate() - - assert error.recoverable == false - assert error.message =~ "doesn't exist" - end - - test "fails when missing 'args' param" do - {:error, error} = - build_workflow("tags", "get", nil) - |> WorkflowEngine.evaluate() - - assert error.recoverable == false - assert error.message =~ "Missing required step parameter \"args\"" - end - - test "fails when calling function with wrong arity" do - {:error, error} = - build_workflow("tags", "get", []) - |> WorkflowEngine.evaluate() - - assert error.recoverable == false - assert error.message =~ "BXDK.Tags.get/0 doesn't exist" - end - - test "fails when args logic doesn't return a list" do - {:error, error} = - build_workflow("tags", "get", %{}) - |> WorkflowEngine.evaluate() - - assert error.recoverable == false - assert error.message =~ "Args logic must return a list" - end - end - - describe "API Action - Results" do - test "returns ok result for success result" do - BXDKTagsMock - |> expect(:get, fn _params -> {:ok, %{"id" => 1, "name" => "Test Tag"}} end) - - {:ok, result} = - build_workflow("tags", "get", [1]) - |> WorkflowEngine.evaluate() - ~> WorkflowEngine.State.get_var("result") - - assert result == %{"id" => 1, "name" => "Test Tag"} - end - - test "returns ok result for stream result" do - BXDKTagsMock - |> expect(:get, fn _params -> - Stream.cycle([%{"id" => 1, "name" => "Test Tag"}]) |> Stream.take(1) - end) - - {:ok, result} = - build_workflow("tags", "get", [1]) - |> WorkflowEngine.evaluate() - ~> WorkflowEngine.State.get_var("result") - - assert Enum.to_list(result) == [%{"id" => 1, "name" => "Test Tag"}] - end - - test "returns error for error result" do - BXDKTagsMock - |> expect(:get, fn _params -> - {:error, {:validation, %{"message" => "Something went wrong"}}} - end) - - {:error, error} = - build_workflow("tags", "get", [1]) - |> WorkflowEngine.evaluate() - - assert error.message =~ "Something went wrong" - end - - test "returns error for non-existent BXDK entity" do - {:error, error} = - build_workflow("asset", "audit", ["a1234567", true]) - |> WorkflowEngine.evaluate() - - assert error.recoverable == false - assert error.message =~ "ApiAction: BXDK entity \"Asset\" doesn't exist" - end - end - - defp build_workflow(entity, operation, args) do - %{ - "steps" => [ - %{ - "type" => "api", - "entity" => entity, - "operation" => operation, - "args" => args, - "result" => %{"as" => "result"} - } - ] - } - end -end diff --git a/test/actions/document_ai_test.exs b/test/actions/document_ai_test.exs deleted file mode 100644 index 774253e..0000000 --- a/test/actions/document_ai_test.exs +++ /dev/null @@ -1,55 +0,0 @@ -defmodule WorkflowEngine.Actions.DocumentAiTest do - use ExUnit.Case, async: true - use OK.Pipe - - alias WorkflowEngine.Actions.DocumentAi - - defmodule __MODULE__.JsonLogic do - use JsonLogic.Base, - extensions: [JsonLogic.Extensions.Obj] - end - - describe "Document AI" do - @tag :external_service - test "Params in body" do - DocumentAi.execute(%{}, %{ - "type" => "document_ai", - "model_id" => "rekord-fenster-delivery-note", - "document_url" => - "https://images.box-id.com/insecure/w:0/h:0/el:t/rt:fit/g:ce:0:0/aHR0cHM6Ly9zMy5ldS1jZW50cmFsLTEuYW1hem9uYXdzLmNvbTo0NDMvbWVkaWFib3hpZC9iMjM2NzYxY2IyODM3Y2M0ZWU2YzU1NzdhNDA1MWI3OQ==.jpg" - }) - end - - @tag :external_service - test "Params in JSON logic" do - build_workflow(%{ - "model_id" => %{ - "var" => "params.model_id" - }, - "document_url" => %{ - "var" => "params.document_url" - } - }) - |> WorkflowEngine.evaluate( - params: %{ - "model_id" => "rekord-fenster-delivery-note", - "document_url" => - "https://images.box-id.com/insecure/w:0/h:0/el:t/rt:fit/g:ce:0:0/aHR0cHM6Ly9zMy5ldS1jZW50cmFsLTEuYW1hem9uYXdzLmNvbTo0NDMvbWVkaWFib3hpZC9iMjM2NzYxY2IyODM3Y2M0ZWU2YzU1NzdhNDA1MWI3OQ==.jpg" - }, - json_logic: __MODULE__.JsonLogic - ) - end - end - - defp build_workflow(fields \\ %{}) do - %{ - "steps" => [ - %{ - "type" => "document_ai", - "result" => %{"as" => "result"} - } - |> Map.merge(fields) - ] - } - end -end diff --git a/workflow_language.md b/workflow_language.md index 957fb78..9500856 100644 --- a/workflow_language.md +++ b/workflow_language.md @@ -44,26 +44,6 @@ interface ResultDescription { } ``` -### ApiAction - -Executes an action using the BXDK/Internal API SDK. Operations are encoded using `entity`, `operation` and a list of -`args` (arguments to the function described by entity and operation). The concrete values must be looked up using the [BXDK documentation](https://intern-docs.box-id.com/sdk_internal_api_elixir/api-reference.html). - -```typescript -interface ApiAction extends Action { - type: "api"; - entity: string; - operation: string; - // should result in type: (string | number | boolean | Record)[]; - args: JsonLogic; -} -``` - -Currently, no special attention is being paid to authentication, neither: - -1. That the correct client_id is used in the correct place in the action's args -2. That the user who created the batch operation has the required permissions to execute the modification - ### HTTPAction Executes a generic HTTP action. From 2ae88952145489f9ef71eb80d366b6471deaee9b Mon Sep 17 00:00:00 2001 From: "M. Peter" Date: Mon, 16 Jun 2025 16:26:41 +0200 Subject: [PATCH 2/7] removed small left overs from the box id actions --- Makefile | 5 ++--- test/test_helper.exs | 3 --- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/Makefile b/Makefile index 13a8d48..9992d19 100644 --- a/Makefile +++ b/Makefile @@ -4,8 +4,7 @@ cnf ?= config.env include $(cnf) export $(shell sed 's/=.*//' $(cnf)) +.PHONY: help test + test: mix test - -test-document-ai: - mix test test/actions/document_ai_test.exs --include external_service diff --git a/test/test_helper.exs b/test/test_helper.exs index 7a015c3..4b2be66 100644 --- a/test/test_helper.exs +++ b/test/test_helper.exs @@ -1,7 +1,4 @@ ExUnit.configure(exclude: [:external_service]) ExUnit.start() -Mox.defmock(BXDKTagsMock, for: BXDK.Tags) -Application.put_env(:bxdk, BXDK.Tags, BXDKTagsMock) - Mox.defmock(ActionMock, for: WorkflowEngine.Action) From 705fc976e8ac0af3cd5a54881d085fe234869cd8 Mon Sep 17 00:00:00 2001 From: "M. Peter" Date: Mon, 16 Jun 2025 16:37:31 +0200 Subject: [PATCH 3/7] updated and cleaned up dependencies --- config/runtime.exs | 5 ----- mix.exs | 10 +++------- mix.lock | 5 +++-- 3 files changed, 6 insertions(+), 14 deletions(-) diff --git a/config/runtime.exs b/config/runtime.exs index 5b588b4..becde76 100644 --- a/config/runtime.exs +++ b/config/runtime.exs @@ -1,6 +1 @@ import Config -import ConfigHelpers - -if config_env() == :test do - config :bxdk, MQTT, enabled: false -end diff --git a/mix.exs b/mix.exs index 9253cfc..bf5bbf2 100644 --- a/mix.exs +++ b/mix.exs @@ -25,18 +25,14 @@ defmodule WorkflowEngine.MixProject do defp deps do [ {:ok, "~> 2.3"}, - {:jason, "~> 1.2"}, + {:jason, "~> 1.4"}, {:ex_minimatch, github: "box-id/ex_minimatch", ref: "ee65d07"}, # Our fork of JsonLogic is used at runtime and during tests, but in production it has to be # provided by upstream application to avoid version conflicts - {:json_logic, github: "box-id/json_logic_elixir", tag: "1.0.0", only: [:dev, :test]}, - # Same for BXDK. We could use `optional: true`, but since git tags are exact, this is not - # a suitable way of expressing a "minimum version" requirement. - {:bxdk, github: "box-id/bxdk", tag: "0.30.0", only: [:dev, :test]}, + {:json_logic, github: "box-id/json_logic_elixir", tag: "1.2.1", only: [:dev, :test]}, {:mix_test_watch, "~> 1.0", only: :dev, runtime: false}, - {:mox, "~> 1.0", only: :test}, + {:mox, "~> 1.2", only: :test}, {:bypass, "~> 2.1", only: :test}, - {:config_helpers, "~> 1.0"}, {:nimble_csv, "~> 1.2.0"}, {:stream_split, "~> 0.1.7"}, {:req, System.get_env("BX_CI_REQ_VERSION", "~> 0.3.1 or ~> 0.5.0")} diff --git a/mix.lock b/mix.lock index 7c44c35..c653bab 100644 --- a/mix.lock +++ b/mix.lock @@ -18,15 +18,16 @@ "glob_ex": {:hex, :glob_ex, "0.1.4", "fc69cb3f6df9138a1e36e9aa041ef2eab0d4dfe916331425f6bac290d1977e79", [:mix], [], "hexpm", "583d35559dc5b17f14612f7153aaaf6dcc13edf2e383126e2dfb5f2d19c78b89"}, "hpax": {:hex, :hpax, "0.1.2", "09a75600d9d8bbd064cdd741f21fc06fc1f4cf3d0fcc335e5aa19be1a7235c84", [:mix], [], "hexpm", "2c87843d5a23f5f16748ebe77969880e29809580efdaccd615cd3bed628a8c13"}, "jason": {:hex, :jason, "1.4.0", "e855647bc964a44e2f67df589ccf49105ae039d4179db7f6271dfd3843dc27e6", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "79a3791085b2a0f743ca04cec0f7be26443738779d09302e01318f97bdb82121"}, - "json_logic": {:git, "https://github.com/box-id/json_logic_elixir.git", "d5f3ac2f08f2f980428379eaa9fe7e925ecbdf4e", [tag: "1.0.0"]}, + "json_logic": {:git, "https://github.com/box-id/json_logic_elixir.git", "b8cfcc121c474084e4898a29c083856f671e2e5b", [tag: "1.2.1"]}, "jumper": {:hex, :jumper, "1.0.1", "3c00542ef1a83532b72269fab9f0f0c82bf23a35e27d278bfd9ed0865cecabff", [:mix], [], "hexpm", "318c59078ac220e966d27af3646026db9b5a5e6703cb2aa3e26bcfaba65b7433"}, "knigge": {:hex, :knigge, "1.4.1", "8258067fc0a1b73730c9136757b6fc8848c19cebae3a9d29212c2683a3b0fa77", [:mix], [{:bunt, "~> 0.2", [hex: :bunt, repo: "hexpm", optional: false]}], "hexpm", "55cbff4648eac4d3a9068e248d27028a66db32a51fcc227da82ca16a60947e10"}, "mime": {:hex, :mime, "2.0.5", "dc34c8efd439abe6ae0343edbb8556f4d63f178594894720607772a041b04b02", [:mix], [], "hexpm", "da0d64a365c45bc9935cc5c8a7fc5e49a0e0f9932a761c55d6c52b142780a05c"}, "mint": {:hex, :mint, "1.5.1", "8db5239e56738552d85af398798c80648db0e90f343c8469f6c6d8898944fb6f", [:mix], [{:castore, "~> 0.1.0 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:hpax, "~> 0.1.1", [hex: :hpax, repo: "hexpm", optional: false]}], "hexpm", "4a63e1e76a7c3956abd2c72f370a0d0aecddc3976dea5c27eccbecfa5e7d5b1e"}, "mix_test_watch": {:hex, :mix_test_watch, "1.1.0", "330bb91c8ed271fe408c42d07e0773340a7938d8a0d281d57a14243eae9dc8c3", [:mix], [{:file_system, "~> 0.2.1 or ~> 0.3", [hex: :file_system, repo: "hexpm", optional: false]}], "hexpm", "52b6b1c476cbb70fd899ca5394506482f12e5f6b0d6acff9df95c7f1e0812ec3"}, - "mox": {:hex, :mox, "1.0.2", "dc2057289ac478b35760ba74165b4b3f402f68803dd5aecd3bfd19c183815d64", [:mix], [], "hexpm", "f9864921b3aaf763c8741b5b8e6f908f44566f1e427b2630e89e9a73b981fef2"}, + "mox": {:hex, :mox, "1.2.0", "a2cd96b4b80a3883e3100a221e8adc1b98e4c3a332a8fc434c39526babafd5b3", [:mix], [{:nimble_ownership, "~> 1.0", [hex: :nimble_ownership, repo: "hexpm", optional: false]}], "hexpm", "c7b92b3cc69ee24a7eeeaf944cd7be22013c52fcb580c1f33f50845ec821089a"}, "nimble_csv": {:hex, :nimble_csv, "1.2.0", "4e26385d260c61eba9d4412c71cea34421f296d5353f914afe3f2e71cce97722", [:mix], [], "hexpm", "d0628117fcc2148178b034044c55359b26966c6eaa8e2ce15777be3bbc91b12a"}, "nimble_options": {:hex, :nimble_options, "1.0.2", "92098a74df0072ff37d0c12ace58574d26880e522c22801437151a159392270e", [:mix], [], "hexpm", "fd12a8db2021036ce12a309f26f564ec367373265b53e25403f0ee697380f1b8"}, + "nimble_ownership": {:hex, :nimble_ownership, "1.0.1", "f69fae0cdd451b1614364013544e66e4f5d25f36a2056a9698b793305c5aa3a6", [:mix], [], "hexpm", "3825e461025464f519f3f3e4a1f9b68c47dc151369611629ad08b636b73bb22d"}, "nimble_pool": {:hex, :nimble_pool, "1.0.0", "5eb82705d138f4dd4423f69ceb19ac667b3b492ae570c9f5c900bb3d2f50a847", [:mix], [], "hexpm", "80be3b882d2d351882256087078e1b1952a28bf98d0a287be87e4a24a710b67a"}, "ok": {:hex, :ok, "2.3.0", "0a3d513ec9038504dc5359d44e14fc14ef59179e625563a1a144199cdc3a6d30", [:mix], [], "hexpm", "f0347b3f8f115bf347c704184b33cf084f2943771273f2b98a3707a5fa43c4d5"}, "phoenix_pubsub": {:hex, :phoenix_pubsub, "2.1.3", "3168d78ba41835aecad272d5e8cd51aa87a7ac9eb836eabc42f6e57538e3731d", [:mix], [], "hexpm", "bba06bc1dcfd8cb086759f0edc94a8ba2bc8896d5331a1e2c2902bf8e36ee502"}, From 2e88ff33287f7edb7dbd0db9d14fdb972625954a Mon Sep 17 00:00:00 2001 From: "M. Peter" Date: Mon, 16 Jun 2025 16:47:24 +0200 Subject: [PATCH 4/7] fixed GH actions folders --- {.github_workflows => .github/workflows}/ci.yml | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename {.github_workflows => .github/workflows}/ci.yml (100%) diff --git a/.github_workflows/ci.yml b/.github/workflows/ci.yml similarity index 100% rename from .github_workflows/ci.yml rename to .github/workflows/ci.yml From 95a7357ffecfc09441f525c38c76e7c39d5fd9de Mon Sep 17 00:00:00 2001 From: "M. Peter" Date: Mon, 16 Jun 2025 16:49:58 +0200 Subject: [PATCH 5/7] as we do no longer use BXDK we can drop the secret setup from ci tests --- .github/workflows/ci.yml | 6 ------ 1 file changed, 6 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1407784..6f7d24d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -26,12 +26,6 @@ jobs: - name: Check out Repository uses: actions/checkout@v4 - - name: Set up SSH Agent - uses: webfactory/ssh-agent@v0.9.0 - with: - ssh-private-key: | - ${{ secrets.DEPLOY_KEY_SDK_INTERNAL_API_ELIXIR }} - - name: Set up Elixir uses: erlef/setup-beam@v1 with: From e491f6956ddcbd02bb8e66276efd101ebd882fbc Mon Sep 17 00:00:00 2001 From: "M. Peter" Date: Mon, 16 Jun 2025 16:52:36 +0200 Subject: [PATCH 6/7] added 1.18.x to ci tests --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6f7d24d..47e3c21 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -7,7 +7,7 @@ jobs: strategy: matrix: otp: ["25.x", "26.x", "27.x"] - elixir: ["1.15.x", "1.16.x", "1.17.x"] + elixir: ["1.15.x", "1.16.x", "1.17.x", "1.18.x"] req: ["0.5.7"] # Exclude incompatible combinations of OTP and Elixir exclude: From ae2ec0b342d6bc52cc6ce22a3f35fc3f35ae5d30 Mon Sep 17 00:00:00 2001 From: "M. Peter" Date: Tue, 17 Jun 2025 08:50:31 +0200 Subject: [PATCH 7/7] fixed moduledoc --- lib/actions/action.ex | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/actions/action.ex b/lib/actions/action.ex index bb807d3..345085b 100644 --- a/lib/actions/action.ex +++ b/lib/actions/action.ex @@ -1,7 +1,6 @@ defmodule WorkflowEngine.Action do @moduledoc """ - Behavior that describes the necessary methods for an workflow action, as seen in - WorkflowEngine.Actions.Api. + Behavior that describes the necessary methods for an workflow action. """ alias WorkflowEngine.State