linear_client 0.1.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/.gitignore +5 -0
- data/.rspec +3 -0
- data/CHANGELOG.md +5 -0
- data/Gemfile +5 -0
- data/LICENSE +21 -0
- data/README.md +110 -0
- data/Rakefile +7 -0
- data/examples/create_issue.rb +25 -0
- data/examples/my_issues.rb +13 -0
- data/examples/report.rb +12 -0
- data/lib/linear_client/client.rb +114 -0
- data/lib/linear_client/version.rb +5 -0
- data/lib/linear_client.rb +4 -0
- data/linear_client.gemspec +29 -0
- metadata +99 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 87b5a9b41c84b4044ca5462cd2570eb31d8c6aa35aaaa85dfac2f19be4e8da41
|
|
4
|
+
data.tar.gz: 9ebe3adfea20b1eef397fd295a9cefb1914a92b4e1d8806e617aa72c17cf6be2
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: a0ae7497191bbd81967090e3854ace3069851e606059e0027e4e7957dc3a5a1eadf50b90d6be13152116954d86964f1a9a5f00a7e35866ac5f3df35af10bd268
|
|
7
|
+
data.tar.gz: 42b7cc949edaba299a73f4d7207c76ab4b29bde6f031cf4a447610be95c3e2e14faf378248823e9d6a2466f226642be7823539c7f0edd73a1bf7c6c59b442780
|
data/.rspec
ADDED
data/CHANGELOG.md
ADDED
data/Gemfile
ADDED
data/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Lenio Ferretto
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
data/README.md
ADDED
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
# linear_client
|
|
2
|
+
|
|
3
|
+
Cliente Ruby puro para a [API GraphQL do Linear](https://developers.linear.app/docs/graphql/working-with-the-graphql-api) — sem gems externas, apenas a stdlib (`net/http`, `uri`, `json`).
|
|
4
|
+
|
|
5
|
+
Não há SDK oficial para Ruby; este projeto preenche essa lacuna com uma interface simples para criar issues, comentar e consultar dados no Linear.
|
|
6
|
+
|
|
7
|
+
## Instalação
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
gem install linear_client
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
ou no Gemfile:
|
|
14
|
+
|
|
15
|
+
```ruby
|
|
16
|
+
gem "linear_client"
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Configuração
|
|
20
|
+
|
|
21
|
+
1. Gere uma API key pessoal no Linear em `Settings > Account > Security > API keys`.
|
|
22
|
+
2. Exporte a chave como variável de ambiente (nunca hardcode no código):
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
export LINEAR_API_KEY="lin_api_xxxxxxxx"
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
> Trate a API key como uma senha: não a compartilhe, não a commit em arquivos versionados, e revogue/gere outra se ela vazar.
|
|
29
|
+
|
|
30
|
+
## Uso
|
|
31
|
+
|
|
32
|
+
```ruby
|
|
33
|
+
require "linear_client"
|
|
34
|
+
|
|
35
|
+
client = LinearClient::Client.new
|
|
36
|
+
# ou, explicitamente:
|
|
37
|
+
client = LinearClient::Client.new(api_key: "lin_api_xxxxxxxx")
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
### Descobrir times
|
|
41
|
+
|
|
42
|
+
```ruby
|
|
43
|
+
client.teams
|
|
44
|
+
# => [{"id"=>"...", "name"=>"Engineering", "key"=>"ENG"}, ...]
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### Criar um card e comentar
|
|
48
|
+
|
|
49
|
+
```ruby
|
|
50
|
+
result = client.create_issue(team_id: "TEAM_ID", title: "Bug no login", description: "Detalhes...")
|
|
51
|
+
issue_id = result.dig("issue", "id")
|
|
52
|
+
|
|
53
|
+
client.create_comment(issue_id: issue_id, body: "Já reproduzi, investigando.")
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### Listar issues atribuídas a você
|
|
57
|
+
|
|
58
|
+
```ruby
|
|
59
|
+
client.my_issues.each { |i| puts "#{i['identifier']} [#{i['state']['name']}] #{i['title']}" }
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### Dados do usuário autenticado
|
|
63
|
+
|
|
64
|
+
```ruby
|
|
65
|
+
client.viewer
|
|
66
|
+
# => {"name"=>"...", "email"=>"..."}
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
## Referência da API
|
|
70
|
+
|
|
71
|
+
| Método | Descrição | Retorno |
|
|
72
|
+
|---|---|---|
|
|
73
|
+
| `teams` | Lista os times do workspace (`id`, `name`, `key`) | `Array<Hash>` |
|
|
74
|
+
| `viewer` | Nome e e-mail do dono da API key | `Hash` |
|
|
75
|
+
| `my_issues` | Issues atribuídas ao dono da API key, com prioridade, datas, estado e time | `Array<Hash>` |
|
|
76
|
+
| `create_issue(team_id:, title:, description: nil)` | Cria um card num time | `Hash` com `"success"` e `"issue"` (`id`, `identifier`, `title`, `url`) |
|
|
77
|
+
| `create_comment(issue_id:, body:)` | Comenta num card existente | `Hash` com `"success"` e `"comment"` (`id`, `url`) |
|
|
78
|
+
|
|
79
|
+
Todos os métodos lançam `LinearClient::Client::Error` se a API retornar erros GraphQL.
|
|
80
|
+
|
|
81
|
+
## Testes
|
|
82
|
+
|
|
83
|
+
Suíte em RSpec, com [WebMock](https://github.com/bblimke/webmock) simulando as respostas da API (nenhum teste bate na rede real):
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
bundle install
|
|
87
|
+
bundle exec rspec
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
## Scripts de exemplo
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
# Lista os times e cria um card de teste no time indicado pelo key (ex: ENG)
|
|
94
|
+
ruby examples/create_issue.rb ENG
|
|
95
|
+
|
|
96
|
+
# Lista as issues atribuídas a você
|
|
97
|
+
ruby examples/my_issues.rb
|
|
98
|
+
|
|
99
|
+
# Exporta viewer + issues atribuídas para JSON
|
|
100
|
+
ruby examples/report.rb caminho/para/saida.json
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
## Notas de segurança
|
|
104
|
+
|
|
105
|
+
- A API key vai no header `Authorization` (sem prefixo `Bearer`), conforme exigido pela API do Linear.
|
|
106
|
+
- Nunca dê commit em arquivos `.env` ou qualquer arquivo com a chave em texto puro — este repositório já ignora `.env` via `.gitignore`.
|
|
107
|
+
|
|
108
|
+
## Licença
|
|
109
|
+
|
|
110
|
+
[MIT](LICENSE)
|
data/Rakefile
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
require_relative "../lib/linear_client"
|
|
3
|
+
|
|
4
|
+
client = LinearClient::Client.new
|
|
5
|
+
|
|
6
|
+
teams = client.teams
|
|
7
|
+
puts "Times disponiveis:"
|
|
8
|
+
teams.each { |t| puts " #{t['key']} (#{t['name']}) -> id: #{t['id']}" }
|
|
9
|
+
|
|
10
|
+
team_key = ARGV.first || teams.first.fetch("key")
|
|
11
|
+
team = teams.find { |t| t.fetch("key") == team_key }
|
|
12
|
+
raise "Time '#{team_key}' nao encontrado" unless team
|
|
13
|
+
|
|
14
|
+
team_id = team.fetch("id")
|
|
15
|
+
|
|
16
|
+
result = client.create_issue(
|
|
17
|
+
team_id: team_id,
|
|
18
|
+
title: "Card de teste criado via Ruby",
|
|
19
|
+
description: "Criado pelo script examples/create_issue.rb"
|
|
20
|
+
)
|
|
21
|
+
issue = result.fetch("issue")
|
|
22
|
+
puts "Issue criada: #{issue['identifier']} - #{issue['url']}"
|
|
23
|
+
|
|
24
|
+
client.create_comment(issue_id: issue.fetch("id"), body: "Primeiro comentario via API.")
|
|
25
|
+
puts "Comentario adicionado."
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
require_relative "../lib/linear_client"
|
|
3
|
+
|
|
4
|
+
client = LinearClient::Client.new
|
|
5
|
+
issues = client.my_issues
|
|
6
|
+
|
|
7
|
+
if issues.empty?
|
|
8
|
+
puts "Nenhuma issue atribuida a voce."
|
|
9
|
+
else
|
|
10
|
+
issues.each do |issue|
|
|
11
|
+
puts "#{issue['identifier']} [#{issue['team']['key']} / #{issue['state']['name']}] #{issue['title']} -> #{issue['url']}"
|
|
12
|
+
end
|
|
13
|
+
end
|
data/examples/report.rb
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
require_relative "../lib/linear_client"
|
|
3
|
+
require "json"
|
|
4
|
+
|
|
5
|
+
client = LinearClient::Client.new
|
|
6
|
+
viewer = client.viewer
|
|
7
|
+
issues = client.my_issues
|
|
8
|
+
|
|
9
|
+
output = { viewer: viewer, issues: issues }
|
|
10
|
+
path = ARGV.first || "/tmp/linear_report_data.json"
|
|
11
|
+
File.write(path, JSON.pretty_generate(output))
|
|
12
|
+
puts "Dados salvos em #{path} (#{issues.size} issues)"
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "net/http"
|
|
4
|
+
require "uri"
|
|
5
|
+
require "json"
|
|
6
|
+
|
|
7
|
+
module LinearClient
|
|
8
|
+
# Cliente minimo para a API GraphQL do Linear (https://api.linear.app/graphql).
|
|
9
|
+
# Nao ha SDK oficial para Ruby, entao falamos GraphQL diretamente via Net::HTTP.
|
|
10
|
+
class Client
|
|
11
|
+
ENDPOINT = "https://api.linear.app/graphql"
|
|
12
|
+
|
|
13
|
+
class Error < StandardError; end
|
|
14
|
+
|
|
15
|
+
def initialize(api_key: ENV["LINEAR_API_KEY"])
|
|
16
|
+
raise ArgumentError, "LINEAR_API_KEY nao configurada" if api_key.nil? || api_key.empty?
|
|
17
|
+
|
|
18
|
+
@api_key = api_key
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# team_id: id do time no Linear (veja #teams para descobrir)
|
|
22
|
+
def create_issue(team_id:, title:, description: nil)
|
|
23
|
+
query = <<~GRAPHQL
|
|
24
|
+
mutation IssueCreate($input: IssueCreateInput!) {
|
|
25
|
+
issueCreate(input: $input) {
|
|
26
|
+
success
|
|
27
|
+
issue { id identifier title url }
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
GRAPHQL
|
|
31
|
+
|
|
32
|
+
data = execute(query, input: { teamId: team_id, title: title, description: description })
|
|
33
|
+
data.fetch("issueCreate")
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def create_comment(issue_id:, body:)
|
|
37
|
+
query = <<~GRAPHQL
|
|
38
|
+
mutation CommentCreate($input: CommentCreateInput!) {
|
|
39
|
+
commentCreate(input: $input) {
|
|
40
|
+
success
|
|
41
|
+
comment { id url }
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
GRAPHQL
|
|
45
|
+
|
|
46
|
+
data = execute(query, input: { issueId: issue_id, body: body })
|
|
47
|
+
data.fetch("commentCreate")
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# Issues atribuidas ao dono da API key
|
|
51
|
+
def my_issues
|
|
52
|
+
query = <<~GRAPHQL
|
|
53
|
+
query MyIssues {
|
|
54
|
+
viewer {
|
|
55
|
+
assignedIssues {
|
|
56
|
+
nodes {
|
|
57
|
+
id
|
|
58
|
+
identifier
|
|
59
|
+
title
|
|
60
|
+
url
|
|
61
|
+
priority
|
|
62
|
+
createdAt
|
|
63
|
+
updatedAt
|
|
64
|
+
completedAt
|
|
65
|
+
state { name type }
|
|
66
|
+
team { key }
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
GRAPHQL
|
|
72
|
+
|
|
73
|
+
execute(query).dig("viewer", "assignedIssues", "nodes")
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def viewer
|
|
77
|
+
query = <<~GRAPHQL
|
|
78
|
+
query Viewer {
|
|
79
|
+
viewer { name email }
|
|
80
|
+
}
|
|
81
|
+
GRAPHQL
|
|
82
|
+
|
|
83
|
+
execute(query).fetch("viewer")
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
# Util para descobrir os teamIds disponiveis no workspace
|
|
87
|
+
def teams
|
|
88
|
+
query = <<~GRAPHQL
|
|
89
|
+
query Teams {
|
|
90
|
+
teams { nodes { id name key } }
|
|
91
|
+
}
|
|
92
|
+
GRAPHQL
|
|
93
|
+
|
|
94
|
+
execute(query).dig("teams", "nodes")
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
private
|
|
98
|
+
|
|
99
|
+
def execute(query, **variables)
|
|
100
|
+
uri = URI.parse(ENDPOINT)
|
|
101
|
+
request = Net::HTTP::Post.new(uri)
|
|
102
|
+
request["Content-Type"] = "application/json"
|
|
103
|
+
request["Authorization"] = @api_key
|
|
104
|
+
request.body = { query: query, variables: variables }.to_json
|
|
105
|
+
|
|
106
|
+
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }
|
|
107
|
+
payload = JSON.parse(response.body)
|
|
108
|
+
|
|
109
|
+
raise Error, payload["errors"].to_s if payload["errors"] && !payload["errors"].empty?
|
|
110
|
+
|
|
111
|
+
payload.fetch("data")
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "lib/linear_client/version"
|
|
4
|
+
|
|
5
|
+
Gem::Specification.new do |spec|
|
|
6
|
+
spec.name = "linear_client"
|
|
7
|
+
spec.version = LinearClient::VERSION
|
|
8
|
+
spec.authors = ["Lenio Ferretto"]
|
|
9
|
+
spec.email = ["ferretto@users.noreply.github.com"]
|
|
10
|
+
|
|
11
|
+
spec.summary = "Cliente Ruby puro para a API GraphQL do Linear"
|
|
12
|
+
spec.description = "Cliente minimalista, sem dependencias externas, para criar issues, " \
|
|
13
|
+
"comentar e consultar dados no Linear (linear.app) via sua API GraphQL."
|
|
14
|
+
spec.homepage = "https://github.com/ferretto/linear_client"
|
|
15
|
+
spec.license = "MIT"
|
|
16
|
+
spec.required_ruby_version = ">= 3.0"
|
|
17
|
+
|
|
18
|
+
spec.metadata["source_code_uri"] = spec.homepage
|
|
19
|
+
spec.metadata["changelog_uri"] = "#{spec.homepage}/blob/main/CHANGELOG.md"
|
|
20
|
+
|
|
21
|
+
spec.files = Dir.chdir(__dir__) do
|
|
22
|
+
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{\A(?:test|spec|\.github)/}) }
|
|
23
|
+
end
|
|
24
|
+
spec.require_paths = ["lib"]
|
|
25
|
+
|
|
26
|
+
spec.add_development_dependency "rake", "~> 13.0"
|
|
27
|
+
spec.add_development_dependency "rspec", "~> 3.13"
|
|
28
|
+
spec.add_development_dependency "webmock", "~> 3.26"
|
|
29
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: linear_client
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Lenio Ferretto
|
|
8
|
+
bindir: bin
|
|
9
|
+
cert_chain: []
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
11
|
+
dependencies:
|
|
12
|
+
- !ruby/object:Gem::Dependency
|
|
13
|
+
name: rake
|
|
14
|
+
requirement: !ruby/object:Gem::Requirement
|
|
15
|
+
requirements:
|
|
16
|
+
- - "~>"
|
|
17
|
+
- !ruby/object:Gem::Version
|
|
18
|
+
version: '13.0'
|
|
19
|
+
type: :development
|
|
20
|
+
prerelease: false
|
|
21
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
22
|
+
requirements:
|
|
23
|
+
- - "~>"
|
|
24
|
+
- !ruby/object:Gem::Version
|
|
25
|
+
version: '13.0'
|
|
26
|
+
- !ruby/object:Gem::Dependency
|
|
27
|
+
name: rspec
|
|
28
|
+
requirement: !ruby/object:Gem::Requirement
|
|
29
|
+
requirements:
|
|
30
|
+
- - "~>"
|
|
31
|
+
- !ruby/object:Gem::Version
|
|
32
|
+
version: '3.13'
|
|
33
|
+
type: :development
|
|
34
|
+
prerelease: false
|
|
35
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
36
|
+
requirements:
|
|
37
|
+
- - "~>"
|
|
38
|
+
- !ruby/object:Gem::Version
|
|
39
|
+
version: '3.13'
|
|
40
|
+
- !ruby/object:Gem::Dependency
|
|
41
|
+
name: webmock
|
|
42
|
+
requirement: !ruby/object:Gem::Requirement
|
|
43
|
+
requirements:
|
|
44
|
+
- - "~>"
|
|
45
|
+
- !ruby/object:Gem::Version
|
|
46
|
+
version: '3.26'
|
|
47
|
+
type: :development
|
|
48
|
+
prerelease: false
|
|
49
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
50
|
+
requirements:
|
|
51
|
+
- - "~>"
|
|
52
|
+
- !ruby/object:Gem::Version
|
|
53
|
+
version: '3.26'
|
|
54
|
+
description: Cliente minimalista, sem dependencias externas, para criar issues, comentar
|
|
55
|
+
e consultar dados no Linear (linear.app) via sua API GraphQL.
|
|
56
|
+
email:
|
|
57
|
+
- ferretto@users.noreply.github.com
|
|
58
|
+
executables: []
|
|
59
|
+
extensions: []
|
|
60
|
+
extra_rdoc_files: []
|
|
61
|
+
files:
|
|
62
|
+
- ".gitignore"
|
|
63
|
+
- ".rspec"
|
|
64
|
+
- CHANGELOG.md
|
|
65
|
+
- Gemfile
|
|
66
|
+
- LICENSE
|
|
67
|
+
- README.md
|
|
68
|
+
- Rakefile
|
|
69
|
+
- examples/create_issue.rb
|
|
70
|
+
- examples/my_issues.rb
|
|
71
|
+
- examples/report.rb
|
|
72
|
+
- lib/linear_client.rb
|
|
73
|
+
- lib/linear_client/client.rb
|
|
74
|
+
- lib/linear_client/version.rb
|
|
75
|
+
- linear_client.gemspec
|
|
76
|
+
homepage: https://github.com/ferretto/linear_client
|
|
77
|
+
licenses:
|
|
78
|
+
- MIT
|
|
79
|
+
metadata:
|
|
80
|
+
source_code_uri: https://github.com/ferretto/linear_client
|
|
81
|
+
changelog_uri: https://github.com/ferretto/linear_client/blob/main/CHANGELOG.md
|
|
82
|
+
rdoc_options: []
|
|
83
|
+
require_paths:
|
|
84
|
+
- lib
|
|
85
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
86
|
+
requirements:
|
|
87
|
+
- - ">="
|
|
88
|
+
- !ruby/object:Gem::Version
|
|
89
|
+
version: '3.0'
|
|
90
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
91
|
+
requirements:
|
|
92
|
+
- - ">="
|
|
93
|
+
- !ruby/object:Gem::Version
|
|
94
|
+
version: '0'
|
|
95
|
+
requirements: []
|
|
96
|
+
rubygems_version: 3.6.7
|
|
97
|
+
specification_version: 4
|
|
98
|
+
summary: Cliente Ruby puro para a API GraphQL do Linear
|
|
99
|
+
test_files: []
|