linear-cli 0.5.3 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b9dbcbc2f5187f96fc259c3255587676d654919430f20a62e734ed9e5b43dccd
4
- data.tar.gz: 0ed365c14b74cb25b818037aff0f84abb03316bba52d7eb6b2705a06fc1d9b54
3
+ metadata.gz: bc273e12a3dd9e864894c2484bd08a203531da62873505b33d5706f13349e2c6
4
+ data.tar.gz: ffb38d1c66023c229bc98812fa55e4a58e29342adb46e96f63cf0054560a3964
5
5
  SHA512:
6
- metadata.gz: 677845b48a38aa6b7c03323db68f69de36645516f84f9085f5cd3b5a30ac8e99cfb45d4e14122a5b48a308ca8470ffa33db3033db7cf7e6e5e17d44d50801226
7
- data.tar.gz: c4f131d5548f80c8ab49cb0f85136bd38b04e13303dd66446488101c1a355b0b9939fa1c6e11fc23a37d7252a7039fe70e4ffe9150ce09c26ebc70b2a0d2326c
6
+ metadata.gz: 2323c788c7095f385320006a7be3b167b7dc9fc731c96a13ea5af48dcdec0dc013f8e6f55c71e9631022ae744a5faecbc34c8bda668c172cfb98d935c1af40a0
7
+ data.tar.gz: c8422224df18d500f92d1d8e0d90cd27f41cc8d0c148943b6f53f6e6269d67aae676f2fd006e9a4210199e5aae572e39e9b3bf46ddce2206f2880d88c3a78fac
data/CHANGELOG.md CHANGED
@@ -2,8 +2,27 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [0.6.0] - 2024-02-04
6
+
7
+ ## [0.5.5] - 2024-02-04
8
+ ### Added
9
+ - Added lclose alias and 'issue update' subcommand (@bougyman)
10
+
11
+ ## [0.5.4] - 2024-02-04
12
+
13
+ ## [0.5.3] - 2024-02-03
14
+ ### Added
15
+ - Added support for multiline descriptions without failing (@bougyman)
16
+
17
+ ### Changed
18
+ - Changed default branch to use upstream default branch name (@bougyman)
19
+
5
20
  ## [0.5.2] - 2024-02-03
6
21
  ### Added
7
22
  - Added new changelog management system (changelog-rb) (@bougyman)
8
23
 
9
- [Unreleased]: https://github.com/rubyists/linear-cli/compare/v0.5.2...HEAD
24
+ [Unreleased]: https://github.com/rubyists/linear-cli/compare/0.6.0...HEAD
25
+ [0.6.0]: https://github.com/rubyists/linear-cli/compare/v0.5.5...0.6.0
26
+ [0.5.5]: https://github.com/rubyists/linear-cli/compare/v0.5.4...v0.5.5
27
+ [0.5.4]: https://github.com/rubyists/linear-cli/compare/v0.5.3...v0.5.4
28
+ [0.5.3]: https://github.com/rubyists/linear-cli/compare/v0.5.2...v0.5.3
data/Readme.adoc CHANGED
@@ -82,6 +82,7 @@ $ lc w --teams
82
82
  ----
83
83
  $ lcls
84
84
  $ lcls --full
85
+ $ lcls -f CRY-1
85
86
  ----
86
87
 
87
88
  ==== Assign one or more issues to yourself (take em!)
@@ -100,7 +101,41 @@ $ lc issue take CRY-456 CRY-789
100
101
 
101
102
  [source,sh]
102
103
  ----
103
- $ lc i c --title "My new issue" --description "This is a new issue"
104
+ $ lc i c --title "My new issue" --description "This is a new issue" --labels Bug,Feature --team CRY
105
+ $ lc i c -t "My new issue" -T CRY -l Improvment,Feature
106
+ ----
107
+
108
+ NOTE: If you don't provide a title, team, labels or description, you will be prompted to enter them.
109
+
110
+ ==== Develop an issue
111
+
112
+ This will switch to the branch for the issue, creating the branch if it doesn't exist.
113
+
114
+ 'dev' is a shortcut for the 'develop' subcommand of the issue command
115
+
116
+ [source,sh]
117
+ ----
118
+ $ lc i dev CRY-1234
119
+ ----
120
+
121
+ TIP: You may pass the --dev option to the create subcommand to immediately develop the creted issue.
122
+
123
+ ==== Update an issue
124
+
125
+ All of the update options can work on multiple issues, so long as it's not more than 50
126
+ at a time. You can also use the 'u' alias for 'update', and as always, the 'i' alias for 'issue'.
127
+
128
+ ===== Add a comment to one or more issues
129
+
130
+ [source,sh]
131
+ ----
132
+ $ lc issue update --comment "Here is a comment" CRY-1234
133
+ ----
134
+
135
+ ===== Close one or many issues
136
+
137
+ [source,sh]
138
+ ----
139
+ $ lc i u --close --reason "These were closable" CRY-1234 CRY-2
104
140
  ----
