diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml new file mode 100644 index 00000000..30b1d1f6 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -0,0 +1,104 @@ +name: Bug Report +description: Reportar um bug no app +title: "[Bug]: " +labels: ["bug"] +body: + - type: markdown + attributes: + value: | + Obrigado por reportar! Preencha todos os campos obrigatórios para que possamos reproduzir e corrigir o problema. + + - type: input + id: app-version + attributes: + label: Versão do app + description: Vá em Ajustes > Sobre para ver a versão + placeholder: "ex: 5.2.0 (build 142)" + validations: + required: true + + - type: dropdown + id: device + attributes: + label: Dispositivo + description: Em qual dispositivo o bug acontece? + options: + - iPhone (tela pequena — SE, Mini) + - iPhone (tela normal — 16, 16 Pro) + - iPhone (tela grande — 16 Plus, 16 Pro Max) + - iPad + - Mac (Designed for iPad) + - Apple Watch + validations: + required: true + + - type: input + id: ios-version + attributes: + label: Versão do iOS/iPadOS/watchOS + description: Vá em Ajustes > Geral > Sobre + placeholder: "ex: iOS 26.0" + validations: + required: true + + - type: textarea + id: description + attributes: + label: Descrição do bug + description: O que aconteceu de errado? + placeholder: "Descreva o que você viu acontecer" + validations: + required: true + + - type: textarea + id: expected + attributes: + label: Comportamento esperado + description: O que deveria ter acontecido? + placeholder: "Descreva o que você esperava que acontecesse" + validations: + required: true + + - type: textarea + id: steps + attributes: + label: Passos para reproduzir + description: Como chegamos no bug? Seja específico. + placeholder: | + 1. Abra o app + 2. Vá em... + 3. Toque em... + 4. Observe que... + validations: + required: true + + - type: dropdown + id: frequency + attributes: + label: Frequência + description: Com que frequência o bug acontece? + options: + - Sempre (100%) + - Frequentemente (>50%) + - Às vezes (<50%) + - Raramente (aconteceu 1-2 vezes) + validations: + required: true + + - type: textarea + id: screenshots + attributes: + label: Screenshots ou vídeos + description: Anexe imagens ou gravações de tela que mostrem o problema + placeholder: "Arraste imagens/vídeos aqui" + validations: + required: false + + - type: textarea + id: additional + attributes: + label: Contexto adicional + description: Algo mais que possa ajudar? (ex. estava offline, acabou de atualizar, tema escuro, etc.) + placeholder: "Informações extras..." + validations: + required: false diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 00000000..7386750e --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,5 @@ +blank_issues_enabled: false +contact_links: + - name: Discussões Gerais + url: https://github.com/MacMagazine/app-iOS/discussions + about: Para perguntas ou conversas que não são bugs nem features diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml new file mode 100644 index 00000000..252afa33 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.yml @@ -0,0 +1,63 @@ +name: Feature Request +description: Sugerir uma nova funcionalidade +title: "[Feature]: " +labels: ["enhancement"] +body: + - type: markdown + attributes: + value: | + Obrigado pela sugestão! Descreva a funcionalidade que gostaria de ver no app. + + - type: textarea + id: problem + attributes: + label: Qual problema isso resolve? + description: Descreva a frustração ou limitação que você enfrenta hoje + placeholder: "Eu fico frustrado quando..." + validations: + required: true + + - type: textarea + id: solution + attributes: + label: Solução desejada + description: Como você imagina que deveria funcionar? + placeholder: "Gostaria que o app..." + validations: + required: true + + - type: textarea + id: alternatives + attributes: + label: Alternativas consideradas + description: Você já tentou resolver de outra forma? + placeholder: "Tentei usar... mas não funcionou porque..." + validations: + required: false + + - type: dropdown + id: area + attributes: + label: Área do app + description: Em qual parte do app a funcionalidade se encaixa? + options: + - Notícias + - Podcasts + - Vídeos + - Busca + - Ajustes + - Widget + - Apple Watch + - Push Notifications + - Outro + validations: + required: true + + - type: textarea + id: screenshots + attributes: + label: Mockups ou referências + description: Tem alguma imagem, mockup ou app de referência? + placeholder: "Arraste imagens aqui ou cole links de referência" + validations: + required: false diff --git a/.github/ISSUE_TEMPLATE/improvement.yml b/.github/ISSUE_TEMPLATE/improvement.yml new file mode 100644 index 00000000..76eaf4a2 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/improvement.yml @@ -0,0 +1,55 @@ +name: Melhoria +description: Sugerir uma melhoria em funcionalidade existente +title: "[Melhoria]: " +labels: ["improvement"] +body: + - type: markdown + attributes: + value: | + Descreva o que gostaria de melhorar no app. + + - type: dropdown + id: area + attributes: + label: Área do app + description: Qual parte do app precisa de melhoria? + options: + - Notícias + - Podcasts + - Vídeos + - Busca + - Ajustes / Aparência + - Widget + - Apple Watch + - Performance + - Acessibilidade + - Outro + validations: + required: true + + - type: textarea + id: current + attributes: + label: Como funciona hoje + description: Descreva o comportamento atual + placeholder: "Hoje quando eu faço X, acontece Y..." + validations: + required: true + + - type: textarea + id: desired + attributes: + label: Como deveria funcionar + description: Descreva o comportamento desejado + placeholder: "Gostaria que ao fazer X, acontecesse Z..." + validations: + required: true + + - type: textarea + id: screenshots + attributes: + label: Screenshots ou referências + description: Imagens mostrando o estado atual ou o resultado desejado + placeholder: "Arraste imagens aqui" + validations: + required: false diff --git a/.github/workflows/issue-validation.yml b/.github/workflows/issue-validation.yml new file mode 100644 index 00000000..95db70ea --- /dev/null +++ b/.github/workflows/issue-validation.yml @@ -0,0 +1,164 @@ +name: Issue Validation + +on: + issues: + types: [opened, edited] + +jobs: + validate-issue: + runs-on: ubuntu-latest + permissions: + issues: write + + steps: + - name: Validate bug report fields + if: contains(github.event.issue.labels.*.name, 'bug') + uses: actions/github-script@v7 + with: + script: | + const body = context.payload.issue.body || ''; + const errors = []; + + // Check required fields for bug reports + const requiredFields = [ + { label: 'Versão do app', pattern: /### Versão do app\s*\n\s*\n\s*(.+)/m }, + { label: 'Dispositivo', pattern: /### Dispositivo\s*\n\s*\n\s*(.+)/m }, + { label: 'Versão do iOS', pattern: /### Versão do iOS\/iPadOS\/watchOS\s*\n\s*\n\s*(.+)/m }, + { label: 'Descrição do bug', pattern: /### Descrição do bug\s*\n\s*\n\s*(.+)/m }, + { label: 'Comportamento esperado', pattern: /### Comportamento esperado\s*\n\s*\n\s*(.+)/m }, + { label: 'Passos para reproduzir', pattern: /### Passos para reproduzir\s*\n\s*\n\s*(.+)/m }, + { label: 'Frequência', pattern: /### Frequência\s*\n\s*\n\s*(.+)/m } + ]; + + for (const field of requiredFields) { + const match = body.match(field.pattern); + if (!match || match[1].trim() === '' || match[1].trim() === '_No response_') { + errors.push(`- **${field.label}** não foi preenchido`); + } + } + + if (errors.length > 0) { + const comment = `⚠️ **Issue incompleta**\n\nOs seguintes campos obrigatórios estão faltando ou vazios:\n\n${errors.join('\n')}\n\nPor favor, edite a issue e preencha todos os campos para que possamos investigar o problema.`; + + await github.rest.issues.createComment({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.issue.number, + body: comment + }); + + await github.rest.issues.addLabels({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.issue.number, + labels: ['needs-info'] + }); + } else { + // Remove needs-info label if it exists and all fields are now filled + try { + await github.rest.issues.removeLabel({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.issue.number, + name: 'needs-info' + }); + } catch (e) { + // Label didn't exist, that's fine + } + } + + - name: Validate feature request fields + if: contains(github.event.issue.labels.*.name, 'enhancement') + uses: actions/github-script@v7 + with: + script: | + const body = context.payload.issue.body || ''; + const errors = []; + + const requiredFields = [ + { label: 'Qual problema isso resolve?', pattern: /### Qual problema isso resolve\?\s*\n\s*\n\s*(.+)/m }, + { label: 'Solução desejada', pattern: /### Solução desejada\s*\n\s*\n\s*(.+)/m }, + { label: 'Área do app', pattern: /### Área do app\s*\n\s*\n\s*(.+)/m } + ]; + + for (const field of requiredFields) { + const match = body.match(field.pattern); + if (!match || match[1].trim() === '' || match[1].trim() === '_No response_') { + errors.push(`- **${field.label}** não foi preenchido`); + } + } + + if (errors.length > 0) { + const comment = `⚠️ **Issue incompleta**\n\nOs seguintes campos obrigatórios estão faltando:\n\n${errors.join('\n')}\n\nPor favor, edite a issue e preencha todos os campos.`; + + await github.rest.issues.createComment({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.issue.number, + body: comment + }); + + await github.rest.issues.addLabels({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.issue.number, + labels: ['needs-info'] + }); + } else { + try { + await github.rest.issues.removeLabel({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.issue.number, + name: 'needs-info' + }); + } catch (e) {} + } + + - name: Validate improvement fields + if: contains(github.event.issue.labels.*.name, 'improvement') + uses: actions/github-script@v7 + with: + script: | + const body = context.payload.issue.body || ''; + const errors = []; + + const requiredFields = [ + { label: 'Área do app', pattern: /### Área do app\s*\n\s*\n\s*(.+)/m }, + { label: 'Como funciona hoje', pattern: /### Como funciona hoje\s*\n\s*\n\s*(.+)/m }, + { label: 'Como deveria funcionar', pattern: /### Como deveria funcionar\s*\n\s*\n\s*(.+)/m } + ]; + + for (const field of requiredFields) { + const match = body.match(field.pattern); + if (!match || match[1].trim() === '' || match[1].trim() === '_No response_') { + errors.push(`- **${field.label}** não foi preenchido`); + } + } + + if (errors.length > 0) { + const comment = `⚠️ **Issue incompleta**\n\nOs seguintes campos obrigatórios estão faltando:\n\n${errors.join('\n')}\n\nPor favor, edite a issue e preencha todos os campos.`; + + await github.rest.issues.createComment({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.issue.number, + body: comment + }); + + await github.rest.issues.addLabels({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.issue.number, + labels: ['needs-info'] + }); + } else { + try { + await github.rest.issues.removeLabel({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.issue.number, + name: 'needs-info' + }); + } catch (e) {} + }