Skip to content

header image

header image #3

Workflow file for this run

name: Build & Test
on:
push:
branches: [main]
pull_request:
branches: [main]
types: [opened, synchronize, reopened, labeled, unlabeled]
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
env:
GOLANG_VERSION: 1.24.4
permissions:
contents: read
pull-requests: write
jobs:
check-label:
name: Check Required Label
runs-on: ubuntu-latest
if: github.event_name == 'pull_request'
outputs:
should-run: ${{ steps.check.outputs.should-run }}
steps:
- name: Check for run-checks label
id: check
uses: actions/github-script@v7
with:
script: |
const labels = context.payload.pull_request.labels.map(label => label.name);
const hasRunChecks = labels.includes('run-checks');
console.log('PR labels:', labels);
console.log('Has run-checks label:', hasRunChecks);
// Remove checks-passed label if it exists (we'll re-add it if checks pass)
if (labels.includes('checks-passed')) {
console.log('Removing checks-passed label');
try {
await github.rest.issues.removeLabel({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
name: 'checks-passed'
});
} catch (error) {
console.log('Failed to remove checks-passed label:', error.message);
console.log('This may be due to insufficient permissions.');
}
}
core.setOutput('should-run', hasRunChecks.toString());
if (!hasRunChecks) {
console.log('Skipping checks - run-checks label not found');
}
build:
runs-on: ubuntu-latest
needs: [check-label]
if: github.event_name == 'push' || needs.check-label.outputs.should-run == 'true'
strategy:
matrix:
go-version: ["1.24.4"]
steps:
- uses: actions/checkout@v4
- uses: ./.github/actions/go-setup
with:
go-version: ${{ matrix.go-version }}
- name: Cache build artifacts
uses: actions/cache@v4
with:
path: build/
key: build-${{ runner.os }}-${{ github.sha }}-${{ hashFiles('**/*.go') }}
restore-keys: |
build-${{ runner.os }}-${{ github.sha }}-
build-${{ runner.os }}-
- name: Verify dependencies
run: task mod:verify
- name: Check formatting
run: task fmt:check
- name: Build
run: task build
test:
name: Unit Tests
runs-on: ubuntu-latest
needs: [build, lint]
if: always() && !cancelled() && (needs.build.result == 'success' && needs.lint.result == 'success')
strategy:
matrix:
go-version: ["1.24.4"]
steps:
- uses: actions/checkout@v4
- uses: ./.github/actions/go-setup
with:
go-version: ${{ matrix.go-version }}
- name: Cache test results
uses: actions/cache@v4
with:
path: |
coverage.out
coverage.html
key: test-coverage-${{ runner.os }}-${{ github.sha }}-${{ hashFiles('**/*.go', '**/*_test.go') }}
restore-keys: |
test-coverage-${{ runner.os }}-${{ github.sha }}-
test-coverage-${{ runner.os }}-
- name: Run tests with coverage
run: task test:coverage
- name: Upload test results
uses: actions/upload-artifact@v4
with:
name: test-artifact
path: |
coverage.out
coverage.html
lint:
name: Lint
runs-on: ubuntu-latest
needs: [check-label]
if: github.event_name == 'push' || needs.check-label.outputs.should-run == 'true'
steps:
- uses: actions/checkout@v4
- uses: ./.github/actions/go-setup
with:
go-version: "${{ env.GOLANG_VERSION }}"
- name: Run golangci-lint
uses: golangci/golangci-lint-action@v8
with:
version: v2.1.6
args: --timeout=5m --skip-dirs=docs
vulnerability-check:
name: Vulnerability Check
runs-on: ubuntu-latest
needs: [build, lint]
if: always() && !cancelled() && (needs.build.result == 'success' && needs.lint.result == 'success')
steps:
- uses: actions/checkout@v4
- uses: ./.github/actions/go-setup
with:
go-version: "${{ env.GOLANG_VERSION }}"
- name: Cache govulncheck
uses: actions/cache@v4
with:
path: ~/go/bin/govulncheck
key: govulncheck-${{ runner.os }}-v1.1.3
restore-keys: |
govulncheck-${{ runner.os }}-
- name: Install govulncheck
run: |
go install golang.org/x/vuln/cmd/govulncheck@v1.1.3
- name: Cache vulnerability database
uses: actions/cache@v4
with:
path: ~/.cache/go-build
key: vuln-db-${{ runner.os }}-${{ hashFiles('go.sum') }}
restore-keys: |
vuln-db-${{ runner.os }}-
- name: Run vulnerability check with docs
run: task vuln:check
quality-check-summary:
name: Quality Check Summary
runs-on: ubuntu-latest
needs: [check-label, build, test, lint, vulnerability-check]
if: always() && github.event_name == 'pull_request' && needs.check-label.outputs.should-run == 'true'
steps:
- name: Post Quality Check Results
uses: actions/github-script@v7
with:
script: |
const { data: comments } = await github.rest.issues.listComments({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
});
// Find all bot comments with the quality check header
const botComments = comments.filter(comment =>
comment.user.type === 'Bot' &&
comment.body.includes('## 💎 Quality Check')
);
// Delete all previous quality check comments
for (const comment of botComments) {
await github.rest.issues.deleteComment({
owner: context.repo.owner,
repo: context.repo.repo,
comment_id: comment.id,
});
}
const buildStatus = '${{ needs.build.result }}';
const testStatus = '${{ needs.test.result }}';
const lintStatus = '${{ needs.lint.result }}';
const vulnStatus = '${{ needs.vulnerability-check.result }}';
console.log('Job statuses:', { buildStatus, testStatus, lintStatus, vulnStatus });
let statusEmoji = '✅';
let statusText = 'All quality checks passed!';
const requiredChecks = [buildStatus, testStatus, lintStatus, vulnStatus];
if (requiredChecks.some(status => status !== 'success')) {
statusEmoji = '❌';
statusText = 'Some quality checks failed.';
}
const body = `## 💎 Environment Manager Quality Check
${statusEmoji} **Status**: ${statusText}
### Quality Summary
| Check | Status |
|-------|--------|
| **Build** | ${buildStatus === 'success' ? '✅ Application builds successfully' : '❌ Build failures'} |
| **Unit Tests** | ${testStatus === 'success' ? '✅ All tests pass with race detection' : '❌ Test failures'} |
| **Code Quality** | ${lintStatus === 'success' ? '✅ golangci-lint clean' : '❌ Linting issues'} |
| **Security** | ${vulnStatus === 'success' ? '✅ No known vulnerabilities' : '❌ Vulnerabilities detected'} |
${statusEmoji === '✅' ? '### 🎉 Your code is ready to deploy!' : '### ⚠️ Please address the failing checks above.'}
<details>
<summary>View detailed results</summary>
- **Build**: ${buildStatus}
- **Unit Tests**: ${testStatus}
- **Lint**: ${lintStatus}
- **Vulnerability Check**: ${vulnStatus}
</details>
---
<sub>🤖 This comment is automatically updated on each workflow run.</sub>`;
// Always create a new comment
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
body: body
});
// Add checks-passed label if all enabled checks succeeded
if (statusEmoji === '✅') {
console.log('All enabled checks passed - adding checks-passed label');
try {
await github.rest.issues.addLabels({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
labels: ['checks-passed']
});
} catch (error) {
console.log('Failed to add checks-passed label:', error.message);
console.log('This may be due to insufficient permissions. The label needs to be added manually.');
}
}