diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 98824083..3e1dd744 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -4,8 +4,8 @@ # https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates version: 2 -updates: - - package-ecosystem: "gomod" # See documentation for possible values - directory: "/" # Location of package manifests - schedule: - interval: "daily" \ No newline at end of file +updates: [] +# - package-ecosystem: "gomod" # See documentation for possible values +# directory: "/" # Location of package manifests +# schedule: +# interval: "daily" diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index a73ee5bd..3e1862a1 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -38,8 +38,6 @@ GITPLOY_GITHUB_CLIENT_SECRET=XXXXXXXXXXXXX GITPLOY_STORE_SOURCE=file:./sqlite3.db?cache=shared&_fk=1 ``` -Note that if you want to interact with GitHub in the local environment, you should install tunneling tools such as [ngork](https://ngrok.com/) and expose your local server. - 3\. Run the server: ``` @@ -71,3 +69,22 @@ REACT_APP_GITPLOY_SERVER=http://localhost ``` npm start ``` + +### Authorization + +1\. Run with ngrok + +Connect to the public host via [ngrok](https://ngrok.com/) to authorize with GitHub OAuth. + +```shell +ngrok http 80 +``` + +2\. Configure GitHub OAuth Apps + +Configure the Homepage URL and Authorization callback URLs with the public host which generated by ngrok. + +3\. Access the index page + +Access the index page of server with the browser. You can find the user is created after authorization. + diff --git a/LICENSE b/LICENSE index 37c97e6b..558d8a80 100644 --- a/LICENSE +++ b/LICENSE @@ -1,46 +1,7 @@ -Copyright 2021 Gitploy.IO, Inc. +Copyright 2024 Gitploy.io -The Gitploy Community Edition is licensed under the Apache License, -Version 2.0 (the "Apache License"). +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - http://www.apache.org/licenses/LICENSE-2.0 +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. -The source files in this repository are under the Apache License -basically, but some files are under the Gitploy Non-Commercial License. -The header of files indicating which license they are under. - -The Gitploy Enterprise Edition is licensed under the Gitploy -Non-Commercial License (the "Non-Commercial License"). A copy of -the Non-Commercial License is provided below. - -The BUILDING_OSS file provides -instructions for creating the Community Edition distribution -subject to the terms of the Apache License. - ------------------------------------------------------------------ - -Gitploy Non-Commercial License - -Contributor: Gitploy.IO, Inc. - -Source Code: https://github.com/gitploy-io/gitploy - -This license lets you use and share this software for free, -under the count of user limit on commercial use. Specifically: - -If you follow the rules below, you may do everything with this -software that would otherwise infringe either the contributor's -copyright in it. - -1. You must limit use of this software in any manner primarily - intended for commercial advantage or private monetary compensation. - This limit does not apply to use in developing feedback or extensions - that you contribute back to those giving this license. - -2. Ensure everyone who gets a copy of this software from you, in - source code, gets the text of this license. - -**This software comes as is, without any warranty at all. As far -as the law allows, the contributor will not be liable for any -damages related to this software or this license, for any kind of -legal claim.** +THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/README.md b/README.md index fa4caab0..d52b3142 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,7 @@ # Gitploy

