fjord_boot_camp 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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 688db9e7dcb6975c8ab319f5ce4656d13469b5f3795206143a7bb3b476cdb366
4
+ data.tar.gz: 50ea78d5d21b11c0637ce3b0cc09953ce0f5e83691a8e6a74c7798e0a80c75a4
5
+ SHA512:
6
+ metadata.gz: 4a9755de8cdfddb5c6ea3762d258f6585c8b3b07dfec900d9662d48ee00842d6cb415939f107af10b11e648b2994ade472f4574c6d8b0bb8a8c705d7c3f28a28
7
+ data.tar.gz: 6ee790658dee29968e261e0570521de25b98c7ec5ec3dfbe82bddef3b18502cd8bfd70f9045581d26ba4a61e8a03d56c8b0baa4feb08b68db845b909a7f4c3d4
@@ -0,0 +1,40 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+ branches: [main]
8
+
9
+ jobs:
10
+ test:
11
+ runs-on: ubuntu-latest
12
+ strategy:
13
+ matrix:
14
+ ruby-version: ['3.1', '3.2', '3.3', '3.4']
15
+
16
+ steps:
17
+ - uses: actions/checkout@v4
18
+
19
+ - name: Set up Ruby ${{ matrix.ruby-version }}
20
+ uses: ruby/setup-ruby@v1
21
+ with:
22
+ ruby-version: ${{ matrix.ruby-version }}
23
+ bundler-cache: true
24
+
25
+ - name: Run tests
26
+ run: bundle exec rake test
27
+
28
+ rubocop:
29
+ runs-on: ubuntu-latest
30
+ steps:
31
+ - uses: actions/checkout@v4
32
+
33
+ - name: Set up Ruby
34
+ uses: ruby/setup-ruby@v1
35
+ with:
36
+ ruby-version: '3.4'
37
+ bundler-cache: true
38
+
39
+ - name: Run RuboCop
40
+ run: bundle exec rubocop
@@ -0,0 +1,60 @@
1
+ name: Release
2
+
3
+ on:
4
+ push:
5
+ tags:
6
+ - 'v*'
7
+
8
+ jobs:
9
+ test:
10
+ runs-on: ubuntu-latest
11
+ strategy:
12
+ matrix:
13
+ ruby-version: ['3.1', '3.2', '3.3', '3.4']
14
+
15
+ steps:
16
+ - uses: actions/checkout@v4
17
+
18
+ - name: Set up Ruby ${{ matrix.ruby-version }}
19
+ uses: ruby/setup-ruby@v1
20
+ with:
21
+ ruby-version: ${{ matrix.ruby-version }}
22
+ bundler-cache: true
23
+
24
+ - name: Run tests
25
+ run: bundle exec rake test
26
+
27
+ rubocop:
28
+ runs-on: ubuntu-latest
29
+ steps:
30
+ - uses: actions/checkout@v4
31
+
32
+ - name: Set up Ruby
33
+ uses: ruby/setup-ruby@v1
34
+ with:
35
+ ruby-version: '3.4'
36
+ bundler-cache: true
37
+
38
+ - name: Run RuboCop
39
+ run: bundle exec rubocop
40
+
41
+ release:
42
+ needs: [test, rubocop]
43
+ runs-on: ubuntu-latest
44
+ environment: release
45
+
46
+ permissions:
47
+ id-token: write
48
+ contents: write
49
+
50
+ steps:
51
+ - uses: actions/checkout@v4
52
+
53
+ - name: Set up Ruby
54
+ uses: ruby/setup-ruby@v1
55
+ with:
56
+ ruby-version: '3.4'
57
+ bundler-cache: true
58
+
59
+ - name: Publish to RubyGems
60
+ uses: rubygems/release-gem@v1
data/.gitignore ADDED
@@ -0,0 +1,8 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
data/.mise.toml ADDED
@@ -0,0 +1,2 @@
1
+ [tools]
2
+ ruby = "3.4.4"
data/.rubocop.yml ADDED
@@ -0,0 +1,49 @@
1
+ plugins:
2
+ - rubocop-minitest
3
+
4
+ AllCops:
5
+ TargetRubyVersion: 3.1
6
+ NewCops: enable
7
+ SuggestExtensions: false
8
+
9
+ Style/Documentation:
10
+ Enabled: false
11
+
12
+ Style/FrozenStringLiteralComment:
13
+ Enabled: true
14
+
15
+ Style/SafeNavigationChainLength:
16
+ Enabled: false
17
+
18
+ Metrics/MethodLength:
19
+ Max: 50
20
+
21
+ Metrics/AbcSize:
22
+ Max: 50
23
+
24
+ Metrics/ClassLength:
25
+ Max: 300
26
+
27
+ Metrics/CyclomaticComplexity:
28
+ Max: 25
29
+
30
+ Metrics/PerceivedComplexity:
31
+ Max: 25
32
+
33
+ Metrics/BlockLength:
34
+ Max: 50
35
+
36
+ Layout/LineLength:
37
+ Max: 180
38
+
39
+ Naming/MethodParameterName:
40
+ MinNameLength: 1
41
+
42
+ Naming/VariableNumber:
43
+ Enabled: false
44
+
45
+ Gemspec/DevelopmentDependencies:
46
+ Enabled: false
47
+
48
+ Minitest/MultipleAssertions:
49
+ Max: 10
data/Gemfile ADDED
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ source 'https://rubygems.org'
4
+
5
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,85 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ fjord_boot_camp (0.1.0)
5
+ faraday (>= 1.0, < 3.0)
6
+ thor (~> 1.0)
7
+
8
+ GEM
9
+ remote: https://rubygems.org/
10
+ specs:
11
+ addressable (2.8.9)
12
+ public_suffix (>= 2.0.2, < 8.0)
13
+ ast (2.4.3)
14
+ bigdecimal (4.0.1)
15
+ crack (1.0.1)
16
+ bigdecimal
17
+ rexml
18
+ faraday (2.14.1)
19
+ faraday-net_http (>= 2.0, < 3.5)
20
+ json
21
+ logger
22
+ faraday-net_http (3.4.2)
23
+ net-http (~> 0.5)
24
+ hashdiff (1.2.1)
25
+ json (2.19.2)
26
+ language_server-protocol (3.17.0.5)
27
+ lint_roller (1.1.0)
28
+ logger (1.7.0)
29
+ minitest (5.27.0)
30
+ net-http (0.9.1)
31
+ uri (>= 0.11.1)
32
+ parallel (1.27.0)
33
+ parser (3.3.10.2)
34
+ ast (~> 2.4.1)
35
+ racc
36
+ prism (1.9.0)
37
+ public_suffix (7.0.5)
38
+ racc (1.8.1)
39
+ rainbow (3.1.1)
40
+ rake (13.3.1)
41
+ regexp_parser (2.11.3)
42
+ rexml (3.4.4)
43
+ rubocop (1.86.0)
44
+ json (~> 2.3)
45
+ language_server-protocol (~> 3.17.0.2)
46
+ lint_roller (~> 1.1.0)
47
+ parallel (~> 1.10)
48
+ parser (>= 3.3.0.2)
49
+ rainbow (>= 2.2.2, < 4.0)
50
+ regexp_parser (>= 2.9.3, < 3.0)
51
+ rubocop-ast (>= 1.49.0, < 2.0)
52
+ ruby-progressbar (~> 1.7)
53
+ unicode-display_width (>= 2.4.0, < 4.0)
54
+ rubocop-ast (1.49.1)
55
+ parser (>= 3.3.7.2)
56
+ prism (~> 1.7)
57
+ rubocop-minitest (0.39.1)
58
+ lint_roller (~> 1.1)
59
+ rubocop (>= 1.75.0, < 2.0)
60
+ rubocop-ast (>= 1.38.0, < 2.0)
61
+ ruby-progressbar (1.13.0)
62
+ thor (1.5.0)
63
+ unicode-display_width (3.2.0)
64
+ unicode-emoji (~> 4.1)
65
+ unicode-emoji (4.2.0)
66
+ uri (1.1.1)
67
+ webmock (3.26.2)
68
+ addressable (>= 2.8.0)
69
+ crack (>= 0.3.2)
70
+ hashdiff (>= 0.4.0, < 2.0.0)
71
+
72
+ PLATFORMS
73
+ ruby
74
+ x86_64-darwin-25
75
+
76
+ DEPENDENCIES
77
+ fjord_boot_camp!
78
+ minitest (~> 5.0)
79
+ rake (~> 13.0)
80
+ rubocop (~> 1.0)
81
+ rubocop-minitest (~> 0.36)
82
+ webmock (~> 3.0)
83
+
84
+ BUNDLED WITH
85
+ 2.6.7
data/README.md ADDED
@@ -0,0 +1,90 @@
1
+ # fjord_boot_camp
2
+
3
+ FJORD BOOT CAMP API の Ruby クライアント。ライブラリとしても CLI としても使える。
4
+
5
+ ## インストール
6
+
7
+ ```ruby
8
+ gem install fjord_boot_camp
9
+ ```
10
+
11
+ または Gemfile に追加:
12
+
13
+ ```ruby
14
+ gem "fjord_boot_camp"
15
+ ```
16
+
17
+ ## セットアップ
18
+
19
+ 環境変数を設定:
20
+
21
+ ```bash
22
+ export BOOTCAMP_URL="https://bootcamp.fjord.jp"
23
+ export BOOTCAMP_ACCESS_TOKEN="your-oauth-token"
24
+ ```
25
+
26
+ ## CLI で使う
27
+
28
+ ```bash
29
+ # 最近の日報
30
+ fjord_boot_camp reports recent
31
+
32
+ # 日報一覧(JSON出力)
33
+ fjord_boot_camp reports list --format json --limit 10
34
+
35
+ # 日報詳細
36
+ fjord_boot_camp reports show 12345
37
+
38
+ # ユーザー一覧
39
+ fjord_boot_camp users list --target trainee
40
+
41
+ # 研修生の週次進捗レポート
42
+ fjord_boot_camp progress
43
+ fjord_boot_camp progress --week-start 2026-03-16
44
+ fjord_boot_camp progress --company-id 1
45
+
46
+ # JSON出力(AIエージェント向き)
47
+ fjord_boot_camp progress --format json
48
+ ```
49
+
50
+ ## ライブラリとして使う
51
+
52
+ ```ruby
53
+ require "fjord_boot_camp"
54
+
55
+ FjordBootCamp.configure do |config|
56
+ config.base_url = "https://bootcamp.fjord.jp"
57
+ config.access_token = "your-oauth-token"
58
+ end
59
+
60
+ client = FjordBootCamp.client
61
+
62
+ # 日報
63
+ reports = client.reports.list(limit: 10)
64
+ report = client.reports.find(12345)
65
+ recent = client.reports.recent
66
+
67
+ # ユーザー
68
+ trainees = client.users.trainees
69
+ user = client.users.find(1)
70
+
71
+ # プラクティス
72
+ practices = client.practices.list
73
+
74
+ # 研修生進捗
75
+ progress = client.trainee_progresses.list
76
+ progress = client.trainee_progresses.list(week_start: "2026-03-16", company_id: 1)
77
+ ```
78
+
79
+ ## 開発
80
+
81
+ ```bash
82
+ git clone https://github.com/fjordllc/fjord_boot_camp.git
83
+ cd fjord_boot_camp
84
+ bin/setup
85
+ bin/console
86
+ ```
87
+
88
+ ## License
89
+
90
+ MIT
data/Rakefile ADDED
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rake/testtask'
4
+
5
+ Rake::TestTask.new(:test) do |t|
6
+ t.libs << 'test'
7
+ t.libs << 'lib'
8
+ t.test_files = FileList['test/**/*_test.rb']
9
+ end
10
+
11
+ task default: :test
data/bin/console ADDED
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require 'bundler/setup'
5
+ require 'fjord_boot_camp'
6
+
7
+ # You can add fixtures and/or initialization code here to make experimenting
8
+ # with your gem easier. You can also use a different console, if you like.
9
+
10
+ # (If you use this, don't forget to add pry to your Gemfile!)
11
+ # require "pry"
12
+ # Pry.start
13
+
14
+ require 'irb'
15
+ IRB.start(__FILE__)
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require 'fjord_boot_camp'
5
+ require 'fjord_boot_camp/cli'
6
+
7
+ FjordBootCamp::CLI.start(ARGV)
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ lib = File.expand_path('lib', __dir__)
4
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
+ require 'fjord_boot_camp/version'
6
+
7
+ Gem::Specification.new do |spec|
8
+ spec.name = 'fjord_boot_camp'
9
+ spec.version = FjordBootCamp::VERSION
10
+ spec.authors = ['komagata']
11
+ spec.email = ['komagata@gmail.com']
12
+
13
+ spec.summary = 'Ruby client for FJORD BOOT CAMP API'
14
+ spec.description = 'A Ruby gem to interact with the FJORD BOOT CAMP API. Provides both a library and CLI for accessing reports, users, practices, and trainee progress data.'
15
+ spec.homepage = 'https://github.com/fjordllc/fjord_boot_camp'
16
+ spec.license = 'MIT'
17
+ spec.required_ruby_version = '>= 3.1.0'
18
+
19
+ spec.metadata['homepage_uri'] = spec.homepage
20
+ spec.metadata['source_code_uri'] = 'https://github.com/fjordllc/fjord_boot_camp'
21
+ spec.metadata['rubygems_mfa_required'] = 'true'
22
+
23
+ spec.files = Dir.chdir(File.expand_path(__dir__)) do
24
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
25
+ end
26
+ spec.bindir = 'exe'
27
+ spec.executables = ['fjord_boot_camp']
28
+ spec.require_paths = ['lib']
29
+
30
+ spec.add_dependency 'faraday', '>= 1.0', '< 3.0'
31
+ spec.add_dependency 'thor', '~> 1.0'
32
+
33
+ spec.add_development_dependency 'minitest', '~> 5.0'
34
+ spec.add_development_dependency 'rake', '~> 13.0'
35
+ spec.add_development_dependency 'rubocop', '~> 1.0'
36
+ spec.add_development_dependency 'rubocop-minitest', '~> 0.36'
37
+ spec.add_development_dependency 'webmock', '~> 3.0'
38
+ end
@@ -0,0 +1,220 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'thor'
4
+ require 'json'
5
+
6
+ module FjordBootCamp
7
+ class CLI < Thor
8
+ class_option :url, type: :string, desc: 'Base URL (default: $BOOTCAMP_URL or https://bootcamp.fjord.jp)'
9
+ class_option :token, type: :string, desc: 'Access token (default: $BOOTCAMP_ACCESS_TOKEN)'
10
+ class_option :format, type: :string, default: 'text', enum: %w[text json], desc: 'Output format'
11
+
12
+ desc 'reports [list|show ID]', '日報を取得'
13
+ option :user_id, type: :numeric, desc: 'ユーザーIDで絞り込み'
14
+ option :limit, type: :numeric, desc: '取得件数'
15
+ option :page, type: :numeric, desc: 'ページ番号'
16
+ def reports(subcommand = 'list', id = nil)
17
+ case subcommand
18
+ when 'list'
19
+ data = client.reports.list(
20
+ user_id: options[:user_id],
21
+ limit: options[:limit],
22
+ page: options[:page]
23
+ )
24
+ if json_output?
25
+ puts JSON.pretty_generate(data)
26
+ else
27
+ print_reports(data['reports'] || data)
28
+ end
29
+ when 'show'
30
+ abort 'Usage: fjord_boot_camp reports show ID' unless id
31
+ data = client.reports.find(id)
32
+ json_output? ? puts(JSON.pretty_generate(data)) : print_report_detail(data)
33
+ when 'recent'
34
+ data = client.reports.recent
35
+ if json_output?
36
+ puts JSON.pretty_generate(data)
37
+ else
38
+ print_reports(data['reports'] || data)
39
+ end
40
+ else
41
+ abort "Unknown subcommand: #{subcommand}. Use: list, show, recent"
42
+ end
43
+ end
44
+
45
+ desc 'users [list|show ID]', 'ユーザーを取得'
46
+ option :target, type: :string, desc: 'フィルタ (student, trainee, mentor, adviser, graduate等)'
47
+ option :page, type: :numeric, desc: 'ページ番号'
48
+ def users(subcommand = 'list', id = nil)
49
+ case subcommand
50
+ when 'list'
51
+ data = client.users.list(target: options[:target], page: options[:page])
52
+ if json_output?
53
+ puts JSON.pretty_generate(data)
54
+ else
55
+ print_users(data['users'] || data)
56
+ end
57
+ when 'show'
58
+ abort 'Usage: fjord_boot_camp users show ID' unless id
59
+ data = client.users.find(id)
60
+ json_output? ? puts(JSON.pretty_generate(data)) : print_user_detail(data)
61
+ when 'trainees'
62
+ data = client.users.trainees
63
+ json_output? ? puts(JSON.pretty_generate(data)) : print_users(data['users'] || data)
64
+ else
65
+ abort "Unknown subcommand: #{subcommand}. Use: list, show, trainees"
66
+ end
67
+ end
68
+
69
+ desc 'practices [list|show ID]', 'プラクティスを取得'
70
+ def practices(subcommand = 'list', id = nil)
71
+ case subcommand
72
+ when 'list'
73
+ data = client.practices.list
74
+ json_output? ? puts(JSON.pretty_generate(data)) : print_practices(data['practices'] || data)
75
+ when 'show'
76
+ abort 'Usage: fjord_boot_camp practices show ID' unless id
77
+ data = client.practices.find(id)
78
+ puts JSON.pretty_generate(data)
79
+ else
80
+ abort "Unknown subcommand: #{subcommand}. Use: list, show"
81
+ end
82
+ end
83
+
84
+ desc 'progress', '研修生の週次進捗レポート'
85
+ option :week_start, type: :string, desc: '対象週の開始日 (例: 2026-03-23)'
86
+ option :company_id, type: :numeric, desc: '企業IDで絞り込み'
87
+ def progress
88
+ data = client.trainee_progresses.list(
89
+ week_start: options[:week_start],
90
+ company_id: options[:company_id]
91
+ )
92
+ json_output? ? puts(JSON.pretty_generate(data)) : print_progress_report(data)
93
+ end
94
+
95
+ desc 'version', 'バージョンを表示'
96
+ def version
97
+ puts "fjord_boot_camp #{FjordBootCamp::VERSION}"
98
+ end
99
+
100
+ private
101
+
102
+ def client
103
+ config = FjordBootCamp::Configuration.new
104
+ config.base_url = options[:url] if options[:url]
105
+ config.access_token = options[:token] if options[:token]
106
+ FjordBootCamp::Client.new(config)
107
+ end
108
+
109
+ def json_output?
110
+ options[:format] == 'json'
111
+ end
112
+
113
+ def print_reports(reports)
114
+ reports.each do |r|
115
+ emoji = { 'positive' => '😄', 'neutral' => '😐', 'negative' => '😢' }[r['emotion']] || '📝'
116
+ wip = r['wip'] ? ' [WIP]' : ''
117
+ user = r.dig('user', 'longName') || r.dig('user', 'login_name') || ''
118
+ puts "#{emoji} #{r['reportedOn']} #{r['title']}#{wip} (#{user})"
119
+ puts " #{r['url']}" if r['url']
120
+ end
121
+ end
122
+
123
+ def print_report_detail(r)
124
+ puts '=' * 60
125
+ puts "📝 #{r['title']}"
126
+ puts " 日付: #{r['reportedOn']}"
127
+ puts " URL: #{r['url']}"
128
+ user = r['user']
129
+ puts " 著者: #{user['longName'] || user['login_name']}" if user
130
+ puts '-' * 60
131
+ puts r['description'] if r['description']
132
+ if r['comments']&.any?
133
+ puts
134
+ puts "💬 コメント (#{r['comments'].size}件)"
135
+ r['comments'].each do |c|
136
+ author = c.dig('user', 'longName') || c.dig('user', 'login_name') || '?'
137
+ puts " #{author}: #{c['description']&.lines&.first&.strip}"
138
+ end
139
+ end
140
+ puts '=' * 60
141
+ end
142
+
143
+ def print_users(users)
144
+ users.each do |u|
145
+ role = u['primaryRole'] || u['roles']&.first || ''
146
+ company = u.dig('company', 'url') ? " (#{u.dig('company', 'url')})" : ''
147
+ puts "👤 #{u['longName'] || u['login_name']} [#{role}]#{company}"
148
+ end
149
+ end
150
+
151
+ def print_user_detail(u)
152
+ puts "👤 #{u['longName'] || u['login_name']}"
153
+ puts " ログイン名: #{u['login_name']}"
154
+ puts " ロール: #{u['roles']&.join(', ')}"
155
+ end
156
+
157
+ def print_practices(practices)
158
+ practices.each do |p|
159
+ puts "📚 #{p['id']}: #{p['title']}"
160
+ end
161
+ end
162
+
163
+ def print_progress_report(data)
164
+ puts '=' * 60
165
+ puts "📊 研修生週次レポート #{data['weekStart']} 〜 #{data['weekEnd']}"
166
+ puts '=' * 60
167
+ puts
168
+
169
+ (data['trainees'] || []).each do |t|
170
+ activity = t['weeklyActivity'] || {}
171
+ current = t['currentPractice'] || {}
172
+ overall = t['overallProgress'] || {}
173
+ company = t.dig('company', 'name') || '所属なし'
174
+ course = t.dig('course', 'title') || ''
175
+
176
+ report_count = activity['reportCount'] || 0
177
+ weekdays = activity['weekdays'] || 5
178
+ percentage = overall['completedPercentage'] || 0
179
+
180
+ # ステータス判定
181
+ status = if report_count >= 4
182
+ '✅'
183
+ elsif report_count >= 2
184
+ '⚠️'
185
+ else
186
+ '🔴'
187
+ end
188
+
189
+ puts "■ #{t['longName']}(#{company})- #{course} [#{percentage}%]"
190
+ puts " 日報: #{report_count}/#{weekdays}日 #{status}"
191
+
192
+ # 今週の変化
193
+ changes = activity['practiceChanges'] || []
194
+ changes.each do |c|
195
+ case c['status']
196
+ when 'complete'
197
+ puts " 今週: 「#{c['practiceTitle']}」完了 🎉"
198
+ when 'submitted'
199
+ puts " 今週: 「#{c['practiceTitle']}」提出"
200
+ when 'started'
201
+ puts " 今週: 「#{c['practiceTitle']}」着手"
202
+ end
203
+ end
204
+
205
+ # 現在のプラクティス
206
+ if current['title']
207
+ days = current['daysOnPractice'] || 0
208
+ slow = if days >= 14
209
+ ' 🐢'
210
+ else
211
+ days >= 7 ? ' ⏳' : ''
212
+ end
213
+ puts " 現在: 「#{current['title']}」(#{days}日目#{slow})"
214
+ end
215
+
216
+ puts
217
+ end
218
+ end
219
+ end
220
+ end
@@ -0,0 +1,58 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'faraday'
4
+ require 'json'
5
+
6
+ module FjordBootCamp
7
+ class Client
8
+ attr_reader :configuration
9
+
10
+ def initialize(configuration = nil)
11
+ @configuration = configuration || FjordBootCamp.configuration || Configuration.new
12
+ end
13
+
14
+ def reports
15
+ Resources::Reports.new(self)
16
+ end
17
+
18
+ def users
19
+ Resources::Users.new(self)
20
+ end
21
+
22
+ def practices
23
+ Resources::Practices.new(self)
24
+ end
25
+
26
+ def trainee_progresses
27
+ Resources::TraineeProgresses.new(self)
28
+ end
29
+
30
+ def get(path, params = {})
31
+ response = connection.get(path, params)
32
+ handle_response(response)
33
+ end
34
+
35
+ private
36
+
37
+ def connection
38
+ @connection ||= Faraday.new(url: configuration.base_url) do |f|
39
+ f.headers['Authorization'] = "Bearer #{configuration.access_token}" if configuration.access_token
40
+ f.headers['Accept'] = 'application/json'
41
+ f.adapter Faraday.default_adapter
42
+ end
43
+ end
44
+
45
+ def handle_response(response)
46
+ case response.status
47
+ when 200..299
48
+ JSON.parse(response.body)
49
+ when 401
50
+ raise AuthenticationError, 'Authentication failed. Check your access token.'
51
+ when 404
52
+ raise NotFoundError, "Resource not found: #{response.env.url.path}"
53
+ else
54
+ raise ApiError, "API error (#{response.status}): #{response.body}"
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ module FjordBootCamp
4
+ class Configuration
5
+ attr_accessor :base_url, :access_token
6
+
7
+ def initialize
8
+ @base_url = ENV.fetch('BOOTCAMP_URL', 'https://bootcamp.fjord.jp')
9
+ @access_token = ENV.fetch('BOOTCAMP_ACCESS_TOKEN', nil)
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module FjordBootCamp
4
+ module Resources
5
+ class Base
6
+ attr_reader :client
7
+
8
+ def initialize(client)
9
+ @client = client
10
+ end
11
+
12
+ private
13
+
14
+ def get(path, params = {})
15
+ client.get(path, params)
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'base'
4
+
5
+ module FjordBootCamp
6
+ module Resources
7
+ class Practices < Base
8
+ # プラクティス一覧を取得
9
+ def list
10
+ get('/api/practices')
11
+ end
12
+
13
+ # プラクティス詳細を取得
14
+ # @param id [Integer] プラクティスID
15
+ def find(id)
16
+ get("/api/practices/#{id}")
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'base'
4
+
5
+ module FjordBootCamp
6
+ module Resources
7
+ class Reports < Base
8
+ # 日報一覧を取得
9
+ # @param user_id [Integer, nil] ユーザーIDで絞り込み
10
+ # @param practice_id [Integer, nil] プラクティスIDで絞り込み
11
+ # @param company_id [Integer, nil] 企業IDで絞り込み
12
+ # @param limit [Integer, nil] 取得件数
13
+ # @param page [Integer, nil] ページ番号
14
+ def list(user_id: nil, practice_id: nil, company_id: nil, limit: nil, page: nil)
15
+ params = {}
16
+ params[:user_id] = user_id if user_id
17
+ params[:practice_id] = practice_id if practice_id
18
+ params[:company_id] = company_id if company_id
19
+ params[:limit] = limit if limit
20
+ params[:page] = page if page
21
+ get('/api/reports', params)
22
+ end
23
+
24
+ # 日報詳細を取得(コメント・プラクティス付き)
25
+ # @param id [Integer] 日報ID
26
+ def find(id)
27
+ get("/api/reports/#{id}")
28
+ end
29
+
30
+ # 最近の日報を取得(直近20件)
31
+ def recent
32
+ get('/api/reports/recents')
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'base'
4
+
5
+ module FjordBootCamp
6
+ module Resources
7
+ class TraineeProgresses < Base
8
+ # 研修生の週次進捗を取得
9
+ # @param week_start [String, nil] 対象週の開始日 (例: "2026-03-23")。省略時は今週
10
+ # @param company_id [Integer, nil] 企業IDで絞り込み
11
+ def list(week_start: nil, company_id: nil)
12
+ params = {}
13
+ params[:week_start] = week_start if week_start
14
+ params[:company_id] = company_id if company_id
15
+ get('/api/trainee_progresses', params)
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'base'
4
+
5
+ module FjordBootCamp
6
+ module Resources
7
+ class Users < Base
8
+ # ユーザー一覧を取得
9
+ # @param target [String, nil] フィルタ (student, trainee, student_and_trainee, mentor, adviser, graduate等)
10
+ # @param company_id [Integer, nil] 企業IDで絞り込み
11
+ # @param tag [String, nil] タグで絞り込み
12
+ # @param page [Integer, nil] ページ番号
13
+ def list(target: nil, company_id: nil, tag: nil, page: nil)
14
+ params = {}
15
+ params[:target] = target if target
16
+ params[:company_id] = company_id if company_id
17
+ params[:tag] = tag if tag
18
+ params[:page] = page if page
19
+ get('/api/users', params)
20
+ end
21
+
22
+ # ユーザー詳細を取得
23
+ # @param id [Integer] ユーザーID
24
+ def find(id)
25
+ get("/api/users/#{id}")
26
+ end
27
+
28
+ # 研修生一覧を取得
29
+ def trainees
30
+ list(target: 'trainee')
31
+ end
32
+
33
+ # メンター一覧を取得
34
+ def mentors
35
+ list(target: 'mentor')
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module FjordBootCamp
4
+ VERSION = '0.1.0'
5
+ end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'fjord_boot_camp/version'
4
+ require 'fjord_boot_camp/configuration'
5
+ require 'fjord_boot_camp/client'
6
+ require 'fjord_boot_camp/resources/reports'
7
+ require 'fjord_boot_camp/resources/users'
8
+ require 'fjord_boot_camp/resources/practices'
9
+ require 'fjord_boot_camp/resources/trainee_progresses'
10
+
11
+ module FjordBootCamp
12
+ class Error < StandardError; end
13
+ class AuthenticationError < Error; end
14
+ class NotFoundError < Error; end
15
+ class ApiError < Error; end
16
+
17
+ class << self
18
+ attr_accessor :configuration
19
+
20
+ def configure
21
+ self.configuration ||= Configuration.new
22
+ yield(configuration)
23
+ end
24
+
25
+ def client
26
+ @client = nil if @client&.configuration != configuration
27
+ @client ||= Client.new(configuration)
28
+ end
29
+
30
+ def reset!
31
+ @client = nil
32
+ self.configuration = nil
33
+ end
34
+ end
35
+ end
metadata ADDED
@@ -0,0 +1,172 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: fjord_boot_camp
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - komagata
8
+ bindir: exe
9
+ cert_chain: []
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
+ dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: faraday
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - ">="
17
+ - !ruby/object:Gem::Version
18
+ version: '1.0'
19
+ - - "<"
20
+ - !ruby/object:Gem::Version
21
+ version: '3.0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ requirements:
26
+ - - ">="
27
+ - !ruby/object:Gem::Version
28
+ version: '1.0'
29
+ - - "<"
30
+ - !ruby/object:Gem::Version
31
+ version: '3.0'
32
+ - !ruby/object:Gem::Dependency
33
+ name: thor
34
+ requirement: !ruby/object:Gem::Requirement
35
+ requirements:
36
+ - - "~>"
37
+ - !ruby/object:Gem::Version
38
+ version: '1.0'
39
+ type: :runtime
40
+ prerelease: false
41
+ version_requirements: !ruby/object:Gem::Requirement
42
+ requirements:
43
+ - - "~>"
44
+ - !ruby/object:Gem::Version
45
+ version: '1.0'
46
+ - !ruby/object:Gem::Dependency
47
+ name: minitest
48
+ requirement: !ruby/object:Gem::Requirement
49
+ requirements:
50
+ - - "~>"
51
+ - !ruby/object:Gem::Version
52
+ version: '5.0'
53
+ type: :development
54
+ prerelease: false
55
+ version_requirements: !ruby/object:Gem::Requirement
56
+ requirements:
57
+ - - "~>"
58
+ - !ruby/object:Gem::Version
59
+ version: '5.0'
60
+ - !ruby/object:Gem::Dependency
61
+ name: rake
62
+ requirement: !ruby/object:Gem::Requirement
63
+ requirements:
64
+ - - "~>"
65
+ - !ruby/object:Gem::Version
66
+ version: '13.0'
67
+ type: :development
68
+ prerelease: false
69
+ version_requirements: !ruby/object:Gem::Requirement
70
+ requirements:
71
+ - - "~>"
72
+ - !ruby/object:Gem::Version
73
+ version: '13.0'
74
+ - !ruby/object:Gem::Dependency
75
+ name: rubocop
76
+ requirement: !ruby/object:Gem::Requirement
77
+ requirements:
78
+ - - "~>"
79
+ - !ruby/object:Gem::Version
80
+ version: '1.0'
81
+ type: :development
82
+ prerelease: false
83
+ version_requirements: !ruby/object:Gem::Requirement
84
+ requirements:
85
+ - - "~>"
86
+ - !ruby/object:Gem::Version
87
+ version: '1.0'
88
+ - !ruby/object:Gem::Dependency
89
+ name: rubocop-minitest
90
+ requirement: !ruby/object:Gem::Requirement
91
+ requirements:
92
+ - - "~>"
93
+ - !ruby/object:Gem::Version
94
+ version: '0.36'
95
+ type: :development
96
+ prerelease: false
97
+ version_requirements: !ruby/object:Gem::Requirement
98
+ requirements:
99
+ - - "~>"
100
+ - !ruby/object:Gem::Version
101
+ version: '0.36'
102
+ - !ruby/object:Gem::Dependency
103
+ name: webmock
104
+ requirement: !ruby/object:Gem::Requirement
105
+ requirements:
106
+ - - "~>"
107
+ - !ruby/object:Gem::Version
108
+ version: '3.0'
109
+ type: :development
110
+ prerelease: false
111
+ version_requirements: !ruby/object:Gem::Requirement
112
+ requirements:
113
+ - - "~>"
114
+ - !ruby/object:Gem::Version
115
+ version: '3.0'
116
+ description: A Ruby gem to interact with the FJORD BOOT CAMP API. Provides both a
117
+ library and CLI for accessing reports, users, practices, and trainee progress data.
118
+ email:
119
+ - komagata@gmail.com
120
+ executables:
121
+ - fjord_boot_camp
122
+ extensions: []
123
+ extra_rdoc_files: []
124
+ files:
125
+ - ".github/workflows/ci.yml"
126
+ - ".github/workflows/release.yml"
127
+ - ".gitignore"
128
+ - ".mise.toml"
129
+ - ".rubocop.yml"
130
+ - Gemfile
131
+ - Gemfile.lock
132
+ - README.md
133
+ - Rakefile
134
+ - bin/console
135
+ - bin/setup
136
+ - exe/fjord_boot_camp
137
+ - fjord_boot_camp.gemspec
138
+ - lib/fjord_boot_camp.rb
139
+ - lib/fjord_boot_camp/cli.rb
140
+ - lib/fjord_boot_camp/client.rb
141
+ - lib/fjord_boot_camp/configuration.rb
142
+ - lib/fjord_boot_camp/resources/base.rb
143
+ - lib/fjord_boot_camp/resources/practices.rb
144
+ - lib/fjord_boot_camp/resources/reports.rb
145
+ - lib/fjord_boot_camp/resources/trainee_progresses.rb
146
+ - lib/fjord_boot_camp/resources/users.rb
147
+ - lib/fjord_boot_camp/version.rb
148
+ homepage: https://github.com/fjordllc/fjord_boot_camp
149
+ licenses:
150
+ - MIT
151
+ metadata:
152
+ homepage_uri: https://github.com/fjordllc/fjord_boot_camp
153
+ source_code_uri: https://github.com/fjordllc/fjord_boot_camp
154
+ rubygems_mfa_required: 'true'
155
+ rdoc_options: []
156
+ require_paths:
157
+ - lib
158
+ required_ruby_version: !ruby/object:Gem::Requirement
159
+ requirements:
160
+ - - ">="
161
+ - !ruby/object:Gem::Version
162
+ version: 3.1.0
163
+ required_rubygems_version: !ruby/object:Gem::Requirement
164
+ requirements:
165
+ - - ">="
166
+ - !ruby/object:Gem::Version
167
+ version: '0'
168
+ requirements: []
169
+ rubygems_version: 3.6.7
170
+ specification_version: 4
171
+ summary: Ruby client for FJORD BOOT CAMP API
172
+ test_files: []