105
141
 
106
- NOTE: If you don't provide a title or description, you will be prompted to enter them.
@@ -0,0 +1,4 @@
1
+ type: Added
2
+ title: >
3
+ Added support for multiline descriptions without failing
4
+ author: bougyman
@@ -0,0 +1 @@
1
+ date: 2024-02-04
@@ -0,0 +1,4 @@
1
+ type: Added
2
+ title: >
3
+ Added lclose alias and 'issue update' subcommand
4
+ author: bougyman
@@ -0,0 +1 @@
1
+ date: 2024-02-04
@@ -0,0 +1 @@
1
+ date: 2024-02-04
data/exe/lclose ADDED
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ exec File.join(__dir__, 'lclose.sh'), *ARGV
data/exe/lclose.sh ADDED
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env bash
2
+ if [[ "$*" =~ "--help" ]]
3
+ then
4
+ printf "This wrapper adds the --close option to the 'issue update' command.\n" >&2
5
+ printf "It is used to close one or many issues. The issues are specified by their ID/slugs.\n" >&2
6
+ printf "For closing multiple issues, you really want to pass --reason so you do not get prompted for each issue.\n\n" >&2
7
+ exec lc issue update --help
8
+ fi
9
+ exec lc issue update --close "$@"
data/lib/linear/api.rb CHANGED
@@ -41,7 +41,13 @@ module Rubyists
41
41
  end
42
42
 
43
43
  def query(query)
44
- call format('{ "query": "%s" }', query.to_s.gsub("\n", '').gsub('"', '\"'))
44
+ call format('{ "query": %s }', query.to_s.to_json)
45
+ rescue StandardError => e
46
+ logger.error('Error in query', query:, error: e)
47
+ raise e unless Rubyists::Linear.verbosity > 2
48
+
49
+ require 'pry'
50
+ binding.pry # rubocop:disable Lint/Debugger
45
51
  end
46
52
 
47
53
  def api_key
@@ -51,6 +57,7 @@ module Rubyists
51
57
  @api_key = ENV.fetch('LINEAR_API_KEY')
52
58
  end
53
59
  end
60
+ # Acts as a singleton for a GraphApi instance
54
61
  Api = Rubyists::Linear::GraphApi.new
55
62
  end
56
63
  end
@@ -47,10 +47,24 @@ module Rubyists
47
47
  ask_for_team
48
48
  end
49
49
 
50
+ def reason_for(reason = nil, four: nil)
51
+ return reason if reason
52
+
53
+ question = four ? "Reason for #{four}:" : 'Reason:'
54
+ prompt.ask(question)
55
+ end
56
+
57
+ def completed_state_for(thingy)
58
+ states = thingy.completed_states
59
+ return states.first if states.size == 1
60
+
61
+ prompt.select('Choose a completed state', states.to_h { |s| [s.name, s.id] })
62
+ end
63
+
50
64
  def description_for(description = nil)
51
65
  return description if description
52
66
 
53
- prompt.multiline('Description:').join(' ')
67
+ prompt.multiline('Description:').map(&:chomp).join('\\n')
54
68
  end
55
69
 
56
70
  def title_for(title = nil)
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Rubyists
4
4
  module Linear
5
- VERSION = '0.5.3'
5
+ VERSION = '0.6.0'
6
6
  end
7
7
  end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'semantic_logger'
