bddgenx 2.4.7 → 2.4.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/VERSION +1 -1
- data/lib/bddgenx/configuration.rb +65 -7
- data/lib/bddgenx/generators/runner.rb +60 -37
- data/lib/bddgenx/ia/microsoft_copilot_cliente.rb +133 -0
- data/lib/bddgenx/locales/en.yml +1 -0
- data/lib/bddgenx/locales/pt.yml +1 -0
- data/lib/bddgenx/reports/tracer.rb +101 -30
- data/lib/bddgenx/support/properties_loader.rb +108 -0
- data/lib/env.rb +64 -51
- metadata +4 -3
- data/Rakefile +0 -36
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: adf58e7c99b89027c56542f9b2dbff2cc71c336ca164eb6a2bc65308546beef3
|
4
|
+
data.tar.gz: 2093d4ac9a62eea83e87eb7faff89a43196f0a4585f885e515c967e52e0688b8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 10e4ffafcb2230a6a88cd3556ab995dfe936c36925c86027fee92d0e8f74f7e7b75c4bf6ea0415ec5a083dd5c63f9043750b350dcfa04176b3740c1123e67fa8
|
7
|
+
data.tar.gz: 3791efeb6c7a684e666bd73cfa03d21d2f8cc0825e6791655aa639f51901395c0595170661ff06b331e801ee2a158ec5193182ce4e6030712133c0c10c0b1176
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
2.4.
|
1
|
+
2.4.9
|
@@ -1,34 +1,92 @@
|
|
1
|
-
#
|
1
|
+
# encoding: utf-8
|
2
|
+
#
|
3
|
+
# Este arquivo define a classe de configuração global da gem BDDGenX.
|
4
|
+
#
|
5
|
+
# A classe `Bddgenx::Configuration` permite configurar o modo de operação da ferramenta
|
6
|
+
# (ex: estático ou com IA) e define as variáveis de ambiente que armazenam as chaves de API
|
7
|
+
# para serviços externos como OpenAI (ChatGPT), Google Gemini e Microsoft Copilot.
|
8
|
+
|
2
9
|
module Bddgenx
|
10
|
+
# Classe de configuração principal da gem BDDGenX.
|
11
|
+
# Permite definir o modo de geração BDD e os nomes das variáveis de ambiente
|
12
|
+
# que armazenam as chaves de API para integração com serviços de IA.
|
3
13
|
class Configuration
|
4
|
-
#
|
14
|
+
# Modo de execução da gem.
|
15
|
+
# Pode ser:
|
16
|
+
# - :static → geração local
|
17
|
+
# - :chatgpt → uso da IA do ChatGPT (OpenAI)
|
18
|
+
# - :gemini → uso da IA Gemini (Google)
|
19
|
+
# - :copilot → uso do Microsoft Copilot
|
20
|
+
#
|
21
|
+
# @return [Symbol]
|
5
22
|
attr_accessor :mode
|
6
23
|
|
7
|
-
#
|
8
|
-
|
24
|
+
# Nome da variável de ambiente que contém a chave da API da OpenAI
|
25
|
+
# @return [String]
|
26
|
+
attr_accessor :openai_api_key_env
|
27
|
+
|
28
|
+
# Nome da variável de ambiente que contém a chave da API do Google Gemini
|
29
|
+
# @return [String]
|
30
|
+
attr_accessor :gemini_api_key_env
|
31
|
+
|
32
|
+
# Nome da variável de ambiente que contém a chave da API do Microsoft Copilot
|
33
|
+
# @return [String]
|
34
|
+
attr_accessor :microsoft_copilot_api_env
|
9
35
|
|
36
|
+
##
|
37
|
+
# Inicializa a configuração com valores padrão:
|
38
|
+
# - modo: :static
|
39
|
+
# - ENV keys: 'OPENAI_API_KEY', 'GEMINI_API_KEY', 'MICROSOFT_COPILOT_API_KEY'
|
10
40
|
def initialize
|
11
41
|
@mode = :static
|
12
42
|
@openai_api_key_env = 'OPENAI_API_KEY'
|
13
43
|
@gemini_api_key_env = 'GEMINI_API_KEY'
|
44
|
+
@microsoft_copilot_api_env = 'MICROSOFT_COPILOT_API_KEY'
|
14
45
|
end
|
15
46
|
|
16
|
-
|
47
|
+
##
|
48
|
+
# Retorna a chave da API do OpenAI, lida diretamente da ENV.
|
49
|
+
#
|
50
|
+
# @return [String, nil] Chave de API ou nil se não definida
|
17
51
|
def openai_api_key
|
18
52
|
ENV[@openai_api_key_env]
|
19
53
|
end
|
20
54
|
|
55
|
+
##
|
56
|
+
# Retorna a chave da API do Gemini, lida diretamente da ENV.
|
57
|
+
#
|
58
|
+
# @return [String, nil] Chave de API ou nil se não definida
|
21
59
|
def gemini_api_key
|
22
60
|
ENV[@gemini_api_key_env]
|
23
61
|
end
|
62
|
+
|
63
|
+
##
|
64
|
+
# Retorna a chave da API do Microsoft Copilot, lida diretamente da ENV.
|
65
|
+
#
|
66
|
+
# @return [String, nil] Chave de API ou nil se não definida
|
67
|
+
def microsoft_copilot_api_key
|
68
|
+
ENV[@microsoft_copilot_api_env]
|
69
|
+
end
|
24
70
|
end
|
25
71
|
|
26
|
-
|
72
|
+
##
|
73
|
+
# Retorna uma instância singleton da configuração da gem.
|
74
|
+
#
|
75
|
+
# @return [Configuration]
|
27
76
|
def self.configuration
|
28
77
|
@configuration ||= Configuration.new
|
29
78
|
end
|
30
79
|
|
31
|
-
|
80
|
+
##
|
81
|
+
# Permite configurar a gem usando um bloco DSL.
|
82
|
+
#
|
83
|
+
# Exemplo:
|
84
|
+
# Bddgenx.configure do |config|
|
85
|
+
# config.mode = :gemini
|
86
|
+
# config.gemini_api_key_env = 'MY_GEMINI_KEY'
|
87
|
+
# end
|
88
|
+
#
|
89
|
+
# @yieldparam config [Configuration] instância de configuração atual
|
32
90
|
def self.configure
|
33
91
|
yield(configuration)
|
34
92
|
end
|
@@ -1,36 +1,49 @@
|
|
1
1
|
# lib/bddgenx/cli.rb
|
2
2
|
# encoding: utf-8
|
3
3
|
#
|
4
|
-
# Este arquivo define a classe Runner (CLI) da gem
|
5
|
-
#
|
6
|
-
#
|
7
|
-
#
|
4
|
+
# Este arquivo define a classe Runner (CLI) da gem BDDGenX.
|
5
|
+
#
|
6
|
+
# A Runner é responsável por orquestrar todo o fluxo de geração BDD:
|
7
|
+
# - Leitura e validação de histórias (arquivos `.txt`)
|
8
|
+
# - Geração de arquivos `.feature` e steps
|
9
|
+
# - Integração com IA (ChatGPT, Gemini, Copilot)
|
10
|
+
# - Exportação para PDF
|
11
|
+
# - Rastreabilidade via CSV
|
12
|
+
#
|
13
|
+
# Esta classe é o ponto de entrada da gem em execução via terminal (CLI).
|
14
|
+
# O comportamento é configurado com variáveis de ambiente como:
|
15
|
+
# - BDDGENX_MODE (static, chatgpt, gemini, copilot)
|
16
|
+
# - BDDGENX_LANG (pt, en)
|
8
17
|
|
9
18
|
require_relative '../../bddgenx'
|
10
19
|
|
11
20
|
module Bddgenx
|
12
|
-
# Classe principal de execução da gem.
|
13
|
-
#
|
14
|
-
# e
|
21
|
+
# Classe principal de execução da gem BDDGenX.
|
22
|
+
# Controla o fluxo de leitura de histórias, geração de artefatos BDD
|
23
|
+
# e exportação de relatórios. Suporta execução via terminal.
|
15
24
|
class Runner
|
16
25
|
|
17
26
|
##
|
18
|
-
# Retorna a lista de arquivos
|
19
|
-
#
|
20
|
-
#
|
27
|
+
# Retorna a lista de arquivos `.txt` a processar.
|
28
|
+
#
|
29
|
+
# - Se ARGV contiver argumentos, usa esses nomes como arquivos `.txt`
|
30
|
+
# - Caso contrário, entra em modo interativo para seleção manual
|
21
31
|
#
|
22
|
-
# @param input_dir [String] Caminho do diretório
|
23
|
-
# @return [Array<String>] Lista de arquivos `.txt`
|
32
|
+
# @param input_dir [String] Caminho do diretório com arquivos `.txt`
|
33
|
+
# @return [Array<String>] Lista de caminhos de arquivos `.txt`
|
24
34
|
def self.choose_files(input_dir)
|
25
35
|
ARGV.any? ? selecionar_arquivos_txt(input_dir) : choose_input(input_dir)
|
26
36
|
end
|
27
37
|
|
28
38
|
##
|
29
|
-
# Processa argumentos
|
30
|
-
#
|
39
|
+
# Processa os argumentos da linha de comando (ARGV) e gera caminhos
|
40
|
+
# completos para arquivos `.txt` no diretório informado.
|
31
41
|
#
|
32
|
-
#
|
33
|
-
#
|
42
|
+
# - Se a extensão `.txt` estiver ausente, ela é adicionada.
|
43
|
+
# - Arquivos inexistentes são ignorados com aviso.
|
44
|
+
#
|
45
|
+
# @param input_dir [String] Diretório base onde estão os arquivos `.txt`
|
46
|
+
# @return [Array<String>] Lista de arquivos válidos encontrados
|
34
47
|
def self.selecionar_arquivos_txt(input_dir)
|
35
48
|
ARGV.map do |arg|
|
36
49
|
nome = arg.end_with?('.txt') ? arg : "#{arg}.txt"
|
@@ -44,15 +57,18 @@ module Bddgenx
|
|
44
57
|
end
|
45
58
|
|
46
59
|
##
|
47
|
-
#
|
48
|
-
#
|
60
|
+
# Modo interativo para o usuário escolher o arquivo `.txt` a ser processado.
|
61
|
+
#
|
62
|
+
# Exibe uma lista numerada com os arquivos disponíveis no diretório.
|
63
|
+
# O usuário pode selecionar um específico ou pressionar ENTER para todos.
|
49
64
|
#
|
50
|
-
# @param input_dir [String]
|
51
|
-
# @return [Array<String>]
|
65
|
+
# @param input_dir [String] Caminho do diretório com arquivos `.txt`
|
66
|
+
# @return [Array<String>] Arquivo selecionado ou todos disponíveis
|
52
67
|
def self.choose_input(input_dir)
|
53
68
|
files = Dir.glob(File.join(input_dir, '*.txt'))
|
54
69
|
if files.empty?
|
55
|
-
warn "❌ Não há arquivos .txt no diretório #{input_dir}"
|
70
|
+
warn "❌ Não há arquivos .txt no diretório #{input_dir}"
|
71
|
+
exit 1
|
56
72
|
end
|
57
73
|
|
58
74
|
puts "Selecione o arquivo de história para processar:"
|
@@ -63,20 +79,24 @@ module Bddgenx
|
|
63
79
|
return files if choice.empty?
|
64
80
|
idx = choice.to_i - 1
|
65
81
|
unless idx.between?(0, files.size - 1)
|
66
|
-
warn "❌ Escolha inválida."
|
82
|
+
warn "❌ Escolha inválida."
|
83
|
+
exit 1
|
67
84
|
end
|
68
85
|
[files[idx]]
|
69
86
|
end
|
70
87
|
|
71
88
|
##
|
72
|
-
# Executa o fluxo
|
73
|
-
#
|
74
|
-
#
|
75
|
-
# -
|
76
|
-
# -
|
77
|
-
# -
|
89
|
+
# Executa o fluxo principal de geração dos artefatos BDD.
|
90
|
+
#
|
91
|
+
# Etapas executadas:
|
92
|
+
# - Detecta o modo de execução via ENV['BDDGENX_MODE'] (static/chatgpt/gemini/copilot)
|
93
|
+
# - Carrega e valida histórias de usuário
|
94
|
+
# - Gera arquivos `.feature` e seus respectivos steps
|
95
|
+
# - Executa geração via IA (quando aplicável)
|
96
|
+
# - Exporta arquivos em PDF
|
97
|
+
# - Gera rastreabilidade via CSV
|
78
98
|
#
|
79
|
-
#
|
99
|
+
# Exibe no final um resumo das operações executadas.
|
80
100
|
#
|
81
101
|
# @return [void]
|
82
102
|
def self.execute
|
@@ -90,7 +110,7 @@ module Bddgenx
|
|
90
110
|
exit 1
|
91
111
|
end
|
92
112
|
|
93
|
-
# Contadores
|
113
|
+
# Contadores
|
94
114
|
total = features = steps = ignored = 0
|
95
115
|
skipped_steps = []
|
96
116
|
generated_pdfs = []
|
@@ -103,23 +123,22 @@ module Bddgenx
|
|
103
123
|
historia = Parser.ler_historia(arquivo)
|
104
124
|
idioma = Utils.obter_idioma_do_arquivo(arquivo) || historia[:idioma]
|
105
125
|
historia[:idioma] = idioma
|
126
|
+
|
106
127
|
unless Validator.validar(historia)
|
107
128
|
ignored += 1
|
108
129
|
puts "❌ #{I18n.t('messages.invalid_story')}: #{arquivo}"
|
109
130
|
next
|
110
131
|
end
|
111
132
|
|
112
|
-
#
|
113
|
-
if %w[gemini chatgpt].include?(modo)
|
133
|
+
# IA: geração de cenários com Gemini, ChatGPT ou Copilot
|
134
|
+
if %w[gemini chatgpt copilot].include?(modo)
|
114
135
|
puts I18n.t('messages.start_ia', modo: modo.capitalize)
|
115
|
-
idioma = Utils.obter_idioma_do_arquivo(arquivo) || historia[:idioma]
|
116
136
|
|
117
137
|
feature_text = Support::Loader.run(I18n.t('messages.ia_waiting'), :default) do
|
118
138
|
case modo
|
119
|
-
when 'gemini'
|
120
|
-
|
121
|
-
when '
|
122
|
-
IA::ChatGptCliente.gerar_cenarios(historia, idioma)
|
139
|
+
when 'gemini' then IA::GeminiCliente.gerar_cenarios(historia, idioma)
|
140
|
+
when 'chatgpt' then IA::ChatGptCliente.gerar_cenarios(historia, idioma)
|
141
|
+
when 'copilot' then IA::MicrosoftCopilotCliente.gerar_cenarios(historia, idioma)
|
123
142
|
end
|
124
143
|
end
|
125
144
|
|
@@ -139,7 +158,9 @@ module Bddgenx
|
|
139
158
|
end
|
140
159
|
end
|
141
160
|
|
161
|
+
# Salva versão antiga se existir
|
142
162
|
Backup.salvar_versao_antiga(feature_path)
|
163
|
+
|
143
164
|
features += 1 if Generator.salvar_feature(feature_path, feature_content)
|
144
165
|
|
145
166
|
if StepsGenerator.gerar_passos(feature_path)
|
@@ -150,6 +171,8 @@ module Bddgenx
|
|
150
171
|
|
151
172
|
FileUtils.mkdir_p('reports')
|
152
173
|
result = PDFExporter.exportar_todos(only_new: true)
|
174
|
+
Tracer.adicionar_entrada(historia, feature_path)
|
175
|
+
|
153
176
|
generated_pdfs.concat(result[:generated])
|
154
177
|
skipped_pdfs.concat(result[:skipped])
|
155
178
|
end
|
@@ -0,0 +1,133 @@
|
|
1
|
+
module Bddgenx
|
2
|
+
module IA
|
3
|
+
##
|
4
|
+
# Cliente para interação com a API Microsoft Copilot para geração
|
5
|
+
# de conteúdo, aqui usado para criar cenários BDD no formato Gherkin.
|
6
|
+
#
|
7
|
+
class MicrosoftCopilotCliente
|
8
|
+
MICROSOFT_COPILOT_API_URL = ENV['MICROSOFT_COPILOT_API_URL']
|
9
|
+
|
10
|
+
##
|
11
|
+
# Gera cenários BDD baseados em uma história, solicitando à API Microsoft Copilot
|
12
|
+
# o retorno no formato Gherkin com palavras-chave no idioma desejado.
|
13
|
+
#
|
14
|
+
# @param historia [String] Texto base da história para gerar os cenários.
|
15
|
+
# @param idioma [String] Código do idioma, 'pt' por padrão.
|
16
|
+
# @return [String, nil] Cenários no formato Gherkin, ou nil em caso de erro.
|
17
|
+
#
|
18
|
+
def self.gerar_cenarios(historia, idioma = 'pt')
|
19
|
+
api_key = Bddgenx.configuration.microsoft_copilot_api_key # para Copilot
|
20
|
+
|
21
|
+
# Define as palavras-chave para os cenários BDD
|
22
|
+
keywords_pt = {
|
23
|
+
feature: "Funcionalidade",
|
24
|
+
scenario: "Cenário",
|
25
|
+
scenario_outline: "Esquema do Cenário",
|
26
|
+
examples: "Exemplos",
|
27
|
+
given: "Dado",
|
28
|
+
when: "Quando",
|
29
|
+
then: "Então",
|
30
|
+
and: "E"
|
31
|
+
}
|
32
|
+
|
33
|
+
keywords_en = {
|
34
|
+
feature: "Feature",
|
35
|
+
scenario: "Scenario",
|
36
|
+
scenario_outline: "Scenario Outline",
|
37
|
+
examples: "Examples",
|
38
|
+
given: "Given",
|
39
|
+
when: "When",
|
40
|
+
then: "Then",
|
41
|
+
and: "And"
|
42
|
+
}
|
43
|
+
|
44
|
+
# Escolhe o conjunto de palavras-chave conforme o idioma
|
45
|
+
keywords = idioma == 'en' ? keywords_en : keywords_pt
|
46
|
+
|
47
|
+
# Prompt base que instrui a IA a gerar cenários Gherkin no idioma indicado
|
48
|
+
prompt_base = <<~PROMPT
|
49
|
+
Gere cenários BDD no formato Gherkin, utilizando as palavras-chave estruturais no idioma "#{idioma}":
|
50
|
+
Feature: #{keywords[:feature]}
|
51
|
+
Scenario: #{keywords[:scenario]}
|
52
|
+
Scenario Outline: #{keywords[:scenario_outline]}
|
53
|
+
Examples: #{keywords[:examples]}
|
54
|
+
Given: #{keywords[:given]}
|
55
|
+
When: #{keywords[:when]}
|
56
|
+
Then: #{keywords[:then]}
|
57
|
+
And: #{keywords[:and]}
|
58
|
+
|
59
|
+
Instruções:
|
60
|
+
- Todos os textos dos passos devem ser escritos em **português**.
|
61
|
+
- Use as palavras-chave Gherkin no idioma especificado ("#{idioma}").
|
62
|
+
- Gere **vários cenários**, incluindo positivos e negativos.
|
63
|
+
- Use `Scenario Outline` e `Examples` sempre que houver valores variáveis.
|
64
|
+
- Mantenha os parâmetros como `<email>`, `<senha>` e outros entre colchetes angulares, exatamente como aparecem.
|
65
|
+
- Se a história fornecer contexto (ex: `[CONTEXT]` ou "Dado que..."), utilize-o como base para os cenários.
|
66
|
+
- Se não houver contexto explícito, **crie um coerente** baseado na história.
|
67
|
+
- A primeira linha do resultado deve conter obrigatoriamente `# language: #{idioma}`.
|
68
|
+
- Evite passos vagos ou genéricos. Use ações claras e específicas.
|
69
|
+
- Gere apenas o conteúdo da feature, sem explicações adicionais.
|
70
|
+
|
71
|
+
História fornecida:
|
72
|
+
#{historia}
|
73
|
+
PROMPT
|
74
|
+
|
75
|
+
# Verifica se a chave de API foi configurada corretamente
|
76
|
+
unless api_key
|
77
|
+
warn "❌ API Key do Microsoft Copilot não encontrada no .env (MICROSOFT_COPILOT_API_KEY)"
|
78
|
+
return nil
|
79
|
+
end
|
80
|
+
|
81
|
+
# Define o endpoint da API Microsoft Copilot
|
82
|
+
uri = URI("#{MICROSOFT_COPILOT_API_URL}?key=#{api_key}")
|
83
|
+
|
84
|
+
# Estrutura do corpo da requisição para a API Microsoft Copilot
|
85
|
+
request_body = {
|
86
|
+
contents: [
|
87
|
+
{
|
88
|
+
model: "o4-mini",
|
89
|
+
role: "user",
|
90
|
+
parts: [{ text: prompt_base }]
|
91
|
+
}
|
92
|
+
]
|
93
|
+
}
|
94
|
+
|
95
|
+
# Executa requisição POST para a API Microsoft Copilot
|
96
|
+
response = Net::HTTP.post(uri, request_body.to_json, { "Content-Type" => "application/json" })
|
97
|
+
|
98
|
+
# Verifica se a resposta foi bem-sucedida
|
99
|
+
if response.is_a?(Net::HTTPSuccess)
|
100
|
+
json = JSON.parse(response.body)
|
101
|
+
|
102
|
+
unless json["choices"]&.is_a?(Array) && json["choices"].any?
|
103
|
+
warn "❌ Resposta da IA sem candidatos válidos:"
|
104
|
+
warn JSON.pretty_generate(json)
|
105
|
+
return nil
|
106
|
+
end
|
107
|
+
|
108
|
+
# Recupera o conteúdo gerado pela IA
|
109
|
+
texto_ia = json["choices"].first.dig("message", "content")
|
110
|
+
|
111
|
+
if texto_ia
|
112
|
+
# Limpeza e sanitização do texto para manter padrão Gherkin
|
113
|
+
texto_limpo = Utils.limpar(texto_ia)
|
114
|
+
Utils.remover_steps_duplicados(texto_ia, idioma)
|
115
|
+
|
116
|
+
# Ajuste da diretiva de idioma na saída gerada
|
117
|
+
texto_limpo.sub!(/^# language: .*/, "# language: #{idioma}")
|
118
|
+
texto_limpo.prepend("# language: #{idioma}\n") unless texto_limpo.start_with?("# language:")
|
119
|
+
|
120
|
+
return texto_limpo
|
121
|
+
else
|
122
|
+
warn I18n.t('errors.ia_no_content')
|
123
|
+
warn JSON.pretty_generate(json)
|
124
|
+
return nil
|
125
|
+
end
|
126
|
+
else
|
127
|
+
warn I18n.t('errors.microsoft_copilot_error', code: response.code, body: response.body)
|
128
|
+
return nil
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
data/lib/bddgenx/locales/en.yml
CHANGED
@@ -28,6 +28,7 @@ en:
|
|
28
28
|
ia_no_content: "❌ No content returned from AI"
|
29
29
|
gemini_error: "❌ Error calling Gemini: %{code} - %{body}"
|
30
30
|
chatgpt_key_missing: "❌ ChatGPT API key not found in .env (OPENAI_API_KEY)"
|
31
|
+
microsoft_copilot_error: "Erro"
|
31
32
|
openai_quota: "❌ OpenAI API quota exceeded."
|
32
33
|
openai_check_usage: "🔗 Check your usage: https://platform.openai.com/account/usage"
|
33
34
|
feature_not_found: "⚠️ Feature not found: %{feature}"
|
data/lib/bddgenx/locales/pt.yml
CHANGED
@@ -29,6 +29,7 @@ pt:
|
|
29
29
|
gemini_error: "❌ Erro ao chamar Gemini: %{code} - %{body}"
|
30
30
|
chatgpt_key_missing: "❌ API Key do ChatGPT não encontrada no .env (OPENAI_API_KEY)"
|
31
31
|
openai_quota: "❌ Limite de uso da API OpenAI excedido."
|
32
|
+
microsoft_copilot_error: "Erro"
|
32
33
|
openai_check_usage: "🔗 Verifique sua conta: https://platform.openai.com/account/usage"
|
33
34
|
feature_not_found: "⚠️ Feature não encontrada: %{feature}"
|
34
35
|
pdf_generation_failed: "❌ Erro ao gerar PDF de %{file}: %{error}"
|
@@ -1,70 +1,141 @@
|
|
1
|
-
# lib/bddgenx/tracer.rb
|
2
1
|
# encoding: utf-8
|
3
2
|
#
|
4
|
-
# Este arquivo define a classe Tracer
|
5
|
-
#
|
6
|
-
#
|
3
|
+
# Este arquivo define a classe `Tracer`, responsável por gerar arquivos de rastreabilidade
|
4
|
+
# (CSV) a partir das features geradas automaticamente pela gem BDDGenX.
|
5
|
+
#
|
6
|
+
# Para cada feature processada, o `Tracer` extrai os cenários da própria feature `.feature`
|
7
|
+
# e associa cada passo definido na história original com o bloco Gherkin correspondente.
|
8
|
+
# O objetivo é fornecer visibilidade e rastreabilidade completa entre requisitos e testes.
|
9
|
+
|
10
|
+
require 'csv'
|
11
|
+
require 'fileutils'
|
12
|
+
|
7
13
|
module Bddgenx
|
8
|
-
# Classe
|
14
|
+
# Classe responsável por rastrear os artefatos gerados pela gem
|
15
|
+
# e exportá-los em arquivos CSV, um por funcionalidade.
|
16
|
+
#
|
17
|
+
# Para cada grupo de passos (do `.txt`), associa os dados com o
|
18
|
+
# cenário equivalente gerado no arquivo `.feature`.
|
9
19
|
class Tracer
|
10
|
-
|
11
|
-
#
|
20
|
+
##
|
21
|
+
# Adiciona entradas de rastreabilidade a um CSV baseado na feature gerada.
|
22
|
+
#
|
23
|
+
# - Cada funcionalidade recebe um arquivo CSV próprio, salvo em:
|
24
|
+
# `reports/output/funcionalidade_<nome>.csv`
|
25
|
+
#
|
26
|
+
# - A coluna "BDD" contém o cenário completo extraído diretamente do `.feature`,
|
27
|
+
# preservando a sintaxe original do Gherkin (cenário, steps, tags).
|
12
28
|
#
|
13
29
|
# @param historia [Hash]
|
14
|
-
#
|
15
|
-
#
|
16
|
-
#
|
17
|
-
#
|
30
|
+
# Hash representando a história extraída do `.txt`, contendo:
|
31
|
+
# - :quero → nome da funcionalidade
|
32
|
+
# - :grupos → lista de blocos com :tipo, :tag e :passos
|
33
|
+
#
|
34
|
+
# @param feature_path [String]
|
35
|
+
# Caminho do arquivo `.feature` já gerado no sistema
|
36
|
+
#
|
18
37
|
# @return [void]
|
19
|
-
def self.adicionar_entrada(historia,
|
20
|
-
# Garante existência do diretório de saída
|
38
|
+
def self.adicionar_entrada(historia, feature_path)
|
21
39
|
FileUtils.mkdir_p('reports/output')
|
22
|
-
arquivo_csv = 'reports/output/rastreabilidade.csv'
|
23
40
|
|
24
|
-
|
25
|
-
|
41
|
+
nome_funcionalidade = historia[:quero].gsub(/^Quero\s*/, '').strip
|
42
|
+
nome_funcionalidade_sanitizado = nome_funcionalidade.downcase.gsub(/[^a-z0-9]+/, '_')
|
43
|
+
arquivo_csv = "reports/output/funcionalidade_#{nome_funcionalidade_sanitizado}.csv"
|
26
44
|
|
45
|
+
cabecalho = ['Funcionalidade', 'Tipo', 'Tag', 'Cenário', 'Passo', 'Origem', 'BDD']
|
27
46
|
linhas = []
|
28
47
|
|
29
|
-
#
|
48
|
+
# Leitura real da feature gerada
|
49
|
+
blocos_gherkin = extrair_cenarios_gherkin(feature_path)
|
50
|
+
|
30
51
|
historia[:grupos].each_with_index do |grupo, idx|
|
31
52
|
tipo = grupo[:tipo]
|
32
|
-
tag = grupo[:tag]
|
53
|
+
tag = grupo[:tag] || '-'
|
33
54
|
passos = grupo[:passos] || []
|
34
|
-
|
35
|
-
nome_funcionalidade = historia[:quero].gsub(/^Quero\s*/, '').strip
|
36
55
|
nome_cenario = "Cenário #{idx + 1}"
|
37
56
|
|
57
|
+
# Bloco Gherkin real do cenário gerado
|
58
|
+
gherkin_bloco = blocos_gherkin[idx] || ''
|
59
|
+
|
38
60
|
passos.each do |passo|
|
39
61
|
linhas << [
|
40
62
|
nome_funcionalidade,
|
41
63
|
tipo,
|
42
|
-
tag
|
64
|
+
tag,
|
43
65
|
nome_cenario,
|
44
66
|
passo,
|
45
|
-
File.basename(
|
67
|
+
File.basename(feature_path),
|
68
|
+
gherkin_bloco
|
46
69
|
]
|
47
70
|
end
|
48
71
|
end
|
49
72
|
|
50
|
-
# Escreve ou anexa as linhas geradas ao CSV
|
51
73
|
escrever_csv(arquivo_csv, cabecalho, linhas)
|
52
74
|
end
|
53
75
|
|
54
|
-
|
76
|
+
##
|
77
|
+
# Escreve ou anexa dados em um arquivo CSV.
|
78
|
+
# - Cria o cabeçalho caso seja a primeira escrita.
|
79
|
+
# - Evita duplicações com base na combinação "Passo + Origem".
|
80
|
+
#
|
81
|
+
# @param caminho [String] Caminho completo do arquivo CSV a ser salvo
|
82
|
+
# @param cabecalho [Array<String>] Títulos das colunas do CSV
|
83
|
+
# @param novas_linhas [Array<Array>] Linhas de conteúdo a serem gravadas
|
55
84
|
#
|
56
|
-
# @param caminho [String] Caminho completo para o arquivo CSV de rastreabilidade
|
57
|
-
# @param cabecalho [Array<String>] Array de títulos das colunas a serem escritos
|
58
|
-
# @param linhas [Array<Array<String>>] Dados a serem gravados no CSV (cada sub-array é uma linha)
|
59
85
|
# @return [void]
|
60
|
-
def self.escrever_csv(caminho, cabecalho,
|
61
|
-
# Verifica se é um novo arquivo para incluir o cabeçalho
|
86
|
+
def self.escrever_csv(caminho, cabecalho, novas_linhas)
|
62
87
|
novo_arquivo = !File.exist?(caminho)
|
63
88
|
|
89
|
+
existentes = []
|
90
|
+
if File.exist?(caminho)
|
91
|
+
existentes = CSV.read(caminho, col_sep: ';', headers: true).map do |row|
|
92
|
+
[row['Passo'], row['Origem']]
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
64
96
|
CSV.open(caminho, 'a+', col_sep: ';', force_quotes: true) do |csv|
|
65
97
|
csv << cabecalho if novo_arquivo
|
66
|
-
|
98
|
+
|
99
|
+
novas_linhas.each do |linha|
|
100
|
+
passo, origem = linha[4], linha[5]
|
101
|
+
next if existentes.include?([passo, origem])
|
102
|
+
csv << linha
|
103
|
+
end
|
67
104
|
end
|
68
105
|
end
|
106
|
+
|
107
|
+
##
|
108
|
+
# Extrai todos os cenários completos do arquivo `.feature` gerado,
|
109
|
+
# preservando a estrutura Gherkin original (cenários, tags, steps).
|
110
|
+
#
|
111
|
+
# Um novo bloco é iniciado quando uma das palavras-chave de título
|
112
|
+
# de cenário é encontrada.
|
113
|
+
#
|
114
|
+
# @param feature_path [String] Caminho completo do arquivo `.feature`
|
115
|
+
# @return [Array<String>] Lista de blocos Gherkin, um por cenário
|
116
|
+
def self.extrair_cenarios_gherkin(feature_path)
|
117
|
+
return [] unless File.exist?(feature_path)
|
118
|
+
|
119
|
+
content = File.read(feature_path)
|
120
|
+
linhas = content.lines
|
121
|
+
|
122
|
+
blocos = []
|
123
|
+
bloco_atual = []
|
124
|
+
capturando = false
|
125
|
+
|
126
|
+
linhas.each_with_index do |linha, i|
|
127
|
+
if linha.strip =~ /^(Scenario|Scenario Outline|Cenário|Esquema do Cenário):/i
|
128
|
+
# Novo cenário → salva anterior
|
129
|
+
blocos << bloco_atual.join if bloco_atual.any?
|
130
|
+
bloco_atual = [linha]
|
131
|
+
capturando = true
|
132
|
+
elsif capturando
|
133
|
+
bloco_atual << linha
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
blocos << bloco_atual.join if bloco_atual.any?
|
138
|
+
blocos
|
139
|
+
end
|
69
140
|
end
|
70
141
|
end
|
@@ -0,0 +1,108 @@
|
|
1
|
+
# lib/bddgenx/properties_loader.rb
|
2
|
+
#
|
3
|
+
# Módulo `Bddgenx::PropertiesLoader` é responsável por carregar e processar os arquivos de configuração
|
4
|
+
# `.properties` que contêm variáveis de ambiente, além de também carregar as variáveis do arquivo `.env`.
|
5
|
+
# Este módulo lida com a substituição de placeholders nas propriedades, garantindo que as variáveis de ambiente
|
6
|
+
# sejam corretamente carregadas e definidas para uso no sistema.
|
7
|
+
#
|
8
|
+
# O fluxo de trabalho é o seguinte:
|
9
|
+
# 1. Carregar variáveis de ambiente a partir do arquivo `.env`.
|
10
|
+
# 2. Localizar e ler arquivos `.properties` presentes no diretório raiz do projeto.
|
11
|
+
# 3. Substituir placeholders no conteúdo dos arquivos `.properties` com variáveis de ambiente.
|
12
|
+
# 4. Mesclar as propriedades carregadas e definir as variáveis de ambiente no Ruby.
|
13
|
+
#
|
14
|
+
# Este módulo permite a configuração flexível de variáveis de ambiente, com suporte tanto para arquivos `.env`
|
15
|
+
# quanto para arquivos `.properties`.
|
16
|
+
|
17
|
+
module Bddgenx
|
18
|
+
class PropertiesLoader
|
19
|
+
# Carregar as variáveis do arquivo .env
|
20
|
+
#
|
21
|
+
# Este método utiliza a gem `dotenv` para carregar variáveis de ambiente a partir de um arquivo `.env`.
|
22
|
+
# Ele carrega as variáveis do arquivo `.env` para o ambiente de execução, onde elas ficam disponíveis via
|
23
|
+
# `ENV['VAR_NAME']` em qualquer parte do código.
|
24
|
+
def self.load_env_variables
|
25
|
+
Dotenv.load # Carrega as variáveis do .env automaticamente
|
26
|
+
end
|
27
|
+
|
28
|
+
# Função para substituir variáveis no conteúdo do arquivo .properties
|
29
|
+
#
|
30
|
+
# Este método recebe o conteúdo de um arquivo `.properties` e substitui os placeholders no formato `{{VAR_NAME}}`
|
31
|
+
# pelas variáveis de ambiente correspondentes, se definidas. Caso a variável de ambiente não esteja definida,
|
32
|
+
# o placeholder original é mantido no conteúdo.
|
33
|
+
#
|
34
|
+
# @param content [String] O conteúdo do arquivo `.properties` a ser processado.
|
35
|
+
# @return [String] O conteúdo com os placeholders substituídos pelas variáveis de ambiente.
|
36
|
+
def self.replace_placeholders(content)
|
37
|
+
content.gsub!(/\{\{(\w+)\}\}/) do |match|
|
38
|
+
ENV[$1] || match # Substitui pela variável de ambiente ou mantém o placeholder
|
39
|
+
end
|
40
|
+
content
|
41
|
+
end
|
42
|
+
|
43
|
+
# Função para garantir que o arquivo seja lido com a codificação correta
|
44
|
+
#
|
45
|
+
# Este método lê um arquivo especificado com codificação UTF-8. Caso o arquivo contenha caracteres inválidos,
|
46
|
+
# eles são substituídos por um caractere de substituição, garantindo que o conteúdo seja lido corretamente.
|
47
|
+
#
|
48
|
+
# @param file [String] O caminho do arquivo a ser lido.
|
49
|
+
# @return [String] O conteúdo do arquivo lido, com caracteres inválidos substituídos, se necessário.
|
50
|
+
def self.read_file_with_correct_encoding(file)
|
51
|
+
# Lê o arquivo com codificação UTF-8 e ignora caracteres inválidos
|
52
|
+
content = File.read(file, encoding: 'UTF-8')
|
53
|
+
content.encode('UTF-8', invalid: :replace, undef: :replace, replace: '?')
|
54
|
+
end
|
55
|
+
|
56
|
+
# Carregar e substituir propriedades de arquivos .properties
|
57
|
+
#
|
58
|
+
# Este método localiza todos os arquivos `.properties` no diretório raiz do projeto,
|
59
|
+
# lê seu conteúdo, substitui os placeholders pelas variáveis de ambiente, carrega as propriedades
|
60
|
+
# e mescla essas propriedades em um único hash.
|
61
|
+
#
|
62
|
+
# Após carregar as propriedades, ele também define as variáveis de ambiente no Ruby (via `ENV`)
|
63
|
+
# usando as propriedades carregadas, mas não sobrescreve as variáveis de ambiente já definidas.
|
64
|
+
#
|
65
|
+
# @return [Hash] O hash contendo as propriedades carregadas e mescladas dos arquivos `.properties`.
|
66
|
+
def self.load_properties
|
67
|
+
# Carregar variáveis do .env primeiro
|
68
|
+
load_env_variables
|
69
|
+
|
70
|
+
# Localizar arquivos .properties na raiz do projeto
|
71
|
+
properties_files = Dir.glob(File.expand_path('../*.properties', __dir__))
|
72
|
+
|
73
|
+
properties = {}
|
74
|
+
|
75
|
+
properties_files.each do |file|
|
76
|
+
# Forçar a leitura do arquivo com codificação UTF-8 e lidar com caracteres inválidos
|
77
|
+
content = read_file_with_correct_encoding(file)
|
78
|
+
|
79
|
+
# Substituir os placeholders antes de carregar as propriedades
|
80
|
+
content = replace_placeholders(content)
|
81
|
+
|
82
|
+
# Carregar as propriedades do arquivo
|
83
|
+
file_properties = JavaProperties::Properties.load(StringIO.new(content))
|
84
|
+
|
85
|
+
# Mesclar as propriedades carregadas no hash
|
86
|
+
properties.merge!(file_properties.to_h)
|
87
|
+
end
|
88
|
+
|
89
|
+
# Agora, define as variáveis de ambiente a partir das propriedades carregadas
|
90
|
+
set_environment_variables(properties)
|
91
|
+
|
92
|
+
properties
|
93
|
+
end
|
94
|
+
|
95
|
+
# Função para definir variáveis de ambiente a partir das propriedades carregadas
|
96
|
+
#
|
97
|
+
# Este método percorre as propriedades carregadas e as define como variáveis de ambiente (`ENV`) no Ruby.
|
98
|
+
# Se a variável de ambiente já estiver definida (por exemplo, pelo `.env`), ela não será sobrescrita.
|
99
|
+
#
|
100
|
+
# @param properties [Hash] O hash contendo as propriedades carregadas dos arquivos `.properties`.
|
101
|
+
def self.set_environment_variables(properties)
|
102
|
+
properties.each do |key, value|
|
103
|
+
# Se a variável de ambiente já estiver definida, não sobrescreve
|
104
|
+
ENV[key.upcase] ||= value
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
data/lib/env.rb
CHANGED
@@ -1,10 +1,14 @@
|
|
1
|
-
# lib/bddgenx/env.rb
|
2
1
|
# encoding: utf-8
|
3
2
|
#
|
4
|
-
#
|
5
|
-
#
|
6
|
-
#
|
7
|
-
#
|
3
|
+
# Este arquivo é responsável por carregar todas as dependências da gem `bddgenx`.
|
4
|
+
#
|
5
|
+
# Ele inclui:
|
6
|
+
# - Gems padrão do Ruby (ex: JSON, net/http, fileutils)
|
7
|
+
# - Gems externas (ex: Prawn, Faraday, Dotenv)
|
8
|
+
# - Módulos internos do projeto `bddgenx`
|
9
|
+
#
|
10
|
+
# Também define o idioma ativo da gem (via I18n), configura variáveis de ambiente
|
11
|
+
# e carrega clientes de IA, geradores, validadores, exportadores e estruturas de projeto.
|
8
12
|
|
9
13
|
# --------------------------------------
|
10
14
|
# 📦 Gems padrão da linguagem Ruby
|
@@ -14,98 +18,107 @@ require 'json' # Manipulação de dados JSON
|
|
14
18
|
require 'net/http' # Requisições HTTP nativas
|
15
19
|
require 'uri' # Manipulação de URLs
|
16
20
|
require 'fileutils' # Operações com arquivos e diretórios
|
17
|
-
require 'open3' # Execução de comandos externos
|
18
|
-
require 'bigdecimal' # Cálculos
|
19
|
-
require 'i18n' # Internacionalização
|
21
|
+
require 'open3' # Execução de comandos externos
|
22
|
+
require 'bigdecimal' # Cálculos com alta precisão
|
23
|
+
require 'i18n' # Internacionalização
|
24
|
+
require 'csv' # Manipulação de arquivos CSV
|
25
|
+
require 'yard' # Documentação automática
|
20
26
|
|
21
27
|
# --------------------------------------
|
22
28
|
# 📚 Gems externas
|
23
29
|
# --------------------------------------
|
24
30
|
|
25
|
-
require 'prawn' # Geração de
|
26
|
-
require 'prawn/table' #
|
31
|
+
require 'prawn' # Geração de PDFs
|
32
|
+
require 'prawn/table' # Tabelas em PDF
|
27
33
|
require 'prawn-svg' # Suporte a SVG no PDF
|
28
|
-
require 'faraday' # Cliente HTTP
|
29
|
-
require 'dotenv' # Carrega variáveis de
|
30
|
-
require 'unicode' # Manipulação
|
34
|
+
require 'faraday' # Cliente HTTP
|
35
|
+
require 'dotenv' # Carrega variáveis de .env
|
36
|
+
require 'unicode' # Manipulação de caracteres unicode
|
37
|
+
require 'java_properties'# Leitura de arquivos .properties
|
38
|
+
require 'stringio' # IO virtual em memória
|
39
|
+
require 'tempfile' # Arquivos temporários
|
31
40
|
|
32
41
|
# --------------------------------------
|
33
42
|
# 🌍 Configuração de idioma (I18n)
|
34
43
|
# --------------------------------------
|
35
44
|
|
36
|
-
Dotenv.load # Carrega variáveis
|
45
|
+
Dotenv.load # Carrega as variáveis do `.env`
|
37
46
|
|
38
|
-
#
|
47
|
+
# Carrega os arquivos de tradução do diretório `locales/`
|
39
48
|
locales_path = File.expand_path('bddgenx/locales/*.yml', __dir__)
|
40
49
|
I18n.load_path += Dir[locales_path]
|
41
50
|
|
42
|
-
# Define o idioma ativo
|
43
|
-
|
44
|
-
if idioma_env && !idioma_env.strip.empty?
|
45
|
-
I18n.locale = idioma_env.strip.to_sym
|
46
|
-
else
|
47
|
-
I18n.locale = :pt
|
48
|
-
end
|
49
|
-
|
51
|
+
# Define o idioma ativo com base em ENV['BDDGENX_LANG'], padrão: :pt
|
52
|
+
I18n.locale = ENV['BDDGENX_LANG']&.strip&.to_sym || :pt
|
50
53
|
|
51
54
|
# --------------------------------------
|
52
|
-
# 🔧 Bundler (para
|
55
|
+
# 🔧 Bundler (para carregar dependências do Gemfile)
|
53
56
|
# --------------------------------------
|
54
57
|
|
55
|
-
# Carrega as dependências listadas no Gemfile (se houver)
|
56
58
|
require 'bundler/setup' if File.exist?(File.expand_path('../../Gemfile', __FILE__))
|
57
59
|
|
58
60
|
# --------------------------------------
|
59
|
-
# 🧩 Módulos utilitários
|
61
|
+
# 🧩 Módulos utilitários internos
|
60
62
|
# --------------------------------------
|
61
63
|
|
62
|
-
require_relative 'bddgenx/support/validator'
|
63
|
-
require_relative 'bddgenx/support/font_loader'
|
64
|
-
|
65
|
-
require_relative 'bddgenx/utils/
|
66
|
-
require_relative 'bddgenx/utils/remover_steps_duplicados_helper' # Remove passos duplicados
|
64
|
+
require_relative 'bddgenx/support/validator'
|
65
|
+
require_relative 'bddgenx/support/font_loader'
|
66
|
+
require_relative 'bddgenx/utils/gherkin_cleaner_helper'
|
67
|
+
require_relative 'bddgenx/utils/remover_steps_duplicados_helper'
|
67
68
|
require_relative 'bddgenx/utils/language_helper'
|
68
69
|
|
69
70
|
# --------------------------------------
|
70
|
-
# 🤖 Clientes de IA (
|
71
|
+
# 🤖 Clientes de IA (OpenAI, Gemini, Copilot)
|
71
72
|
# --------------------------------------
|
72
73
|
|
73
|
-
require_relative 'bddgenx/ia/gemini_cliente'
|
74
|
-
require_relative 'bddgenx/ia/chatgtp_cliente'
|
74
|
+
require_relative 'bddgenx/ia/gemini_cliente'
|
75
|
+
require_relative 'bddgenx/ia/chatgtp_cliente'
|
76
|
+
require_relative 'bddgenx/ia/microsoft_copilot_cliente'
|
75
77
|
|
76
78
|
# --------------------------------------
|
77
|
-
# 🛠 Geradores
|
79
|
+
# 🛠 Geradores e Orquestrador
|
78
80
|
# --------------------------------------
|
79
81
|
|
80
|
-
require_relative 'bddgenx/generators/generator'
|
81
|
-
require_relative 'bddgenx/generators/steps_generator'
|
82
|
-
require_relative 'bddgenx/generators/runner'
|
82
|
+
require_relative 'bddgenx/generators/generator'
|
83
|
+
require_relative 'bddgenx/generators/steps_generator'
|
84
|
+
require_relative 'bddgenx/generators/runner'
|
83
85
|
|
84
86
|
# --------------------------------------
|
85
|
-
# 📄 Parser e
|
87
|
+
# 📄 Parser e Metadados
|
86
88
|
# --------------------------------------
|
87
89
|
|
88
|
-
require_relative 'parser'
|
89
|
-
require_relative 'bddgenx/version'
|
90
|
+
require_relative 'parser'
|
91
|
+
require_relative 'bddgenx/version'
|
90
92
|
|
91
93
|
# --------------------------------------
|
92
|
-
# 📤 Relatórios e
|
94
|
+
# 📤 Relatórios e Exportação
|
93
95
|
# --------------------------------------
|
94
96
|
|
95
|
-
require_relative 'bddgenx/reports/pdf_exporter'
|
96
|
-
require_relative 'bddgenx/reports/backup'
|
97
|
-
require_relative 'bddgenx/reports/tracer'
|
97
|
+
require_relative 'bddgenx/reports/pdf_exporter'
|
98
|
+
require_relative 'bddgenx/reports/backup'
|
99
|
+
require_relative 'bddgenx/reports/tracer'
|
98
100
|
|
99
101
|
# --------------------------------------
|
100
|
-
# ⚙️ Configuração
|
102
|
+
# ⚙️ Configuração e Setup
|
101
103
|
# --------------------------------------
|
102
104
|
|
103
|
-
require_relative 'bddgenx/configuration'
|
104
|
-
require_relative 'bddgenx/setup'
|
105
|
-
require_relative 'bddgenx/support/loader'
|
105
|
+
require_relative 'bddgenx/configuration'
|
106
|
+
require_relative 'bddgenx/setup'
|
107
|
+
require_relative 'bddgenx/support/loader'
|
108
|
+
require_relative 'bddgenx/support/properties_loader'
|
106
109
|
|
107
110
|
# --------------------------------------
|
108
|
-
# 🔁
|
111
|
+
# 🔁 Carregamento de propriedades como variáveis de ambiente
|
109
112
|
# --------------------------------------
|
110
113
|
|
111
|
-
|
114
|
+
properties = Bddgenx::PropertiesLoader.load_properties
|
115
|
+
|
116
|
+
# Mapeamento de variáveis .properties → ENV
|
117
|
+
ENV['CHATGPT_API_URL'] ||= properties['openai.api.url']
|
118
|
+
ENV['OPENAI_API_KEY'] ||= properties['openai.api.key']
|
119
|
+
ENV['GEMINI_API_URL'] ||= properties['gemini.api.url']
|
120
|
+
ENV['GEMINI_API_KEY'] ||= properties['gemini.api.key']
|
121
|
+
ENV['MICROSOFT_COPILOT_API_URL'] ||= properties['copilot.api.url']
|
122
|
+
ENV['MICROSOFT_COPILOT_API_KEY'] ||= properties['copilot.api.key']
|
123
|
+
ENV['BDDGENX_MODE'] ||= properties['mode']
|
124
|
+
ENV['BDDGENX_LANG'] ||= properties['lang']
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: bddgenx
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.4.
|
4
|
+
version: 2.4.9
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- David Nascimento
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2025-05-
|
11
|
+
date: 2025-05-20 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: prawn
|
@@ -118,7 +118,6 @@ extensions: []
|
|
118
118
|
extra_rdoc_files: []
|
119
119
|
files:
|
120
120
|
- README.md
|
121
|
-
- Rakefile
|
122
121
|
- VERSION
|
123
122
|
- bin/bddgenx
|
124
123
|
- lib/bddgenx.rb
|
@@ -132,6 +131,7 @@ files:
|
|
132
131
|
- lib/bddgenx/generators/steps_generator.rb
|
133
132
|
- lib/bddgenx/ia/chatgtp_cliente.rb
|
134
133
|
- lib/bddgenx/ia/gemini_cliente.rb
|
134
|
+
- lib/bddgenx/ia/microsoft_copilot_cliente.rb
|
135
135
|
- lib/bddgenx/locales/en.yml
|
136
136
|
- lib/bddgenx/locales/pt.yml
|
137
137
|
- lib/bddgenx/reports/backup.rb
|
@@ -140,6 +140,7 @@ files:
|
|
140
140
|
- lib/bddgenx/setup.rb
|
141
141
|
- lib/bddgenx/support/font_loader.rb
|
142
142
|
- lib/bddgenx/support/loader.rb
|
143
|
+
- lib/bddgenx/support/properties_loader.rb
|
143
144
|
- lib/bddgenx/support/validator.rb
|
144
145
|
- lib/bddgenx/utils/gherkin_cleaner_helper.rb
|
145
146
|
- lib/bddgenx/utils/language_helper.rb
|
data/Rakefile
DELETED
@@ -1,36 +0,0 @@
|
|
1
|
-
require 'bddgenx'
|
2
|
-
require 'rake'
|
3
|
-
|
4
|
-
namespace :bddgenx do
|
5
|
-
desc 'Executa geração interativa: escolha entre static, chatgpt, gemini ou deepseek'
|
6
|
-
task :generate do
|
7
|
-
puts "=== Qual modo deseja usar para gerar os cenários? ==="
|
8
|
-
puts "1. static (sem IA)"
|
9
|
-
puts "2. chatgpt (via OpenAI)"
|
10
|
-
puts "3. gemini (via Google)"
|
11
|
-
print "Digite o número (1-3): "
|
12
|
-
|
13
|
-
escolha = STDIN.gets.chomp.to_i
|
14
|
-
|
15
|
-
modo = case escolha
|
16
|
-
when 1 then :static
|
17
|
-
when 2 then :chatgpt
|
18
|
-
when 3 then :gemini
|
19
|
-
else
|
20
|
-
puts "❌ Opção inválida. Saindo."; exit 1
|
21
|
-
end
|
22
|
-
|
23
|
-
Bddgenx.configure do |config|
|
24
|
-
config.mode = modo
|
25
|
-
config.openai_api_key_env = 'OPENAI_API_KEY'
|
26
|
-
config.gemini_api_key_env = 'GEMINI_API_KEY'
|
27
|
-
end
|
28
|
-
|
29
|
-
# ⚠️ Limpa o ARGV antes de executar para evitar que [static] seja interpretado como nome de arquivo
|
30
|
-
ARGV.clear
|
31
|
-
|
32
|
-
ENV['BDDGENX_MODE'] = modo.to_s
|
33
|
-
puts "\n⚙️ Modo selecionado: #{modo}\n\n"
|
34
|
-
Bddgenx::Runner.execute
|
35
|
-
end
|
36
|
-
end
|