diff --git a/.forgejo/workflows/format.yaml b/.forgejo/workflows/format-lint-test.yaml
similarity index 60%
rename from .forgejo/workflows/format.yaml
rename to .forgejo/workflows/format-lint-test.yaml
index f6289ac..e87c328 100644
--- a/.forgejo/workflows/format.yaml
+++ b/.forgejo/workflows/format-lint-test.yaml
@@ -23,3 +23,19 @@ jobs:
- name: Run Format Check
run: |
make format
+
+ test:
+ runs-on: docker
+
+ steps:
+ - name: Checkout Code
+ uses: actions/checkout@v4
+
+ - name: Setup Go
+ uses: actions/setup-go@v5
+ with:
+ go-version: '1.23.3'
+
+ - name: Run Tests
+ run: |
+ make test-coverage
diff --git a/Makefile b/Makefile
index 818b0c7..2ff2e4a 100644
--- a/Makefile
+++ b/Makefile
@@ -38,3 +38,6 @@ build-docker:
-t ghcr.io/aides-infra/aides-repo-api:${DOCKER_TAG}\
.
+test-coverage:
+ go test ./... -v -coverpkg=./... -coverprofile=coverage.out
+ bash scripts/coverage-badge.sh
diff --git a/README.md b/README.md
index 6224fdb..ec3df60 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,5 @@
# Aides repo API
-[![Go Report Card](https://goreportcard.com/badge/code.alt-gnome.ru/aides-infra/aides-repo-api)](https://goreportcard.com/report/code.alt-gnome.ru/aides-infra/aides-repo-api)
\ No newline at end of file
+[![Go Report Card](https://goreportcard.com/badge/code.alt-gnome.ru/aides-infra/aides-repo-api)](https://goreportcard.com/report/code.alt-gnome.ru/aides-infra/aides-repo-api)
+
+![Coverage](./coverage-badge.svg)
\ No newline at end of file
diff --git a/cmd/aides-repo-api/main.go b/cmd/aides-repo-api/main.go
index 61ce37c..bec75cf 100644
--- a/cmd/aides-repo-api/main.go
+++ b/cmd/aides-repo-api/main.go
@@ -8,13 +8,20 @@ import (
//
// @title Aides Repo API
// @description API For Aides repo
-// @schemes https
+// @schemes http https
//
// @license.name GPL-3.0
// @license.url https://www.gnu.org/licenses/gpl-3.0-standalone.html
//
// @tag.name tasks
// @tag.description Work with tags
+//
+
+// @securityDefinitions.apikey ApiKeyAuth
+// @in header
+// @name Authorization
+// @description Type "Bearer" followed by a space and token.
+
func main() {
app, err := app.New()
if err != nil {
diff --git a/coverage-badge.svg b/coverage-badge.svg
new file mode 100644
index 0000000..f305a5c
--- /dev/null
+++ b/coverage-badge.svg
@@ -0,0 +1,6 @@
+
diff --git a/docs/docs.go b/docs/docs.go
index 8b0bbb7..cff3a83 100644
--- a/docs/docs.go
+++ b/docs/docs.go
@@ -21,6 +21,11 @@ const docTemplate = `{
"paths": {
"/tasks": {
"post": {
+ "security": [
+ {
+ "ApiKeyAuth": []
+ }
+ ],
"description": "Create a new task for a specific repository",
"consumes": [
"application/json"
@@ -67,6 +72,11 @@ const docTemplate = `{
},
"/tasks/{taskID}/upload": {
"post": {
+ "security": [
+ {
+ "ApiKeyAuth": []
+ }
+ ],
"description": "Upload multiple files associated with a specific task ID. Each file must be less than 10MB.",
"consumes": [
"multipart/form-data"
@@ -190,6 +200,14 @@ const docTemplate = `{
}
}
},
+ "securityDefinitions": {
+ "ApiKeyAuth": {
+ "description": "Type \"Bearer\" followed by a space and token.",
+ "type": "apiKey",
+ "name": "Authorization",
+ "in": "header"
+ }
+ },
"tags": [
{
"description": "Work with tags",
@@ -203,7 +221,7 @@ var SwaggerInfo = &swag.Spec{
Version: "",
Host: "",
BasePath: "",
- Schemes: []string{"https"},
+ Schemes: []string{"http", "https"},
Title: "Aides Repo API",
Description: "API For Aides repo",
InfoInstanceName: "swagger",
diff --git a/docs/swagger.json b/docs/swagger.json
index 7c89391..385c2a0 100644
--- a/docs/swagger.json
+++ b/docs/swagger.json
@@ -1,5 +1,6 @@
{
"schemes": [
+ "http",
"https"
],
"swagger": "2.0",
@@ -15,6 +16,11 @@
"paths": {
"/tasks": {
"post": {
+ "security": [
+ {
+ "ApiKeyAuth": []
+ }
+ ],
"description": "Create a new task for a specific repository",
"consumes": [
"application/json"
@@ -61,6 +67,11 @@
},
"/tasks/{taskID}/upload": {
"post": {
+ "security": [
+ {
+ "ApiKeyAuth": []
+ }
+ ],
"description": "Upload multiple files associated with a specific task ID. Each file must be less than 10MB.",
"consumes": [
"multipart/form-data"
@@ -184,6 +195,14 @@
}
}
},
+ "securityDefinitions": {
+ "ApiKeyAuth": {
+ "description": "Type \"Bearer\" followed by a space and token.",
+ "type": "apiKey",
+ "name": "Authorization",
+ "in": "header"
+ }
+ },
"tags": [
{
"description": "Work with tags",
diff --git a/docs/swagger.yaml b/docs/swagger.yaml
index 77ebdd3..82675ff 100644
--- a/docs/swagger.yaml
+++ b/docs/swagger.yaml
@@ -85,6 +85,8 @@ paths:
description: Internal server error
schema:
$ref: '#/definitions/errors.ErrResponse'
+ security:
+ - ApiKeyAuth: []
summary: Create a new task
tags:
- tasks
@@ -120,11 +122,20 @@ paths:
description: Internal Server Error
schema:
$ref: '#/definitions/errors.ErrResponse'
+ security:
+ - ApiKeyAuth: []
summary: Upload files to a task
tags:
- tasks
schemes:
+- http
- https
+securityDefinitions:
+ ApiKeyAuth:
+ description: Type "Bearer" followed by a space and token.
+ in: header
+ name: Authorization
+ type: apiKey
swagger: "2.0"
tags:
- description: Work with tags
diff --git a/go.mod b/go.mod
index 0fde56f..ee88673 100644
--- a/go.mod
+++ b/go.mod
@@ -4,16 +4,21 @@ go 1.23.3
require (
github.com/caarlos0/env/v11 v11.2.2
+ github.com/cavaliergopher/rpm v1.2.0
github.com/go-chi/chi/v5 v5.1.0
github.com/go-chi/render v1.0.3
+ github.com/stretchr/testify v1.10.0
+)
+
+require (
+ github.com/davecgh/go-spew v1.1.1 // indirect
+ github.com/pmezard/go-difflib v1.0.0 // indirect
)
require (
github.com/KyleBanks/depth v1.2.1 // indirect
- github.com/PuerkitoBio/purell v1.2.1 // indirect
- github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect
github.com/ajg/form v1.5.1 // indirect
- github.com/go-co-op/gocron/v2 v2.13.0 // indirect
+ github.com/go-co-op/gocron/v2 v2.13.0
github.com/go-openapi/jsonpointer v0.21.0 // indirect
github.com/go-openapi/jsonreference v0.21.0 // indirect
github.com/go-openapi/spec v0.21.0 // indirect
@@ -31,20 +36,19 @@ require (
github.com/mattn/go-sqlite3 v1.14.24 // indirect
github.com/robfig/cron/v3 v3.0.1 // indirect
github.com/swaggo/files v1.0.1 // indirect
- github.com/swaggo/http-swagger v1.3.4 // indirect
- github.com/swaggo/swag v1.16.4 // indirect
+ github.com/swaggo/http-swagger v1.3.4
+ github.com/swaggo/swag v1.16.4
go.uber.org/multierr v1.11.0 // indirect
- go.uber.org/zap v1.27.0 // indirect
+ go.uber.org/zap v1.27.0
golang.org/x/crypto v0.31.0 // indirect
golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8 // indirect
golang.org/x/net v0.32.0 // indirect
golang.org/x/sync v0.10.0 // indirect
golang.org/x/text v0.21.0 // indirect
golang.org/x/tools v0.28.0 // indirect
- gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
- gorm.io/driver/postgres v1.5.11 // indirect
- gorm.io/driver/sqlite v1.5.7 // indirect
- gorm.io/gorm v1.25.12 // indirect
+ gorm.io/driver/postgres v1.5.11
+ gorm.io/driver/sqlite v1.5.7
+ gorm.io/gorm v1.25.12
moul.io/zapgorm2 v1.3.0
)
diff --git a/go.sum b/go.sum
index 95b2111..ec51ca0 100644
--- a/go.sum
+++ b/go.sum
@@ -1,15 +1,14 @@
github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc=
github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE=
-github.com/PuerkitoBio/purell v1.2.1 h1:QsZ4TjvwiMpat6gBCBxEQI0rcS9ehtkKtSpiUnd9N28=
-github.com/PuerkitoBio/purell v1.2.1/go.mod h1:ZwHcC/82TOaovDi//J/804umJFFmbOHPngi8iYYv/Eo=
-github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M=
-github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
github.com/ajg/form v1.5.1 h1:t9c7v8JUKu/XxOGBU0yjNpaMloxGEJhUkqFRq0ibGeU=
github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY=
github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
github.com/caarlos0/env/v11 v11.2.2 h1:95fApNrUyueipoZN/EhA8mMxiNxrBwDa+oAZrMWl3Kg=
github.com/caarlos0/env/v11 v11.2.2/go.mod h1:JBfcdeQiBoI3Zh1QRAWfe+tpiNTmDtcCj/hHHHMx0vc=
+github.com/cavaliergopher/rpm v1.2.0 h1:s0h+QeVK252QFTolkhGiMeQ1f+tMeIMhGl8B1HUmGUc=
+github.com/cavaliergopher/rpm v1.2.0/go.mod h1:R0q3vTqa7RUvPofAZYrnjJ63hh2vngjFfphuXiExVos=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/go-chi/chi/v5 v5.1.0 h1:acVI1TYaD+hhedDJ3r54HyA6sExp3HfXq7QWEEY/xMw=
github.com/go-chi/chi/v5 v5.1.0/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
@@ -45,20 +44,28 @@ github.com/jonboulle/clockwork v0.4.0/go.mod h1:xgRqUGwRcjKCO1vbZUEtSLrqKoPSsUpK
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
+github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
+github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
+github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
github.com/mattn/go-sqlite3 v1.14.24 h1:tpSp2G2KyMnnQu99ngJ47EIkWVmliIizyZBfPrBWDRM=
github.com/mattn/go-sqlite3 v1.14.24/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs=
github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
+github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M=
+github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
+github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/swaggo/files v1.0.1 h1:J1bVJ4XHZNq0I46UU90611i9/YzdrF7x92oX1ig5IdE=
github.com/swaggo/files v1.0.1/go.mod h1:0qXmMNH6sXNf+73t65aKeB+ApmgxdnkQzVTAj2uaMUg=
github.com/swaggo/http-swagger v1.3.4 h1:q7t/XLx0n15H1Q9/tk3Y9L4n210XzJF5WtnDX64a5ww=
@@ -69,6 +76,8 @@ github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ=
+go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
+go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
go.uber.org/multierr v1.7.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak=
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
@@ -86,6 +95,8 @@ golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8/go.mod h1:jj3sYF3dwk5D+ghuXy
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
+golang.org/x/mod v0.22.0 h1:D4nJWe9zXqHOmWqj4VMOJhvzj7bEZg4wEYa759z1pH4=
+golang.org/x/mod v0.22.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
@@ -130,9 +141,9 @@ golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8T
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
+gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
-gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
-gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
diff --git a/internal/controllers/taskcontroller/create.go b/internal/controllers/taskcontroller/create.go
index baad0b8..25324fa 100644
--- a/internal/controllers/taskcontroller/create.go
+++ b/internal/controllers/taskcontroller/create.go
@@ -28,6 +28,7 @@ func (c *CreateTaskResponse) Render(w http.ResponseWriter, r *http.Request) erro
// @Summary Create a new task
// @Description Create a new task for a specific repository
// @Tags tasks
+// @Security ApiKeyAuth
// @Accept json
// @Produce json
// @Param body body CreateTaskDTO true "Request body to create a task"
diff --git a/internal/controllers/taskcontroller/upload.go b/internal/controllers/taskcontroller/upload.go
index 7d4c2eb..e6c8a86 100644
--- a/internal/controllers/taskcontroller/upload.go
+++ b/internal/controllers/taskcontroller/upload.go
@@ -1,12 +1,14 @@
package taskcontroller
import (
+ "errors"
"net/http"
"github.com/go-chi/chi/v5"
"github.com/go-chi/render"
- "code.alt-gnome.ru/aides-infra/aides-repo-api/internal/common/errors"
+ commonErrors "code.alt-gnome.ru/aides-infra/aides-repo-api/internal/common/errors"
+
"code.alt-gnome.ru/aides-infra/aides-repo-api/internal/logger"
"code.alt-gnome.ru/aides-infra/aides-repo-api/internal/services/taskservice"
)
@@ -25,6 +27,7 @@ func (rd *TaskUploadResponse) Render(w http.ResponseWriter, r *http.Request) err
// @Summary Upload files to a task
// @Description Upload multiple files associated with a specific task ID. Each file must be less than 10MB.
// @Tags tasks
+// @Security ApiKeyAuth
// @Accept multipart/form-data
// @Produce json
// @Param taskID path string true "Task ID"
@@ -36,7 +39,7 @@ func (rd *TaskUploadResponse) Render(w http.ResponseWriter, r *http.Request) err
func (c *TaskController) Upload(w http.ResponseWriter, r *http.Request) {
taskID := chi.URLParam(r, "taskID")
if taskID == "" {
- render.Render(w, r, &errors.ErrResponse{
+ render.Render(w, r, &commonErrors.ErrResponse{
HTTPStatusCode: http.StatusBadRequest,
StatusText: "taskID is required",
})
@@ -45,7 +48,7 @@ func (c *TaskController) Upload(w http.ResponseWriter, r *http.Request) {
err := r.ParseMultipartForm(10240 << 20)
if err != nil {
- render.Render(w, r, &errors.ErrResponse{
+ render.Render(w, r, &commonErrors.ErrResponse{
HTTPStatusCode: http.StatusBadRequest,
StatusText: "Bad Request",
})
@@ -55,7 +58,7 @@ func (c *TaskController) Upload(w http.ResponseWriter, r *http.Request) {
files := r.MultipartForm.File["files"]
for _, fileHeader := range files {
if fileHeader.Size > (1024 << 20) {
- render.Render(w, r, &errors.ErrResponse{
+ render.Render(w, r, &commonErrors.ErrResponse{
HTTPStatusCode: http.StatusBadRequest,
StatusText: "File too large",
})
@@ -72,7 +75,18 @@ func (c *TaskController) Upload(w http.ResponseWriter, r *http.Request) {
log.Error("Error while upload task", map[string]interface{}{
"err": err,
})
- render.Render(w, r, &errors.ErrResponse{
+
+ var e *taskservice.TooOldError
+ if errors.As(err, &e) {
+ render.Render(w, r, &commonErrors.ErrResponse{
+ HTTPStatusCode: http.StatusBadRequest,
+ StatusText: err.Error(),
+ Err: err,
+ })
+ return
+ }
+
+ render.Render(w, r, &commonErrors.ErrResponse{
HTTPStatusCode: http.StatusInternalServerError,
StatusText: "Internal Server Error",
Err: err,
@@ -86,7 +100,7 @@ func (c *TaskController) Upload(w http.ResponseWriter, r *http.Request) {
}
if err := render.Render(w, r, &response); err != nil {
- render.Render(w, r, errors.ErrRender(err))
+ render.Render(w, r, commonErrors.ErrRender(err))
return
}
}
diff --git a/internal/models/db.go b/internal/models/db.go
index 0def57a..950a1f9 100644
--- a/internal/models/db.go
+++ b/internal/models/db.go
@@ -22,8 +22,13 @@ type RPMFile struct {
TaskID int
Task Task
- Name string
- Arch string
+ Filename string
+
+ Name string
+ Arch string
+ Version string
+ Release string
+ Epoch int
}
type TaskStatus int
diff --git a/internal/services/reposervice/service.go b/internal/services/reposervice/service.go
index 0548672..a987dd1 100644
--- a/internal/services/reposervice/service.go
+++ b/internal/services/reposervice/service.go
@@ -123,13 +123,13 @@ func (s *Service) ForceUpdate() error {
for _, el := range tasks {
for _, fileInfo := range el.Files {
localFilePath := path.Join(
- strconv.FormatUint(uint64(el.ID), 10), fileInfo.Name,
+ strconv.FormatUint(uint64(el.ID), 10), fileInfo.Filename,
)
symLink := path.Join(
futureRepoPath,
fileInfo.Arch,
"RPMS.aides",
- fileInfo.Name,
+ fileInfo.Filename,
)
targetPath := path.Join("../../../../tasks/", localFilePath)
err := createSymlink(targetPath, symLink)
diff --git a/internal/services/taskservice/create.go b/internal/services/taskservice/create.go
index 91d8cef..208e67d 100644
--- a/internal/services/taskservice/create.go
+++ b/internal/services/taskservice/create.go
@@ -23,6 +23,7 @@ func (s *Service) Create(repo string) (*models.Task, error) {
RepoID: taskRepo.ID,
ALTRepo: altRepo,
Type: models.TypeUpsert,
+ Status: models.StatusPending,
}
result := s.db.Create(&task)
diff --git a/internal/services/taskservice/errors.go b/internal/services/taskservice/errors.go
new file mode 100644
index 0000000..e36f74f
--- /dev/null
+++ b/internal/services/taskservice/errors.go
@@ -0,0 +1,11 @@
+package taskservice
+
+import "fmt"
+
+type TooOldError struct {
+ Name string
+}
+
+func (e TooOldError) Error() string {
+ return fmt.Sprintf("%s is too old!", e.Name)
+}
diff --git a/internal/services/taskservice/upload.go b/internal/services/taskservice/upload.go
index 2f27fef..df2efa3 100644
--- a/internal/services/taskservice/upload.go
+++ b/internal/services/taskservice/upload.go
@@ -6,13 +6,14 @@ import (
"io"
"mime/multipart"
"os"
- "os/exec"
"path"
"strconv"
"strings"
+ "github.com/cavaliergopher/rpm"
"gorm.io/gorm"
+ "code.alt-gnome.ru/aides-infra/aides-repo-api/internal/logger"
"code.alt-gnome.ru/aides-infra/aides-repo-api/internal/models"
)
@@ -22,19 +23,9 @@ type TaskUploadInput struct {
Files []*multipart.FileHeader
}
-func getRPMArchitecture(filePath string) (string, error) {
- cmd := exec.Command("rpm", "-qp", "--queryformat", "%{ARCH}", filePath)
-
- output, err := cmd.Output()
- if err != nil {
- return "", fmt.Errorf("ошибка при выполнении команды rpm: %v", err)
- }
-
- arch := strings.TrimSpace(string(output))
- return arch, nil
-}
-
func (s *Service) Upload(input *TaskUploadInput) error {
+ log := logger.GetLogger()
+
taskID, err := strconv.Atoi(input.TaskID)
if err != nil {
return err
@@ -42,12 +33,11 @@ func (s *Service) Upload(input *TaskUploadInput) error {
files := input.Files
task := models.Task{}
- result := s.db.Preload("Repo").Where(
- "id = ?", taskID,
- ).First(&task)
- /*.Where(
- "status = ?", models.StatusPending,
- )*/
+ result := s.db.
+ Preload("Repo").
+ Where("id = ?", taskID).
+ First(&task).
+ Where("status = ?", models.StatusPending)
if errors.Is(result.Error, gorm.ErrRecordNotFound) {
return result.Error
@@ -56,17 +46,45 @@ func (s *Service) Upload(input *TaskUploadInput) error {
return result.Error
}
+ currentTask := &models.Task{}
+ result = s.db.
+ Model(&models.GitRepoAltRepoTask{}).
+ Select("tasks.*").
+ Joins("JOIN tasks ON tasks.id = git_repo_alt_repo_tasks.current_task_id").
+ Where(&models.GitRepoAltRepoTask{
+ ALTRepoID: task.ALTRepoID,
+ RepoID: task.RepoID,
+ }).
+ Preload("Files").
+ Limit(1).
+ Find(currentTask)
+ if result.Error != nil {
+ return result.Error
+ }
+
+ log.Debug("", map[string]interface{}{
+ "val": currentTask,
+ })
+
localPath := path.Join(input.TaskID)
taskFolderPath := path.Join(s.config.GetUploadDir(), "tasks", localPath)
err = os.MkdirAll(taskFolderPath, os.ModePerm)
if err != nil {
return err
}
+ shouldCleanTask := true
+ defer func() {
+ if shouldCleanTask {
+ os.RemoveAll(taskFolderPath)
+ }
+ }()
+
+ rpmFiles := []models.RPMFile{}
for _, fileHeader := range files {
file, err := fileHeader.Open()
if err != nil {
- return err
+ return fmt.Errorf("can't open fileHeader %w", err)
}
defer file.Close()
@@ -96,34 +114,56 @@ func (s *Service) Upload(input *TaskUploadInput) error {
return err
}
- arch, err := getRPMArchitecture(filePath)
+ pkg, err := rpm.Open(filePath)
if err != nil {
return err
}
f := models.RPMFile{
- Name: fileHeader.Filename,
- Arch: arch,
- Task: task,
+ Filename: fileHeader.Filename,
+ Name: pkg.Name(),
+ Arch: pkg.Architecture(),
+ Version: pkg.Version(),
+ Release: pkg.Release(),
+ Epoch: pkg.Epoch(),
+ Task: task,
}
- if err := s.db.Save(&f).Error; err != nil {
- return err
+ rpmFiles = append(rpmFiles, f)
+ }
+
+ if currentTask.ID != 0 {
+ groupedByName := make(map[string][]*models.RPMFile)
+ for _, file := range rpmFiles {
+ groupedByName[file.Name] = append(groupedByName[file.Name], &file)
+ }
+ for _, file := range currentTask.Files {
+ groupedByName[file.Name] = append(groupedByName[file.Name], &file)
}
- // Символическая ссылка
- /*
- targetPath := path.Join("../../../../tasks/", localPath, fileHeader.Filename)
- symLink := path.Join(s.app.Config.UploadDir, "repo/Sisyphus", arch, "RPMS.aides", fileHeader.Filename)
- err = createSymlink(targetPath, symLink)
- if err != nil {
- return err
+ for name, group := range groupedByName {
+ if len(group) > 1 {
+ result := rpm.Compare(
+ &WrapperRpmVersion{group[0]},
+ &WrapperRpmVersion{group[1]},
+ )
+
+ if result < 1 {
+ return &TooOldError{
+ Name: name,
+ }
+ }
}
- */
+ }
+ }
+ result = s.db.Create(&rpmFiles)
+ if result.Error != nil {
+ return result.Error
}
task.Status = models.StatusCompleted
+ shouldCleanTask = false
return s.onTaskComplete(&task)
}
diff --git a/internal/services/taskservice/utils.go b/internal/services/taskservice/utils.go
new file mode 100644
index 0000000..860b9c4
--- /dev/null
+++ b/internal/services/taskservice/utils.go
@@ -0,0 +1,11 @@
+package taskservice
+
+import "code.alt-gnome.ru/aides-infra/aides-repo-api/internal/models"
+
+type WrapperRpmVersion struct {
+ file *models.RPMFile
+}
+
+func (c *WrapperRpmVersion) Epoch() int { return c.file.Epoch }
+func (c *WrapperRpmVersion) Version() string { return c.file.Version }
+func (c *WrapperRpmVersion) Release() string { return c.file.Release }
diff --git a/scripts/coverage-badge.sh b/scripts/coverage-badge.sh
new file mode 100755
index 0000000..fc2b512
--- /dev/null
+++ b/scripts/coverage-badge.sh
@@ -0,0 +1,10 @@
+#!/bin/bash
+COVERAGE=$(go tool cover -func=coverage.out | grep total | awk '{print $3}' | sed 's/%//')
+cat < coverage-badge.svg
+
+EOF
\ No newline at end of file