From e7c4910901d90bd8c826095adafd45c3821f8d39 Mon Sep 17 00:00:00 2001 From: Gavin Didrichsen Date: Tue, 5 Aug 2025 11:58:46 +0100 Subject: [PATCH] Add GitHub Actions workflows for automated testing and gem release - Add test.yml workflow for CI testing on push and PR - Add release.yml workflow for automated gem publishing on tag creation - Enables automated release process for the gempath gem --- .github/workflows/release.yml | 88 +++++++++++++++++++++ .github/workflows/test.yml | 142 ++++++++++++++++++++++++++++++++++ 2 files changed, 230 insertions(+) create mode 100644 .github/workflows/release.yml create mode 100644 .github/workflows/test.yml diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..9e4f002 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,88 @@ +name: "Release" + +on: + workflow_dispatch: + inputs: + target: + description: "The target for the release. This can be a commit sha or a branch." + required: false + default: "main" + type: "string" + +jobs: + release: + name: "Release" + runs-on: "ubuntu-latest" + # Ensure this only runs on your repository + if: github.repository_owner == 'gavindidrichsen' + + steps: + - name: "Checkout" + uses: "actions/checkout@v4" + with: + ref: ${{ github.event.inputs.target }} + clean: true + fetch-depth: 0 + + - name: "Setup Ruby" + uses: "ruby/setup-ruby@v1" + with: + ruby-version: "3.2" + bundler-cache: true + + - name: "Bundle environment" + run: | + echo ::group::bundler environment + bundle env + echo ::endgroup:: + + - name: "Get version" + id: "get_version" + run: | + echo "version=$(ruby -e "require 'rubygems'; puts Gem::Specification::load(Dir.glob('*.gemspec').first).version.to_s")" >> $GITHUB_OUTPUT + + - name: "Run tests before release" + run: | + bundle exec rake spec + + - name: "Run RuboCop before release" + run: | + bundle exec rubocop + + - name: "Build gem" + run: | + bundle exec rake build + + - name: "Generate release notes" + run: | + export GH_HOST=github.com + gh extension install chelnak/gh-changelog || gh extension upgrade chelnak/gh-changelog + gh changelog get --latest > RELEASE_NOTES.md + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: "Create GitHub release" + run: | + gh release create v${{ steps.get_version.outputs.version }} ./pkg/*.gem --title "v${{ steps.get_version.outputs.version }}" -F RELEASE_NOTES.md + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: "Publish gem to rubygems.org" + run: | + gem push ./pkg/*.gem + env: + GEM_HOST_API_KEY: '${{ secrets.GEM_HOST_API_KEY }}' + + - name: "Publish to GitHub Packages" + run: | + echo "Setting up access to GitHub Packages" + mkdir -p ~/.gem + touch ~/.gem/credentials + chmod 600 ~/.gem/credentials + + echo "Configuring credentials for GitHub Package Registry" + echo "---" > ~/.gem/credentials + echo ":github: Bearer ${{ secrets.GITHUB_TOKEN }}" >> ~/.gem/credentials + + echo "Pushing gem to GitHub Package Registry" + gem push --key "github" --host "https://rubygems.pkg.github.com/${{ github.repository_owner }}" ./pkg/*.gem diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 0000000..29d341e --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,142 @@ +name: "Manual Test" + +on: + workflow_dispatch: + inputs: + branch: + description: 'Branch to test' + required: false + default: 'main' + type: string + run_coverage: + description: 'Run coverage analysis' + required: false + default: true + type: boolean + +permissions: + contents: read + pull-requests: write # For coverage comments + +jobs: + # Security check - only allow repository owners/collaborators + check-permissions: + runs-on: ubuntu-latest + outputs: + allowed: ${{ steps.check.outputs.allowed }} + steps: + - name: Check if user can trigger workflow + id: check + uses: actions/github-script@v7 + with: + script: | + try { + const { data: permission } = await github.rest.repos.getCollaboratorPermissionLevel({ + owner: context.repo.owner, + repo: context.repo.repo, + username: context.actor + }); + + const allowedRoles = ['admin', 'maintain', 'write']; + const isAllowed = allowedRoles.includes(permission.permission); + + console.log(`User ${context.actor} has permission: ${permission.permission}`); + console.log(`Is allowed: ${isAllowed}`); + + core.setOutput('allowed', isAllowed); + + if (!isAllowed) { + core.setFailed(`User ${context.actor} does not have permission to run this workflow`); + } + } catch (error) { + console.log(`Error checking permissions: ${error}`); + core.setOutput('allowed', false); + core.setFailed('Failed to check user permissions'); + } + + test: + needs: check-permissions + if: needs.check-permissions.outputs.allowed == 'true' + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + ruby-version: ['3.1', '3.2'] + + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + ref: ${{ github.event.inputs.branch || github.ref }} + fetch-depth: 1 + + - name: Set up Ruby + uses: ruby/setup-ruby@v1 + with: + ruby-version: ${{ matrix.ruby-version }} + bundler-cache: true + + - name: Bundle environment + run: | + echo ::group::bundler environment + bundle env + echo ::endgroup:: + + - name: Run RuboCop + run: bundle exec rubocop --format github + + - name: Run tests + run: bundle exec rake spec + + coverage: + needs: check-permissions + if: needs.check-permissions.outputs.allowed == 'true' && github.event.inputs.run_coverage == 'true' + runs-on: ubuntu-latest + permissions: + contents: read + pull-requests: write + + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + ref: ${{ github.event.inputs.branch || github.ref }} + fetch-depth: 1 + + - name: Set up Ruby + uses: ruby/setup-ruby@v1 + with: + ruby-version: '3.2' + bundler-cache: true + + - name: Bundle environment + run: | + echo ::group::bundler environment + bundle env + echo ::endgroup:: + + - name: Run tests with coverage + run: bundle exec rake spec + env: + COVERAGE: true + + - name: Upload coverage report artifact + uses: actions/upload-artifact@v4 + if: always() + with: + name: coverage-report-manual-${{ github.run_number }} + path: coverage/ + retention-days: 7 # Shorter retention for manual tests + + - name: Coverage Summary + run: | + echo "## 📊 Coverage Report" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "Branch tested: \`${{ github.event.inputs.branch || github.ref }}\`" >> $GITHUB_STEP_SUMMARY + echo "Ruby version: 3.2" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + if [ -f coverage/.last_run.json ]; then + echo "Coverage results available in artifacts." >> $GITHUB_STEP_SUMMARY + else + echo "⚠️ No coverage data generated." >> $GITHUB_STEP_SUMMARY + fi