schleuder-gitlab-ticketing 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/README.md +191 -0
- data/lib/schleuder-gitlab-ticketing.rb +6 -0
- data/lib/schleuder-gitlab-ticketing/config.rb +45 -0
- data/lib/schleuder-gitlab-ticketing/gitlab_config.rb +11 -0
- data/lib/schleuder-gitlab-ticketing/list.rb +198 -0
- data/lib/schleuder-gitlab-ticketing/version.rb +3 -0
- data/lib/schleuder/filters/post_decryption/99_gitlab_ticketing.rb +25 -0
- metadata +104 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: b59177cf964bf88408cc0d315ba893e8c5a8379fc250b1df318f36c136d1a2b0
|
4
|
+
data.tar.gz: 7b407e3792310e646fe68c949eb7d1b71d15bd617b89e2c85178a29492046cab
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 1b448ce81e1cac8ae9ddeb6fa66d7517bc927fa5e3bafa283caa51fee703aca240870848aa6d205b6a2171614834780e250997770f1f2f90e52885e88270e2d6
|
7
|
+
data.tar.gz: 26164f54b6bca5e1fdfd5abb23208e87281028e4c5798279b2bdb98da3a8df7b3e391b9ed9e7fb6fc57d630cab243be3b629d32d45e6b42593f983ebac5ad7e8
|
data/README.md
ADDED
@@ -0,0 +1,191 @@
|
|
1
|
+
Schleuder Gitlab Ticketing
|
2
|
+
==========================
|
3
|
+
|
4
|
+
A schleuder filter/plugin to hook lists into the issue tracker of a gitlab project.
|
5
|
+
|
6
|
+
Background
|
7
|
+
----------
|
8
|
+
|
9
|
+
Schleuderlists are not only a helpful tool for communication within groups, they can also be
|
10
|
+
used for newsletters, or by using its famous remailer capabilities to be used as a contact
|
11
|
+
address for a project or as a help desk.
|
12
|
+
|
13
|
+
In the latter two cases keeping an overview of the different interactions can become somewhat
|
14
|
+
cumbersome, especially in a bigger collective where not everybody is able to dedicate the same
|
15
|
+
amount of time/attention to the contact address / help desk. Hence it is easy that a certain
|
16
|
+
thread (and so task) on the list is getting lost. Having some kind of ticketing system in place
|
17
|
+
can help to easily keep track of what is done, what is in progress and what should be looked at.
|
18
|
+
|
19
|
+
Additionally, folks do not like to double the work and hence as much as possible should be done
|
20
|
+
while emails flow over the list.
|
21
|
+
|
22
|
+
This schleuder filter / plugin allows to map emails through an id in the subject to issues in
|
23
|
+
a gitlab project. Additionally, it opens an issue on new emails or closes issues if the subject
|
24
|
+
indicates that the job is done.
|
25
|
+
|
26
|
+
The gitlab issues are mainly used to keep the state of a certain email thread and contains only
|
27
|
+
as much plaintext information as was transmitted in plaintext over the wire. This means it only
|
28
|
+
stores From:, Subject: and Message-Id: as issue comments.
|
29
|
+
|
30
|
+
How it works
|
31
|
+
------------
|
32
|
+
|
33
|
+
The filter / plugin hooks into the filter process list in schleuder. First schleuder will check
|
34
|
+
whether there is a configuration for the current list, as well as whether this configuration
|
35
|
+
is correct. Otherwise the filter is immediately skipped.
|
36
|
+
|
37
|
+
Schleuder then dispatches the processing to the specific list instance, which checks whether
|
38
|
+
the email comes from a sender that shall be ignored (e.g. well known spammers or announce lists)
|
39
|
+
or whether the subject matches any of the configured subject filters. The email is also ignored
|
40
|
+
if the well known `X-Spam-Flag` header is set to `yes`.
|
41
|
+
|
42
|
+
If none of that matches, the email is being processed and first the email's subject is analyzed
|
43
|
+
to get an already existing ticket id. The plugin expects something like `Subject: my subject [gp#123]`,
|
44
|
+
where gp is a configureable project identifier and 123 matches an issue id in gitlab. The brackets
|
45
|
+
enclose the ticket identifier and can be anywhere within the subject.
|
46
|
+
|
47
|
+
If no ticket id can be found or no issue can be found in gitlab a new issue will be created in
|
48
|
+
gitlab. The ticket id will be appended to the subject, a faulty ticket id will be replaced.
|
49
|
+
|
50
|
+
If a ticket can be found, a comment is added to the issue, that includes the sender email address,
|
51
|
+
as well as the Subject and Message-ID of the email.
|
52
|
+
|
53
|
+
Additionally, if the email is sent from an email address, that is a member of the gitlab project
|
54
|
+
the ticket will be assigned to said user. Furthermore, the label `inprocess` is added to ticket
|
55
|
+
to indicate that someone of the project is working on that thread.
|
56
|
+
|
57
|
+
If the ticket is already closed it will be re-opened.
|
58
|
+
|
59
|
+
If the subject contains: `[ok]` the ticket will be closed and the label `inprocess` removed. An
|
60
|
+
already closed ticket stays closed.
|
61
|
+
|
62
|
+
That's it.
|
63
|
+
|
64
|
+
Prerequisits
|
65
|
+
------------
|
66
|
+
|
67
|
+
* ruby >=2.1
|
68
|
+
* schleuder >= 3.3.0
|
69
|
+
* A working schleuder installation and a schleuder list
|
70
|
+
* A gitlab project and a dedicated user and its API token
|
71
|
+
|
72
|
+
Installation
|
73
|
+
------------
|
74
|
+
|
75
|
+
* Install the gem (depends on the gitlab gem)
|
76
|
+
* Link `lib/schleuder/filters/post_decrpytion/99_gitlab_ticketing.rb` into `/usr/local/lib/schleuder/filters/post_decryption/`,
|
77
|
+
so the plugin gets loaded.
|
78
|
+
|
79
|
+
Configuration
|
80
|
+
-------------
|
81
|
+
|
82
|
+
The plugin is looking for a configuration in `/etc/schleuder/gitlab.yml`. The configuration file
|
83
|
+
expects a `gitlab` and a lists `configuration` section:
|
84
|
+
|
85
|
+
```
|
86
|
+
gitlab:
|
87
|
+
endpoint: https://gitlab.example.com/api/v4
|
88
|
+
token: xxxx
|
89
|
+
|
90
|
+
lists:
|
91
|
+
test@schleuder.example.com:
|
92
|
+
project: tickets
|
93
|
+
namespace: support
|
94
|
+
```
|
95
|
+
|
96
|
+
The key of the lists configuration indicates the listname on schleuder side, which matches its
|
97
|
+
email address. A list's setting requires 2 configuration options: `project` & `namespace` which
|
98
|
+
map to the path within gitlab, where the project exists. Namespace can either be the group or
|
99
|
+
the users name, depending of where a project lives.
|
100
|
+
|
101
|
+
The plugin supports working for multiple lists, as well as allows individual gitlab configuration
|
102
|
+
for different lists:
|
103
|
+
|
104
|
+
```
|
105
|
+
gitlab:
|
106
|
+
endpoint: https://gitlab.example.com/api/v4
|
107
|
+
token: xxxx
|
108
|
+
lists:
|
109
|
+
test@schleuder.example.com:
|
110
|
+
project: tickets
|
111
|
+
namespace: support
|
112
|
+
test2@schleuder.example.com:
|
113
|
+
gitlab:
|
114
|
+
endpoint: https://gitlab2.example.com/api/v4
|
115
|
+
token: aaaa
|
116
|
+
```
|
117
|
+
|
118
|
+
Additionally, you can specify filters based on the sender or the subject. They must be valid ruby
|
119
|
+
regexps and can also be specified on a global and local level.
|
120
|
+
|
121
|
+
```
|
122
|
+
gitlab:
|
123
|
+
endpoint: https://gitlab.example.com/api/v4
|
124
|
+
token: xxxx
|
125
|
+
|
126
|
+
subject_filters:
|
127
|
+
- '\[announce\]'
|
128
|
+
sender_filters:
|
129
|
+
- '^spammer@example\.com$'
|
130
|
+
|
131
|
+
lists:
|
132
|
+
test@schleuder.example.com:
|
133
|
+
project: tickets
|
134
|
+
namespace: support
|
135
|
+
subject_filters:
|
136
|
+
- 'ignore me'
|
137
|
+
test2@schleuder.example.com:
|
138
|
+
gitlab:
|
139
|
+
endpoint: https://gitlab2.example.com/api/v4
|
140
|
+
token: aaaa
|
141
|
+
sender_filters:
|
142
|
+
- 'noreply@example\.com'
|
143
|
+
|
144
|
+
```
|
145
|
+
|
146
|
+
Additionally, you can specify a specifc identifier to more easily identify a particular ticket id in
|
147
|
+
the subject:
|
148
|
+
|
149
|
+
```
|
150
|
+
lists:
|
151
|
+
test@schleuder.example.com:
|
152
|
+
project: tickets
|
153
|
+
namespace: support
|
154
|
+
ticket_prefix: ourid
|
155
|
+
```
|
156
|
+
|
157
|
+
This will look for the following string in a subject: `[ourid#\d+]`. By default it would look for:
|
158
|
+
`[gl/test#\d+]`
|
159
|
+
|
160
|
+
Todo
|
161
|
+
----
|
162
|
+
|
163
|
+
This plugin is in a working state and has been tested by multiple use cases for nearly a year.
|
164
|
+
|
165
|
+
Some more ideas:
|
166
|
+
|
167
|
+
* Use schleuder's verification capabilities to further prove that the email comes from a list member.
|
168
|
+
* Hook into schleuder's plugin capabilities, to allow more ticket actions (e.g. assign, labels, ...)
|
169
|
+
|
170
|
+
Contributing
|
171
|
+
------------
|
172
|
+
|
173
|
+
Please see [CONTRIBUTING.md](CONTRIBUTING.md).
|
174
|
+
|
175
|
+
|
176
|
+
Mission statement
|
177
|
+
-----------------
|
178
|
+
|
179
|
+
Please see [MISSION_STATEMENT.md](MISSION_STATEMENT.md).
|
180
|
+
|
181
|
+
|
182
|
+
Code of Conduct
|
183
|
+
---------------
|
184
|
+
|
185
|
+
We adopted a code of conduct. Please read [CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.md).
|
186
|
+
|
187
|
+
|
188
|
+
License
|
189
|
+
-------
|
190
|
+
|
191
|
+
GNU GPL 3.0. Please see [LICENSE.txt](LICENSE.txt).
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module SchleuderGitlabTicketing
|
2
|
+
class Config
|
3
|
+
include SchleuderGitlabTicketing::GitlabConfig
|
4
|
+
|
5
|
+
def initialize(config_path='/etc/schleuder/gitlab.yml')
|
6
|
+
@config = if File.exists?(config_path)
|
7
|
+
YAML.load_file(config_path)
|
8
|
+
else
|
9
|
+
{}
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
# returns true if mail was handled
|
14
|
+
# returns 'config-error' if list-config is not properly
|
15
|
+
# returns nil if list is not configured to handle
|
16
|
+
# gitlab plugin
|
17
|
+
def process_list(list_name, mail)
|
18
|
+
if l = lists[list_name]
|
19
|
+
if l.configured?
|
20
|
+
l.process(mail)
|
21
|
+
else
|
22
|
+
'config-error'
|
23
|
+
end
|
24
|
+
else
|
25
|
+
nil
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def lists
|
30
|
+
@lists ||= read_lists
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
def read_lists
|
35
|
+
Hash(@config['lists']).inject({}) do |res,a|
|
36
|
+
n,v = a
|
37
|
+
v['gitlab'] ||= gitlab
|
38
|
+
v['subject_filters'] = Array(v['subject_filters']) + Array(@config['subject_filters'])
|
39
|
+
v['sender_filters'] = Array(v['sender_filters']) + Array(@config['sender_filters'])
|
40
|
+
res[n] = SchleuderGitlabTicketing::List.new(n,v)
|
41
|
+
res
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
module SchleuderGitlabTicketing
|
2
|
+
module GitlabConfig
|
3
|
+
def gitlab
|
4
|
+
@gitlab ||= if @config['gitlab']['endpoint'] && @config['gitlab']['token']
|
5
|
+
Gitlab.client(endpoint: @config['gitlab']['endpoint'], private_token: @config['gitlab']['token'])
|
6
|
+
else
|
7
|
+
nil
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,198 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
require 'gitlab'
|
3
|
+
require 'set'
|
4
|
+
module SchleuderGitlabTicketing
|
5
|
+
class List
|
6
|
+
include SchleuderGitlabTicketing::GitlabConfig
|
7
|
+
|
8
|
+
def initialize(name, config)
|
9
|
+
@name = name
|
10
|
+
@config = config
|
11
|
+
end
|
12
|
+
|
13
|
+
def configured?
|
14
|
+
unless @config['project'] && @config['namespace'] && @config['gitlab'] && gitlab && project
|
15
|
+
return false
|
16
|
+
end
|
17
|
+
true
|
18
|
+
end
|
19
|
+
|
20
|
+
def process(mail)
|
21
|
+
return false if ignore_mail?(mail)
|
22
|
+
ticket_id = get_ticket_id(mail.subject)
|
23
|
+
ticket = ticket_id ? get_ticket(ticket_id) : nil
|
24
|
+
|
25
|
+
if (title = clean_subject(mail.subject)).nil? || title.empty?
|
26
|
+
title = "Request from #{mail.from.first}"
|
27
|
+
end
|
28
|
+
desc = desc(mail)
|
29
|
+
updates = {}
|
30
|
+
labels = Set.new
|
31
|
+
|
32
|
+
if !ticket
|
33
|
+
ticket = create_ticket(title, desc)
|
34
|
+
ticket_id = ticket.iid
|
35
|
+
mail.subject = update_subject(mail.subject, ticket_id)
|
36
|
+
else
|
37
|
+
labels = Set.new(ticket.labels)
|
38
|
+
comment_ticket(ticket_id,desc)
|
39
|
+
assignee_id = team_member_id(mail.from.first)
|
40
|
+
if assignee_id && ((as = ticket.assignee).nil? || as.id != assignee_id)
|
41
|
+
updates[:assignee_id] = assignee_id
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
bc = be_closed?(mail.subject)
|
46
|
+
tc = ticket_closed?(ticket)
|
47
|
+
|
48
|
+
if !tc && bc
|
49
|
+
labels.delete('inprocess')
|
50
|
+
updates[:state_event] = 'close'
|
51
|
+
elsif !tc && !bc
|
52
|
+
labels << 'inprocess' if updates[:assignee_id]
|
53
|
+
elsif tc && !bc
|
54
|
+
labels << 'inprocess'
|
55
|
+
updates[:state_event] = 'reopen'
|
56
|
+
end
|
57
|
+
if labels.empty? && (updates[:state_event] == 'close')
|
58
|
+
# make sure we remove the inprocess label
|
59
|
+
updates[:labels] = ''
|
60
|
+
elsif !labels.empty? && (labels.to_a.sort != ticket.labels.sort)
|
61
|
+
updates[:labels] = labels.to_a.join(',')
|
62
|
+
end
|
63
|
+
update_ticket(ticket_id, updates)
|
64
|
+
true
|
65
|
+
end
|
66
|
+
|
67
|
+
def gitlab
|
68
|
+
@gitlab ||= if @config['gitlab'].is_a?(Gitlab::Client)
|
69
|
+
@config['gitlab']
|
70
|
+
else
|
71
|
+
super
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def sender_filters
|
76
|
+
Array(@config['sender_filters'])
|
77
|
+
end
|
78
|
+
def subject_filters
|
79
|
+
Array(@config['subject_filters'])
|
80
|
+
end
|
81
|
+
|
82
|
+
private
|
83
|
+
def desc(mail)
|
84
|
+
res = []
|
85
|
+
res << "From: #{mail.from.first}"
|
86
|
+
res << "Message-Id: #{mail.message_id}"
|
87
|
+
res << "Subject: #{mail.subject || '[not set]'}"
|
88
|
+
res.join("\n\n")
|
89
|
+
end
|
90
|
+
|
91
|
+
def be_closed?(subject)
|
92
|
+
!(subject =~ /\[ok\]/).nil?
|
93
|
+
end
|
94
|
+
|
95
|
+
def ticket_closed?(ticket)
|
96
|
+
ticket.state == 'closed'
|
97
|
+
end
|
98
|
+
|
99
|
+
def update_ticket(ticket_id,updates)
|
100
|
+
return if updates.empty?
|
101
|
+
gitlab.edit_issue(project.id, ticket_id, updates)
|
102
|
+
rescue Gitlab::Error::NotFound => e
|
103
|
+
nil
|
104
|
+
end
|
105
|
+
|
106
|
+
def create_ticket(title, desc)
|
107
|
+
opts = { description: desc }
|
108
|
+
gitlab.create_issue(project.id, title, opts)
|
109
|
+
end
|
110
|
+
|
111
|
+
def comment_ticket(ticket_id, desc)
|
112
|
+
gitlab.create_issue_note(project.id, ticket_id, desc)
|
113
|
+
end
|
114
|
+
|
115
|
+
def get_ticket(id)
|
116
|
+
gitlab.issue(project.id, id)
|
117
|
+
rescue Gitlab::Error::NotFound => e
|
118
|
+
nil
|
119
|
+
end
|
120
|
+
|
121
|
+
def get_ticket_id(str)
|
122
|
+
if str && (m = str.match(/.*\[#{Regexp.escape(ticket_prefix)}\#(\d+)\].*/)) && m[1]
|
123
|
+
m[1].to_i
|
124
|
+
else
|
125
|
+
nil
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
def project
|
130
|
+
@project ||= gitlab.search_projects(@config['project']).find{|p| p.namespace.name == @config['namespace'] && p.name == @config['project'] }
|
131
|
+
rescue Gitlab::Error::NotFound => e
|
132
|
+
nil
|
133
|
+
end
|
134
|
+
|
135
|
+
def issues
|
136
|
+
gitlab.issues(p.id)
|
137
|
+
end
|
138
|
+
|
139
|
+
def team_member_id(email)
|
140
|
+
if user_id = find_user_id(email)
|
141
|
+
user_id if project_member?(project, user_id)
|
142
|
+
else
|
143
|
+
nil
|
144
|
+
end
|
145
|
+
rescue Gitlab::Error::NotFound => e
|
146
|
+
nil
|
147
|
+
end
|
148
|
+
|
149
|
+
def project_member?(project, user_id)
|
150
|
+
begin
|
151
|
+
gitlab.team_member(project.id, user_id)
|
152
|
+
rescue Gitlab::Error::NotFound
|
153
|
+
gitlab.group_member(project.namespace.id, user_id)
|
154
|
+
end
|
155
|
+
rescue Gitlab::Error::NotFound => e
|
156
|
+
nil
|
157
|
+
end
|
158
|
+
|
159
|
+
def find_user_id(username_or_email)
|
160
|
+
users = gitlab.user_search(username_or_email)
|
161
|
+
# did we look for an email => exact match
|
162
|
+
# or by username?
|
163
|
+
user = if username_or_email =~ /@/
|
164
|
+
users.first
|
165
|
+
else
|
166
|
+
users.find do |u|
|
167
|
+
u.name == username_or_email || u.username == username_or_email
|
168
|
+
end
|
169
|
+
end
|
170
|
+
user.nil? ? nil : user.id
|
171
|
+
rescue Gitlab::Error::NotFound => e
|
172
|
+
nil
|
173
|
+
end
|
174
|
+
|
175
|
+
def ignore_mail?(mail)
|
176
|
+
return true if mail.respond_to?(:[]) && mail['X-Spam-Flag'].to_s.downcase == 'yes'
|
177
|
+
return true if sender_filters.any?{|s| mail.from.first =~ /#{s}/ }
|
178
|
+
return true if subject_filters.any?{|s| mail.subject =~ /#{s}/ }
|
179
|
+
false
|
180
|
+
end
|
181
|
+
|
182
|
+
def ticket_prefix
|
183
|
+
@ticket_prefix ||= (@config['ticket_prefix'] || "gl/#{@config['project']}")
|
184
|
+
end
|
185
|
+
|
186
|
+
def clean_subject(subj)
|
187
|
+
subj.nil? ? nil : subj.gsub(/^(Re|Fw):\s*/,'').gsub(/\[[<>]?#{list_subj}\]\s*/,'').gsub(/\s*\[#{Regexp.escape(ticket_prefix)}#\d+\](\s*$)?/,'').gsub(/\s*\[ok\](\s*$)?/,'').strip
|
188
|
+
end
|
189
|
+
|
190
|
+
def list_subj
|
191
|
+
@list_subj ||= (@config['list_subj'] || @name.split('@',2).first)
|
192
|
+
end
|
193
|
+
|
194
|
+
def update_subject(subject,ticket_id)
|
195
|
+
[subject.nil? ? nil : subject.gsub(/(\s)?\[#{Regexp.escape(ticket_prefix)}#\d+\]/,''), "[#{ticket_prefix}##{ticket_id}]"].compact.join(' ')
|
196
|
+
end
|
197
|
+
end
|
198
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Schleuder
|
2
|
+
module Filters
|
3
|
+
def self.gitlab_ticketing(list, mail)
|
4
|
+
@gt_config ||= begin
|
5
|
+
require 'schleuder-gitlab-ticketing'
|
6
|
+
SchleuderGitlabTicketing::Config.new
|
7
|
+
end
|
8
|
+
|
9
|
+
res = @gt_config.process_list(list.email, mail)
|
10
|
+
if res.nil?
|
11
|
+
list.logger.debug('No gitlab ticketing enabled for list')
|
12
|
+
elsif res == 'config-error'
|
13
|
+
list.logger.error('gitlab ticketing not correctly configured')
|
14
|
+
elsif res == false
|
15
|
+
list.logger.debug('Email skipped by list configuration')
|
16
|
+
end
|
17
|
+
nil
|
18
|
+
# make sure we catch any error with that filter
|
19
|
+
# so we don't affect list processing
|
20
|
+
rescue Exception => e
|
21
|
+
list.logger.notify_admin "Unable to process the following mail with gitlab-ticketing:\n\n#{e}\n\n#{e.backtrace.join("\n")}", mail.original_message, 'Error while processing mail with gitlab-ticketing'
|
22
|
+
nil
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
metadata
ADDED
@@ -0,0 +1,104 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: schleuder-gitlab-ticketing
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- schleuder dev team
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2019-02-21 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: gitlab
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '4.8'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '4.8'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: schleuder
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '3.3'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '3.3'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rspec
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '3.5'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '3.5'
|
55
|
+
description: Schleuder Gitlab Ticketing combines a schleuder list with the issue tracker
|
56
|
+
of a gitlab project and operates as a state tracker of threads on the list. This
|
57
|
+
allows one to keep an overview on the state of various requests on a help desk powered
|
58
|
+
by schleuder
|
59
|
+
email: team@schleuder.org
|
60
|
+
executables: []
|
61
|
+
extensions: []
|
62
|
+
extra_rdoc_files: []
|
63
|
+
files:
|
64
|
+
- README.md
|
65
|
+
- lib/schleuder-gitlab-ticketing.rb
|
66
|
+
- lib/schleuder-gitlab-ticketing/config.rb
|
67
|
+
- lib/schleuder-gitlab-ticketing/gitlab_config.rb
|
68
|
+
- lib/schleuder-gitlab-ticketing/list.rb
|
69
|
+
- lib/schleuder-gitlab-ticketing/version.rb
|
70
|
+
- lib/schleuder/filters/post_decryption/99_gitlab_ticketing.rb
|
71
|
+
homepage: https://schleuder.org/
|
72
|
+
licenses:
|
73
|
+
- GPL-3.0
|
74
|
+
metadata:
|
75
|
+
homepage_uri: https://schleuder.org/
|
76
|
+
documentation_uri: https://schleuder.org/docs/
|
77
|
+
changelog_uri: https://0xacab.org/schleuder/schleuder-gitlab-ticketing/blob/master/CHANGELOG.md
|
78
|
+
source_code_uri: https://0xacab.org/schleuder/schleuder-gitlab-ticketing/
|
79
|
+
bug_tracker_uri: https://0xacab.org/schleuder/schleuder-gitlab-ticketing/issues
|
80
|
+
mailing_list_uri: https://lists.nadir.org/mailman/listinfo/schleuder-announce/
|
81
|
+
post_install_message: "\n\n To activate the filter plugin you will need to link\n
|
82
|
+
\ lib/schleuder/filters/post_decryption/99_gitlab_ticketing.rb\n to /usr/local/lib/schleuder/filters/post_decryption/\n\n
|
83
|
+
\ "
|
84
|
+
rdoc_options: []
|
85
|
+
require_paths:
|
86
|
+
- lib
|
87
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
88
|
+
requirements:
|
89
|
+
- - ">="
|
90
|
+
- !ruby/object:Gem::Version
|
91
|
+
version: 2.1.0
|
92
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
requirements: []
|
98
|
+
rubyforge_project: "[none]"
|
99
|
+
rubygems_version: 2.7.8
|
100
|
+
signing_key:
|
101
|
+
specification_version: 4
|
102
|
+
summary: Schleuder Gitlab Ticketing is a filter plugin for schleuder to hook a list
|
103
|
+
into a gitlab issue tracker
|
104
|
+
test_files: []
|