Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
21adbf3
Update .gitignore to exclude additional client directories and docume…
andrenfe Jun 24, 2026
44177ad
docs(openspec): plan NFE.io Ruby SDK v1 greenfield rewrite
andrenfe Jun 25, 2026
6ee8b14
feat!: v1 greenfield SDK — foundation, HTTP transport, OpenAPI pipeline
andrenfe Jun 25, 2026
78f8733
chore(openspec): archive completed changes and sync specs
andrenfe Jun 25, 2026
1ed98ca
feat(client-core): Nfe::Client, Configuration, AbstractResource + 17 …
andrenfe Jun 25, 2026
803c6a3
feat(entity-resources): companies, people, webhooks + signature & cer…
andrenfe Jun 25, 2026
76fc741
chore(openspec): archive client-core + entity-resources, sync specs
andrenfe Jun 25, 2026
0bb6f53
feat(invoice-resources): emission + query for the 5 invoice families
andrenfe Jun 25, 2026
272f5c6
feat(lookup-resources): 8 query/lookup resources + DateNormalizer
andrenfe Jun 25, 2026
1409daf
feat(rtc-invoice-emission): RTC NFS-e + NF-e/NFC-e emission resources
andrenfe Jun 25, 2026
a63c269
chore(release-tooling): gem packaging, docs, samples, release automation
andrenfe Jun 25, 2026
fd50b0f
docs: correct production/test separation (account-side, not the API key)
andrenfe Jun 25, 2026
25fd245
docs: Docusaurus-ready docs site + branded YARD API reference
andrenfe Jun 26, 2026
3c7a4de
docs: pt-BR slugs in frontmatter + rename resources/ -> recursos/
andrenfe Jun 26, 2026
f4f0fa8
docs: absolute slug on the Ruby SDK landing (matches nodejs/index.md)
andrenfe Jun 26, 2026
db7a8bc
fix(resources): corrigir 3 descasamentos com a API real (smoke test s…
andrenfe Jun 26, 2026
74031f6
feat(smoke): add smoke test for NF-e issuance against real API (sandbox)
andrenfe Jul 1, 2026
05e2a14
ci: rodar CI no branch next e alinhar o gate do release (rbs validate)
andrenfe Jul 1, 2026
c577006
ci: bump actions/checkout v4 -> v5 (roda em Node 24)
andrenfe Jul 2, 2026
45a4d0b
fix(security): eliminar ReDoS polinomial na validacao de e-mail (Code…
andrenfe Jul 2, 2026
2a1f937
ci(release): usar OIDC API Key Role do RubyGems (role-to-assume)
andrenfe Jul 2, 2026
05a1ffb
ci(release): usar Trusted Publishing do RubyGems (sem role-to-assume)
andrenfe Jul 2, 2026
a11d433
docs(changelog): data de release da 1.0.0 -> 2026-07-02
andrenfe Jul 2, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
16 changes: 16 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# Keep the build context small and avoid leaking sibling repos / local junk.
.git
.github
# Local dev symlinks to sibling repos (would be dangling inside the container).
client-nodejs
client-php
nfeio-docs
# Build/test artifacts (regenerated inside the container).
coverage
pkg
tmp
.bundle
.steep
*.gem
Gemfile.lock
.env
12 changes: 12 additions & 0 deletions .env.docker.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# Copy to .env (one-time) so the container user matches your host UID/GID and
# bind-mount-written files (Gemfile.lock, coverage/) stay owned by you.
#
# cp .env.docker.example .env
#
# On Linux, set these to your own ids: `id -u` and `id -g`.
UID=1000
GID=1000

# Optional SDK credentials forwarded into the container (for future E2E scripts):
# NFE_API_KEY=
# NFE_DATA_API_KEY=
3 changes: 3 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Generated artifacts (from the OpenAPI pipeline) — collapse diffs on GitHub.
lib/nfe/generated/** linguist-generated=true
sig/nfe/generated/** linguist-generated=true
42 changes: 42 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
name: CI

on:
push:
branches: [master, next]
pull_request:
branches: [master, next]

permissions:
contents: read

jobs:
test:
name: Ruby ${{ matrix.ruby }}
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
ruby: ["3.2", "3.3", "3.4"]
steps:
- uses: actions/checkout@v5

- name: Set up Ruby ${{ matrix.ruby }}
uses: ruby/setup-ruby@v1
with:
ruby-version: ${{ matrix.ruby }}
bundler-cache: true

- name: RSpec (fails if coverage < 80%)
run: bundle exec rspec

- name: RuboCop
run: bundle exec rubocop

- name: RBS validate
run: bundle exec rbs validate

- name: Steep type-check
run: bundle exec steep check

- name: OpenAPI generated code is in sync
run: bundle exec rake generate:check
208 changes: 208 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,208 @@
name: Release

# Disparado pelo push de uma tag de versão (forma com hífen):
# v1.0.0, v1.0.0-rc.1, v1.0.0-beta.2
#
# Pipeline:
# verify -> roda o MESMO gate do ci.yml na matrix Ruby 3.2/3.3/3.4.
# publish -> needs: verify; constrói o gem, publica no RubyGems via OIDC
# (trusted publishing) e cria o GitHub Release com o .gem + .sha256.
#
# A versão do gem (Nfe::VERSION) usa a forma com PONTO (1.0.0.rc.1); a tag usa
# a forma com HÍFEN (v1.0.0-rc.1). O job publish deriva a forma pontilhada da
# tag e aborta se o gem construído divergir.

on:
push:
tags:
- "v*"

# Permissão mínima no nível do workflow; o job publish eleva o que precisa.
permissions:
contents: read

jobs:
# ---------------------------------------------------------------------------
# Gate de CI: idêntico ao ci.yml. Falha aqui = release abortado (publish não roda).
# ---------------------------------------------------------------------------
verify:
name: Verify (Ruby ${{ matrix.ruby }})
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
ruby: ["3.2", "3.3", "3.4"]
steps:
- name: Checkout
uses: actions/checkout@v5

- name: Set up Ruby ${{ matrix.ruby }}
uses: ruby/setup-ruby@v1
with:
ruby-version: ${{ matrix.ruby }}
bundler-cache: true

- name: RSpec (fails if coverage < 80%)
run: bundle exec rake spec

- name: RuboCop
run: bundle exec rubocop

- name: RBS validate
run: bundle exec rbs validate

- name: Steep type-check
run: bundle exec steep check

- name: OpenAPI generated code is in sync
run: bundle exec rake generate:check

# ---------------------------------------------------------------------------
# Build + publish. Só roda se TODA a matrix verify passar.
# ---------------------------------------------------------------------------
publish:
name: Build & publish to RubyGems
needs: verify
runs-on: ubuntu-latest
permissions:
contents: write # criar o GitHub Release e anexar artefatos
id-token: write # OIDC para RubyGems trusted publishing
# Opcional: para exigir aprovação manual antes de publicar, crie um GitHub
# Environment (Settings > Environments) e descomente a linha abaixo.
# environment: rubygems
steps:
- name: Checkout
uses: actions/checkout@v5

- name: Set up Ruby 3.3
uses: ruby/setup-ruby@v1
with:
ruby-version: "3.3"
bundler-cache: true

# A tag é a forma com hífen (refs/tags/v1.0.0-rc.1). Derivamos:
# TAG_VERSION = 1.0.0-rc.1 (sem o 'v')
# DOTTED_VERSION = 1.0.0.rc.1 (forma do RubyGems; primeiro '-' vira '.')
# PRERELEASE = true|false (tag contém '-rc.'/'-beta.')
- name: Derive version from tag
id: ver
run: |
set -euo pipefail
tag="${GITHUB_REF_NAME}"
tag_version="${tag#v}"
dotted_version="${tag_version/-/.}"
if [[ "$tag_version" == *-rc.* || "$tag_version" == *-beta.* ]]; then
prerelease=true
else
prerelease=false
fi
{
echo "tag=$tag"
echo "tag_version=$tag_version"
echo "dotted_version=$dotted_version"
echo "prerelease=$prerelease"
} >> "$GITHUB_OUTPUT"
echo "tag=$tag dotted=$dotted_version prerelease=$prerelease"

# Garante que Nfe::VERSION (e portanto o gem) bate com a tag empurrada.
# Aborta o publish em qualquer divergência ANTES de construir/publicar.
- name: Assert Nfe::VERSION matches tag
run: |
set -euo pipefail
gem_version="$(ruby -r ./lib/nfe/version -e 'print Nfe::VERSION')"
expected="${{ steps.ver.outputs.dotted_version }}"
echo "Nfe::VERSION='$gem_version' esperado='$expected'"
if [[ "$gem_version" != "$expected" ]]; then
echo "::error::Nfe::VERSION ('$gem_version') não bate com a versão derivada da tag ('$expected'). Abortando."
exit 1
fi

- name: Build gem
id: build
run: |
set -euo pipefail
gem build nfe-io.gemspec
gem_file="$(ls -1 nfe-io-*.gem | head -n1)"
echo "gem_file=$gem_file" >> "$GITHUB_OUTPUT"
echo "Built $gem_file"

# Sanidade: a versão DENTRO do .gem construído deve bater com a esperada.
- name: Assert built gem version
run: |
set -euo pipefail
# `gem specification FILE version` imprime o YAML do objeto Gem::Version;
# a linha 'version: X.Y.Z[.rc.N]' carrega o valor. Extraímos esse campo.
built="$(gem specification "${{ steps.build.outputs.gem_file }}" version | awk '/^version:/ {print $2; exit}')"
expected="${{ steps.ver.outputs.dotted_version }}"
echo "gem interno='$built' esperado='$expected'"
if [[ "$built" != "$expected" ]]; then
echo "::error::Versão do gem construído ('$built') != esperada ('$expected'). Abortando."
exit 1
fi

- name: Checksum (SHA-256)
run: |
set -euo pipefail
sha256sum "${{ steps.build.outputs.gem_file }}" > "${{ steps.build.outputs.gem_file }}.sha256"
cat "${{ steps.build.outputs.gem_file }}.sha256"

# Extrai as notas da versão do CHANGELOG (forma pontilhada) para o Release.
- name: Extract changelog notes
id: notes
run: |
set -euo pipefail
ver="${{ steps.ver.outputs.dotted_version }}"
notes_file="RELEASE_NOTES.md"
awk -v ver="$ver" '
$0 ~ "^## \\[" ver "\\]" { capture = 1; next }
capture && /^## / { exit }
capture { print }
' CHANGELOG.md > "$notes_file" || true
if [[ ! -s "$notes_file" ]]; then
echo "Release ${{ steps.ver.outputs.tag }}." > "$notes_file"
fi
echo "notes_file=$notes_file" >> "$GITHUB_OUTPUT"

# ----- Publicação no RubyGems via OIDC (Trusted Publishing) ------------
# Nenhuma API key de longa duração. Requer um Trusted Publisher cadastrado
# na página do gem nfe-io no RubyGems, vinculado a:
# repository = nfe/client-ruby workflow = release.yml environment = (vazio)
# A action troca o token OIDC do GitHub; o RubyGems confere os claims
# (repo + workflow) contra o Trusted Publisher — sem role-to-assume.
- name: Configure RubyGems credentials (OIDC trusted publishing)
id: oidc
continue-on-error: true
uses: rubygems/configure-rubygems-credentials@v2.1.0

- name: Push gem to RubyGems (OIDC)
if: steps.oidc.outcome == 'success'
run: gem push "${{ steps.build.outputs.gem_file }}"

# ----- Fallback: API key em secret (se OIDC não estiver configurado) ----
# Ative cadastrando o secret RUBYGEMS_API_KEY no repositório. Só roda se
# o passo OIDC acima falhar (ex.: trusted publisher ainda não vinculado).
- name: Push gem to RubyGems (API key fallback)
if: steps.oidc.outcome != 'success'
env:
GEM_HOST_API_KEY: ${{ secrets.RUBYGEMS_API_KEY }}
run: |
set -euo pipefail
if [[ -z "${GEM_HOST_API_KEY:-}" ]]; then
echo "::error::OIDC trusted publishing indisponível e o secret RUBYGEMS_API_KEY não está configurado. Configure um dos dois."
exit 1
fi
gem push "${{ steps.build.outputs.gem_file }}"

# ----- GitHub Release com o .gem + .sha256 -----------------------------
# Pré-releases (-rc/-beta) são marcadas como prerelease e NÃO viram latest.
- name: Create GitHub Release
uses: softprops/action-gh-release@v2.0.8
with:
tag_name: ${{ steps.ver.outputs.tag }}
name: ${{ steps.ver.outputs.tag }}
body_path: ${{ steps.notes.outputs.notes_file }}
prerelease: ${{ steps.ver.outputs.prerelease }}
make_latest: ${{ steps.ver.outputs.prerelease == 'false' }}
files: |
${{ steps.build.outputs.gem_file }}
${{ steps.build.outputs.gem_file }}.sha256
15 changes: 12 additions & 3 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,11 +1,20 @@
/.idea/
/.bundle/
/.yardoc
/Gemfile.lock
/_yardoc/
/coverage/
/doc/
/docs/api/
/pkg/
/spec/reports/
/tmp/
/nfe-io-*.gem
/spec/reports/
Gemfile.lock
*.gem
.env
.steep/
.rbs_collection.lock
.rbs_collection.yaml
# Local dev symlinks to sibling repos (references / source of truth) — not part of the gem.
/nfeio-docs
/client-nodejs
/client-php
1 change: 1 addition & 0 deletions .rspec
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
--require spec_helper
--format documentation
--color
Loading
Loading