Skip to content

Commit a4d3069

Browse files
committed
init
0 parents  commit a4d3069

File tree

23 files changed

+1878
-0
lines changed

23 files changed

+1878
-0
lines changed

.air.toml

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
root = "."
2+
testdata_dir = "testdata"
3+
tmp_dir = "tmp"
4+
5+
[build]
6+
args_bin = []
7+
bin = "./tmp/main"
8+
cmd = "go build -o ./tmp/main ./cmd/api/main.go"
9+
delay = 1000
10+
exclude_dir = ["assets", "tmp", "vendor", "testdata", "node_modules"]
11+
exclude_file = []
12+
exclude_regex = ["_test.go"]
13+
exclude_unchanged = false
14+
follow_symlink = false
15+
full_bin = ""
16+
include_dir = []
17+
include_ext = ["go", "tpl", "tmpl", "html"]
18+
include_file = []
19+
kill_delay = "0s"
20+
log = "build-errors.log"
21+
poll = false
22+
poll_interval = 0
23+
rerun = false
24+
rerun_delay = 500
25+
send_interrupt = false
26+
stop_on_error = false
27+
28+
[color]
29+
app = ""
30+
build = "yellow"
31+
main = "magenta"
32+
runner = "green"
33+
watcher = "cyan"
34+
35+
[log]
36+
main_only = false
37+
time = false
38+
39+
[misc]
40+
clean_on_exit = false
41+
42+
[screen]
43+
clear_on_rebuild = false
44+
keep_scroll = true

.env.example

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# API Configuration
2+
API_KEY=your-api-key-here
3+
4+
# Server Configuration (optional)
5+
PORT=8080
6+
7+
# AWS Configuration (optional, can use AWS CLI profile instead)
8+
# AWS_ACCESS_KEY_ID=your-access-key
9+
# AWS_SECRET_ACCESS_KEY=your-secret-key
10+
# AWS_REGION=us-west-1
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
# .github/actions/go-setup/action.yml
2+
name: 'Go Environment Setup'
3+
description: 'Sets up Go, installs Go Task, and swag for documentation generation.'
4+
inputs:
5+
go-version:
6+
description: 'The Go version to set up.'
7+
required: false
8+
default: '1.24.4' # Match the project's Go version
9+
10+
runs:
11+
using: "composite"
12+
steps:
13+
- name: Set up Go ${{ inputs.go-version }}
14+
uses: actions/setup-go@v5
15+
with:
16+
go-version: ${{ inputs.go-version }}
17+
cache: true
18+
cache-dependency-path: |
19+
go.sum
20+
go.mod
21+
22+
- name: Cache Go tools
23+
uses: actions/cache@v4
24+
id: cache-go-tools
25+
with:
26+
path: |
27+
~/go/bin/task
28+
~/go/bin/swag
29+
key: go-tools-${{ runner.os }}-${{ inputs.go-version }}-task-v3-swag-latest
30+
restore-keys: |
31+
go-tools-${{ runner.os }}-${{ inputs.go-version }}-
32+
33+
- name: Install Go Task
34+
if: steps.cache-go-tools.outputs.cache-hit != 'true'
35+
shell: bash
36+
run: |
37+
go install github.com/go-task/task/v3/cmd/task@latest
38+
39+
- name: Install swag for docs generation
40+
if: steps.cache-go-tools.outputs.cache-hit != 'true'
41+
shell: bash
42+
run: |
43+
go install github.com/swaggo/swag/cmd/swag@latest
44+
45+
- name: Cache generated docs
46+
uses: actions/cache@v4
47+
id: cache-docs
48+
with:
49+
path: docs/
50+
key: swagger-docs-${{ runner.os }}-${{ hashFiles('cmd/docs/main.go', 'internal/handlers/*.go', 'internal/types/*.go') }}
51+
restore-keys: |
52+
swagger-docs-${{ runner.os }}-
53+
54+
- name: Generate documentation
55+
if: steps.cache-docs.outputs.cache-hit != 'true'
56+
shell: bash
57+
run: |
58+
task docs

.github/workflows/go.yml