4
+ require 'git'
5
+ require_relative '../issue'
6
+
7
+ module Rubyists
8
+ # Namespace for Linear
9
+ module Linear
10
+ M :issue, :user, :label
11
+ # Namespace for CLI
12
+ module CLI
13
+ module Issue
14
+ Update = Class.new Dry::CLI::Command
15
+ # The Update class is a Dry::CLI::Command to update an issue
16
+ class Update
17
+ include SemanticLogger::Loggable
18
+ include Rubyists::Linear::CLI::CommonOptions
19
+ include Rubyists::Linear::CLI::Issue # for #gimme_da_issue! and other Issue methods
20
+ desc 'Update an issue'
21
+ argument :issue_ids, type: :array, required: true, desc: 'Issue IDs (i.e. ISS-1)'
22
+ option :comment, type: :string, aliases: ['--message'], desc: 'Comment to add to the issue'
23
+ option :pr, type: :boolean, aliases: ['--pull-request'], default: false, desc: 'Create a pull request'
24
+ option :close, type: :boolean, default: false, desc: 'Close the issue'
25
+ option :reason, type: :string, aliases: ['--close-reason'], desc: 'Reason for closing the issue'
26
+
27
+ def call(issue_ids:, **options)
28
+ logger.debug('Updating issues', issue_ids:, options:)
29
+ Rubyists::Linear::Issue.find_all(issue_ids).each do |issue|
30
+ update_issue(issue, **options)
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
@@ -12,13 +12,40 @@ module Rubyists
12
12
  include CLI::SubCommands
13
13
  # Aliases for Issue commands
14
14
  ALIASES = {
15
- create: %w[c new add], # aliases for the create command
16
- develop: %w[d dev], # aliases for the create command
17
- list: %w[l ls], # aliases for the list command
18
- show: %w[s view v], # aliases for the show command
19
- issue: %w[i issues] # aliases for the main issue command itself
15
+ create: %w[c new add], # aliases for the create command
16
+ develop: %w[d dev], # aliases for the develop command
17
+ list: %w[l ls], # aliases for the list command
18
+ update: %w[u], # aliases for the close command
19
+ issue: %w[i issues] # aliases for the main issue command itself
20
20
  }.freeze
21
21
 
22
+ def issue_comment(issue, comment)
23
+ issue.add_comment(comment)
24
+ prompt.ok("Comment added to #{issue.identifier}")
25
+ end
26
+
27
+ def close_issue(issue, **options)
28
+ reason = reason_for(options[:reason], four: "closing #{issue.identifier} - #{issue.title}")
29
+ issue_comment(issue, reason)
30
+ close_state = completed_state_for(issue)
31
+ issue.close!(state: close_state, trash: options[:trash])
32
+ prompt.ok("#{issue.identifier} was closed")
33
+ end
34
+
35
+ def issue_pr(issue)
36
+ issue.create_pr!
37
+ prompt.ok("Pull request created for #{issue.identifier}")
38
+ end
39
+
40
+ def update_issue(issue, **options)
41
+ issue_comment(issue, options[:comment]) if options[:comment]
42
+ return close_issue(issue, **options) if options[:close]
43
+ return issue_pr(issue) if options[:pr]
44
+
45
+ prompt.warn('No action taken, no options specified')
46
+ prompt.ok('Issue was not updated')
47
+ end
48
+
22
49
  def make_da_issue!(**options)
23
50
  # These *_for methods are defined in Rubyists::Linear::CLI::SubCommands
24
51
  title = title_for options[:title]
@@ -28,7 +55,7 @@ module Rubyists
28
55
  Rubyists::Linear::Issue.create(title:, description:, team:, labels:)
29
56
  end
30
57
 
31
- def gimme_da_issue!(issue_id, me) # rubocop:disable Naming/MethodParameterName
58
+ def gimme_da_issue!(issue_id, me: Rubyists::Linear::User.me) # rubocop:disable Naming/MethodParameterName
32
59
  logger.trace('Looking up issue', issue_id:, me:)
33
60
  issue = Rubyists::Linear::Issue.find(issue_id)
34
61
  if issue.assignee && issue.assignee[:id] == me.id
@@ -5,7 +5,9 @@ require 'semantic_logger'
5
5
  require 'sequel/extensions/inflector'
6
6
 
7
7
  module Rubyists
8
+ # Namespace for Linear
8
9
  module Linear
10
+ L :api, :fragments
9
11
  # Module which provides a base model for Linear models.
