diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index dc3f2a8..3aee342 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -6,6 +6,17 @@ Provide project context and coding guidelines that AI should follow when generat # 🤖 GitHub Copilot - Guia de Interação +## ⭐ Princípio Fundamental: Verificar, Depois Agir + +**NUNCA confie na memória ou no contexto da conversa. SEMPRE verifique o estado atual do repositório antes de executar qualquer ação.** + +- **Antes de Commitar:** Use `git status --porcelain` para confirmar os arquivos a serem commitados. +- **Antes de Fazer Push:** Use `git log --left-right` para comparar a branch local com a remota se houver risco de divergência. +- **Antes de Criar um PR de Release:** Use `git log main..HEAD` para gerar a lista de mudanças a partir da fonte da verdade (o Git), não da memória. +- **Antes de Editar um Arquivo:** Releia o arquivo se houver qualquer dúvida sobre seu estado atual. + +Este princípio é a base para evitar retrabalho e garantir que todas as ações sejam deliberadas e baseadas em fatos. + ## 📋 Sobre Esta Documentação Este arquivo serve como guia de referência para futuras interações com o GitHub Copilot no desenvolvimento deste projeto. @@ -210,7 +221,7 @@ git push -u origin feature/nome-da-feature ### Visão Geral -**Portfolio React SPA** - Site de portfólio moderno com animações, construído com React 18 + TypeScript + Vite. +**Portfolio React SPA** - Site de portfólio moderno com animações, construído com React 19 + TypeScript + Vite. **Arquitetura Principal:** @@ -354,6 +365,23 @@ pnpm lint:fix # Correção automática - `reusable-release.yml`: Semantic release automation - Cache de build artifacts (`.vite`, `node_modules/.cache`, `.eslintcache`) +**Debugging de Workflows do GitHub Actions:** + +- **Tutorial completo:** Consulte `tutorial-github-actions-schema.md` para guia detalhado +- **Passo 1:** Execute `pnpm lint:yaml` para verificar sintaxe YAML +- **Passo 2:** Execute `pnpm lint` para verificar código relacionado +- **Passo 3:** Valide YAML com Python se necessário +- **Passo 4:** Analise erros específicos do linter (ex: condições `if`) +- **Regra:** YAML válido ≠ Workflow válido - sempre teste todas as camadas + +**Correção de Erros de Lint em Workflows:** + +- **Sintaxe YAML:** Use `pnpm lint:yaml` para validar arquivos `.github/workflows/*.yml` +- **Condições `if`:** Não use aspas em expressões GitHub Actions + - ❌ Errado: `if: "always() && !contains(...)"` + - ✅ Correto: `if: always() && !contains(...)` +- **Validação:** YAML válido não significa workflow válido - teste sempre + ### Workflow Preview - Otimizações Recentes **Implementado em novembro de 2025 - Resolução de duplicação e status checks quebrados:** diff --git a/.github/workflows/create-beta-tag.yml b/.github/workflows/create-beta-tag.yml deleted file mode 100644 index e4cc798..0000000 --- a/.github/workflows/create-beta-tag.yml +++ /dev/null @@ -1,117 +0,0 @@ -name: Create Beta Tag - -# Workflow manual para criar tags beta em release branches -# Executado manualmente via workflow_dispatch -# Realiza testes, deploy e cria tag beta automática - -on: - workflow_dispatch: - inputs: - branch: - description: "Release branch (e.g., release/1.1.0)" - required: true - type: string - -env: - VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }} - VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID }} - -jobs: - validate-branch: - name: Validate Branch - runs-on: ubuntu-latest - permissions: - contents: read - pull-requests: read - outputs: - has_pr: ${{ steps.check_pr.outputs.has_pr }} - version: ${{ steps.extract_version.outputs.version }} - commit_sha: ${{ steps.get_commit.outputs.commit_sha }} - steps: - - name: Checkout code - uses: actions/checkout@v4 - with: - ref: ${{ inputs.branch }} - fetch-depth: 0 - - - name: Check if PR exists for this branch - id: check_pr - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: | - BRANCH_NAME="${{ inputs.branch }}" - PR_COUNT=$(gh pr list --head "$BRANCH_NAME" --state open --json number --jq 'length') - if [ "$PR_COUNT" -gt 0 ]; then - echo "::warning::PR exists for branch $BRANCH_NAME. Beta tag creation may interfere with PR." - echo "has_pr=true" >> $GITHUB_OUTPUT - else - echo "No open PR found for branch $BRANCH_NAME. Safe to proceed." - echo "has_pr=false" >> $GITHUB_OUTPUT - fi - - - name: Extract version from branch name - id: extract_version - run: | - BRANCH_NAME="${{ inputs.branch }}" - VERSION=$(echo "$BRANCH_NAME" | sed 's|^release/||') - echo "version=$VERSION" >> $GITHUB_OUTPUT - echo "Version extracted: $VERSION" - - - name: Get commit SHA - id: get_commit - run: | - COMMIT_SHA=$(git rev-parse HEAD) - echo "commit_sha=$COMMIT_SHA" >> $GITHUB_OUTPUT - echo "Commit SHA: $COMMIT_SHA" - - test-and-lint: - needs: validate-branch - uses: ./.github/workflows/reusable-test-and-lint.yml - with: - node-version: "22.x" - - deploy-preview: - needs: [validate-branch, test-and-lint] - uses: ./.github/workflows/reusable-deploy-vercel.yml - with: - environment: Preview - ref: ${{ needs.validate-branch.outputs.commit_sha }} - prebuilt: true - secrets: - vercel-token: ${{ secrets.VERCEL_TOKEN }} - github-token: ${{ secrets.GITHUB_TOKEN }} - - create-beta-tag: - needs: [validate-branch, deploy-preview] - uses: ./.github/workflows/reusable-create-tag.yml - with: - tag-type: beta - version: ${{ needs.validate-branch.outputs.version }} - commit-sha: ${{ needs.validate-branch.outputs.commit_sha }} - create-version-commit: false - secrets: inherit - permissions: - contents: write - - summary: - name: Deployment Summary - needs: [validate-branch, deploy-preview, create-beta-tag] - if: always() - runs-on: ubuntu-latest - steps: - - name: Create Summary - run: | - echo "## 🚀 Beta Tag Creation Summary" >> $GITHUB_STEP_SUMMARY - echo "" >> $GITHUB_STEP_SUMMARY - echo "**Branch:** \`${{ inputs.branch }}\`" >> $GITHUB_STEP_SUMMARY - echo "**Version:** \`${{ needs.validate-branch.outputs.version }}\`" >> $GITHUB_STEP_SUMMARY - echo "**Commit:** \`${{ needs.validate-branch.outputs.commit_sha }}\`" >> $GITHUB_STEP_SUMMARY - echo "" >> $GITHUB_STEP_SUMMARY - echo "### Results:" >> $GITHUB_STEP_SUMMARY - echo "- ✅ Tests & Lint: ${{ needs.test-and-lint.result }}" >> $GITHUB_STEP_SUMMARY - echo "- ✅ Deploy: ${{ needs.deploy-preview.result }}" >> $GITHUB_STEP_SUMMARY - echo "- ✅ Tag Creation: ${{ needs.create-beta-tag.result }}" >> $GITHUB_STEP_SUMMARY - if [ "${{ needs.validate-branch.outputs.has_pr }}" = "true" ]; then - echo "" >> $GITHUB_STEP_SUMMARY - echo "⚠️ **Warning:** An open PR exists for this branch." >> $GITHUB_STEP_SUMMARY - fi diff --git a/.github/workflows/develop.yml b/.github/workflows/develop.yml index 9267de0..c2872c9 100644 --- a/.github/workflows/develop.yml +++ b/.github/workflows/develop.yml @@ -15,14 +15,17 @@ on: jobs: test-and-lint: - name: Test & Lint + name: Develop - Test & Lint uses: ./.github/workflows/reusable-test-and-lint.yml with: node-version: "22.x" deploy-develop: - name: Deploy to Vercel Preview + name: Develop - Deploy to Vercel needs: test-and-lint + # ✅ CORREÇÃO: Aplicando o tutorial + # 'if:' sem aspas externas + if: needs.test-and-lint.outputs.code-changed == 'true' uses: ./.github/workflows/reusable-deploy-vercel.yml with: environment: Development @@ -31,4 +34,4 @@ jobs: prebuilt: true secrets: vercel-token: ${{ secrets.VERCEL_TOKEN }} - github-token: ${{ secrets.GITHUB_TOKEN }} \ No newline at end of file + github-token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/preview.yml b/.github/workflows/preview.yml index 483929b..f2e652b 100644 --- a/.github/workflows/preview.yml +++ b/.github/workflows/preview.yml @@ -1,70 +1,77 @@ name: Preview Environment # Workflow para deploy do ambiente de preview/staging -# Executado em Pull Requests para validar mudanças com testes, lint e um deploy de preview. +# Executado em: +# - Pull Requests (para preview de mudanças) +# - Push em branches release/* (para testes de release) +# Realiza testes, linting, build, deploy para Vercel (ambiente preview) +# e atualização automática de comentários nos PRs env: VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }} VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID }} +# ✅ MÁGICA 1: Adicionado 'concurrency' para evitar disparos duplos +# (push + synchronize) no mesmo commit. +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.head.sha || github.sha }} + cancel-in-progress: true + on: pull_request: types: [opened, synchronize, reopened] + push: + branches: + - release/** workflow_dispatch: -concurrency: - group: ${{ github.workflow }}-${{ github.head_ref }} - cancel-in-progress: true - jobs: test-and-lint: - name: Test & Lint + name: Preview - Test & Lint + # Este job SEMPRE roda (para satisfazer o check obrigatório) + # O 'dummy pass' acontece DENTRO do 'reusable-lint' uses: ./.github/workflows/reusable-test-and-lint.yml with: node-version: "22.x" - always-run-check: - name: Basic Validation - runs-on: ubuntu-latest - steps: - - name: Always pass for required checks - run: echo "✅ PR validation completed" - deploy-preview: - name: Deploy to Vercel Preview + name: Preview - Deploy to Vercel needs: test-and-lint - if: ${{ needs.test-and-lint.outputs.code-changed == 'true' }} + # ❌ REMOVIDO: O 'if: needs.test-and-lint.outputs.code-changed == 'true'' + # Este job TEM que rodar sempre para o status check uses: ./.github/workflows/reusable-deploy-vercel.yml with: - environment: Preview-${{ github.event.pull_request.number }} + environment: Preview vercel-environment: preview - ref: ${{ github.event.pull_request.head.sha }} + ref: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.sha }} prebuilt: true prod: false secrets: vercel-token: ${{ secrets.VERCEL_TOKEN }} github-token: ${{ secrets.GITHUB_TOKEN }} - validate-branch-for-main: - name: Validate Branch for Main - if: github.base_ref == 'main' + validate-release-branch: + # ✅ SEGUINDO O TUTORIAL: 'if:' sem aspas + if: github.event_name == 'pull_request' && github.base_ref == 'main' runs-on: ubuntu-latest steps: - name: Check source branch name run: | SOURCE_BRANCH="${{ github.head_ref }}" echo "Source branch: $SOURCE_BRANCH" - if [[ "$SOURCE_BRANCH" == release/* ]] || [[ "$SOURCE_BRANCH" == hotfix/* ]]; then - echo "Source branch '$SOURCE_BRANCH' is valid for merging into 'main'." - else - echo "::error::Pull Request from branch '$SOURCE_BRANCH' cannot be merged into 'main'. Only branches starting with 'release/' or 'hotfix/' are allowed." + if [[ "$SOURCE_BRANCH" != release/* ]]; then + echo "::error::Pull Request from branch '$SOURCE_BRANCH' cannot be merged into 'main'. Only branches starting with 'release/' are allowed." exit 1 + else + echo "Source branch '$SOURCE_BRANCH' is a valid release branch." fi update-pr-comment: + # ✅ SEGUINDO O TUTORIAL: 'if:' sem aspas + if: github.event_name == 'pull_request' name: Update PR Comment + # Este 'needs' garante que ele espere o deploy terminar (ou ser pulado) needs: deploy-preview - if: ${{ needs.deploy-preview.result == 'success' }} runs-on: ubuntu-latest permissions: pull-requests: write @@ -88,9 +95,9 @@ jobs: | Recurso | Link | |---|---| - | **🔗 URL de Preview** | [URL de Preview](${{ needs.deploy-preview.outputs.deployment_url }}) | + | **🔗 URL de Preview** | https://www.dpreview.com/(${{ needs.deploy-preview.outputs.deployment_url }}) | | **📜 Logs do Deploy** | [Ver logs da Action](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}) | --- *Commit: `${{ github.event.pull_request.head.sha }}`* - edit-mode: replace + edit-mode: replace \ No newline at end of file diff --git a/.github/workflows/production.yml b/.github/workflows/production.yml index 5050553..f9df569 100644 --- a/.github/workflows/production.yml +++ b/.github/workflows/production.yml @@ -16,19 +16,24 @@ on: jobs: test-and-lint: - name: Test & Lint - if: ${{ !contains(github.event.head_commit.message, 'chore(release)') }} + name: Production - Test & Lint + # Este job SEMPRE roda para satisfazer o Required Check + # O filtro de paths está DENTRO do reusable-test-and-lint uses: ./.github/workflows/reusable-test-and-lint.yml with: node-version: "22.x" deploy-production: - name: Deploy to Vercel Production + name: Production - Deploy to Vercel needs: test-and-lint + # ✅ CORREÇÃO: Aplicando o tutorial + # 'if:' sem aspas externas + # Pula o deploy se 'code-changed' for falso + if: needs.test-and-lint.outputs.code-changed == 'true' uses: ./.github/workflows/reusable-deploy-vercel.yml with: environment: Production - vercel-environment: production + vercel-environment: production # ref: ${{ github.sha }} prebuilt: true prod: true @@ -38,8 +43,14 @@ jobs: run-semantic-release: name: Run Semantic Release - needs: deploy-production - if: ${{ !contains(github.event.head_commit.message, 'chore(release)') }} + needs: [test-and-lint, deploy-production] # Depende dos dois + + # ✅ CORREÇÃO: Aplicando o tutorial + # 'if:' sem aspas externas + # 'always()' garante que ele rode mesmo se 'deploy-production' for 'skipped' + # 'not(contains...)' é a trava anti-loop (substituindo o '!') + if: always() && !contains(github.event.head_commit.message, 'chore(release)') + runs-on: ubuntu-latest permissions: contents: write @@ -50,7 +61,7 @@ jobs: uses: actions/checkout@v5 with: fetch-depth: 0 - persist-credentials: false + persist-credentials: false # - name: Setup pnpm uses: pnpm/action-setup@v4 diff --git a/.github/workflows/reusable-create-tag.yml b/.github/workflows/reusable-create-tag.yml deleted file mode 100644 index 47ef57d..0000000 --- a/.github/workflows/reusable-create-tag.yml +++ /dev/null @@ -1,155 +0,0 @@ -name: Reusable Create Tag - -# Workflow reutilizável para criação de tags -# Consolidação de lógica para evitar duplicação -# Suporta tags de release (production) e beta (staging) - -on: - workflow_call: - inputs: - tag-type: - description: "Tipo da tag: 'release' ou 'beta'" - required: true - type: string - version: - description: "Versão a ser tagueada (ex: 1.1.0)" - required: true - type: string - commit-sha: - description: "SHA do commit a ser tagueado" - required: true - type: string - create-version-commit: - description: "Se deve criar commit de version bump" - required: false - type: boolean - default: false - outputs: - tag-name: - description: "Nome da tag criada" - value: ${{ jobs.create-tag.outputs.tag_name }} - tag-created: - description: "Se a tag foi criada com sucesso" - value: ${{ jobs.create-tag.outputs.tag_created }} - -jobs: - create-tag: - name: Create Git Tag - runs-on: ubuntu-latest - permissions: - contents: write - outputs: - tag_name: ${{ steps.create_tag.outputs.tag_name }} - tag_created: ${{ steps.create_tag.outputs.tag_created }} - steps: - - name: Checkout code - uses: actions/checkout@v4 - with: - ref: ${{ inputs.commit-sha }} - fetch-depth: 0 - - - name: Setup pnpm - if: inputs.create-version-commit - uses: pnpm/action-setup@v4 - - - name: Setup Node.js - if: inputs.create-version-commit - uses: actions/setup-node@v4 - with: - node-version: "22.x" - cache: "pnpm" - - - name: Validate inputs - run: | - VERSION="${{ inputs.version }}" - TAG_TYPE="${{ inputs.tag-type }}" - - # Validar tipo de tag - if [[ "$TAG_TYPE" != "release" && "$TAG_TYPE" != "beta" ]]; then - echo "::error::Invalid tag type: $TAG_TYPE. Must be 'release' or 'beta'." - exit 1 - fi - - # Validar formato de versão (básico) - if [[ -z "$VERSION" ]]; then - echo "::error::Version cannot be empty." - exit 1 - fi - - echo "✅ Input validation passed" - - - name: Prepare tag information - id: prepare_tag - run: | - VERSION="${{ inputs.version }}" - TAG_TYPE="${{ inputs.tag-type }}" - - # Remover prefixo release/ se existir - VERSION=$(echo "$VERSION" | sed 's|^release/||') - - if [ "$TAG_TYPE" = "beta" ]; then - TAG_NAME="v${VERSION}-beta.${{ github.run_id }}" - TAG_MESSAGE="Beta Release ${TAG_NAME}" - else - TAG_NAME="v${VERSION}" - TAG_MESSAGE="Release ${TAG_NAME}" - fi - - echo "TAG_NAME=$TAG_NAME" >> $GITHUB_ENV - echo "TAG_MESSAGE=$TAG_MESSAGE" >> $GITHUB_ENV - echo "tag_name=$TAG_NAME" >> $GITHUB_OUTPUT - echo "📦 Prepared tag: $TAG_NAME" - - - name: Check if tag already exists - id: check_tag - run: | - git fetch --tags - if git rev-parse "refs/tags/${{ env.TAG_NAME }}" >/dev/null 2>&1; then - echo "::warning::Tag ${{ env.TAG_NAME }} already exists. Skipping tag creation." - echo "tag_exists=true" >> $GITHUB_OUTPUT - echo "tag_created=false" >> $GITHUB_OUTPUT - else - echo "Tag ${{ env.TAG_NAME }} does not exist. Proceeding with tag creation." - echo "tag_exists=false" >> $GITHUB_OUTPUT - echo "tag_created=true" >> $GITHUB_OUTPUT - fi - - - name: Update package.json version - if: inputs.create-version-commit && steps.check_tag.outputs.tag_exists == 'false' - run: | - git config --global user.name "github-actions[bot]" - git config --global user.email "github-actions[bot]@users.noreply.github.com" - - # Extrair apenas a versão sem o prefixo beta - VERSION=$(echo "${{ env.TAG_NAME }}" | sed 's/^v//') - - pnpm version "$VERSION" --no-git-tag-version - git add package.json pnpm-lock.yaml - git commit -m "chore: bump version to $VERSION [skip ci]" - git push - - - name: Create Git tag - id: create_tag - if: steps.check_tag.outputs.tag_exists == 'false' - run: | - git config --global user.name "github-actions[bot]" - git config --global user.email "github-actions[bot]@users.noreply.github.com" - - git tag "${{ env.TAG_NAME }}" -m "${{ env.TAG_MESSAGE }}" - git push origin "${{ env.TAG_NAME }}" - - echo "✅ Tag ${{ env.TAG_NAME }} created successfully!" - - - name: Summary - if: always() - run: | - if [ "${{ steps.check_tag.outputs.tag_exists }}" = "true" ]; then - echo "ℹ️ Tag ${{ env.TAG_NAME }} already exists. No action taken." >> $GITHUB_STEP_SUMMARY - else - echo "✅ Tag ${{ env.TAG_NAME }} created successfully!" >> $GITHUB_STEP_SUMMARY - echo "" >> $GITHUB_STEP_SUMMARY - echo "**Tag Details:**" >> $GITHUB_STEP_SUMMARY - echo "- Name: \`${{ env.TAG_NAME }}\`" >> $GITHUB_STEP_SUMMARY - echo "- Type: \`${{ inputs.tag-type }}\`" >> $GITHUB_STEP_SUMMARY - echo "- Commit: \`${{ inputs.commit-sha }}\`" >> $GITHUB_STEP_SUMMARY - fi diff --git a/.github/workflows/reusable-deploy-vercel.yml b/.github/workflows/reusable-deploy-vercel.yml index a90a7c8..a4c0045 100644 --- a/.github/workflows/reusable-deploy-vercel.yml +++ b/.github/workflows/reusable-deploy-vercel.yml @@ -29,6 +29,10 @@ on: deployment_url: description: "URL do deployment no Vercel" value: ${{ jobs.deploy.outputs.deployment_url }} + # ✅ MÁGICA: Exportando o resultado do filtro + code-changed: + description: "Indica se o deploy realmente rodou" + value: ${{ jobs.deploy.outputs.code-changed }} jobs: deploy: @@ -36,6 +40,7 @@ jobs: runs-on: ubuntu-latest outputs: deployment_url: ${{ steps.deploy_step.outputs.deployment_url }} + code-changed: ${{ steps.filter.outputs.code }} environment: name: ${{ inputs.environment }} url: ${{ steps.deploy_step.outputs.deployment_url }} @@ -49,6 +54,7 @@ jobs: with: fetch-depth: 0 + # ✅ MÁGICA: O paths-filter ESTÁ DE VOLTA - name: Check for code changes id: filter uses: dorny/paths-filter@v3 @@ -64,6 +70,11 @@ jobs: - 'eslint.config.mjs' - '.github/workflows/**' + - name: Set code-changed output + id: set-output + run: echo "code-changed=${{ steps.filter.outputs.code }}" >> $GITHUB_OUTPUT + + # ✅ MÁGICA: Todos os steps de deploy agora dependem do filtro - name: Install Vercel CLI if: steps.filter.outputs.code == 'true' run: npm install --global vercel@latest @@ -71,7 +82,9 @@ jobs: - name: Pull Vercel Environment Information if: steps.filter.outputs.code == 'true' run: | - vercel pull --yes --environment=${{ inputs.vercel-environment }} --token=${{ secrets.vercel-token }} + # Correção do case-sensitive (Preview vs preview) + ENV_NAME=$(echo "${{ inputs.vercel-environment }}" | tr '[:upper:]' '[:lower:]') + vercel pull --yes --environment=$ENV_NAME --token=${{ secrets.vercel-token }} - name: Ensure Vercel cache directory exists if: steps.filter.outputs.code == 'true' @@ -105,11 +118,6 @@ jobs: exit $DEPLOY_STATUS fi - - name: Report Skipped Deployment - if: steps.filter.outputs.code != 'true' - run: | - echo "Deployment skipped: No code changes detected." - - name: Upload debug logs on failure if: failure() uses: actions/upload-artifact@v4 @@ -126,4 +134,4 @@ jobs: /tmp/vercel-* /tmp/node-* /tmp/npm-* - /tmp/pnpm-* + /tmp/pnpm-* \ No newline at end of file diff --git a/.github/workflows/reusable-release.yml b/.github/workflows/reusable-release.yml deleted file mode 100644 index 6ad0351..0000000 --- a/.github/workflows/reusable-release.yml +++ /dev/null @@ -1,62 +0,0 @@ -name: Reusable Release - -on: - workflow_call: - inputs: - version: - required: true - type: string - node-version: - required: true - type: string - -jobs: - release: - name: Create Git Tag and Bump Version - runs-on: ubuntu-latest - permissions: - contents: write - steps: - - name: Checkout code - uses: actions/checkout@v4 - with: - fetch-depth: 0 - - - name: Setup pnpm - uses: pnpm/action-setup@v4 - - - name: Setup Node.js - uses: actions/setup-node@v4 - with: - node-version: ${{ inputs.node-version }} - cache: "pnpm" - - - name: Get version - id: get_version - run: | - echo "VERSION=${{ inputs.version }}" >> $GITHUB_ENV - echo "TAG_VERSION=v${{ inputs.version }}" >> $GITHUB_ENV - - - name: Check if tag already exists - id: check_tag - run: | - git fetch --tags - if git rev-parse "refs/tags/${{ env.TAG_VERSION }}" >/dev/null 2>&1; then - echo "Tag ${{ env.TAG_VERSION }} already exists. Skipping release." - echo "SKIP_ALL=true" >> $GITHUB_OUTPUT - else - echo "Tag ${{ env.TAG_VERSION }} does not exist. Proceeding with release." - echo "SKIP_ALL=false" >> $GITHUB_OUTPUT - fi - - - name: Update version and create tag - if: steps.check_tag.outputs.SKIP_ALL == 'false' - run: | - git config --global user.name "github-actions[bot]" - git config --global user.email "github-actions[bot]@users.noreply.github.com" - pnpm version ${{ env.VERSION }} --no-git-tag-version - git add package.json pnpm-lock.yaml - git commit -m "chore: Bump version to ${{ env.VERSION }}" - git tag ${{ env.TAG_VERSION }} -m "Release ${{ env.TAG_VERSION }}" - git push - git push origin ${{ env.TAG_VERSION }} diff --git a/CHANGELOG.md b/CHANGELOG.md index a4c3741..169ea4a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,12 @@ +## [1.3.1-beta.1](https://github.com/JaegerCaiser/mrdeveloper/compare/v1.3.0...v1.3.1-beta.1) (2025-11-07) + + +### Bug Fixes + +* correct preview URL link in PR comment ([b983a4b](https://github.com/JaegerCaiser/mrdeveloper/commit/b983a4b72400e381a11111695a7672dd697a4221)) +* rename workflow jobs to prevent status check conflicts ([7f1170e](https://github.com/JaegerCaiser/mrdeveloper/commit/7f1170ed09ce5c361041651cbc57099601d38abb)) +* rename workflow jobs to prevent status check conflicts ([b723c32](https://github.com/JaegerCaiser/mrdeveloper/commit/b723c320ab002923fc62e731e0086809c2620be7)) + # [1.3.0](https://github.com/JaegerCaiser/mrdeveloper/compare/v1.2.4...v1.3.0) (2025-11-07) diff --git a/package.json b/package.json index 29fcb78..2baa15d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "mrdeveloper", - "version": "1.3.0", + "version": "1.3.1-beta.1", "type": "module", "packageManager": "pnpm@10.20.0", "homepage": "https://www.mrdeveloper.com.br/", diff --git a/tutorial-github-actions-schema.md b/tutorial-github-actions-schema.md new file mode 100644 index 0000000..9209adb --- /dev/null +++ b/tutorial-github-actions-schema.md @@ -0,0 +1,214 @@ +# Tutorial: Schema do GitHub Actions - Entendendo Workflows + +## 🎯 Introdução + +Este tutorial explica como funciona o **schema do GitHub Actions**, com foco em erros comuns e melhores práticas. Baseado em experiências reais de debugging. + +## 📋 O que é o Schema do GitHub Actions? + +O schema define **regras específicas** para escrever workflows YAML. Diferente do YAML comum, o GitHub Actions tem **sintaxe própria** para certas funcionalidades. + +### ❌ Erro Comum: YAML válido ≠ Workflow válido + +```yaml +# ❌ YAML válido, mas ERRO no GitHub Actions +if: "always() && !contains(github.event.head_commit.message, 'chore(release)')" + +# ✅ Correto no GitHub Actions +if: always() && !contains(github.event.head_commit.message, 'chore(release)') +``` + +## 🔧 Condições `if` - A Armadilha Mais Comum + +### Regras Fundamentais + +1. **Não use aspas** em expressões com funções +2. **Aspas só** para strings literais +3. **Funções** como `always()`, `contains()`, `startsWith()` não precisam de aspas + +### Exemplos Práticos + +#### ✅ Correto + +```yaml +# Funções sem aspas +if: always() +if: contains(github.event.head_commit.message, 'fix') +if: startsWith(github.event.ref, 'refs/tags/') + +# Combinações +if: always() && !contains(github.event.head_commit.message, 'chore(release)') +if: github.event_name == 'pull_request' && github.event.action == 'opened' + +# Com variáveis +if: needs.test-job.outputs.success == 'true' +``` + +#### ❌ Errado + +```yaml +# Aspas desnecessárias +if: "always()" +if: "contains(github.event.head_commit.message, 'fix')" + +# Aspas em combinações (QUEBRAM tudo) +if: "always() && !contains(github.event.head_commit.message, 'chore(release)')" +``` + +### Por que isso acontece? + +- GitHub Actions trata aspas como **strings literais** +- `"always()"` vira uma string, não uma função +- O parser espera uma **expressão booleana**, não uma string + +## 🏗️ Estrutura de um Workflow + +### Jobs e Dependências + +```yaml +jobs: + job-a: + runs-on: ubuntu-latest + steps: + - run: echo "Job A" + + job-b: + needs: job-a # ✅ Correto: referência simples + if: needs.job-a.result == 'success' # ✅ Correto: expressão + runs-on: ubuntu-latest +``` + +### Outputs entre Jobs + +```yaml +jobs: + test: + outputs: + code-changed: ${{ steps.filter.outputs.code }} + steps: + - id: filter + run: echo "code=true" >> $GITHUB_OUTPUT + + deploy: + needs: test + if: needs.test.outputs.code-changed == 'true' # ✅ Correto + runs-on: ubuntu-latest +``` + +## 🎭 Contextos e Variáveis + +### Contextos Disponíveis + +- `github.*` - Informações do evento +- `env.*` - Variáveis de ambiente +- `vars.*` - Variáveis do repositório +- `secrets.*` - Segredos +- `needs.*` - Outputs de jobs +- `steps.*` - Outputs de steps + +### Exemplos de Uso + +```yaml +# Contexto github +if: github.event_name == 'pull_request' +if: github.base_ref == 'main' + +# Contexto needs +if: needs.build.result == 'success' + +# Contexto env +if: env.NODE_ENV == 'production' +``` + +## 🔄 Estratégias de Debugging + +### Checklist Sistemático + +1. **Sintaxe YAML básica** + + ```bash + pnpm lint:yaml + ``` + +2. **Validação de estrutura** + + ```bash + python3 -c "import yaml; yaml.safe_load(open('workflow.yml'))" + ``` + +3. **Teste de expressões** + + - Verifique condições `if` sem aspas + - Teste funções uma por vez + - Use `always()` para debug + +4. **Validação no GitHub** + - Push e veja se workflow roda + - Verifique logs de erro específicos + +### Erros Comuns e Soluções + +| Erro | Causa | Solução | +| ------------------------------------ | ---------------------- | -------------------------- | +| `Unexpected symbol: '"always'` | Aspas em funções | Remova aspas | +| `needs.job-a.outputs is not defined` | Job não tem outputs | Defina outputs no job | +| `contains is not defined` | Função não reconhecida | Use `contains()` sem aspas | +| Workflow não dispara | Problema no `on:` | Verifique triggers | + +## 🚀 Melhores Práticas + +### 1. Teste Incremental + +```yaml +# Comece simples +if: always() + +# Adicione complexidade gradualmente +if: always() && github.event_name == 'push' + +# Teste final +if: always() && !contains(github.event.head_commit.message, 'skip') +``` + +### 2. Use IDs em Steps + +```yaml +steps: + - id: test + run: echo "success=true" >> $GITHUB_OUTPUT + + - name: Deploy + if: steps.test.outputs.success == 'true' + run: echo "Deploying..." +``` + +### 3. Valide Sempre + +- Use `pnpm lint:yaml` antes de commitar +- Teste workflows em branches separadas +- Leia logs de erro com atenção + +### 4. Documente Lógica Complexa + +```yaml +# ❌ Sem comentário +if: always() && !contains(github.event.head_commit.message, 'chore(release)') + +# ✅ Com explicação +# Sempre rode, mas pule se for commit de release automático +if: always() && !contains(github.event.head_commit.message, 'chore(release)') +``` + +## 🎯 Conclusão + +O schema do GitHub Actions é **poderoso mas rigoroso**. Os erros mais comuns vêm de: + +1. **Aspas desnecessárias** em condições `if` +2. **Sintaxe incorreta** de funções +3. **Referências erradas** a contextos + +**Lembre-se:** Debugging sistemático > Tentativa e erro! + +--- + +_Baseado em experiências reais de debugging de workflows complexos._