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

Automate v8 source upgrade #181

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .github/workflows/v8build.yml
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
name: V8 Build

on: workflow_dispatch

jobs:
build:
name: Build V8 for ${{ matrix.platform }}
strategy:
fail-fast: false
matrix:
platform: [ubuntu-18.04, macos-latest, windows-latest]
runs-on: ${{ matrix.platform }}
Expand Down
42 changes: 42 additions & 0 deletions .github/workflows/v8upgrade.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
name: V8 Upgrade

on:
workflow_dispatch:
schedule:
- cron: '0 0 * * *' # Run every day
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stable releases are on average every 4 weeks. Running every day seems excessive, but I guess most of the time it will just be a version check.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Roughly every 4 weeks a new major Stable release is done.

(Source: https://v8.dev/docs/release-process#stable-releases)

Emphasis on "major" was mine, they more frequently release patch version bumps.

Currently, https://omahaproxy.appspot.com shows the most recent version bump was only about a week apart:

  • current_reldate: 09/30/21
  • previous_reldate: 09/24/21

If we tracked the branch head for the stable channel (currently branch-heads/9.4) then that would make the changes even more frequent. Releasing fixes that frequently might be overkill, but automating the preparation work for getting a security fix out would be useful.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can start with every day and if it gets noisy (which it shouldn't if it's largely version checks and silent exiting if releases are more like once a week), we can reduce the frequency.


jobs:
upgrade:
name: Upgrade V8
runs-on: ubuntu-18.04
steps:
- name: Checkout
uses: actions/checkout@v2
with:
submodules: true
fetch-depth: 0
- uses: actions/setup-python@v2
with:
python-version: '3.8'
- name: Update depot_tools fetch config
run: cd deps/depot_tools && git config --unset-all remote.origin.fetch; git config --add remote.origin.fetch +refs/heads/*:refs/remotes/origin/*
shell: bash
- name: Add depot_tools to PATH
run: echo "$PWD/deps/depot_tools" >> $GITHUB_PATH
shell: bash
- name: Run upgrade script
run: cd deps && python upgrade_v8.py
- name: Create PR metadata
id: pr_metadata
run: |
echo ::set-output name=pr_branch::"v8_$(cat deps/v8_version)_upgrade"
- name: Create PR
uses: peter-evans/create-pull-request@v3
with:
commit-message: Upgrade V8 binaries
branch: ${{steps.pr_metadata.outputs.pr_branch}}
delete-branch: true
title: Upgrade V8 binary
body: Auto-generated pull request to upgarde V8 binary


32 changes: 11 additions & 21 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Execute JavaScript from Go

<a href="https://github.com/rogchap/v8go/releases"><img src="https://img.shields.io/github/v/release/rogchap/v8go" alt="Github release"></a>
[![Go Report Card](https://goreportcard.com/badge/rogchap.com/v8go)](https://goreportcard.com/report/rogchap.com/v8go)
[![Go Report Card](https://goreportcard.com/badge/rogchap.com/v8go)](https://goreportcard.com/report/rogchap.com/v8go)
[![Go Reference](https://pkg.go.dev/badge/rogchap.com/v8go.svg)](https://pkg.go.dev/rogchap.com/v8go)
[![CI](https://github.com/rogchap/v8go/workflows/CI/badge.svg)](https://github.com/rogchap/v8go/actions?query=workflow%3ACI)
![V8 Build](https://github.com/rogchap/v8go/workflows/V8%20Build/badge.svg)
Expand Down Expand Up @@ -106,7 +106,7 @@ case err := <- errs:
// javascript error
case <- time.After(200 * time.Milliseconds):
vm := ctx.Isolate() // get the Isolate from the context
vm.TerminateExecution() // terminate the execution
vm.TerminateExecution() // terminate the execution
err := <- errs // will get a termination error back from the running script
}
```
Expand Down Expand Up @@ -177,7 +177,7 @@ To set this up:
2. Add the Mingw-w64 bin to your PATH environment variable (`C:\msys64\mingw64\bin` by default)
3. Open MSYS2 MSYS and execute `pacman -S mingw-w64-x86_64-toolchain`

V8 requires 64-bit on Windows, therefore it will not work on 32-bit systems.
V8 requires 64-bit on Windows, therefore it will not work on 32-bit systems.

## V8 dependency

Expand Down Expand Up @@ -215,26 +215,16 @@ This project also aims to keep up-to-date with the latest (stable) release of V8

### Upgrading the V8 binaries

This process is non-trivial, and hopefully we can automate more of this in the future.
We have the [upgradev8](https://github.com/rogchap/v8go/.github/workflow/v8upgrade.yml) workflow.
The workflow is triggered every day or manually.

1) Make sure to clone the projects submodules (ie. the V8's `depot_tools` project): `git submodule update --init --recursive`
1) Add the `depot_tools` folder to your `PATH` eg: `export PATH=~/Development/rogchap/v8go/deps/depot_tools:$PATH`
1) From the `deps` folder run `fetch v8`; you only need to do this once, if you don't already have the V8 source.
1) Find the current stable release (`v8_version`) here: [https://omahaproxy.appspot.com](https://omahaproxy.appspot.com)
1) Create a new git branch from `master` eg. `git checkout -b v8_7_upgrade`
1) Enter the v8 folder and fetch all the latest git branches: `cd deps/v8 && git fetch`
1) Find the right `branch-heads/**` to checkout, for example if the `v8_version` is 8.7.220.31 then you want to `git checkout
branch-heads/8.7`. You can check all the `branch-heads` with `git branch --remotes | grep branch-heads/`
1) Copy all the contents of `deps/v8/include` to `deps/include` making sure not to delete any of the `vendor.go` files,
which are required for users that are using `go mod vendor`. If there are any new folders added, make sure to create new
`vendor.go` files in each folder within `deps/include` and update `cgo.go`.
1) Optionally build the V8 binary for your OS: `cd deps && ./build.py`. V8 is a large project, and building the binary
can take up to 30 minutes. Once built all the tests should still pass via `go test -v .`
1) Commit your changes, making sure that the git submodules have been updated to the new checksum for the version of V8.
Make sure *NOT* to add your build of the binary, as this will be build via CI.
1) Because the build is so long, this is not automatically triggered. Go to the [V8
If the current [v8_version](https://github.com/rogchap/v8go/deps/v8_version) is different from the latest stable version, the workflow takes care of fetching the latest stable v8 files and copying them into `deps/include`. The last step of the workflow opens a new PR with the branch name `v8_upgrade/<v8-version>` with all the changes.

The next steps are:

1) The build is not yet triggered automatically. To trigger it manually, go to the [V8
Build](https://github.com/rogchap/v8go/actions?query=workflow%3A%22V8+Build%22) Github Action, Select "Run workflow",
and select your pushed branch eg. `v8_7_upgrade`.
and select your pushed branch eg. `v8_upgrade/<v8-version>`.
1) Once built, this should open 3 PRs against your branch to add the `libv8.a` for Linux, macOS and Windows; merge
these PRs into your branch. You are now ready to raise the PR against `master` with the latest version of V8.

Expand Down
110 changes: 110 additions & 0 deletions deps/upgrade_v8.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
#!/usr/bin/env python

import urllib.request
import sys
import json
import subprocess
import os
import fnmatch
import pathlib
import shutil

vendor_file_template = """// Generated by deps/upgrade_v8.py, DO NOT REMOVE/EDIT MANUALLY.
// Package %s is required to provide support for vendoring modules
package %s
"""

include_vendor_file_template = """// Generated by deps/upgrade_v8.py, DO NOT REMOVE/EDIT MANUALLY.
// Package include is required to provide support for vendoring modules
package include

import (
%s
)
"""

CHROME_VERSIONS_URL = "https://omahaproxy.appspot.com/all.json?os=linux&channel=stable"
V8_VERSION_FILE = "v8_version"

deps_path = os.path.dirname(os.path.realpath(__file__))
v8go_path = os.path.abspath(os.path.join(deps_path, os.pardir))
env = os.environ.copy()
v8_path = os.path.join(deps_path, "v8")
v8_include_path = os.path.join(v8_path, "include")
deps_include_path = os.path.join(deps_path, "include")

def get_directories_names(path):
flist = []
for p in pathlib.Path(path).iterdir():
if p.is_dir():
flist.append(p.name)
return sorted(flist)

def package_name(package, index, total):
name = f'_ "rogchap.com/v8go/deps/include/{package}"'
if (index + 1 == total):
return name
else:
return name + '\n'

def create_include_vendor_file(src_path, directories):
package_names = []
total_directories = len(directories)

for index, directory_name in enumerate(directories):
package_names.append(package_name(directory_name, index, total_directories))

with open(os.path.join(src_path, 'vendor.go'), 'w') as temp_file:
temp_file.write(include_vendor_file_template % (' '.join(package_names)))

def create_vendor_files(src_path):
directories = get_directories_names(src_path)

create_include_vendor_file(src_path, directories)

for directory in directories:
directory_path = os.path.join(src_path, directory)

vendor_go_file_path = os.path.join(directory_path, 'vendor.go')

if os.path.isfile(vendor_go_file_path):
continue

with open(os.path.join(directory_path, 'vendor.go'), 'w') as temp_file:
temp_file.write(vendor_file_template % (directory, directory))

def update_v8_version_file(src_path, version):
with open(os.path.join(src_path, V8_VERSION_FILE), "w") as v8_file:
v8_file.write(version)

def read_v8_version_file(src_path):
v8_version_file = open(os.path.join(src_path, V8_VERSION_FILE), "r")
return v8_version_file.read().strip()

def get_latest_v8_info():
with urllib.request.urlopen(CHROME_VERSIONS_URL) as response:
json_response = response.read()

return json.loads(json_response)

# Current version
current_v8_version_installed = read_v8_version_file(deps_path)

# Get latest version
latest_v8_info = get_latest_v8_info()

latest_stable_v8_version = latest_v8_info[0]["versions"][0]["v8_version"]

if current_v8_version_installed != latest_stable_v8_version:
subprocess.check_call(["git", "fetch", "origin", latest_stable_v8_version],
cwd=v8_path,
env=env)
# checkout latest stable commit
subprocess.check_call(["git", "checkout", latest_stable_v8_version],
cwd=v8_path,
env=env)

shutil.rmtree(deps_include_path)
shutil.copytree(v8_include_path, deps_include_path, dirs_exist_ok=True)
create_vendor_files(deps_include_path)
update_v8_version_file(deps_path, latest_stable_v8_version)
1 change: 1 addition & 0 deletions deps/v8_version
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
9.0.257.18