10
12
  class BaseModel
11
13
  extend GQLi::DSL
@@ -32,6 +34,20 @@ module Rubyists
32
34
 
33
35
  # Class methods for Linear models.
34
36
  class << self
37
+ def has_one(relation, klass) # rubocop:disable Naming/PredicateName
38
+ define_method relation do
39
+ return instance_variable_get("@#{relation}") if instance_variable_defined?("@#{relation}")
40
+
41
+ instance_variable_set("@#{relation}", Rubyists::Linear.const_get(klass).new(data[relation]))
42
+ end
43
+
44
+ define_method "#{relation}=" do |val|
45
+ hash = val.is_a?(Hash) ? val : val.data
46
+ updated_data[relation] = hash
47
+ instance_variable_set("@#{relation}", Rubyists::Linear.const_get(klass).new(hash))
48
+ end
49
+ end
50
+
35
51
  def const_added(const)
36
52
  return unless const == :Base
37
53
 
@@ -108,6 +124,10 @@ module Rubyists
108
124
  data != updated_data
109
125
  end
110
126
 
127
+ def completed_states
128
+ workflow_states.select { |ws| ws.type == 'completed' }
129
+ end
130
+
111
131
  def to_h
112
132
  updated_data
113
133
  end
@@ -5,14 +5,13 @@ require 'gqli'
5
5
  module Rubyists
6
6
  # Namespace for Linear
7
7
  module Linear
8
- L :api
9
- L :fragments
10
- M :base_model
11
- M :user
8
+ M :base_model, :user
12
9
  Issue = Class.new(BaseModel)
13
10
  # The Issue class represents a Linear issue.
14
- class Issue
11
+ class Issue # rubocop:disable Metrics/ClassLength
15
12
  include SemanticLogger::Loggable
13
+ has_one :assignee, :User
14
+ has_one :team, :Team
16
15
 
17
16
  BASIC_FILTER = { completedAt: { null: true } }.freeze
18
17
 
@@ -20,7 +19,6 @@ module Rubyists
20
19
  id
21
20
  identifier
22
21
  title
23
- assignee { ___ User::Base }
24
22
  branchName
25
23
  description
26
24
  createdAt
@@ -28,33 +26,88 @@ module Rubyists
28
26
  end
29
27
 
30
28
  class << self
29
+ def base_fragment
30
+ @base_fragment ||= fragment('IssueWithTeams', 'Issue') do
31
+ ___ Base
32
+ assignee { ___ User.base_fragment }
33
+ team { ___ Team.base_fragment }
34
+ end
35
+ end
36
+
31
37
  def find(slug)
32
- q = query { issue(id: slug) { ___ Base } }
38
+ q = query { issue(id: slug) { ___ Issue.base_fragment } }
33
39
  data = Api.query(q)
34
40
  raise NotFoundError, "Issue not found: #{slug}" if data.nil?
35
41
 
36
42
  new(data[:issue])
37
43
  end
38
44
 
45
+ def find_all(*slugs)
46
+ slugs.flatten.map { |slug| find(slug) }
47
+ end
48
+
39
49
  def create(title:, description:, team:, labels: [])
40
50
  team_id = team.id
41
51
  label_ids = labels.map(&:id)
42
52
  input = { title:, description:, teamId: team_id }
43
- input.merge!(labelIds: label_ids) unless label_ids.empty?
44
- m = mutation { issueCreate(input:) { issue { ___ Base } } }
45
- data = Api.query(m)
46
- new(data[:issueCreate][:issue])
53
+ input[:labelIds] = label_ids unless label_ids.empty?
54
+ m = mutation { issueCreate(input:) { issue { ___ Issue.base_fragment } } }
55
+ query_data = Api.query(m)
56
+ new query_data.dig(:issueCreate, :issue)
47
57
  end
48
58
  end
49
59
 
