From 2d99e4a5ed01060244b27c3a341c9cc58c50211d Mon Sep 17 00:00:00 2001
From: Martin Chodur <martin.chodur@firma.seznam.cz>
Date: Sun, 11 Aug 2019 20:05:44 +0200
Subject: [PATCH] feat: initial release

Signed-off-by: Martin Chodur <m.chodur@seznam.cz>
---
 .circleci/config.yml                          |  49 ++++
 .gitignore                                    |  11 +-
 .golangci.yml                                 |   6 +
 .promu.yml                                    |  20 ++
 CHANGELOG.md                                  |  62 ++++
 Dockerfile                                    |  16 +
 LICENSE                                       | 222 ++++++++++++--
 MAINTAINERS.md                                |   1 +
 Makefile                                      |  23 ++
 Makefile.common                               | 277 ++++++++++++++++++
 README.md                                     |  93 +++++-
 VERSION                                       |   1 +
 .../prometheus-gitlab-notifier.go             | 189 ++++++++++++
 conf/alert.json                               |  32 ++
 conf/alertmanager_conf.yaml                   |   9 +
 conf/default_issue.tmpl                       |  31 ++
 conf/issue_example.png                        | Bin 0 -> 46088 bytes
 errcheck_excludes.txt                         |   1 +
 go.mod                                        |  13 +
 go.sum                                        | 195 ++++++++++++
 kubernetes/gitlab-token-secret.yaml           |   6 +
 kubernetes/issue-template-configmap.yaml      |  37 +++
 ...prometheus-gitlab-notifier-deployment.yaml |  55 ++++
 .../prometheus-gitlab-notifier-service.yaml   |  12 +
 pkg/alertmanager/webhook.go                   |  49 ++++
 pkg/api/api.go                                |  86 ++++++
 pkg/gitlab/gitlab.go                          | 249 ++++++++++++++++
 pkg/handler/handler.go                        |  72 +++++
 pkg/metrics/metrics.go                        |  73 +++++
 pkg/prober/prober.go                          |  79 +++++
 pkg/processor/processor.go                    |  85 ++++++
 31 files changed, 2031 insertions(+), 23 deletions(-)
 create mode 100644 .circleci/config.yml
 create mode 100644 .golangci.yml
 create mode 100644 .promu.yml
 create mode 100644 CHANGELOG.md
 create mode 100644 Dockerfile
 create mode 100644 MAINTAINERS.md
 create mode 100644 Makefile
 create mode 100644 Makefile.common
 create mode 100644 VERSION
 create mode 100644 cmd/prometheus-gitlab-notifier/prometheus-gitlab-notifier.go
 create mode 100644 conf/alert.json
 create mode 100644 conf/alertmanager_conf.yaml
 create mode 100644 conf/default_issue.tmpl
 create mode 100644 conf/issue_example.png
 create mode 100644 errcheck_excludes.txt
 create mode 100644 go.mod
 create mode 100644 go.sum
 create mode 100644 kubernetes/gitlab-token-secret.yaml
 create mode 100644 kubernetes/issue-template-configmap.yaml
 create mode 100644 kubernetes/prometheus-gitlab-notifier-deployment.yaml
 create mode 100644 kubernetes/prometheus-gitlab-notifier-service.yaml
 create mode 100644 pkg/alertmanager/webhook.go
 create mode 100644 pkg/api/api.go
 create mode 100644 pkg/gitlab/gitlab.go
 create mode 100644 pkg/handler/handler.go
 create mode 100644 pkg/metrics/metrics.go
 create mode 100644 pkg/prober/prober.go
 create mode 100644 pkg/processor/processor.go

diff --git a/.circleci/config.yml b/.circleci/config.yml
new file mode 100644
index 0000000..c2f20be
--- /dev/null
+++ b/.circleci/config.yml
@@ -0,0 +1,49 @@
+---
+version: 2.1
+
+executors:
+  # Whenever the Go version is updated here, .travis.yml and .promu.yml
+  # should also be updated.
+  golang:
+    docker:
+    - image: circleci/golang:1.12
+
+jobs:
+  test:
+    executor: golang
+
+    steps:
+    - prometheus/setup_environment
+    - run: make
+    - prometheus/store_artifact:
+        file: prometheus-gitlab-notifier
+
+workflows:
+  version: 2
+  pushgateway:
+    jobs:
+    - test:
+        filters:
+          tags:
+            only: /.*/
+    - prometheus/build:
+        name: build
+        filters:
+          tags:
+            only: /.*/
+    - prometheus/publish_master:
+        requires:
+        - test
+        - build
+        filters:
+          branches:
+            only: master
+    - prometheus/publish_release:
+        requires:
+        - test
+        - build
+        filters:
+          tags:
+            only: /^v[0-9]+(\.[0-9]+){2}(-.+|[^-.]*)$/
+          branches:
+            ignore: /.*/
diff --git a/.gitignore b/.gitignore
index f1c181e..2336c74 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,5 @@
+# Created by .ignore support plugin (hsz.mobi)
+### Go template
 # Binaries for programs and plugins
 *.exe
 *.exe~
@@ -5,8 +7,15 @@
 *.so
 *.dylib
 
-# Test binary, build with `go test -c`
+# Test binary, built with `go test -c`
 *.test
 
 # Output of the go coverage tool, specifically when used with LiteIDE
 *.out
