Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pre-cache official Ruby binaries on GitHub Actions images instead of custom binaries #98

Closed
AlenaSviridenko opened this issue Oct 26, 2020 · 46 comments
Assignees

Comments

@AlenaSviridenko
Copy link

AlenaSviridenko commented Oct 26, 2020

We are the maintainers of actions/virtual-environments repo and owns the Hosted images for GitHub Actions and Azure DevOps. We are looking for some collaboration and improving UX of our customers in Ruby area.

Currently, we support two tasks related to Ruby: actions/setup-ruby (for GitHub Actions) and UseRuby (for Azure DevOps). Both tasks require pre-built binaries of Ruby for Linux and MacOS to be placed on images. We build them by ourselves from source code and then put to the images during image generation.

Although this approach works, we believe that a more proper way is to use official Ruby binaries through the https://github.com/ruby/setup-ruby task that is provided by you. You have more expertise in Ruby building and supporting. Actually, ruby/setup-ruby is already mentioned in starter workflow as a default way to use Ruby for GitHub Actions https://github.com/actions/starter-workflows/blob/main/ci/ruby.yml#L27.

The only benefit of actions/setup-ruby is that it understands when Ruby version is already pre-cached on image and doesn't download it again. Action ruby/setup-ruby always downloads specified version.

We think that it would be great if we can collaborate more and pre-cache binaries provided by ruby-builder to our images:

  1. You will be able to configure your task to switch Ruby immediately without latency and download in runtime only in case if it is not pre-cached
    • Currently, we pre-cache the latest patch version for every major-minor pair of Ruby on images. It would speed up the task in the most of the cases.
  2. We will be able to avoid maintenance of own ruby-builder from our side

We have done investigation in order to investigate differences between ruby-builder and how we build Ruby from our side.
The main difference is that you build with shared libs support that means that binaries are bound to location where they were built and can’t be run from different location.

  • You build your binaries under $HOME/.rubies/ruby-<version>.
  • We build our binaries under /opt/hostedtoolcache/Ruby/<version>.
    NOTE: hostedtoolcache is recommended approach to store cached tools on images. actions/toolkit works with it by default. Also both actions/setup-ruby (GitHub Actions) and UseRuby (Azure DevOps) tasks are expecting to consume binaries from hostedtoolcache.

Is it possible to change the ruby-builder directory and build binaries under hostedtoolcache? If so, we would be able to achieve better customers UX and get benefits that were mentioned above.

Thank you,
Alyona.

cc: @maxim-lobanov, @alepauly, @sergey-akhalkov

@eregon
Copy link
Member

eregon commented Oct 28, 2020

Thanks for opening this issue, that makes sense to me.

So the logic would be like:

  • If tc.find('Ruby', version)
    • Use that
  • Otherwise use the current logic (download the prebuilt Ruby)

Currently, we pre-cache the latest patch version for every major-minor pair of Ruby on images.

Only Ruby >= 2.4 currently (2.4, 2.5, 2.6, 2.7), right?

Is RUNNER_TOOL_CACHE guaranteed to always be /opt/hostedtoolcache/ on Linux & /Users/runner/hostedtoolcache on macOS?
I guess not for self-hosted runners (not the main subject of this issue, but would be nice to find a Ruby in the hostedtoolcache of a self-hosted runner).
$RUNNER_TOOL_CACHE seems to be currently /opt/hostedtoolcache on Linux, /Users/runner/hostedtoolcache on macOS and C:/hostedtoolcache/windows on Windows.

It might be possible to make the Ruby builds work in any directory. I'm not sure how feasible/reliable is that, but it would be convenient.

Is it OK to write to the hostedtoolcache, so even downloaded versions would be placed there for consistency?

Ruby gems will get installed under the Ruby prefix by default, and I would very much like to avoid messing with GEM_HOME/GEM_PATH variables, as that can lead to various non-trivial issues.
That means, the Ruby prefix must be writable.

What about Windows?
This action uses builds from RubyInstaller. For Ruby >= 2.4 it downloads the .7z archive (without DevKit), since there is already a MSYS2 toolchain on GitHub Actions. URLs are here.
So if the same archives are already extracted in the hostedtoolcache, we should be able to reuse them.