50
- def assign!(user)
60
+ def comment_fragment
61
+ @comment_fragment ||= fragment('Comment', 'Comment') do
62
+ id
63
+ body
64
+ url
65
+ end
66
+ end
67
+
68
+ # Reference for this mutation:
69
+ # https://studio.apollographql.com/public/Linear-API/variant/current/schema/reference/inputs/CommentCreateInput
70
+ def add_comment(comment)
71
+ id_for_this = identifier
72
+ comment_frag = comment_fragment
73
+ m = mutation { commentCreate(input: { issueId: id_for_this, body: comment }) { comment { ___ comment_frag } } }
74
+
75
+ query_data = Api.query(m)
76
+ query_data.dig(:commentCreate, :comment)
77
+ self
78
+ end
79
+
80
+ def close_mutation(close_state, trash: false)
51
81
  id_for_this = identifier
52
- m = mutation { issueUpdate(id: id_for_this, input: { assigneeId: user.id }) { issue { ___ Base } } }
53
- data = Api.query(m)
54
- updated = data.dig(:issueUpdate, :issue)
82
+ input = { stateId: close_state.id }
83
+ input[:trash] = true if trash
84
+ mutation { issueUpdate(id: id_for_this, input:) { issue { ___ Issue.base_fragment } } }
85
+ end
86
+
87
+ def close!(state: nil, trash: false)
88
+ logger.warn "Using first completed state found: #{completed_states.first}" if state.nil?
89
+ state ||= completed_states.first
90
+ query_data = Api.query close_mutation(state, trash:)
91
+ updated = query_data.dig(:issueUpdate, :issue)
92
+ raise SmellsBad, "Unknown response for issue close: #{data} (should have :issueUpdate key)" if updated.nil?
93
+
94
+ @data = @updated_data = updated
95
+ self
96
+ end
97
+
98
+ def assign!(user)
99
+ this_id = identifier
100
+ m = mutation { issueUpdate(id: this_id, input: { assigneeId: user.id }) { issue { ___ Issue.base_fragment } } }
101
+ query_data = Api.query(m)
102
+ updated = query_data.dig(:issueUpdate, :issue)
55
103
  raise SmellsBad, "Unknown response for issue update: #{data} (should have :issueUpdate key)" if updated.nil?
56
104
 
57
- Issue.new updated
105
+ @data = @updated_data = updated
106
+ self
107
+ end
108
+
109
+ def workflow_states
110
+ @workflow_states ||= team.workflow_states
58
111
  end
59
112
 
60
113
  def inspection
@@ -62,18 +115,26 @@ module Rubyists
62
115
  end
63
116
 
64
117
  def to_s
65
- basic = format('%<id>-12s %<title>s', id: data[:identifier], title: data[:title])
118
+ basic = format('%<id>-12s %<title>s', id: identifier, title:)
66
119
  return basic unless (name = data.dig(:assignee, :name))
67
120
 
68
121
  format('%<basic>s (%<name>s)', basic:, name:)
69
122
  end
70
123
 
124
+ def parsed_description
125
+ return TTY::Markdown.parse(description) if description && !description.empty?
126
+
127
+ TTY::Markdown.parse(['# No Description For this issue??',
128
+ 'Issues really need description',
129
+ "## What's up with that?"].join("\n"))
130
+ rescue StandardError => e
131
+ logger.error 'Error parsing description', e
132
+ "Description was unparsable: #{description}\n"
133
+ end
134
+
71
135
  def full
72
136
  sep = '-' * to_s.length
73
- format("%<to_s>s\n%<sep>s\n%<description>s\n",
74
- sep:,
75
- to_s:,
76
- description: (TTY::Markdown.parse(data[:description]) rescue 'No Description?')) # rubocop:disable Style/RescueModifier
137
+ format("%<to_s>s\n%<sep>s\n%<description>s\n", sep:, to_s:, description: parsed_description)
77
138
  end
78
139
 
79
140
  def display(options)
@@ -31,14 +31,14 @@ module Rubyists
31
31
  fragment('LabelWithTeams', 'IssueLabel') do
32
32
  ___ Base
33
33
  parent { ___ Base }
34
- team { ___ Team::Base }
34
+ team { ___ Team.base_fragment }
35
35
  end
36
36
  end
37
37
 
38
38
  def self.find_all_by_name(names)
39
39
  q = query do
40
40
  issueLabels(filter: { name: { in: names } }) do
41
- edges { node { ___ Base } }
41
+ edges { node { ___ base_fragment } }
42
42
  end
43
43
  end
44
44
  data = Api.query(q)
@@ -5,8 +5,7 @@ require 'gqli'
5
5
  module Rubyists
