From e65f95754b79d446f4a655276c621dec3cf8b156 Mon Sep 17 00:00:00 2001 From: Elio Neto Date: Mon, 9 Mar 2026 13:47:53 -0300 Subject: [PATCH] feat: optimize all workflows for faster execution and better parallelization - Consolidated build and test jobs to reduce redundancy - Improved caching with Swatinem/rust-cache@v2 - Added parallel execution where possible - Reduced git fetch operations with appropriate fetch-depth - Consolidated issue extraction to single step - Optimized test workflow to run only essential checks - Reduced matrix strategy to stable + nightly only --- .github/workflows/develop-to-release.yml | 174 ++++------------ .github/workflows/feature-fix-workflow.yml | 227 ++++++--------------- .github/workflows/release-workflow.yml | 117 +++-------- .github/workflows/test.yml | 103 +++------- 4 files changed, 164 insertions(+), 457 deletions(-) diff --git a/.github/workflows/develop-to-release.yml b/.github/workflows/develop-to-release.yml index 1bcd759..02dd580 100644 --- a/.github/workflows/develop-to-release.yml +++ b/.github/workflows/develop-to-release.yml @@ -31,31 +31,27 @@ jobs: with: fetch-depth: 0 - - name: Determine version bump + - name: Determine version and extract info id: version run: | - # Fetch all tags to ensure we have the latest git fetch --tags --force - # Get the latest tag (preferably from main branch) LAST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "v0.0.0") echo "Last tag: $LAST_TAG" - # Parse version LAST_VERSION=${LAST_TAG#v} IFS='.' read -ra VERSION_PARTS <<< "$LAST_VERSION" MAJOR=${VERSION_PARTS[0]:-0} MINOR=${VERSION_PARTS[1]:-0} PATCH=${VERSION_PARTS[2]:-0} - # Get commits since last tag if [ "$LAST_TAG" = "v0.0.0" ]; then COMMITS=$(git log --pretty=format:"%s") else COMMITS=$(git log "${LAST_TAG}..HEAD" --pretty=format:"%s") fi - # Determine bump type based on conventional commits + # Determine bump type if echo "$COMMITS" | grep -qiE "^(BREAKING CHANGE|feat!|fix!):"; then MAJOR=$((MAJOR + 1)) MINOR=0 @@ -72,9 +68,7 @@ jobs: NEW_VERSION="${MAJOR}.${MINOR}.${PATCH}" - # Check if this version already exists as a tag and increment if needed while git rev-parse "v${NEW_VERSION}" >/dev/null 2>&1; do - echo "⚠️ Tag v${NEW_VERSION} already exists, incrementing patch version..." PATCH=$((PATCH + 1)) NEW_VERSION="${MAJOR}.${MINOR}.${PATCH}" done @@ -82,7 +76,20 @@ jobs: echo "new_version=$NEW_VERSION" >> "$GITHUB_OUTPUT" echo "bump_type=$BUMP_TYPE" >> "$GITHUB_OUTPUT" echo "last_tag=$LAST_TAG" >> "$GITHUB_OUTPUT" - echo "✅ New version will be: v$NEW_VERSION (${BUMP_TYPE} bump from $LAST_TAG)" + + # Extract issues + ISSUES=$(echo "$COMMITS" | grep -oiE '(close[sd]?|fix(es|ed)?|resolve[sd]?) #[0-9]+' | grep -oE '#[0-9]+' | sort -u | tr '\n' ' ' || echo "") + echo "issues=$ISSUES" >> "$GITHUB_OUTPUT" + + # Generate changelog + if [ "$LAST_TAG" = "v0.0.0" ]; then + CHANGELOG=$(git log --pretty=format:'- %s `%h`' | head -20) + else + CHANGELOG=$(git log "${LAST_TAG}..HEAD" --pretty=format:'- %s `%h`') + fi + echo "changelog<> "$GITHUB_OUTPUT" + echo "$CHANGELOG" >> "$GITHUB_OUTPUT" + echo "EOF" >> "$GITHUB_OUTPUT" - name: Create or update release branch env: @@ -94,98 +101,38 @@ jobs: git config user.email "github-actions[bot]@users.noreply.github.com" if git ls-remote --heads origin "$RELEASE_BRANCH" | grep -q "$RELEASE_BRANCH"; then - echo "📌 Branch $RELEASE_BRANCH já existe, atualizando..." git fetch origin "$RELEASE_BRANCH" git checkout "$RELEASE_BRANCH" git merge origin/develop --no-edit else - echo "🆕 Criando nova branch $RELEASE_BRANCH" git checkout -b "$RELEASE_BRANCH" fi git push origin "$RELEASE_BRANCH" - echo "RELEASE_BRANCH=$RELEASE_BRANCH" >> "$GITHUB_ENV" - - - name: Check if PR exists - id: check-pr - env: - GH_TOKEN: ${{ github.token }} - NEW_VERSION: ${{ steps.version.outputs.new_version }} - run: | - RELEASE_BRANCH="release/v${NEW_VERSION}" - - PR_EXISTS=$(gh pr list --head "$RELEASE_BRANCH" --base main --json number --jq 'length') - echo "pr_exists=$PR_EXISTS" >> "$GITHUB_OUTPUT" - - if [ "$PR_EXISTS" -gt 0 ]; then - PR_NUMBER=$(gh pr list --head "$RELEASE_BRANCH" --base main --json number --jq '.[0].number') - echo "pr_number=$PR_NUMBER" >> "$GITHUB_OUTPUT" - fi - - - name: Extract issues from commits - id: extract-issues - env: - LAST_TAG: ${{ steps.version.outputs.last_tag }} - run: | - if [ "$LAST_TAG" = "v0.0.0" ]; then - COMMITS=$(git log --pretty=format:'%s' | head -50) - else - COMMITS=$(git log "${LAST_TAG}..HEAD" --pretty=format:'%s') - fi - - # Extract issue numbers (Closes #123, Fixes #456, #789) - ISSUES=$(echo "$COMMITS" | grep -oiE '(close[sd]?|fix(es|ed)?|resolve[sd]?) #[0-9]+' | grep -oE '#[0-9]+' | sort -u | tr '\n' ' ' || echo "") - echo "issues=$ISSUES" >> "$GITHUB_OUTPUT" - - if [ -n "$ISSUES" ]; then - echo "Found issues: $ISSUES" - else - echo "No issues referenced in commits" - fi - - - name: Generate changelog - id: changelog - env: - LAST_TAG: ${{ steps.version.outputs.last_tag }} - run: | - if [ "$LAST_TAG" = "v0.0.0" ]; then - CHANGELOG=$(git log --pretty=format:'- %s `%h`' | head -20) - else - CHANGELOG=$(git log "${LAST_TAG}..HEAD" --pretty=format:'- %s `%h`') - fi - echo "$CHANGELOG" > /tmp/changelog.txt - - - name: Create or update PR to main + - name: Check and create PR env: GH_TOKEN: ${{ github.token }} NEW_VERSION: ${{ steps.version.outputs.new_version }} BUMP_TYPE: ${{ steps.version.outputs.bump_type }} - ISSUES: ${{ steps.extract-issues.outputs.issues }} + ISSUES: ${{ steps.version.outputs.issues }} LAST_TAG: ${{ steps.version.outputs.last_tag }} + CHANGELOG: ${{ steps.version.outputs.changelog }} run: | RELEASE_BRANCH="release/v${NEW_VERSION}" - CHANGELOG=$(cat /tmp/changelog.txt) - - # Format issues list for PR body (optional section) - ISSUES_SECTION="" - if [ -n "$ISSUES" ]; then - ISSUES_LIST="" - for ISSUE in $ISSUES; do - ISSUE_NUM=${ISSUE#\#} - ISSUES_LIST+="- $ISSUE\n" - done - ISSUES_SECTION="### 🐛 Issues Resolvidas - $ISSUES_LIST - - _Essas issues serão fechadas automaticamente quando este PR for mergeado._ - - --- + + PR_EXISTS=$(gh pr list --head "$RELEASE_BRANCH" --base main --json number --jq 'length') - " - fi + if [ "$PR_EXISTS" -eq 0 ]; then + ISSUES_SECTION="" + if [ -n "$ISSUES" ]; then + ISSUES_LIST="" + for ISSUE in $ISSUES; do + ISSUES_LIST+="- $ISSUE\n" + done + ISSUES_SECTION="### 🐛 Issues Resolvidas\n$ISSUES_LIST\n\n---\n\n" + fi - if [ "${{ steps.check-pr.outputs.pr_exists }}" -eq 0 ]; then gh pr create \ --base main \ --head "$RELEASE_BRANCH" \ @@ -197,16 +144,9 @@ jobs: --- ### ⚙️ Release Configuration - **Escolha o tipo de release editando abaixo:** - Release Type: [lts] - **Opções válidas:** - - \`alpha\` - Release alpha (instável, desenvolvimento) - - \`beta\` - Release beta (pré-release, testes) - - \`lts\` - Release estável de longo prazo (produção) - - **📝 Instruções:** Edite este PR e substitua \`lts\` acima por \`alpha\`, \`beta\` ou mantenha \`lts\`. + **Options:** \`alpha\`, \`beta\`, \`lts\` --- @@ -215,20 +155,8 @@ jobs: --- - ### ✅ Checklist antes do merge - - [ ] Revisei as mudanças - - [ ] Defini o tipo de release correto - - [ ] Testes passaram em develop - - [ ] Documentação atualizada (se necessário) - - --- - - _Este PR foi gerado automaticamente pelo workflow develop-to-release_" \ + _Auto-generated by develop-to-release workflow_" \ --draft - - echo "✅ PR criado: release/v${NEW_VERSION} → main (draft)" - else - echo "ℹ️ PR já existe (#${{ steps.check-pr.outputs.pr_number }})" fi close-issues-on-release: @@ -243,20 +171,13 @@ jobs: with: fetch-depth: 0 - - name: Extract version from branch - id: version - run: | - BRANCH_NAME="${{ github.head_ref }}" - VERSION=${BRANCH_NAME#release/} - echo "version=$VERSION" >> "$GITHUB_OUTPUT" - echo "Checking for issues to close in release $VERSION" - - name: Extract and close issues env: GH_TOKEN: ${{ github.token }} - VERSION: ${{ steps.version.outputs.version }} run: | - # Get the last tag before this release + BRANCH_NAME="${{ github.head_ref }}" + VERSION=${BRANCH_NAME#release/} + LAST_TAG=$(git describe --tags --abbrev=0 HEAD^ 2>/dev/null || echo "") if [ -n "$LAST_TAG" ]; then @@ -265,40 +186,21 @@ jobs: COMMITS=$(git log --pretty=format:'%s') fi - # Extract all issue references ISSUES=$(echo "$COMMITS" | grep -oiE '(close[sd]?|fix(es|ed)?|resolve[sd]?|#)[[:space:]]*#[0-9]+' | grep -oE '#[0-9]+' | sort -u || echo "") if [ -z "$ISSUES" ]; then - echo "ℹ️ No issues referenced in commits - skipping issue closure" - echo "This is normal if commits didn't reference any issues." exit 0 fi - echo "Found issues to close: $ISSUES" - for ISSUE in $ISSUES; do ISSUE_NUM=${ISSUE#\#} - echo "Processing issue #$ISSUE_NUM" - # Check if issue exists if gh issue view "$ISSUE_NUM" &>/dev/null; then - # Add comment to issue gh issue comment "$ISSUE_NUM" --body "✅ **Resolved in Release $VERSION** - This issue has been fixed and released in version \`$VERSION\`. - - **Release Details:** - - 🏷️ Version: $VERSION - - 📦 Release: [View Release](https://github.com/${{ github.repository }}/releases/tag/$VERSION) - - 🔀 PR: #${{ github.event.pull_request.number }} + **Release:** [View Release](https://github.com/${{ github.repository }}/releases/tag/$VERSION) + **PR:** #${{ github.event.pull_request.number }}" 2>/dev/null || true - Thank you for your contribution!" 2>/dev/null || echo "⚠️ Could not comment on issue #$ISSUE_NUM" - - # Close the issue - gh issue close "$ISSUE_NUM" --reason completed 2>/dev/null && echo "✅ Issue #$ISSUE_NUM closed" || echo "⚠️ Could not close issue #$ISSUE_NUM (may already be closed)" - else - echo "⚠️ Issue #$ISSUE_NUM not found - skipping" + gh issue close "$ISSUE_NUM" --reason completed 2>/dev/null || true fi done - - echo "✅ Issue processing complete" diff --git a/.github/workflows/feature-fix-workflow.yml b/.github/workflows/feature-fix-workflow.yml index 6064571..e9e6436 100644 --- a/.github/workflows/feature-fix-workflow.yml +++ b/.github/workflows/feature-fix-workflow.yml @@ -29,195 +29,137 @@ jobs: steps: - uses: actions/checkout@v4 + with: + fetch-depth: 1 - name: Setup Rust uses: dtolnay/rust-toolchain@stable + with: + components: clippy - name: Rust cache uses: Swatinem/rust-cache@v2 with: cache-on-failure: true + shared-key: "build-test" - - name: Build - run: cargo build --release --all-features - - - name: Run tests - run: cargo test --all-features + - name: Build and test + run: | + cargo build --release --all-features + cargo test --all-features - name: Run clippy run: cargo clippy --all-features -- -D warnings continue-on-error: true - create-pr-to-develop: + manage-pr-and-issues: if: github.event_name == 'push' needs: build-and-test runs-on: ubuntu-latest permissions: pull-requests: write contents: read + issues: write steps: - uses: actions/checkout@v4 with: fetch-depth: 0 - - name: Check for commits difference - id: check-commits + - name: Check commits and extract issues + id: analyze run: | - git fetch origin develop + git fetch origin develop --depth=50 COMMITS_AHEAD=$(git rev-list --count "origin/develop..${{ github.ref_name }}") echo "commits_ahead=$COMMITS_AHEAD" >> "$GITHUB_OUTPUT" - echo "Branch está $COMMITS_AHEAD commits à frente de develop" - - - name: Extract issues from commits - id: extract-issues - if: steps.check-commits.outputs.commits_ahead > 0 - run: | - git fetch origin develop - COMMITS=$(git log "origin/develop..${{ github.ref_name }}" --pretty=format:'%s') - - # Extract issue numbers - ISSUES=$(echo "$COMMITS" | grep -oiE '(close[sd]?|fix(es|ed)?|resolve[sd]?|#)[[:space:]]*#[0-9]+' | grep -oE '#[0-9]+' | sort -u | tr '\n' ' ' || echo "") - echo "issues=$ISSUES" >> "$GITHUB_OUTPUT" - if [ -n "$ISSUES" ]; then - echo "Found issues: $ISSUES" - else - echo "No issues referenced in commits" + if [ "$COMMITS_AHEAD" -gt 0 ]; then + COMMITS=$(git log "origin/develop..${{ github.ref_name }}" --pretty=format:'%s') + ISSUES=$(echo "$COMMITS" | grep -oiE '(close[sd]?|fix(es|ed)?|resolve[sd]?|#)[[:space:]]*#[0-9]+' | grep -oE '#[0-9]+' | sort -u | tr '\n' ' ' || echo "") + echo "issues=$ISSUES" >> "$GITHUB_OUTPUT" + + RECENT_COMMITS=$(git log "origin/develop..${{ github.ref_name }}" -n 5 --pretty=format:'- %s (%h)') + echo "recent_commits<> "$GITHUB_OUTPUT" + echo "$RECENT_COMMITS" >> "$GITHUB_OUTPUT" + echo "EOF" >> "$GITHUB_OUTPUT" fi - - name: Check if PR already exists + - name: Check existing PR id: check-pr - if: steps.check-commits.outputs.commits_ahead > 0 + if: steps.analyze.outputs.commits_ahead > 0 env: GH_TOKEN: ${{ github.token }} run: | - BRANCH_NAME="${{ github.ref_name }}" - PR_LIST=$(gh pr list --head "$BRANCH_NAME" --base develop --json number) - PR_EXISTS=$(echo "$PR_LIST" | jq 'length') - echo "pr_exists=$PR_EXISTS" >> "$GITHUB_OUTPUT" - - if [ "$PR_EXISTS" -gt 0 ]; then + PR_LIST=$(gh pr list --head "${{ github.ref_name }}" --base develop --json number,state) + PR_COUNT=$(echo "$PR_LIST" | jq 'length') + echo "pr_exists=$PR_COUNT" >> "$GITHUB_OUTPUT" + + if [ "$PR_COUNT" -gt 0 ]; then PR_NUMBER=$(echo "$PR_LIST" | jq -r '.[0].number') echo "pr_number=$PR_NUMBER" >> "$GITHUB_OUTPUT" fi - - name: Create Pull Request to develop - if: steps.check-commits.outputs.commits_ahead > 0 && steps.check-pr.outputs.pr_exists == '0' + - name: Create or update PR and issues + if: steps.analyze.outputs.commits_ahead > 0 env: GH_TOKEN: ${{ github.token }} - ISSUES: ${{ steps.extract-issues.outputs.issues }} + ISSUES: ${{ steps.analyze.outputs.issues }} + RECENT_COMMITS: ${{ steps.analyze.outputs.recent_commits }} + PR_EXISTS: ${{ steps.check-pr.outputs.pr_exists }} run: | - # Format issues list (optional section) + # Format issues section ISSUES_SECTION="" if [ -n "$ISSUES" ]; then ISSUES_LIST="" for ISSUE in $ISSUES; do ISSUES_LIST+="- $ISSUE\n" done - ISSUES_SECTION="### 🐛 Issues Addressed - $ISSUES_LIST - - " + ISSUES_SECTION="### 🐛 Issues Addressed\n$ISSUES_LIST\n\n" fi - - gh pr create \ - --base develop \ - --head "${{ github.ref_name }}" \ - --title "[${{ github.ref_name }}] Merge to develop" \ - --body "## 🤖 Automated PR + + # Create PR if doesn't exist + if [ "$PR_EXISTS" -eq 0 ]; then + gh pr create \ + --base develop \ + --head "${{ github.ref_name }}" \ + --title "[${{ github.ref_name }}] Merge to develop" \ + --body "## 🤖 Automated PR ✅ **Build:** Passed ✅ **Tests:** Passed ${ISSUES_SECTION}### 📊 Details - - **Commits:** ${{ steps.check-commits.outputs.commits_ahead }} + - **Commits:** ${{ steps.analyze.outputs.commits_ahead }} - **Branch:** \`${{ github.ref_name }}\` - - **Commit:** \`${{ github.sha }}\` - **Author:** @${{ github.actor }} ### 📝 Recent Commits - $(git log "origin/develop..${{ github.ref_name }}" --pretty=format:'- %s (%h)' | head -5) + $RECENT_COMMITS --- - _This PR was automatically created by the feature-fix-workflow_" - - - name: Skip PR creation - No new commits - if: steps.check-commits.outputs.commits_ahead == 0 - run: | - echo "⏭️ Nenhum commit novo entre ${{ github.ref_name }} e develop" - echo "PR não será criado pois não há mudanças para mergear" - - - name: Skip PR creation - PR already exists - if: steps.check-commits.outputs.commits_ahead > 0 && steps.check-pr.outputs.pr_exists != '0' - run: | - echo "ℹ️ PR já existe para a branch ${{ github.ref_name }}" - - add-issue-comments: - if: github.event_name == 'push' - needs: build-and-test - runs-on: ubuntu-latest - permissions: - issues: write - contents: read - - steps: - - uses: actions/checkout@v4 - with: - fetch-depth: 0 - - - name: Extract and comment on issues - env: - GH_TOKEN: ${{ github.token }} - run: | - git fetch origin develop - COMMITS=$(git log "origin/develop..${{ github.ref_name }}" --pretty=format:'%s' 2>/dev/null || echo "") - - if [ -z "$COMMITS" ]; then - echo "ℹ️ No commits to process" - exit 0 + _Auto-created by feature-fix-workflow_" fi - - # Extract issue numbers - ISSUES=$(echo "$COMMITS" | grep -oiE '(close[sd]?|fix(es|ed)?|resolve[sd]?|#)[[:space:]]*#[0-9]+' | grep -oE '#[0-9]+' | sort -u || echo "") - - if [ -z "$ISSUES" ]; then - echo "ℹ️ No issues referenced in commits - skipping" - echo "This is normal for commits that don't reference issues." - exit 0 - fi - - echo "Found issues to comment on: $ISSUES" - - for ISSUE in $ISSUES; do - ISSUE_NUM=${ISSUE#\#} - echo "Processing issue #$ISSUE_NUM" - - # Check if issue exists and is open - ISSUE_STATE=$(gh issue view "$ISSUE_NUM" --json state --jq .state 2>/dev/null || echo "NOT_FOUND") - - if [ "$ISSUE_STATE" = "OPEN" ]; then - # Get recent commits for this branch - RECENT_COMMITS=$(git log "origin/develop..${{ github.ref_name }}" -n 3 --pretty=format:'- %s (%h)') - - gh issue comment "$ISSUE_NUM" --body "🔄 **Update from \`${{ github.ref_name }}\`** + + # Comment on open issues + if [ -n "$ISSUES" ]; then + for ISSUE in $ISSUES; do + ISSUE_NUM=${ISSUE#\#} + ISSUE_STATE=$(gh issue view "$ISSUE_NUM" --json state --jq .state 2>/dev/null || echo "NOT_FOUND") + + if [ "$ISSUE_STATE" = "OPEN" ]; then + gh issue comment "$ISSUE_NUM" --body "🔄 **Update from \`${{ github.ref_name }}\`** New commits pushed: $RECENT_COMMITS **Status:** In development - **Branch:** [${{ github.ref_name }}](https://github.com/${{ github.repository }}/tree/${{ github.ref_name }}) **Latest commit:** [${{ github.sha }}](https://github.com/${{ github.repository }}/commit/${{ github.sha }}) - --- - _Automated update from feature/fix workflow_" 2>/dev/null && echo "✅ Comment added to issue #$ISSUE_NUM" || echo "⚠️ Could not comment on issue #$ISSUE_NUM" - else - echo "⏭️ Skipping issue #$ISSUE_NUM (state: $ISSUE_STATE)" - fi - done - - echo "✅ Issue comment processing complete" + _Auto-update from feature/fix workflow_" 2>/dev/null || true + fi + done + fi close-issues-on-merge: if: github.event_name == 'pull_request' && github.event.pull_request.merged == true && github.base_ref == 'develop' @@ -225,74 +167,39 @@ jobs: permissions: issues: write contents: read - pull-requests: read steps: - uses: actions/checkout@v4 with: - fetch-depth: 0 - ref: develop + fetch-depth: 1 - - name: Extract and close issues + - name: Close referenced issues env: GH_TOKEN: ${{ github.token }} PR_NUMBER: ${{ github.event.pull_request.number }} - HEAD_REF: ${{ github.event.pull_request.head.ref }} run: | - echo "PR #$PR_NUMBER merged from $HEAD_REF into develop" - - # Get commits from the merged PR COMMITS=$(gh pr view "$PR_NUMBER" --json commits --jq '.commits[].messageHeadline') - - if [ -z "$COMMITS" ]; then - echo "ℹ️ No commits found in PR" - exit 0 - fi - - echo "Commits in PR:" - echo "$COMMITS" - - # Extract all issue references (Closes #123, Fixes #456, #789) ISSUES=$(echo "$COMMITS" | grep -oiE '(close[sd]?|fix(es|ed)?|resolve[sd]?)[[:space:]]*#[0-9]+' | grep -oE '#[0-9]+' | sort -u || echo "") if [ -z "$ISSUES" ]; then - echo "ℹ️ No issues referenced with close/fix/resolve keywords" + echo "No issues to close" exit 0 fi - echo "Found issues to close: $ISSUES" - for ISSUE in $ISSUES; do ISSUE_NUM=${ISSUE#\#} - echo "Processing issue #$ISSUE_NUM" - - # Check if issue exists and is open ISSUE_STATE=$(gh issue view "$ISSUE_NUM" --json state --jq .state 2>/dev/null || echo "NOT_FOUND") if [ "$ISSUE_STATE" = "OPEN" ]; then - # Add completion comment gh issue comment "$ISSUE_NUM" --body "✅ **Completed and merged to develop** - This issue has been resolved and merged into the \`develop\` branch. - **Merge Details:** - 🔀 PR: #$PR_NUMBER - - 🌿 Branch: \`$HEAD_REF\` + - 🌿 Branch: \`${{ github.event.pull_request.head.ref }}\` - 👤 Merged by: @${{ github.event.pull_request.merged_by.login }} - - 📅 Merged at: ${{ github.event.pull_request.merged_at }} - This fix will be included in the next release. - - --- - _Automatically closed by feature-fix workflow_" 2>/dev/null && echo "✅ Comment added to issue #$ISSUE_NUM" || echo "⚠️ Could not comment on issue #$ISSUE_NUM" + This fix will be included in the next release." 2>/dev/null || true - # Close the issue - gh issue close "$ISSUE_NUM" --reason completed 2>/dev/null && echo "✅ Issue #$ISSUE_NUM closed" || echo "⚠️ Could not close issue #$ISSUE_NUM" - elif [ "$ISSUE_STATE" = "CLOSED" ]; then - echo "ℹ️ Issue #$ISSUE_NUM already closed" - else - echo "⚠️ Issue #$ISSUE_NUM not found" + gh issue close "$ISSUE_NUM" --reason completed 2>/dev/null || true fi done - - echo "✅ Issue closure processing complete" diff --git a/.github/workflows/release-workflow.yml b/.github/workflows/release-workflow.yml index 79005b2..66d255b 100644 --- a/.github/workflows/release-workflow.yml +++ b/.github/workflows/release-workflow.yml @@ -29,63 +29,41 @@ jobs: steps: - uses: actions/checkout@v4 with: - fetch-depth: 0 + fetch-depth: 1 - - name: Check if PR already exists - id: check-pr + - name: Check and create PR env: GH_TOKEN: ${{ github.token }} run: | HEAD_BRANCH="${{ github.ref_name }}" PR_EXISTS=$(gh pr list --head "$HEAD_BRANCH" --base main --json number --jq 'length') - echo "pr_exists=$PR_EXISTS" >> "$GITHUB_OUTPUT" - if [ "$PR_EXISTS" -gt 0 ]; then - PR_NUMBER=$(gh pr list --head "$HEAD_BRANCH" --base main --json number --jq '.[0].number') - echo "pr_number=$PR_NUMBER" >> "$GITHUB_OUTPUT" - fi + if [ "$PR_EXISTS" -eq 0 ]; then + VERSION="${HEAD_BRANCH#release/v}" - - name: Create PR to main - if: steps.check-pr.outputs.pr_exists == '0' - env: - GH_TOKEN: ${{ github.token }} - run: | - HEAD_BRANCH="${{ github.ref_name }}" - VERSION="${HEAD_BRANCH#release/v}" - - gh pr create \ - --base main \ - --head "$HEAD_BRANCH" \ - --title "🚀 Release v${VERSION}" \ - --body "## 🚀 Release v${VERSION} + gh pr create \ + --base main \ + --head "$HEAD_BRANCH" \ + --title "🚀 Release v${VERSION}" \ + --body "## 🚀 Release v${VERSION} ### ⚙️ Release Configuration - **Escolha o tipo de release editando abaixo:** - Release Type: [lts] - **Opções válidas:** - - \`alpha\` - Release alpha (instável, desenvolvimento) - - \`beta\` - Release beta (pré-release, testes) - - \`lts\` - Release estável de longo prazo (produção) + **Options:** \`alpha\`, \`beta\`, \`lts\` --- - _PR criado automaticamente pelo release-workflow_" \ - --draft - - - name: PR already exists - if: steps.check-pr.outputs.pr_exists != '0' - run: | - echo "ℹ️ PR já existe (#${{ steps.check-pr.outputs.pr_number }}) para ${{ github.ref_name }} -> main" + _Auto-created by release-workflow_" \ + --draft + fi create-release: - name: Create GitHub Release (on merge) + name: Create GitHub Release if: github.event_name == 'pull_request' && github.event.pull_request.merged == true && startsWith(github.event.pull_request.head.ref, 'release/') runs-on: ubuntu-latest permissions: contents: write - pull-requests: write steps: - uses: actions/checkout@v4 @@ -93,7 +71,7 @@ jobs: fetch-depth: 0 ref: ${{ github.event.pull_request.merge_commit_sha }} - - name: Extract version and release type + - name: Extract version and type id: extract env: PR_BODY: ${{ github.event.pull_request.body }} @@ -103,12 +81,7 @@ jobs: echo "version=$VERSION" >> "$GITHUB_OUTPUT" PR_BODY_CLEAN=$(printf '%s' "$PR_BODY" | tr -d '\r') - - RELEASE_TYPE=$(printf '%s' "$PR_BODY_CLEAN" | grep -oP 'Release Type:\s*\[\K(alpha|beta|lts)(?=\])' || true) - if [ -z "$RELEASE_TYPE" ]; then - RELEASE_TYPE=$(printf '%s' "$PR_BODY_CLEAN" | grep -oP 'Release Type:\s*\K(alpha|beta|lts)' || echo "lts") - fi - + RELEASE_TYPE=$(printf '%s' "$PR_BODY_CLEAN" | grep -oP 'Release Type:\s*\[\K(alpha|beta|lts)(?=\])' || echo "lts") echo "release_type=$RELEASE_TYPE" >> "$GITHUB_OUTPUT" if [ "$RELEASE_TYPE" = "lts" ]; then @@ -118,97 +91,63 @@ jobs: fi echo "full_tag=$FULL_TAG" >> "$GITHUB_OUTPUT" - echo "✅ Version: $VERSION" - echo "✅ Release Type: $RELEASE_TYPE" - echo "✅ Full Tag: $FULL_TAG" - - name: Setup Rust + - name: Setup Rust and build uses: dtolnay/rust-toolchain@stable - name: Rust cache uses: Swatinem/rust-cache@v2 - with: - cache-on-failure: true - name: Build release artifacts run: | - echo "🔨 Building release artifacts..." cargo build --release - mkdir -p artifacts - if [ -d "target/release" ]; then - find target/release -maxdepth 1 -type f -executable -exec cp {} artifacts/ \; - fi + find target/release -maxdepth 1 -type f -executable -exec cp {} artifacts/ \; || true - echo "📦 Artifacts criados:" - ls -lh artifacts/ || true - - - name: Create and push tag + - name: Create tag and release env: + GH_TOKEN: ${{ github.token }} FULL_TAG: ${{ steps.extract.outputs.full_tag }} + VERSION: ${{ steps.extract.outputs.version }} + RELEASE_TYPE: ${{ steps.extract.outputs.release_type }} run: | git config user.name "github-actions[bot]" git config user.email "github-actions[bot]@users.noreply.github.com" - echo "🏷️ Creating tag $FULL_TAG" git tag -a "$FULL_TAG" -m "Release $FULL_TAG" git push origin "$FULL_TAG" - echo "✅ Tag $FULL_TAG created and pushed" - - name: Generate changelog - id: changelog - run: | LAST_TAG=$(git describe --tags --abbrev=0 HEAD^ 2>/dev/null || echo "") if [ -z "$LAST_TAG" ]; then - echo "📝 Generating full changelog (first release)" CHANGELOG=$(git log --pretty=format:"- %s (\`%h\`)" | head -50) else - echo "📝 Generating changelog from $LAST_TAG" CHANGELOG=$(git log "${LAST_TAG}..HEAD" --pretty=format:"- %s (\`%h\`)") fi - echo "$CHANGELOG" > /tmp/changelog.txt - - - name: Create GitHub Release - env: - GH_TOKEN: ${{ github.token }} - FULL_TAG: ${{ steps.extract.outputs.full_tag }} - VERSION: ${{ steps.extract.outputs.version }} - RELEASE_TYPE: ${{ steps.extract.outputs.release_type }} - run: | PRERELEASE_FLAG="" RELEASE_LABEL="Stable" if [ "$RELEASE_TYPE" = "alpha" ]; then PRERELEASE_FLAG="--prerelease" - RELEASE_LABEL="Alpha (Unstable)" + RELEASE_LABEL="Alpha" elif [ "$RELEASE_TYPE" = "beta" ]; then PRERELEASE_FLAG="--prerelease" - RELEASE_LABEL="Beta (Pre-release)" + RELEASE_LABEL="Beta" elif [ "$RELEASE_TYPE" = "lts" ]; then - RELEASE_LABEL="LTS (Long Term Support)" + RELEASE_LABEL="LTS" fi - CHANGELOG=$(cat /tmp/changelog.txt) - gh release create "$FULL_TAG" \ --title "Release $FULL_TAG" \ - --notes "## 🎉 Release $VERSION - - ### 📦 Release Type - **$RELEASE_LABEL** + --notes "## 🎉 Release $VERSION ($RELEASE_LABEL) ### 📝 Changes $CHANGELOG --- - - **Pull Request**: #${{ github.event.pull_request.number }} - - --- - - _Released on: $(date +'%Y-%m-%d %H:%M:%S UTC')_ - _Built from commit: \`${{ github.sha }}\`_" \ + **PR:** #${{ github.event.pull_request.number }} + **Commit:** \`${{ github.sha }}\`" \ $PRERELEASE_FLAG \ artifacts/* 2>/dev/null || true diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index a9f1c9e..0a39c0e 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -10,6 +10,10 @@ env: CARGO_TERM_COLOR: always RUST_BACKTRACE: 1 +concurrency: + group: test-${{ github.ref }} + cancel-in-progress: true + jobs: test: name: Test Suite @@ -17,101 +21,51 @@ jobs: strategy: fail-fast: false matrix: - rust: [stable, beta, nightly] + rust: [stable, nightly] steps: - name: Checkout code uses: actions/checkout@v4 + with: + fetch-depth: 1 - name: Install Rust toolchain uses: dtolnay/rust-toolchain@master with: toolchain: ${{ matrix.rust }} - - name: Cache cargo registry - uses: actions/cache@v4 - with: - path: ~/.cargo/registry - key: ${{ runner.os }}-cargo-registry-${{ hashFiles('**/Cargo.lock') }} - restore-keys: | - ${{ runner.os }}-cargo-registry- - - - name: Cache cargo index - uses: actions/cache@v4 + - name: Rust cache + uses: Swatinem/rust-cache@v2 with: - path: ~/.cargo/git - key: ${{ runner.os }}-cargo-git-${{ hashFiles('**/Cargo.lock') }} - restore-keys: | - ${{ runner.os }}-cargo-git- - - - name: Cache target directory - uses: actions/cache@v4 - with: - path: target - key: ${{ runner.os }}-target-${{ matrix.rust }}-${{ hashFiles('**/Cargo.lock') }} - restore-keys: | - ${{ runner.os }}-target-${{ matrix.rust }}- - ${{ runner.os }}-target- - - - name: Build project - run: cargo build --all-features --verbose + cache-on-failure: true + key: ${{ matrix.rust }} - - name: Run tests (all features) - run: cargo test --all-features --verbose + - name: Build and test + run: | + cargo build --all-features --verbose + cargo test --all-features --verbose + cargo test --doc --all-features --verbose - - name: Run doctests - run: cargo test --doc --all-features --verbose - - fmt: - name: Rustfmt + quality: + name: Code Quality runs-on: ubuntu-latest steps: - name: Checkout code uses: actions/checkout@v4 - - - name: Install Rust toolchain - uses: dtolnay/rust-toolchain@stable with: - components: rustfmt - - - name: Check formatting - run: cargo fmt --all -- --check - - clippy: - name: Clippy - runs-on: ubuntu-latest - steps: - - name: Checkout code - uses: actions/checkout@v4 + fetch-depth: 1 - name: Install Rust toolchain uses: dtolnay/rust-toolchain@stable with: - components: clippy + components: rustfmt, clippy - - name: Cache cargo registry - uses: actions/cache@v4 + - name: Rust cache + uses: Swatinem/rust-cache@v2 with: - path: ~/.cargo/registry - key: ${{ runner.os }}-cargo-registry-${{ hashFiles('**/Cargo.lock') }} - restore-keys: | - ${{ runner.os }}-cargo-registry- + cache-on-failure: true - - name: Cache cargo index - uses: actions/cache@v4 - with: - path: ~/.cargo/git - key: ${{ runner.os }}-cargo-git-${{ hashFiles('**/Cargo.lock') }} - restore-keys: | - ${{ runner.os }}-cargo-git- - - - name: Cache target directory - uses: actions/cache@v4 - with: - path: target - key: ${{ runner.os }}-target-clippy-${{ hashFiles('**/Cargo.lock') }} - restore-keys: | - ${{ runner.os }}-target-clippy- - ${{ runner.os }}-target- + - name: Check formatting + run: cargo fmt --all -- --check - name: Run Clippy run: cargo clippy --all-features --all-targets -- -D warnings @@ -122,12 +76,17 @@ jobs: steps: - name: Checkout code uses: actions/checkout@v4 + with: + fetch-depth: 1 - name: Install Rust toolchain uses: dtolnay/rust-toolchain@stable + - name: Rust cache + uses: Swatinem/rust-cache@v2 + - name: Install tarpaulin - run: cargo install cargo-tarpaulin + run: cargo install cargo-tarpaulin --locked - name: Generate coverage run: cargo tarpaulin --all-features --workspace --timeout 300 --out Xml