From 480a6ec32cd408b25307106f8b6ac1be32692533 Mon Sep 17 00:00:00 2001 From: Kay0u Date: Wed, 15 Sep 2021 15:28:07 +0200 Subject: [PATCH 01/11] remove old actions and config panel --- actions.json | 24 ---------------- config_panel.json | 42 --------------------------- scripts/actions/web_account | 57 ------------------------------------- 3 files changed, 123 deletions(-) delete mode 100644 actions.json delete mode 100644 config_panel.json delete mode 100644 scripts/actions/web_account diff --git a/actions.json b/actions.json deleted file mode 100644 index e283eca..0000000 --- a/actions.json +++ /dev/null @@ -1,24 +0,0 @@ -[ - { - "id": "web_account", - "name": "External users", - "command": "/bin/bash scripts/actions/web_account", - "user": "root", - "accepted_return_codes": [ - 0 - ], - "description": { - "en": "Allow user to be created without yunohost account." - }, - "arguments": [ - { - "name": "use_web_account", - "type": "boolean", - "ask": { - "en": "Authorized external user creation ?" - }, - "default": true - } - ] - } -] \ No newline at end of file diff --git a/config_panel.json b/config_panel.json deleted file mode 100644 index 9366c54..0000000 --- a/config_panel.json +++ /dev/null @@ -1,42 +0,0 @@ -{ - "name": "GitLab configuration panel", - "version": "0.1", - "panel": [ - { - "name": "GitLab configuration", - "id": "main", - "sections": [ - { - "name": "Overwriting config files", - "id": "overwrite_files", - "options": [ - { - "name": "overwrite_nginx", - "ask": { - "en": "Overwrite the nginx config file ?" - }, - "help": "If the file is overwritten, a backup will be created.", - "type": "boolean", - "default": true - } - ] - }, - { - "name": "External users", - "id": "users", - "options": [ - { - "name": "use_web_account", - "ask": { - "en": "Authorized external user creation ?" - }, - "help": "Allow user to be created without yunohost account.", - "type": "boolean", - "default": true - } - ] - } - ] - } - ] -} \ No newline at end of file diff --git a/scripts/actions/web_account b/scripts/actions/web_account deleted file mode 100644 index 4f6111a..0000000 --- a/scripts/actions/web_account +++ /dev/null @@ -1,57 +0,0 @@ -#!/bin/bash - -#================================================= -# GENERIC STARTING -#================================================= -# IMPORT GENERIC HELPERS -#================================================= - -source scripts/_common.sh -source /usr/share/yunohost/helpers - -#================================================= -# RETRIEVE ARGUMENTS -#================================================= - -# Get use_web_account -use_web_account=${YNH_ACTION_USE_WEB_ACCOUNT} - -app=${YNH_APP_INSTANCE_NAME:-$YNH_APP_ID} - -#================================================= -# CHECK IF ARGUMENTS ARE CORRECT -#================================================= - -#================================================= -# CHECK IF AN ACTION HAS TO BE DONE -#================================================= - -use_web_account_old=$(ynh_app_setting_get --app=$app --key=use_web_account) - -if [ $use_web_account -eq $use_web_account_old ] -then - ynh_die "use_web_account is already set as $use_web_account." 0 -fi - -#================================================= -# SPECIFIC ACTION -#================================================= -# SET USER CREATION POLICY -#================================================= -if [ $use_web_account -eq 0 ]; then - web_account="Enable" -else - web_account="Disable" -fi -ynh_script_progression --message=--message="$web_account web user creation..." --weight=13 - -echo "ApplicationSetting.last.update_attributes(password_authentication_enabled_for_web: $use_web_account, signup_enabled: $use_web_account)" | gitlab-rails console - -# Update the config of the app -ynh_app_setting_set --app=$app --key=use_web_account --value=$use_web_account - -#================================================= -# END OF SCRIPT -#================================================= - -ynh_script_progression --message="Execution completed" --last \ No newline at end of file From 7e3bcd27f77b3d05dc87c77a8b5750a08cc95ac7 Mon Sep 17 00:00:00 2001 From: Kay0u Date: Wed, 15 Sep 2021 15:28:21 +0200 Subject: [PATCH 02/11] New config panel version --- config_panel.toml | 21 +++++++++++++++++ scripts/config | 59 +++++++++-------------------------------------- 2 files changed, 32 insertions(+), 48 deletions(-) create mode 100644 config_panel.toml diff --git a/config_panel.toml b/config_panel.toml new file mode 100644 index 0000000..aaee3ed --- /dev/null +++ b/config_panel.toml @@ -0,0 +1,21 @@ +version = "1.0" +name = "GitLab configuration panel" + +[main] +name = "GitLab configuration" + + [main.overwrite_files] + name = "Overwriting config files" + + [main.overwrite_files.overwrite_nginx] + ask = "Overwrite the nginx config file ?" + type = "boolean" + help = "If the file is overwritten, a backup will be created." + + [main.users] + name = "External users" + + [main.users.use_web_account] + ask = "Authorized external user creation ?" + type = "boolean" + bind = "null" \ No newline at end of file diff --git a/scripts/config b/scripts/config index 277cb57..004b47f 100644 --- a/scripts/config +++ b/scripts/config @@ -6,65 +6,28 @@ # IMPORT GENERIC HELPERS #================================================= -source _common.sh source /usr/share/yunohost/helpers +ynh_abort_if_errors + #================================================= # RETRIEVE ARGUMENTS #================================================= -app=${YNH_APP_INSTANCE_NAME:-$YNH_APP_ID} - - #================================================= -# LOAD VALUES +# SPECIFIC GETTERS FOR TOML SHORT KEY #================================================= -# Load the real value from the app config or elsewhere. -# Then get the value from the form. -# If the form has a value for a variable, take the value from the form, -# Otherwise, keep the value from the app config. - -# Overwrite nginx configuration -old_overwrite_nginx="$(ynh_app_setting_get --app=$app --key=overwrite_nginx)" -overwrite_nginx="${YNH_CONFIG_MAIN_OVERWRITE_FILES_OVERWRITE_NGINX:-$old_overwrite_nginx}" - -# use_web_account -old_use_web_account="$(ynh_app_setting_get --app=$app --key=use_web_account)" -use_web_account="${YNH_CONFIG_MAIN_USERS_USE_WEB_ACCOUNT:-$old_use_web_account}" - #================================================= -# SHOW_CONFIG FUNCTION FOR 'SHOW' COMMAND +# SPECIFIC SETTERS FOR TOML SHORT KEYS #================================================= -show_config() { - # here you are supposed to read some config file/database/other then print the values - # echo "YNH_CONFIG_${PANEL_ID}_${SECTION_ID}_${OPTION_ID}=value" +set__use_web_account() { + if [ -n "${use_web_account}" ] + then + echo "ApplicationSetting.last.update_attributes(password_authentication_enabled_for_web: $use_web_account, signup_enabled: $use_web_account)" | gitlab-rails console - ynh_return "YNH_CONFIG_MAIN_OVERWRITE_FILES_OVERWRITE_NGINX=$overwrite_nginx" - - ynh_return "YNH_CONFIG_MAIN_USERS_USE_WEB_ACCOUNT=$use_web_account" + # Update the config of the app + ynh_app_setting_set --app=$app --key=use_web_account --value=$use_web_account + fi } - -#================================================= -# MODIFY THE CONFIGURATION -#================================================= - -apply_config() { - # Change use_web_account - yunohost app action run $app web_account --args use_web_account=$use_web_account - - # Set overwrite_nginx - ynh_app_setting_set --app=$app --key=overwrite_nginx --value="$overwrite_nginx" -} - -#================================================= -# GENERIC FINALIZATION -#================================================= -# SELECT THE ACTION FOLLOWING THE GIVEN ARGUMENT -#================================================= - -case $1 in - show) show_config;; - apply) apply_config;; -esac \ No newline at end of file From 9f48368d573fc18b3baa8a4653cbbcf82a5be25b Mon Sep 17 00:00:00 2001 From: Kay0u Date: Wed, 15 Sep 2021 15:32:46 +0200 Subject: [PATCH 03/11] Remove useless name key --- config_panel.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/config_panel.toml b/config_panel.toml index aaee3ed..04fc2b6 100644 --- a/config_panel.toml +++ b/config_panel.toml @@ -1,5 +1,4 @@ version = "1.0" -name = "GitLab configuration panel" [main] name = "GitLab configuration" From d61999e293b3c9c7237a70ab030fe6a0467b97fe Mon Sep 17 00:00:00 2001 From: Kay0u Date: Wed, 15 Sep 2021 16:01:49 +0200 Subject: [PATCH 04/11] fix the config panel --- scripts/config | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/scripts/config b/scripts/config index 004b47f..025538b 100644 --- a/scripts/config +++ b/scripts/config @@ -14,6 +14,8 @@ ynh_abort_if_errors # RETRIEVE ARGUMENTS #================================================= +final_path=$(ynh_app_setting_get --app=$app --key=final_path) + #================================================= # SPECIFIC GETTERS FOR TOML SHORT KEY #================================================= @@ -31,3 +33,8 @@ set__use_web_account() { ynh_app_setting_set --app=$app --key=use_web_account --value=$use_web_account fi } + +#================================================= +# GENERIC FINALIZATION +#================================================= +ynh_app_config_run $1 \ No newline at end of file From fe6e7bc3648c820812bd204038a8772b0e8b5f7b Mon Sep 17 00:00:00 2001 From: Kay0u Date: Wed, 15 Sep 2021 16:34:50 +0200 Subject: [PATCH 05/11] update_attributes is now update --- scripts/config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/config b/scripts/config index 025538b..78b5566 100644 --- a/scripts/config +++ b/scripts/config @@ -27,7 +27,7 @@ final_path=$(ynh_app_setting_get --app=$app --key=final_path) set__use_web_account() { if [ -n "${use_web_account}" ] then - echo "ApplicationSetting.last.update_attributes(password_authentication_enabled_for_web: $use_web_account, signup_enabled: $use_web_account)" | gitlab-rails console + echo "ApplicationSetting.last.update(password_authentication_enabled_for_web: $use_web_account, signup_enabled: $use_web_account)" | gitlab-rails console # Update the config of the app ynh_app_setting_set --app=$app --key=use_web_account --value=$use_web_account From 288ac68099767b181e5ebaec9f384e773cf68652 Mon Sep 17 00:00:00 2001 From: Kay0u Date: Thu, 16 Sep 2021 11:31:35 +0200 Subject: [PATCH 06/11] final_path not needed anymore --- scripts/config | 2 -- 1 file changed, 2 deletions(-) diff --git a/scripts/config b/scripts/config index 78b5566..6e70251 100644 --- a/scripts/config +++ b/scripts/config @@ -14,8 +14,6 @@ ynh_abort_if_errors # RETRIEVE ARGUMENTS #================================================= -final_path=$(ynh_app_setting_get --app=$app --key=final_path) - #================================================= # SPECIFIC GETTERS FOR TOML SHORT KEY #================================================= From 5bef9d79065b9aca5ec3cf40a65676b9e973708d Mon Sep 17 00:00:00 2001 From: Kay0u Date: Tue, 21 Sep 2021 23:12:20 +0200 Subject: [PATCH 07/11] bind is not required here --- config_panel.toml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/config_panel.toml b/config_panel.toml index 04fc2b6..c44664d 100644 --- a/config_panel.toml +++ b/config_panel.toml @@ -16,5 +16,4 @@ name = "GitLab configuration" [main.users.use_web_account] ask = "Authorized external user creation ?" - type = "boolean" - bind = "null" \ No newline at end of file + type = "boolean" \ No newline at end of file From f309b2d08f23bf41ef20dddf2986978dc8d3e6af Mon Sep 17 00:00:00 2001 From: "ljf (zamentur)" Date: Wed, 20 Oct 2021 13:55:53 +0200 Subject: [PATCH 08/11] [fix] Don't display all db migration log --- scripts/upgrade | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/upgrade b/scripts/upgrade index 299628a..5006f67 100644 --- a/scripts/upgrade +++ b/scripts/upgrade @@ -308,7 +308,7 @@ then chown root:root "$config_path/gitlab-persistent.rb" chmod 640 "$config_path/gitlab-persistent.rb" - gitlab-ctl reconfigure + gitlab-ctl reconfigure > /dev/null fi fi done @@ -325,7 +325,7 @@ touch "$config_path/gitlab-persistent.rb" chown root:root "$config_path/gitlab-persistent.rb" chmod 640 "$config_path/gitlab-persistent.rb" -gitlab-ctl reconfigure +gitlab-ctl reconfigure > /dev/null # Allow ssh for git usermod -a -G "ssh.app" "git" From 111cd4e684175c2a4d40fb694ae1d320b429156c Mon Sep 17 00:00:00 2001 From: Kay0u Date: Tue, 2 Nov 2021 11:55:29 +0100 Subject: [PATCH 09/11] Discard logs if the reconfigure process passes --- scripts/upgrade | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/scripts/upgrade b/scripts/upgrade index 5006f67..9d442f1 100644 --- a/scripts/upgrade +++ b/scripts/upgrade @@ -308,7 +308,10 @@ then chown root:root "$config_path/gitlab-persistent.rb" chmod 640 "$config_path/gitlab-persistent.rb" - gitlab-ctl reconfigure > /dev/null + # During large migrations, the logs are too big to be sent to paste.yunohost.org + # Send the reconfigure logs in a file, and if the process succeeds, just delete it. + gitlab-ctl reconfigure > "/tmp/gitlab_upgrade_$current_version.log" + ynh_secure_remove --file="/tmp/gitlab_upgrade_$current_version.log" fi fi done @@ -325,7 +328,7 @@ touch "$config_path/gitlab-persistent.rb" chown root:root "$config_path/gitlab-persistent.rb" chmod 640 "$config_path/gitlab-persistent.rb" -gitlab-ctl reconfigure > /dev/null +gitlab-ctl reconfigure # Allow ssh for git usermod -a -G "ssh.app" "git" From d70b3c2b134700e5d6b9850dd1969a7f5796565f Mon Sep 17 00:00:00 2001 From: Kay0u Date: Mon, 22 Nov 2021 18:49:19 +0100 Subject: [PATCH 10/11] 14.5.0 --- conf/gitlab.rb | 36 +++++++++++++++++++++++++++++++ manifest.json | 2 +- scripts/upgrade.d/upgrade.last.sh | 12 +++++------ 3 files changed, 43 insertions(+), 7 deletions(-) diff --git a/conf/gitlab.rb b/conf/gitlab.rb index 46c0ae3..7ee02d2 100644 --- a/conf/gitlab.rb +++ b/conf/gitlab.rb @@ -195,6 +195,7 @@ external_url '__GENERATED_EXTERNAL_URL__' # gitlab_rails['namespaces_in_product_marketing_emails_worker_cron'] = "0 9 * * *" # gitlab_rails['ssh_keys_expired_notification_worker_cron'] = "0 2 * * *" # gitlab_rails['ssh_keys_expiring_soon_notification_worker_cron'] = "0 1 * * *" +# gitlab_rails['loose_foreign_keys_cleanup_worker_cron'] = "*/5 * * * *" ### Webhook Settings ###! Number of seconds to wait for HTTP response after sending webhook HTTP POST @@ -680,6 +681,7 @@ gitlab_rails['gitlab_shell_ssh_port'] = __SSH_PORT__ ### Extra customization # gitlab_rails['extra_google_analytics_id'] = '_your_tracking_id' # gitlab_rails['extra_google_tag_manager_id'] = '_your_tracking_id' +# gitlab_rails['extra_one_trust_id'] = '_your_one_trust_id' # gitlab_rails['extra_matomo_url'] = '_your_matomo_url' # gitlab_rails['extra_matomo_site_id'] = '_your_matomo_site_id' # gitlab_rails['extra_matomo_disable_cookies'] = false @@ -793,6 +795,8 @@ gitlab_rails['gitlab_shell_ssh_port'] = __SSH_PORT__ # gitlab_rails['redis_actioncable_sentinels'] = nil # gitlab_rails['redis_rate_limiting_instance'] = nil # gitlab_rails['redis_rate_limiting_sentinels'] = nil +# gitlab_rails['redis_sessions_instance'] = nil +# gitlab_rails['redis_sessions_sentinels'] = nil ################################################################################ ## Container Registry settings @@ -1615,6 +1619,10 @@ nginx['listen_https'] = false ##! Default to 0 for unlimited connections. # gitlab_pages['max_connections'] = 0 +##! Configure the maximum length of URIs accepted by GitLab Pages +##! By default is limited for security reasons. Set 0 for unlimited +# gitlab_pages['max_uri_length'] = 1024 + ##! Setting the propagate_correlation_id to true allows installations behind a reverse proxy ##! generate and set a correlation ID to requests sent to GitLab Pages. If a reverse proxy ##! sets the header value X-Request-ID, the value will be propagated in the request chain. @@ -1707,6 +1715,16 @@ nginx['listen_https'] = false ##! Enable serving content from disk instead of Object Storage # gitlab_pages['enable_disk'] = nil +##! Rate-limiting options below work in report-only mode: +##! they only count rejected requests, but don't reject them +##! enable `FF_ENABLE_RATE_LIMITER=true` environment variable to +##! reject requests. + +##! Rate limit per source IP in number of requests per second, 0 means is disabled +# gitlab_pages['rate_limit_source_ip'] = 50.0 +##! Rate limit per source IP maximum burst allowed per second +# gitlab_pages['rate_limit_source_ip_burst'] = 600 + # gitlab_pages['env_directory'] = "/opt/gitlab/etc/gitlab-pages/env" # gitlab_pages['env'] = { # 'SSL_CERT_DIR' => "#{node['package']['install-dir']}/embedded/ssl/certs/" @@ -1745,6 +1763,7 @@ nginx['listen_https'] = false # gitlab_rails['gitlab_kas_enabled'] = true # gitlab_rails['gitlab_kas_external_url'] = ws://gitlab.example.com/-/kubernetes-agent # gitlab_rails['gitlab_kas_internal_url'] = grpc://localhost:8153 +# gitlab_rails['gitlab_kas_external_k8s_proxy_url'] = ws://gitlab.example.com/-/kubernetes-agent ##! Enable GitLab KAS # gitlab_kas['enable'] = true @@ -1760,16 +1779,29 @@ nginx['listen_https'] = false ##! Shared secret used for authentication between KAS and GitLab # gitlab_kas['api_secret_key'] = nil # Will be generated if not set. Base64 encoded and exactly 32 bytes long. +##! Shared secret used for authentication between different KAS instances in a multi-node setup +# gitlab_kas['private_api_secret_key'] = nil # Will be generated if not set. Base64 encoded and exactly 32 bytes long. + ##! Listen configuration for GitLab KAS # gitlab_kas['listen_address'] = 'localhost:8150' # gitlab_kas['listen_network'] = 'tcp' # gitlab_kas['listen_websocket'] = true # gitlab_kas['internal_api_listen_network'] = 'tcp' # gitlab_kas['internal_api_listen_address'] = 'localhost:8153' +# gitlab_kas['kubernetes_api_listen_address'] = 'localhost:8154' +# gitlab_kas['private_api_listen_network'] = 'tcp' +# gitlab_kas['private_api_listen_address'] = 'localhost:8155' ##! Metrics configuration for GitLab KAS # gitlab_kas['metrics_usage_reporting_period'] = 60 +##! Environment variables for GitLab KAS +# gitlab_kas['env'] = { +# 'SSL_CERT_DIR' => "/opt/gitlab/embedded/ssl/certs/", +# # In a multi-node setup, this address MUST be reachable from other KAS instances. In a single-node setup, it can be on localhost for simplicity +# 'OWN_PRIVATE_API_URL' => 'grpc://localhost:8155' +# } + ##! Directories for GitLab KAS # gitlab_kas['dir'] = '/var/opt/gitlab/gitlab-kas' # gitlab_kas['log_directory'] = '/var/log/gitlab/gitlab-kas' @@ -2074,6 +2106,10 @@ nginx['listen_https'] = false ##! Manage gitlab-exporter sidekiq probes. false by default when Sentinels are ##! found. # gitlab_exporter['probe_sidekiq'] = true +##! Service name used to register GitLab Exporter as a Consul service +# gitlab_exporter['consul_service_name'] = 'gitlab-exporter' +##! Semantic metadata used when registering GitLab Exporter as a Consul service +# gitlab_exporter['consul_service_meta'] = {} # To completely disable prometheus, and all of it's exporters, set to false # prometheus_monitoring['enable'] = true diff --git a/manifest.json b/manifest.json index 5637fcf..597018c 100644 --- a/manifest.json +++ b/manifest.json @@ -2,7 +2,7 @@ "name": "GitLab", "id": "gitlab", "packaging_format": 1, - "version": "14.4.0~ynh1", + "version": "14.5.0~ynh1", "description": { "en": "Git-repository manager providing wiki, issue-tracking and CI/CD pipeline features.", "fr": "Gestionnaire de dépôts Git proposant des fonctionnalités de wiki, suivi de bugs et de pipeline CI/CD." diff --git a/scripts/upgrade.d/upgrade.last.sh b/scripts/upgrade.d/upgrade.last.sh index 1ca3430..c81c4a8 100644 --- a/scripts/upgrade.d/upgrade.last.sh +++ b/scripts/upgrade.d/upgrade.last.sh @@ -1,15 +1,15 @@ #!/bin/bash -gitlab_version="14.4.0" +gitlab_version="14.5.0" # sha256sum found here: https://packages.gitlab.com/gitlab gitlab_debian_version="buster" -gitlab_x86_64_buster_source_sha256="89d12148595ac1e5e127ec96ed877e738c28e5eed02328d26b1610341c291d92" +gitlab_x86_64_buster_source_sha256="9665cde5950fb531bde2c585fbab6a76e6a9677868dc573d6435003b580833d4" -gitlab_arm64_buster_source_sha256="98ec153767bf80c55e12be896f2005658e91ed761715841fbf87bfb41953f961" +gitlab_arm64_buster_source_sha256="bb0372c1fe0aa8f7f741c3e0b709374309a1aa82462c391be4800fca189d209e" -gitlab_arm_buster_source_sha256="e950b5f4fa76d051eddd20ae9cd1aab017f9b0abee41be1fee566ed0b39146ea" +gitlab_arm_buster_source_sha256="9c7b3bf6704f4937d69ec7a5f3abeda2fcfe59721887d1012be3bca472cc13e7" architecture=$(ynh_app_setting_get --app="$app" --key=architecture) @@ -20,8 +20,8 @@ elif [ "$architecture" = "arm64" ]; then elif [ "$architecture" = "arm" ]; then # If the version for arm doesn't exist, then use an older one if [ -z "$gitlab_arm_buster_source_sha256" ]; then - gitlab_version="14.4.0" - gitlab_arm_buster_source_sha256="e950b5f4fa76d051eddd20ae9cd1aab017f9b0abee41be1fee566ed0b39146ea" + gitlab_version="14.5.0" + gitlab_arm_buster_source_sha256="9c7b3bf6704f4937d69ec7a5f3abeda2fcfe59721887d1012be3bca472cc13e7" fi gitlab_source_sha256=$gitlab_arm_buster_source_sha256 fi From 549bd754c8bac3bee77fd14b97634d2a1739af06 Mon Sep 17 00:00:00 2001 From: Yunohost-Bot <> Date: Mon, 22 Nov 2021 17:49:27 +0000 Subject: [PATCH 11/11] Auto-update README --- README.md | 2 +- README_fr.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index f2ddf19..075f6a0 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ If you don't have YunoHost, please consult [the guide](https://yunohost.org/#/in Git-repository manager providing wiki, issue-tracking and CI/CD pipeline features. -**Shipped version:** 14.4.0~ynh1 +**Shipped version:** 14.5.0~ynh1 **Demo:** https://gitlab.com/explore diff --git a/README_fr.md b/README_fr.md index 037a39b..e15dcea 100644 --- a/README_fr.md +++ b/README_fr.md @@ -13,7 +13,7 @@ Si vous n'avez pas YunoHost, regardez [ici](https://yunohost.org/#/install) pour Gestionnaire de dépôts Git proposant des fonctionnalités de wiki, suivi de bugs et de pipeline CI/CD. -**Version incluse :** 14.4.0~ynh1 +**Version incluse :** 14.5.0~ynh1 **Démo :** https://gitlab.com/explore