6
6
  # Namespace for Linear
7
7
  module Linear
8
- L :api, :fragments
9
- M :base_model, :issue, :user
8
+ M :base_model, :issue, :user, :workflow_state
10
9
  Team = Class.new(BaseModel)
11
10
  # The Issue class represents a Linear issue.
12
11
  class Team
@@ -96,6 +95,26 @@ module Rubyists
96
95
  def display(_options)
97
96
  printf "%s\n", full
98
97
  end
98
+
99
+ def workflow_states_query
100
+ team_id = id
101
+ query do
102
+ team(id: team_id) do
103
+ states do
104
+ nodes { ___ WorkflowState.base_fragment }
105
+ end
106
+ end
107
+ end
108
+ end
109
+
110
+ def workflow_states
111
+ return @workflow_states if @workflow_states
112
+
113
+ data = Api.query(workflow_states_query)
114
+ @workflow_states = data.dig(:team, :states, :nodes)&.map do |state|
115
+ WorkflowState.new state
116
+ end
117
+ end
99
118
  end
100
119
  end
101
120
  end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'gqli'
4
+
5
+ module Rubyists
6
+ # Namespace for Linear
7
+ module Linear
8
+ M :base_model
9
+ WorkflowState = Class.new(BaseModel)
10
+ # The WorkflowState class represents a Linear workflow state.
11
+ class WorkflowState
12
+ include SemanticLogger::Loggable
13
+
14
+ Base = fragment('BaseWorkflowState', 'WorkflowState') do
15
+ id
16
+ name
17
+ position
18
+ type
19
+ description
20
+ createdAt
21
+ updatedAt
22
+ end
23
+
24
+ def to_s
25
+ format('%<name>-12s %<type>s', name:, type:)
26
+ end
27
+
28
+ def inspection
29
+ format('name: "%<name>s" type: "%<type>s"', name:, type:)
30
+ end
31
+ end
32
+ end
33
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: linear-cli
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.3
4
+ version: 0.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tj (bougyman) Vanderpoel
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2024-02-03 00:00:00.000000000 Z
11
+ date: 2024-02-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: base64
@@ -183,6 +183,8 @@ email:
183
183
  - tj@rubyists.com
184
184
  executables:
185
185
  - lc
186
+ - lclose
187
+ - lclose.sh
186
188
  - lcls
187
189
  - lcls.sh
188
190
  extensions: []
@@ -194,10 +196,17 @@ files:
194
196
  - Readme.adoc
195
197
  - changelog/0.5.2/added_new_changelog_management_system_changelog_rb.yml
196
198
  - changelog/0.5.2/tag.yml
199
+ - changelog/0.5.3/added_support_for_multiline_descriptions_without_failing.yml
197
200
  - changelog/0.5.3/changed_default_branch_to_use_upstream_default_branch_name.yml
198
201
  - changelog/0.5.3/tag.yml
202
+ - changelog/0.5.4/tag.yml
203
+ - changelog/0.5.5/added_lclose_alias_and_issue_update_subcommand.yml
204
+ - changelog/0.5.5/tag.yml
205
+ - changelog/0.6.0/tag.yml
199
206
  - changelog/unreleased/.gitkeep
200
207
  - exe/lc
208
+ - exe/lclose
209
+ - exe/lclose.sh
201
210
  - exe/lcls
202
211
  - exe/lcls.sh
203
212
  - lib/linear.rb
@@ -213,6 +222,7 @@ files:
213
222
  - lib/linear/commands/issue/develop.rb
214
223
  - lib/linear/commands/issue/list.rb
215
224
  - lib/linear/commands/issue/take.rb
225
+ - lib/linear/commands/issue/update.rb
216
226
  - lib/linear/commands/team.rb
217
227
  - lib/linear/commands/team/list.rb
218
228
  - lib/linear/commands/whoami.rb
@@ -223,6 +233,7 @@ files:
223
233
  - lib/linear/models/label.rb
224
234
  - lib/linear/models/team.rb
225
235
  - lib/linear/models/user.rb
236
+ - lib/linear/models/workflow_state.rb
226
237
  - lib/linear/version.rb
227
238
  - linear-cli.gemspec
228
239
  - sig/linear/cli.rbs