+
+# Dependency directories (remove the comment below to include it)
+# vendor/
+
+/conf/*.token
+/prometheus-gitlab-notifier
+
diff --git a/.golangci.yml b/.golangci.yml
new file mode 100644
index 0000000..f9abe8d
--- /dev/null
+++ b/.golangci.yml
@@ -0,0 +1,6 @@
+service:
+  golangci-lint-version: 1.12.4
+
+linters-settings:
+  errcheck:
+    exclude: errcheck_excludes.txt
diff --git a/.promu.yml b/.promu.yml
new file mode 100644
index 0000000..d4e4510
--- /dev/null
+++ b/.promu.yml
@@ -0,0 +1,20 @@
+go:
+  # Whenever the Go version is updated here, .travis.yml and
+  # .circle/config.yml should also be updated.
+  version: 1.12
+repository:
+  path: github.com/fusakla/prometheus-gitlab-notifier
+build:
+  binaries:
+    - name: prometheus-gitlab-notifier
+      path: ./cmd/prometheus-gitlab-notifier
+  flags: -a -tags netgo
+  ldflags: |
+    -X github.com/fusakla/prometheus-gitlab-notifier/metrics.appVersion={{.Version}}
+    -X github.com/fusakla/prometheus-gitlab-notifier/metrics.gitRevision={{.Revision}}
+    -X github.com/fusakla/prometheus-gitlab-notifier/metrics.gitBranch={{.Branch}}
+    -X github.com/fusakla/prometheus-gitlab-notifier/metrics.gitTag={{.Version}}
+tarball:
+  files:
+    - LICENSE
+    - NOTICE
diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
index 0000000..cf94cc5
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,62 @@
+# Changelog
+All notable changes to this project will be documented in this file.
+
+The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
+and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
+
+## [Unreleased]
+
+## [0.6.0] - 2019-07-17
+
+>**! Warning:** This release significantly changes logic of creating Gitlab issues and labeling scheme. 
+Please read more about the new grouping feature.  
+
+## Changed
+- Dynamic labels are now added as scoped labels to the issues in form `label::value`
+- To every issue the group- To every issue the grouping labels are added as scoped labels same way as dynamic labels. 
+ing labels are added as scoped labels same way as dynamic labels. 
+
+## Added
+- If alert comes and opened issue with the same group labels is present in the Gitlab, 
+the rendered template is just appended to this already existing issue instead of creating a new one.
+This applies only for issues younger than by default `1h` which can be controlled by new flag `--group.interval`. 
+Every appended issue gets new scoped label `appended-alerts::<numer>` with number of times it was appended.
+- Readme notes about contributing and release.
+
+## [0.5.0] - 2019-07-10
+
+## Added
+- Added dynamic label addition from the alert labels using flag `dynamic.issue.label.name`
+
+## [0.4.1] - 2019-06-27
+
+## Fixed
+- Metric `app_build_info` is now initialized to value `1`
+
+## [0.4.0] - 2019-06-27
+
+## Added
+- Added time to log messages
+- Added metric `app_build_info` with info about version of the app, build etc.
+
+## [0.3.0] - 2019-06-26
+
+## Changed
+- Removed Gitlab call from readiness probe since the alerts
+are just enqueued and retrying should take care of that.
+
+## Added
+- Check on startup that Gitlab is reachable.
+
+## [0.2.0] - 2019-06-26
+
+## Added:
+- Added `status_code` to metrics and access log.
+
+## Changed
+- Refactored HTTP server middleware.
+
+## [0.1.0] - 2019-06-25
+
+Initial release
+
diff --git a/Dockerfile b/Dockerfile
new file mode 100644
index 0000000..84792d8
--- /dev/null
+++ b/Dockerfile
@@ -0,0 +1,16 @@
+ARG ARCH="amd64"
+ARG OS="linux"
+FROM quay.io/prometheus/busybox:latest
+LABEL maintainer="FUSAKLA Martin Chodúr <m.chodur@seznam.cz>"
+
+COPY --chown=nobody:nogroup .build/${OS}-${ARCH}/prometheus-gitlab-notifier /bin/prometheus-gitlab-notifier
+COPY --chown=nobody:nogroup conf/default_issue.tmpl /prometheus-gitlab-notifier/conf/
+COPY --chown=nobody:nogroup Dockerfile /
+
+EXPOSE 9288
+RUN mkdir -p /prometheus-gitlab-notifier && chown nobody:nogroup /prometheus-gitlab-notifier
+WORKDIR /prometheus-gitlab-notifier
+
+USER 65534
+
+ENTRYPOINT ["/bin/prometheus-gitlab-notifier"]
diff --git a/LICENSE b/LICENSE
index 43fddfd..261eeb9 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,21 +1,201 @@
-MIT License
-
-Copyright (c) 2019 Martin Chodur
-
-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.
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
diff --git a/MAINTAINERS.md b/MAINTAINERS.md
new file mode 100644
index 0000000..cd9df82
--- /dev/null
+++ b/MAINTAINERS.md
@@ -0,0 +1 @@
+* FUSAKLA Martin Chodúr <m.chodur@seznam.cz>
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..9fcb143
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,23 @@
+# Copyright 2016 The Prometheus Authors
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Needs to be defined before including Makefile.common to auto-generate targets
+DOCKER_ARCHS ?= amd64 armv7 arm64
+
+include Makefile.common
+
+DOCKER_IMAGE_NAME ?= prometheus-gitlab-notifier
+
+assets:
+	@echo ">> writing assets"
+	@cd $(PREFIX)/asset && GO111MODULE=$(GO111MODULE) $(GO) generate && $(GOFMT) -w assets_vfsdata.go
diff --git a/Makefile.common b/Makefile.common
new file mode 100644
index 0000000..db98993
--- /dev/null
+++ b/Makefile.common
@@ -0,0 +1,277 @@
+# Copyright 2018 The Prometheus Authors
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+
+# A common Makefile that includes rules to be reused in different prometheus projects.
+# !!! Open PRs only against the prometheus/prometheus/Makefile.common repository!
+
+# Example usage :
+# Create the main Makefile in the root project directory.
+# include Makefile.common
+# customTarget:
+# 	@echo ">> Running customTarget"
+#
+
+# Ensure GOBIN is not set during build so that promu is installed to the correct path
+unexport GOBIN
+
+GO           ?= go
+GOFMT        ?= $(GO)fmt
+FIRST_GOPATH := $(firstword $(subst :, ,$(shell $(GO) env GOPATH)))
+GOOPTS       ?=
+GOHOSTOS     ?= $(shell $(GO) env GOHOSTOS)
+GOHOSTARCH   ?= $(shell $(GO) env GOHOSTARCH)
+
+GO_VERSION        ?= $(shell $(GO) version)
+GO_VERSION_NUMBER ?= $(word 3, $(GO_VERSION))
+PRE_GO_111        ?= $(shell echo $(GO_VERSION_NUMBER) | grep -E 'go1\.(10|[0-9])\.')
+
+GOVENDOR :=
+GO111MODULE :=
+ifeq (, $(PRE_GO_111))
+	ifneq (,$(wildcard go.mod))
+		# Enforce Go modules support just in case the directory is inside GOPATH (and for Travis CI).
+		GO111MODULE := on
+
+		ifneq (,$(wildcard vendor))
+			# Always use the local vendor/ directory to satisfy the dependencies.
+			GOOPTS := $(GOOPTS) -mod=vendor
+		endif
+	endif
+else
+	ifneq (,$(wildcard go.mod))
+		ifneq (,$(wildcard vendor))
+$(warning This repository requires Go >= 1.11 because of Go modules)
+$(warning Some recipes may not work as expected as the current Go runtime is '$(GO_VERSION_NUMBER)')
+		endif
+	else
+		# This repository isn't using Go modules (yet).
+		GOVENDOR := $(FIRST_GOPATH)/bin/govendor
+	endif
+endif
+PROMU        := $(FIRST_GOPATH)/bin/promu
+pkgs          = ./...
+
+ifeq (arm, $(GOHOSTARCH))
+	GOHOSTARM ?= $(shell GOARM= $(GO) env GOARM)
+	GO_BUILD_PLATFORM ?= $(GOHOSTOS)-$(GOHOSTARCH)v$(GOHOSTARM)
+else
+	GO_BUILD_PLATFORM ?= $(GOHOSTOS)-$(GOHOSTARCH)
+endif
+
+PROMU_VERSION ?= 0.5.0
+PROMU_URL     := https://github.com/prometheus/promu/releases/download/v$(PROMU_VERSION)/promu-$(PROMU_VERSION).$(GO_BUILD_PLATFORM).tar.gz
+
+GOLANGCI_LINT :=
+GOLANGCI_LINT_OPTS ?=
+GOLANGCI_LINT_VERSION ?= v1.17.1
+# golangci-lint only supports linux, darwin and windows platforms on i386/amd64.
+# windows isn't included here because of the path separator being different.
+ifeq ($(GOHOSTOS),$(filter $(GOHOSTOS),linux darwin))
+	ifeq ($(GOHOSTARCH),$(filter $(GOHOSTARCH),amd64 i386))
+		GOLANGCI_LINT := $(FIRST_GOPATH)/bin/golangci-lint
+	endif
+endif
+
+PREFIX                  ?= $(shell pwd)
+BIN_DIR                 ?= $(shell pwd)
+DOCKER_IMAGE_TAG        ?= $(subst /,-,$(shell git rev-parse --abbrev-ref HEAD))
+DOCKERFILE_PATH         ?= ./Dockerfile
+DOCKERBUILD_CONTEXT     ?= ./
+DOCKER_REPO             ?= prom
+
+DOCKER_ARCHS            ?= amd64
+
+BUILD_DOCKER_ARCHS = $(addprefix common-docker-,$(DOCKER_ARCHS))
+PUBLISH_DOCKER_ARCHS = $(addprefix common-docker-publish-,$(DOCKER_ARCHS))
+TAG_DOCKER_ARCHS = $(addprefix common-docker-tag-latest-,$(DOCKER_ARCHS))
+
+ifeq ($(GOHOSTARCH),amd64)
+        ifeq ($(GOHOSTOS),$(filter $(GOHOSTOS),linux freebsd darwin windows))
+                # Only supported on amd64
+                test-flags := -race
+        endif
+endif
+
+# This rule is used to forward a target like "build" to "common-build".  This
+# allows a new "build" target to be defined in a Makefile which includes this
+# one and override "common-build" without override warnings.
+%: common-% ;
+
+.PHONY: common-all
+common-all: precheck style check_license lint unused build test
+
+.PHONY: common-style
+common-style:
+	@echo ">> checking code style"
+	@fmtRes=$$($(GOFMT) -d $$(find . -path ./vendor -prune -o -name '*.go' -print)); \
+	if [ -n "$${fmtRes}" ]; then \
+		echo "gofmt checking failed!"; echo "$${fmtRes}"; echo; \
+		echo "Please ensure you are using $$($(GO) version) for formatting code."; \
+		exit 1; \
+	fi
+
+.PHONY: common-check_license
+common-check_license:
+	@echo ">> checking license header"
+	@licRes=$$(for file in $$(find . -type f -iname '*.go' ! -path './vendor/*') ; do \
+               awk 'NR<=3' $$file | grep -Eq "(Copyright|generated|GENERATED)" || echo $$file; \
+       done); \
+       if [ -n "$${licRes}" ]; then \
+               echo "license header checking failed:"; echo "$${licRes}"; \
+               exit 1; \
+       fi
+
+.PHONY: common-deps
+common-deps:
+	@echo ">> getting dependencies"
+ifdef GO111MODULE
+	GO111MODULE=$(GO111MODULE) $(GO) mod download
+else
+	$(GO) get $(GOOPTS) -t ./...
+endif
+
+.PHONY: common-test-short
+common-test-short:
+	@echo ">> running short tests"
+	GO111MODULE=$(GO111MODULE) $(GO) test -short $(GOOPTS) $(pkgs)
+
+.PHONY: common-test
+common-test:
+	@echo ">> running all tests"
+	GO111MODULE=$(GO111MODULE) $(GO) test $(test-flags) $(GOOPTS) $(pkgs)
+
+.PHONY: common-format
+common-format:
+	@echo ">> formatting code"
+	GO111MODULE=$(GO111MODULE) $(GO) fmt $(pkgs)
+
+.PHONY: common-vet
+common-vet:
+	@echo ">> vetting code"
+	GO111MODULE=$(GO111MODULE) $(GO) vet $(GOOPTS) $(pkgs)
+
+.PHONY: common-lint
+common-lint: $(GOLANGCI_LINT)
+ifdef GOLANGCI_LINT
+	@echo ">> running golangci-lint"
+ifdef GO111MODULE
+# 'go list' needs to be executed before staticcheck to prepopulate the modules cache.
+# Otherwise staticcheck might fail randomly for some reason not yet explained.
+	GO111MODULE=$(GO111MODULE) $(GO) list -e -compiled -test=true -export=false -deps=true -find=false -tags= -- ./... > /dev/null
+	GO111MODULE=$(GO111MODULE) $(GOLANGCI_LINT) run $(GOLANGCI_LINT_OPTS) $(pkgs)
+else
+	$(GOLANGCI_LINT) run $(pkgs)
+endif
+endif
+
+# For backward-compatibility.
+.PHONY: common-staticcheck
+common-staticcheck: lint
+
+.PHONY: common-unused
+common-unused: $(GOVENDOR)
+ifdef GOVENDOR
+	@echo ">> running check for unused packages"
+	@$(GOVENDOR) list +unused | grep . && exit 1 || echo 'No unused packages'
+else
+ifdef GO111MODULE
+	@echo ">> running check for unused/missing packages in go.mod"
+	GO111MODULE=$(GO111MODULE) $(GO) mod tidy
+ifeq (,$(wildcard vendor))
+	@git diff --exit-code -- go.sum go.mod
+else
+	@echo ">> running check for unused packages in vendor/"
+	GO111MODULE=$(GO111MODULE) $(GO) mod vendor
+	@git diff --exit-code -- go.sum go.mod vendor/
+endif
+endif
+endif
+
+.PHONY: common-build
+common-build: promu
+	@echo ">> building binaries"
+	GO111MODULE=$(GO111MODULE) $(PROMU) build --prefix $(PREFIX)
+
+.PHONY: common-tarball
+common-tarball: promu
+	@echo ">> building release tarball"
+	$(PROMU) tarball --prefix $(PREFIX) $(BIN_DIR)
+
+.PHONY: common-docker $(BUILD_DOCKER_ARCHS)
+common-docker: $(BUILD_DOCKER_ARCHS)
+$(BUILD_DOCKER_ARCHS): common-docker-%:
+	docker build -t "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$*:$(DOCKER_IMAGE_TAG)" \
+		-f $(DOCKERFILE_PATH) \
+		--build-arg ARCH="$*" \
+		--build-arg OS="linux" \
+		$(DOCKERBUILD_CONTEXT)
+
+.PHONY: common-docker-publish $(PUBLISH_DOCKER_ARCHS)
+common-docker-publish: $(PUBLISH_DOCKER_ARCHS)
+$(PUBLISH_DOCKER_ARCHS): common-docker-publish-%:
+	docker push "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$*:$(DOCKER_IMAGE_TAG)"
+
+.PHONY: common-docker-tag-latest $(TAG_DOCKER_ARCHS)
+common-docker-tag-latest: $(TAG_DOCKER_ARCHS)
+$(TAG_DOCKER_ARCHS): common-docker-tag-latest-%:
+	docker tag "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$*:$(DOCKER_IMAGE_TAG)" "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$*:latest"
+
+.PHONY: common-docker-manifest
+common-docker-manifest:
+	DOCKER_CLI_EXPERIMENTAL=enabled docker manifest create -a "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME):$(DOCKER_IMAGE_TAG)" $(foreach ARCH,$(DOCKER_ARCHS),$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$(ARCH):$(DOCKER_IMAGE_TAG))
+	DOCKER_CLI_EXPERIMENTAL=enabled docker manifest push "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME):$(DOCKER_IMAGE_TAG)"
+
+.PHONY: promu
+promu: $(PROMU)
+
+$(PROMU):
+	$(eval PROMU_TMP := $(shell mktemp -d))
+	curl -s -L $(PROMU_URL) | tar -xvzf - -C $(PROMU_TMP)
+	mkdir -p $(FIRST_GOPATH)/bin
+	cp $(PROMU_TMP)/promu-$(PROMU_VERSION).$(GO_BUILD_PLATFORM)/promu $(FIRST_GOPATH)/bin/promu
+	rm -r $(PROMU_TMP)
+
+.PHONY: proto
+proto:
+	@echo ">> generating code from proto files"
+	@./scripts/genproto.sh
+
+ifdef GOLANGCI_LINT
+$(GOLANGCI_LINT):
+	mkdir -p $(FIRST_GOPATH)/bin
+	curl -sfL https://raw.githubusercontent.com/golangci/golangci-lint/$(GOLANGCI_LINT_VERSION)/install.sh \
+		| sed -e '/install -d/d' \
+		| sh -s -- -b $(FIRST_GOPATH)/bin $(GOLANGCI_LINT_VERSION)
+endif
+
+ifdef GOVENDOR
+.PHONY: $(GOVENDOR)
+$(GOVENDOR):
+	GOOS= GOARCH= $(GO) get -u github.com/kardianos/govendor
+endif
+
+.PHONY: precheck
+precheck::
+
+define PRECHECK_COMMAND_template =
+precheck:: $(1)_precheck
+
+PRECHECK_COMMAND_$(1) ?= $(1) $$(strip $$(PRECHECK_OPTIONS_$(1)))
+.PHONY: $(1)_precheck
+$(1)_precheck:
+	@if ! $$(PRECHECK_COMMAND_$(1)) 1>/dev/null 2>&1; then \
+		echo "Execution of '$$(PRECHECK_COMMAND_$(1))' command failed. Is $(1) installed?"; \
+		exit 1; \
+	fi
+endef
diff --git a/README.md b/README.md
index 1143b31..f0c0e17 100644
--- a/README.md
+++ b/README.md
@@ -1 +1,92 @@
-# prometheus-gitlab-notifier
\ No newline at end of file
+# Prometheus Gitlab Notifier
+
+Tool which implements [Alertmanager](https://github.com/prometheus/alertmanager) webhook notifier
+and creates Gitlab issue with the alert metadata.
+
+For new features or changes check out the [CHANGELOG.md](./CHANGELOG.md)
+
+### How to run it
+```
+$ ./prometheus-gitlab-notifier --help
+usage: prometheus-gitlab-notifier --gitlab.url=GITLAB.URL --gitlab.token.file=GITLAB.TOKEN.FILE --project.id=PROJECT.ID [<flags>]
+
+Web server listening for webhooks of alertmanager and creating an issue in Gitlab based on it.
+
+Flags:
+  --help                         Show context-sensitive help (also try --help-long and --help-man).
+  --debug                        Enables debug logging.
+  --server.addr="0.0.0.0:9288"   Allows to change the address and port at which the server will listen for incoming connections.
+  --gitlab.url=GITLAB.URL        URL of the Gitlab API.
+  --gitlab.token.file=GITLAB.TOKEN.FILE  
+                                 Path to file containing gitlab token.
+  --project.id=PROJECT.ID        Id of project where to create the issues.
+  --group.interval=1h            Duration how long back to check for opened issues with the same group labels to append the new alerts to (go duration syntax allowing 'ns', 'us' , 'ms', 's', 'm', 'h').
+  --issue.label=ISSUE.LABEL ...  Labels to add to the created issue. (Can be passed multiple times)
+  --dynamic.issue.label.name=DYNAMIC.ISSUE.LABEL.NAME ...  
+                                 Alert label, which is to be propagated to the resulting Gitlab issue as scoped label if present in the received alert. (Can be passed multiple times)
+  --issue.template=conf/default_issue.tmpl  
+                                 Path to the issue golang template file.
+  --queue.size.limit=100         Limit of the alert queue size.
+  --retry.backoff=5m             Duration how long to wait till next retry (go duration syntax allowing 'ns', 'us' , 'ms', 's', 'm', 'h').
+  --retry.limit=5                Maximum number of retries for single alert. If exceeded it's thrown away.
+  --graceful.shutdown.wait.duration=30s  
+                                 Duration how long to wait on graceful shutdown marked as not ready (go duration syntax allowing 'ns', 'us' , 'ms', 's', 'm', 'h').
+```
+
+To test it is running check logs or http://0.0.0.0:9288/readiness
+
+### Issue template
+Look of the resulting issue in Gitlab can be customized using [Go template]{https://golang.org/pkg/text/template/}.
+Default template can be found in [conf/default_issue.tmpl](conf/default_issue.tmpl).
+The available data during templating is the Alertmanager webhook message struct itself.
+Example can be found in [conf/alert.json](conf/alert.json).
+To use own template override the default one with the `--issue.template` flag.
+> The template is validated on startup but if even after validation the templating
+fails in the runtime, raw JSON of the alert will be pasted to the text of the issue as a fallback.
+
+Example of the default template:
+
+![Issue axample](conf/issue_example.png)
+
+### Configure Alertmanager
+You just need to add the [`<webhook_config>`](https://prometheus.io/docs/alerting/configuration/#webhook_config)
+receiver to your Alertmanager configuration and disable sending resolved notifications with `send_resolved: false`.
+Also better to set the `repeat_interval` to higher value since every retry will create new issue.
+
+See the minimal example in the [conf/alertmanager_conf.yaml](conf/alertmanager_conf.yaml).
+
+
+### Issue labeling scheme
+The Gitlab notifier allows to label the resulting issue based on the alert labels.
+It uses mostly Gitlab scoped labels in format `label::value`.
+The grouping labels of the alert are added to the issue automatically to allow identifying same 
+alerts (more on that in [Grouping](#Grouping) section).
+Additionally you can specify names of labels to be also added to the issue using flag `--dynamic.issue.label.name`.
+Last thing you can add are static labels which will be added to every issue using flag `--issue.label`,
+
+
+### Grouping
+To avoid flooding gitlab with identical alerts if they happen to fire and resolve again and again, 
+Gitlab notifier checks for issues witch the same grouping labels as the new incoming alert.
+If if finds any still open issue younger than `1h` by default (can be controlled by flag `--group.interval`),
+it only appends the rendered template to the end of the issue description 
+and adds to the issue label `appended-alerts::<number>` witch count of how many times it was updated. 
+
+
+### Deployment
+Example kubernetes manifests can be found at [kubernetes/](./kubernetes)
+
+
+### Instrumentation
+
+- `/liveness`: liveness endpoint returns always 200
+- `/readiness`: tries HEAD request to the configured Gitlab URL and fails if it does not succeeds. 
+- `/metrics`: metrics endpoint returning app runtime metrics in Prometheus format
+
+### How to contribute and release
+
+**Contributing:**
+1. Implement your changes and test them on your own testing repository.
+1. Add note about changes made to the [CHANGELOG.md](CHANGELOG.md) `[Unreleased]` section.
+1. Create PR and apply for CR from maintainers.
+1. Get it merged.
diff --git a/VERSION b/VERSION
new file mode 100644
index 0000000..a918a2a
--- /dev/null
+++ b/VERSION
@@ -0,0 +1 @@
+0.6.0
diff --git a/cmd/prometheus-gitlab-notifier/prometheus-gitlab-notifier.go b/cmd/prometheus-gitlab-notifier/prometheus-gitlab-notifier.go
new file mode 100644
index 0000000..7741b76
--- /dev/null
+++ b/cmd/prometheus-gitlab-notifier/prometheus-gitlab-notifier.go
@@ -0,0 +1,189 @@
+// Copyright 2019 FUSAKLA Martin Chodúr
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package main
+
+import (
+	"context"
+	"io/ioutil"
+	"net/http"
+	"os"
+	"os/signal"
+	"strings"
+	"syscall"
+	"text/template"
+	"time"
+
+	"github.com/alecthomas/kingpin"
+	"github.com/fusakla/prometheus-gitlab-notifier/pkg/alertmanager"
+	"github.com/fusakla/prometheus-gitlab-notifier/pkg/api"
+	"github.com/fusakla/prometheus-gitlab-notifier/pkg/gitlab"
+	"github.com/fusakla/prometheus-gitlab-notifier/pkg/handler"
+	"github.com/fusakla/prometheus-gitlab-notifier/pkg/metrics"
+	"github.com/fusakla/prometheus-gitlab-notifier/pkg/prober"
+	"github.com/fusakla/prometheus-gitlab-notifier/pkg/processor"
+	"github.com/go-kit/kit/log"
+	"github.com/go-kit/kit/log/level"
+	"github.com/gorilla/mux"
+	"github.com/pkg/errors"
+)
+
+func setupLogger(debug bool) log.Logger {
+	l := log.NewLogfmtLogger(log.NewSyncWriter(os.Stdout))
+	l = log.With(l, "ts", log.DefaultTimestamp, "caller", log.DefaultCaller)
+	if debug {
+		l = level.NewFilter(l, level.AllowDebug())
+	} else {
+		l = level.NewFilter(l, level.AllowInfo())
+	}
+	return l
+}
+
+func waitForEmptyChannel(logger log.Logger, ch <-chan *alertmanager.Webhook) {
+	level.Info(logger).Log("msg", "waiting for all the alerts to be processed")
+	for {
+		if len(ch) > 0 {
+			level.Info(logger).Log("msg", "there are still alerts in the queue, waiting forthem to be processed", "queue_size", len(ch))
+			time.Sleep(10 * time.Millisecond)
+			continue
+		}
+		break
+	}
+	level.Info(logger).Log("msg", "processing of the rest of alerts is done")
+}
+
+func startServer(logger log.Logger, r http.Handler) (*http.Server, <-chan error) {
+	errCh := make(chan error, 1)
+	srv := &http.Server{
+		Handler:      handler.Instrumented(logger, r),
+		Addr:         *serverAddr,
+		WriteTimeout: 5 * time.Second,
+		ReadTimeout:  5 * time.Second,
+	}
+	go func() {
+		defer close(errCh)
+		level.Info(logger).Log("msg", "Starting prometheus-gitlab-notifier", "addr", "0.0.0.0:9288")
+		if err := srv.ListenAndServe(); err != nil {
+			if err != http.ErrServerClosed {
+				level.Error(logger).Log("msg", "server failed", "error", err)
+				errCh <- err
+			}
+		}
+	}()
+	return srv, errCh
+}
+
+var (
+	app                  = kingpin.New("prometheus-gitlab-notifier", "Web server listening for webhooks of alertmanager and creating an issue in Gitlab based on it.")
+	debug                = app.Flag("debug", "Enables debug logging.").Bool()
+	serverAddr           = app.Flag("server.addr", "Allows to change the address and port at which the server will listen for incoming connections.").Default("0.0.0.0:9288").String()
+	gitlabURL            = app.Flag("gitlab.url", "URL of the Gitlab API.").Required().String()
+	gitlabTokenFile      = app.Flag("gitlab.token.file", "Path to file containing gitlab token.").Required().ExistingFile()
+	projectId            = app.Flag("project.id", "Id of project where to create the issues.").Required().Int()
+	groupInterval        = app.Flag("group.interval", "Duration how long back to check for opened issues with the same group labels to append the new alerts to (go duration syntax allowing 'ns', 'us' , 'ms', 's', 'm', 'h').").Default("1h").Duration()
+	issueLabels          = app.Flag("issue.label", "Labels to add to the created issue. (Can be passed multiple times)").Strings()
+	dynamicIssueLabels   = app.Flag("dynamic.issue.label.name", "Alert label, which is to be propagated to the resulting Gitlab issue as scoped label if present in the received alert. (Can be passed multiple times)").Strings()
+	issueTemplatePath    = app.Flag("issue.template", "Path to the issue golang template file.").Default("conf/default_issue.tmpl").ExistingFile()
+	queueSizeLimit       = app.Flag("queue.size.limit", "Limit of the alert queue size.").Default("100").Int()
+	retryBackoff         = app.Flag("retry.backoff", "Duration how long to wait till next retry (go duration syntax allowing 'ns', 'us' , 'ms', 's', 'm', 'h').").Default("5m").Duration()
+	retryLimit           = app.Flag("retry.limit", "Maximum number of retries for single alert. If exceeded it's thrown away.").Default("5").Int()
+	gracefulShutdownWait = app.Flag("graceful.shutdown.wait.duration", "Duration how long to wait on graceful shutdown marked as not ready (go duration syntax allowing 'ns', 'us' , 'ms', 's', 'm', 'h').").Default("30s").Duration()
+)
+
+func main() {
+
+	kingpin.MustParse(app.Parse(os.Args[1:]))
+
+	// Initiate logging.
+	logger := setupLogger(*debug)
+
+	// Initiate Gitlab client.
+	gitlabIssueTextTemplate, err := template.ParseFiles(*issueTemplatePath)
+	if err != nil {
+		level.Error(logger).Log("msg", "invalid gitlab issue template", "file", *issueTemplatePath, "err", err)
+		os.Exit(1)
+	}
+	token, err := ioutil.ReadFile(*gitlabTokenFile)
+	if err != nil {
+		level.Error(logger).Log("msg", "failed to read token file", "file", gitlabTokenFile, "err", err)
+		os.Exit(1)
+	}
+	g, err := gitlab.New(
+		log.With(logger, "component", "gitlab"),
+		*gitlabURL,
+		strings.TrimSpace(string(token)),
+		*projectId,
+		gitlabIssueTextTemplate,
+		issueLabels,
+		dynamicIssueLabels,
+		groupInterval,
+	)
+	if err != nil {
+		level.Error(logger).Log("msg", "invalid gitlab configuration")
+		os.Exit(1)
+	}
+
+	// Start processing all incoming alerts.
+	alertChan := make(chan *alertmanager.Webhook, *queueSizeLimit)
+	proc := processor.New(log.With(logger, "component", "processor"))
+	processCtx, processCancelFunc := context.WithCancel(context.Background())
+	defer processCancelFunc()
+	proc.Process(processCtx, g, alertChan, *retryLimit, *retryBackoff)
+
+	// Setup routing for HTTP server.
+	r := mux.NewRouter()
+	// Initialize the main API.
+	webhookApi := api.NewInRouter(
+		log.With(logger, "component", "api"),
+		r.PathPrefix("/api").Subrouter(),
+		alertChan,
+	)
+	// Initialize prober providing readiness and liveness checks.
+	readinessProber := prober.NewInRouter(
+		log.With(logger, "component", "prober"),
+		r.PathPrefix("/").Subrouter(),
+	)
+	// Initialize metrics handler to serve Prometheus metrics.
+	metrics.HandleInRouter(r)
+
+	// Start HTTP server
+	_, serverErrorChan := startServer(log.With(logger, "component", "server"), r)
+
+	// Subscribe to system signals so we can react on them with graceful termination.
+	gracefulStop := make(chan os.Signal, 2)
+	signal.Notify(gracefulStop, syscall.SIGTERM)
+	signal.Notify(gracefulStop, syscall.SIGINT)
+
+	// It the server fails or we receive signal to gracefully shut down we wait till the alert queue is processed(empty).
+	for {
+		select {
+		case <-serverErrorChan:
+			// If server failed just wait for all the alerts to be processed.
+			waitForEmptyChannel(logger, alertChan)
+			os.Exit(1)
+		case sig := <-gracefulStop:
+			level.Info(logger).Log("msg", "received system signal for graceful shutdown", "signal", sig)
+			// Mark server as not ready so no new connections will come.
+			readinessProber.SetServerNotReady(errors.New("server is shutting down"))
+			// Wait for specified time after marking server not ready so the environment can react on it.
+			level.Info(logger).Log("msg", "waiting for graceful shutdown", "duration", gracefulShutdownWait)
+			time.Sleep(*gracefulShutdownWait)
+			// Stop receiving new alerts.
+			webhookApi.Close()
+			// Wait for all enqueued alerts to be processed.
+			waitForEmptyChannel(logger, alertChan)
+			os.Exit(0)
+		}
+	}
+
+}
diff --git a/conf/alert.json b/conf/alert.json
new file mode 100644
index 0000000..81a1e80
--- /dev/null
+++ b/conf/alert.json
@@ -0,0 +1,32 @@
+{
+  "version": "1",
+  "groupKey": "meh",
+  "receiver": "test-receiver",
+  "status": "firing",
+  "alerts": [
+    {
+      "status": "test",
+      "labels": {
+        "app": "test"
+      },
+      "annotations": {
+        "description": "this is a testing alert"
+      },
+      "startsAt": "2018-09-22T12:42:31Z",
+      "endsAt": "2018-09-22T12:42:31Z",
+      "generatorURL": "http://test.com"
+    }
+  ],
+  "groupLabels": {
+    "label": "value"
+  },
+  "commonLabels": {
+    "locality": "nagano",
+    "severity": "warning",
+    "alertname": "ThisIsATestingAlert"
+  },
+  "commonAnnotations": {
+    "title": "Something is wrong!!!"
+  },
+  "externalURL": "http://test.com"
+}
diff --git a/conf/alertmanager_conf.yaml b/conf/alertmanager_conf.yaml
new file mode 100644
index 0000000..1e3044d
--- /dev/null
+++ b/conf/alertmanager_conf.yaml
@@ -0,0 +1,9 @@
+route:
+  repeat_interval: 10000h
+  receiver: PrometheusGitlabNotifier
+
+  receivers:
+    - name: PrometheusGitlabNotifier
+      webhook_configs:
+        - send_resolved: false
+          url: http://0.0.0.0:9288/api/alertmanager
diff --git a/conf/default_issue.tmpl b/conf/default_issue.tmpl
new file mode 100644
index 0000000..d05b890
--- /dev/null
+++ b/conf/default_issue.tmpl
@@ -0,0 +1,31 @@
+{{define "alert"}}
+  - **`{{ index .Annotations "description" }}`**
+    - **Starts at**: {{ .StartsAt }}
+    - **Ends at**: {{ .EndsAt }}
+    - **Generator URL**: [{{ .GeneratorURL }}]({{ .GeneratorURL }})
+    - **Labels**: `{{`{`}}{{ range $k,$v := .Labels }}{{$k}}="{{$v}}", {{end}}{{`}`}}`
+{{end}}
+
+
+# `{{ index .CommonLabels "severity" }}` alert `{{ index .CommonLabels "alertname" }}` occurred
+**Title:** {{ index .CommonAnnotations "title" }}
+**Alertmanager link:** [{{ .ExternalURL }}]({{ .ExternalURL }})
+
+### Common labels:
+{{- range $k,$v := .CommonLabels }}
+  - **`{{ $k }}`**: `{{ $v }}`
+{{- end }}
+
+### Common annotations:
+{{- range $k,$v := .CommonAnnotations }}
+  {{- if and (not (eq $k "title")) (not (eq $k "description")) }}
+  - **`{{ $k }}`**: `{{ $v }}`
+  {{- end }}
+{{- end }}
+
+---
+
+## Alerts
+{{- range .Alerts }}
+  {{ template "alert" . }}
+{{- end }}
diff --git a/conf/issue_example.png b/conf/issue_example.png
new file mode 100644
index 0000000000000000000000000000000000000000..1fc2427e13ff018d242713f6e8b42597a49344f9
GIT binary patch
literal 46088
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

literal 0
HcmV?d00001

diff --git a/errcheck_excludes.txt b/errcheck_excludes.txt
new file mode 100644
index 0000000..97b9771
--- /dev/null
+++ b/errcheck_excludes.txt
@@ -0,0 +1 @@
+(github.com/go-kit/kit/log.Logger).Log
diff --git a/go.mod b/go.mod
new file mode 100644
index 0000000..f870b07
--- /dev/null
+++ b/go.mod
@@ -0,0 +1,13 @@
+module github.com/fusakla/prometheus-gitlab-notifier
+
+go 1.12
+
+require (
+	github.com/alecthomas/kingpin v2.2.6+incompatible
+	github.com/go-kit/kit v0.8.0
+	github.com/gorilla/mux v1.7.2
+	github.com/pkg/errors v0.8.0
+	github.com/prometheus/alertmanager v0.17.1-0.20190619131440-bef850ac905c
+	github.com/prometheus/client_golang v1.0.0
+	github.com/xanzy/go-gitlab v0.18.0
+)
diff --git a/go.sum b/go.sum
new file mode 100644
index 0000000..f4a26cf
--- /dev/null
+++ b/go.sum
@@ -0,0 +1,195 @@
+github.com/OneOfOne/xxhash v1.2.2 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE=
+github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
+github.com/PuerkitoBio/purell v1.1.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
+github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
+github.com/alecthomas/kingpin v2.2.6+incompatible h1:5svnBTFgJjZvGKyYBtMB0+m5wvrbUHiqye8wRJMlnYI=
+github.com/alecthomas/kingpin v2.2.6+incompatible/go.mod h1:59OFYbFVLKQKq+mqrL6Rw5bR0c3ACQaawgXx0QYndlE=
+github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc h1:cAKDfWh5VpdgMhJosfJnn5/FoN2SRZ4p7fJNX58YPaU=
+github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
+github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf h1:qet1QNfXsQxTZqLG4oE62mJzwPIB8+Tee4RNCL9ulrY=
+github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
+github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da h1:8GUt8eRujhVEGZFFEjBj46YV4rDjvGrNxb0KMWYkL2I=
+github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
+github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
+github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
+github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
+github.com/beorn7/perks v1.0.0 h1:HWo1m869IqiPhD389kmkxeTalrjNbbJTC8LXupb+sl0=
+github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
+github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
+github.com/cenkalti/backoff v0.0.0-20181003080854-62661b46c409 h1:Da6uN+CAo1Wf09Rz1U4i9QN8f0REjyNJ73BEwAq/paU=
+github.com/cenkalti/backoff v0.0.0-20181003080854-62661b46c409/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM=
+github.com/cespare/xxhash v0.0.0-20181017004759-096ff4a8a059 h1:o4GWHLIzU2GCL0R5PZVFpVdPCGmzBH0tXXZlZ78QddA=
+github.com/cespare/xxhash v0.0.0-20181017004759-096ff4a8a059/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
+github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
+github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/docker/go-units v0.3.3/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
+github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
+github.com/globalsign/mgo v0.0.0-20180905125535-1ca0a4f7cbcb/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q=
+github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q=
+github.com/go-kit/kit v0.8.0 h1:Wz+5lgoB0kkuqLEc6NVmwRknTKP6dTGbSqvhZtBI/j0=
+github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
+github.com/go-logfmt/logfmt v0.3.0 h1:8HUsc87TaSWLKwrnumgC8/YconD2fJQsRJAsWaPg2ic=
+github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
+github.com/go-openapi/analysis v0.0.0-20180825180245-b006789cd277/go.mod h1:k70tL6pCuVxPJOHXQ+wIac1FUrvNkHolPie/cLEU6hI=
+github.com/go-openapi/analysis v0.17.0/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik=
+github.com/go-openapi/analysis v0.17.2/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik=
+github.com/go-openapi/errors v0.17.0/go.mod h1:LcZQpmvG4wyF5j4IhA73wkLFQg+QJXOQHVjmcZxhka0=
+github.com/go-openapi/errors v0.17.2/go.mod h1:LcZQpmvG4wyF5j4IhA73wkLFQg+QJXOQHVjmcZxhka0=
+github.com/go-openapi/jsonpointer v0.17.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M=
+github.com/go-openapi/jsonpointer v0.17.2/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M=
+github.com/go-openapi/jsonreference v0.17.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I=
+github.com/go-openapi/jsonreference v0.17.2/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I=
+github.com/go-openapi/loads v0.17.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU=
+github.com/go-openapi/loads v0.17.2/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU=
+github.com/go-openapi/runtime v0.0.0-20180920151709-4f900dc2ade9/go.mod h1:6v9a6LTXWQCdL8k1AO3cvqx5OtZY/Y9wKTgaoP6YRfA=
+github.com/go-openapi/runtime v0.18.0/go.mod h1:uI6pHuxWYTy94zZxgcwJkUWa9wbIlhteGfloI10GD4U=
+github.com/go-openapi/spec v0.17.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI=
+github.com/go-openapi/spec v0.17.2/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI=
+github.com/go-openapi/strfmt v0.17.0/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU=
+github.com/go-openapi/strfmt v0.17.2/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU=
+github.com/go-openapi/swag v0.17.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg=
+github.com/go-openapi/swag v0.17.2/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg=
+github.com/go-openapi/validate v0.17.2/go.mod h1:Uh4HdOzKt19xGIGm1qHf/ofbX1YQ4Y+MYsct2VUrAJ4=
+github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk=
+github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
+github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
+github.com/gogo/protobuf v1.2.1 h1:/s5zKNz0uPFCZ5hddgPdo2TK2TVrUNMn0OOX8/aZMTE=
+github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
+github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.3.1 h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg=
+github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c h1:964Od4U6p2jUkFxvCydnIczKteheJEzHRToSGK3Bnlw=
+github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
+github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk=
+github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
+github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+github.com/google/uuid v1.1.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+github.com/gorilla/mux v1.7.2 h1:zoNxOV7WjqXptQOVngLmcSQgXmgk4NMz1HibBchjl/I=
+github.com/gorilla/mux v1.7.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
+github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA=
+github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
+github.com/hashicorp/go-immutable-radix v1.0.0 h1:AKDB1HM5PWEA7i4nhcpwOrO2byshxBjXVn/J/3+z5/0=
+github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
+github.com/hashicorp/go-msgpack v0.5.3 h1:zKjpN5BK/P5lMYrLmBHdBULWbJ0XpYR+7NGzqkZzoD4=
+github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
+github.com/hashicorp/go-multierror v1.0.0 h1:iVjPR7a6H0tWELX5NxNe7bYopibicUzc7uPribsnS6o=
+github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
+github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU=
+github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc=
+github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A=
+github.com/hashicorp/go-uuid v1.0.0 h1:RS8zrF7PhGwyNPOtxSClXXj9HA8feRnJzgnI1RJCSnM=
+github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
+github.com/hashicorp/golang-lru v0.5.0 h1:CL2msUPvZTLb5O648aiLNJw3hnBxN2+1Jq8rCOH9wdo=
+github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
+github.com/hashicorp/memberlist v0.1.3 h1:EmmoJme1matNzb+hMpDuR/0sbJSUisxyqBGG676r31M=
+github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I=
+github.com/jessevdk/go-flags v0.0.0-20180331124232-1c38ed7ad0cc/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
+github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
+github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
+github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
+github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
+github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
+github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515 h1:T+h1c/A9Gawja4Y9mFVWj2vyii2bbUNDw3kt9VxK2EY=
+github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
+github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
+github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
+github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
+github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
+github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
+github.com/kylelemons/godebug v0.0.0-20160406211939-eadb3ce320cb/go.mod h1:B69LEHPfb2qLo0BaaOLcbitczOKLWTsrBG9LczfCD4k=
+github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
+github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
+github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
+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 h1:9jZdLNd/P4+SfEJ0TNyxYpsK8N4GtfylBLqtbYN1sbA=
+github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
+github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
+github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo=
+github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
+github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
+github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
+github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223 h1:F9x/1yl3T2AeKLr2AMdilSD8+f9bvMnNN8VS5iDtovc=
+github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
+github.com/oklog/run v1.0.0 h1:Ru7dDtJNOyC66gQ5dQmaCa0qIsAUFY3sFpK1Xk8igrw=
+github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA=
+github.com/oklog/ulid v0.0.0-20170117200651-66bb6560562f h1:UpfE/Q64+1idrbE+phdstApLr3SJBSjkxg8AvRx1mSk=
+github.com/oklog/ulid v0.0.0-20170117200651-66bb6560562f/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
+github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c h1:Lgl0gzECD8GnQ5QCWA8o6BtfL6mDH5rQgM4/fX3avOs=
+github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
+github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k=
+github.com/pkg/errors v0.8.0 h1:WdK/asTD0HN+q6hsWO3/vpuAkAr+tw6aNJNDFFf0+qw=
+github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
+github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
+github.com/prometheus/alertmanager v0.17.1-0.20190619131440-bef850ac905c h1:NT8YaSNAgl5RYWyL/i05KO+R8yCq2mn1NLhUPFdnaoU=
+github.com/prometheus/alertmanager v0.17.1-0.20190619131440-bef850ac905c/go.mod h1:WcxHBl40VSPuOaqWae6l6HpnEOVRIycEJ7i9iYkadEE=
+github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
+github.com/prometheus/client_golang v1.0.0 h1:vrDKnkGzuGvhNAL56c7DBz29ZL+KxnoR0x7enabFceM=
+github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
+github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
+github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90 h1:S/YWwWx/RA8rT8tKFRuGUZhuA90OyIBpPCXkcbwU8DE=
+github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
+github.com/prometheus/common v0.4.1 h1:K0MGApIoQvMw27RTdJkPbr3JZ7DNbtxQNyi5STVM6Kw=
+github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
+github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
+github.com/prometheus/procfs v0.0.2 h1:6LJUbpNm42llc4HRCuvApCSWB/WfhuNo9K98Q9sNGfs=
+github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
+github.com/prometheus/prometheus v0.0.0-20180315085919-58e2a31db8de/go.mod h1:oAIUtOny2rjMX0OWN5vPR5/q/twIROJvdqnQKDdil/s=
+github.com/rs/cors v1.6.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU=
+github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
+github.com/satori/go.uuid v0.0.0-20160603004225-b111a074d5ef h1:RoeI7K0oZIcUirMHsFpQjTVDrl1ouNh8T7v3eNsUxL0=
+github.com/satori/go.uuid v0.0.0-20160603004225-b111a074d5ef/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
+github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 h1:nn5Wsu0esKSJiIVhscUtVbo7ada43DJhG55ua/hjS5I=
+github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
+github.com/shurcooL/httpfs v0.0.0-20171119174359-809beceb2371 h1:SWV2fHctRpRrp49VXJ6UZja7gU9QLHwRpIPBN89SKEo=
+github.com/shurcooL/httpfs v0.0.0-20171119174359-809beceb2371/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg=
+github.com/shurcooL/vfsgen v0.0.0-20180825020608-02ddb050ef6b h1:rKVW5h3pEu8gGxD+ZlOmBvFYAxXLCYeQv/eg+t6QvLQ=
+github.com/shurcooL/vfsgen v0.0.0-20180825020608-02ddb050ef6b/go.mod h1:TrYk7fJVaAttu97ZZKrO9UbRa8izdowaMIZcxYMbVaw=
+github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
+github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72 h1:qLC7fQah7D6K1B0ujays3HV9gkFtllcxhzImRR7ArPQ=
+github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
+github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
+github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
+github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
+github.com/xanzy/go-gitlab v0.18.0 h1:LybNSWSIw8BK+GnxuETAhUXEzzh5rHsHjopqVkGJXRE=
+github.com/xanzy/go-gitlab v0.18.0/go.mod h1:LSfUQ9OPDnwRqulJk2HcWaAiFfCzaknyeGvjQI67MbE=
+github.com/xlab/treeprint v0.0.0-20180616005107-d6fb6747feb6/go.mod h1:ce1O1j6UtZfjr22oyGxGLbauSBp2YVXpARAosm7dHBg=
+golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
+golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3 h1:KYQXGkl6vs02hK7pK4eIbw0NpNPedieTSTEiJ//bwGs=
+golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
+golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20181005035420-146acd28ed58/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20181108082009-03003ca0c849/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20181201002055-351d144fa1fc h1:a3CU5tJYVj92DY2LaA1kUkrsqD5/3mLDhx2NcNqyW+0=
+golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/oauth2 v0.0.0-20181106182150-f42d05182288 h1:JIqe8uIcRBHXDQVvZtHwp80ai3Lw3IJAeJEs55Dc1W0=
+golang.org/x/oauth2 v0.0.0-20181106182150-f42d05182288/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
+golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4 h1:YUO/7uOKsKeq9UokNS62b8FYywz3ker1l1vDZRCRefw=
+golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/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-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5 h1:mzjBh+S5frKOsOBobWIMAbXavqjmgO17k/2puhcFR94=
+golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.3.1-0.20180805044716-cb6730876b98/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20190118193359-16909d206f00 h1:6OmoTtlNJlHuWNIjTEyUtMBHrryp8NRuf/XtnC7MmXM=
+golang.org/x/tools v0.0.0-20190118193359-16909d206f00/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+google.golang.org/appengine v1.3.0 h1:FBSsiFRMz3LBeXIomRnVzrQwSDj4ibvcRexLG0LZGQk=
+google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
+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 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
+gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
+gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
diff --git a/kubernetes/gitlab-token-secret.yaml b/kubernetes/gitlab-token-secret.yaml
new file mode 100644
index 0000000..a75ca85
--- /dev/null
+++ b/kubernetes/gitlab-token-secret.yaml
@@ -0,0 +1,6 @@
+apiVersion: v1
+kind: Secret
+metadata:
+  name: prometheus-gitlab-notifier-gitlab-token
+data:
+  gitlab_token: "Y2hhY2hh"
diff --git a/kubernetes/issue-template-configmap.yaml b/kubernetes/issue-template-configmap.yaml
new file mode 100644
index 0000000..1fa8b02
--- /dev/null
+++ b/kubernetes/issue-template-configmap.yaml
@@ -0,0 +1,37 @@
+apiVersion: v1
+kind: ConfigMap
+metadata:
+  name: prometheus-gitlab-notifier-issue-template
+data:
+  issue.tmpl: |
+    {{define "alert"}}
+      - **`{{ index .Annotations "description" }}`**
+        - **Starts at**: {{ .StartsAt }}
+        - **Ends at**: {{ .EndsAt }}
+        - **Generator URL**: [{{ .GeneratorURL }}]({{ .GeneratorURL }})
+        - **Labels**: `{{`{`}}{{ range $k,$v := .Labels }}{{$k}}="{{$v}}", {{end}}{{`}`}}`
+    {{end}}
+
+
+    # `{{ index .CommonLabels "severity" }}` alert `{{ index .CommonLabels "alertname" }}` occurred
+    **Title:** {{ index .CommonAnnotations "title" }}
+    **Alertmanager link:** [{{ .ExternalURL }}]({{ .ExternalURL }})
+
+    ### Common labels:
+    {{- range $k,$v := .CommonLabels }}
+      - **`{{ $k }}`**: `{{ $v }}`
+    {{- end }}
+
+    ### Common annotations:
+    {{- range $k,$v := .CommonAnnotations }}
+      {{- if and (not (eq $k "title")) (not (eq $k "description")) }}
+      - **`{{ $k }}`**: `{{ $v }}`
+      {{- end }}
+    {{- end }}
+
+    ---
+
+    ## Alerts
+    {{- range .Alerts }}
+      {{ template "alert" . }}
+    {{- end }}
diff --git a/kubernetes/prometheus-gitlab-notifier-deployment.yaml b/kubernetes/prometheus-gitlab-notifier-deployment.yaml
new file mode 100644
index 0000000..25f4444
--- /dev/null
+++ b/kubernetes/prometheus-gitlab-notifier-deployment.yaml
@@ -0,0 +1,55 @@
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  name: prometheus-gitlab-notifier
+spec:
+  selector:
+    matchLabels:
+      app: prometheus-gitlab-notifier
+  replicas: 2
+  template:
+    metadata:
+      labels:
+        app: prometheus-gitlab-notifier
+    spec:
+      containers:
+        - name: prometheus-gitlab-notifier
+          image: fusakla/prometheus-gitlab-notifier:0.6.0
+          args:
+            - "--gitlab.url=https://gitlab.com/api/v4"
+            - "--project.id=13766104"
+            - "--issue.label=automated-alert-issue"
+            - "--group.interval=168h" # 7d
+            - "--issue.template=/prometheus-gitlab-notifier/issue-templates/issue.tmpl"
+            - "--gitlab.token.file=/prometheus-gitlab-notifier/secrets/gitlab_token"
+          readinessProbe:
+            httpGet:
+              port: 9288
+              path: /readiness
+          livenessProbe:
+            httpGet:
+              port: 9288
+              path: /liveness
+          ports:
+            - containerPort: 9288
+          resources:
+            requests:
+              cpu: "50m"
+              memory: "50Mi"
+            limits:
+              cpu: "500m"
+              memory: "512Mi"
+          volumeMounts:
+            - name: issue-template
+              readOnly: true
+              mountPath: "/prometheus-gitlab-notifier/issue-templates/"
+            - name: gitlab-token
+              readOnly: true
+              mountPath: "/prometheus-gitlab-notifier/secrets"
+      volumes:
+        - name: issue-template
+          configMap:
+            name: prometheus-gitlab-notifier-issue-template
+        - name: gitlab-token
+          secret:
+            secretName: prometheus-gitlab-notifier-gitlab-token
diff --git a/kubernetes/prometheus-gitlab-notifier-service.yaml b/kubernetes/prometheus-gitlab-notifier-service.yaml
new file mode 100644
index 0000000..18ff7f9
--- /dev/null
+++ b/kubernetes/prometheus-gitlab-notifier-service.yaml
@@ -0,0 +1,12 @@
+apiVersion: v1
+kind: Service
+metadata:
+  name: prometheus-gitlab-notifier
+  labels:
+    app: prometheus-gitlab-notifier
+spec:
+  ports:
+    - port: 9288
+      protocol: TCP
+  selector:
+    app: prometheus-gitlab-notifier
diff --git a/pkg/alertmanager/webhook.go b/pkg/alertmanager/webhook.go
new file mode 100644
index 0000000..7093d5e
--- /dev/null
+++ b/pkg/alertmanager/webhook.go
@@ -0,0 +1,49 @@
+// Copyright 2019 FUSAKLA Martin Chodúr
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package alertmanager
+
+import (
+	"sync"
+
+	"github.com/prometheus/alertmanager/notify/webhook"
+)
+
+// NewWebhookFromAlertmanagerMessage returns new Webhook wrapping the original Alertmanager webhook.message.
+func NewWebhookFromAlertmanagerMessage(message webhook.Message) *Webhook {
+	return &Webhook{
+		Message:    message,
+		retryCount: 0,
+	}
+}
+
+// Webhook is wrapper for the Alertmanager webhook.message adding retry counter.
+type Webhook struct {
+	webhook.Message
+	retryCount int
+	retryMtx   sync.RWMutex
+}
+
+// Retry increments number of retries for the Webhook.
+func (w *Webhook) Retry() {
+	w.retryMtx.Lock()
+	defer w.retryMtx.Unlock()
+	w.retryCount++
+}
+
+// RetryCount returns number of retries for the given alertmanager message.
+func (w *Webhook) RetryCount() int {
+	w.retryMtx.RLock()
+	defer w.retryMtx.RUnlock()
+	return w.retryCount
+}
diff --git a/pkg/api/api.go b/pkg/api/api.go
new file mode 100644
index 0000000..5acd4b8
--- /dev/null
+++ b/pkg/api/api.go
@@ -0,0 +1,86 @@
+// Copyright 2019 FUSAKLA Martin Chodúr
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package api
+
+import (
+	"encoding/json"
+	"fmt"
+	"io"
+	"net/http"
+	"sync"
+
+	"github.com/fusakla/prometheus-gitlab-notifier/pkg/alertmanager"
+
+	"github.com/go-kit/kit/log"
+	"github.com/go-kit/kit/log/level"
+	"github.com/gorilla/mux"
+	"github.com/prometheus/alertmanager/notify/webhook"
+)
+
+// NewInRouter creates new Api instance which will register it's handlers in the given router.
+func NewInRouter(logger log.Logger, r *mux.Router, ch chan<- *alertmanager.Webhook) *Api {
+	api := &Api{
+		logger:        logger,
+		alertChan:     ch,
+		receiveAlerts: true,
+	}
+	api.registerHandlers(r)
+	return api
+}
+
+// Api defines handler functions for receiving Alertmanager endpoints.
+type Api struct {
+	logger           log.Logger
+	alertChan        chan<- *alertmanager.Webhook
+	receiveAlerts    bool
+	receiveAlertsMtx sync.RWMutex
+}
+
+func (a *Api) registerHandlers(router *mux.Router) {
+	router.HandleFunc("/alertmanager", a.webhookHandler)
+}
+
+func (a *Api) webhookHandler(w http.ResponseWriter, r *http.Request) {
+	if !a.canReceiveAlerts() {
+		http.Error(w, "Server is not receiving new alerts.", http.StatusServiceUnavailable)
+		return
+	}
+	var message webhook.Message
+	err := json.NewDecoder(r.Body).Decode(&message)
+	if err != nil {
+		http.Error(w, fmt.Sprintf("Invalid incomming webhook format. Failed with error: %s", err), http.StatusBadRequest)
+		return
+	}
+
+	// Push the message to channel
+	a.alertChan <- alertmanager.NewWebhookFromAlertmanagerMessage(message)
+	level.Debug(a.logger).Log("msg", "enqueued alert for processing", "group_key", message.GroupKey)
+
+	w.WriteHeader(http.StatusOK)
+	_, _ = io.WriteString(w, `Ok, Alert enqueued.`)
+}
+
+// Close disabled receiving of new alerts in the API used mainly for graceful shutdown.
+func (a *Api) Close() {
+	a.receiveAlertsMtx.Lock()
+	defer a.receiveAlertsMtx.Unlock()
+	a.receiveAlerts = false
+	close(a.alertChan)
+}
+
+func (a *Api) canReceiveAlerts() bool {
+	a.receiveAlertsMtx.RLock()
+	defer a.receiveAlertsMtx.RUnlock()
+	return a.receiveAlerts
+}
diff --git a/pkg/gitlab/gitlab.go b/pkg/gitlab/gitlab.go
new file mode 100644
index 0000000..69942c7
--- /dev/null
+++ b/pkg/gitlab/gitlab.go
@@ -0,0 +1,249 @@
+// Copyright 2019 FUSAKLA Martin Chodúr
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package gitlab
+
+import (
+	"bufio"
+	"bytes"
+	"encoding/json"
+	"fmt"
+	"net/http"
+	"regexp"
+	"strconv"
+	"text/template"
+	"time"
+
+	"github.com/fusakla/prometheus-gitlab-notifier/pkg/alertmanager"
+	"github.com/fusakla/prometheus-gitlab-notifier/pkg/metrics"
+	"github.com/go-kit/kit/log"
+	"github.com/go-kit/kit/log/level"
+	"github.com/xanzy/go-gitlab"
+)
+
+// New creates new Gitlab instance configured to work with specified gitlab instance, project and with given authentication.
+func New(logger log.Logger, url string, token string, projectId int, issueTemplate *template.Template, issueLabels *[]string, dynamicIssueLabels *[]string, groupInterval *time.Duration) (*Gitlab, error) {
+	cli := gitlab.NewClient(nil, token)
+	if err := cli.SetBaseURL(url); err != nil {
+		level.Error(logger).Log("msg", "invalid Gitlab URL", "url", url, "err", "err")
+		return nil, err
+	}
+	g := &Gitlab{
+		client:             cli,
+		projectId:          projectId,
+		issueTemplate:      issueTemplate,
+		issueLabels:        issueLabels,
+		dynamicIssueLabels: dynamicIssueLabels,
+		groupInterval:      groupInterval,
+		logger:             logger,
+	}
+	if err := g.ping(); err != nil {
+		level.Error(logger).Log("msg", "cannot reach the Gitlab", "url", url, "err", "err")
+		return nil, err
+	}
+	return g, nil
+}
+
+// Gitlab holds configured Gitlab client and provides API for creating templated issue from the Webhook.
+type Gitlab struct {
+	client             *gitlab.Client
+	projectId          int
+	issueTemplate      *template.Template
+	issueLabels        *[]string
+	dynamicIssueLabels *[]string
+	groupInterval      *time.Duration
+	logger             log.Logger
+}
+
+func (g *Gitlab) formatGitlabScopedLabel(key string, value string) string {
+	return fmt.Sprintf("%s::%s", key, value)
+}
+
+func (g *Gitlab) extractDynamicLabels(msg *alertmanager.Webhook) []string {
+	var labelsMap = map[string]string{}
+	for _, a := range msg.Alerts {
+		for k, v := range a.Labels {
+			for _, l := range *g.dynamicIssueLabels {
+				if k == l {
+					labelsMap[k] = v
+				}
+			}
+		}
+	}
+	var resLabels []string
+	for k, v := range labelsMap {
+		resLabels = append(resLabels, g.formatGitlabScopedLabel(k, v))
+	}
+	return resLabels
+}
+
+func (g *Gitlab) extractGroupingLabels(msg *alertmanager.Webhook) []string {
+	var resLabels []string
+	for k, v := range msg.GroupLabels {
+		resLabels = append(resLabels, g.formatGitlabScopedLabel(k, v))
+	}
+	return resLabels
+}
+
+func (g *Gitlab) renderIssueTemplate(msg *alertmanager.Webhook) (*bytes.Buffer, error) {
+	var issueText bytes.Buffer
+	// Try to template the issue text template with the alert data.
+	if err := g.issueTemplate.Execute(&issueText, msg.Data); err != nil {
+		// As a fallback we try to add raw JSON of the alert to the issue text so we don't miss an alert just because of template error.
+		metrics.ReportError("IssueTemplateError", "")
+		level.Error(g.logger).Log("msg", "failed to template issue text, using pure JSON instead", "err", err)
+		w := bufio.NewWriter(&issueText)
+		if err := json.NewEncoder(w).Encode(msg); err != nil {
+			// If even JSON marshalling fails we return error
+			metrics.ReportError("JSONMarshalError", "")
+			level.Error(g.logger).Log("msg", "failed to marshall alert to JSON", "err", err)
+			return nil, err
+		}
+	}
+	return &issueText, nil
+}
+
+func (g *Gitlab) getOpenIssuesSince(groupingLabels []string, sinceTime time.Time) ([]*gitlab.Issue, error) {
+	openState := "opened"
+	scope := "created_by_me"
+	orderBy := "created_at"
+	listOpts := gitlab.ListIssuesOptions{
+		Labels:       groupingLabels,
+		CreatedAfter: &sinceTime,
+		State:        &openState,
+		Scope:        &scope,
+		OrderBy:      &orderBy,
+	}
+	issues, response, err := g.client.Issues.ListIssues(&listOpts)
+	if err != nil {
+		metrics.ReportError("ListGitlabIssuesError", "gitlab")
+		level.Error(g.logger).Log("msg", "failed to list gitlab issues with", "opts", listOpts, "response", response, "err", err)
+		return []*gitlab.Issue{}, err
+	}
+	return issues, nil
+}
+
+func (g *Gitlab) getTimeBefore(before *time.Duration) time.Time {
+	return time.Now().Local().Add(-*before)
+}
+
+func (g *Gitlab) createGitlabIssue(msg *alertmanager.Webhook, groupingLabels []string, issueText *bytes.Buffer) error {
+	// Collect all new issue labels
+	labels := *g.issueLabels
+	labels = append(labels, groupingLabels...)
+	labels = append(labels, g.extractDynamicLabels(msg)...)
+	options := &gitlab.CreateIssueOptions{
+		Title:       gitlab.String(fmt.Sprintf("Firing alert `%s`", msg.CommonLabels["alertname"])),
+		Description: gitlab.String(issueText.String()),
+		Labels:      labels,
+	}
+
+	createdIssue, response, err := g.client.Issues.CreateIssue(g.projectId, options)
+	if err != nil {
+		metrics.ReportError("FailedToCreateGitlabIssue", "gitlab")
+		level.Error(g.logger).Log("msg", "failed to create gitlab issue", "err", err, "response", response)
+		return err
+	}
+	level.Info(g.logger).Log("msg", "created issue in gitlab", "gitlab_issue_id", createdIssue.IID, "alert_grouping_key", msg.GroupKey)
+	return nil
+}
+
+func (g *Gitlab) increaseAppendLabel(labels []string) []string {
+	// Every updated issue has special label containing number of updates
+	appendLabelRegex := regexp.MustCompile(`(appended-alerts)::(\d+)`)
+	alreadyAppended := false
+	var newLabels []string
+	for _, l := range labels {
+		// Check if the label is the special one
+		matched := appendLabelRegex.FindStringSubmatch(l)
+		if len(matched) == 3 {
+			alreadyAppended = true
+			// Convert it to number if possible otherwise leave the old one as is
+			count, err := strconv.Atoi(matched[2])
+			if err != nil {
+				level.Error(g.logger).Log("msg", "failed to parse gitlab issue label `appended-alerts`, leaving it unmodified", "label_value", l, "err", err)
+				newLabels = append(newLabels, l)
+				continue
+			}
+			// Increase the number of appends and add override the old label with it
+			newLabels = append(newLabels, g.formatGitlabScopedLabel(matched[1], strconv.Itoa(count+1)))
+			continue
+		}
+		newLabels = append(newLabels, l)
+	}
+	if !alreadyAppended {
+		newLabels = append(newLabels, g.formatGitlabScopedLabel("appended-alerts", "1"))
+	}
+	return newLabels
+}
+
+func (g *Gitlab) updateGitlabIssue(issue *gitlab.Issue, issueText *bytes.Buffer) error {
+	newLabels := g.increaseAppendLabel(issue.Labels)
+	options := &gitlab.UpdateIssueOptions{
+		// Concat original description with the new rendered template separated by `Appended on <date>` statement
+		Description: gitlab.String(fmt.Sprintf("%s\n\n&nbsp;\n\n&nbsp;\n\n&nbsp;\n\n_Appended on `%s`_\n%s", issue.Description, time.Now().Local(), issueText.String())),
+		Labels:      newLabels,
+	}
+	issue, response, err := g.client.Issues.UpdateIssue(g.projectId, issue.IID, options)
+	if err != nil {
+		metrics.ReportError("FailedToUpdateGitlabIssue", "gitlab")
+		level.Error(g.logger).Log("msg", "failed to update gitlab issue, will try to create new", "err", err, "response", response)
+		return err
+	}
+	level.Info(g.logger).Log("msg", "updated issue in gitlab", "gitlab_issue_id", issue.IID)
+	return nil
+}
+
+// CreateIssue from the Webhook in Gitlab
+func (g *Gitlab) CreateIssue(msg *alertmanager.Webhook) error {
+	// Extract grouping labels from the message
+	groupingLabels := g.extractGroupingLabels(msg)
+
+	// Check for existing issues with same grouping labels
+	matchingIssues, err := g.getOpenIssuesSince(groupingLabels, g.getTimeBefore(g.groupInterval))
+	if err != nil {
+		level.Warn(g.logger).Log("msg", "listing of open issues to check for duplicates failed , opening a new one even though possible duplicate")
+	}
+
+	// Try to render the issue text template
+	issueText, err := g.renderIssueTemplate(msg)
+	if err != nil {
+		return err
+	}
+
+	if len(matchingIssues) > 0 {
+		// Issues are ordered by created date, we update the first so the newest one.
+		issueToUpdate := matchingIssues[0]
+		if err := g.updateGitlabIssue(issueToUpdate, issueText); err != nil {
+			level.Warn(g.logger).Log("msg", "updating an existing issue failed, opening a new one", "updated_issue_id", issueToUpdate.IID)
+		} else {
+			return nil
+		}
+	}
+	// Try to create a new issue rather than discarding it after failed update.
+	if err := g.createGitlabIssue(msg, groupingLabels, issueText); err != nil {
+		return err
+	}
+	return nil
+}
+
+func (g *Gitlab) ping() error {
+	level.Debug(g.logger).Log("msg", "trying to ping gitlab", "url", g.client.BaseURL())
+	_, err := http.Head(g.client.BaseURL().String())
+	if err != nil {
+		metrics.ReportError("FailedToPingGitlab", "gitlab")
+		level.Error(g.logger).Log("msg", "failed to ping gitlab with HEAD request", "err", err)
+		return err
+	}
+	return nil
+}
diff --git a/pkg/handler/handler.go b/pkg/handler/handler.go
new file mode 100644
index 0000000..2159e7f
--- /dev/null
+++ b/pkg/handler/handler.go
@@ -0,0 +1,72 @@
+// Copyright 2019 FUSAKLA Martin Chodúr
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package handler
+
+import (
+	"net/http"
+	"strconv"
+	"time"
+
+	"github.com/fusakla/prometheus-gitlab-notifier/pkg/metrics"
+	"github.com/go-kit/kit/log"
+	"github.com/go-kit/kit/log/level"
+	"github.com/prometheus/client_golang/prometheus"
+)
+
+var (
+	requestDuration = prometheus.NewHistogramVec(prometheus.HistogramOpts{
+		Name:    "request_duration_seconds",
+		Help:    "Time (in seconds) spent serving HTTP requests.",
+		Buckets: prometheus.DefBuckets,
+	}, []string{"app", "method", "endpoint", "status_code"})
+)
+
+func init() {
+	metrics.Register(requestDuration)
+}
+
+type instrumentedWriter struct {
+	http.ResponseWriter
+	status int
+}
+
+// WriteHeader writes header to the response.
+func (w *instrumentedWriter) WriteHeader(status int) {
+	w.status = status
+	w.ResponseWriter.WriteHeader(status)
+}
+
+func (w *instrumentedWriter) Write(b []byte) (int, error) {
+	if w.status == 0 {
+		w.status = 200
+	}
+	n, err := w.ResponseWriter.Write(b)
+	return n, err
+}
+
+// Instrumented returns instrumented handler which provides access logging and prometheus metrics for incoming requests.
+func Instrumented(logger log.Logger, handler http.Handler) http.HandlerFunc {
+	return func(w http.ResponseWriter, r *http.Request) {
+		start := time.Now()
+		sw := instrumentedWriter{ResponseWriter: w}
+		handler.ServeHTTP(&sw, r)
+		duration := time.Since(start)
+		level.Info(logger).Log("msg", "access log", "uri", r.RequestURI, "method", r.Method, "status", sw.status, "remote_addr", r.RemoteAddr, "duration", duration)
+		metricsEndpoint := r.URL.Path
+		if sw.status == 404 {
+			metricsEndpoint = "non-existing-endpoint"
+		}
+		requestDuration.WithLabelValues(metrics.AppLabel, r.Method, metricsEndpoint, strconv.Itoa(sw.status)).Observe(float64(duration.Seconds()))
+	}
+}
diff --git a/pkg/metrics/metrics.go b/pkg/metrics/metrics.go
new file mode 100644
index 0000000..668c05c
--- /dev/null
+++ b/pkg/metrics/metrics.go
@@ -0,0 +1,73 @@
+// Copyright 2019 FUSAKLA Martin Chodúr
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package metrics
+
+import (
+	"github.com/gorilla/mux"
+	"github.com/prometheus/client_golang/prometheus"
+	"github.com/prometheus/client_golang/prometheus/promhttp"
+)
+
+// AppLabel is constant name of the application used
+const AppLabel = "prometheus-gitlab-notifier"
+
+var (
+	appVersion  = "unknown"
+	gitRevision = "unknown"
+	gitBranch   = "unknown"
+	gitTag      = "unknown"
+
+	registry     *prometheus.Registry
+	errorsTotal  *prometheus.CounterVec
+	appBuildInfo *prometheus.CounterVec
+)
+
+func init() {
+	registry = prometheus.NewRegistry()
+
+	// Metric with information about build AppVersion, golang AppVersion etc/
+	appBuildInfo = prometheus.NewCounterVec(prometheus.CounterOpts{
+		Name: "app_build_info",
+		Help: "Metadata metric with info about build and AppVersion.",
+	}, []string{"app", "version", "revision", "branch", "tag"})
+	registry.MustRegister(appBuildInfo)
+	appBuildInfo.WithLabelValues(AppLabel, appVersion, gitRevision, gitBranch, gitTag).Inc()
+
+	// Generic metric for reporting errors
+	errorsTotal = prometheus.NewCounterVec(prometheus.CounterOpts{
+		Name: "errors_total",
+		Help: "Count of occurred errors.",
+	}, []string{"app", "type", "remote_app"})
+	registry.MustRegister(errorsTotal)
+
+	// When using custom registry we need to explicitly register the Go and process collectors.
+	registry.MustRegister(prometheus.NewGoCollector())
+	registry.MustRegister(prometheus.NewProcessCollector(prometheus.ProcessCollectorOpts{}))
+
+}
+
+// HandleInRouter registers prometheus metrics rendering in given router.
+func HandleInRouter(r *mux.Router) {
+	r.Handle("/metrics", promhttp.HandlerFor(registry, promhttp.HandlerOpts{}))
+}
+
+// Register new Prometheus metric Collector to the registry.
+func Register(m prometheus.Collector) {
+	registry.MustRegister(m)
+}
+
+// ReportError to errors_total metric global for the whole application.
+func ReportError(errorType string, remoteApp string) {
+	errorsTotal.WithLabelValues(AppLabel, errorType, remoteApp).Inc()
+}
diff --git a/pkg/prober/prober.go b/pkg/prober/prober.go
new file mode 100644
index 0000000..823a7d7
--- /dev/null
+++ b/pkg/prober/prober.go
@@ -0,0 +1,79 @@
+// Copyright 2019 FUSAKLA Martin Chodúr
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package prober
+
+import (
+	"io"
+	"net/http"
+	"sync"
+
+	"github.com/go-kit/kit/log"
+	"github.com/go-kit/kit/log/level"
+	"github.com/gorilla/mux"
+)
+
+// NewInRouter returns new Prober which registers it's endpoints in the Router to provide readiness and liveness endpoints.
+func NewInRouter(logger log.Logger, router *mux.Router) *prober {
+	p := &prober{
+		logger:      logger,
+		serverReady: nil,
+	}
+	p.registerInRouter(router)
+	return p
+}
+
+// prober holds application readiness/liveness status and provides handlers for reporting it.
+type prober struct {
+	logger         log.Logger
+	serverReadyMtx sync.RWMutex
+	serverReady    error
+}
+
+func (p *prober) registerInRouter(router *mux.Router) {
+	router.HandleFunc("/liveness", p.livenessHandler)
+	router.HandleFunc("/readiness", p.readinessHandler)
+}
+
+func (p *prober) livenessHandler(w http.ResponseWriter, r *http.Request) {
+	w.WriteHeader(http.StatusOK)
+	_, _ = io.WriteString(w, `OK`)
+}
+
+func (p *prober) writeFailedReadiness(w http.ResponseWriter, err error) {
+	level.Error(p.logger).Log("msg", "readiness probe failed", "err", err)
+	http.Error(w, err.Error(), http.StatusServiceUnavailable)
+}
+
+func (p *prober) readinessHandler(w http.ResponseWriter, r *http.Request) {
+	if err := p.isReady(); err != nil {
+		p.writeFailedReadiness(w, err)
+		return
+	}
+	w.WriteHeader(http.StatusOK)
+	_, _ = io.WriteString(w, `OK`)
+}
+
+// SetServerNotReady sets the readiness probe to invalid state.
+func (p *prober) SetServerNotReady(err error) {
+	p.serverReadyMtx.Lock()
+	defer p.serverReadyMtx.Unlock()
+	level.Warn(p.logger).Log("msg", "Marking server as not ready", "reason", err)
+	p.serverReady = err
+}
+
+func (p *prober) isReady() error {
+	p.serverReadyMtx.RLock()
+	defer p.serverReadyMtx.RUnlock()
+	return p.serverReady
+}
diff --git a/pkg/processor/processor.go b/pkg/processor/processor.go
new file mode 100644
index 0000000..815852d
--- /dev/null
+++ b/pkg/processor/processor.go
@@ -0,0 +1,85 @@
+// Copyright 2019 FUSAKLA Martin Chodúr
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package processor
+
+import (
+	"context"
+	"time"
+
+	"github.com/fusakla/prometheus-gitlab-notifier/pkg/alertmanager"
+	"github.com/fusakla/prometheus-gitlab-notifier/pkg/gitlab"
+	"github.com/go-kit/kit/log"
+	"github.com/go-kit/kit/log/level"
+	"github.com/prometheus/client_golang/prometheus"
+)
+
+var (
+	processedItems = prometheus.NewCounter(prometheus.CounterOpts{
+		Name: "prometheus_gitlab_notifier_processed_alerts_processed_total",
+		Help: "Count of processed alerts.",
+	})
+	retryCount = prometheus.NewCounter(prometheus.CounterOpts{
+		Name: "prometheus_gitlab_notifier_processed_alerts_retried_total",
+		Help: "Count of retries.",
+	})
+)
+
+func init() {
+	prometheus.MustRegister(processedItems)
+	prometheus.MustRegister(retryCount)
+}
+
+// New returns new processor which handles the alert queue and retrying.
+func New(logger log.Logger) *processor {
+	return &processor{
+		logger: logger,
+	}
+}
+
+type processor struct {
+	logger log.Logger
+}
+
+// Process processes alerts from the given channel and creates Gitlab issues from them.
+func (p *processor) Process(ctx context.Context, gitlab *gitlab.Gitlab, alertChannel chan *alertmanager.Webhook, retryLimit int, retryBackoff time.Duration) {
+	doneChannel := make(chan bool, 1)
+	go func() {
+		defer close(doneChannel)
+		for {
+			select {
+			case <-ctx.Done():
+				return
+			case alert, ok := <-alertChannel:
+				if !ok {
+					return
+				}
+				level.Debug(p.logger).Log("msg", "fetched alert from queue for processing", "group_key", alert.GroupKey)
+				if err := gitlab.CreateIssue(alert); err != nil {
+					if alert.RetryCount() >= retryLimit-1 {
+						level.Warn(p.logger).Log("msg", "alert exceeded maximum number of retries, dropping it", "group_key", alert.GroupKey, "retry_count", retryLimit)
+						continue
+					}
+					go func() {
+						time.Sleep(retryBackoff)
+						alert.Retry()
+						alertChannel <- alert
+						retryCount.Inc()
+						level.Warn(p.logger).Log("msg", "added alert to queue for retrying ", "group_key", alert.GroupKey, "retry_backoff", retryBackoff)
+					}()
+				}
+				processedItems.Inc()
+			}
+		}
+	}()
+}
-- 
GitLab