Lines changed: 282 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,282 @@
1+
name: Build & Test
2+
3+
on:
4+
push:
5+
branches: [main]
6+
pull_request:
7+
branches: [main]
8+
types: [opened, synchronize, reopened, labeled, unlabeled]
9+
10+
concurrency:
11+
group: ${{ github.workflow }}-${{ github.ref }}
12+
cancel-in-progress: true
13+
14+
env:
15+
GOLANG_VERSION: 1.24.4
16+
17+
permissions:
18+
contents: read
19+
pull-requests: write
20+
21+
jobs:
22+
check-label:
23+
name: Check Required Label
24+
runs-on: ubuntu-latest
25+
if: github.event_name == 'pull_request'
26+
outputs:
27+
should-run: ${{ steps.check.outputs.should-run }}
28+
steps:
29+
- name: Check for run-checks label
30+
id: check
31+
uses: actions/github-script@v7
32+
with:
33+
script: |
34+
const labels = context.payload.pull_request.labels.map(label => label.name);
35+
const hasRunChecks = labels.includes('run-checks');
36+
console.log('PR labels:', labels);
37+
console.log('Has run-checks label:', hasRunChecks);
38+
39+
// Remove checks-passed label if it exists (we'll re-add it if checks pass)
40+
if (labels.includes('checks-passed')) {
41+
console.log('Removing checks-passed label');
42+
try {
43+
await github.rest.issues.removeLabel({
44+
owner: context.repo.owner,
45+
repo: context.repo.repo,
46+
issue_number: context.issue.number,
47+
name: 'checks-passed'
48+
});
49+
} catch (error) {
50+
console.log('Failed to remove checks-passed label:', error.message);
51+
console.log('This may be due to insufficient permissions.');
52+
}
53+
}
54+
55+
core.setOutput('should-run', hasRunChecks.toString());
56+
if (!hasRunChecks) {
57+
console.log('Skipping checks - run-checks label not found');
58+
}
59+
60+
build:
61+
runs-on: ubuntu-latest
62+
needs: [check-label]
63+
if: github.event_name == 'push' || needs.check-label.outputs.should-run == 'true'
64+
strategy:
65+
matrix:
66+
go-version: ["1.24.4"]
67+
68+
steps:
69+
- uses: actions/checkout@v4
70+
71+
- uses: ./.github/actions/go-setup
72+
with:
73+
go-version: ${{ matrix.go-version }}
74+
75+
- name: Cache build artifacts
76+
uses: actions/cache@v4
77+
with:
78+
path: build/
79+
key: build-${{ runner.os }}-${{ github.sha }}-${{ hashFiles('**/*.go') }}
80+
restore-keys: |
81+
build-${{ runner.os }}-${{ github.sha }}-
82+
build-${{ runner.os }}-
83+
84+
- name: Verify dependencies
85+
run: task mod:verify
86+
87+
- name: Check formatting
88+
run: task fmt:check
89+
90+
- name: Build
91+
run: task build
92+
93+
test:
94+
name: Unit Tests
95+
runs-on: ubuntu-latest
96+
needs: [build, lint]
97+
if: always() && !cancelled() && (needs.build.result == 'success' && needs.lint.result == 'success')
98+
strategy:
99+
matrix:
100+
go-version: ["1.24.4"]
101+
102+
steps:
103+
- uses: actions/checkout@v4
104+
105+
- uses: ./.github/actions/go-setup
106+
with:
107+
go-version: ${{ matrix.go-version }}
108+
109+
- name: Cache test results
110+
uses: actions/cache@v4
111+
with:
112+
path: |
113+
coverage.out
114+
coverage.html
115+
key: test-coverage-${{ runner.os }}-${{ github.sha }}-${{ hashFiles('**/*.go', '**/*_test.go') }}
116+
restore-keys: |
117+
test-coverage-${{ runner.os }}-${{ github.sha }}-
118+
test-coverage-${{ runner.os }}-
119+
120+
- name: Run tests with coverage
121+
run: task test:coverage
122+
123+
- name: Upload test results
124+
uses: actions/upload-artifact@v4
125+
with:
126+
name: test-artifact
127+
path: |
128+
coverage.out
129+
coverage.html
130+
131+
lint:
132+
name: Lint
133+
runs-on: ubuntu-latest
134+
needs: [check-label]
135+
if: github.event_name == 'push' || needs.check-label.outputs.should-run == 'true'
136+
steps:
137+
- uses: actions/checkout@v4
138+
139+
- uses: ./.github/actions/go-setup
140+
with:
141+
go-version: "${{ env.GOLANG_VERSION }}"
142+
143+
- name: Run golangci-lint
144+
uses: golangci/golangci-lint-action@v8
145+
with:
146+
version: v2.1.6
147+
args: --timeout=5m --skip-dirs=docs
148+
149+
vulnerability-check:
150+
name: Vulnerability Check
151+
runs-on: ubuntu-latest
152+
needs: [build, lint]
153+
if: always() && !cancelled() && (needs.build.result == 'success' && needs.lint.result == 'success')
154+
steps:
155+
- uses: actions/checkout@v4
156+
157+
- uses: ./.github/actions/go-setup
158+
with:
159+
go-version: "${{ env.GOLANG_VERSION }}"
160+
161+
- name: Cache govulncheck
162+
uses: actions/cache@v4
163+
with:
164+
path: ~/go/bin/govulncheck
165+
key: govulncheck-${{ runner.os }}-v1.1.3
166+
restore-keys: |
167+
govulncheck-${{ runner.os }}-
168+
169+
- name: Install govulncheck
170+
run: |
171+
go install golang.org/x/vuln/cmd/govulncheck@v1.1.3
172+
173+
- name: Cache vulnerability database
174+
uses: actions/cache@v4
175+
with:
176+
path: ~/.cache/go-build
177+
key: vuln-db-${{ runner.os }}-${{ hashFiles('go.sum') }}
178+
restore-keys: |
179+
vuln-db-${{ runner.os }}-
180+
181+
- name: Run vulnerability check with docs
182+
run: task vuln:check
183+
184+
quality-check-summary:
185+
name: Quality Check Summary
186+
runs-on: ubuntu-latest
187+
needs: [check-label, build, test, lint, vulnerability-check]
188+
if: always() && github.event_name == 'pull_request' && needs.check-label.outputs.should-run == 'true'
189+
steps:
190+
- name: Post Quality Check Results
191+
uses: actions/github-script@v7
192+
with:
193+
script: |
194+
const { data: comments } = await github.rest.issues.listComments({
195+
owner: context.repo.owner,
196+
repo: context.repo.repo,
197+
issue_number: context.issue.number,
198+
});
199+
200+
// Find all bot comments with the quality check header
201+
const botComments = comments.filter(comment =>
202+
comment.user.type === 'Bot' &&
203+
comment.body.includes('## 💎 Quality Check')
204+
);
205+
206+
// Delete all previous quality check comments
207+
for (const comment of botComments) {
208+
await github.rest.issues.deleteComment({
209+
owner: context.repo.owner,
210+
repo: context.repo.repo,
211+
comment_id: comment.id,
212+
});
213+
}
214+
215+
const buildStatus = '${{ needs.build.result }}';
216+
const testStatus = '${{ needs.test.result }}';
217+
const lintStatus = '${{ needs.lint.result }}';
218+
const vulnStatus = '${{ needs.vulnerability-check.result }}';
219+
console.log('Job statuses:', { buildStatus, testStatus, lintStatus, vulnStatus });
220+
221+
let statusEmoji = '✅';
222+
let statusText = 'All quality checks passed!';
223+
224+
const requiredChecks = [buildStatus, testStatus, lintStatus, vulnStatus];
225+
226+
if (requiredChecks.some(status => status !== 'success')) {
227+
statusEmoji = '❌';
228+
statusText = 'Some quality checks failed.';
229+
}
230+
231+
232+
const body = `## 💎 Environment Manager Quality Check
233+
234+
${statusEmoji} **Status**: ${statusText}
235+
236+
### Quality Summary
237+
238+
| Check | Status |
239+
|-------|--------|
240+
| **Build** | ${buildStatus === 'success' ? '✅ Application builds successfully' : '❌ Build failures'} |
241+
| **Unit Tests** | ${testStatus === 'success' ? '✅ All tests pass with race detection' : '❌ Test failures'} |
242+
| **Code Quality** | ${lintStatus === 'success' ? '✅ golangci-lint clean' : '❌ Linting issues'} |
243+
| **Security** | ${vulnStatus === 'success' ? '✅ No known vulnerabilities' : '❌ Vulnerabilities detected'} |
244+
245+
${statusEmoji === '✅' ? '### 🎉 Your code is ready to deploy!' : '### ⚠️ Please address the failing checks above.'}
246+
247+
<details>
248+
<summary>View detailed results</summary>
249+
250+
- **Build**: ${buildStatus}
251+
- **Unit Tests**: ${testStatus}
252+
- **Lint**: ${lintStatus}
253+
- **Vulnerability Check**: ${vulnStatus}
254+
255+
</details>
256+
257+
---
258+
<sub>🤖 This comment is automatically updated on each workflow run.</sub>`;
259+
260+
// Always create a new comment
261+
await github.rest.issues.createComment({
262+
owner: context.repo.owner,
263+
repo: context.repo.repo,
264+
issue_number: context.issue.number,
265+
body: body
266+
});
267+
268+
// Add checks-passed label if all enabled checks succeeded
269+
if (statusEmoji === '✅') {
270+
console.log('All enabled checks passed - adding checks-passed label');
271+
try {
272+
await github.rest.issues.addLabels({
273+
owner: context.repo.owner,
274+
repo: context.repo.repo,
275+
issue_number: context.issue.number,
276+
labels: ['checks-passed']
277+
});
278+
} catch (error) {
279+
console.log('Failed to add checks-passed label:', error.message);
280+
console.log('This may be due to insufficient permissions. The label needs to be added manually.');
281+
}
282+
}

0 commit comments

Comments
 (0)