chore: add tests, fix swagger

This commit is contained in:
Максим Слипенко 2024-12-26 16:42:54 +03:00
parent 6693ceabcc
commit dd432d9d4a
19 changed files with 253 additions and 63 deletions

View file

@ -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

View file

@ -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

View file

@ -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)
[![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)

View file

@ -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 {

6
coverage-badge.svg Normal file
View file

@ -0,0 +1,6 @@
<svg xmlns="http://www.w3.org/2000/svg" width="98" height="20">
<rect width="59" height="20" fill="#555"/>
<rect x="59" width="39" height="20" fill="#4c1"/>
<text x="30" y="14" fill="#fff" font-family="Verdana" font-size="11">coverage</text>
<text x="65" y="14" fill="#fff" font-family="Verdana" font-size="11">22.3%</text>
</svg>

After

Width:  |  Height:  |  Size: 339 B

View file

@ -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",

View file

@ -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",

View file

@ -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

24
go.mod
View file

@ -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
)

23
go.sum
View file

@ -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=

View file

@ -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"

View file

@ -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
}
}

View file

@ -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

View file

@ -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)

View file

@ -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)

View file

@ -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)
}

View file

@ -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)
}

View file

@ -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 }

10
scripts/coverage-badge.sh Executable file
View file

@ -0,0 +1,10 @@
#!/bin/bash
COVERAGE=$(go tool cover -func=coverage.out | grep total | awk '{print $3}' | sed 's/%//')
cat <<EOF > coverage-badge.svg
<svg xmlns="http://www.w3.org/2000/svg" width="98" height="20">
<rect width="59" height="20" fill="#555"/>
<rect x="59" width="39" height="20" fill="#4c1"/>
<text x="30" y="14" fill="#fff" font-family="Verdana" font-size="11">coverage</text>
<text x="65" y="14" fill="#fff" font-family="Verdana" font-size="11">${COVERAGE}%</text>
</svg>
EOF