diff --git a/.drone1.yml b/.drone1.yml index abdc7cf8a5..de2001dec8 100644 --- a/.drone1.yml +++ b/.drone1.yml @@ -52,13 +52,26 @@ steps: commands: - git fetch --tags - - name: build + # We're statically compiling the magefile to avoid race condition issues caused by multiple pipeline steps + # compiling the same magefile at the same time. It's also faster if each step does not need to compile it first. + - name: mage image: vikunja/golang-build:latest pull: true environment: GOPROXY: 'https://goproxy.kolaente.de' commands: - - make build + - mage -compile ./mage-static + when: + event: [ push, tag, pull_request ] + + - name: build + image: vikunja/golang-build:latest + pull: true + environment: + GOPROXY: 'https://goproxy.kolaente.de' + depends_on: [ mage ] + commands: + - ./mage-static build:build when: event: [ push, tag, pull_request ] @@ -69,17 +82,17 @@ steps: GOPROXY: 'https://goproxy.kolaente.de' depends_on: [ build ] commands: - - make generate - - make lint - - make fmt-check - # - make got-swag # Commented out until we figured out how to get this working on drone - - make ineffassign-check - - make misspell-check - - make goconst-check - - make gocyclo-check - - make static-check + - ./mage-static build:generate + - ./mage-static check:lint + - ./mage-static check:fmt + - ./mage-static check:got-swag + - ./mage-static check:ineffassign + - ./mage-static check:misspell + - ./mage-static check:goconst + - ./mage-static check:gocyclo + - ./mage-static check:static - wget -O - -q https://raw.githubusercontent.com/securego/gosec/master/install.sh | sh -s -- -b $GOPATH/bin v2.2.0 # Need to manually install as it does not support being installed via go modules like the rest. - - make gosec-check + - ./mage-static check:gosec when: event: [ push, tag, pull_request ] @@ -152,9 +165,9 @@ steps: environment: GOPROXY: 'https://goproxy.kolaente.de' commands: - - make generate - - make test - depends_on: [ fetch-tags ] + - ./mage-static build:generate + - ./mage-static test:unit + depends_on: [ fetch-tags, mage ] when: event: [ push, tag, pull_request ] @@ -166,9 +179,9 @@ steps: VIKUNJA_TESTS_USE_CONFIG: 1 VIKUNJA_DATABASE_TYPE: sqlite commands: - - make generate - - make test - depends_on: [ fetch-tags ] + - ./mage-static build:generate + - ./mage-static test:unit + depends_on: [ fetch-tags, mage ] when: event: [ push, tag, pull_request ] @@ -184,9 +197,9 @@ steps: VIKUNJA_DATABASE_PASSWORD: vikunjatest VIKUNJA_DATABASE_DATABASE: vikunjatest commands: - - make generate - - make test - depends_on: [ fetch-tags ] + - ./mage-static build:generate + - ./mage-static test:unit + depends_on: [ fetch-tags, mage ] when: event: [ push, tag, pull_request ] @@ -203,9 +216,9 @@ steps: VIKUNJA_DATABASE_DATABASE: vikunjatest VIKUNJA_DATABASE_SSLMODE: disable commands: - - make generate - - make test - depends_on: [ fetch-tags ] + - ./mage-static build:generate + - ./mage-static test:unit + depends_on: [ fetch-tags, mage ] when: event: [ push, tag, pull_request ] @@ -215,9 +228,9 @@ steps: environment: GOPROXY: 'https://goproxy.kolaente.de' commands: - - make generate - - make integration-test - depends_on: [ fetch-tags ] + - ./mage-static build:generate + - ./mage-static test:integration + depends_on: [ fetch-tags, mage ] when: event: [ push, tag, pull_request ] @@ -229,9 +242,9 @@ steps: VIKUNJA_TESTS_USE_CONFIG: 1 VIKUNJA_DATABASE_TYPE: sqlite commands: - - make generate - - make integration-test - depends_on: [ fetch-tags ] + - ./mage-static build:generate + - ./mage-static test:integration + depends_on: [ fetch-tags, mage ] when: event: [ push, tag, pull_request ] @@ -247,9 +260,9 @@ steps: VIKUNJA_DATABASE_PASSWORD: vikunjatest VIKUNJA_DATABASE_DATABASE: vikunjatest commands: - - make generate - - make integration-test - depends_on: [ fetch-tags ] + - ./mage-static build:generate + - ./mage-static test:integration + depends_on: [ fetch-tags, mage ] when: event: [ push, tag, pull_request ] @@ -266,9 +279,9 @@ steps: VIKUNJA_DATABASE_DATABASE: vikunjatest VIKUNJA_DATABASE_SSLMODE: disable commands: - - make generate - - make integration-test - depends_on: [ fetch-tags ] + - ./mage-static build:generate + - ./mage-static test:integration + depends_on: [ fetch-tags, mage ] when: event: [ push, tag, pull_request ] @@ -299,14 +312,27 @@ steps: commands: - git fetch --tags + # We're statically compiling the magefile to avoid race condition issues caused by multiple pipeline steps + # compiling the same magefile at the same time. It's also faster if each step does not need to compile it first. + - name: mage + image: vikunja/golang-build:latest + pull: true + environment: + GOPROXY: 'https://goproxy.kolaente.de' + commands: + - mage -compile ./mage-static + when: + event: [ push, tag, pull_request ] + - name: before-static-build image: techknowlogick/xgo:latest pull: true commands: - export PATH=$PATH:$GOPATH/bin - - make generate - - make release-dirs - depends_on: [ fetch-tags ] + - go install github.com/magefile/mage + - ./mage-static build:generate + - ./mage-static release:dirs + depends_on: [ fetch-tags, mage ] - name: static-build-windows image: techknowlogick/xgo:latest @@ -317,7 +343,8 @@ steps: GOPATH: /srv/app commands: - export PATH=$PATH:$GOPATH/bin - - make release-windows + - go install github.com/magefile/mage + - ./mage-static release:windows depends_on: [ before-static-build ] - name: static-build-linux @@ -329,7 +356,8 @@ steps: GOPATH: /srv/app commands: - export PATH=$PATH:$GOPATH/bin - - make release-linux + - go install github.com/magefile/mage + - ./mage-static release:linux depends_on: [ before-static-build ] - name: static-build-darwin @@ -341,7 +369,8 @@ steps: GOPATH: /srv/app commands: - export PATH=$PATH:$GOPATH/bin - - make release-darwin + - go install github.com/magefile/mage + - ./mage-static release:darwin depends_on: [ before-static-build ] - name: after-build-compress @@ -352,7 +381,7 @@ steps: - static-build-linux - static-build-darwin commands: - - make release-compress + - ./mage-static release:compress - name: after-build-static image: techknowlogick/xgo:latest @@ -360,10 +389,11 @@ steps: depends_on: - after-build-compress commands: - - make release-copy - - make release-check - - make release-os-package - - make release-zip + - go install github.com/magefile/mage + - ./mage-static release:copy + - ./mage-static release:check + - ./mage-static release:os-package + - ./mage-static release:zip - name: sign-release image: plugins/gpgsign:1 @@ -428,7 +458,7 @@ steps: image: kolaente/fpm pull: true commands: - - make build-deb + - ./mage-static build-deb depends_on: [ static-build-linux ] - name: deb-structure @@ -446,7 +476,7 @@ steps: - gpg --import ~/frederik.gpg - mkdir debian/conf -p - cp build/reprepro-dist-conf debian/conf/distributions - - make reprepro + - ./mage-static reprepro depends_on: [ build-deb ] # Push the releases to our pseudo-s3-bucket diff --git a/docs/content/doc/development/mage.md b/docs/content/doc/development/mage.md new file mode 100644 index 0000000000..6afbe7f424 --- /dev/null +++ b/docs/content/doc/development/mage.md @@ -0,0 +1,179 @@ +--- +date: "2019-02-12:00:00+02:00" +title: "Magefile" +draft: false +type: "doc" +menu: + sidebar: + parent: "development" +--- + +# Mage + +Vikunja uses [Mage](https://magefile.org/) to script common development tasks and even releasing. +Mage is a pure go solution which allows for greater flexibility and things like better paralelization. + +This document explains what taks are available and what they do. + +## Installation + +To use mage, you'll need to install the mage cli. +To install it, run the following command: + +``` +go install github.com/magefile/mage +``` + +## Categories + +There are multiple categories of subcommands in the magefile: + +* `build`: Contains commands to build a single binary +* `check`: Contains commands to statically check the source code +* `release`: Contains commands to release Vikunja with everything that's required +* `test`: Contains commands to run all kinds of tests +* `misc`: Commands which do not belong in either of the other categories + +## CI + +These tasks are automatically run in our CI every time someone pushes to master or you update a pull request: + +* `mage check:lint` +* `mage check:fmt` +* `mage check:ineffassign` +* `mage check:misspell` +* `mage check:goconst` +* `mage build:generate` +* `mage build:build` + +## Build + +### Build Vikunja + +{{< highlight bash >}} +mage build:build +{{< /highlight >}} + +Builds a `vikunja`-binary in the root directory of the repo for the platform it is run on. + +### Statically compile all templates into the binary + +{{< highlight bash >}} +mage build:generate +{{< /highlight >}} + +This generates static code with all templates, meaning no template need to be referenced at runtime. + +### clean + +{{< highlight bash >}} +mage build:clean +{{< /highlight >}} + +Cleans all build, executable and bindata files + +## Check + +All check sub-commands exit with a status code of 1 if the check fails. + +Various code-checks are available: + +* `mage check:all`: Runs fmt-check, lint, got-swag, misspell-check, ineffasign-check, gocyclo-check, static-check, gosec-check, goconst-check all in parallel +* `mage check:fmt`: Checks if the code is properly formatted with go fmt +* `mage check:go-sec`: Checks the source code for potential security issues by scanning the Go AST using the [gosec tool](https://github.com/securego/gosec) +* `mage check:goconst`: Checks for repeated strings that could be replaced by a constant using [goconst](https://github.com/jgautheron/goconst/) +* `mage check:gocyclo`: Checks for the cyclomatic complexity of the source code using [gocyclo](https://github.com/fzipp/gocyclo) +* `mage check:got-swag`: Checks if the swagger docs need to be re-generated from the code annotations +* `mage check:ineffassign`: Checks the source code for ineffectual assigns using [ineffassign](https://github.com/gordonklaus/ineffassign) +* `mage check:lint`: Runs golint on all packages +* `mage check:misspell`: Checks the source code for misspellings +* `mage check:static`: Statically analyzes the source code about a range of different problems using [staticcheck](https://staticcheck.io/docs/) + +## Release + +### Build Releases + +{{< highlight bash >}} +mage release +{{< /highlight >}} + +Builds binaries for all platforms and zips them with a copy of the `templates/` folder. +All built zip files are stored into `dist/zips/`. Binaries are stored in `dist/binaries/`, +binaries bundled with `templates` are stored in `dist/releases/`. + +All cross-platform binaries built using this series of commands are built with the help of +[xgo](https://github.com/techknowlogick/xgo). The mage command will automatically install the +binary to be able to use it. + +`mage release:release` is a shortcut to execute `mage release:dirs release:windows release:linux release:darwin release:copy release:check release:os-package release:zip`. + +* `mage release:dirs` creates all directories needed +* `mage release:windows`/`release:linux`/`release:darwin` execute xgo to build for their respective platforms +* `mage release:copy` bundles binaries with a copy of the `LICENSE` and sample config files to then be zipped +* `mage release:check` creates sha256 checksums for each binary which will be included in the zip file +* `mage release:os-package` bundles a binary with the `sha256` checksum file, a sample `config.yml` and a copy of the license in a folder for each architecture +* `mage release:compress` compresses all build binaries with `upx` to save space +* `mage release:zip` paclages a zip file for the files created by `release:os-package` + +### Build debian packages + +{{< highlight bash >}} +mage release:deb +{{< /highlight >}} + +Will build a `.deb` package into the current folder. +You need to have [fpm](https://fpm.readthedocs.io/en/latest/intro.html) installed to be able to do this. + +### Make a debian repo + +{{< highlight bash >}} +mage release:reprepro +{{< /highlight >}} + +Takes an already built debian package and creates a debian repo structure around it. + +Used to be run inside a [docker container](https://git.kolaente.de/konrad/reprepro-docker) in the CI process when releasing. + +## Test + +### unit + +{{< highlight bash >}} +mage test:unit +{{< /highlight >}} + +Runs all tests except integration tests. + +### coverage + +{{< highlight bash >}} +mage test:coverage +{{< /highlight >}} + +Runs all tests except integration tests and generates a `coverage.html` file to inspect the code coverage. + +### integration + +{{< highlight bash >}} +mage test:integration +{{< /highlight >}} + +Runs all integration tests. + +## Misc + +### Format the code + +{{< highlight bash >}} +mage fmt +{{< /highlight >}} + +Formats all source code using `go fmt`. + +### Generate swagger definitions from code comments + +{{< highlight bash >}} +mage do-the-swag +{{< /highlight >}} + +Generates swagger definitions from the comment annotations in the code. diff --git a/docs/content/doc/development/make.md b/docs/content/doc/development/make.md deleted file mode 100644 index bd7b9d99b7..0000000000 --- a/docs/content/doc/development/make.md +++ /dev/null @@ -1,151 +0,0 @@ ---- -date: "2019-02-12:00:00+02:00" -title: "Makefile" -draft: false -type: "doc" -menu: - sidebar: - parent: "development" ---- - -# Makefile - -We scripted a lot of tasks used mostly for developing into the makefile. This documents explains what -taks are available and what they do. - -## CI - -These tasks are automatically run in our CI every time someone pushes to master or you update a pull request: - -* `make lint` -* `make fmt-check` -* `make ineffassign-check` -* `make misspell-check` -* `make goconst-check` -* `make generate` -* `make build` - -### clean - -{{< highlight bash >}} -make clean -{{< /highlight >}} - -Clears all builds and binaries. - -### test - -{{< highlight bash >}} -make test -{{< /highlight >}} - -Runs all tests in Vikunja. - -### Format the code - -{{< highlight bash >}} -make fmt -{{< /highlight >}} - -Formats all source code using `go fmt`. - -#### Check formatting - -{{< highlight bash >}} -make fmt-check -{{< /highlight >}} - -Checks if the code needs to be formatted. Fails if it does. - -### Build Vikunja - -{{< highlight bash >}} -make build -{{< /highlight >}} - -Builds a `vikunja`-binary in the root directory of the repo for the platform it is run on. - -### Statically compile all templates into the binary - -{{< highlight bash >}} -make generate -{{< /highlight >}} - -This generates static code with all templates, meaning no template need to be referenced at runtime. - -### Compress the built binary - -{{< highlight bash >}} -make compress-build -{{< /highlight >}} - -Go binaries are very big. -To make the vikunja binary smaller, we can compress it using [upx](https://upx.github.io/). - -### Build Releases - -{{< highlight bash >}} -make release -{{< /highlight >}} - -Builds binaries for all platforms and zips them with a copy of the `templates/` folder. -All built zip files are stored into `dist/zips/`. Binaries are stored in `dist/binaries/`, -binaries bundled with `templates` are stored in `dist/releases/`. - -All cross-platform binaries built using this series of commands are built with the help of -[xgo](https://github.com/techknowlogick/xgo). The make command will automatically install the -binary to be able to use it. - -`make release` is actually just a shortcut to execute `make release-dirs release-windows release-linux release-darwin release-copy release-check release-os-package release-zip`. - -* `release-dirs` creates all directories needed -* `release-windows`/`release-linux`/`release-darwin` execute xgo to build for their respective platforms -* `release-copy` bundles binaries with a copy of `templates/` to then be zipped -* `release-check` creates sha256 checksums for each binary which will be included in the zip file -* `release-os-package` bundles a binary with a copy of the `templates/` folder, the `sha256` checksum file, a sample `config.yml` and a copy of the license in a folder for each architecture -* `release-compress` compresses all build binaries, see `compress-build` -* `release-zip` makes a zip file for the files created by `release-os-package` - -### Build debian packages - -{{< highlight bash >}} -make build-deb -{{< /highlight >}} - -Will build a `.deb` package into the current folder. You need to have [fpm](https://fpm.readthedocs.io/en/latest/intro.html) installed to be able to do this. - -#### Make a debian repo - -{{< highlight bash >}} -make reprepro -{{< /highlight >}} - -Takes an already built debian package and creates a debian repo structure around it. - -Used to be run inside a [docker container](https://git.kolaente.de/konrad/reprepro-docker) in the CI process when releasing. - -### Generate swagger definitions from code comments - -{{< highlight bash >}} -make do-the-swag -{{< /highlight >}} - -Generates swagger definitions from the comments in the code. - -#### Check if swagger generation is needed - -{{< highlight bash >}} -make got-swag -{{< /highlight >}} - -This command is currently more an experiment, use it with caution. -It may bring up wrong results. - -### Code-Checks - -* `misspell-check`: Checks for commonly misspelled words -* `ineffassign-check`: Checks for ineffectual assignments in the code using [ineffassign](https://github.com/gordonklaus/ineffassign). -* `gocyclo-check`: Calculates cyclomatic complexities of functions using [gocyclo](https://github.com/fzipp/gocyclo). -* `static-check`: Analyzes the code for bugs, improvements and more using [staticcheck](https://staticcheck.io/docs/). -* `gosec-check`: Inspects source code for security problems by scanning the Go AST using the [gosec tool](https://github.com/securego/gosec). -* `goconst-check`: Finds repeated strings that could be replaced by a constant using [goconst](https://github.com/jgautheron/goconst/). \ No newline at end of file diff --git a/go.mod b/go.mod index 98e04fb7ee..3e86debcff 100644 --- a/go.mod +++ b/go.mod @@ -46,6 +46,7 @@ require ( github.com/labstack/gommon v0.3.0 github.com/laurent22/ical-go v0.1.1-0.20181107184520-7e5d6ade8eef github.com/lib/pq v1.8.0 + github.com/magefile/mage v1.10.0 github.com/mailru/easyjson v0.7.0 // indirect github.com/mattn/go-sqlite3 v1.14.2 github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect @@ -69,6 +70,7 @@ require ( golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a golang.org/x/image v0.0.0-20200801110659-972c09e46d76 golang.org/x/lint v0.0.0-20200302205851-738671d3881b + golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208 golang.org/x/tools v0.0.0-20200410194907-79a7a3126eef // indirect gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f // indirect diff --git a/go.sum b/go.sum index 43b16c709e..3cbbbe9c6a 100644 --- a/go.sum +++ b/go.sum @@ -1,7 +1,5 @@ 4d63.com/embedfiles v0.0.0-20190311033909-995e0740726f h1:oyYjGRBNq1TxAIG8aHqtxlvqUfzdZf+MbcRb/oweNfY= 4d63.com/embedfiles v0.0.0-20190311033909-995e0740726f/go.mod h1:HxEsUxoVZyRxsZML/S6e2xAuieFMlGO0756ncWx1aXE= -4d63.com/tz v1.1.0 h1:Hi58WbeFjiUH4XOWuCpl5iSzuUuw1axZzTqIfMKPKrg= -4d63.com/tz v1.1.0/go.mod h1:SHGqVdL7hd2ZaX2T9uEiOZ/OFAUfCCLURdLPJsd8ZNs= 4d63.com/tz v1.2.0 h1:EpJt060xY+M+M0Wj8btz+THdOJbSxj4i8jhVQP3Wr0U= 4d63.com/tz v1.2.0/go.mod h1:SHGqVdL7hd2ZaX2T9uEiOZ/OFAUfCCLURdLPJsd8ZNs= cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= @@ -63,12 +61,6 @@ github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hC github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= -github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a h1:idn718Q4B6AGu/h5Sxe66HYVdqdGu2l9Iebqhi/AEoA= -github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= -github.com/asaskevich/govalidator v0.0.0-20200817114649-df4adffc9d8c h1:W9P/cRMhwMMfrtInPTAn5rcNu/+vb3zKdGeAd+87tFs= -github.com/asaskevich/govalidator v0.0.0-20200817114649-df4adffc9d8c/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= -github.com/asaskevich/govalidator v0.0.0-20200818142706-50839af6027e h1:6P0tOQaAiB0G+etsknZvSDjNpdYshZ7wFXTqJpl41h0= -github.com/asaskevich/govalidator v0.0.0-20200818142706-50839af6027e/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= github.com/asaskevich/govalidator v0.0.0-20200819183940-29e1ff8eb0bb h1:kvlW1qyM1aU3xeyeIVTU2jx5fSvjKpsU3aXvuaCMg3Q= github.com/asaskevich/govalidator v0.0.0-20200819183940-29e1ff8eb0bb/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= github.com/aymerick/raymond v2.0.3-0.20180322193309-b565731e1464+incompatible/go.mod h1:osfaiScAUVup+UC9Nfq76eWqDhXlp+4UYaA8uhTBO6g= @@ -84,8 +76,6 @@ github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kB github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84= github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc h1:biVzkmvwrH8WK8raXaxBx6fRVTlJILwEwQGL1I/ByEI= github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= -github.com/c2h5oh/datasize v0.0.0-20200112174442-28bbd4740fee h1:BnPxIde0gjtTnc9Er7cxvBk8DHLWhEux0SxayC8dP6I= -github.com/c2h5oh/datasize v0.0.0-20200112174442-28bbd4740fee/go.mod h1:S/7n9copUssQ56c7aAgHqftWO4LTf4xY6CGWt8Bc+3M= github.com/c2h5oh/datasize v0.0.0-20200825124411-48ed595a09d2 h1:t8KYCwSKsOEZBFELI4Pn/phbp38iJ1RRAkDFNin1aak= github.com/c2h5oh/datasize v0.0.0-20200825124411-48ed595a09d2/go.mod h1:S/7n9copUssQ56c7aAgHqftWO4LTf4xY6CGWt8Bc+3M= github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= @@ -296,10 +286,6 @@ github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= -github.com/iancoleman/strcase v0.0.0-20191112232945-16388991a334 h1:VHgatEHNcBFEB7inlalqfNqw65aNkM1lGX2yt3NmbS8= -github.com/iancoleman/strcase v0.0.0-20191112232945-16388991a334/go.mod h1:SK73tn/9oHe+/Y0h39VT4UCxmurVJkR5NA7kMEAOgSE= -github.com/iancoleman/strcase v0.1.0 h1:Lar8rut26AXkJUmVOb2bRsFGv//+tJBeJLxXvpZpF1Q= -github.com/iancoleman/strcase v0.1.0/go.mod h1:SK73tn/9oHe+/Y0h39VT4UCxmurVJkR5NA7kMEAOgSE= github.com/iancoleman/strcase v0.1.1 h1:2I+LRClyCYB7JgZb9U0k75VHUiQe9RfknRqDyUfzp7k= github.com/iancoleman/strcase v0.1.1/go.mod h1:SK73tn/9oHe+/Y0h39VT4UCxmurVJkR5NA7kMEAOgSE= github.com/imdario/mergo v0.3.11 h1:3tnifQM4i+fbajXKBHXWEH+KvNHqojZ778UH75j3bGA= @@ -433,6 +419,8 @@ github.com/lib/pq v1.6.0 h1:I5DPxhYJChW9KYc66se+oKFFQX6VuQrKiprsX6ivRZc= github.com/lib/pq v1.6.0/go.mod h1:4vXEAYvW1fRQ2/FhZ78H73A60MHw1geSm145z2mdY1g= github.com/lib/pq v1.8.0 h1:9xohqzkUwzR4Ga4ivdTcawVS89YSDVxXMa3xJX3cGzg= github.com/lib/pq v1.8.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= +github.com/magefile/mage v1.10.0 h1:3HiXzCUY12kh9bIuyXShaVe529fJfyqoVM42o/uom2g= +github.com/magefile/mage v1.10.0/go.mod h1:z5UZb/iS3GoOSn0JgWuiw7dxlurVYTu+/jHXqQg881A= github.com/magiconair/properties v1.8.0 h1:LLgXmsheXeRoUOBOjtwPQCWIYqM/LU1ayDtDePerRcY= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4= @@ -469,8 +457,6 @@ github.com/mattn/go-sqlite3 v1.10.0 h1:jbhqpg7tQe4SupckyijYiy0mJJ/pRyHvXf7JdWK86 github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= github.com/mattn/go-sqlite3 v1.14.0 h1:mLyGNKR8+Vv9CAU7PphKa2hkEqxxhn8i32J6FPj1/QA= github.com/mattn/go-sqlite3 v1.14.0/go.mod h1:JIl7NbARA7phWnGvh0LKTyg7S9BA+6gx71ShQilpsus= -github.com/mattn/go-sqlite3 v1.14.1 h1:AHx9Ra40wIzl+GelgX2X6AWxmT5tfxhI1PL0523HcSw= -github.com/mattn/go-sqlite3 v1.14.1/go.mod h1:JIl7NbARA7phWnGvh0LKTyg7S9BA+6gx71ShQilpsus= github.com/mattn/go-sqlite3 v1.14.2 h1:A2EQLwjYf/hfYaM20FVjs1UewCTTFR7RmjEHkLjldIA= github.com/mattn/go-sqlite3 v1.14.2/go.mod h1:JIl7NbARA7phWnGvh0LKTyg7S9BA+6gx71ShQilpsus= github.com/mattn/goveralls v0.0.2/go.mod h1:8d1ZMHsd7fW6IRPKQh46F2WRpyib5/X4FOpevwGNQEw= @@ -594,8 +580,6 @@ github.com/shurcooL/httpfs v0.0.0-20190707220628-8d4bc4ba7749 h1:bUGsEnyNbVPw06B github.com/shurcooL/httpfs v0.0.0-20190707220628-8d4bc4ba7749/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg= github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= -github.com/shurcooL/vfsgen v0.0.0-20200627165143-92b8a710ab6c h1:XLPw6rny9Vrrvrzhw8pNLrC2+x/kH0a/3gOx5xWDa6Y= -github.com/shurcooL/vfsgen v0.0.0-20200627165143-92b8a710ab6c/go.mod h1:TrYk7fJVaAttu97ZZKrO9UbRa8izdowaMIZcxYMbVaw= github.com/shurcooL/vfsgen v0.0.0-20200824052919-0d455de96546 h1:pXY9qYc/MP5zdvqWEUH6SjNiu7VhSjuVFTFiTcphaLU= github.com/shurcooL/vfsgen v0.0.0-20200824052919-0d455de96546/go.mod h1:TrYk7fJVaAttu97ZZKrO9UbRa8izdowaMIZcxYMbVaw= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= @@ -800,7 +784,10 @@ golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e h1:vcxGaoTs7kV8m5Np9uUNQin4BrLOthgV7252N8V+FwY= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208 h1:qwRHBd0NqMbJxfbotnDhm2ByMI1Shq4Y6oRJo21SGJA= +golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= diff --git a/magefile.go b/magefile.go new file mode 100644 index 0000000000..86f54005c3 --- /dev/null +++ b/magefile.go @@ -0,0 +1,648 @@ +// Vikunja is a to-do list application to facilitate your life. +// Copyright 2018-2020 Vikunja and contributors. All rights reserved. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +// +build mage + +package main + +import ( + "bufio" + "bytes" + "context" + "crypto/sha256" + "fmt" + "github.com/magefile/mage/mg" + "golang.org/x/sync/errgroup" + "io" + "os" + "os/exec" + "path/filepath" + "runtime" + "strings" +) + +const ( + PACKAGE = `code.vikunja.io/api` + DIST = `dist` +) + +var ( + Goflags = []string{ + "-v", + } + Executable = "vikunja" + Ldflags = "" + Tags = "" + VersionNumber = "dev" + Version = "master" // This holds the built version, master by default, when building from a tag or release branch, their name + BinLocation = "" + PkgVersion = "master" + ApiPackages = []string{} + RootPath = "" + GoFiles = []string{} + + // Aliases are mage aliases of targets + Aliases = map[string]interface{}{ + "do-the-swag": DoTheSwag, + "check:go-sec": Check.GoSec, + "check:got-swag": Check.GotSwag, + "release:os-package": Release.OsPackage, + } +) + +func setVersion() { + versionCmd := exec.Command("git", "describe", "--tags", "--always", "--abbrev=10") + version, err := versionCmd.Output() + if err != nil { + fmt.Printf("Error getting version: %s\n", err) + os.Exit(1) + } + VersionNumber = strings.Trim(string(version), "\n") + VersionNumber = strings.Replace(VersionNumber, "-", "+", 1) + VersionNumber = strings.Replace(VersionNumber, "-g", "-", 1) + + if os.Getenv("DRONE_TAG") != "" { + Version = os.Getenv("DRONE_TAG") + } else if os.Getenv("DRONE_BRANCH") != "" { + Version = strings.Replace(os.Getenv("DRONE_BRANCH"), "release/v", "", 1) + } +} + +func setBinLocation() { + if os.Getenv("DRONE_WORKSPACE") != "" { + BinLocation = DIST + `/binaries/` + Executable + `-` + Version + `-linux-amd64` + } else { + BinLocation = Executable + } +} + +func setPkgVersion() { + if Version == "master" { + PkgVersion = VersionNumber + } +} + +func setExecutable() { + if runtime.GOOS == "windows" { + Executable += ".exe" + } +} + +func setApiPackages() { + cmd := exec.Command("go", "list", "all") + pkgs, err := cmd.Output() + if err != nil { + fmt.Printf("Error getting packages: %s\n", err) + os.Exit(1) + } + for _, p := range strings.Split(string(pkgs), "\n") { + if strings.Contains(p, "code.vikunja.io/api") && !strings.Contains(p, "code.vikunja.io/api/pkg/integrations") { + ApiPackages = append(ApiPackages, p) + } + } +} + +func setRootPath() { + pwd, err := os.Getwd() + if err != nil { + fmt.Printf("Error getting pwd: %s\n", err) + os.Exit(1) + } + if err := os.Setenv("VIKUNJA_SERVICE_ROOTPATH", pwd); err != nil { + fmt.Printf("Error setting root path: %s\n", err) + os.Exit(1) + } + RootPath = pwd +} + +func setGoFiles() { + // GOFILES := $(shell find . -name "*.go" -type f ! -path "*/bindata.go") + cmd := exec.Command("find", ".", "-name", "*.go", "-type", "f", "!", "-path", "*/bindata.go") + files, err := cmd.Output() + if err != nil { + fmt.Printf("Error getting go files: %s\n", err) + os.Exit(1) + } + for _, f := range strings.Split(string(files), "\n") { + if strings.HasSuffix(f, ".go") { + GoFiles = append(GoFiles, RootPath+strings.TrimLeft(f, ".")) + } + } +} + +func init() { + Tags = os.Getenv("TAGS") + setVersion() + setExecutable() + setBinLocation() + setPkgVersion() + setApiPackages() + setRootPath() + setGoFiles() + Ldflags = `-X "` + PACKAGE + `/pkg/version.Version=` + VersionNumber + `" -X "main.Tags=` + Tags + `"` +} + +func runAndStreamOutput(cmd string, args ...string) { + c := exec.Command(cmd, args...) + + c.Env = os.Environ() + c.Dir = RootPath + + fmt.Printf("%s\n\n", c.String()) + + stdout, _ := c.StdoutPipe() + errbuf := bytes.Buffer{} + c.Stderr = &errbuf + c.Start() + + reader := bufio.NewReader(stdout) + line, err := reader.ReadString('\n') + for err == nil { + fmt.Print(line) + line, err = reader.ReadString('\n') + } + + if err := c.Wait(); err != nil { + fmt.Printf(errbuf.String()) + fmt.Printf("Error: %s\n", err) + os.Exit(1) + } +} + +// Will check if the tool exists and if not install it from the provided import path +// If any errors occur, it will exit with a status code of 1. +func checkAndInstallGoTool(tool, importPath string) { + if err := exec.Command(tool).Run(); err != nil && strings.Contains(err.Error(), "executable file not found") { + fmt.Printf("%s not installed, installing %s...\n", tool, importPath) + if err := exec.Command("go", "install", Goflags[0], importPath).Run(); err != nil { + fmt.Printf("Error installing %s\n", tool) + os.Exit(1) + } + fmt.Println("Installed.") + } +} + +// Calculates a hash of a file +func calculateSha256FileHash(path string) (hash string, err error) { + f, err := os.Open(path) + if err != nil { + return "", err + } + defer f.Close() + + h := sha256.New() + if _, err := io.Copy(h, f); err != nil { + return "", err + } + + return fmt.Sprintf("%x", h.Sum(nil)), nil +} + +// Copy the src file to dst. Any existing file will be overwritten and will not +// copy file attributes. +func copyFile(src, dst string) error { + in, err := os.Open(src) + if err != nil { + return err + } + defer in.Close() + + out, err := os.Create(dst) + if err != nil { + return err + } + defer out.Close() + + _, err = io.Copy(out, in) + if err != nil { + return err + } + + si, err := os.Stat(src) + if err != nil { + return err + } + + if err := os.Chmod(dst, si.Mode()); err != nil { + return err + } + + return out.Close() +} + +// Formats the code using go fmt +func Fmt() { + args := append([]string{"-s", "-w"}, GoFiles...) + runAndStreamOutput("gofmt", args...) +} + +// Generates the swagger docs from the code annotations +func DoTheSwag() { + checkAndInstallGoTool("swag", "github.com/swaggo/swag/cmd/swag") + runAndStreamOutput("swag", "init", "-g", "./pkg/routes/routes.go", "--parseDependency", "-d", RootPath, "-o", RootPath+"/pkg/swagger") +} + +type Test mg.Namespace + +// Runs all tests except integration tests +func (Test) Unit() { + // We run everything sequentially and not in parallel to prevent issues with real test databases + args := append([]string{"test", Goflags[0], "-p", "1"}, ApiPackages...) + runAndStreamOutput("go", args...) +} + +// Runs the tests and builds the coverage html file from coverage output +func (Test) Coverage() { + mg.Deps(Test.Unit) + runAndStreamOutput("go", "tool", "cover", "-html=cover.out", "-o", "cover.html") +} + +// Runs the integration tests +func (Test) Integration() { + // We run everything sequentially and not in parallel to prevent issues with real test databases + runAndStreamOutput("go", "test", Goflags[0], "-p", "1", PACKAGE+"/pkg/integrations") +} + +type Check mg.Namespace + +// Checks if the code is properly formatted with go fmt +func (Check) Fmt() error { + args := append([]string{"-s", "-d"}, GoFiles...) + c := exec.Command("gofmt", args...) + out, err := c.Output() + if err != nil { + return err + } + + if len(out) > 0 { + fmt.Println("Code is not properly gofmt'ed.") + fmt.Println("Please run 'mage fmt' and commit the result:") + fmt.Print(string(out)) + os.Exit(1) + } + + return nil +} + +// Runs golint on all packages +func (Check) Lint() { + checkAndInstallGoTool("golint", "golang.org/x/lint/golint") + args := append([]string{"-set_exit_status"}, ApiPackages...) + runAndStreamOutput("golint", args...) +} + +// Checks if the swagger docs need to be re-generated from the code annotations +func (Check) GotSwag() { + // The check is pretty cheaply done: We take the hash of the swagger.json file, generate the docs, + // hash the file again and compare the two hashes to see if anything changed. If that's the case, + // regenerating the docs is necessary. + // swag is not capable of just outputting the generated docs to stdout, therefore we need to do it this way. + // Another drawback of this is obviously it will only work once - we're not resetting the newly generated + // docs after the check. This behaviour is good enough for ci though. + oldHash, err := calculateSha256FileHash(RootPath + "/pkg/swagger/swagger.json") + if err != nil { + fmt.Printf("Error getting old hash of the swagger docs: %s", err) + os.Exit(1) + } + + DoTheSwag() + + newHash, err := calculateSha256FileHash(RootPath + "/pkg/swagger/swagger.json") + if err != nil { + fmt.Printf("Error getting new hash of the swagger docs: %s", err) + os.Exit(1) + } + + if oldHash != newHash { + fmt.Println("Swagger docs are not up to date.") + fmt.Println("Please run 'mage do-the-swag' and commit the result.") + os.Exit(1) + } +} + +// Checks the source code for misspellings +func (Check) Misspell() { + checkAndInstallGoTool("misspell", "github.com/client9/misspell/cmd/misspell") + runAndStreamOutput("misspell", append([]string{"-error"}, GoFiles...)...) +} + +// Checks the source code for ineffectual assigns +func (Check) Ineffassign() { + checkAndInstallGoTool("ineffassign", "github.com/gordonklaus/ineffassign") + runAndStreamOutput("ineffassign", GoFiles...) +} + +// Checks for the cyclomatic complexity of the source code +func (Check) Gocyclo() { + checkAndInstallGoTool("gocyclo", "github.com/fzipp/gocyclo") + runAndStreamOutput("gocyclo", append([]string{"-over", "49"}, GoFiles...)...) +} + +// Statically analyzes the source code about a range of different problems +func (Check) Static() { + checkAndInstallGoTool("staticcheck", "honnef.co/go/tools/cmd/staticcheck") + runAndStreamOutput("staticcheck", ApiPackages...) +} + +// Checks the source code for potential security issues +func (Check) GoSec() { + if err := exec.Command("gosec").Run(); err != nil && strings.Contains(err.Error(), "executable file not found") { + fmt.Println("Please manually install gosec by running") + fmt.Println("curl -sfL https://raw.githubusercontent.com/securego/gosec/master/install.sh | bash -s -- -b $GOPATH/bin v2.2.0") + os.Exit(1) + } + runAndStreamOutput("gosec", "./...") +} + +// Checks for repeated strings that could be replaced by a constant +func (Check) Goconst() { + checkAndInstallGoTool("goconst", "github.com/jgautheron/goconst/cmd/goconst") + runAndStreamOutput("goconst", ApiPackages...) +} + +// Runs fmt-check, lint, got-swag, misspell-check, ineffasign-check, gocyclo-check, static-check, gosec-check, goconst-check all in parallel +func (Check) All() { + mg.Deps( + Check.Fmt, + Check.Lint, + Check.GotSwag, + Check.Misspell, + Check.Ineffassign, + Check.Gocyclo, + Check.Static, + Check.GoSec, + Check.Goconst, + ) +} + +type Build mg.Namespace + +// Cleans all build, executable and bindata files +func (Build) Clean() error { + if err := exec.Command("go", "clean", "./...").Run(); err != nil { + return err + } + if err := os.Remove(Executable); err != nil && !os.IsNotExist(err) { + return err + } + if err := os.RemoveAll(DIST); err != nil && !os.IsNotExist(err) { + return err + } + if err := os.RemoveAll(BinLocation); err != nil && !os.IsNotExist(err) { + return err + } + return nil +} + +// Generates static content into the final binary +func (Build) Generate() { + runAndStreamOutput("go", "generate", PACKAGE+"/pkg/static") +} + +// Builds a vikunja binary, ready to run +func (Build) Build() { + mg.Deps(Build.Generate) + runAndStreamOutput("go", "build", Goflags[0], "-tags", Tags, "-ldflags", "-s -w "+Ldflags, "-o", Executable) +} + +type Release mg.Namespace + +// Runs all steps in the right order to create release packages for various platforms +func (Release) Release(ctx context.Context) error { + mg.Deps(Build.Generate, Release.Dirs) + mg.Deps(Release.Windows, Release.Linux, Release.Darwin) + + // Run compiling in parallel to speed it up + errs, _ := errgroup.WithContext(ctx) + errs.Go((Release{}).Windows) + errs.Go((Release{}).Linux) + errs.Go((Release{}).Darwin) + if err := errs.Wait(); err != nil { + return err + } + + if err := (Release{}).Compress(ctx); err != nil { + return err + } + if err := (Release{}).Copy(); err != nil { + return err + } + if err := (Release{}).Check(); err != nil { + return err + } + if err := (Release{}).OsPackage(); err != nil { + return err + } + if err := (Release{}).Zip(); err != nil { + return err + } + + return nil +} + +// Creates all directories needed to release vikunja +func (Release) Dirs() error { + for _, d := range []string{"binaries", "release", "zip"} { + if err := os.MkdirAll(RootPath+"/"+DIST+"/"+d, 0755); err != nil { + return err + } + } + return nil +} + +func runXgo(targets string) error { + checkAndInstallGoTool("xgo", "src.techknowlogick.com/xgo") + runAndStreamOutput("xgo", + "-dest", RootPath+"/"+DIST+"/binaries", + "-tags", "netgo "+Tags, + "-ldflags", `-linkmode external -extldflags "-static" `+Ldflags, + "-targets", targets, + "-out", Executable+"-"+Version, + RootPath) + if os.Getenv("DRONE_WORKSPACE") != "" { + return filepath.Walk("/build/", func(path string, info os.FileInfo, err error) error { + return os.Rename(path, RootPath+"/"+DIST+"/binaries/"+info.Name()) + }) + } + return nil +} + +// Builds binaries for windows +func (Release) Windows() error { + return runXgo("windows/*") +} + +// Builds binaries for linux +func (Release) Linux() error { + return runXgo("linux/*") +} + +// Builds binaries for darwin +func (Release) Darwin() error { + return runXgo("darwin/*") +} + +// Compresses the built binaries in dist/binaries/ to reduce their filesize +func (Release) Compress(ctx context.Context) error { + // $(foreach file,$(filter-out $(wildcard $(wildcard $(DIST)/binaries/$(EXECUTABLE)-*mips*)),$(wildcard $(DIST)/binaries/$(EXECUTABLE)-*)), upx -9 $(file);) + + errs, _ := errgroup.WithContext(ctx) + + filepath.Walk(RootPath+"/"+DIST+"/binaries/", func(path string, info os.FileInfo, err error) error { + // Only executable files + if !strings.Contains(info.Name(), Executable) { + return nil + } + // No mips or s390x for you today + if strings.Contains(info.Name(), "mips") || strings.Contains(info.Name(), "s390x") { + return nil + } + + // Runs compressing in parallel since upx is single-threaded + errs.Go(func() error { + runAndStreamOutput("upx", "-9", path) + return nil + }) + + return nil + }) + + return errs.Wait() +} + +// Copies all built binaries to dist/release/ in preparation for creating the os packages +func (Release) Copy() error { + return filepath.Walk(RootPath+"/"+DIST+"/binaries/", func(path string, info os.FileInfo, err error) error { + // Only executable files + if !strings.Contains(info.Name(), Executable) { + return nil + } + + return copyFile(path, RootPath+"/"+DIST+"/release/"+info.Name()) + }) +} + +// Creates sha256 checksum files for each binary in dist/release/ +func (Release) Check() error { + p := RootPath + "/" + DIST + "/release/" + return filepath.Walk(p, func(path string, info os.FileInfo, err error) error { + if info.IsDir() { + return nil + } + + f, err := os.Create(p + info.Name() + ".sha256") + if err != nil { + return err + } + + hash, err := calculateSha256FileHash(path) + if err != nil { + return err + } + + _, err = f.WriteString(hash + " " + info.Name()) + if err != nil { + return err + } + + return f.Close() + }) +} + +// Creates a folder for each +func (Release) OsPackage() error { + p := RootPath + "/" + DIST + "/release/" + + // We first put all files in a map to then iterate over it since the walk function would otherwise also iterate + // over the newly created files, creating some kind of endless loop. + bins := make(map[string]os.FileInfo) + if err := filepath.Walk(p, func(path string, info os.FileInfo, err error) error { + if strings.Contains(info.Name(), ".sha256") || info.IsDir() { + return nil + } + bins[path] = info + return nil + }); err != nil { + return err + } + + for path, info := range bins { + folder := p + info.Name() + "-full/" + if err := os.Mkdir(folder, 0755); err != nil { + return err + } + if err := os.Rename(p+info.Name()+".sha256", folder+info.Name()+".sha256"); err != nil { + return err + } + if err := os.Rename(path, folder+info.Name()); err != nil { + return err + } + if err := copyFile(RootPath+"/config.yml.sample", folder+"config.yml.sample"); err != nil { + return err + } + if err := copyFile(RootPath+"/LICENSE", folder+"LICENSE"); err != nil { + return err + } + } + return nil +} + +// Creates a zip file from all os-package folders in dist/release +func (Release) Zip() error { + p := RootPath + "/" + DIST + "/release/" + if err := filepath.Walk(p, func(path string, info os.FileInfo, err error) error { + if !info.IsDir() || info.Name() == "release" { + return nil + } + + fmt.Printf("Zipping %s...\n", info.Name()) + + c := exec.Command("zip", "-r", RootPath+"/"+DIST+"/zip/"+info.Name(), ".", "-i", "*") + c.Dir = path + out, err := c.Output() + fmt.Print(string(out)) + return err + }); err != nil { + return err + } + + return nil +} + +// Creates a debian package from a built binary +func (Release) Deb() { + runAndStreamOutput( + "fpm", + "-s", "dir", + "-t", "deb", + "--url", "https://vikunja.io", + "-n", "vikunja", + "-v", PkgVersion, + "--license", "GPLv3", + "--directories", "/opt/vikunja", + "--after-install", "./build/after-install.sh", + "--description", "'Vikunja is an open-source todo application, written in Go. It lets you create lists,tasks and share them via teams or directly between users.'", + "-m", "maintainers@vikunja.io", + "-p", RootPath+"/"+Executable+"-"+Version+"_amd64.deb", + "./"+BinLocation+"=/opt/vikunja/vikunja", + "./config.yml.sample=/etc/vikunja/config.yml", + ) +} + +// Creates a debian repo structure +func (Release) Reprepro() { + runAndStreamOutput("reprepro_expect", "debian", "includedeb", "strech", RootPath+"/"+Executable+"-"+Version+"_amd64.deb") +} diff --git a/pkg/swagger/docs.go b/pkg/swagger/docs.go index 8e1c856aa2..2689a06073 100644 --- a/pkg/swagger/docs.go +++ b/pkg/swagger/docs.go @@ -6157,7 +6157,6 @@ var doc = `{ } }, "definitions": { -"code.vikunja.io.web.HTTPError": {"type": "object","properties": {"code": {"type": "integer"},"message": {"type": "string"}}}, "afero.File": { "type": "object" }, diff --git a/pkg/swagger/swagger.yaml b/pkg/swagger/swagger.yaml index 0b44c392f0..07bc079ed0 100644 --- a/pkg/swagger/swagger.yaml +++ b/pkg/swagger/swagger.yaml @@ -7,8 +7,7 @@ definitions: id: type: string info: - description: This can be used to supply extra information from an image provider - to clients + description: This can be used to supply extra information from an image provider to clients type: object thumb: type: string @@ -45,8 +44,7 @@ definitions: models.Bucket: properties: created: - description: A timestamp when this bucket was created. You cannot change this - value. + description: A timestamp when this bucket was created. You cannot change this value. type: string created_by: $ref: '#/definitions/user.User' @@ -68,8 +66,7 @@ definitions: minLength: 1 type: string updated: - description: A timestamp when this bucket was last updated. You cannot change - this value. + description: A timestamp when this bucket was last updated. You cannot change this value. type: string type: object models.BulkAssignees: @@ -96,8 +93,7 @@ definitions: description: BucketID is the ID of the kanban bucket this task belongs to. type: integer created: - description: A timestamp when this task was created. You cannot change this - value. + description: A timestamp when this task was created. You cannot change this value. type: string created_by: $ref: '#/definitions/user.User' @@ -126,8 +122,7 @@ definitions: description: The unique, numeric id of this task. type: integer identifier: - description: The task identifier, based on the list identifier and the task's - index + description: The task identifier, based on the list identifier and the task's index type: string index: description: The task index, calculated per list @@ -153,27 +148,22 @@ definitions: which also leaves a lot of room for rearranging and sorting later. type: number priority: - description: The task priority. Can be anything you want, it is possible to - sort by this later. + description: The task priority. Can be anything you want, it is possible to sort by this later. type: integer related_tasks: $ref: '#/definitions/models.RelatedTaskMap' description: All related tasks, grouped by their relation kind type: object reminder_dates: - description: An array of datetimes when the user wants to be reminded of the - task. + description: An array of datetimes when the user wants to be reminded of the task. items: type: string type: array repeat_after: - description: An amount in seconds this task repeats itself. If this is set, - when marking the task as done, it will mark itself as "undone" and then - increase all remindes and the due date by its amount. + description: An amount in seconds this task repeats itself. If this is set, when marking the task as done, it will mark itself as "undone" and then increase all remindes and the due date by its amount. type: integer repeat_from_current_date: - description: If specified, a repeating task will repeat from the current date - rather than the last set date. + description: If specified, a repeating task will repeat from the current date rather than the last set date. type: boolean start_date: description: When this task starts. @@ -189,15 +179,13 @@ definitions: minLength: 3 type: string updated: - description: A timestamp when this task was last updated. You cannot change - this value. + description: A timestamp when this task was last updated. You cannot change this value. type: string type: object models.Label: properties: created: - description: A timestamp when this label was created. You cannot change this - value. + description: A timestamp when this label was created. You cannot change this value. type: string created_by: $ref: '#/definitions/user.User' @@ -214,21 +202,18 @@ definitions: description: The unique, numeric id of this label. type: integer title: - description: The title of the lable. You'll see this one on tasks associated - with it. + description: The title of the lable. You'll see this one on tasks associated with it. maxLength: 250 minLength: 3 type: string updated: - description: A timestamp when this label was last updated. You cannot change - this value. + description: A timestamp when this label was last updated. You cannot change this value. type: string type: object models.LabelTask: properties: created: - description: A timestamp when this task was created. You cannot change this - value. + description: A timestamp when this task was created. You cannot change this value. type: string label_id: description: The label id you want to associate with a task. @@ -245,8 +230,7 @@ definitions: models.LinkSharing: properties: created: - description: A timestamp when this list was shared. You cannot change this - value. + description: A timestamp when this list was shared. You cannot change this value. type: string hash: description: The public id to get this shared list @@ -256,8 +240,7 @@ definitions: type: integer right: default: 0 - description: The right this list is shared with. 0 = Read only, 1 = Read & - Write, 2 = Admin. See the docs for more details. + description: The right this list is shared with. 0 = Read only, 1 = Read & Write, 2 = Admin. See the docs for more details. maximum: 2 type: integer shared_by: @@ -266,25 +249,20 @@ definitions: type: object sharing_type: default: 0 - description: The kind of this link. 0 = undefined, 1 = without password, 2 - = with password (currently not implemented). + description: The kind of this link. 0 = undefined, 1 = without password, 2 = with password (currently not implemented). maximum: 2 type: integer updated: - description: A timestamp when this share was last updated. You cannot change - this value. + description: A timestamp when this share was last updated. You cannot change this value. type: string type: object models.List: properties: background_information: - description: Holds extra information about the background set since some background - providers require attribution or similar. If not null, the background can - be accessed at /lists/{listID}/background + description: Holds extra information about the background set since some background providers require attribution or similar. If not null, the background can be accessed at /lists/{listID}/background type: object created: - description: A timestamp when this list was created. You cannot change this - value. + description: A timestamp when this list was created. You cannot change this value. type: string description: description: The description of the list. @@ -316,8 +294,7 @@ definitions: minLength: 3 type: string updated: - description: A timestamp when this list was last updated. You cannot change - this value. + description: A timestamp when this list was last updated. You cannot change this value. type: string type: object models.ListDuplicate: @@ -333,21 +310,18 @@ definitions: models.ListUser: properties: created: - description: A timestamp when this relation was created. You cannot change - this value. + description: A timestamp when this relation was created. You cannot change this value. type: string id: description: The unique, numeric id of this list <-> user relation. type: integer right: default: 0 - description: The right this user has. 0 = Read only, 1 = Read & Write, 2 = - Admin. See the docs for more details. + description: The right this user has. 0 = Read only, 1 = Read & Write, 2 = Admin. See the docs for more details. maximum: 2 type: integer updated: - description: A timestamp when this relation was last updated. You cannot change - this value. + description: A timestamp when this relation was last updated. You cannot change this value. type: string user_id: description: The username. @@ -362,8 +336,7 @@ definitions: models.Namespace: properties: created: - description: A timestamp when this namespace was created. You cannot change - this value. + description: A timestamp when this namespace was created. You cannot change this value. type: string description: description: The description of the namespace @@ -388,28 +361,24 @@ definitions: minLength: 5 type: string updated: - description: A timestamp when this namespace was last updated. You cannot - change this value. + description: A timestamp when this namespace was last updated. You cannot change this value. type: string type: object models.NamespaceUser: properties: created: - description: A timestamp when this relation was created. You cannot change - this value. + description: A timestamp when this relation was created. You cannot change this value. type: string id: description: The unique, numeric id of this namespace <-> user relation. type: integer right: default: 0 - description: The right this user has. 0 = Read only, 1 = Read & Write, 2 = - Admin. See the docs for more details. + description: The right this user has. 0 = Read only, 1 = Read & Write, 2 = Admin. See the docs for more details. maximum: 2 type: integer updated: - description: A timestamp when this relation was last updated. You cannot change - this value. + description: A timestamp when this relation was last updated. You cannot change this value. type: string user_id: description: The username. @@ -418,8 +387,7 @@ definitions: models.NamespaceWithLists: properties: created: - description: A timestamp when this namespace was created. You cannot change - this value. + description: A timestamp when this namespace was created. You cannot change this value. type: string description: description: The description of the namespace @@ -448,8 +416,7 @@ definitions: minLength: 5 type: string updated: - description: A timestamp when this namespace was last updated. You cannot - change this value. + description: A timestamp when this namespace was last updated. You cannot change this value. type: string type: object models.RelatedTaskMap: @@ -474,8 +441,7 @@ definitions: description: BucketID is the ID of the kanban bucket this task belongs to. type: integer created: - description: A timestamp when this task was created. You cannot change this - value. + description: A timestamp when this task was created. You cannot change this value. type: string created_by: $ref: '#/definitions/user.User' @@ -504,8 +470,7 @@ definitions: description: The unique, numeric id of this task. type: integer identifier: - description: The task identifier, based on the list identifier and the task's - index + description: The task identifier, based on the list identifier and the task's index type: string index: description: The task index, calculated per list @@ -531,27 +496,22 @@ definitions: which also leaves a lot of room for rearranging and sorting later. type: number priority: - description: The task priority. Can be anything you want, it is possible to - sort by this later. + description: The task priority. Can be anything you want, it is possible to sort by this later. type: integer related_tasks: $ref: '#/definitions/models.RelatedTaskMap' description: All related tasks, grouped by their relation kind type: object reminder_dates: - description: An array of datetimes when the user wants to be reminded of the - task. + description: An array of datetimes when the user wants to be reminded of the task. items: type: string type: array repeat_after: - description: An amount in seconds this task repeats itself. If this is set, - when marking the task as done, it will mark itself as "undone" and then - increase all remindes and the due date by its amount. + description: An amount in seconds this task repeats itself. If this is set, when marking the task as done, it will mark itself as "undone" and then increase all remindes and the due date by its amount. type: integer repeat_from_current_date: - description: If specified, a repeating task will repeat from the current date - rather than the last set date. + description: If specified, a repeating task will repeat from the current date rather than the last set date. type: boolean start_date: description: When this task starts. @@ -562,8 +522,7 @@ definitions: minLength: 3 type: string updated: - description: A timestamp when this task was last updated. You cannot change - this value. + description: A timestamp when this task was last updated. You cannot change this value. type: string type: object models.TaskAssginee: @@ -605,8 +564,7 @@ definitions: models.TaskRelation: properties: created: - description: A timestamp when this label was created. You cannot change this - value. + description: A timestamp when this label was created. You cannot change this value. type: string created_by: $ref: '#/definitions/user.User' @@ -625,8 +583,7 @@ definitions: models.Team: properties: created: - description: A timestamp when this relation was created. You cannot change - this value. + description: A timestamp when this relation was created. You cannot change this value. type: string created_by: $ref: '#/definitions/user.User' @@ -649,83 +606,71 @@ definitions: minLength: 5 type: string updated: - description: A timestamp when this relation was last updated. You cannot change - this value. + description: A timestamp when this relation was last updated. You cannot change this value. type: string type: object models.TeamList: properties: created: - description: A timestamp when this relation was created. You cannot change - this value. + description: A timestamp when this relation was created. You cannot change this value. type: string id: description: The unique, numeric id of this list <-> team relation. type: integer right: default: 0 - description: The right this team has. 0 = Read only, 1 = Read & Write, 2 = - Admin. See the docs for more details. + description: The right this team has. 0 = Read only, 1 = Read & Write, 2 = Admin. See the docs for more details. maximum: 2 type: integer team_id: description: The team id. type: integer updated: - description: A timestamp when this relation was last updated. You cannot change - this value. + description: A timestamp when this relation was last updated. You cannot change this value. type: string type: object models.TeamMember: properties: admin: - description: Whether or not the member is an admin of the team. See the docs - for more about what a team admin can do + description: Whether or not the member is an admin of the team. See the docs for more about what a team admin can do type: boolean created: - description: A timestamp when this relation was created. You cannot change - this value. + description: A timestamp when this relation was created. You cannot change this value. type: string id: description: The unique, numeric id of this team member relation. type: integer username: - description: The username of the member. We use this to prevent automated - user id entering. + description: The username of the member. We use this to prevent automated user id entering. type: string type: object models.TeamNamespace: properties: created: - description: A timestamp when this relation was created. You cannot change - this value. + description: A timestamp when this relation was created. You cannot change this value. type: string id: description: The unique, numeric id of this namespace <-> team relation. type: integer right: default: 0 - description: The right this team has. 0 = Read only, 1 = Read & Write, 2 = - Admin. See the docs for more details. + description: The right this team has. 0 = Read only, 1 = Read & Write, 2 = Admin. See the docs for more details. maximum: 2 type: integer team_id: description: The team id. type: integer updated: - description: A timestamp when this relation was last updated. You cannot change - this value. + description: A timestamp when this relation was last updated. You cannot change this value. type: string type: object models.TeamUser: properties: admin: - description: Whether or not the member is an admin of the team. See the docs - for more about what a team admin can do + description: Whether or not the member is an admin of the team. See the docs for more about what a team admin can do type: boolean created: - description: A timestamp when this task was created. You cannot change this - value. + description: A timestamp when this task was created. You cannot change this value. type: string email: description: The user's email address. @@ -735,8 +680,7 @@ definitions: description: The unique, numeric id of this user. type: integer updated: - description: A timestamp when this task was last updated. You cannot change - this value. + description: A timestamp when this task was last updated. You cannot change this value. type: string username: description: The username of the user. Is always unique. @@ -747,8 +691,7 @@ definitions: models.TeamWithRight: properties: created: - description: A timestamp when this relation was created. You cannot change - this value. + description: A timestamp when this relation was created. You cannot change this value. type: string created_by: $ref: '#/definitions/user.User' @@ -773,15 +716,13 @@ definitions: right: type: integer updated: - description: A timestamp when this relation was last updated. You cannot change - this value. + description: A timestamp when this relation was last updated. You cannot change this value. type: string type: object models.UserWithRight: properties: created: - description: A timestamp when this task was created. You cannot change this - value. + description: A timestamp when this task was created. You cannot change this value. type: string email: description: The user's email address. @@ -793,8 +734,7 @@ definitions: right: type: integer updated: - description: A timestamp when this task was last updated. You cannot change - this value. + description: A timestamp when this task was last updated. You cannot change this value. type: string username: description: The username of the user. Is always unique. @@ -817,8 +757,7 @@ definitions: description: The unique, numeric id of this user. type: integer password: - description: The user's password in clear text. Only used when registering - the user. + description: The user's password in clear text. Only used when registering the user. maxLength: 250 minLength: 8 type: string @@ -873,8 +812,7 @@ definitions: user.TOTP: properties: enabled: - description: The totp entry will only be enabled after the user verified they - have a working totp setup. + description: The totp entry will only be enabled after the user verified they have a working totp setup. type: boolean secret: type: string @@ -890,8 +828,7 @@ definitions: user.User: properties: created: - description: A timestamp when this task was created. You cannot change this - value. + description: A timestamp when this task was created. You cannot change this value. type: string email: description: The user's email address. @@ -901,8 +838,7 @@ definitions: description: The unique, numeric id of this user. type: integer updated: - description: A timestamp when this task was last updated. You cannot change - this value. + description: A timestamp when this task was last updated. You cannot change this value. type: string username: description: The username of the user. Is always unique. @@ -1062,8 +998,7 @@ paths: - list /backgrounds/unsplash/image/{image}/thumb: get: - description: Get an unsplash thumbnail image. The thumbnail is cropped to a - max width of 200px. **Returns json on error.** + description: Get an unsplash thumbnail image. The thumbnail is cropped to a max width of 200px. **Returns json on error.** parameters: - description: Unsplash Image ID in: path @@ -1098,8 +1033,7 @@ paths: in: query name: s type: string - - description: The page number. Used for pagination. If not provided, the first - page of results is returned. + - description: The page number. Used for pagination. If not provided, the first page of results is returned. in: query name: p type: integer @@ -1123,8 +1057,7 @@ paths: - list /info: get: - description: Returns the version, frontendurl, motd and various settings of - Vikunja + description: Returns the version, frontendurl, motd and various settings of Vikunja produces: - application/json responses: @@ -1139,16 +1072,13 @@ paths: get: consumes: - application/json - description: Returns all labels which are either created by the user or associated - with a task the user has at least read-access to. + description: Returns all labels which are either created by the user or associated with a task the user has at least read-access to. parameters: - - description: The page number. Used for pagination. If not provided, the first - page of results is returned. + - description: The page number. Used for pagination. If not provided, the first page of results is returned. in: query name: page type: integer - - description: The maximum number of items per page. Note this parameter is - limited by the configured maximum of items per page. + - description: The maximum number of items per page. Note this parameter is limited by the configured maximum of items per page. in: query name: per_page type: integer @@ -1209,8 +1139,7 @@ paths: delete: consumes: - application/json - description: Delete an existing label. The user needs to be the creator of the - label to be able to do this. + description: Delete an existing label. The user needs to be the creator of the label to be able to do this. parameters: - description: Label ID in: path @@ -1278,8 +1207,7 @@ paths: put: consumes: - application/json - description: Update an existing label. The user needs to be the creator of the - label to be able to do this. + description: Update an existing label. The user needs to be the creator of the label to be able to do this. parameters: - description: Label ID in: path @@ -1326,13 +1254,11 @@ paths: - application/json description: Returns all lists a user has access to. parameters: - - description: The page number. Used for pagination. If not provided, the first - page of results is returned. + - description: The page number. Used for pagination. If not provided, the first page of results is returned. in: query name: page type: integer - - description: The maximum number of items per page. Note this parameter is - limited by the configured maximum of items per page. + - description: The maximum number of items per page. Note this parameter is limited by the configured maximum of items per page. in: query name: per_page type: integer @@ -1631,8 +1557,7 @@ paths: get: consumes: - application/json - description: Returns all kanban buckets with belong to a list including their - tasks. + description: Returns all kanban buckets with belong to a list including their tasks. parameters: - description: List Id in: path @@ -1701,8 +1626,7 @@ paths: get: consumes: - application/json - description: Lists all users (without emailadresses). Also possible to search - for a specific user. + description: Lists all users (without emailadresses). Also possible to search for a specific user. parameters: - description: Search for a user by its name. in: query @@ -1750,13 +1674,11 @@ paths: name: id required: true type: integer - - description: The page number. Used for pagination. If not provided, the first - page of results is returned. + - description: The page number. Used for pagination. If not provided, the first page of results is returned. in: query name: page type: integer - - description: The maximum number of items per page. Note this parameter is - limited by the configured maximum of items per page. + - description: The maximum number of items per page. Note this parameter is limited by the configured maximum of items per page. in: query name: per_page type: integer @@ -1841,13 +1763,11 @@ paths: name: id required: true type: integer - - description: The page number. Used for pagination. If not provided, the first - page of results is returned. + - description: The page number. Used for pagination. If not provided, the first page of results is returned. in: query name: page type: integer - - description: The maximum number of items per page. Note this parameter is - limited by the configured maximum of items per page. + - description: The maximum number of items per page. Note this parameter is limited by the configured maximum of items per page. in: query name: per_page type: integer @@ -1932,13 +1852,11 @@ paths: name: list required: true type: integer - - description: The page number. Used for pagination. If not provided, the first - page of results is returned. + - description: The page number. Used for pagination. If not provided, the first page of results is returned. in: query name: page type: integer - - description: The maximum number of items per page. Note this parameter is - limited by the configured maximum of items per page. + - description: The maximum number of items per page. Note this parameter is limited by the configured maximum of items per page. in: query name: per_page type: integer @@ -1967,8 +1885,7 @@ paths: put: consumes: - application/json - description: Share a list via link. The user needs to have write-access to the - list to be able do this. + description: Share a list via link. The user needs to have write-access to the list to be able do this. parameters: - description: List ID in: path @@ -2013,8 +1930,7 @@ paths: delete: consumes: - application/json - description: Remove a link share. The user needs to have write-access to the - list to be able do this. + description: Remove a link share. The user needs to have write-access to the list to be able do this. parameters: - description: List ID in: path @@ -2093,8 +2009,7 @@ paths: delete: consumes: - application/json - description: Deletes an existing kanban bucket and dissociates all of its task. - It does not delete any tasks. You cannot delete the last bucket on a list. + description: Deletes an existing kanban bucket and dissociates all of its task. It does not delete any tasks. You cannot delete the last bucket on a list. parameters: - description: List Id in: path @@ -2175,10 +2090,7 @@ paths: put: consumes: - application/json - description: Copies the list, tasks, files, kanban data, assignees, comments, - attachments, lables, relations, backgrounds, user/team rights and link shares - from one list to a new namespace. The user needs read access in the list and - write access in the namespace of the new list. + description: Copies the list, tasks, files, kanban data, assignees, comments, attachments, lables, relations, backgrounds, user/team rights and link shares from one list to a new namespace. The user needs read access in the list and write access in the namespace of the new list. parameters: - description: The list ID to duplicate in: path @@ -2226,13 +2138,11 @@ paths: name: listID required: true type: integer - - description: The page number. Used for pagination. If not provided, the first - page of results is returned. + - description: The page number. Used for pagination. If not provided, the first page of results is returned. in: query name: page type: integer - - description: The maximum number of items per page. Note this parameter is - limited by the configured maximum of items per page. + - description: The maximum number of items per page. Note this parameter is limited by the configured maximum of items per page. in: query name: per_page type: integer @@ -2240,22 +2150,15 @@ paths: in: query name: s type: string - - description: The sorting parameter. You can pass this multiple times to get - the tasks ordered by multiple different parametes, along with `order_by`. - Possible values to sort by are `id`, `title`, `description`, `done`, `done_at`, - `due_date`, `created_by_id`, `list_id`, `repeat_after`, `priority`, `start_date`, - `end_date`, `hex_color`, `percent_done`, `uid`, `created`, `updated`. Default - is `id`. + - description: The sorting parameter. You can pass this multiple times to get the tasks ordered by multiple different parametes, along with `order_by`. Possible values to sort by are `id`, `title`, `description`, `done`, `done_at`, `due_date`, `created_by_id`, `list_id`, `repeat_after`, `priority`, `start_date`, `end_date`, `hex_color`, `percent_done`, `uid`, `created`, `updated`. Default is `id`. in: query name: sort_by type: string - - description: The ordering parameter. Possible values to order by are `asc` - or `desc`. Default is `asc`. + - description: The ordering parameter. Possible values to order by are `asc` or `desc`. Default is `asc`. in: query name: order_by type: string - - description: The name of the field to filter by. Accepts an array for multiple - filters which will be chanied together, all supplied filter must match. + - description: The name of the field to filter by. Accepts an array for multiple filters which will be chanied together, all supplied filter must match. in: query name: filter_by type: string @@ -2263,19 +2166,15 @@ paths: in: query name: filter_value type: string - - description: The comparator to use for a filter. Available values are `equals`, - `greater`, `greater_equals`, `less` and `less_equals`. Defaults to `equals` + - description: The comparator to use for a filter. Available values are `equals`, `greater`, `greater_equals`, `less` and `less_equals`. Defaults to `equals` in: query name: filter_comparator type: string - - description: The concatinator to use for filters. Available values are `and` - or `or`. Defaults to `or`. + - description: The concatinator to use for filters. Available values are `and` or `or`. Defaults to `or`. in: query name: filter_concat type: string - - description: If set to true the result will include filtered fields whose - value is set to `null`. Available values are `true` or `false`. Defaults - to `false`. + - description: If set to true the result will include filtered fields whose value is set to `null`. Available values are `true` or `false`. Defaults to `false`. in: query name: filter_include_nulls type: string @@ -2299,8 +2198,7 @@ paths: - task /lists/{listID}/teams/{teamID}: delete: - description: Delets a team from a list. The team won't have access to the list - anymore. + description: Delets a team from a list. The team won't have access to the list anymore. parameters: - description: List ID in: path @@ -2339,8 +2237,7 @@ paths: post: consumes: - application/json - description: Update a team <-> list relation. Mostly used to update the right - that team has. + description: Update a team <-> list relation. Mostly used to update the right that team has. parameters: - description: List ID in: path @@ -2384,8 +2281,7 @@ paths: - sharing /lists/{listID}/users/{userID}: delete: - description: Delets a user from a list. The user won't have access to the list - anymore. + description: Delets a user from a list. The user won't have access to the list anymore. parameters: - description: List ID in: path @@ -2424,8 +2320,7 @@ paths: post: consumes: - application/json - description: Update a user <-> list relation. Mostly used to update the right - that user has. + description: Update a user <-> list relation. Mostly used to update the right that user has. parameters: - description: List ID in: path @@ -2503,8 +2398,7 @@ paths: - user /migration/todoist/auth: get: - description: Returns the auth url where the user needs to get its auth code. - This code can then be used to migrate everything from todoist to Vikunja. + description: Returns the auth url where the user needs to get its auth code. This code can then be used to migrate everything from todoist to Vikunja. produces: - application/json responses: @@ -2525,11 +2419,9 @@ paths: post: consumes: - application/json - description: Migrates all projects, tasks, notes, reminders, subtasks and files - from todoist to vikunja. + description: Migrates all projects, tasks, notes, reminders, subtasks and files from todoist to vikunja. parameters: - - description: The auth code previously obtained from the auth url. See the - docs for /migration/todoist/auth. + - description: The auth code previously obtained from the auth url. See the docs for /migration/todoist/auth. in: body name: migrationCode required: true @@ -2553,9 +2445,7 @@ paths: - migration /migration/todoist/status: get: - description: Returns if the current user already did the migation or not. This - is useful to show a confirmation message in the frontend if the user is trying - to do the same migration again. + description: Returns if the current user already did the migation or not. This is useful to show a confirmation message in the frontend if the user is trying to do the same migration again. produces: - application/json responses: @@ -2574,8 +2464,7 @@ paths: - migration /migration/wunderlist/auth: get: - description: Returns the auth url where the user needs to get its auth code. - This code can then be used to migrate everything from wunderlist to Vikunja. + description: Returns the auth url where the user needs to get its auth code. This code can then be used to migrate everything from wunderlist to Vikunja. produces: - application/json responses: @@ -2596,11 +2485,9 @@ paths: post: consumes: - application/json - description: Migrates all folders, lists, tasks, notes, reminders, subtasks - and files from wunderlist to vikunja. + description: Migrates all folders, lists, tasks, notes, reminders, subtasks and files from wunderlist to vikunja. parameters: - - description: The auth code previously obtained from the auth url. See the - docs for /migration/wunderlist/auth. + - description: The auth code previously obtained from the auth url. See the docs for /migration/wunderlist/auth. in: body name: migrationCode required: true @@ -2624,9 +2511,7 @@ paths: - migration /migration/wunderlist/status: get: - description: Returns if the current user already did the migation or not. This - is useful to show a confirmation message in the frontend if the user is trying - to do the same migration again. + description: Returns if the current user already did the migation or not. This is useful to show a confirmation message in the frontend if the user is trying to do the same migration again. produces: - application/json responses: @@ -2690,13 +2575,11 @@ paths: - application/json description: Returns all namespaces a user has access to. parameters: - - description: The page number. Used for pagination. If not provided, the first - page of results is returned. + - description: The page number. Used for pagination. If not provided, the first page of results is returned. in: query name: page type: integer - - description: The maximum number of items per page. Note this parameter is - limited by the configured maximum of items per page. + - description: The maximum number of items per page. Note this parameter is limited by the configured maximum of items per page. in: query name: per_page type: integer @@ -2865,21 +2748,18 @@ paths: get: consumes: - application/json - description: Returns a namespace with all teams which have access on a given - namespace. + description: Returns a namespace with all teams which have access on a given namespace. parameters: - description: Namespace ID in: path name: id required: true type: integer - - description: The page number. Used for pagination. If not provided, the first - page of results is returned. + - description: The page number. Used for pagination. If not provided, the first page of results is returned. in: query name: page type: integer - - description: The maximum number of items per page. Note this parameter is - limited by the configured maximum of items per page. + - description: The maximum number of items per page. Note this parameter is limited by the configured maximum of items per page. in: query name: per_page type: integer @@ -2957,21 +2837,18 @@ paths: get: consumes: - application/json - description: Returns a namespace with all users which have access on a given - namespace. + description: Returns a namespace with all users which have access on a given namespace. parameters: - description: Namespace ID in: path name: id required: true type: integer - - description: The page number. Used for pagination. If not provided, the first - page of results is returned. + - description: The page number. Used for pagination. If not provided, the first page of results is returned. in: query name: page type: integer - - description: The maximum number of items per page. Note this parameter is - limited by the configured maximum of items per page. + - description: The maximum number of items per page. Note this parameter is limited by the configured maximum of items per page. in: query name: per_page type: integer @@ -3049,8 +2926,7 @@ paths: put: consumes: - application/json - description: Creates a new list in a given namespace. The user needs write-access - to the namespace. + description: Creates a new list in a given namespace. The user needs write-access to the namespace. parameters: - description: Namespace ID in: path @@ -3089,8 +2965,7 @@ paths: - list /namespaces/{namespaceID}/teams/{teamID}: delete: - description: Delets a team from a namespace. The team won't have access to the - namespace anymore. + description: Delets a team from a namespace. The team won't have access to the namespace anymore. parameters: - description: Namespace ID in: path @@ -3129,8 +3004,7 @@ paths: post: consumes: - application/json - description: Update a team <-> namespace relation. Mostly used to update the - right that team has. + description: Update a team <-> namespace relation. Mostly used to update the right that team has. parameters: - description: Namespace ID in: path @@ -3174,8 +3048,7 @@ paths: - sharing /namespaces/{namespaceID}/users/{userID}: delete: - description: Delets a user from a namespace. The user won't have access to the - namespace anymore. + description: Delets a user from a namespace. The user won't have access to the namespace anymore. parameters: - description: Namespace ID in: path @@ -3214,8 +3087,7 @@ paths: post: consumes: - application/json - description: Update a user <-> namespace relation. Mostly used to update the - right that user has. + description: Update a user <-> namespace relation. Mostly used to update the right that user has. parameters: - description: Namespace ID in: path @@ -3277,8 +3149,7 @@ paths: schema: $ref: '#/definitions/user.User' "400": - description: No or invalid user register object provided / User already - exists. + description: No or invalid user register object provided / User already exists. schema: $ref: '#/definitions/web.HTTPError' "500": @@ -3384,9 +3255,7 @@ paths: post: consumes: - application/json - description: Updates a task. This includes marking it as done. Assignees you - pass will be updated, see their individual endpoints for more details on how - this is done. To update labels, see the description of the endpoint. + description: Updates a task. This includes marking it as done. Assignees you pass will be updated, see their individual endpoints for more details on how this is done. To update labels, see the description of the endpoint. parameters: - description: Task ID in: path @@ -3434,13 +3303,11 @@ paths: name: id required: true type: integer - - description: The page number. Used for pagination. If not provided, the first - page of results is returned. + - description: The page number. Used for pagination. If not provided, the first page of results is returned. in: query name: page type: integer - - description: The maximum number of items per page. Note this parameter is - limited by the configured maximum of items per page. + - description: The maximum number of items per page. Note this parameter is limited by the configured maximum of items per page. in: query name: per_page type: integer @@ -3473,8 +3340,7 @@ paths: put: consumes: - multipart/form-data - description: Upload a task attachment. You can pass multiple files with the - files form param. + description: Upload a task attachment. You can pass multiple files with the files form param. parameters: - description: Task ID in: path @@ -3598,13 +3464,11 @@ paths: name: task required: true type: integer - - description: The page number. Used for pagination. If not provided, the first - page of results is returned. + - description: The page number. Used for pagination. If not provided, the first page of results is returned. in: query name: page type: integer - - description: The maximum number of items per page. Note this parameter is - limited by the configured maximum of items per page. + - description: The maximum number of items per page. Note this parameter is limited by the configured maximum of items per page. in: query name: per_page type: integer @@ -3633,8 +3497,7 @@ paths: put: consumes: - application/json - description: Add a label to a task. The user needs to have write-access to the - list to be able do this. + description: Add a label to a task. The user needs to have write-access to the list to be able do this. parameters: - description: Task ID in: path @@ -3679,8 +3542,7 @@ paths: delete: consumes: - application/json - description: Remove a label from a task. The user needs to have write-access - to the list to be able do this. + description: Remove a label from a task. The user needs to have write-access to the list to be able do this. parameters: - description: Task ID in: path @@ -3722,13 +3584,11 @@ paths: - application/json description: Returns an array with all assignees for this task. parameters: - - description: The page number. Used for pagination. If not provided, the first - page of results is returned. + - description: The page number. Used for pagination. If not provided, the first page of results is returned. in: query name: page type: integer - - description: The maximum number of items per page. Note this parameter is - limited by the configured maximum of items per page. + - description: The maximum number of items per page. Note this parameter is limited by the configured maximum of items per page. in: query name: per_page type: integer @@ -3762,8 +3622,7 @@ paths: put: consumes: - application/json - description: Adds a new assignee to a task. The assignee needs to have access - to the list, the doer must be able to edit this task. + description: Adds a new assignee to a task. The assignee needs to have access to the list, the doer must be able to edit this task. parameters: - description: The assingee object in: body @@ -3836,10 +3695,7 @@ paths: post: consumes: - application/json - description: Adds multiple new assignees to a task. The assignee needs to have - access to the list, the doer must be able to edit this task. Every user not - in the list will be unassigned from the task, pass an empty array to unassign - everyone. + description: Adds multiple new assignees to a task. The assignee needs to have access to the list, the doer must be able to edit this task. Every user not in the list will be unassigned from the task, pass an empty array to unassign everyone. parameters: - description: The array of assignees in: body @@ -3876,8 +3732,7 @@ paths: get: consumes: - application/json - description: Get all task comments. The user doing this need to have at least - read access to the task. + description: Get all task comments. The user doing this need to have at least read access to the task. parameters: - description: Task ID in: path @@ -3905,8 +3760,7 @@ paths: put: consumes: - application/json - description: Create a new task comment. The user doing this need to have at - least write access to the task this comment should belong to. + description: Create a new task comment. The user doing this need to have at least write access to the task this comment should belong to. parameters: - description: The task comment object in: body @@ -3943,8 +3797,7 @@ paths: delete: consumes: - application/json - description: Remove a task comment. The user doing this need to have at least - write access to the task this comment belongs to. + description: Remove a task comment. The user doing this need to have at least write access to the task this comment belongs to. parameters: - description: Task ID in: path @@ -3983,8 +3836,7 @@ paths: get: consumes: - application/json - description: Remove a task comment. The user doing this need to have at least - read access to the task this comment belongs to. + description: Remove a task comment. The user doing this need to have at least read access to the task this comment belongs to. parameters: - description: Task ID in: path @@ -4023,8 +3875,7 @@ paths: post: consumes: - application/json - description: Update an existing task comment. The user doing this need to have - at least write access to the task this comment belongs to. + description: Update an existing task comment. The user doing this need to have at least write access to the task this comment belongs to. parameters: - description: Task ID in: path @@ -4064,10 +3915,7 @@ paths: post: consumes: - application/json - description: Updates all labels on a task. Every label which is not passed but - exists on the task will be deleted. Every label which does not exist on the - task will be added. All labels which are passed and already exist on the task - won't be touched. + description: Updates all labels on a task. Every label which is not passed but exists on the task will be deleted. Every label which does not exist on the task will be added. All labels which are passed and already exist on the task won't be touched. parameters: - description: The array of labels in: body @@ -4143,10 +3991,7 @@ paths: put: consumes: - application/json - description: Creates a new relation between two tasks. The user needs to have - update rights on the base task and at least read rights on the other task. - Both tasks do not need to be on the same list. Take a look at the docs for - available task relation kinds. + description: Creates a new relation between two tasks. The user needs to have update rights on the base task and at least read rights on the other task. Both tasks do not need to be on the same list. Take a look at the docs for available task relation kinds. parameters: - description: The relation object in: body @@ -4185,13 +4030,11 @@ paths: - application/json description: Returns all tasks on any list the user has access to. parameters: - - description: The page number. Used for pagination. If not provided, the first - page of results is returned. + - description: The page number. Used for pagination. If not provided, the first page of results is returned. in: query name: page type: integer - - description: The maximum number of items per page. Note this parameter is - limited by the configured maximum of items per page. + - description: The maximum number of items per page. Note this parameter is limited by the configured maximum of items per page. in: query name: per_page type: integer @@ -4199,22 +4042,15 @@ paths: in: query name: s type: string - - description: The sorting parameter. You can pass this multiple times to get - the tasks ordered by multiple different parametes, along with `order_by`. - Possible values to sort by are `id`, `text`, `description`, `done`, `done_at`, - `due_date`, `created_by_id`, `list_id`, `repeat_after`, `priority`, `start_date`, - `end_date`, `hex_color`, `percent_done`, `uid`, `created`, `updated`. Default - is `id`. + - description: The sorting parameter. You can pass this multiple times to get the tasks ordered by multiple different parametes, along with `order_by`. Possible values to sort by are `id`, `text`, `description`, `done`, `done_at`, `due_date`, `created_by_id`, `list_id`, `repeat_after`, `priority`, `start_date`, `end_date`, `hex_color`, `percent_done`, `uid`, `created`, `updated`. Default is `id`. in: query name: sort_by type: string - - description: The ordering parameter. Possible values to order by are `asc` - or `desc`. Default is `asc`. + - description: The ordering parameter. Possible values to order by are `asc` or `desc`. Default is `asc`. in: query name: order_by type: string - - description: The name of the field to filter by. Accepts an array for multiple - filters which will be chanied together, all supplied filter must match. + - description: The name of the field to filter by. Accepts an array for multiple filters which will be chanied together, all supplied filter must match. in: query name: filter_by type: string @@ -4222,13 +4058,11 @@ paths: in: query name: filter_value type: string - - description: The comparator to use for a filter. Available values are `equals`, - `greater`, `greater_equals`, `less` and `less_equals`. Defaults to `equals` + - description: The comparator to use for a filter. Available values are `equals`, `greater`, `greater_equals`, `less` and `less_equals`. Defaults to `equals` in: query name: filter_comparator type: string - - description: The concatinator to use for filters. Available values are `and` - or `or`. Defaults to `or`. + - description: The concatinator to use for filters. Available values are `and` or `or`. Defaults to `or`. in: query name: filter_concat type: string @@ -4254,12 +4088,9 @@ paths: post: consumes: - application/json - description: 'Updates a bunch of tasks at once. This includes marking them as - done. Note: although you could supply another ID, it will be ignored. Use - task_ids instead.' + description: 'Updates a bunch of tasks at once. This includes marking them as done. Note: although you could supply another ID, it will be ignored. Use task_ids instead.' parameters: - - description: The task object. Looks like a normal task, the only difference - is it uses an array of list_ids to update. + - description: The task object. Looks like a normal task, the only difference is it uses an array of list_ids to update. in: body name: task required: true @@ -4295,13 +4126,11 @@ paths: - application/json description: Returns all teams the current user is part of. parameters: - - description: The page number. Used for pagination. If not provided, the first - page of results is returned. + - description: The page number. Used for pagination. If not provided, the first page of results is returned. in: query name: page type: integer - - description: The maximum number of items per page. Note this parameter is - limited by the configured maximum of items per page. + - description: The maximum number of items per page. Note this parameter is limited by the configured maximum of items per page. in: query name: per_page type: integer @@ -4330,8 +4159,7 @@ paths: put: consumes: - application/json - description: Creates a new team in a given namespace. The user needs write-access - to the namespace. + description: Creates a new team in a given namespace. The user needs write-access to the namespace. parameters: - description: The team you want to create. in: body @@ -4361,8 +4189,7 @@ paths: - team /teams/{id}: delete: - description: Delets a team. This will also remove the access for all users in - that team. + description: Delets a team. This will also remove the access for all users in that team. parameters: - description: Team ID in: path @@ -4498,8 +4325,7 @@ paths: - team /teams/{id}/members/{userID}: delete: - description: Remove a user from a team. This will also revoke any access this - user might have via that team. + description: Remove a user from a team. This will also revoke any access this user might have via that team. parameters: - description: Team ID in: path @@ -4682,8 +4508,7 @@ paths: post: consumes: - application/json - description: Requests a token to reset a users password. The token is sent via - email. + description: Requests a token to reset a users password. The token is sent via email. parameters: - description: The username of the user to request a token for. in: body @@ -4737,8 +4562,7 @@ paths: post: consumes: - application/json - description: Changes the user avatar. Valid types are gravatar (uses the user - email), upload, initials, default. + description: Changes the user avatar. Valid types are gravatar (uses the user email), upload, initials, default. parameters: - description: The user's avatar setting in: body @@ -4770,8 +4594,7 @@ paths: put: consumes: - multipart/form-data - description: Upload a user avatar. This will also set the user's avatar provider - to "upload" + description: Upload a user avatar. This will also set the user's avatar provider to "upload" parameters: - description: The avatar as single file. in: formData @@ -4842,8 +4665,7 @@ paths: get: consumes: - application/json - description: Returns the current user totp setting or an error if it is not - enabled. + description: Returns the current user totp setting or an error if it is not enabled. produces: - application/json responses: @@ -4900,8 +4722,7 @@ paths: post: consumes: - application/json - description: Enables a previously enrolled totp setting by providing a totp - passcode. + description: Enables a previously enrolled totp setting by providing a totp passcode. parameters: - description: The totp passcode. in: body @@ -4941,9 +4762,7 @@ paths: post: consumes: - application/json - description: Creates an initial setup for the user in the db. After this step, - the user needs to verify they have a working totp setup with the "enable totp" - endpoint. + description: Creates an initial setup for the user in the db. After this step, the user needs to verify they have a working totp setup with the "enable totp" endpoint. produces: - application/json responses: @@ -5012,8 +4831,7 @@ paths: get: consumes: - application/json - description: Lists all users (without emailadresses). Also possible to search - for a specific user. + description: Lists all users (without emailadresses). Also possible to search for a specific user. parameters: - description: Search for a user by its name. in: query diff --git a/pkg/version/version.go b/pkg/version/version.go index 6e55a28ba4..43fa4e6092 100644 --- a/pkg/version/version.go +++ b/pkg/version/version.go @@ -20,4 +20,4 @@ package version // It is an own package to avoid import cycles // Version sets the version to be printed to the user. Gets overwritten by "make release" or "make build" with last git commit or tag. -var Version = "0.7" +var Version = "dev" diff --git a/tools.go b/tools.go index 7939f705a4..dc946db17e 100644 --- a/tools.go +++ b/tools.go @@ -33,4 +33,6 @@ import ( _ "honnef.co/go/tools/cmd/staticcheck" _ "github.com/shurcooL/vfsgen" + + _ "github.com/magefile/mage" )