diff --git a/LICENSE b/LICENSE new file mode 100644 index 00000000..5f942d3f --- /dev/null +++ b/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2011-2023 Uladzimir Tsykun, Jordi Boggiano, Nils Adermann + +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: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +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. diff --git a/README.md b/README.md new file mode 100644 index 00000000..4bfea85e --- /dev/null +++ b/README.md @@ -0,0 +1,456 @@ +Packeton - Private PHP package repository for vendors +====================================================== + +[![Docker pulls](https://img.shields.io/docker/pulls/okvpn/packeton.svg?label=docker+pulls)](https://hub.docker.com/r/okvpn/packeton) +[![Docker stars](https://img.shields.io/docker/stars/okvpn/packeton.svg?label=docker+stars)](https://hub.docker.com/r/okvpn/packeton) +[![Docker version](https://images.microbadger.com/badges/version/okvpn/packeton.svg)](https://hub.docker.com/r/okvpn/packeton) +[![Docker layers](https://images.microbadger.com/badges/image/okvpn/packeton.svg)](https://hub.docker.com/r/okvpn/packeton) + +Fork of [Packagist](https://github.com/composer/packagist). +The Open Source alternative of [Private Packagist for vendors](https://packagist.com), that based on [Satis](https://github.com/composer/satis) and [Packagist](https://github.com/composer/packagist). + +Features +-------- + +- Compatible with composer. +- Support update webhook for GitHub, Bitbucket and GitLab. +- Support custom webhook format. +- Customers user and groups. +- Generic Packeton [webhooks](docs/webhook.md) +- Limit access by vendor and versions. +- Allow to freeze updates for the new releases after expire a customers license. +- Mirroring for packages' zip files and downloads its from your host. +- Allow to add ssh keys from UI and use multiple SSH Keys settings for different github/git accounts. + +What was changed in this fork? +----------------------------- +- Disable anonymously access, registrations, spam/antispam, added groups and permissions. +- Support MySQL and PostgresSQL. +- Removed HWIOBundle, Algolia, GoogleAnalytics and other not used dependencies. + +Table of content +--------------- + +- [Run as Docker container](#install-and-run-in-docker) +- [Demo](#demo) +- [Installation from code](#installation) +- [Outgoing Webhook](/docs/webhook.md) + - [Intro](/docs/webhook.md#introduction) + - [Examples](/docs/webhook.md#examples) + - [Telegram notification](/docs/webhook.md#telegram-notification) + - [Slack notification](/docs/webhook.md#slack-notification) + - [JIRA issue fix version](/docs/webhook.md#jira-create-a-new-release-and-set-fix-version) + - [Gitlab setup auto webhook](/docs/webhook.md#gitlab-auto-webhook) +- [Ssh key access](#ssh-key-access-and-composer-oauth-token) +- [Update Webhooks](#update-webhooks) + - [Github](#github-webhooks) + - [GitLab](#gitlab-service) + - [GitLab Organization](#gitlab-group-hooks) + - [Bitbucket](#bitbucket-webhooks) + - [Manual hook](#manual-hook-setup) + - [Custom webhook format](#custom-webhook-format-transformer) +- [Usage](#usage-and-authentication) + - [Create admin user](#create-admin-user) + +Demo +---- +See our [Administration Demo](https://pkg.okvpn.org). Username/password (admin/composer) + +[![Demo](docs/img/demo.png)](docs/img/demo.png) + +Install and Run in Docker +------------------------ + +Pull the image from docker hub https://hub.docker.com/r/okvpn/packeton: + +``` +docker pull okvpn/packeton +``` + +Run the image (with docker-composer): + +```yaml +version: '3' + +services: + packagist: + image: okvpn/packeton:latest + container_name: packagist + restart: unless-stopped + hostname: packagist + volumes: + - .docker/redis:/var/lib/redis # Redis data + - .docker/zipball:/var/www/packagist/app/zipball # Zipped archive cache for "dist" downloads + - .docker/composer:/var/www/.composer # Composer cache + - .docker/ssh:/var/www/.ssh # Share here your ssh keys + environment: + PRIVATE_REPO_DOMAIN_LIST: bitbucket.org gitlab.com github.com + PACKAGIST_DIST_HOST: https://pkg.okvpn.org # Dist url to download the zip package. + DATABASE_HOST: 172.17.0.1 + DATABASE_PORT: 5432 + DATABASE_DRIVER: pdo_pgsql + DATABASE_USER: postgres + DATABASE_NAME: packagist + DATABASE_PASSWORD: 123456 + ADMIN_USER: admin + ADMIN_PASSWORD: composer + ADMIN_EMAIL: admin@example.com + GITHUB_NO_API: 'true' + ports: + - 127.0.0.1:8080:80 +``` + +Also you can configure Packeton server to run behind a NGINX reverse proxy. +For example to enable ssl. + +``` +server { + listen *:443 ssl http2; + + server_name pkg.okvpn.org; + + ssl_certificate /etc/letsencrypt/live/pkg.okvpn.org/fullchain.pem; + ssl_certificate_key /etc/letsencrypt/live/pkg.okvpn.org/privkey.pem; + ssl_dhparam /etc/nginx/ssl/dh.pem; + ssl_ciphers 'ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:ECDHE-RSA-DES-CBC3-SHA:AES256-GCM-SHA384:AES128-GCM-SHA256:AES256-SHA256:AES128-SHA256:AES256-SHA:AES128-SHA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!MD5:!PSK:!RC4'; + + ssl_protocols TLSv1.1 TLSv1.2; + ssl_prefer_server_ciphers on; + ssl_session_cache builtin:1000 shared:SSL:10m; + ssl_session_timeout 5m; + access_log off; + error_log /var/log/nginx/pkg_error.log; + + gzip_vary on; + gzip_proxied any; + gzip_comp_level 6; + gzip_buffers 16 16k; + gzip_http_version 1.1; + gzip_min_length 2048; + gzip_types text/css image/svg+xml application/octet-stream application/javascript text/javascript application/json; + + location / { + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-Proto https; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_pass http://127.0.0.1:8080/; + } +} + +server { + if ($host = pkg.okvpn.org) { + return 301 https://$host$request_uri; + } # managed by Certbot + + listen 80; + return 301 https://$host$request_uri; + server_name pkg.okvpn.org; +} +``` + +Installation +------------ + +### Requirements + +- MySQL or PostgresSQL for the main data store. +- Redis for some functionality (favorites, download statistics, worker queue). +- git/svn/hg depending on which repositories you want to support. +- Supervisor to run a background job worker + +1. Clone the repository +2. Copy and edit `app/config/parameters.yml` and change the relevant values for your setup. +3. Install dependencies: `composer install` +4. Run `bin/console doctrine:schema:create` to setup the DB +5. Run `bin/console assets:install web` to deploy the assets on the web dir. +6. Run `bin/console cache:warmup --env=prod` and `app/console cache:warmup --env=prod` to warmup cache +7. Create admin user via console. + +``` +php bin/console fos:user:create +# Add admin role +php bin/console fos:user:promote ROLE_ADMIN +# Add maintainer role +php bin/console fos:user:promote ROLE_MAINTAINER +``` + +8. Enable cron tabs and background jobs. +Enable crontab `crontab -e -u www-data` + +``` +* * * * * /var/www/packagist/bin/console --env=prod okvpn:cron >> /dev/null +``` + +Setup Supervisor to run worker. + +``` +sudo apt -y --no-install-recommends install supervisor +``` + +Create a new supervisor configuration. + +``` +sudo vim /etc/supervisor/conf.d/packagist.conf +``` +Add the following lines to the file. + +``` +[program:packagist-workers] +environment = + HOME=/var/www/ +command=/var/www/packagist/bin/console packagist:run-workers --env=prod --no-debug +directory=/var/www/packagist/ +process_name=%(program_name)s_%(process_num)02d +numprocs=1 +autostart=true +autorestart=true +startsecs=0 +redirect_stderr=true +priority=1 +user=www-data +``` + +9. **IMPORTANT** Make sure that web-server, cron and supervisor run under the same user, that should have an ssh key +that gives it read (clone) access to your git/svn/hg repositories. If you run application under `www-data` +you can add your ssh keys to /var/www/.ssh/ + +You should now be able to access the site, create a user, etc. + +10. Make a VirtualHost with DocumentRoot pointing to web/ + +Ssh key access and composer oauth token. +----------------------- +Packagist uses the Composer global config and global ssh-key to get read access to your repositories, so +the supervisor worker `packagist:run-workers` and web-server must run under the user, +that have ssh key or composer config that gives it read (clone) access to your git/svn/hg repositories. +For example, if your application runs under `www-data` and have home directory `/var/www`, directory +structure must be like this. + +``` + └── /var/www/ + ├── .ssh/ # ssh keys directory + │ ├── config + │ ├── id_rsa # main ssh key + │ ├── private_key_2 # additional ssh key + │ └── private_key_3 + │ + └── .composer/ # composer home + ├── auth.json + └── config.json + +``` + +Example ssh config for multiple SSH Keys for different github account/repos, +see [here for details](https://gist.github.com/jexchan/2351996) + +``` +# .ssh/config - example + +Host github-oroinc + HostName github.com + User git + IdentityFile /var/www/.ssh/private_key_2 + IdentitiesOnly yes + +Host github-org2 + HostName github.com + User git + IdentityFile /var/www/.ssh/private_key_3 + IdentitiesOnly yes + +``` + +You can add GitHub/GitLab access token to `auth.json`, see [here](https://gist.github.com/jeffersonmartin/d0d4a8dfec90d224d14f250b36c74d2f) + +``` +{ + "github-oauth": { + "github.com": "xxxxxxxxxxxxx" + } +} +``` + +#### Don't use GitHub Api. + +By default composer will use GitHub API to get metadata for your GitHub repository, you can add +`use-github-api` to composer config.json to always use ssh key and clone the repository as +it would with any other git repository, [see here](https://getcomposer.org/doc/06-config.md#use-github-api) + +Update Webhooks +--------------- +You can use GitLab, GitHub, and Bitbucket project post-receive hook to keep your packages up to date +every time you push code. + +#### Bitbucket Webhooks +To enable the Bitbucket web hook, go to your BitBucket repository, +open the settings and select "Webhooks" in the menu. Add a new hook. Y +ou have to enter the Packagist endpoint, containing both your username and API token. +Enter `https:///api/bitbucket?token=user:token` as URL. Save your changes and you're done. + +#### GitLab Service + +To enable the GitLab service integration, go to your GitLab repository, open +the Settings > Integrations page from the menu. +Search for Packagist in the list of Project Services. Check the "Active" box, +enter your `packeton.org` username and API token. Save your changes and you're done. + +#### GitLab Group Hooks + +Group webhooks will apply to all projects in a group and allow to sync all projects. +To enable the Group GitLab webhook you must have the paid plan. +Go to your GitLab Group > Settings > Webhooks. +Enter `https:///api/update-package?token=user:token` as URL. + +#### GitHub Webhooks +To enable the GitHub webhook go to your GitHub repository. Click the "Settings" button, click "Webhooks". +Add a new hook. Enter `https:///api/github?token=user:token` as URL. + +#### Manual hook setup + +If you do not use Bitbucket or GitHub there is a generic endpoint you can call manually +from a git post-receive hook or similar. You have to do a POST request to +`https://pkg.okvpn.org/api/update-package?token=user:api_token` with a request body looking like this: + +``` +{ + "repository": { + "url": "PACKAGIST_PACKAGE_URL" + } +} +``` + +Also you can overwrite regex that was used to parse the repository url, +see [ApiController](src/Packagist/WebBundle/Controller/ApiController.php#L348) + +``` +{ + "repository": { + "url": "PACKAGIST_PACKAGE_URL" + }, + "packeton": { + "regex": "{^(?:ssh://git@|https?://|git://|git@)?(?P[a-z0-9.-]+)(?::[0-9]+/|[:/])(scm/)?(?P[\\w.-]+(?:/[\\w.-]+?)+)(?:\\.git|/)?$}i" + } +} +``` + +You can do this using curl for example: + +``` +curl -XPOST -H 'content-type:application/json' 'https://pkg.okvpn.org/api/update-package?token=user:api_token' -d' {"repository":{"url":"PACKAGIST_PACKAGE_URL"}}' +``` + +Instead of using repo url you can use directly composer package name. +You have to do a POST request with a request body. + +``` +{ + "composer": { + "package_name": "okvpn/test" + } +} +``` + +``` +{ + "composer": { + "package_name": ["okvpn/test", "okvpn/pack2"] + } +} +``` + +#### Custom webhook format transformer + +You can create a proxy middleware to transform JSON payload to the applicable inner format. +In first you need create a new Rest Endpoint to accept external request. + +Go to `Settings > Webhooks` and click `Add webhook`. Fill the form: + - url - `https:///api/update-package?token=user:token` + - More options > Name restriction - `#your-unique-name#` (must be a valid regex) + - Trigger > By HTTP requests to https://APP_URL/api/webhook-invoke/{name} - select checkbox + - Payload - Write a script using twig expression to transform external request to POST request from previous example. + +For example, if the input request has a format, the twig payload may look like this: + +```json +{ + "repository":{ + "slug":"vtsykun-packeton", + "id":11, + "name":"vtsykun-packeton", + "scmId":"git", + "state":"AVAILABLE", + "links": { + "clone": [ + {"href": "https://github.com/vtsykun/packeton.git"} + ] + } + } +} +``` + +```twig +{% set repository = request.repository.links.clone[0].href %} +{% if repository is null %} + {{ interrupt('Request does not contains repository link') }} +{% endif %} + +{% set response = { + 'repository': {'url': repository }, + 'packeton': {'regex': '{^(?:ssh://git@|https?://|git://|git@)?(?P[a-z0-9.-]+)(?::[0-9]+/|[:/])(scm/)?(?P[\\w.-]+(?:/[\\w.-]+?)+)(?:\\.git|/)?$}i'} +} %} + +{{ response|json_encode }} +``` + +See [twig expression](docs/webhook.md) syntax for details. + +Click the "Save button" + +Now if you call the url `https://APP_URL/api/webhook-invoke/your-unique-name?token=:` +request will be forward to `https://APP_URL/api/update-package?token=user:token` with converted POST +payload according to your rules. + +Usage and Authentication +------------------------ +By default admin user have access to all repositories and able to submit packages, create users, view statistics. +The customer users can only see related packages and own profile with instruction how to use api token. + +To authenticate composer access to repository needs add credentials globally into auth.json, for example: + +``` +composer config --global --auth http-basic.pkg.okvpn.org +``` + +API Token you can found in your Profile. + +Configure this private repository in your `composer.json`. + +``` +{ + "repositories": [{ + "type": "composer", + "url": "https://packeton.company.com" + }], + "require": { + "company/name1": "1.0.*", + .... + } +} +``` + +### Create admin and maintainer users. + +Only admin and maintainer user can submit a new package. +Only admin user can create the new customer users. +You can create an user and then promote to admin or maintainer via console using fos user bundle commands. + +``` +php bin/console fos:user:create +php bin/console fos:user:promote ROLE_ADMIN +``` + + +LICENSE +------ +MIT diff --git a/docs/img/demo.png b/docs/img/demo.png new file mode 100644 index 00000000..dc94d249 Binary files /dev/null and b/docs/img/demo.png differ diff --git a/docs/img/diagram.png b/docs/img/diagram.png new file mode 100644 index 00000000..f9278ca2 Binary files /dev/null and b/docs/img/diagram.png differ diff --git a/docs/img/jira.png b/docs/img/jira.png new file mode 100644 index 00000000..c2f1d587 Binary files /dev/null and b/docs/img/jira.png differ diff --git a/docs/img/jira_response.png b/docs/img/jira_response.png new file mode 100644 index 00000000..04bd1dd1 Binary files /dev/null and b/docs/img/jira_response.png differ diff --git a/docs/img/placeholder.png b/docs/img/placeholder.png new file mode 100644 index 00000000..255e3a30 Binary files /dev/null and b/docs/img/placeholder.png differ diff --git a/docs/img/telegram.png b/docs/img/telegram.png new file mode 100644 index 00000000..a40e144c Binary files /dev/null and b/docs/img/telegram.png differ diff --git a/docs/webhook.md b/docs/webhook.md new file mode 100644 index 00000000..4201eeb7 --- /dev/null +++ b/docs/webhook.md @@ -0,0 +1,351 @@ +# Generic Packeton webhooks + +Introduction +---------- +Webhooks allow external services to be notified when certain events happen. +When the specified events happen, packeton will send a POST request to each of the URLs you provide. +Now is supported the next events: + +- new_release +- update_release +- delete_release +- push_new_event +- update_new_event +- http_request +- update_repo_failed +- new_repo +- delete_repo + +![diagram](img/diagram.png) + +It may be useful for release/deploy process, for example: Automatically create new Jira release +when a new version is created in packagist (triggered when new tag is created in bitbucket) and +update "fix version" attribute of all the related issues from that release. + + +To build a custom request payload uses Twig expression language. +This allows you to create custom queries. Untrusted template code is evaluate in a Twig sandbox mode, so +you will get an error if try to get access for security sensitive information. +By default only admin users can use Webhooks. + +``` +Exception (Twig\Sandbox\SecurityNotAllowedMethodError). Calling "setemail" method on a "Packagist\WebBundle\Entity\User" object is not allowed in "__string_template__0d2344b042278505e67568413272d80429f07ecccea43af39cb33608fa747830" at line 1. +``` + +Examples +======== + + - [List of twig variables](#twig-variables) + - [Telegram notification](#telegram-notification) + - [Slack notification](#slack-notification) + - [How to use url placeholder](#use-url-placeholder) + - [Interrupt request](#interrupt-request) + - [Nesting webhook](#nesting-webhook) + - [Gitlab setup auto webhook](#gitlab-auto-webhook) + - [JIRA issue fix version](#jira-create-a-new-release-and-set-fix-version) + - [Accept external request](#external-request) + - [Packeton twig function](#new-twig-functions) + +Twig variables +--------------- + +- package - `Package` entity. +- versions - `Versions[]` array of versions. +- webhook - `Webhook` current webhook entity. +- user - `User` entity. Only for user login event. +- parentResponse - `HookResponse` object. Only for nesting webhook. +- request - `array` Only for http request event. + +Telegram notification +--------------------- + +POST `https://api.telegram.org/bot$TELEGRAM_TOKEN/sendMessage` + +Options: +```json +{ + "headers": { + "Content-Type": "application/json" + } +} +``` + +Payload + +```twig +{% set text = "*New Releases*\n" %} +{% set title = package.name ~ ' (' ~ versions|map(v => "#{v.version}")|join(',') ~ ')' %} +{% set text = text ~ "[" ~ title ~ "](https://pkg.okvpn.org/packages/" ~ package.name ~ ")\n" %} +{% set text = text ~ package.description %} + +{% set request = { + 'chat_id': '-1000006111000', + 'parse_mode': 'Markdown', + 'text': text +} %} + +{{ request|json_encode }} +``` + +![Telegram](img/telegram.png) + +Slack notification +------------------ +In first you need create a [slack app](https://api.slack.com/apps) + +POST `https://slack.com/api/chat.postMessage` + +Options: + +```json +{ + "headers": { + "Content-Type": "application/json", + "Authorization": "Bearer xoxp-xxxxxxxxxxxxxxxxxxxxxxxxxx" + } +} +``` + +Payload + +```twig +{% set text = "*New Releases*\n" %} +{% set title = package.name ~ ' (' ~ versions|map(v => "#{v.version}")|join(',') ~ ')' %} +{% set text = text ~ "\n" %} +{% set text = text ~ package.description %} + +{% set request = { + 'channel': 'jenkins', + 'text': text +} %} + +{{ request|json_encode }} +``` + +Use url placeholder +------------------- + +The placeholder allow to build URL parameters from twig template. + +`http://httpbin.org/{{ method }}?repo={{ repoName }}` + +*Syntax* + +Use `placeholder` tag +``` +URL: http://httpbin.org/post?repo={{ paramName }} + +Variant 1. Send single request. + +{% placeholder with %} + +Variant 2. Send many request for each value from array string[] + +{% placeholder with %} +``` + +Example + +`http://httpbin.org/{{ method }}?repo={{ repoName }}` + +Payload + +```twig +{% placeholder method with 'post' %} +{% placeholder repoName with [package.name, 'test/test'] %} +``` + +![URL Placeholder](img/placeholder.png) + +Interrupt request +----------------- + +You can interrupt request if condition is not pass + +*Syntax* + +Use `interrupt` function. + +Payload + +```twig +{% set request = { + 'chat_id': '1555151', + 'parse_mode': 'Markdown', + 'text': 'Text' +} %} + +{% if package.name == 'okvpn/mq-insight' %} + {{ interrupt() }} +{% endif %} + +{{ request|json_encode }} +``` + +Nesting webhook +--------------- + +You can trigger webhook from twig code. It may be used for send two requests a one event. + +*Syntax* + +Use `trigger_webhook(hookId: int|Webhook, context: array)` function. + +Example Payload + +```twig +{% do trigger_webhook(6, {'project': 'OK', 'version': versions[0].version}) %} +``` + +Jira create a new release and set fix version +--------------------------------------- + +You need to create two webhook for its, the first must triggers on a new release event, +the second will be called from twig code. + +![Jira](img/jira.png) + +#### Create a new release in JIRA + +POST `https://jiraserver/rest/api/2/version` + +Options: + +```json +{ + "headers": { + "Content-Type": "application/json" + }, + "auth_basic": "jirauser:password" +} +``` + +Payload + +```twig +{% set changeLog = get_changelog(package, null, versions[0].version) %} +{% set ticket = preg_match_all('/((OK|OTEK)-(\\d+))\\s*:/u', changeLog|join(';'), 1) %} + +{% set request = { + 'archived': false, + 'releaseDate': versions[0].releasedAt|date('Y-m-d'), + 'name': versions[0].version, + 'released': true, + 'description': 'Packagist auto release', + 'project': 'OK' +} %} + +{% if ticket|length == 0 %} + {{ interrupt('There are not commits with JIRA tiket no.') }} +{% endif %} + +{% do trigger_webhook(6, {'project': 'OK', 'ticket': ticket, 'version': versions[0].version}) %} +{{ request|json_encode }} +``` + +#### Update an issue fix version + +PUT `https://jiraserver/rest/api/2/issue/{{ issue }}` + +Options: + +```json +{ + "headers": { + "Content-Type": "application/json" + }, + "auth_basic": "jirauser:password" +} +``` +Payload + +```twig +{% placeholder issue with ticket %} + +{% set request = { + 'fields': { + 'fixVersions': [{'name': version}] + } +} %} + +{{ request|json_encode }} +``` + +![Jira issue](img/jira_response.png) + +Http request from code +--------------------- + +You can made http request from twig code. + +```twig +{% set tags = http_request('https://registry.hub.docker.com/v1/repositories/okvpn/orocommerce/tags') %} + +{{ tags|json_encode }} +``` + +External request +---------------- +Triggered webhook by HTTP requests to `https://PACKEGIST_URL/api/webhook-invoke/{name}` + +Optional `name`. If it is specified then this webhook can only be triggered if that name is supplied +when invoking `https://PACKEGIST_URL/api/webhook-invoke/{name}` and name restriction is match. + +Example payload: + +```twig +{% if request.packageName is null %} + {{ interrupt('package name is not found') }} +{% endif %} + +{% set tags = http_request('https://registry.hub.docker.com/v1/repositories/' ~ request.packageName ~'/tags') %} + +{{ tags|json_encode }} +``` + +Gitlab auto webhook +------------------- +You can use the event `new_repo` to add a hook to the specified Gitlab project. +It can be useful, if you don't have a Gold Gitlab Plan that allows configure webhooks for your group, +so you need add it manually for each a new repository. + +POST `https://{{ host }}/api/v4/projects/{{ repo }}/hooks?private_token=xxxxxxxxxxxxxxxx` + +Options: + +```json +{ + "headers": { + "Content-Type": "application/json" + } +} +``` + +Payload + +```twig +{% set regex = '#^(?:ssh://git@|https?://|git://|git@)?(?P[a-z0-9.-]+)(?::[0-9]+/|[:/])(?P[\\w.-]+(?:/[\\w.-]+?)+)(?:\\.git|/)?$#i' %} +{% set repository = preg_match_all(regex, package.repository) %} + +{% if repository.path[0] is null or repository.host[0] is null %} + {{ interrupt('Regex is not match') }} +{% endif %} + +{% set request = { + 'url': 'https://pkg.okvpn.org/api/update-package?token=admin:xxxxxxxxxxxxxxxx', + 'push_events': true, + 'tag_push_events': true +} %} + +{% placeholder host with repository.host[0] %} +{% placeholder repo with repository.path[0]|url_encode %} + +{{ request|json_encode }} +``` + +Here you need replace `request.url` on your packagist. + +New twig functions +----------------- + +See [WebhookExtension](/src/Packagist/WebBundle/Webhook/Twig/WebhookExtension.php) for details.