-
- Gitploy - Build the deployment system around GitHub in minutes. | Product Hunt - Gitploy - Build the deployment system around GitHub in minutes. | Product Hunt -
+
diff --git a/go.mod b/go.mod index bf5f9213..07d15731 100644 --- a/go.mod +++ b/go.mod @@ -16,16 +16,16 @@ require ( github.com/go-sql-driver/mysql v1.6.0 github.com/golang/mock v1.6.0 github.com/google/go-github/v42 v42.0.0 - github.com/jackc/pgx/v4 v4.17.0 + github.com/jackc/pgx/v4 v4.17.2 github.com/joho/godotenv v1.4.0 github.com/kelseyhightower/envconfig v1.4.0 - github.com/mattn/go-sqlite3 v1.14.15 + github.com/mattn/go-sqlite3 v1.14.16 github.com/pkg/errors v0.9.1 - github.com/prometheus/client_golang v1.12.2 + github.com/prometheus/client_golang v1.14.0 github.com/shurcooL/githubv4 v0.0.0-20201206200315-234843c633fa - github.com/slack-go/slack v0.11.3 - github.com/tidwall/gjson v1.14.2 - github.com/urfave/cli/v2 v2.16.2 + github.com/slack-go/slack v0.11.4 + github.com/tidwall/gjson v1.14.4 + github.com/urfave/cli/v2 v2.23.5 go.uber.org/zap v1.21.0 golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a gopkg.in/h2non/gock.v1 v1.1.2 @@ -45,7 +45,7 @@ require ( github.com/go-playground/validator/v10 v10.10.0 // indirect github.com/goccy/go-json v0.9.7 // indirect github.com/golang/protobuf v1.5.2 // indirect - github.com/google/go-cmp v0.5.7 // indirect + github.com/google/go-cmp v0.5.8 // indirect github.com/google/go-querystring v1.1.0 // indirect github.com/google/uuid v1.3.0 // indirect github.com/gorilla/websocket v1.5.0 // indirect @@ -66,9 +66,9 @@ require ( github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/pelletier/go-toml/v2 v2.0.1 // indirect - github.com/prometheus/client_model v0.2.0 // indirect - github.com/prometheus/common v0.32.1 // indirect - github.com/prometheus/procfs v0.7.3 // indirect + github.com/prometheus/client_model v0.3.0 // indirect + github.com/prometheus/common v0.37.0 // indirect + github.com/prometheus/procfs v0.8.0 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/shurcooL/graphql v0.0.0-20200928012149-18c5c3165e3a // indirect github.com/tidwall/match v1.1.1 // indirect @@ -80,12 +80,12 @@ require ( go.uber.org/multierr v1.6.0 // indirect golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa // indirect golang.org/x/mod v0.5.1 // indirect - golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd // indirect - golang.org/x/sys v0.0.0-20220114195835-da31bd327af9 // indirect + golang.org/x/net v0.0.0-20220225172249-27dd8689420f // indirect + golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a // indirect golang.org/x/text v0.3.7 // indirect golang.org/x/tools v0.1.9-0.20211216111533-8d383106f7e7 // indirect golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect google.golang.org/appengine v1.6.7 // indirect - google.golang.org/protobuf v1.28.0 // indirect + google.golang.org/protobuf v1.28.1 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect ) diff --git a/go.sum b/go.sum index bd5d6a4e..8b59ff62 100644 --- a/go.sum +++ b/go.sum @@ -53,7 +53,7 @@ entgo.io/ent v0.10.1/go.mod h1:YPgxeLnoQ/YdpVORRtqjBF+wCy9NX9IR7veTv3Bffus= github.com/AlekSi/pointer v1.2.0 h1:glcy/gc4h8HnG2Z3ZECSzZ1IX1x2JxRVuDzaJwQE0+w= github.com/AlekSi/pointer v1.2.0/go.mod h1:gZGfd3dpW4vEc/UlyfKKi1roIqcCgwOIvb0tSNSBle0= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/BurntSushi/toml v1.1.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= +github.com/BurntSushi/toml v1.2.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/DATA-DOG/go-sqlmock v1.5.0 h1:Shsta01QNfFxHCfpW6YH2STWB0MudeXXEWMr20OEh60= github.com/DATA-DOG/go-sqlmock v1.5.0/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM= @@ -160,9 +160,11 @@ github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2 github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= +github.com/go-kit/log v0.2.0/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= +github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= github.com/go-openapi/inflect v0.19.0 h1:9jCH9scKIbHeV9m12SmPilScz6krDxKRasNNSNPXu/4= github.com/go-openapi/inflect v0.19.0/go.mod h1:lHpZVlpIQqLyKwJ4N+YSc9hchQy/i12fJykb83CRBH4= github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A= @@ -236,8 +238,9 @@ github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.7 h1:81/ik6ipDQS2aGcBfIN5dHDB36BwrStyeAQquSYCV4o= github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= +github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg= +github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-github/v39 v39.0.0/go.mod h1:C1s8C5aCC9L+JXIYpJM5GYytdX52vC1bLvHEF1IhBrE= github.com/google/go-github/v42 v42.0.0 h1:YNT0FwjPrEysRkLIiKuEfSvBPCGKphW5aS5PxwaoLec= github.com/google/go-github/v42 v42.0.0/go.mod h1:jgg/jvyI0YlDOM1/ps6XYh04HNQ3vKf0CVko62/EhRg= @@ -356,12 +359,12 @@ github.com/jackc/pgx/v4 v4.0.0-20190420224344-cc3461e65d96/go.mod h1:mdxmSJJuR08 github.com/jackc/pgx/v4 v4.0.0-20190421002000-1b8f0016e912/go.mod h1:no/Y67Jkk/9WuGR0JG/JseM9irFbnEPbuWV2EELPNuM= github.com/jackc/pgx/v4 v4.0.0-pre1.0.20190824185557-6972a5742186/go.mod h1:X+GQnOEnf1dqHGpw7JmHqHc1NxDoalibchSk9/RWuDc= github.com/jackc/pgx/v4 v4.12.1-0.20210724153913-640aa07df17c/go.mod h1:1QD0+tgSXP7iUjYm9C1NxKhny7lq6ee99u/z+IHFcgs= -github.com/jackc/pgx/v4 v4.17.0 h1:Hsx+baY8/zU2WtPLQyZi8WbecgcsWEeyoK1jvg/WgIo= -github.com/jackc/pgx/v4 v4.17.0/go.mod h1:Gd6RmOhtFLTu8cp/Fhq4kP195KrshxYJH3oW8AWJ1pw= +github.com/jackc/pgx/v4 v4.17.2 h1:0Ut0rpeKwvIVbMQ1KbMBU4h6wxehBI535LK6Flheh8E= +github.com/jackc/pgx/v4 v4.17.2/go.mod h1:lcxIZN44yMIrWI78a5CpucdD14hX0SBDbNRvjDBItsw= github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= -github.com/jackc/puddle v1.2.1/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= +github.com/jackc/puddle v1.3.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4= github.com/joho/godotenv v1.4.0 h1:3l4+N6zfMWnkbPEXKng2o2/MR5mSwTrBih4ZEkkz1lg= github.com/joho/godotenv v1.4.0/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= @@ -426,8 +429,8 @@ github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9 github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= github.com/mattn/go-sqlite3 v1.14.10/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= -github.com/mattn/go-sqlite3 v1.14.15 h1:vfoHhTN1af61xCRSWzFIWzx2YskyMTwHLrExkBOjvxI= -github.com/mattn/go-sqlite3 v1.14.15/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= +github.com/mattn/go-sqlite3 v1.14.16 h1:yOQRA0RpS5PFz/oikGwBEqvAWhWg5ufRz4ETLjwpU1Y= +github.com/mattn/go-sqlite3 v1.14.16/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= @@ -474,26 +477,30 @@ github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5Fsn github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= -github.com/prometheus/client_golang v1.12.2 h1:51L9cDoUHVrXx4zWYlcLQIZ+d+VXHgqnYKkIuq4g/34= -github.com/prometheus/client_golang v1.12.2/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= +github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= +github.com/prometheus/client_golang v1.14.0 h1:nJdhIvne2eSX/XRAFV9PcvFFRbrjbcTUj0VP62TMhnw= +github.com/prometheus/client_golang v1.14.0/go.mod h1:8vpkKitgIVNcqrRBWh1C4TIUQgYNtG/XQE4E/Zae36Y= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M= github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4= +github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= -github.com/prometheus/common v0.32.1 h1:hWIdL3N2HoUx3B8j3YN9mWor0qhY/NlEKZEaXxuIRh4= github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= +github.com/prometheus/common v0.37.0 h1:ccBbHCgIiT9uSoFY0vX8H3zsNR5eLt17/RQLUvn8pXE= +github.com/prometheus/common v0.37.0/go.mod h1:phzohg0JFMnBEFGxTDbfu3QyL5GI8gTQJFhYO5B3mfA= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= -github.com/prometheus/procfs v0.7.3 h1:4jVXhlkAyzOScmCkXBTOLRLTz8EeU+eyjrwB/EPq0VU= github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= +github.com/prometheus/procfs v0.8.0 h1:ODq8ZFEaYeCaZOJlZZdJA2AbQR98dSHSM1KW/You5mo= +github.com/prometheus/procfs v0.8.0/go.mod h1:z7EfXMXOkbkqb9IINtpCn86r/to3BnA0uaxHdg830/4= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= @@ -521,8 +528,8 @@ github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPx github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= -github.com/slack-go/slack v0.11.3 h1:GN7revxEMax4amCc3El9a+9SGnjmBvSUobs0QnO6ZO8= -github.com/slack-go/slack v0.11.3/go.mod h1:hlGi5oXA+Gt+yWTPP0plCdRKmjsDxecdHxYQdlMQKOw= +github.com/slack-go/slack v0.11.4 h1:ojSa7KlPm3PqY2AomX4VTxEsK5eci5JaxCjlzGV5zoM= +github.com/slack-go/slack v0.11.4/go.mod h1:hlGi5oXA+Gt+yWTPP0plCdRKmjsDxecdHxYQdlMQKOw= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spf13/afero v1.3.3/go.mod h1:5KUK8ByomD5Ti5Artl0RtHeI5pTF7MIDuXL3yY520V4= github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= @@ -547,8 +554,8 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= -github.com/tidwall/gjson v1.14.2 h1:6BBkirS0rAHjumnjHF6qgy5d2YAJ1TLIaFE2lzfOLqo= -github.com/tidwall/gjson v1.14.2/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= +github.com/tidwall/gjson v1.14.4 h1:uo0p8EbA09J7RQaflQ1aBRffTR7xedD2bcIVSYxLnkM= +github.com/tidwall/gjson v1.14.4/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs= @@ -558,8 +565,8 @@ github.com/ugorji/go v1.2.7 h1:qYhyWUUd6WbiM+C6JZAUkIJt/1WrjzNHY9+KCIjVqTo= github.com/ugorji/go v1.2.7/go.mod h1:nF9osbDWLy6bDVv/Rtoh6QgnvNDpmCalQV5urGCCS6M= github.com/ugorji/go/codec v1.2.7 h1:YPXUKf7fYbp/y8xloBqZOw2qaVggbfwMlI8WM3wZUJ0= github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY= -github.com/urfave/cli/v2 v2.16.2 h1:54KkXv2+tay5GSZJzuVgcE0C+A/Uzv6BsfNXH0wjU4c= -github.com/urfave/cli/v2 v2.16.2/go.mod h1:1CNUng3PtjQMtRzJO4FMXBQvkGtuYRxxiR9xMa7jMwI= +github.com/urfave/cli/v2 v2.23.5 h1:xbrU7tAYviSpqeR3X4nEFWUdB/uDZ6DE+HxmRU7Xtyw= +github.com/urfave/cli/v2 v2.23.5/go.mod h1:GHupkWPMM0M/sj1a2b4wUrWBPzazNrIjouW6fmdJLxc= github.com/vmihailenco/msgpack v3.3.3+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk= github.com/vmihailenco/msgpack/v4 v4.3.12/go.mod h1:gborTTJjAo/GWTqqRjrLCn9pgNN+NXzzngzBKDPIqw4= github.com/vmihailenco/tagparser v0.1.1/go.mod h1:OeAg3pn3UbLjkWt+rN9oFYB6u/cQgqMEUPoW2WPyhdI= @@ -708,8 +715,9 @@ golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qx golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd h1:O7DYs+zxREGLKzKoMQrtrEacpb0ZVXA5rIwylE2Xchk= golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220225172249-27dd8689420f h1:oA4XRj0qtSt8Yo1Zms0CUlsT3KG69V2UGQWPBxujDmc= +golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -727,6 +735,7 @@ golang.org/x/oauth2 v0.0.0-20210805134026-6f1e6394065a/go.mod h1:KelEdhl1UZF7XfJ golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20211005180243-6b3c2da341f1/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a h1:qfl7ob3DIEs3Ml9oLuPwY2N04gymzAW04WsUQHIClgM= golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -740,6 +749,7 @@ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/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= @@ -816,8 +826,9 @@ golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211205182925-97ca703d548d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220114195835-da31bd327af9 h1:XfKQ4OlFl8okEOr5UvAqFRVj8pY/4yfcXrddB8qAbU0= golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a h1:dGzPydgVsqGcTRVwiLJ1jVbufYwmzD3LfVPLKsKg+0k= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= @@ -1046,8 +1057,9 @@ google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlba google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw= google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= +google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/internal/interactor/interface.go b/internal/interactor/interface.go index 4b187f12..31fd4f50 100644 --- a/internal/interactor/interface.go +++ b/internal/interactor/interface.go @@ -61,6 +61,7 @@ type ( BranchSCM interface { ListBranches(ctx context.Context, u *ent.User, r *ent.Repo, opt *ListOptions) ([]*extent.Branch, error) GetBranch(ctx context.Context, u *ent.User, r *ent.Repo, branch string) (*extent.Branch, error) + GetDefaultBranch(ctx context.Context, u *ent.User, r *ent.Repo) (*extent.Branch, error) } TagSCM interface { diff --git a/internal/interactor/mock/pkg.go b/internal/interactor/mock/pkg.go index ddef757b..f708cb56 100644 --- a/internal/interactor/mock/pkg.go +++ b/internal/interactor/mock/pkg.go @@ -1263,6 +1263,21 @@ func (mr *MockSCMMockRecorder) GetConfigRedirectURL(ctx, u, r interface{}) *gomo return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetConfigRedirectURL", reflect.TypeOf((*MockSCM)(nil).GetConfigRedirectURL), ctx, u, r) } +// GetDefaultBranch mocks base method. +func (m *MockSCM) GetDefaultBranch(ctx context.Context, u *ent.User, r *ent.Repo) (*extent.Branch, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetDefaultBranch", ctx, u, r) + ret0, _ := ret[0].(*extent.Branch) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetDefaultBranch indicates an expected call of GetDefaultBranch. +func (mr *MockSCMMockRecorder) GetDefaultBranch(ctx, u, r interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetDefaultBranch", reflect.TypeOf((*MockSCM)(nil).GetDefaultBranch), ctx, u, r) +} + // GetNewConfigRedirectURL mocks base method. func (m *MockSCM) GetNewConfigRedirectURL(ctx context.Context, u *ent.User, r *ent.Repo) (string, error) { m.ctrl.T.Helper() @@ -1573,6 +1588,21 @@ func (mr *MockBranchSCMMockRecorder) GetBranch(ctx, u, r, branch interface{}) *g return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetBranch", reflect.TypeOf((*MockBranchSCM)(nil).GetBranch), ctx, u, r, branch) } +// GetDefaultBranch mocks base method. +func (m *MockBranchSCM) GetDefaultBranch(ctx context.Context, u *ent.User, r *ent.Repo) (*extent.Branch, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetDefaultBranch", ctx, u, r) + ret0, _ := ret[0].(*extent.Branch) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetDefaultBranch indicates an expected call of GetDefaultBranch. +func (mr *MockBranchSCMMockRecorder) GetDefaultBranch(ctx, u, r interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetDefaultBranch", reflect.TypeOf((*MockBranchSCM)(nil).GetDefaultBranch), ctx, u, r) +} + // ListBranches mocks base method. func (m *MockBranchSCM) ListBranches(ctx context.Context, u *ent.User, r *ent.Repo, opt *interactor.ListOptions) ([]*extent.Branch, error) { m.ctrl.T.Helper() diff --git a/internal/pkg/github/deployment.go b/internal/pkg/github/deployment.go index 1ee57637..83723721 100644 --- a/internal/pkg/github/deployment.go +++ b/internal/pkg/github/deployment.go @@ -32,9 +32,21 @@ func (g *Github) CreateRemoteDeployment(ctx context.Context, u *ent.User, r *ent ProductionEnvironment: env.ProductionEnvironment, }) if res.StatusCode == http.StatusConflict { + // Determine if there is a merge conflict or a commit status check failed. + // https://github.com/gitploy-io/gitploy/issues/526 + for _, es := range err.(*github.ErrorResponse).Errors { + if es.Field == "required_contexts" { + return nil, e.NewErrorWithMessage( + e.ErrorCodeEntityUnprocessable, + "A commit status check failed.", + err, + ) + } + } + return nil, e.NewErrorWithMessage( e.ErrorCodeEntityUnprocessable, - "There is merge conflict or a commit status check failed.", + "There is merge conflict. Retry after resolving the conflict.", err, ) } else if res.StatusCode == http.StatusUnprocessableEntity { diff --git a/internal/pkg/github/repos.go b/internal/pkg/github/repos.go index 4467177b..94e3c31a 100644 --- a/internal/pkg/github/repos.go +++ b/internal/pkg/github/repos.go @@ -157,6 +157,26 @@ func (g *Github) GetBranch(ctx context.Context, u *ent.User, r *ent.Repo, branch return mapGithubBranchToBranch(b), nil } +func (g *Github) GetDefaultBranch(ctx context.Context, u *ent.User, r *ent.Repo) (*extent.Branch, error) { + rr, res, err := g.Client(ctx, u.Token).Repositories.Get(ctx, r.Namespace, r.Name) + if res.StatusCode == http.StatusNotFound { + return nil, e.NewErrorWithMessage(e.ErrorCodeEntityNotFound, "The default branch is not found.", err) + } else if err != nil { + return nil, e.NewError(e.ErrorCodeInternalError, err) + } + + b, res, err := g.Client(ctx, u.Token). + Repositories. + GetBranch(ctx, r.Namespace, r.Name, *rr.DefaultBranch, false) + if res.StatusCode == http.StatusNotFound { + return nil, e.NewErrorWithMessage(e.ErrorCodeEntityNotFound, "The default branch is not found.", err) + } else if err != nil { + return nil, e.NewError(e.ErrorCodeInternalError, err) + } + + return mapGithubBranchToBranch(b), nil +} + // ListTags list up tags as ordered by commit date. // Github GraphQL explore - https://docs.github.com/en/graphql/overview/explorer func (g *Github) ListTags(ctx context.Context, u *ent.User, r *ent.Repo, opt *i.ListOptions) ([]*extent.Tag, error) { diff --git a/internal/server/api/shared/middleware_test.go b/internal/server/api/shared/middleware_test.go index aa63f30e..04b1121b 100644 --- a/internal/server/api/shared/middleware_test.go +++ b/internal/server/api/shared/middleware_test.go @@ -42,33 +42,6 @@ func TestMiddleware_IsLicenseExpired(t *testing.T) { } }) - t.Run("Return 402 error when the count of member is over the limit.", func(t *testing.T) { - ctrl := gomock.NewController(t) - m := mock.NewMockInteractor(ctrl) - - m. - EXPECT(). - GetLicense(gomock.Any()). - Return(extent.NewTrialLicense(extent.TrialMemberLimit+1, extent.TrialDeploymentLimit), nil) - - gin.SetMode(gin.ReleaseMode) - router := gin.New() - - lm := NewMiddleware(m) - router.GET("/repos", lm.IsLicenseExpired(), func(c *gin.Context) { - c.Status(http.StatusOK) - }) - - req, _ := http.NewRequest("GET", "/repos", nil) - w := httptest.NewRecorder() - - router.ServeHTTP(w, req) - - if w.Code != http.StatusPaymentRequired { - t.Fatalf("IsLicenseExpired = %v, wanted %v", w.Code, http.StatusPaymentRequired) - } - }) - t.Run("Return 200 when the count of member is under the limit.", func(t *testing.T) { ctrl := gomock.NewController(t) m := mock.NewMockInteractor(ctrl) diff --git a/internal/server/api/v1/repos/branch_get.go b/internal/server/api/v1/repos/branch_get.go index 664b48c3..c2155f63 100644 --- a/internal/server/api/v1/repos/branch_get.go +++ b/internal/server/api/v1/repos/branch_get.go @@ -32,3 +32,22 @@ func (s *BranchAPI) Get(c *gin.Context) { gb.Response(c, http.StatusOK, b) } + +func (s *BranchAPI) GetDefault(c *gin.Context) { + ctx := c.Request.Context() + + uv, _ := c.Get(gb.KeyUser) + u := uv.(*ent.User) + + rv, _ := c.Get(KeyRepo) + repo := rv.(*ent.Repo) + + b, err := s.i.GetDefaultBranch(ctx, u, repo) + if err != nil { + s.log.Check(gb.GetZapLogLevel(err), "Failed to get the branch.").Write(zap.Error(err)) + gb.ResponseWithError(c, err) + return + } + + gb.Response(c, http.StatusOK, b) +} diff --git a/internal/server/api/v1/repos/interface.go b/internal/server/api/v1/repos/interface.go index fbf86191..26f43b9d 100644 --- a/internal/server/api/v1/repos/interface.go +++ b/internal/server/api/v1/repos/interface.go @@ -55,6 +55,7 @@ type ( ListBranches(ctx context.Context, u *ent.User, r *ent.Repo, opt *i.ListOptions) ([]*extent.Branch, error) GetBranch(ctx context.Context, u *ent.User, r *ent.Repo, branch string) (*extent.Branch, error) + GetDefaultBranch(ctx context.Context, u *ent.User, r *ent.Repo) (*extent.Branch, error) ListTags(ctx context.Context, u *ent.User, r *ent.Repo, opt *i.ListOptions) ([]*extent.Tag, error) GetTag(ctx context.Context, u *ent.User, r *ent.Repo, tag string) (*extent.Tag, error) diff --git a/internal/server/api/v1/repos/mock/interactor.go b/internal/server/api/v1/repos/mock/interactor.go index 142e711d..95e2b4b4 100644 --- a/internal/server/api/v1/repos/mock/interactor.go +++ b/internal/server/api/v1/repos/mock/interactor.go @@ -337,6 +337,21 @@ func (mr *MockInteractorMockRecorder) GetConfig(ctx, u, r interface{}) *gomock.C return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetConfig", reflect.TypeOf((*MockInteractor)(nil).GetConfig), ctx, u, r) } +// GetDefaultBranch mocks base method. +func (m *MockInteractor) GetDefaultBranch(ctx context.Context, u *ent.User, r *ent.Repo) (*extent.Branch, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetDefaultBranch", ctx, u, r) + ret0, _ := ret[0].(*extent.Branch) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetDefaultBranch indicates an expected call of GetDefaultBranch. +func (mr *MockInteractorMockRecorder) GetDefaultBranch(ctx, u, r interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetDefaultBranch", reflect.TypeOf((*MockInteractor)(nil).GetDefaultBranch), ctx, u, r) +} + // GetEvaluatedConfig mocks base method. func (m *MockInteractor) GetEvaluatedConfig(ctx context.Context, u *ent.User, r *ent.Repo, v *extent.EvalValues) (*extent.Config, error) { m.ctrl.T.Helper() diff --git a/internal/server/global/http.go b/internal/server/global/http.go index fed8676b..3c9c07b4 100644 --- a/internal/server/global/http.go +++ b/internal/server/global/http.go @@ -13,7 +13,7 @@ func Response(c *gin.Context, httpCode int, data interface{}) { func ResponseWithError(c *gin.Context, err error) { if ge, ok := err.(*e.Error); ok { - c.JSON(e.GetHttpCode(ge.Code), map[string]string{ + c.JSON(ge.GetHTTPCode(), map[string]string{ "code": string(ge.Code), "message": ge.Message, }) @@ -44,7 +44,7 @@ func ResponseWithStatusAndError(c *gin.Context, status int, err error) { func AbortWithError(c *gin.Context, err error) { if ge, ok := err.(*e.Error); ok { - c.AbortWithStatusJSON(e.GetHttpCode(ge.Code), map[string]string{ + c.AbortWithStatusJSON(ge.GetHTTPCode(), map[string]string{ "code": string(ge.Code), "message": ge.Message, }) diff --git a/internal/server/router.go b/internal/server/router.go index dcd06729..bf58d9b9 100644 --- a/internal/server/router.go +++ b/internal/server/router.go @@ -133,6 +133,7 @@ func NewRouter(c *RouterConfig) *gin.Engine { repov1.GET("/:namespace/:name/commits/:sha/statuses", rm.RepoReadPerm(), api.Commits.ListStatuses) repov1.GET("/:namespace/:name/branches", rm.RepoReadPerm(), api.Branch.List) repov1.GET("/:namespace/:name/branches/:branch", rm.RepoReadPerm(), api.Branch.Get) + repov1.GET("/:namespace/:name/default-branch", rm.RepoReadPerm(), api.Branch.GetDefault) repov1.GET("/:namespace/:name/tags", rm.RepoReadPerm(), api.Tag.List) repov1.GET("/:namespace/:name/tags/:tag", rm.RepoReadPerm(), api.Tag.Get) repov1.GET("/:namespace/:name/deployments", rm.RepoReadPerm(), api.Deployment.List) diff --git a/model/extent/license.go b/model/extent/license.go index 33c6b804..d7176943 100644 --- a/model/extent/license.go +++ b/model/extent/license.go @@ -1,10 +1,15 @@ package extent -import "time" +import ( + "math" + "time" +) const ( TrialMemberLimit = 5 TrialDeploymentLimit = 5000 + InfiniteMemberLimit = math.MaxInt + InfiniteDeploymentLimit = math.MaxInt ) const ( @@ -47,9 +52,9 @@ func NewTrialLicense(memberCnt, deploymentCnt int) *License { return &License{ Kind: LicenseKindTrial, MemberCount: memberCnt, - MemberLimit: TrialMemberLimit, + MemberLimit: InfiniteMemberLimit, DeploymentCount: deploymentCnt, - DeploymentLimit: TrialDeploymentLimit, + DeploymentLimit: InfiniteMemberLimit, } } @@ -57,7 +62,7 @@ func NewStandardLicense(memberCnt int, d *SigningData) *License { return &License{ Kind: LicenseKindStandard, MemberCount: memberCnt, - MemberLimit: d.MemberLimit, + MemberLimit: InfiniteMemberLimit, DeploymentCount: -1, ExpiredAt: d.ExpiredAt, } diff --git a/model/extent/license_test.go b/model/extent/license_test.go index 32282bb3..e8864382 100644 --- a/model/extent/license_test.go +++ b/model/extent/license_test.go @@ -15,24 +15,6 @@ func TestLicense_IsOverLimit(t *testing.T) { } }) - t.Run("Return true when the trial license is over the member limit.", func(t *testing.T) { - l := NewTrialLicense(TrialMemberLimit+1, 0) - - expected := true - if finished := l.IsOverLimit(); finished != expected { - t.Fatalf("IsOverLimit = %v, wanted %v", finished, expected) - } - }) - - t.Run("Return true when the trial license is over the deployment limit.", func(t *testing.T) { - l := NewTrialLicense(5, TrialDeploymentLimit+1) - - expected := true - if finished := l.IsOverLimit(); finished != expected { - t.Fatalf("IsOverLimit = %v, wanted %v", finished, expected) - } - }) - t.Run("Return false when the trial license is less than or equal to the limit.", func(t *testing.T) { l := NewTrialLicense(TrialMemberLimit, TrialDeploymentLimit) diff --git a/pkg/e/code.go b/pkg/e/code.go index 999497e2..4ef65a54 100644 --- a/pkg/e/code.go +++ b/pkg/e/code.go @@ -3,6 +3,7 @@ package e import ( "errors" "fmt" + "net/http" "strings" ) @@ -62,22 +63,26 @@ type ( Code ErrorCode Message string Wrap error + + httpCode int } ) func NewError(code ErrorCode, wrap error) *Error { return &Error{ - Code: code, - Message: GetMessage(code), - Wrap: wrap, + Code: code, + Message: GetMessage(code), + Wrap: wrap, + httpCode: mapHTTPCode(code), } } func NewErrorWithMessage(code ErrorCode, message string, wrap error) *Error { return &Error{ - Code: code, - Message: message, - Wrap: wrap, + Code: code, + Message: message, + Wrap: wrap, + httpCode: mapHTTPCode(code), } } @@ -94,10 +99,29 @@ func (e *Error) Error() string { return strings.Join(msgs, ", ") } +// GetHTTPCode returns the HTTP code. +func (e *Error) GetHTTPCode() int { + return e.httpCode +} + +// SetHTTPCode sets the HTTP code manually. +func (e *Error) SetHTTPCode(code int) { + e.httpCode = code +} + func (e *Error) Unwrap() error { return e.Wrap } +func mapHTTPCode(code ErrorCode) int { + httpCode, ok := httpCodes[code] + if !ok { + return http.StatusInternalServerError + } + + return httpCode +} + func IsError(err error) bool { var ge *Error return errors.As(err, &ge) diff --git a/pkg/e/code_test.go b/pkg/e/code_test.go index 689aeaf8..f8b97194 100644 --- a/pkg/e/code_test.go +++ b/pkg/e/code_test.go @@ -2,9 +2,19 @@ package e import ( "fmt" + "net/http" "testing" ) +func TestError_GetHTTPError(t *testing.T) { + t.Run("Return the matche HTTP code.", func(t *testing.T) { + err := NewError(ErrorCodeInternalError, nil) + if err.GetHTTPCode() != http.StatusInternalServerError { + t.Fatalf("GetHTTPCode = %v, wanted %v", err.GetHTTPCode(), http.StatusInternalServerError) + } + }) +} + func Test_IsError(t *testing.T) { t.Run("Return true when the type of error is Error.", func(t *testing.T) { err := NewError(ErrorCodeInternalError, nil) diff --git a/pkg/e/trans.go b/pkg/e/trans.go index 3eb07d27..ec0e9c2a 100644 --- a/pkg/e/trans.go +++ b/pkg/e/trans.go @@ -52,12 +52,3 @@ var httpCodes = map[ErrorCode]int{ ErrorPermissionRequired: http.StatusForbidden, ErrorRepoUniqueName: http.StatusUnprocessableEntity, } - -func GetHttpCode(code ErrorCode) int { - httpCode, ok := httpCodes[code] - if !ok { - return http.StatusInternalServerError - } - - return httpCode -} diff --git a/ui/src/apis/branch.ts b/ui/src/apis/branch.ts index 785f08d4..154a4b63 100644 --- a/ui/src/apis/branch.ts +++ b/ui/src/apis/branch.ts @@ -52,3 +52,27 @@ export const getBranch = async ( return ret; }; + +export const getDefaultBranch = async ( + namespace: string, + name: string +): Promise => { + const response = await _fetch( + `${instance}/api/v1/repos/${namespace}/${name}/default-branch`, + { + headers, + credentials: 'same-origin', + } + ); + + if (response.status === StatusCodes.NOT_FOUND) { + const message = await response.json().then((data) => data.message); + throw new HttpNotFoundError(message); + } + + const ret: Branch = await response + .json() + .then((b: any) => mapDataToBranch(b)); + + return ret; +}; diff --git a/ui/src/apis/index.ts b/ui/src/apis/index.ts index 328743b8..ff710e30 100644 --- a/ui/src/apis/index.ts +++ b/ui/src/apis/index.ts @@ -20,7 +20,7 @@ export { } from './deployment'; export { getConfig } from './config'; export { listCommits, getCommit, listStatuses } from './commit'; -export { listBranches, getBranch } from './branch'; +export { listBranches, getBranch, getDefaultBranch } from './branch'; export { listTags, getTag } from './tag'; export { listUsers, updateUser, deleteUser, getMe, getRateLimit } from './user'; export { checkSlack } from './chat'; diff --git a/ui/src/redux/repoDeploy.tsx b/ui/src/redux/repoDeploy.tsx index c04e2d22..58fe7248 100644 --- a/ui/src/redux/repoDeploy.tsx +++ b/ui/src/redux/repoDeploy.tsx @@ -23,6 +23,7 @@ import { listDeployments, listBranches, getBranch, + getDefaultBranch, listCommits, getCommit, listStatuses, @@ -121,7 +122,23 @@ export const fetchBranches = createAsyncThunk< const { namespace, name } = getState().repoDeploy; const branches = await listBranches(namespace, name, firstPage, perPage); - return branches; + + const defaultBranch = await getDefaultBranch(namespace, name); + + // Add the default branch, and remove the duplicated one. + branches.unshift(defaultBranch); + + const reduced = branches.reduce((acc, cur) => { + if (acc.findIndex((b) => b.name === cur.name) === -1) { + acc.push(cur); + } + + return acc; + }, [] as Branch[]); + + console.log(reduced); + + return reduced; }); export const checkBranch = createAsyncThunk< diff --git a/ui/src/views/repoDeploy/DynamicPayloadModal.tsx b/ui/src/views/repoDeploy/DynamicPayloadModal.tsx index 6397424e..a541858b 100644 --- a/ui/src/views/repoDeploy/DynamicPayloadModal.tsx +++ b/ui/src/views/repoDeploy/DynamicPayloadModal.tsx @@ -103,7 +103,7 @@ function DynamicItem({ name, input }: DynamicItemProps): JSX.Element { tooltip={description} rules={rules} > - + ); case DynamicPayloadInputTypeEnum.Number: diff --git a/ui/src/views/repoDeploy/index.tsx b/ui/src/views/repoDeploy/index.tsx index 8937d609..d14c3016 100644 --- a/ui/src/views/repoDeploy/index.tsx +++ b/ui/src/views/repoDeploy/index.tsx @@ -2,7 +2,7 @@ import { useEffect, useState } from 'react'; import { shallowEqual } from 'react-redux'; import { useParams } from 'react-router-dom'; import { PageHeader, Result, Button } from 'antd'; - +import { RedoOutlined } from '@ant-design/icons'; import { useAppSelector, useAppDispatch } from '../../redux/hooks'; import { DeploymentType, @@ -48,10 +48,13 @@ export default (): JSX.Element => { envs, env, currentDeployment, + branch, branches, branchStatuses, + commit, commits, commitStatuses, + tag, tags, tagStatuses, deploying, @@ -73,6 +76,24 @@ export default (): JSX.Element => { // eslint-disable-next-line }, [dispatch]); + const onClickRefresh = () => { + dispatch(fetchTags()); + if (tag) { + dispatch(checkTag()); + } + + dispatch(fetchBranches()); + if (branch) { + dispatch(checkBranch()); + // Fetch commits only when a branch is selected. + dispatch(fetchCommits()); + } + + if (commit) { + dispatch(checkCommit()); + } + }; + const onSelectEnv = (env: Env) => { dispatch(actions.setEnv(env)); dispatch(fetchCurrentDeploymentOfEnv(env)); @@ -150,6 +171,7 @@ export default (): JSX.Element => { } return ( { env?: Env; + onClickRefresh(): void; } function RepoDeploy({ + onClickRefresh, // Properities for the DeployForm component. envs, onSelectEnv, @@ -204,8 +228,17 @@ function RepoDeploy({ env, onClickOk, }: RepoDeployProps): JSX.Element { + const [refreshing, setRefreshing] = useState(false); const [payloadModalVisible, setPayloadModalVisible] = useState(false); + const _onClickRefresh = () => { + setRefreshing(true); + onClickRefresh(); + setTimeout(() => { + setRefreshing(false); + }, 1000); + }; + const _onClickDeploy = () => { if (env?.dynamicPayload?.enabled) { setPayloadModalVisible(true); @@ -226,7 +259,20 @@ function RepoDeploy({ return (

- + } + onClick={_onClickRefresh} + />, + ]} + />