On Windows, we noticed the D: drive seems faster than C:, probably because it seems to be a SSD (#14).
But the hostedtoolcache is on C:.
The initial directory when running an action (pwd) is D:, so that seems the "drive to write to when running a workflow".
So this could lead to a slowdown when installing gems and when installing a Ruby version not in the toolcache.
I'm not sure what's a good way to address that.
We could measure again how much difference it makes.

Alternative Ruby implementations like JRuby & TruffleRuby would always be downloaded, unless you consider adding them to the hostedtoolcache too?

@maxim-lobanov
Copy link

So the logic would be like:
Is it OK to write to the hostedtoolcache, so even downloaded versions would be placed there for consistency?

Yes, exactly. If version is not found, download it and do tc.cacheDir. cacheDir will write to hostedtoolcache. It won't be useful on Hosted machines because it is cleaned up after every build but very useful for self-hosted. See full documentation in toolkit.
The good example is setup-java task: https://github.com/actions/setup-java/blob/main/src/installer.ts
Something like that:

let toolPath = tc.find
if (toolPath) {
    core.debug(`Tool found in cache ${toolPath}`);
} else {
  // installation logic
  toolPath = await tc.cacheDir

Is RUNNER_TOOL_CACHE guaranteed to always be /opt/hostedtoolcache/ on Linux & /Users/runner/hostedtoolcache on macOS?

Yes, these paths won't be changed in future because too many things depend on it.

Only Ruby >= 2.4 currently (2.4, 2.5, 2.6, 2.7), right?
Alternative Ruby implementations like JRuby & TruffleRuby would always be downloaded, unless you consider adding them to the hostedtoolcache too?

Yes, we have to find balance between disk space on image and customers' build speed. We don't have telemetry on GitHub Actions but in our understanding, 4 latest versions are most popular and caching them will cover ~90% use-cases. If customers need any specific old version and freeze patch version, they will have minor latency to install in runtime.

As for the Windows

On Windows we use very tricky scheme:
Download exe from RubyInstaller, install it to machine, install MSYS. Then we pack installation directory to archive and unpack this archive to machine during image-generation.
Exe url is https://github.com/oneclick/rubyinstaller2/releases/download/RubyInstaller-${Version}-1/rubyinstaller-${Version}-1-${Architecture}.exe. This code is internal one but you can find result packages that we install on image by this link: https://github.com/orgs/actions/packages?tab=packages&q=ruby
I think we can switch to your approach without any issues on Windows.

It might be possible to make the Ruby builds work in any directory. I'm not sure how feasible/reliable is that, but it would be convenient.

I could be wrong, but in my understanding, if Ruby was built with --enable-shared flag, it will work only in the same directory where it was built.
We have to support binaries for both GitHub Actions task (at least until it is fully deprecated) and Azure DevOps task(it is the main way to use Ruby in Azure DevOps). Both these tasks can't be changed to different directory so it is the reason why we are asking to rebuild your binaries on hostedtoolcache paths to work our of box.

@MSP-Greg
Copy link
Collaborator

I think we can switch to your approach without any issues on Windows.

JFYI, all Windows builds used here are self contained, as they contain the dll's needed at runtime, and all the dll's are 'manifested' (their location is linked in the exe), so the 'builds' can be placed anywhere. None use the internal MSYS2 layout.

@MSP-Greg
Copy link
Collaborator

MSP-Greg commented Oct 30, 2020

@maxim-lobanov

At present, the naming/folder structure for Windows Ruby versions in the toolcache and this action are different. Is that a concern? Most scripts would rely on the Ruby version that 'Path' activates, but there could be scripts that are expecting the current layout?

EDIT:

I knew I had it somewhere in Actions workflows. This action uses rubyinstaller-2.5.8-1-x64, the toolcache uses 2.5.8/x64.

Also, Windows Rubies are currently available in both 64 & 32 bit versions. I'm somewhat active in repos/gems testing & building with Windows, and I don't recall any requests for 32 bit versions. Have you had requests for them in the toolcache?

@maxim-lobanov
Copy link

@MSP-Greg , Yes, naming/structure could be concern.
Both GitHub Actions task and Azure DevOps task are expecting Ruby to be placed on default tool-cache structure, so tc.find is able to find it automatically.
Toolcache use the following structure:

- <toolcache_root>
--- ruby
----- 2.5.8
------- x64
--------- <content of Ruby>
----- 2.7.2
------- x64
--------- <content of Ruby>

actions/toolkit contains two methods: tc.find and tc.cacheDir so you don't need to take care about structure.

As I mentioned above, It could be something like:

if (tc.find != null) {
  // use
} else {
  // old logic to download and install on flight
  tc.cacheDir
 // use

As for the 32 bit versions, we have never seen requests for it so I think we should put x64 versions to the image cache and x32 can be downloaded in runtime with latency as currenty.

@MSP-Greg
Copy link
Collaborator

x32 can be downloaded in runtime

Sorry I wasn't clearer. At present ruby/setup-ruby does not support 32 bit Windows versions. Or, It won't download them, and there's no way to tag the actions inputs that they're 'requested'.

@maxim-lobanov
Copy link

We have never seen requests for 32 bit Ruby on Windows.
I just mentioned that If you would like to add support x32 bit Ruby to this action in future, you will have to add additional input like arch (it could be optional and set as x64 by default but customers can override it to x32). 64 bit Ruby will be switched immediately because it is pre-cached on image. 32 bit will be downloaded.

@eregon
Copy link
Member

eregon commented Oct 31, 2020

tc.cacheDir() copies all extracted files, that seems suboptimal as it might take some extra time, and it will create an extra copy on disk (so less free space).

Is there a way to get the toolcache path, so we could extract directly to the right location?

I think it would be better if we always have the Ruby prefix consistently under toolcache, whether or not we had to download, and whether or not it's self-hosted.

Regarding having a build independent of the build directory, I found these configure options:
./configure --enable-shared --enable-rpath --enable-load-relative. I will try that.

@eregon eregon self-assigned this Oct 31, 2020
@eregon
Copy link
Member

eregon commented Oct 31, 2020

I tried building Ruby with those flags, results at https://github.com/ruby/ruby-builder/releases/tag/load-relative

One issue is that gem install bundler fails on --enable-load-relative Rubies:
https://github.com/ruby/setup-ruby/runs/1336222778?check_suite_focus=true

  /home/runner/.rubies/ruby-2.7.0/bin/gem install bundler -v ~> 2 --no-document
  ERROR:  Error installing bundler:
  	"bundle" from bundler conflicts with /home/runner/.rubies/ruby-2.7.0/bin/bundle
  Took   0.56 seconds
Error: The process '/home/runner/.rubies/ruby-2.7.0/bin/gem' failed with exit code 1

Because the existing bin/bundle starts like:

#!/bin/sh
# -*- ruby -*-
_=_\
=begin
bindir="${0%/*}"
exec "$bindir/ruby" "-x" "$0" "$@"
=end
#!/usr/bin/env ruby
#
# This file was generated by RubyGems.
#
# The application 'bundler' is installed as part of a gem, and
# this file is here to facilitate running it.
#

require 'rubygems'

instead of

#!/home/eregon/.rubies/ruby-2.7.2/bin/ruby
#
# This file was generated by RubyGems.
#
# The application 'bundler' is installed as part of a gem, and
# this file is here to facilitate running it.
#

require 'rubygems'

And RubyGems doesn't seem to notice it's safe to override unfortunately.
RubyGems expects the This file was generated by RubyGems line to be the third line:
https://github.com/rubygems/rubygems/blob/6d7fe84753/lib/rubygems/installer.rb#L220

@eregon
Copy link
Member

eregon commented Oct 31, 2020

Interestingly gem install rake works without error, and the original bin/rake uses a variant:

#!/bin/sh
# -*- ruby -*-
# This file was generated by RubyGems.
#
# The application 'rake' is installed as part of a gem, and
# this file is here to facilitate running it.
#
_=_\
=begin
bindir="${0%/*}"
exec "$bindir/ruby" "-x" "$0" "$@"
=end
#!/usr/bin/env ruby

require 'rubygems'

rake is a bundled gem and not a default gem, probably that's why it works differently.

@eregon
Copy link
Member

eregon commented Nov 1, 2020

Removing the #!/bin/sh part seems to work around this and is easy enough: ruby/ruby-builder@f3e1b0e
https://github.com/ruby/setup-ruby/runs/1336674146?check_suite_focus=true
It should not be done for rake though (can be tested with gem install rake).

@eregon
Copy link
Member

eregon commented Nov 3, 2020

There are various issues with having builds built in a separate directory than the runtime directory:
https://github.com/ruby/setup-ruby/runs/1341373045?check_suite_focus=true

So I think building with --prefix=hosted cache directory seems easier and much more feasible. It's also closer to a regular build, and --enable-load-relative doesn't seem used much in practice (especially for older Rubies), given the bugs above.

Also, this seems unrelated, 2.2.10 fails the compile on macOS because rb_str_change_terminator_length() is not declared, which seems an actual bug of 2.2.10, revealed now because the compiler is more strict by default I guess: https://github.com/ruby/ruby-builder/runs/1338753035?check_suite_focus=true

@maxim-lobanov
Copy link

@eregon thank you for investigation.
Could you please try to rebuild existing packages in hosted toolcache directory and upload them as a separate tag? We will be able to test them from our side.
Exact paths:

  • MacOS: /Users/runner/hostedtoolcache/Ruby/<VERSION>/x64. Example: /Users/runner/hostedtoolcache/Ruby/2.6.6/x64
  • Ubuntu: /opt/hostedtoolcache/Ruby/<VERSION>/x64. Example: /opt/hostedtoolcache/Ruby/2.6.6/x64

P.S. We will be overload next week due to a few upcoming releases. After that, we will try to rework Windows installation as MSP-Greg mentioned above and test binaries

@eregon
Copy link
Member

eregon commented Nov 7, 2020

More of a note, but gem install rake actually already fails on master, for Ruby 2.1 & 2.2 which are no longer supported, that's fine (probably I should fix the version).
But it also fails for RubyInstaller builds, for 2.5-2.7:
https://github.com/ruby/setup-ruby/runs/1368033653?check_suite_focus=true

ERROR:  Error installing rake:
	"rake" from rake conflicts with D:/rubyinstaller-2.7.2-1-x64/bin/rake

It works on RubyInstaller 2.3 & 2.4 interestingly.

I guess it doesn't matter too much since we did not receive a bug report about this, and bundle install with gem "rake" actually works on all versions. Part of why is gems are installed under vendor/bundle with bundler-cache: true. But even without that it worked fine IIRC. So probably bundle install is less picky about the 3rd line than gem install. People don't use gem install much, so it all works fine in practice I guess.

eregon added a commit that referenced this issue Nov 7, 2020
…ble as safe to override"

* This reverts commit 35f0af3.
* It fails for some cases like Ruby <= 2.2 and on some RubyInstaller builds,
  see #98 (comment)
* Most users will use Bundler to install rake, and that already works fine.
@eregon
Copy link
Member

eregon commented Nov 7, 2020

Builds with the hostedtoolcache prefix are at https://github.com/ruby/ruby-builder/releases/tag/toolcache
So far I only built 2.7 to test, but I'll build the rest soon.

The branch to test in this repo is https://github.com/ruby/setup-ruby/compare/toolcache
It seems to work fine for 2.7 builds on all platforms, and for mingw on Windows:
https://github.com/ruby/setup-ruby/runs/1368155359?check_suite_focus=true

@MSP-Greg the mswin build fails during bundle install, maybe the build assumes it's installed under D:\ruby-mswin?
If that's the case, could you try to make a single build that would be installed in C:/hostedtoolcache/windows/Ruby/mswin/x64 to try if that helps?
Oddly enough, bundle install worked in this build, when not using bundler-cache (but the cache wasn't hit) and done later in the workflow:
https://github.com/ruby/setup-ruby/runs/1368164993?check_suite_focus=true#step:15:62
Maybe the fact the Bundler path is set changes something?

@eregon
Copy link
Member

eregon commented Nov 7, 2020

@MSP-Greg Actually, I can easily work around that, my initial condition for "use the tool cache for prefix" was engine == 'ruby' but I can exclude head versions and use the same prefix as before, anyway head builds don't make sense to cache so it seems best to not store them in the tool cache.
Green now: https://github.com/ruby/setup-ruby/runs/1368220427?check_suite_focus=true

@MSP-Greg
Copy link
Collaborator

MSP-Greg commented Nov 7, 2020

@eregon

I hate this (working on something else). Back when I started building mswin, I started on modifying the scripts I used for mingw. Never finished. The scripts for mingw do a bit of processing of the bin *.cmd scripts.

The mswin *.cmd scripts currently have some hard coded paths in them that match the install folders, which I think match the previous location used here. I'm looking at it...

I was writing while you were... I'll still take a look at it. It would be good to be consistent with the install location?

@eregon
Copy link
Member

eregon commented Nov 7, 2020

@MSP-Greg I think it's fine as-is, it's actually not a good idea to have head builds under the hostedtoolcache as that can be persisted for self-hosted runners. Caching head builds would defeat the purpose of head builds. So, everything is fine now :)

@MSP-Greg
Copy link
Collaborator

MSP-Greg commented Nov 7, 2020

Cool. I think the hard coded paths are coming from the 'make' scripts, it's not my code. There is a script I can (easily) modify to remove them.

But, mingw runs all it's test suites from install, I haven't done that yet for mswin. The hard coded paths may be needed since RbConfig is a bit strange when running make tests. I'll see. My memory isn't the best for these things...

@eregon
Copy link
Member

eregon commented Nov 8, 2020

All builds are ready now at https://github.com/ruby/ruby-builder/releases/tag/toolcache.
I now consistently use ruby-build (instead of a mix of ruby-install/ruby-build depending on the version), which as a side effect always builds its own OpenSSL on macOS, so it means #97 will be fixed when using these builds.

Test run at https://github.com/ruby/setup-ruby/actions/runs/352578630, I expect everything will be passing.

@eregon
Copy link
Member

eregon commented Nov 9, 2020

I made a new release of ruby/setup-ruby that uses the new builds:
https://github.com/ruby/setup-ruby/releases/tag/v1.50.0

It doesn't use the if (tc.find()) logic yet, because for that we need the images to use these new builds.
cc @maxim-lobanov

@MSP-Greg
Copy link
Collaborator

@eregon is correct. The standard install folder for MSYS2 is C:/msys64, and all Ruby versions >= 2.4 will find it when using gem & bundler.

Off topic note: at present, compiling (outside of gem or bundler, typically via rake compile) requires that the MSYS2 folder be in path. Adding -rdevkit as a parameter will also find it, but that's inconvenient when doing cross-platform scripts...

@AlenaSviridenko
Copy link
Author

Hi there,
just giving an update:

  • Windows generation process was updated and now we pre-cache official binaries.
  • macOS and Ubuntu are under testing now, we will ask for your review once we are ready with them.

@AlenaSviridenko
Copy link
Author

A couple of questions I wanted to discuss about communication process:

  1. How we can stay in-touch with upcoming changes? We will always grab the latest release of binaries, but if they will contain any critical changes — we would like to know about it beforehand.
    Currently, we create an announcement issue 2 weeks (or more) prior to possible breaking change, and include it to README files to notify customers and give them time to adapt to it.
    Idea that is coming to my mind is: maybe you could create an issue in virtual-environments repo with the description of upcoming critical changes? Just a short description of what is going to be changed.
    If you have any other idea - please, let me know.
  2. Sometimes customers create issues in our repo related to tools that we do not own and don't have expertise to fix. Just because we are large open-source repo in Actions org with a generic name "virtual-environments" 🙂 Usually we are re-directing them to the correct place to create the issue.
    Previously, we were maintainers of Ruby binaries we are pre-caching on the images, and we were responsible for addressing issues with them. But once we move to official binaries, it is not clear where we should point customers if they will file an issue in our repo. https://github.com/ruby/ruby-builder issues are turned off.
    Could you please advise what would be the preferred way for customers to file questions or issues?

@eregon
Copy link
Member

eregon commented Nov 19, 2020

  1. It sounds fine. I'll write down the process in the README of ruby-builder that for breaking changes we should open an issue on actions/virtual-environments 2 weeks before.
    There should be no breaking changes for a given release (e.g., https://github.com/ruby/ruby-builder/releases/tag/toolcache).
    To pull the builds you might want to use the "latest release" link like https://github.com/ruby/ruby-builder/releases/latest. That would be most convenient. Then I can already prepare a new release, but only mark as non-prerelease once it's ready.
  2. I think it's good to redirect them here. I'd rather keep all issues in one repo, hence the issues are disabled on ruby/ruby-builder. I can clarify that in the README of that repo.

eregon added a commit to ruby/ruby-builder that referenced this issue Nov 19, 2020
@eregon
Copy link
Member

eregon commented Nov 19, 2020

@MSP-Greg
Copy link
Collaborator

@AlenaSviridenko

Sometimes customers create issues...

Well phrased. 😊

but if they will contain any critical changes

They shouldn't, but sometimes security issues force changes that could be considered 'breaking', although often narrow in scope.

Note that many repos test against major.minor Ruby versions (not pinned to 'patch'), so there will be CI testing run in the interval between new Ruby patch releases here and the update to them in the image toolcache. I think that made sense...

@eregon
Copy link
Member

eregon commented Nov 20, 2020

Note that many repos test against major.minor Ruby versions (not pinned to 'patch'), so there will be CI testing run in the interval between new Ruby patch releases here and the update to them in the image toolcache. I think that made sense...

That would be the responsibility of these users/customers and/or CRuby branch maintainers then.
Users can pin to a specific x.y.z version if they want full stability, that's supported, so I don't think we need to worry about that.
Also this action has a new release everytime we add a version or basically any change, so it's very easy to rollback shall there be a breaking change in anything.

@MSP-Greg
Copy link
Collaborator

@eregon

Sorry. My point was in reference to new Ruby patch versions having 'critical changes', and that because many repos do not pin to patch versions for CI, the new versions will have been tested on those repos before Actions adds them to the toolcache.

Besides, and as you mentioned, Actions isn't responsible for changes in third party software, their only responsibility is to install new versions in a timely manner.

@eregon
Copy link
Member

eregon commented Nov 21, 2020

Since I have you here, do you know who I could ping on actions/toolkit#632 / who are the maintainers of @actions/cache? It prevents @actions/cache to work on Windows when MSYS2 is in PATH, which could become a pretty big efficiency issue (cache saving always fails).

@AlenaSviridenko
Copy link
Author

I think you can file an issue in https://github.com/actions/cache, since it is an open-source repo

@AlenaSviridenko
Copy link
Author

Thank you for updating README!

@alepauly
Copy link

do you know who I could ping on actions/toolkit#632

@eregon - I pinged the team that owns that and they'll look as soon as they can. thanks!

@maxim-lobanov
Copy link

Hello @eregon , we have tested Ruby binaries from https://github.com/ruby/ruby-builder/releases/tag/toolcache on Ubuntu and MacOS images and can confirm that it works correctly 🚀

If you would like to review pull-requests:

We are planning to deploy the new images with this change in 1-2 weeks. After that you will be able to modify ruby/setup-ruby to use pre-cached binaries.
We are planning always pull latest release from https://github.com/ruby/ruby-builder repo during image-generation. Could you please confirm that all new releases will support $RUNNER_TOOL_CACHE directory like https://github.com/ruby/ruby-builder/releases/tag/toolcache does.

@maxim-lobanov
Copy link

Note:
I have seen updated version of ruby/setup-ruby and would like to propose a few suggestions to work with tool-cache.
Currently, you hardcode tool-cache path in common.getToolCacheRubyPrefix and unpack downloaded Ruby manually to this folder.
The target location is correct but you missed "arch flag" and tc.find won't be able to find this version on machine (if you would like to use actions/toolkit in future)
Sorry, I missed info about "arch flag" in my previous message. Correct tool-cache structure is:

- <toolcache_root>
--- ruby
----- 2.5.8
------- x64.complete
------- x64
--------- <content of Ruby>
----- 2.7.2
------- x64.complete
------- x64
--------- <content of Ruby>

x64.complete is empty file, just a flag located near x64 folder in every version folder. This flag says toolcache that this version really exists.

If you are going to find pre-cached versions manually via custom logic, you don't need to take care about this flag.
If you would like to use tc.find to find pre-cached versions, you have to:

  1. continue use custom downloading logic but add one extra operation to create this flag in tool-cache folder after extracting
  2. use tc.cacheDir to move downloaded version of Ruby to tool-cache structure. This way you won't need to take care about x64.complete file because it will be created by cacheDir function

During image-generation, we just create this flag after unpacking to make sure that both GitHub Actions task and [Azure DevOps task] will be able to resolve version via actions/toolkit: https://github.com/actions/virtual-environments/pull/2084/files#diff-cd3a602dc8e0d7432bae1f80a68dd14d6397606db6474777a1b78f4129f8b345R42

@eregon
Copy link
Member

eregon commented Nov 30, 2020

Sorry for the late reply, I will take a deeper look at this soon.

Could you please confirm that all new releases will support $RUNNER_TOOL_CACHE directory like https://github.com/ruby/ruby-builder/releases/tag/toolcache does.

Yes.

continue use custom downloading logic but add one extra operation to create this flag in tool-cache folder after extracting

I'll do that, and I might try tc.find() and see how well it plays with the hardcoded paths (needed because building Ruby captures the paths where it will be installed (--prefix=...) at build time).

The reason for not using cacheDir() is that would create an extra copy, I would need to first extract, then call cacheDir() which would mean having 2 copies on disk. Doing it manually, I can extract directly to the right directory.

@eregon
Copy link
Member

eregon commented Dec 5, 2020

I did these changes, so now tc.find() is tried for stable CRuby versions.
And the .complete file is written, so for self-hosted tc.find() should detect the previous download & extract.

Changes: v1.56.0...v1.57.0
CI Run: https://github.com/ruby/setup-ruby/runs/1503878827?check_suite_focus=true#step:3:7
Released as https://github.com/ruby/setup-ruby/releases/tag/v1.57.0

For self-hosted the toolcache directory is always persisted, is that correct?
On GitHub runners it's not persisted.

So that creates some difference. For instance both gem foo if the user does gem install foo, and the Bundler version the action installs will be preserved (because they installed under the Ruby prefix, this is RubyGems's default).
With the recent fix in #118, it should hopefully not matter for Bundler, except that many versions of Bundler might be accumulated in the toolcache.
If the user does gem install foo, I don't think there is much we can do about it.
It's probably a good idea in general to regenerate the images or the toolcache regularly for self-hosted runners too anyway.

Gems installed via bundler-cache: true will be under $PWD/vendor/bundle, so that's never preserved, but instead uses @actions/cache, so that's all fine.

@eregon
Copy link
Member

eregon commented Dec 5, 2020

I think we can close this issue now, thanks for proposing it, the feedback and making quick progress on it.
As a result, downloading & extracting is skipped for Rubies already in the toolcache.

Since this action is now a strict superset (in that it also uses Rubies already in the toolcache, and even adds new Rubies there) of actions/setup-ruby, I think we could deprecate actions/setup-ruby soon: actions/setup-ruby#80 (comment)

@eregon eregon closed this as completed Dec 5, 2020
@maxim-lobanov
Copy link

@eregon , thank you for changes on your side.
Just an update: Hosted Ubuntu (16.04, 18.04, 20.04) and MacOS (10.15) and Windows (2016, 2019) were deployed this week. They already contain binaries provided by ruby-builder.
So it is reliable for your action to consume them from tool-cache.

As I understand, currently, your action should work pretty fast for pre-cached versions. Is it correct? Just want to make sure that customers will get the best experience with your action.

@AlenaSviridenko and me will take care about plan for deprecation actions/setup-ruby. Thank you for your help!

@eregon
Copy link
Member

eregon commented Dec 5, 2020

So it is reliable for your action to consume them from tool-cache.

Thanks for confirming, indeed I missed I should wait up to 2 weeks from #98 (comment).

I was actually hesitating to add an input (or a variable in the code) to control whether the toolcache is used (on by default), in case there is any issue. It might be useful in general.

As I understand, currently, your action should work pretty fast for pre-cached versions. Is it correct? Just want to make sure that customers will get the best experience with your action.

Correct, yes, the download and extract steps are removed, and so setting up Ruby itself is < 1 second when already in the toolcache. It's always been the goal of ruby/setup-ruby to be as efficient as possible.

There are extra steps (unless disabled by inputs): installing Bundler can take a couple seconds, and then bundle install can take some time, if bundler-cache: true is used.
You can compare
https://github.com/ruby/setup-ruby/runs/1503880190?check_suite_focus=true#step:3:7 (uses toolcache)
and
https://github.com/ruby/setup-ruby/runs/1503708099?check_suite_focus=true#step:3:14 (does not)
The gain is especially visible on Windows, since there extraction would take ~5s and now 0.

(Linux example: https://github.com/ruby/setup-ruby/runs/1503878808?check_suite_focus=true#step:3:11)

@MSP-Greg
Copy link
Collaborator

MSP-Greg commented Dec 6, 2020

setting up Ruby itself is < 1 second when already in the toolcache

Was running CI elsewhere. All Rubies (on all three OS's) reported '0s' as the step time. No one can complain about that...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

No branches or pull requests

6 participants