Ruby: define Google::Protobuf::VERSION in lib/google/protobuf/version.rb (#30762)
### Motivation
The `google-protobuf` gem does not expose its version in Ruby code. The version is only a string literal in `ruby/google-protobuf.gemspec`. Most gems define a `VERSION` constant in `lib/<gem>/version.rb`, and the gemspec reads it from there. This lets applications and tools read the version at runtime with `Google::Protobuf::VERSION`.
### Changes
- Add `ruby/lib/google/protobuf/version.rb`, which defines `Google::Protobuf::VERSION`.
- Make `ruby/google-protobuf.gemspec` read `s.version` from `Google::Protobuf::VERSION`.
- Require `google/protobuf/version` at the end of `ruby/lib/google/protobuf.rb`, so the constant is available after `require "google/protobuf"`.
- Add `//ruby/lib/google:protobuf/version.rb` to the `rb_bundle_fetch` sources in `WORKSPACE`, because the gemspec now requires the file.
### Required change to the internal version update tool
> [!IMPORTANT]
> The internal version update tool (the `update_versions` library that makes the "Updating version.json and repo version numbers" commits) must change after this PR merges.
The tool currently writes the Ruby version into `ruby/google-protobuf.gemspec`. The legacy `update_version.py` (removed in #9983) used this pattern:
```python
RewriteTextFile('ruby/google-protobuf.gemspec',
lambda line : re.sub(
r'^ s.version = ".*"$',
' s.version = "%s"' % GetFullVersion(rc_suffix = '.rc.'),
line))
```
After this PR, the gemspec does not contain a version literal, so that pattern matches nothing. The tool must write the version into `ruby/lib/google/protobuf/version.rb` instead, for example:
```python
RewriteTextFile('ruby/lib/google/protobuf/version.rb',
lambda line : re.sub(
r'^ VERSION = ".*"$',
' VERSION = "%s"' % GetFullVersion(rc_suffix = '.rc.'),
line))
```
If the tool does not change, the next version bump will leave `version.rb` at the old version without an error, and the gem will be published with the wrong version. `PROTOBUF_RUBY_VERSION` in `protobuf_version.bzl` still names the `.gem` file in the Bazel release rules, so the tool must continue to update both values.
Closes #30762
COPYBARA_INTEGRATE_REVIEW=https://github.com/protocolbuffers/protobuf/pull/30762 from Shopify:uk-add-version-file 36692bbd9ae1561d54622086f4c0e56ddb69fab1
PiperOrigin-RevId: 1002455477
diff --git a/WORKSPACE b/WORKSPACE
index c05fe00..05652a2 100644
--- a/WORKSPACE
+++ b/WORKSPACE
@@ -149,6 +149,7 @@
name = "protobuf_bundle",
srcs = [
"//ruby:google-protobuf.gemspec",
+ "//ruby/lib/google:protobuf/version.rb",
],
gem_checksums = {
"bigdecimal-3.1.9": "2ffc742031521ad69c2dfc815a98e426a230a3d22aeac1995826a75dabfad8cc",
diff --git a/ruby/google-protobuf.gemspec b/ruby/google-protobuf.gemspec
index 0a4ce40..8ea45d8 100644
--- a/ruby/google-protobuf.gemspec
+++ b/ruby/google-protobuf.gemspec
@@ -1,6 +1,8 @@
+require_relative "lib/google/protobuf/version"
+
Gem::Specification.new do |s|
s.name = "google-protobuf"
- s.version = "4.38.0"
+ s.version = Google::Protobuf::VERSION
git_tag = "v#{s.version.to_s.sub(/^\d+\./, '').sub('.rc.', '-rc')}" # Converts X.Y.Z.rc.N to vY.Z-rcN, used for the git tag
s.licenses = ["BSD-3-Clause"]
s.summary = "Protocol Buffers"
diff --git a/ruby/lib/google/protobuf.rb b/ruby/lib/google/protobuf.rb
index fdfa9b6..6349644 100644
--- a/ruby/lib/google/protobuf.rb
+++ b/ruby/lib/google/protobuf.rb
@@ -59,3 +59,5 @@
end
end
end
+
+require 'google/protobuf/version'
diff --git a/ruby/lib/google/protobuf/version.rb b/ruby/lib/google/protobuf/version.rb
new file mode 100644
index 0000000..dcf2603
--- /dev/null
+++ b/ruby/lib/google/protobuf/version.rb
@@ -0,0 +1,12 @@
+# Protocol Buffers - Google's data interchange format
+# Copyright 2026 Google Inc. All rights reserved.
+#
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file or at
+# https://developers.google.com/open-source/licenses/bsd
+
+module Google
+ module Protobuf
+ VERSION = "4.38.0"
+ end
+end