diff --git a/.github/workflows/semantic-release.yml b/.github/workflows/semantic-release.yml
new file mode 100644
index 0000000..6f4a4d2
--- /dev/null
+++ b/.github/workflows/semantic-release.yml
@@ -0,0 +1,59 @@
+name: Semantic-Release
+
+on:
+ push:
+ branches: [ main ]
+
+permissions:
+ contents: write
+ issues: write
+ pull-requests: write
+ id-token: write
+
+jobs:
+ release:
+ environment: SEMANTIC_RELEASE_ENV
+ runs-on: ubuntu-latest
+
+ env:
+ GITHUB_TOKEN: ${{ secrets.GH_TOKEN }}
+ HEX_API_KEY: ${{ secrets.HEX_API_KEY }}
+ GITHUB_API_URL: ${{ vars.GH_API_URL }}
+ PUBLISH_ARTIFACT: ${{ vars.PUBLISH_ARTIFACT }}
+ ELIXIR_VERSION: ${{ vars.ELIXIR_VERSION }}
+ OTP_VERSION: ${{ vars.OTP_VERSION }}
+ SKIP_GIT_HOOKS: 'true'
+
+ steps:
+ - uses: actions/checkout@v4
+
+ - name: Setup Node.js
+ uses: actions/setup-node@v4
+ with:
+ node-version: 20.x
+
+ - name: Set up Elixir ${{ env.ELIXIR_VERSION }} and Otp ${{ env.OTP_VERSION }}
+ uses: erlef/setup-beam@v1
+ with:
+ elixir-version: ${{ env.ELIXIR_VERSION }}
+ otp-version: ${{ env.OTP_VERSION }}
+
+ - name: Setup semantic-release
+ run: npm install -g semantic-release @semantic-release/changelog @semantic-release/github -D
+
+ - name: Call semantic-release
+ run: npx -p @semantic-release/changelog semantic-release
+
+ - name: Set variables From git tag command
+ if: ${{ ( env.PUBLISH_ARTIFACT == 'true' ) }}
+ run: |
+ echo "$VER"
+ echo "RELEASE_VERSION=$(git tag | sort --version-sort | tail -n1 | tr -d 'v')" >> $GITHUB_ENV
+
+ - name: Install Mix dependencies
+ if: ${{ ( env.PUBLISH_ARTIFACT == 'true' ) }}
+ run: mix do local.hex --force, local.rebar --force && mix do deps.clean --unused, deps.get, deps.compile && mix deps.compile
+
+ - name: Publish to HEX
+ if: ${{ ( env.PUBLISH_ARTIFACT == 'true' ) }}
+ run: mix hex.publish --replace --yes
diff --git a/.releaserc b/.releaserc
new file mode 100644
index 0000000..8412468
--- /dev/null
+++ b/.releaserc
@@ -0,0 +1,9 @@
+{
+ "repositoryUrl": "https://github.com/bancolombia/distributed-performance-analyzer.git",
+ "branches": ["main"],
+ "plugins": [
+ "@semantic-release/commit-analyzer",
+ "@semantic-release/release-notes-generator",
+ "@semantic-release/github"
+ ]
+}
diff --git a/README.md b/README.md
index 16cee96..5301532 100644
--- a/README.md
+++ b/README.md
@@ -6,6 +6,8 @@
[![Forks][forks-shield]][forks-url]
[![Stars][stars-shield]][stars-url]
[![Issues][issues-shield]][issues-url]
+[![semantic-release: angular][semantic-release-url-badge]][semantic-release-url]
+
[![Quality Gate Status][sonarcloud-quality-gate-shield]][sonarcloud-url]
[![Maintainability Rating][sonarcloud-maintainability-shield]][sonarcloud-url]
@@ -165,6 +167,8 @@ vs Mean Latency.
![Example 2 - Latency](assets/dresults_example2.png)
+[semantic-release-url-badge]: https://img.shields.io/badge/semantic--release-angular-e10079?logo=semantic-release
+[semantic-release-url]: https://github.com/semantic-release/semantic-release
[scorecards-shield]: https://github.com/bancolombia/distributed-performance-analyzer/actions/workflows/scorecards-analysis.yml/badge.svg
[scorecards-url]: https://github.com/bancolombia/distributed-performance-analyzer/actions/workflows/scorecards-analysis.yml
[docker-shield]: https://img.shields.io/docker/pulls/bancolombia/distributed-performance-analyzer
diff --git a/SEMANTIC-RELEASE.md b/SEMANTIC-RELEASE.md
new file mode 100644
index 0000000..06e7bcf
--- /dev/null
+++ b/SEMANTIC-RELEASE.md
@@ -0,0 +1,32 @@
+# Semantic Release
+## Commit message format
+semantic-release utiliza los mensajes de confirmación para determinar el impacto de los cambios en el release; Siguiendo las convenciones para mensajes de confirmación, semantic-release determina automáticamente el siguiente número de versión semántica, genera un registro de cambios y publica la versión.
+
+De forma predeterminada, la liberación semántica utiliza
+convenciones de mensajes de confirmación angular. [convenciones de mensajes de confirmación angular.](https://github.com/angular/angular/blob/main/CONTRIBUTING.md#-commit-message-format)
+
+Se pueden utilizar herramientas como commitizen o commit-lint para ayudar a los contribuyentes y hacer cumplir los mensajes de confirmación válidos.
+
+La siguiente tabla muestra qué mensaje de confirmación le proporciona qué tipo de versión cuando se ejecuta la versión semántica (usando la configuración predeterminada):
+
+| Commit Message | Release type |
+| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------- |
+| `fix(pencil): stop graphite breaking when too much pressure applied` | ~~Patch~~ Fix Release |
+| `feat(pencil): add 'graphiteWidth' option` | ~~Minor~~ Feature Release |
+| `perf(pencil): remove graphiteWidth option`
`BREAKING CHANGE: The graphiteWidth option has been removed.`
`The default graphite width of 10mm is always used for performance reasons.` | ~~Major~~ Breaking Release
(Note that the `BREAKING CHANGE: ` token must be in the footer of the commit) |
+**[link a la fuente.](https://github.com/semantic-release/semantic-release?tab=readme-ov-file#Commit%20message%20format)**
+
+dentro de la documentación de angular sobre convenciones de mensajes se tienen estos adicionales:
+
+- **build:** cambios que afectan el sistema de compilación o las dependencias externas (alcances de ejemplo: gulp, broccoli, npm).
+- **ci:** Cambios en nuestros archivos y scripts de configuración de CI (ejemplos: CircleCi, SauceLabs).
+- **docs:** La documentación solo cambia.
+- **feat:** una nueva característica.
+- **fix:** una corrección de errores.
+- **perf:** Un cambio de código que mejora el rendimiento.
+- **refactor:** un cambio de código que no corrige un error ni agrega una característica.
+- **test:** agregar pruebas faltantes o corregir pruebas existentes.
+
+## excluir commit del análisis del plugin:
+
+Todas las confirmaciones que contengan [skip release] or [release skip] en su mensaje se excluirán del análisis de confirmación y no participarán en la determinación del tipo de versión.
\ No newline at end of file
diff --git a/lib/domain/use_cases/metrics_collector_use_case.ex b/lib/domain/use_cases/metrics_collector_use_case.ex
index 67e02da..92472a3 100644
--- a/lib/domain/use_cases/metrics_collector_use_case.ex
+++ b/lib/domain/use_cases/metrics_collector_use_case.ex
@@ -37,7 +37,7 @@ defmodule DistributedPerformanceAnalyzer.Domain.UseCase.MetricsCollectorUseCase
end
def get_metrics do
- GenServer.call({:global, __MODULE__}, :get_metrics)
+ GenServer.call({:global, __MODULE__}, :get_metrics, 30_000)
end
def clean_metrics do
diff --git a/lib/infrastructure/driven_adapters/mnesia/mnesia.ex b/lib/infrastructure/driven_adapters/mnesia/mnesia.ex
new file mode 100644
index 0000000..d4966bb
--- /dev/null
+++ b/lib/infrastructure/driven_adapters/mnesia/mnesia.ex
@@ -0,0 +1,137 @@
+defmodule MnesiaAdapter do
+ @moduledoc """
+ Provides a high-level interface for interacting with the Mnesia database.
+
+ This module encapsulates common Mnesia operations such as starting the database,
+ creating tables, writing records, and reading data. It also includes logging
+ for better observability and wraps asynchronous operations in Tasks.
+ """
+
+ require Logger
+ alias :mnesia, as: Mnesia
+
+ @type table_name :: atom()
+ @type table_attributes :: [{atom(), atom()}]
+ @type record :: tuple()
+ @type result :: :ok | {:error, term()}
+
+ @doc """
+ Starts the Mnesia database.
+
+ This function attempts to start Mnesia and logs the result. If Mnesia
+ is already running, it returns :ok.
+
+ Returns:
+ * `:ok` if Mnesia started successfully or was already running
+ * `{:error, reason}` if there was an error starting Mnesia
+ """
+ @spec start() :: result()
+ def start do
+ case Mnesia.start() do
+ :ok ->
+ Logger.info("#{__MODULE__}: Mnesia started successfully")
+ :ok
+
+ {:error, {:already_started, _node}} ->
+ Logger.info("#{__MODULE__}: Mnesia already started")
+ :ok
+
+ {:error, reason} ->
+ Logger.error("#{__MODULE__}: Error starting Mnesia: #{inspect(reason)}")
+ {:error, reason}
+ end
+ end
+
+ @doc """
+ Creates a new Mnesia table.
+
+ This function creates a new table in Mnesia with the given name and attributes.
+ It logs the result of the operation.
+
+ Parameters:
+ * `table`: The name of the table to create (atom)
+ * `attributes`: A list of attribute definitions for the table
+
+ Returns:
+ * `:ok` if the table was created successfully
+ * `{:error, reason}` if there was an error creating the table
+ """
+ @spec create_table(table_name(), table_attributes()) :: result()
+ def create_table(table, attributes) when is_atom(table) and is_list(attributes) do
+ Logger.info("#{__MODULE__}: Creating Mnesia table: #{table}")
+
+ case Mnesia.create_table(table, attributes: attributes) do
+ {:atomic, :ok} ->
+ Logger.info("#{__MODULE__}: Mnesia table #{table} created successfully")
+ :ok
+
+ {:aborted, reason} ->
+ Logger.error("#{__MODULE__}: Error creating Mnesia table #{table}: #{inspect(reason)}")
+ {:error, reason}
+ end
+ end
+
+ @doc """
+ Writes a record to Mnesia asynchronously.
+
+ This function writes the given record to Mnesia using a dirty write operation.
+ The operation is wrapped in a Task for asynchronous execution.
+
+ Parameters:
+ * `record`: The record to write to Mnesia (tuple)
+
+ Returns:
+ * A `Task` that will resolve to `:ok` if the write was successful,
+ or `{:error, reason}` if there was an error
+ """
+ @spec write(record()) :: Task.t()
+ def write(record) do
+ Task.async(fn ->
+ Logger.info("#{__MODULE__}: Writing data to Mnesia: #{inspect(record)}")
+
+ case Mnesia.dirty_write(record) do
+ :ok ->
+ Logger.info("#{__MODULE__}: Data written to Mnesia successfully")
+ :ok
+
+ {:error, reason} ->
+ Logger.error("#{__MODULE__}: Error writing data to Mnesia: #{inspect(reason)}")
+ {:error, reason}
+ end
+ end)
+ end
+
+ @doc """
+ Reads a record from Mnesia asynchronously.
+
+ This function reads a record from Mnesia using a dirty read operation.
+ The operation is wrapped in a Task for asynchronous execution.
+
+ Parameters:
+ * `key`: The key to read from Mnesia (can be a tuple for composite keys)
+
+ Returns:
+ * A `Task` that will resolve to `{:ok, [record]}` if the read was successful,
+ `{:ok, []}` if no record was found, or `{:error, reason}` if there was an error
+ """
+ @spec read(record()) :: Task.t()
+ def read(key) do
+ Task.async(fn ->
+ Logger.info("#{__MODULE__}: Reading data from Mnesia: #{inspect(key)}")
+
+ case Mnesia.dirty_read(key) do
+ [] ->
+ Logger.info("#{__MODULE__}: No data found in Mnesia")
+ {:ok, []}
+
+ result when is_list(result) ->
+ Logger.info("#{__MODULE__}: Data read from Mnesia successfully: #{inspect(result)}")
+ {:ok, result}
+
+ {:error, reason} ->
+ Logger.error("#{__MODULE__}: Error reading data from Mnesia: #{inspect(reason)}")
+ {:error, reason}
+ end
+ end)
+ end
+ end
\ No newline at end of file
diff --git a/mix.exs b/mix.exs
index 519fede..268cef4 100644
--- a/mix.exs
+++ b/mix.exs
@@ -13,7 +13,8 @@ defmodule DistributedPerformanceAnalyzer.MixProject do
],
deps: deps(),
aliases: aliases(),
- metrics: true
+ metrics: true,
+ package: package()
]
end
@@ -88,4 +89,17 @@ defmodule DistributedPerformanceAnalyzer.MixProject do
{:poolboy, "~> 1.5"}
]
end
+
+ defp package() do
+ [
+ # This option is only needed when you don't want to use the OTP application name
+ name: "distributed_performance_analyzer",
+ # The organization the package belongs to. The package will be published to the organization repository, defaults = i"hexpm" repository.
+ organization: "bancolombia",
+ files: ["assets", "config", "hooks", "lib", "rel", "test", "Dockerfile", "LICENSE", "SECURITY.md", "README.md", "coveralls.json", "mix.lock", "mix.exs", "sonar-project.properties", ".formatter.exs", ".credo.exs", ".gitignore", ".dockerignore"],
+ maintainers: ["Brayan Batista Zúniga", "Alejandro Jose Tortolero Machado", "Juan David Giraldo Marin"],
+ licenses: ["MIT License"],
+ links: %{"GitHub" => "https://github.com/bancolombia/distributed-performance-analyzer.git"}
+ ]
+ end
end