kalshi 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/.release-please-config.json +28 -0
- data/.release-please-manifest.json +3 -0
- data/CHANGELOG.md +46 -0
- data/Rakefile +16 -0
- data/Readme.adoc +231 -0
- data/ci/build_image.sh +248 -0
- data/ci/publish-gem.sh +91 -0
- data/lib/kalshi/api_client.rb +48 -0
- data/lib/kalshi/client.rb +85 -0
- data/lib/kalshi/contract.rb +34 -0
- data/lib/kalshi/endpoint.rb +32 -0
- data/lib/kalshi/events/client.rb +30 -0
- data/lib/kalshi/events/list.rb +37 -0
- data/lib/kalshi/events/multivariate.rb +28 -0
- data/lib/kalshi/listable.rb +31 -0
- data/lib/kalshi/market/client.rb +40 -0
- data/lib/kalshi/market/markets.rb +36 -0
- data/lib/kalshi/market/orderbook.rb +16 -0
- data/lib/kalshi/market/series.rb +14 -0
- data/lib/kalshi/market/series_list.rb +29 -0
- data/lib/kalshi/market/trades.rb +29 -0
- data/lib/kalshi/operations/.gitkeep +0 -0
- data/lib/kalshi/search/client.rb +18 -0
- data/lib/kalshi/search/series_tags.rb +14 -0
- data/lib/kalshi/search/sports_filters.rb +14 -0
- data/lib/kalshi/series/client.rb +18 -0
- data/lib/kalshi/series/event_candlesticks.rb +34 -0
- data/lib/kalshi/series/forecast_percentile_history.rb +36 -0
- data/lib/kalshi/series/market_candlesticks.rb +28 -0
- data/lib/kalshi/version.rb +10 -0
- data/lib/kalshi.rb +35 -0
- data/sig/kalshi/rb.rbs +6 -0
- metadata +214 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 9629748b750216c1b4e3bbd22458dd85dd0fea94c9e64a5b624aadb2e1e04112
|
|
4
|
+
data.tar.gz: d9c999475615530d0e7a9238cff6f083df704eaac1b55ec14f298dd9e7e51153
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: bca603a43360c6e46b43bbdea8e24f45f4c0fe06a32be5fbcc38b86259c3b65fdc1d70b9b958ac711e8811f6f001e5234271502078ff9a789f9bb475848a319b
|
|
7
|
+
data.tar.gz: f2cac3252e09ccf560a9a9553e95572c420352414f64422bed7bc1e7b1cc4131e131473ac198c43158d934bad361a5ecd08f5f9eba8e15922dc257d74c3d4865
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
{
|
|
2
|
+
"packages": {
|
|
3
|
+
".": {
|
|
4
|
+
"changelog-path": "CHANGELOG.md",
|
|
5
|
+
"release-type": "simple",
|
|
6
|
+
"bump-minor-pre-major": true,
|
|
7
|
+
"bump-patch-for-minor-pre-major": true,
|
|
8
|
+
"draft": false,
|
|
9
|
+
"prerelease": false,
|
|
10
|
+
"version-file": ".version.txt",
|
|
11
|
+
"extra-files": [
|
|
12
|
+
{
|
|
13
|
+
"type": "generic",
|
|
14
|
+
"path": "lib/kalshi/version.rb"
|
|
15
|
+
}
|
|
16
|
+
],
|
|
17
|
+
"exclude-paths": [
|
|
18
|
+
".release-please-manifest.json",
|
|
19
|
+
".version.txt",
|
|
20
|
+
"lib/kalshi/version.rb",
|
|
21
|
+
".rubocop.yml",
|
|
22
|
+
".overcommit.yml",
|
|
23
|
+
"coverage/coverage.json"
|
|
24
|
+
]
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
"$schema": "https://raw.githubusercontent.com/googleapis/release-please/main/schemas/config.json"
|
|
28
|
+
}
|
data/CHANGELOG.md
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## [0.1.0](https://github.com/rubyists/kalshi/compare/v0.0.5...v0.1.0) (2026-01-05)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### ⚠ BREAKING CHANGES
|
|
7
|
+
|
|
8
|
+
* corrects gemspec source code uri ([#15](https://github.com/rubyists/kalshi/issues/15))
|
|
9
|
+
|
|
10
|
+
### Bug Fixes
|
|
11
|
+
|
|
12
|
+
* corrects gemspec source code uri ([#15](https://github.com/rubyists/kalshi/issues/15)) ([2a69255](https://github.com/rubyists/kalshi/commit/2a69255fdca48bda599b19d5aa9649eca6effe34))
|
|
13
|
+
|
|
14
|
+
## [0.0.5](https://github.com/rubyists/kalshi/compare/v0.0.4...v0.0.5) (2026-01-05)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
### Features
|
|
18
|
+
|
|
19
|
+
* adds series event lookup, and events/ endpoints ([#13](https://github.com/rubyists/kalshi/issues/13)) ([a9fcb72](https://github.com/rubyists/kalshi/commit/a9fcb72724e5e1a51be8671d96bf58514d14904c))
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
### Bug Fixes
|
|
23
|
+
|
|
24
|
+
* correct path to filter_by_sport, adds ApiClient helper ([#8](https://github.com/rubyists/kalshi/issues/8)) ([a608fbe](https://github.com/rubyists/kalshi/commit/a608fbe0e88ad2678dc3ba84ba8198121e1d29aa))
|
|
25
|
+
* renamed #get_without_prefix to #get_url for clarity ([#11](https://github.com/rubyists/kalshi/issues/11)) ([a641a5f](https://github.com/rubyists/kalshi/commit/a641a5f187ba2d42d1e4637fe599e63ea34fd4d8))
|
|
26
|
+
|
|
27
|
+
## [0.0.4](https://github.com/rubyists/kalshi/compare/v0.0.3...v0.0.4) (2026-01-05)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
### Features
|
|
31
|
+
|
|
32
|
+
* adds search endpoints ([#6](https://github.com/rubyists/kalshi/issues/6)) ([d29aa7d](https://github.com/rubyists/kalshi/commit/d29aa7d01d4ac83c5eec9303afb03fe1e47ec056))
|
|
33
|
+
|
|
34
|
+
## [0.0.3](https://github.com/rubyists/kalshi/compare/v0.0.2...v0.0.3) (2026-01-05)
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
### Features
|
|
38
|
+
|
|
39
|
+
* adds all market/ endpoints ([#4](https://github.com/rubyists/kalshi/issues/4)) ([b7bd5a7](https://github.com/rubyists/kalshi/commit/b7bd5a7273db51ac829cbb384a684918b08edac1))
|
|
40
|
+
|
|
41
|
+
## [0.0.2](https://github.com/rubyists/kalshi/compare/v0.0.1...v0.0.2) (2026-01-04)
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
### Features
|
|
45
|
+
|
|
46
|
+
* initial structure ([e102a98](https://github.com/rubyists/kalshi/commit/e102a982f8e3ad9e4ee39b31f32970d3bdee0414))
|
data/Rakefile
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'bundler/gem_tasks'
|
|
4
|
+
require 'rake/testtask'
|
|
5
|
+
|
|
6
|
+
Rake::TestTask.new do |t|
|
|
7
|
+
t.libs << 'test'
|
|
8
|
+
t.test_files = FileList['test/**/*_test.rb']
|
|
9
|
+
t.ruby_opts = %w[-rhelper]
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
require 'rubocop/rake_task'
|
|
13
|
+
|
|
14
|
+
RuboCop::RakeTask.new
|
|
15
|
+
|
|
16
|
+
task default: %i[rubocop test]
|
data/Readme.adoc
ADDED
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
= Kalshi
|
|
2
|
+
:toc: macro
|
|
3
|
+
:icons: font
|
|
4
|
+
|
|
5
|
+
Ruby client for the Kalshi API.
|
|
6
|
+
|
|
7
|
+
== Installation
|
|
8
|
+
|
|
9
|
+
Install the gem and add to the application's Gemfile by executing:
|
|
10
|
+
|
|
11
|
+
[source,bash]
|
|
12
|
+
----
|
|
13
|
+
bundle add kalshi
|
|
14
|
+
----
|
|
15
|
+
|
|
16
|
+
If bundler is not being used to manage dependencies, install the gem by executing:
|
|
17
|
+
|
|
18
|
+
[source,bash]
|
|
19
|
+
----
|
|
20
|
+
gem install kalshi
|
|
21
|
+
----
|
|
22
|
+
|
|
23
|
+
== Usage
|
|
24
|
+
|
|
25
|
+
=== Configuration
|
|
26
|
+
|
|
27
|
+
Configure the gem with your API key (optional for public endpoints). You can set it via the `KALSHI_API_KEY` environment variable or configure it explicitly:
|
|
28
|
+
|
|
29
|
+
[source,ruby]
|
|
30
|
+
----
|
|
31
|
+
Rubyists::Kalshi.configure do |config|
|
|
32
|
+
config.api_key = 'your_api_key'
|
|
33
|
+
config.base_url = 'https://api.elections.kalshi.com/trade-api/v2' # Default
|
|
34
|
+
end
|
|
35
|
+
----
|
|
36
|
+
|
|
37
|
+
=== Client
|
|
38
|
+
|
|
39
|
+
Initialize the client:
|
|
40
|
+
|
|
41
|
+
[source,ruby]
|
|
42
|
+
----
|
|
43
|
+
client = Rubyists::Kalshi.client
|
|
44
|
+
----
|
|
45
|
+
|
|
46
|
+
=== Market
|
|
47
|
+
|
|
48
|
+
Access Market endpoints via the `market` namespace.
|
|
49
|
+
|
|
50
|
+
==== Series List
|
|
51
|
+
|
|
52
|
+
https://docs.kalshi.com/api-reference/market/get-series-list[API Reference]
|
|
53
|
+
|
|
54
|
+
List series with optional filtering:
|
|
55
|
+
|
|
56
|
+
[source,ruby]
|
|
57
|
+
----
|
|
58
|
+
# List series with default filter
|
|
59
|
+
series_list = client.market.series_list.list
|
|
60
|
+
|
|
61
|
+
# List series with custom filter
|
|
62
|
+
series_list = client.market.series_list.list(category: 'Sports', tags: 'Football')
|
|
63
|
+
----
|
|
64
|
+
|
|
65
|
+
==== Series
|
|
66
|
+
|
|
67
|
+
https://docs.kalshi.com/api-reference/market/get-series[API Reference]
|
|
68
|
+
|
|
69
|
+
Get a specific series by ticker:
|
|
70
|
+
|
|
71
|
+
[source,ruby]
|
|
72
|
+
----
|
|
73
|
+
series = client.market.series.fetch('KX-SERIES')
|
|
74
|
+
----
|
|
75
|
+
|
|
76
|
+
==== Markets
|
|
77
|
+
|
|
78
|
+
https://docs.kalshi.com/api-reference/market/get-markets[API Reference]
|
|
79
|
+
|
|
80
|
+
List markets with optional filtering:
|
|
81
|
+
|
|
82
|
+
[source,ruby]
|
|
83
|
+
----
|
|
84
|
+
# List markets with default filter
|
|
85
|
+
markets = client.market.markets.list
|
|
86
|
+
|
|
87
|
+
# List markets with custom filter
|
|
88
|
+
markets = client.market.markets.list(status: 'open', limit: 10)
|
|
89
|
+
----
|
|
90
|
+
|
|
91
|
+
Get a specific market by ticker:
|
|
92
|
+
|
|
93
|
+
[source,ruby]
|
|
94
|
+
----
|
|
95
|
+
market = client.market.markets.fetch('KX-MARKET')
|
|
96
|
+
----
|
|
97
|
+
|
|
98
|
+
==== Orderbook
|
|
99
|
+
|
|
100
|
+
https://docs.kalshi.com/api-reference/market/get-market-orderbook[API Reference]
|
|
101
|
+
|
|
102
|
+
Get the orderbook for a market:
|
|
103
|
+
|
|
104
|
+
[source,ruby]
|
|
105
|
+
----
|
|
106
|
+
# Get full orderbook
|
|
107
|
+
orderbook = client.market.orderbook.fetch('KX-MARKET')
|
|
108
|
+
|
|
109
|
+
# Get orderbook with specific depth
|
|
110
|
+
orderbook = client.market.orderbook.fetch('KX-MARKET', depth: 10)
|
|
111
|
+
----
|
|
112
|
+
|
|
113
|
+
==== Trades
|
|
114
|
+
|
|
115
|
+
https://docs.kalshi.com/api-reference/market/get-trades[API Reference]
|
|
116
|
+
|
|
117
|
+
List trades with optional filtering:
|
|
118
|
+
|
|
119
|
+
[source,ruby]
|
|
120
|
+
----
|
|
121
|
+
# List trades with default filter
|
|
122
|
+
trades = client.market.trades.list
|
|
123
|
+
|
|
124
|
+
# List trades with custom filter
|
|
125
|
+
trades = client.market.trades.list(ticker: 'KX-MARKET', limit: 100)
|
|
126
|
+
----
|
|
127
|
+
|
|
128
|
+
==== Candlesticks
|
|
129
|
+
|
|
130
|
+
https://docs.kalshi.com/api-reference/market/get-market-candlesticks[API Reference]
|
|
131
|
+
|
|
132
|
+
Get candlesticks for a market:
|
|
133
|
+
|
|
134
|
+
[source,ruby]
|
|
135
|
+
----
|
|
136
|
+
candlesticks = client.market.candlesticks.fetch(
|
|
137
|
+
series_ticker: 'KX-SERIES',
|
|
138
|
+
ticker: 'KX-MARKET',
|
|
139
|
+
start_ts: 1600000000,
|
|
140
|
+
end_ts: 1600000060,
|
|
141
|
+
period_interval: 1
|
|
142
|
+
)
|
|
143
|
+
----
|
|
144
|
+
|
|
145
|
+
https://docs.kalshi.com/api-reference/market/batch-get-market-candlesticks[API Reference]
|
|
146
|
+
|
|
147
|
+
Get candlesticks for multiple markets:
|
|
148
|
+
|
|
149
|
+
[source,ruby]
|
|
150
|
+
----
|
|
151
|
+
candlesticks = client.market.candlesticks.batch(
|
|
152
|
+
tickers: ['KX-MARKET-1', 'KX-MARKET-2'],
|
|
153
|
+
series_ticker: 'KX-SERIES',
|
|
154
|
+
start_ts: 1600000000,
|
|
155
|
+
end_ts: 1600000060,
|
|
156
|
+
period_interval: 1
|
|
157
|
+
)
|
|
158
|
+
----
|
|
159
|
+
|
|
160
|
+
=== Search
|
|
161
|
+
|
|
162
|
+
Access Search endpoints via the `search` namespace.
|
|
163
|
+
|
|
164
|
+
==== Tags by Category
|
|
165
|
+
|
|
166
|
+
https://docs.kalshi.com/api-reference/search/get-tags-for-series-categories[API Reference]
|
|
167
|
+
|
|
168
|
+
Get tags organized by series categories:
|
|
169
|
+
|
|
170
|
+
[source,ruby]
|
|
171
|
+
----
|
|
172
|
+
tags = client.search.tags_by_categories
|
|
173
|
+
----
|
|
174
|
+
|
|
175
|
+
==== Filters by Sport
|
|
176
|
+
|
|
177
|
+
https://docs.kalshi.com/api-reference/search/get-filters-for-sports[API Reference]
|
|
178
|
+
|
|
179
|
+
Get filters organized by sport:
|
|
180
|
+
|
|
181
|
+
[source,ruby]
|
|
182
|
+
----
|
|
183
|
+
filters = client.search.filters_by_sport
|
|
184
|
+
----
|
|
185
|
+
|
|
186
|
+
=== WebSocket Client
|
|
187
|
+
|
|
188
|
+
A raw WebSocket client is included in `bin/wss-raw` for testing connection and subscription.
|
|
189
|
+
|
|
190
|
+
IMPORTANT: This script requires the https://www.passwordstore.org/[`pass`] password manager to be installed and configured. It expects the API key on the first line and the PEM private key starting from the third line of the pass entry.
|
|
191
|
+
|
|
192
|
+
NOTE: If you aren't using `pass` yet, you should! It works on Windows, Android, macOS, Linux, and everything else. It is the standard unix password manager.
|
|
193
|
+
|
|
194
|
+
[source,bash]
|
|
195
|
+
----
|
|
196
|
+
# Set up your pass entry at the default path
|
|
197
|
+
printf '%s\n\n%s\n' "$API_KEY" "$PEM_PRIVATE_KEY" | pass insert -m kalshi/api/initial-dev-ro
|
|
198
|
+
|
|
199
|
+
# Default pass path: kalshi/api/initial-dev-ro
|
|
200
|
+
./bin/wss-raw
|
|
201
|
+
|
|
202
|
+
# Set up your pass entry at a custom path
|
|
203
|
+
printf '%s\n\n%s\n' "$API_KEY" "$PEM_PRIVATE_KEY" | pass insert -m my/custom/path
|
|
204
|
+
|
|
205
|
+
# Override pass path
|
|
206
|
+
KALSHI_PASS_PATH=my/custom/path ./bin/wss-raw
|
|
207
|
+
----
|
|
208
|
+
|
|
209
|
+
[IMPORTANT]
|
|
210
|
+
.The "$PEM_PRIVATE_KEY" must include the BEGIN and END lines
|
|
211
|
+
====
|
|
212
|
+
For example:
|
|
213
|
+
|
|
214
|
+
[source]
|
|
215
|
+
----
|
|
216
|
+
-----BEGIN RSA PRIVATE KEY-----
|
|
217
|
+
MIIEvQIBADANBgkqhkiG9w0BAQEFAASC...
|
|
218
|
+
-----END RSA PRIVATE KEY-----
|
|
219
|
+
----
|
|
220
|
+
====
|
|
221
|
+
|
|
222
|
+
|
|
223
|
+
== Development
|
|
224
|
+
|
|
225
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
|
226
|
+
|
|
227
|
+
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
|
228
|
+
|
|
229
|
+
== Contributing
|
|
230
|
+
|
|
231
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/rubyists/kalshi.
|
data/ci/build_image.sh
ADDED
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
|
|
3
|
+
if readlink -f . >/dev/null 2>&1 # {{{ makes readlink work on mac
|
|
4
|
+
then
|
|
5
|
+
readlink=readlink
|
|
6
|
+
else
|
|
7
|
+
if greadlink -f . >/dev/null 2>&1
|
|
8
|
+
then
|
|
9
|
+
readlink=greadlink
|
|
10
|
+
else
|
|
11
|
+
printf "You must install greadlink to use this (brew install coreutils)\n" >&2
|
|
12
|
+
fi
|
|
13
|
+
fi # }}}
|
|
14
|
+
|
|
15
|
+
# Set here to the full path to this script
|
|
16
|
+
me=${BASH_SOURCE[0]}
|
|
17
|
+
[ -L "$me" ] && me=$($readlink -f "$me")
|
|
18
|
+
here=$(cd "$(dirname "$me")" && pwd)
|
|
19
|
+
just_me=$(basename "$me")
|
|
20
|
+
|
|
21
|
+
repo_top=$(git rev-parse --show-toplevel)
|
|
22
|
+
cd "$repo_top" || {
|
|
23
|
+
printf "Could not cd to %s\n" "$repo_top" >&2
|
|
24
|
+
exit 1
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
base_dir=$(basename "$(pwd)")
|
|
28
|
+
: "${BUILD_CONTEXT:=$(pwd)}"
|
|
29
|
+
: "${IMAGE_NAME:=$base_dir}"
|
|
30
|
+
: "${LICENSE:=MIT}"
|
|
31
|
+
: "${APP_VERSION:=$(< "$here"/../.version.txt)}"
|
|
32
|
+
: "${REGISTRY:=ghcr.io}"
|
|
33
|
+
: "${REGISTRY_TOKEN:=$GITHUB_TOKEN}"
|
|
34
|
+
|
|
35
|
+
usage() { # {{{
|
|
36
|
+
cat <<-EOT
|
|
37
|
+
Build an image, optionally pushing it to the registry
|
|
38
|
+
|
|
39
|
+
Usage: $0 <options> <image_tag>
|
|
40
|
+
Options:
|
|
41
|
+
-c CONTAINERFILE Path to the containerfile (default: ./oci/Containerfile)
|
|
42
|
+
-C CONTEXT Build context (default: $BUILD_CONTEXT)
|
|
43
|
+
-i NAME Name of the image (default: $IMAGE_NAME)
|
|
44
|
+
-l LICENSE License of the image (default: $LICENSE)
|
|
45
|
+
-r REGISTRY Registry to push the image to when -p is given (default: $REGISTRY)
|
|
46
|
+
-p Push the image to the registry
|
|
47
|
+
-h Show help / usage
|
|
48
|
+
EOT
|
|
49
|
+
} # }}}
|
|
50
|
+
|
|
51
|
+
die() { # {{{
|
|
52
|
+
local -i code
|
|
53
|
+
code=$1
|
|
54
|
+
shift
|
|
55
|
+
error "$*"
|
|
56
|
+
printf "\n" >&2
|
|
57
|
+
usage >&2
|
|
58
|
+
# shellcheck disable=SC2086
|
|
59
|
+
exit $code
|
|
60
|
+
} # }}}
|
|
61
|
+
|
|
62
|
+
## Logging functions # {{{
|
|
63
|
+
log() { # {{{
|
|
64
|
+
printf "%s [%s] <%s> %s\n" "$(date '+%Y-%m-%d %H:%M:%S.%6N')" "$$" "${just_me:-$0}" "$*"
|
|
65
|
+
} # }}}
|
|
66
|
+
|
|
67
|
+
debug() { # {{{
|
|
68
|
+
[ $verbose -lt 2 ] && return 0
|
|
69
|
+
# shellcheck disable=SC2059
|
|
70
|
+
log_line=$(printf "$@")
|
|
71
|
+
log "[DEBUG] $log_line" >&2
|
|
72
|
+
} # }}}
|
|
73
|
+
|
|
74
|
+
warn() { # {{{
|
|
75
|
+
# shellcheck disable=SC2059
|
|
76
|
+
log_line=$(printf "$@")
|
|
77
|
+
log "[WARN] $log_line" >&2
|
|
78
|
+
} # }}}
|
|
79
|
+
|
|
80
|
+
error() { # {{{
|
|
81
|
+
# shellcheck disable=SC2059
|
|
82
|
+
log_line=$(printf "$@")
|
|
83
|
+
log "[ERROR] $log_line" >&2
|
|
84
|
+
} # }}}
|
|
85
|
+
|
|
86
|
+
info() { # {{{
|
|
87
|
+
[ $verbose -lt 1 ] && return 0
|
|
88
|
+
# shellcheck disable=SC2059
|
|
89
|
+
log_line=$(printf "$@")
|
|
90
|
+
log "[INFO] $log_line" >&2
|
|
91
|
+
} # }}}
|
|
92
|
+
# }}}
|
|
93
|
+
|
|
94
|
+
push=0
|
|
95
|
+
verbose=0
|
|
96
|
+
while getopts :hpvc:C:i:l:r: opt # {{{
|
|
97
|
+
do
|
|
98
|
+
case $opt in
|
|
99
|
+
c)
|
|
100
|
+
CONTAINERFILE=$OPTARG
|
|
101
|
+
;;
|
|
102
|
+
C)
|
|
103
|
+
BUILD_CONTEXT=$OPTARG
|
|
104
|
+
;;
|
|
105
|
+
i)
|
|
106
|
+
IMAGE_NAME=$OPTARG
|
|
107
|
+
;;
|
|
108
|
+
l)
|
|
109
|
+
LICENSE=$OPTARG
|
|
110
|
+
;;
|
|
111
|
+
r)
|
|
112
|
+
REGISTRY=$OPTARG
|
|
113
|
+
;;
|
|
114
|
+
p)
|
|
115
|
+
push=1
|
|
116
|
+
;;
|
|
117
|
+
v)
|
|
118
|
+
verbose=$((verbose + 1))
|
|
119
|
+
;;
|
|
120
|
+
h)
|
|
121
|
+
usage
|
|
122
|
+
exit
|
|
123
|
+
;;
|
|
124
|
+
:)
|
|
125
|
+
printf "Option %s requires an argument\n" "$OPTARG" >&2
|
|
126
|
+
usage >&2
|
|
127
|
+
exit 28
|
|
128
|
+
;;
|
|
129
|
+
?)
|
|
130
|
+
printf "Invalid option '%s'\n" "$OPTARG" >&2
|
|
131
|
+
usage >&2
|
|
132
|
+
exit 27
|
|
133
|
+
;;
|
|
134
|
+
esac
|
|
135
|
+
done # }}}
|
|
136
|
+
shift $((OPTIND-1))
|
|
137
|
+
|
|
138
|
+
tag=$1
|
|
139
|
+
[ -z "$tag" ] && die 1 "Missing image tag"
|
|
140
|
+
shift
|
|
141
|
+
|
|
142
|
+
# Check for extra argument
|
|
143
|
+
if [ $# -gt 0 ]; then
|
|
144
|
+
# If we have the special argument '--' we shift it away, otherwise we die
|
|
145
|
+
[ "$1" != '--' ] && die 2 "Too many arguments"
|
|
146
|
+
# Once this is shifted away, the rest of the arguments are passed to the build command, below
|
|
147
|
+
shift
|
|
148
|
+
fi
|
|
149
|
+
|
|
150
|
+
if [ -z "$CONTAINERFILE" ]; then
|
|
151
|
+
printf "No containerfile specified, looking for default locations\n"
|
|
152
|
+
for containerfile in Containerfile Dockerfile
|
|
153
|
+
do
|
|
154
|
+
if [ -f ./oci/"$containerfile" ]; then
|
|
155
|
+
debug "Found ./oci/%s\n" "$containerfile"
|
|
156
|
+
containerfile=./oci/"$containerfile"
|
|
157
|
+
break
|
|
158
|
+
fi
|
|
159
|
+
if [ -f "$containerfile" ]; then
|
|
160
|
+
debug "Found %s\n" "$containerfile"
|
|
161
|
+
break
|
|
162
|
+
fi
|
|
163
|
+
done
|
|
164
|
+
else
|
|
165
|
+
[ -f "$CONTAINERFILE" ] || die 3 "Containerfile '$CONTAINERFILE' not found"
|
|
166
|
+
debug "Using containerfile %s\n" "$CONTAINERFILE"
|
|
167
|
+
containerfile=$CONTAINERFILE
|
|
168
|
+
fi
|
|
169
|
+
|
|
170
|
+
[ -f "$containerfile" ] || die 4 "No containerfile found"
|
|
171
|
+
|
|
172
|
+
[ -d "$BUILD_CONTEXT" ] || die 5 "Build context '$BUILD_CONTEXT' not found"
|
|
173
|
+
|
|
174
|
+
debug 'Building image from %s in in %s\n' "$containerfile" "$here"
|
|
175
|
+
# Build the image
|
|
176
|
+
if command -v podman 2>/dev/null
|
|
177
|
+
then
|
|
178
|
+
runtime=podman
|
|
179
|
+
elif command -v docker 2>/dev/null
|
|
180
|
+
then
|
|
181
|
+
runtime=docker
|
|
182
|
+
else
|
|
183
|
+
die 6 "No container runtime found"
|
|
184
|
+
fi
|
|
185
|
+
|
|
186
|
+
revision=$(git rev-parse HEAD)
|
|
187
|
+
shortref=$(git rev-parse --short "$revision")
|
|
188
|
+
repo_url=$(git remote get-url origin)
|
|
189
|
+
if [ -z "$repo_url" ]
|
|
190
|
+
then
|
|
191
|
+
die 7 "No remote found"
|
|
192
|
+
fi
|
|
193
|
+
if [[ $repo_url == *github.com/* ]]
|
|
194
|
+
then
|
|
195
|
+
owner_and_repo=${repo_url#*github.com/}
|
|
196
|
+
else
|
|
197
|
+
owner_and_repo=${repo_url##*:}
|
|
198
|
+
fi
|
|
199
|
+
# Get rid of the trailing .git
|
|
200
|
+
service=$(basename "$owner_and_repo" .git)
|
|
201
|
+
owner=$(dirname "$owner_and_repo")
|
|
202
|
+
|
|
203
|
+
full_tag=$IMAGE_NAME:$tag
|
|
204
|
+
created=$(date --utc --iso-8601=seconds 2>/dev/null || gdate --utc --iso-8601=seconds)
|
|
205
|
+
# Pass any extra arguments to the build command ("$@" contains the rest of the arguments)
|
|
206
|
+
$runtime build --tag "$full_tag" "$@" \
|
|
207
|
+
--label org.opencontainers.image.created="$created" \
|
|
208
|
+
--label org.opencontainers.image.description="Image for $service" \
|
|
209
|
+
--label org.opencontainers.image.licenses="$LICENSE" \
|
|
210
|
+
--label org.opencontainers.image.revision="$revision" \
|
|
211
|
+
--label org.opencontainers.image.url="$repo_url" \
|
|
212
|
+
--label org.opencontainers.image.title="$IMAGE_NAME" \
|
|
213
|
+
--label org.opencontainers.image.source="Generated by ruby-automation's build_image.sh ($USER@$HOSTNAME)" \
|
|
214
|
+
--label org.opencontainers.image.version="$full_tag" \
|
|
215
|
+
--label shortref="$shortref" \
|
|
216
|
+
--build-arg APP_VERSION="$APP_VERSION" \
|
|
217
|
+
-f "$containerfile" "$BUILD_CONTEXT" || die 8 "Failed to build image"
|
|
218
|
+
|
|
219
|
+
[ $push -eq 1 ] || exit 0
|
|
220
|
+
if ! $runtime login --get-login "$REGISTRY" >/dev/null 2>/dev/null
|
|
221
|
+
then
|
|
222
|
+
printf "Not logged in to '%s', trying to login\n" "$REGISTRY" >&2
|
|
223
|
+
[ -z "$REGISTRY_TOKEN" ] && die 9 "No REGISTRY_TOKEN (nor GITHUB_TOKEN) set, cannot login"
|
|
224
|
+
printf "%s" "$REGISTRY_TOKEN" | $runtime login -u "$REGISTRY_TOKEN" --password-stdin "$REGISTRY" || die 10 "Failed to login to $REGISTRY"
|
|
225
|
+
fi
|
|
226
|
+
|
|
227
|
+
# Split 1.2.3 into 1.2.3, 1.2, 1. We want to tag our image with all 3 of these
|
|
228
|
+
mapfile -t tags < <(echo "$tag" | awk -F'.' 'NF==3{print; print $1"."$2; print $1; next} NF==2{print; print $1; next} {print}')
|
|
229
|
+
for t in "${tags[@]}"
|
|
230
|
+
do
|
|
231
|
+
new_tag=$IMAGE_NAME:$t
|
|
232
|
+
registry_image_name="$REGISTRY/$owner/$new_tag"
|
|
233
|
+
if [ "$runtime" = "podman" ]
|
|
234
|
+
then
|
|
235
|
+
if [ "$full_tag" != "$new_tag" ]
|
|
236
|
+
then
|
|
237
|
+
debug "Tagging %s as %s\n" "$full_tag" "$new_tag"
|
|
238
|
+
podman tag "$full_tag" "$new_tag" || die 11 "Failed to tag image $full_tag as $new_tag"
|
|
239
|
+
fi
|
|
240
|
+
podman push "$new_tag" "$registry_image_name" || die 12 "Failed to push image $new_tag to $registry_image_name"
|
|
241
|
+
else
|
|
242
|
+
debug "Tagging %s as %s\n" "$full_tag" "$registry_image_name"
|
|
243
|
+
docker tag "$full_tag" "$registry_image_name" || die 13 "Failed to tag image $full_tag as $registry_image_name"
|
|
244
|
+
docker push "$registry_image_name" || die 14 "Failed to push image $new_tag to $registry_image_name"
|
|
245
|
+
fi
|
|
246
|
+
done
|
|
247
|
+
|
|
248
|
+
# vim: set foldmethod=marker et ts=4 sts=4 sw=4 ft=bash :
|
data/ci/publish-gem.sh
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
|
|
3
|
+
if readlink -f . >/dev/null 2>&1 # {{{ makes readlink work on mac
|
|
4
|
+
then
|
|
5
|
+
readlink=readlink
|
|
6
|
+
else
|
|
7
|
+
if greadlink -f . >/dev/null 2>&1
|
|
8
|
+
then
|
|
9
|
+
readlink=greadlink
|
|
10
|
+
else
|
|
11
|
+
printf "You must install greadlink to use this (brew install coreutils)\n" >&2
|
|
12
|
+
fi
|
|
13
|
+
fi # }}}
|
|
14
|
+
|
|
15
|
+
# Set here to the full path to this script
|
|
16
|
+
me=${BASH_SOURCE[0]}
|
|
17
|
+
[ -L "$me" ] && me=$($readlink -f "$me")
|
|
18
|
+
here=$(cd "$(dirname "$me")" && pwd)
|
|
19
|
+
root=$(cd "$here/.." && pwd)
|
|
20
|
+
just_me=$(basename "$me")
|
|
21
|
+
|
|
22
|
+
: "${GEM_NAME:=kalshi}"
|
|
23
|
+
: "${GIT_ORG:=rubyists}"
|
|
24
|
+
|
|
25
|
+
GEM_HOST=$1
|
|
26
|
+
: "${GEM_HOST:=rubygems}"
|
|
27
|
+
|
|
28
|
+
case "$GEM_HOST" in
|
|
29
|
+
rubygems)
|
|
30
|
+
gem_key='rubygems'
|
|
31
|
+
gem_host='https://rubygems.org'
|
|
32
|
+
;;
|
|
33
|
+
github)
|
|
34
|
+
gem_key='github'
|
|
35
|
+
gem_host="https://rubygems.pkg.github.com/$GIT_ORG"
|
|
36
|
+
# Replace the gem host in the gemspec, so it allows pushing to the GitHub package registry
|
|
37
|
+
sed --in-place=.bak -e "s|https://rubygems.org|https://rubygems.pkg.github.com/$GIT_ORG|" "$here/../$GEM_NAME".gemspec
|
|
38
|
+
# Restore the original gemspec after the script finishes
|
|
39
|
+
trap 'mv -v "$here/../$GEM_NAME".gemspec.bak "$here/../$GEM_NAME".gemspec' EXIT
|
|
40
|
+
;;
|
|
41
|
+
*)
|
|
42
|
+
printf 'Unknown GEM_HOST: %s\n' "$GEM_HOST" >&2
|
|
43
|
+
exit 1
|
|
44
|
+
;;
|
|
45
|
+
esac
|
|
46
|
+
|
|
47
|
+
# We only want this part running in CI, with no ~/.gem dir
|
|
48
|
+
# For local testing, you should have a ~/.gem/credentials file with
|
|
49
|
+
# the keys you need to push to rubygems or github
|
|
50
|
+
if [ ! -d ~/.gem ]
|
|
51
|
+
then
|
|
52
|
+
if [ -z "$GEM_TOKEN" ]
|
|
53
|
+
then
|
|
54
|
+
printf 'No GEM_TOKEN provided, cannot publish\n' >&2
|
|
55
|
+
exit 1
|
|
56
|
+
fi
|
|
57
|
+
mkdir -p ~/.gem
|
|
58
|
+
printf '%s\n:%s: %s\n' '---' "$gem_key" "$GEM_TOKEN" > ~/.gem/credentials
|
|
59
|
+
chmod 600 ~/.gem/credentials
|
|
60
|
+
fi
|
|
61
|
+
|
|
62
|
+
bundle exec gem build
|
|
63
|
+
|
|
64
|
+
if [ -f "$here"/../.version.txt ]
|
|
65
|
+
then
|
|
66
|
+
version=$(<"$here"/../.version.txt)
|
|
67
|
+
else
|
|
68
|
+
version=$(git describe --tags --abbrev=0 | sed -e 's/^v//')
|
|
69
|
+
fi
|
|
70
|
+
|
|
71
|
+
if [ -z "$version" ]
|
|
72
|
+
then
|
|
73
|
+
gem="$(ls "$root"/"$GEM_NAME"-*.gem | tail -1)"
|
|
74
|
+
else
|
|
75
|
+
gem="$(printf '%s/%s-%s.gem' "$root" "$GEM_NAME" "$version")"
|
|
76
|
+
fi
|
|
77
|
+
|
|
78
|
+
if [ ! -f "$gem" ]
|
|
79
|
+
then
|
|
80
|
+
printf 'No gem file found: %s\n' "$gem" >&2
|
|
81
|
+
exit 1
|
|
82
|
+
fi
|
|
83
|
+
|
|
84
|
+
if [[ "${TRACE:-false}" == true || "${ACTIONS_STEP_DEBUG:-false}" == true ]]
|
|
85
|
+
then
|
|
86
|
+
printf "DEBUG: [%s] Building And Publishing %s to %s\n" "$just_me" "$gem" "$gem_host" >&2
|
|
87
|
+
fi
|
|
88
|
+
|
|
89
|
+
bundle exec gem push -k "$gem_key" --host "$gem_host" "$(basename "$gem")"
|
|
90
|
+
|
|
91
|
+
# vim: set foldmethod=marker et ts=4 sts=4 sw=4 ft=bash :
|