Hi,
The Rails guides, API (edge and stable), and contrib app, all run in a
Linode I pay from my wallet.
Deployment is triggered via a webhook call from GitHub to this trivial
pure Rack application that also runs in that server:
GitHub - rails/rails-master-hook
As you see, that application just touches a file F.
In the server there is a cron job that runs every minute and runs a
shell script. If F is present it removes it and creates a lock file L
(there is a nanosecond race condition that I don't care about).
Indeed, first we check for L. If L is present the shell script just
exists, regardless of F.
The purpose of that trick is to ensure only one update is running at a
time, and to queue updates calls received while an update is
happening. To simplify the setup, since we do not care about how many
calls the applications has gotten while a process was running,
touching F is enough. If we touch it 7 times that's fine, and is super
cheap, all we need to know is that the new cron job running that does
not find the lock file L will run another update.
For edge docs there is a local working copy of the repo that gets a
git pull and then the builtin rake tasks called. These are all
straightforward shell scripts "do this, and then do that".
Then, stable docs generation runs. The shell script checks the output
of git tag and sees whether there is a new stable tag. A stable tag in
Rails is by definition one that matches
\Av[\d.]+\z
So, "v3.2.11" is a stable tag, and "v3.2.9.rc3" is not.
Stable tags have a dedicated directory in the home. We sort the stable
tags and check whether the maximum exists. If it does not (99% of the
time), there is nothing to do, exit. Otherwise we got a new stable
release. The script goes and checks out the tag in its own directory,
runs the builtin rake tasks, and makes a "stable" symlink that points
to that new directory so that nginx serves the new documents This is
the configuration of nginx:
https://github.com/fxn/rails-docs-server-config/blob/master/nginx.conf
As you see stable docs are picked up on the fly. But GiHub only calls
the Rack webhook for regular pushes, not tags, so in practice we
sometimes force the call as part of the release process (rake
publish_docs), otherwise the generation would need to wait for the
next push with commits. But the rake task only triggers the dummy
webhook, no need to tell "release the docs for this version", that is
all found out automatically as you see.
Since nginx is running with gzip_static after edge or stable docs are
generated I recursively gzip -9 all the files with the script I copy
below.
So that is the setup. In the end is quite simple, a handful of simple
shell scripts and directory conventions, it is designed in a way that
minimizes maintenance, it basically runs autonomously.
I'd be glad to provide more details if you had further questions.
Xavier
rails@dedekind:~$ cat bin/rgzip.rb
#!/usr/bin/env ruby
require 'find'
EXTENSIONS = %w(.js .html .css)
def gzname(file)
"#{file}.gz"
end
def compress(file)
puts "compressing #{file}"
system %(gzip -c -9 "#{file}" > "#{gzname(file)}")
end
def compress?(file)
if EXTENSIONS.include?(File.extname(file))
!File.exists?(gzname(file)) || File.mtime(gzname(file)) < File.mtime(file)
end
end
ARGV.each do |dir|
Find.find(dir) do |file|
compress(file) if compress?(file)
end
end