feat(infra): add pre-commit checks and linting
- Add pre-commit script with frontend and backend checks - Add golangci-lint configuration - Add pre-commit-checks cursor rule - Update frontend note handling and linking - Improve backend note functionality and tests - Moved build.sh to scripts directory
This commit is contained in:
parent
9b54537d9e
commit
26bfc9c5d6
14 changed files with 408 additions and 76 deletions
62
.cursor/rules/pre-commit-checks.mdc
Normal file
62
.cursor/rules/pre-commit-checks.mdc
Normal file
|
@ -0,0 +1,62 @@
|
|||
---
|
||||
description: Always run pre-commit checks before committing changes
|
||||
globs: **/*
|
||||
---
|
||||
<rule>
|
||||
Before committing changes:
|
||||
|
||||
1. Run pre-commit checks:
|
||||
```bash
|
||||
./scripts/pre-commit.sh
|
||||
```
|
||||
|
||||
2. Frontend checks must pass:
|
||||
- Code formatting (bun format)
|
||||
- Linting (bun lint)
|
||||
- Type checking (bun check)
|
||||
- Build verification (bun run build)
|
||||
|
||||
3. Backend checks must pass:
|
||||
- Go tests (go test -v ./...)
|
||||
- Go linting (golangci-lint run)
|
||||
|
||||
4. All checks must pass before committing:
|
||||
- Fix any formatting issues
|
||||
- Address all linting errors
|
||||
- Fix type errors
|
||||
- Fix failing tests
|
||||
- Fix build errors
|
||||
|
||||
5. Do not bypass checks:
|
||||
- Never use git commit --no-verify
|
||||
- Fix issues rather than skipping checks
|
||||
- Keep the codebase clean and consistent
|
||||
|
||||
metadata:
|
||||
priority: high
|
||||
version: 1.0
|
||||
</rule>
|
||||
|
||||
examples:
|
||||
- input: |
|
||||
# Bad: Bypassing checks
|
||||
git commit --no-verify -m "quick fix"
|
||||
output: |
|
||||
# Good: Run checks and fix issues
|
||||
./scripts/pre-commit.sh
|
||||
# Fix any issues
|
||||
git add .
|
||||
git commit -m "fix: resolve linting issues"
|
||||
|
||||
- input: |
|
||||
# Bad: Ignoring failing checks
|
||||
# Checks failed but commit anyway
|
||||
output: |
|
||||
# Good: Address all issues
|
||||
./scripts/pre-commit.sh
|
||||
# Fix frontend formatting
|
||||
bun format
|
||||
# Fix Go lint issues
|
||||
# Fix failing tests
|
||||
./scripts/pre-commit.sh # Run again to verify
|
||||
git commit
|
27
.golangci.yml
Normal file
27
.golangci.yml
Normal file
|
@ -0,0 +1,27 @@
|
|||
linters:
|
||||
enable:
|
||||
- gofmt
|
||||
- govet
|
||||
- gosimple
|
||||
- staticcheck
|
||||
- unused
|
||||
- misspell
|
||||
- goimports
|
||||
- ineffassign
|
||||
- gocritic
|
||||
- errcheck
|
||||
|
||||
run:
|
||||
deadline: 5m
|
||||
tests: true
|
||||
|
||||
issues:
|
||||
exclude-use-default: false
|
||||
max-issues-per-linter: 0
|
||||
max-same-issues: 0
|
||||
|
||||
output:
|
||||
formats:
|
||||
- format: colored-line-number
|
||||
print-issued-lines: true
|
||||
print-linter-name: true
|
|
@ -53,8 +53,10 @@ function createNotesStore() {
|
|||
createdNote.createdAt = new Date(createdNote.createdAt);
|
||||
createdNote.updatedAt = new Date(createdNote.updatedAt);
|
||||
|
||||
// Update local store with the server response
|
||||
innerUpdate((notes) => [...notes, createdNote]);
|
||||
// Reload all notes to get updated link information
|
||||
await notes.load();
|
||||
|
||||
return createdNote;
|
||||
},
|
||||
update: async (id: string, content: Partial<Note>) => {
|
||||
const response = await fetch(`/api/notes/${id}`, {
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
import { page } from '$app/stores';
|
||||
import { goto } from '$app/navigation';
|
||||
import { renderMarkdown } from '$lib/markdown';
|
||||
import Navigation from '$lib/components/Navigation.svelte';
|
||||
|
||||
interface Note {
|
||||
id: string;
|
||||
|
@ -44,77 +45,93 @@
|
|||
content: editedContent
|
||||
});
|
||||
isEditing = false;
|
||||
// Reload all notes to get updated link information
|
||||
await notes.load();
|
||||
} catch (error) {
|
||||
console.error('Failed to update note:', error);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<Navigation />
|
||||
|
||||
{#if note}
|
||||
<div class="container">
|
||||
{#if isEditing}
|
||||
<div class="field">
|
||||
<div class="control">
|
||||
<input
|
||||
class="input is-large"
|
||||
type="text"
|
||||
placeholder="Note Title"
|
||||
bind:value={editedTitle}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="field">
|
||||
<div class="control">
|
||||
<textarea class="textarea" placeholder="Note Content" rows="20" bind:value={editedContent}
|
||||
></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="field is-grouped">
|
||||
<div class="control">
|
||||
<button class="button is-primary" onclick={handleSave}>Save</button>
|
||||
</div>
|
||||
<div class="control">
|
||||
<button class="button" onclick={() => (isEditing = false)}>Cancel</button>
|
||||
</div>
|
||||
</div>
|
||||
{:else}
|
||||
<div class="content">
|
||||
<h1 class="title">{note.title}</h1>
|
||||
{#await renderMarkdown(note.content, note.linksTo || [])}
|
||||
<p>Loading...</p>
|
||||
{:then html}
|
||||
<!-- eslint-disable-next-line svelte/no-at-html-tags -->
|
||||
{@html html}
|
||||
{/await}
|
||||
<div class="field is-grouped mt-4">
|
||||
<div class="control">
|
||||
<button class="button is-primary" onclick={() => (isEditing = true)}>Edit</button>
|
||||
<section class="section">
|
||||
<div class="level">
|
||||
<div class="level-left">
|
||||
<div class="level-item">
|
||||
<h1 class="title">{note.title}</h1>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
{#if (note.linksTo || []).length > 0}
|
||||
<div class="box mt-4">
|
||||
<h2 class="title is-5">Links to:</h2>
|
||||
<div class="tags">
|
||||
{#each note.linksTo || [] as link}
|
||||
<a href="/notes/{link.id}" class="tag is-link">{link.title}</a>
|
||||
{/each}
|
||||
{#if isEditing}
|
||||
<div class="field">
|
||||
<div class="control">
|
||||
<input
|
||||
class="input is-large"
|
||||
type="text"
|
||||
placeholder="Note Title"
|
||||
bind:value={editedTitle}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
{#if (note.linkedBy || []).length > 0}
|
||||
<div class="box mt-4">
|
||||
<h2 class="title is-5">Referenced by:</h2>
|
||||
<div class="tags">
|
||||
{#each note.linkedBy || [] as link}
|
||||
<a href="/notes/{link.id}" class="tag is-info">{link.title}</a>
|
||||
{/each}
|
||||
<div class="field">
|
||||
<div class="control">
|
||||
<textarea
|
||||
class="textarea"
|
||||
placeholder="Note Content"
|
||||
rows="20"
|
||||
bind:value={editedContent}
|
||||
></textarea>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
<div class="field is-grouped">
|
||||
<div class="control">
|
||||
<button class="button is-primary" onclick={handleSave}>Save</button>
|
||||
</div>
|
||||
<div class="control">
|
||||
<button class="button" onclick={() => (isEditing = false)}>Cancel</button>
|
||||
</div>
|
||||
</div>
|
||||
{:else}
|
||||
<div class="content">
|
||||
{#await renderMarkdown(note.content, note.linksTo || [])}
|
||||
<p>Loading...</p>
|
||||
{:then html}
|
||||
<!-- eslint-disable-next-line svelte/no-at-html-tags -->
|
||||
{@html html}
|
||||
{/await}
|
||||
<div class="field is-grouped mt-4">
|
||||
<div class="control">
|
||||
<button class="button is-primary" onclick={() => (isEditing = true)}>Edit</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
{#if (note.linksTo || []).length > 0}
|
||||
<div class="box mt-4">
|
||||
<h2 class="title is-5">Links to:</h2>
|
||||
<div class="tags">
|
||||
{#each note.linksTo || [] as link}
|
||||
<a href="/notes/{link.id}" class="tag is-link">{link.title}</a>
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
{#if (note.linkedBy || []).length > 0}
|
||||
<div class="box mt-4">
|
||||
<h2 class="title is-5">Referenced by:</h2>
|
||||
<div class="tags">
|
||||
{#each note.linkedBy || [] as link}
|
||||
<a href="/notes/{link.id}" class="tag is-info">{link.title}</a>
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
</section>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
<script lang="ts">
|
||||
import { preventDefault } from 'svelte/legacy';
|
||||
|
||||
import { notes } from '$lib';
|
||||
import { goto } from '$app/navigation';
|
||||
import Navigation from '$lib/components/Navigation.svelte';
|
||||
let { data } = $props();
|
||||
|
||||
let title = $state(data.props.prefilledTitle);
|
||||
|
@ -12,20 +12,29 @@
|
|||
if (!title || !content) return;
|
||||
|
||||
try {
|
||||
await notes.add({
|
||||
const createdNote = await notes.add({
|
||||
title,
|
||||
content
|
||||
});
|
||||
goto('/');
|
||||
goto(`/notes/${createdNote.id}`);
|
||||
} catch (error) {
|
||||
console.error('Failed to create note:', error);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<Navigation />
|
||||
|
||||
<div class="container">
|
||||
<section class="section">
|
||||
<h1 class="title">New Note</h1>
|
||||
<div class="level">
|
||||
<div class="level-left">
|
||||
<div class="level-item">
|
||||
<h1 class="title">New Note</h1>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<form onsubmit={preventDefault(handleSave)}>
|
||||
<div class="field">
|
||||
<label class="label" for="title">Title</label>
|
||||
|
|
5
main.go
5
main.go
|
@ -90,6 +90,11 @@ func main() {
|
|||
// Create Gin router
|
||||
r := gin.Default()
|
||||
|
||||
// Trust only loopback addresses
|
||||
if err := r.SetTrustedProxies([]string{"127.0.0.1", "::1"}); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
// API routes
|
||||
api := r.Group("/api")
|
||||
{
|
||||
|
|
|
@ -16,8 +16,8 @@ type Note struct {
|
|||
CreatedAt time.Time `json:"createdAt"`
|
||||
UpdatedAt time.Time `json:"updatedAt"`
|
||||
// Link relationships
|
||||
LinksTo []*Note `json:"linksTo,omitempty" gorm:"many2many:note_links;joinForeignKey:source_note_id;joinReferences:target_note_id"`
|
||||
LinkedBy []*Note `json:"linkedBy,omitempty" gorm:"many2many:note_links;joinForeignKey:target_note_id;joinReferences:source_note_id"`
|
||||
LinksTo []*Note `json:"linksTo,omitempty" gorm:"many2many:note_links;joinForeignKey:source_note_id;joinReferences:target_note_id"`
|
||||
LinkedBy []*Note `json:"linkedBy,omitempty" gorm:"many2many:note_links;joinForeignKey:target_note_id;joinReferences:source_note_id"`
|
||||
}
|
||||
|
||||
// NoteLink represents a connection between two notes
|
||||
|
@ -69,4 +69,4 @@ func (n *Note) UpdateLinks(db *gorm.DB) error {
|
|||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
|
|
@ -183,4 +183,4 @@ func TestUpdateLinks(t *testing.T) {
|
|||
t.Errorf("Expected 1 link, got %d", len(links))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -120,4 +120,4 @@ func (h *Handler) handleReset(c *gin.Context) {
|
|||
return
|
||||
}
|
||||
c.Status(http.StatusOK)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -229,4 +229,4 @@ func TestHandler_ResetNotes(t *testing.T) {
|
|||
if len(response) != 0 {
|
||||
t.Errorf("Expected empty notes list, got %d notes", len(response))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,11 +27,23 @@ func (s *Service) Create(note *Note) error {
|
|||
return fmt.Errorf("failed to create note: %w", err)
|
||||
}
|
||||
|
||||
// Update links
|
||||
// Update links in this note
|
||||
if err := note.UpdateLinks(tx); err != nil {
|
||||
return fmt.Errorf("failed to update note links: %w", err)
|
||||
}
|
||||
|
||||
// Find and update notes that link to this note's title
|
||||
var notesToUpdate []Note
|
||||
if err := tx.Where("content LIKE ?", "%[["+note.Title+"]]%").Find(¬esToUpdate).Error; err != nil {
|
||||
return fmt.Errorf("failed to find notes linking to %q: %w", note.Title, err)
|
||||
}
|
||||
|
||||
for _, n := range notesToUpdate {
|
||||
if err := n.UpdateLinks(tx); err != nil {
|
||||
return fmt.Errorf("failed to update links in note %q: %w", n.Title, err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
|
@ -50,7 +62,14 @@ func (s *Service) Create(note *Note) error {
|
|||
// Get retrieves a note by ID
|
||||
func (s *Service) Get(id string) (*Note, error) {
|
||||
var note Note
|
||||
if err := s.db.Preload("LinksTo").Preload("LinkedBy").First(¬e, "id = ?", id).Error; err != nil {
|
||||
if err := s.db.
|
||||
Preload("LinksTo", func(db *gorm.DB) *gorm.DB {
|
||||
return db.Select("id", "title")
|
||||
}).
|
||||
Preload("LinkedBy", func(db *gorm.DB) *gorm.DB {
|
||||
return db.Select("id", "title")
|
||||
}).
|
||||
First(¬e, "id = ?", id).Error; err != nil {
|
||||
if err == gorm.ErrRecordNotFound {
|
||||
return nil, nil
|
||||
}
|
||||
|
@ -62,7 +81,15 @@ func (s *Service) Get(id string) (*Note, error) {
|
|||
// List retrieves all notes
|
||||
func (s *Service) List() ([]Note, error) {
|
||||
var notes []Note
|
||||
if err := s.db.Preload("LinksTo").Order("updated_at desc").Find(¬es).Error; err != nil {
|
||||
if err := s.db.
|
||||
Preload("LinksTo", func(db *gorm.DB) *gorm.DB {
|
||||
return db.Select("id", "title")
|
||||
}).
|
||||
Preload("LinkedBy", func(db *gorm.DB) *gorm.DB {
|
||||
return db.Select("id", "title")
|
||||
}).
|
||||
Order("updated_at desc").
|
||||
Find(¬es).Error; err != nil {
|
||||
return nil, fmt.Errorf("failed to list notes: %w", err)
|
||||
}
|
||||
return notes, nil
|
||||
|
@ -105,4 +132,4 @@ func (s *Service) Reset() error {
|
|||
return fmt.Errorf("failed to reset notes: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
|
|
@ -57,6 +57,25 @@ func TestService_Create(t *testing.T) {
|
|||
if len(updated.LinksTo) != 1 {
|
||||
t.Errorf("Expected 1 link, got %d", len(updated.LinksTo))
|
||||
}
|
||||
|
||||
// Verify that linked note only contains id and title
|
||||
if link := updated.LinksTo[0]; link != nil {
|
||||
if link.Content != "" {
|
||||
t.Error("Link should not include content")
|
||||
}
|
||||
if link.ID == "" {
|
||||
t.Error("Link should include ID")
|
||||
}
|
||||
if link.Title == "" {
|
||||
t.Error("Link should include Title")
|
||||
}
|
||||
if !link.CreatedAt.IsZero() {
|
||||
t.Error("Link should not include CreatedAt")
|
||||
}
|
||||
if !link.UpdatedAt.IsZero() {
|
||||
t.Error("Link should not include UpdatedAt")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestService_Get(t *testing.T) {
|
||||
|
@ -83,6 +102,18 @@ func TestService_Get(t *testing.T) {
|
|||
t.Fatalf("Failed to create note: %v", err)
|
||||
}
|
||||
|
||||
// Create another note that links to the first one
|
||||
linking := &Note{
|
||||
Title: "Linking Note",
|
||||
Content: "Links to [[Test Note]]",
|
||||
CreatedAt: time.Now(),
|
||||
UpdatedAt: time.Now(),
|
||||
}
|
||||
if err := service.Create(linking); err != nil {
|
||||
t.Fatalf("Failed to create linking note: %v", err)
|
||||
}
|
||||
|
||||
// Get the first note and verify relationships
|
||||
note, err = service.Get(created.ID)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to get note: %v", err)
|
||||
|
@ -90,9 +121,35 @@ func TestService_Get(t *testing.T) {
|
|||
if note == nil {
|
||||
t.Fatal("Expected note, got nil")
|
||||
}
|
||||
|
||||
// Verify basic fields
|
||||
if note.Title != created.Title {
|
||||
t.Errorf("Expected title %q, got %q", created.Title, note.Title)
|
||||
}
|
||||
|
||||
// Verify LinkedBy relationship
|
||||
if len(note.LinkedBy) != 1 {
|
||||
t.Errorf("Expected 1 LinkedBy relationship, got %d", len(note.LinkedBy))
|
||||
}
|
||||
|
||||
// Verify that linking note only contains id and title
|
||||
if link := note.LinkedBy[0]; link != nil {
|
||||
if link.Content != "" {
|
||||
t.Error("LinkedBy should not include content")
|
||||
}
|
||||
if link.ID == "" {
|
||||
t.Error("LinkedBy should include ID")
|
||||
}
|
||||
if link.Title == "" {
|
||||
t.Error("LinkedBy should include Title")
|
||||
}
|
||||
if !link.CreatedAt.IsZero() {
|
||||
t.Error("LinkedBy should not include CreatedAt")
|
||||
}
|
||||
if !link.UpdatedAt.IsZero() {
|
||||
t.Error("LinkedBy should not include UpdatedAt")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestService_List(t *testing.T) {
|
||||
|
@ -117,7 +174,7 @@ func TestService_List(t *testing.T) {
|
|||
}
|
||||
note2 := &Note{
|
||||
Title: "Second Note",
|
||||
Content: "Second content",
|
||||
Content: "Second content with [[First Note]]",
|
||||
CreatedAt: time.Now(),
|
||||
UpdatedAt: time.Now().Add(time.Hour), // Later update time
|
||||
}
|
||||
|
@ -142,6 +199,55 @@ func TestService_List(t *testing.T) {
|
|||
if notes[0].ID != note2.ID {
|
||||
t.Error("Notes not ordered by updated_at desc")
|
||||
}
|
||||
|
||||
// Verify relationships
|
||||
firstNote := notes[1] // note1 should be second due to update time
|
||||
if len(firstNote.LinkedBy) != 1 {
|
||||
t.Errorf("Expected First Note to have 1 LinkedBy, got %d", len(firstNote.LinkedBy))
|
||||
}
|
||||
|
||||
// Verify that linking note only contains id and title
|
||||
if link := firstNote.LinkedBy[0]; link != nil {
|
||||
if link.Content != "" {
|
||||
t.Error("LinkedBy should not include content")
|
||||
}
|
||||
if link.ID == "" {
|
||||
t.Error("LinkedBy should include ID")
|
||||
}
|
||||
if link.Title == "" {
|
||||
t.Error("LinkedBy should include Title")
|
||||
}
|
||||
if !link.CreatedAt.IsZero() {
|
||||
t.Error("LinkedBy should not include CreatedAt")
|
||||
}
|
||||
if !link.UpdatedAt.IsZero() {
|
||||
t.Error("LinkedBy should not include UpdatedAt")
|
||||
}
|
||||
}
|
||||
|
||||
secondNote := notes[0] // note2 should be first due to update time
|
||||
if len(secondNote.LinksTo) != 1 {
|
||||
t.Errorf("Expected Second Note to have 1 LinksTo, got %d", len(secondNote.LinksTo))
|
||||
}
|
||||
|
||||
// Verify that linked note only contains id and title
|
||||
if link := secondNote.LinksTo[0]; link != nil {
|
||||
if link.Content != "" {
|
||||
t.Error("LinksTo should not include content")
|
||||
}
|
||||
if link.ID == "" {
|
||||
t.Error("LinksTo should include ID")
|
||||
}
|
||||
if link.Title == "" {
|
||||
t.Error("LinksTo should include Title")
|
||||
}
|
||||
if !link.CreatedAt.IsZero() {
|
||||
t.Error("LinksTo should not include CreatedAt")
|
||||
}
|
||||
if !link.UpdatedAt.IsZero() {
|
||||
t.Error("LinksTo should not include UpdatedAt")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestService_Delete(t *testing.T) {
|
||||
|
@ -212,4 +318,4 @@ func TestService_Reset(t *testing.T) {
|
|||
if len(notes) != 0 {
|
||||
t.Errorf("Expected empty database after reset, got %d notes", len(notes))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
77
scripts/pre-commit.sh
Executable file
77
scripts/pre-commit.sh
Executable file
|
@ -0,0 +1,77 @@
|
|||
#!/bin/bash
|
||||
set -euo pipefail
|
||||
|
||||
# Find commands and set up environment
|
||||
if command -v bun >/dev/null 2>&1; then
|
||||
BUN_CMD="bun"
|
||||
else
|
||||
BUN_CMD="$HOME/.bun/bin/bun"
|
||||
fi
|
||||
|
||||
# Set up Go environment
|
||||
if command -v go >/dev/null 2>&1; then
|
||||
GO_CMD="go"
|
||||
GOROOT=$(go env GOROOT)
|
||||
else
|
||||
GO_CMD="/usr/local/go/bin/go"
|
||||
GOROOT="/usr/local/go"
|
||||
fi
|
||||
export GOROOT
|
||||
export PATH="$GOROOT/bin:$PATH"
|
||||
|
||||
if command -v golangci-lint >/dev/null 2>&1; then
|
||||
GOLINT_CMD="golangci-lint"
|
||||
else
|
||||
GOLINT_CMD="$HOME/go/bin/golangci-lint"
|
||||
fi
|
||||
|
||||
# Colors for output
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
echo "Running pre-commit checks..."
|
||||
|
||||
# Frontend checks
|
||||
echo -e "\n${GREEN}Running frontend checks...${NC}"
|
||||
pushd frontend
|
||||
|
||||
echo -e "\n${GREEN}Running formatter...${NC}"
|
||||
$BUN_CMD format || {
|
||||
echo -e "${RED}Frontend formatting failed!${NC}"
|
||||
exit 1
|
||||
}
|
||||
|
||||
echo -e "\n${GREEN}Running linter...${NC}"
|
||||
$BUN_CMD lint || {
|
||||
echo -e "${RED}Frontend linting failed!${NC}"
|
||||
exit 1
|
||||
}
|
||||
|
||||
echo -e "\n${GREEN}Running type checker...${NC}"
|
||||
$BUN_CMD check || {
|
||||
echo -e "${RED}Frontend type checking failed!${NC}"
|
||||
exit 1
|
||||
}
|
||||
|
||||
echo -e "\n${GREEN}Building frontend...${NC}"
|
||||
$BUN_CMD run build || {
|
||||
echo -e "${RED}Frontend build failed!${NC}"
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Backend checks
|
||||
popd
|
||||
echo -e "\n${GREEN}Running backend tests...${NC}"
|
||||
$GO_CMD test -v ./... || {
|
||||
echo -e "${RED}Backend tests failed!${NC}"
|
||||
exit 1
|
||||
}
|
||||
|
||||
echo -e "\n${GREEN}Running Go linter...${NC}"
|
||||
$GOLINT_CMD run || {
|
||||
echo -e "${RED}Go linting failed!${NC}"
|
||||
exit 1
|
||||
}
|
||||
|
||||
echo -e "\n${GREEN}All checks passed!${NC}"
|
Loading…
Add table
Reference in a new issue