script to sync fork llvm-premerge-tests/llvm-project
- uniformly append env variables - resolve current HEAD and pass it as BUILDKITE_COMMIT to script generators. Add it as ph_commit_sha.
This commit is contained in:
parent
8bc6bb7d5d
commit
49be688a27
4 changed files with 128 additions and 8 deletions
|
@ -13,9 +13,13 @@
|
||||||
# See the License for the specific language governing permissions and
|
# See the License for the specific language governing permissions and
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
|
|
||||||
|
# Script runs in checked out llvm-project directory.
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
|
||||||
from steps import generic_linux, generic_windows, from_shell_output
|
from steps import generic_linux, generic_windows, from_shell_output, extend_steps_env
|
||||||
|
from sync_fork import sync_fork
|
||||||
|
import git
|
||||||
import yaml
|
import yaml
|
||||||
|
|
||||||
steps_generators = [
|
steps_generators = [
|
||||||
|
@ -27,7 +31,18 @@ if __name__ == '__main__':
|
||||||
no_cache = os.getenv('ph_no_cache') is not None
|
no_cache = os.getenv('ph_no_cache') is not None
|
||||||
log_level = os.getenv('ph_log_level', 'WARNING')
|
log_level = os.getenv('ph_log_level', 'WARNING')
|
||||||
notify_emails = list(filter(None, os.getenv('ph_notify_emails', '').split(',')))
|
notify_emails = list(filter(None, os.getenv('ph_notify_emails', '').split(',')))
|
||||||
|
# Syncing LLVM fork so any pipelines started from upstream llvm-project#
|
||||||
|
# but then triggered a build on fork will observe the commit.
|
||||||
|
sync_fork(os.path.join(os.getenv('BUILDKITE_BUILD_PATH'), 'llvm-project-fork'), [os.getenv('BUILDKITE_BRANCH'), 'main'])
|
||||||
steps = []
|
steps = []
|
||||||
|
|
||||||
|
env = {}
|
||||||
|
for e in os.environ:
|
||||||
|
if e.startswith('ph_'):
|
||||||
|
env[e] = os.getenv(e)
|
||||||
|
repo = git.Repo('.')
|
||||||
|
env['ph_commit_sha'] = repo.head.commit.hexsha
|
||||||
|
|
||||||
steps.extend(generic_linux(
|
steps.extend(generic_linux(
|
||||||
os.getenv('ph_projects', 'llvm;clang;clang-tools-extra;libc;libcxx;libcxxabi;lld;libunwind;mlir;openmp;polly;flang'),
|
os.getenv('ph_projects', 'llvm;clang;clang-tools-extra;libc;libcxx;libcxxabi;lld;libunwind;mlir;openmp;polly;flang'),
|
||||||
False))
|
False))
|
||||||
|
@ -39,10 +54,14 @@ if __name__ == '__main__':
|
||||||
os.getenv('ph_projects', 'llvm;clang;clang-tools-extra;libc;libcxx;libcxxabi;lld;libunwind;mlir;polly;flang')))
|
os.getenv('ph_projects', 'llvm;clang;clang-tools-extra;libc;libcxx;libcxxabi;lld;libunwind;mlir;polly;flang')))
|
||||||
|
|
||||||
if os.getenv('ph_skip_generated') is None:
|
if os.getenv('ph_skip_generated') is None:
|
||||||
|
e = os.environ.copy()
|
||||||
|
# BUILDKITE_COMMIT might be an alias, e.g. "HEAD". Resolve it to make the build hermetic.
|
||||||
|
e["BUILDKITE_COMMIT"] = repo.head.commit.hexsha
|
||||||
for gen in steps_generators:
|
for gen in steps_generators:
|
||||||
steps.extend(from_shell_output(gen))
|
steps.extend(from_shell_output(gen, env=e))
|
||||||
|
|
||||||
notify = []
|
notify = []
|
||||||
for e in notify_emails:
|
for e in notify_emails:
|
||||||
notify.append({'email': e})
|
notify.append({'email': e})
|
||||||
|
extend_steps_env(steps, env)
|
||||||
print(yaml.dump({'steps': steps, 'notify': notify}))
|
print(yaml.dump({'steps': steps, 'notify': notify}))
|
||||||
|
|
|
@ -13,13 +13,15 @@
|
||||||
# See the License for the specific language governing permissions and
|
# See the License for the specific language governing permissions and
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
|
|
||||||
|
# Script runs in checked out llvm-project directory.
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
|
|
||||||
from buildkite_utils import annotate, feedback_url, set_metadata
|
from buildkite_utils import annotate, feedback_url, set_metadata
|
||||||
from choose_projects import ChooseProjects
|
from choose_projects import ChooseProjects
|
||||||
import git
|
import git
|
||||||
from steps import generic_linux, generic_windows, from_shell_output, checkout_scripts, bazel
|
from steps import generic_linux, generic_windows, from_shell_output, checkout_scripts, bazel, extend_steps_env
|
||||||
import yaml
|
import yaml
|
||||||
|
|
||||||
steps_generators = [
|
steps_generators = [
|
||||||
|
@ -42,8 +44,14 @@ if __name__ == '__main__':
|
||||||
set_metadata('ph_buildable_diff', os.getenv("ph_buildable_diff"))
|
set_metadata('ph_buildable_diff', os.getenv("ph_buildable_diff"))
|
||||||
set_metadata('ph_buildable_revision', os.getenv('ph_buildable_revision'))
|
set_metadata('ph_buildable_revision', os.getenv('ph_buildable_revision'))
|
||||||
set_metadata('ph_build_id', os.getenv("ph_build_id"))
|
set_metadata('ph_build_id', os.getenv("ph_build_id"))
|
||||||
# List all affected projects.
|
|
||||||
|
env = {}
|
||||||
|
for e in os.environ:
|
||||||
|
if e.startswith('ph_'):
|
||||||
|
env[e] = os.getenv(e)
|
||||||
repo = git.Repo('.')
|
repo = git.Repo('.')
|
||||||
|
env['ph_commit_sha'] = repo.head.commit.hexsha
|
||||||
|
# List all affected projects.
|
||||||
patch = repo.git.diff("HEAD~1")
|
patch = repo.git.diff("HEAD~1")
|
||||||
cp = ChooseProjects('.')
|
cp = ChooseProjects('.')
|
||||||
modified_files = cp.get_changed_files(patch)
|
modified_files = cp.get_changed_files(patch)
|
||||||
|
@ -71,8 +79,11 @@ if __name__ == '__main__':
|
||||||
steps.extend(generic_windows(';'.join(sorted(windows_projects))))
|
steps.extend(generic_windows(';'.join(sorted(windows_projects))))
|
||||||
# Add custom checks.
|
# Add custom checks.
|
||||||
if os.getenv('ph_skip_generated') is None:
|
if os.getenv('ph_skip_generated') is None:
|
||||||
|
e = os.environ.copy()
|
||||||
|
# BUILDKITE_COMMIT might be an alias, e.g. "HEAD". Resolve it to make the build hermetic.
|
||||||
|
e["BUILDKITE_COMMIT"] = repo.head.commit.hexsha
|
||||||
for gen in steps_generators:
|
for gen in steps_generators:
|
||||||
steps.extend(from_shell_output(gen))
|
steps.extend(from_shell_output(gen, env=e))
|
||||||
steps.extend(bazel(modified_files))
|
steps.extend(bazel(modified_files))
|
||||||
|
|
||||||
if phid is None:
|
if phid is None:
|
||||||
|
@ -95,4 +106,5 @@ if __name__ == '__main__':
|
||||||
}
|
}
|
||||||
steps.append(report_step)
|
steps.append(report_step)
|
||||||
|
|
||||||
|
extend_steps_env(steps, env)
|
||||||
print(yaml.dump({'steps': steps}))
|
print(yaml.dump({'steps': steps}))
|
||||||
|
|
|
@ -17,7 +17,7 @@ import io
|
||||||
import json
|
import json
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
from typing import List, Set
|
from typing import List, Set, Dict
|
||||||
|
|
||||||
from exec_utils import watch_shell
|
from exec_utils import watch_shell
|
||||||
import yaml
|
import yaml
|
||||||
|
@ -153,7 +153,7 @@ def generic_windows(projects: str) -> List:
|
||||||
return [windows_buld_step]
|
return [windows_buld_step]
|
||||||
|
|
||||||
|
|
||||||
def from_shell_output(command) -> []:
|
def from_shell_output(command, **kwargs) -> []:
|
||||||
"""
|
"""
|
||||||
Executes shell command and parses stdout as multidoc yaml file, see
|
Executes shell command and parses stdout as multidoc yaml file, see
|
||||||
https://buildkite.com/docs/agent/v3/cli-pipeline#pipeline-format.
|
https://buildkite.com/docs/agent/v3/cli-pipeline#pipeline-format.
|
||||||
|
@ -165,7 +165,7 @@ def from_shell_output(command) -> []:
|
||||||
logging.debug(f'invoking "{path}"')
|
logging.debug(f'invoking "{path}"')
|
||||||
out = io.BytesIO()
|
out = io.BytesIO()
|
||||||
err = io.BytesIO()
|
err = io.BytesIO()
|
||||||
rc = watch_shell(out.write, err.write, path)
|
rc = watch_shell(out.write, err.write, path, **kwargs)
|
||||||
logging.debug(f'exit code: {rc}, stdout: "{out.getvalue().decode()}", stderr: "{err.getvalue().decode()}"')
|
logging.debug(f'exit code: {rc}, stdout: "{out.getvalue().decode()}", stderr: "{err.getvalue().decode()}"')
|
||||||
steps = []
|
steps = []
|
||||||
if rc != 0:
|
if rc != 0:
|
||||||
|
@ -210,3 +210,21 @@ def checkout_scripts(target_os: str, scripts_refspec: str) -> []:
|
||||||
'pip install -q -r $${SRC}/scripts/requirements.txt',
|
'pip install -q -r $${SRC}/scripts/requirements.txt',
|
||||||
'cd "$$BUILDKITE_BUILD_CHECKOUT_PATH"',
|
'cd "$$BUILDKITE_BUILD_CHECKOUT_PATH"',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def extend_dict(target: Dict, extra: Dict) -> Dict:
|
||||||
|
if not target:
|
||||||
|
return extra
|
||||||
|
for k in extra:
|
||||||
|
if k in target:
|
||||||
|
continue
|
||||||
|
target[k] = extra[k]
|
||||||
|
return target
|
||||||
|
|
||||||
|
|
||||||
|
def extend_steps_env(steps: List[Dict], env: Dict):
|
||||||
|
for s in steps:
|
||||||
|
if 'commands' in s:
|
||||||
|
s['env'] = extend_dict(s.get('env'), env)
|
||||||
|
if 'build' in s:
|
||||||
|
s['build']['env'] = extend_dict(s['build'].get('env'), env)
|
||||||
|
|
71
scripts/sync_fork.py
Executable file
71
scripts/sync_fork.py
Executable file
|
@ -0,0 +1,71 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
# Copyright 2021 Google LLC
|
||||||
|
#
|
||||||
|
# Licensed under the the Apache License v2.0 with LLVM Exceptions (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# https://llvm.org/LICENSE.txt
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import logging
|
||||||
|
import os
|
||||||
|
from typing import List
|
||||||
|
import backoff
|
||||||
|
import git
|
||||||
|
|
||||||
|
"""URL of upstream LLVM repository."""
|
||||||
|
LLVM_GITHUB_URL = 'ssh://git@github.com/llvm/llvm-project'
|
||||||
|
FORK_REMOTE_URL = 'ssh://git@github.com/llvm-premerge-tests/llvm-project'
|
||||||
|
|
||||||
|
|
||||||
|
@backoff.on_exception(backoff.expo, Exception, max_tries=5, logger='', factor=3)
|
||||||
|
def sync_fork(path: str, branches: List[str]):
|
||||||
|
if not os.path.isdir(path):
|
||||||
|
logging.info(f'{path} does not exist, cloning repository...')
|
||||||
|
repo = git.Repo.clone_from(FORK_REMOTE_URL, path)
|
||||||
|
else:
|
||||||
|
logging.info('repository exist, will reuse')
|
||||||
|
repo = git.Repo(path) # type: git.Repo
|
||||||
|
repo.remote('origin').set_url(FORK_REMOTE_URL)
|
||||||
|
os.chdir(path)
|
||||||
|
logging.info(f'working dir {os.getcwd()}')
|
||||||
|
logging.info(f'Syncing origin and upstream branches {branches}')
|
||||||
|
if 'upstream' not in repo.remotes:
|
||||||
|
repo.create_remote('upstream', url=LLVM_GITHUB_URL)
|
||||||
|
repo.git.fetch('--all')
|
||||||
|
for b in branches:
|
||||||
|
logging.info(f'syncing branch {b}')
|
||||||
|
if find_commit(repo, b) is None:
|
||||||
|
logging.info(f'new head {b}')
|
||||||
|
repo.create_head(b)
|
||||||
|
h = repo.heads[b]
|
||||||
|
h.checkout()
|
||||||
|
repo.git.reset('--hard', f'upstream/{b}')
|
||||||
|
repo.git.clean('-ffxdq')
|
||||||
|
repo.git.push('origin', h)
|
||||||
|
repo.git.push('origin', '--tags')
|
||||||
|
|
||||||
|
|
||||||
|
def find_commit(repo, rev):
|
||||||
|
try:
|
||||||
|
return repo.commit(rev)
|
||||||
|
except:
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
parser = argparse.ArgumentParser(description='Sync LLVM fork with origina rpo.')
|
||||||
|
parser.add_argument('--path', type=str, help='repository path', required=True)
|
||||||
|
parser.add_argument('--branch', nargs='+', help='branch to sync (specify multiple to sync many branches)',
|
||||||
|
required=True)
|
||||||
|
parser.add_argument('--log-level', type=str, default='INFO')
|
||||||
|
args = parser.parse_args()
|
||||||
|
logging.basicConfig(level=args.log_level, format='%(levelname)-7s %(message)s')
|
||||||
|
sync_fork(args.path, args.branch)
|
Loading…
Reference in a new issue