aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNikita Kozlovskiy <nikitka@gmail.com>2023-10-10 16:14:03 +0300
committernkozlovskiy <nmk@ydb.tech>2023-10-10 16:45:28 +0300
commitd039bfa4e3a41b10fc8d1fd06d125842dcf94200 (patch)
treef2b24af746fbbfb9109b1d7994b4da23dda03400
parent7722c2d79d4f144aa037357ef2564168286b759e (diff)
downloadydb-d039bfa4e3a41b10fc8d1fd06d125842dcf94200.tar.gz
add ya make and test support
add ya make and test support Pull Request resolved: https://github.com/ydb-platform/ydb/pull/392
-rw-r--r--.github/actions/build_ya/action.yml68
-rw-r--r--.github/actions/s3cmd/action.yml39
-rw-r--r--.github/actions/test_ya/action.yml184
-rwxr-xr-x.github/scripts/tests/generate-summary.py46
-rw-r--r--.github/scripts/tests/junit_utils.py11
-rwxr-xr-x.github/scripts/tests/transform-ya-junit.py209
-rw-r--r--.github/workflows/build_and_test_ya.yml72
-rw-r--r--.github/workflows/build_and_test_ya_ondemand.yml107
-rw-r--r--.github/workflows/build_and_test_ya_provisioned.yml45
-rw-r--r--.mapping.json7
10 files changed, 773 insertions, 15 deletions
diff --git a/.github/actions/build_ya/action.yml b/.github/actions/build_ya/action.yml
new file mode 100644
index 0000000000..273f21a1b2
--- /dev/null
+++ b/.github/actions/build_ya/action.yml
@@ -0,0 +1,68 @@
+name: Build (ya make)
+description: Build targets
+inputs:
+ build_target:
+ required: false
+ description: "build target"
+ sanitizer:
+ required: false
+ description: "sanitizer type (address, memory, thread, undefined, leak)"
+
+ bazel_remote_uri:
+ required: false
+ description: "bazel-remote endpoint"
+ bazel_remote_username:
+ required: false
+ description: "bazel-remote username"
+ bazel_remote_password:
+ required: false
+ description: "bazel-remote password"
+
+runs:
+ using: "composite"
+ steps:
+ - name: Init
+ id: init
+ shell: bash
+ run: |
+ echo "SHELLOPTS=xtrace" >> $GITHUB_ENV
+ export TMP_DIR=$(pwd)/tmp_build
+ echo "TMP_DIR=$TMP_DIR" >> $GITHUB_ENV
+ rm -rf $TMP_DIR && mkdir $TMP_DIR
+
+ - name: build
+ shell: bash
+ run: |
+ extra_params=()
+
+ if [ ! -z "${{ inputs.build_target }}" ]; then
+ extra_params+=(--target="${{ inputs.build_target }}")
+ fi
+
+ if [ ! -z "${{ inputs.sanitizer }}" ] && [ "${{ inputs.sanitizer }}" != "none" ]; then
+ extra_params+=(--sanitize="${{ inputs.sanitizer }}")
+ fi
+
+ if [ ! -z "${{ inputs.bazel_remote_uri }}" ]; then
+ extra_params+=(--bazel-remote-store)
+ extra_params+=(--bazel-remote-base-uri "${{ inputs.bazel_remote_uri }}")
+ fi
+
+ if [ ! -z "${{ inputs.bazel_remote_username }}" ]; then
+ extra_params+=(--bazel-remote-username "${{ inputs.bazel_remote_username }}")
+ extra_params+=(--bazel-remote-password "${{ inputs.bazel_remote_password }}")
+ extra_params+=(--bazel-remote-put --add-result .o --yt-replace-result --yt-replace-result-rm-binaries)
+ fi
+
+ ./ya make --build relwithdebinfo --force-build-depends -D'BUILD_LANGUAGES=CPP PY3' -T --stat \
+ --log-file "$TMP_DIR/ya_log.txt" --evlog-file "$TMP_DIR/ya_evlog.jsonl" \
+ --dump-graph --dump-graph-to-file "$TMP_DIR/ya_graph.json" \
+ "${extra_params[@]}"
+
+ - name: sync logs to s3
+ if: always()
+ shell: bash
+ run: |
+ echo "::group::s3-sync"
+ s3cmd sync --acl-private --no-progress --stats --no-check-md5 "$TMP_DIR/" "$S3_BUCKET_PATH/build_logs/"
+ echo "::endgroup::"
diff --git a/.github/actions/s3cmd/action.yml b/.github/actions/s3cmd/action.yml
new file mode 100644
index 0000000000..6f69695f93
--- /dev/null
+++ b/.github/actions/s3cmd/action.yml
@@ -0,0 +1,39 @@
+name: configure s3cmd
+description: configure s3cmd
+inputs:
+ s3_key_id:
+ required: true
+ description: "s3 key id"
+ s3_key_secret:
+ required: true
+ description: "s3 key secret"
+ s3_bucket:
+ required: true
+ description: "s3 bucket"
+ s3_endpoint:
+ required: true
+ description: "s3 endpoint"
+ log_suffix:
+ required: true
+ description: "log suffix"
+runs:
+ using: "composite"
+ steps:
+ - name: configure s3cmd
+ shell: bash
+ run: |
+ export S3CMD_CONFIG=$(mktemp)
+ echo "S3CMD_CONFIG=$S3CMD_CONFIG" >> $GITHUB_ENV
+ cat <<EOF > $S3CMD_CONFIG
+ [default]
+ access_key = ${s3_key_id}
+ secret_key = ${s3_secret_access_key}
+ bucket_location = ru-central1
+ host_base = storage.yandexcloud.net
+ host_bucket = %(bucket)s.storage.yandexcloud.net
+ EOF
+ echo "S3_BUCKET_PATH=s3://${{ inputs.s3_bucket }}/${{ github.repository }}/${{github.workflow}}/${{ github.run_id }}/${{inputs.log_suffix}}" >> $GITHUB_ENV
+ echo "S3_URL_PREFIX=${{inputs.s3_endpoint}}/${{inputs.s3_bucket}}/${{ github.repository }}/${{github.workflow}}/${{github.run_id}}/${{inputs.log_suffix}}" >> $GITHUB_ENV
+ env:
+ s3_key_id: ${{ inputs.s3_key_id }}
+ s3_secret_access_key: ${{ inputs.s3_key_secret }}
diff --git a/.github/actions/test_ya/action.yml b/.github/actions/test_ya/action.yml
new file mode 100644
index 0000000000..8fabe466fd
--- /dev/null
+++ b/.github/actions/test_ya/action.yml
@@ -0,0 +1,184 @@
+name: Run tests (ya make)
+description: Run tests using ya make
+inputs:
+ build_target:
+ required: false
+ description: "build target"
+
+ sanitizer:
+ required: false
+ description: "sanitizer type (address, memory, thread, undefined, leak)"
+
+ log_suffix:
+ required: true
+ description: "log suffix"
+ test_threads:
+ required: false
+ default: "28"
+ description: "Test threads count"
+
+ testman_token:
+ required: false
+ description: "test manager auth token"
+ testman_url:
+ required: false
+ description: "test manager endpoint"
+ testman_project_id:
+ required: false
+ description: "test manager project id"
+runs:
+ using: "composite"
+ steps:
+ - name: Init
+ id: init
+ shell: bash
+ run: |
+ echo "SHELLOPTS=xtrace" >> $GITHUB_ENV
+ export TMP_DIR=$(pwd)/tmp
+ echo "TMP_DIR=$TMP_DIR" >> $GITHUB_ENV
+ echo "OUT_DIR=$TMP_DIR/out" >> $GITHUB_ENV
+ echo "ARTIFACTS_DIR=$TMP_DIR/artifacts" >> $GITHUB_ENV
+ echo "JUNIT_REPORT_XML=$TMP_DIR/junit.xml" >> $GITHUB_ENV
+ echo "TESTMO_TOKEN=${{ inputs.testman_token }}" >> $GITHUB_ENV
+ echo "TESTMO_URL=${{ inputs.testman_url }}" >> $GITHUB_ENV
+ echo "SUMMARY_LINKS=$(mktemp)" >> $GITHUB_ENV
+
+ - name: prepare
+ shell: bash
+ run: |
+ rm -rf $TMP_DIR $JUNIT_REPORT_XML
+ mkdir -p $TMP_DIR $OUT_DIR $ARTIFACTS_DIR
+
+
+ - name: Install Node required for Testmo CLI
+ uses: actions/setup-node@v3
+ with:
+ node-version: 19
+
+ - name: Install Testmo CLI
+ shell: bash
+ run: npm install -g @testmo/testmo-cli
+ - name: Test history run create
+ id: th
+ if: inputs.testman_token
+ shell: bash
+ env:
+ PR_NUMBER: ${{ github.event.number }}
+ run: |
+ RUN_URL="$GITHUB_SERVER_URL/$GITHUB_REPOSITORY/actions/runs/$GITHUB_RUN_ID"
+ BRANCH_TAG="$GITHUB_REF_NAME"
+ TESTMO_SOURCE="${{ inputs.log_suffix }}"
+ TESTMO_SOURCE="${TESTMO_SOURCE/_/-}"
+
+ case $GITHUB_EVENT_NAME in
+ workflow_dispatch)
+ TESTMO_RUN_NAME="${{ github.run_id }} manual"
+ EXTRA_TAG="manual"
+ ;;
+ pull_request | pull_request_target)
+ TESTMO_RUN_NAME="${{ github.run_id }} PR #${PR_NUMBER}"
+ EXTRA_TAG="pr"
+ BRANCH_TAG=""
+ ;;
+ schedule)
+ TESTMO_RUN_NAME="${{ github.run_id }} schedule"
+ EXTRA_TAG="schedule"
+ ;;
+ *)
+ TESTMO_RUN_NAME="${{ github.run_id }}"
+ EXTRA_TAG=""
+ ;;
+ esac
+
+ testmo automation:resources:add-link --name build --url "$RUN_URL" --resources testmo.json
+ testmo automation:resources:add-field --name git-sha --type string --value "${GITHUB_SHA:0:7}" --resources testmo.json
+ testmo automation:run:create --instance "$TESTMO_URL" --project-id "${{ inputs.testman_project_id }}" --name "$TESTMO_RUN_NAME" \
+ --source "$TESTMO_SOURCE" --resources testmo.json \
+ --tags "$BRANCH_TAG" --tags "$EXTRA_TAG" | \
+ echo "runid=$(cat)" >> $GITHUB_OUTPUT
+
+ - name: Print test history link
+ shell: bash
+ run: |
+ echo "10 [Test history](${TESTMO_URL}/automation/runs/view/${{steps.th.outputs.runid}})" >> $SUMMARY_LINKS
+
+ - name: ya test
+ shell: bash
+ run: |
+ extra_params=()
+
+ if [ ! -z "${{ inputs.build_target }}" ]; then
+ extra_params+=(--target="${{ inputs.build_target }}")
+ fi
+
+ if [ ! -z "${{ inputs.sanitizer }}" ] && [ "${{ inputs.sanitizer }}" != "none" ]; then
+ extra_params+=(--sanitize="${{ inputs.sanitizer }}")
+ fi
+
+ ./ya test -A --build relwithdebinfo -D'BUILD_LANGUAGES=CPP PY3' --test-threads "${{ inputs.test_threads }}" \
+ --do-not-output-stderrs -T \
+ --junit "$JUNIT_REPORT_XML" --output "$OUT_DIR" "${extra_params[@]}" || (
+ RC=$?
+ if [ $RC == 10 ]; then
+ echo "ya test returned failed tests status, recovering.."
+ else
+ exit $RC
+ fi
+ )
+
+ - name: postprocess junit report
+ shell: bash
+ run: |
+ .github/scripts/tests/transform-ya-junit.py -i \
+ --mu .github/config/muted_test.txt \
+ --mf .github/config/muted_functest.txt \
+ --ya-out "$OUT_DIR" \
+ --log-url-prefix "$S3_URL_PREFIX/logs/" \
+ --log-out-dir "$ARTIFACTS_DIR/logs/" \
+ "$JUNIT_REPORT_XML"
+
+ - name: write tests summary
+ if: always()
+ shell: bash
+ env:
+ GITHUB_TOKEN: ${{ github.token }}
+ run: |
+
+ cat $SUMMARY_LINKS | python3 -c 'import sys; print(" | ".join([v for _, v in sorted([l.strip().split(" ", 1) for l in sys.stdin], key=lambda a: (int(a[0]), a))]))' >> $GITHUB_STEP_SUMMARY
+
+ mkdir $ARTIFACTS_DIR/summary/
+
+ .github/scripts/tests/generate-summary.py \
+ --summary-out-path $ARTIFACTS_DIR/summary/ \
+ --summary-url-prefix $S3_URL_PREFIX/summary/ \
+ "Tests" ya-test.html "$JUNIT_REPORT_XML"
+
+
+ - name: Unit test history upload results
+ if: always() && inputs.testman_token
+ shell: bash
+ run: |
+ testmo automation:run:submit-thread \
+ --instance "$TESTMO_URL" --run-id ${{ steps.th.outputs.runid }} \
+ --results "$JUNIT_REPORT_XML"
+
+ - name: sync test results to s3
+ if: always()
+ shell: bash
+ run: |
+ echo "::group::s3-sync"
+ s3cmd sync --follow-symlinks --acl-public --no-progress --stats --no-check-md5 "$ARTIFACTS_DIR/" "$S3_BUCKET_PATH/"
+ echo "::endgroup::"
+
+
+ - name: Test history run complete
+ if: always() && inputs.testman_token
+ shell: bash
+ run: |
+ testmo automation:run:complete --instance "$TESTMO_URL" --run-id ${{ steps.th.outputs.runid }}
+
+ - name: check test results
+ shell: bash
+ run: |
+ .github/scripts/tests/fail-checker.py "$JUNIT_REPORT_XML"
+ \ No newline at end of file
diff --git a/.github/scripts/tests/generate-summary.py b/.github/scripts/tests/generate-summary.py
index fca597e969..6cd3db8aaa 100755
--- a/.github/scripts/tests/generate-summary.py
+++ b/.github/scripts/tests/generate-summary.py
@@ -136,6 +136,9 @@ class TestSummary:
self.is_failed |= line.is_failed
self.lines.append(line)
+ def render_line(self, items):
+ return f"| {' | '.join(items)} |"
+
def render(self, add_footnote=False):
github_srv = os.environ.get("GITHUB_SERVER_URL", "https://github.com")
repo = os.environ.get("GITHUB_REPOSITORY", "ydb-platform/ydb")
@@ -144,25 +147,38 @@ class TestSummary:
footnote = "[^1]" if add_footnote else f'<sup>[?]({footnote_url} "All mute rules are defined here")</sup>'
+ columns = [
+ "TESTS", "PASSED", "ERRORS", "FAILED", "SKIPPED", f"MUTED{footnote}"
+ ]
+
+ need_first_column = len(self.lines) > 1
+
+ if need_first_column:
+ columns.insert(0, "")
+
result = [
- f"| | TESTS | PASSED | ERRORS | FAILED | SKIPPED | MUTED{footnote} |",
- "| :--- | ---: | -----: | -----: | -----: | ------: | ----: |",
+ self.render_line(columns),
]
+
+ if need_first_column:
+ result.append(self.render_line([':---'] + ['---:'] * (len(columns) - 1)))
+ else:
+ result.append(self.render_line(['---:'] * len(columns)))
+
for line in self.lines:
report_url = line.report_url
- result.append(
- " | ".join(
- [
- line.title,
- render_pm(line.test_count, f"{report_url}", 0),
- render_pm(line.passed, f"{report_url}#PASS", 0),
- render_pm(line.errors, f"{report_url}#ERROR", 0),
- render_pm(line.failed, f"{report_url}#FAIL", 0),
- render_pm(line.skipped, f"{report_url}#SKIP", 0),
- render_pm(line.muted, f"{report_url}#MUTE", 0),
- ]
- )
- )
+ row = []
+ if need_first_column:
+ row.append(line.title)
+ row.extend([
+ render_pm(line.test_count, f"{report_url}", 0),
+ render_pm(line.passed, f"{report_url}#PASS", 0),
+ render_pm(line.errors, f"{report_url}#ERROR", 0),
+ render_pm(line.failed, f"{report_url}#FAIL", 0),
+ render_pm(line.skipped, f"{report_url}#SKIP", 0),
+ render_pm(line.muted, f"{report_url}#MUTE", 0),
+ ])
+ result.append(self.render_line(row))
if add_footnote:
result.append("")
diff --git a/.github/scripts/tests/junit_utils.py b/.github/scripts/tests/junit_utils.py
index b4ec72e406..eca82b3956 100644
--- a/.github/scripts/tests/junit_utils.py
+++ b/.github/scripts/tests/junit_utils.py
@@ -18,6 +18,13 @@ def add_junit_link_property(testcase, name, url):
def add_junit_property(testcase, name, value):
props = get_or_create_properties(testcase)
+
+ # remove existing property if exists
+ for item in props.findall("property"):
+ if item.get('name') == name:
+ props.remove(item)
+ break
+
props.append(ET.Element("property", dict(name=name, value=value)))
@@ -92,3 +99,7 @@ def iter_xml_files(folder_or_file):
for suite in suites:
for case in suite.findall("testcase"):
yield fn, suite, case
+
+
+def is_faulty_testcase(testcase):
+ return testcase.find("failure") is not None or testcase.find("error") is not None
diff --git a/.github/scripts/tests/transform-ya-junit.py b/.github/scripts/tests/transform-ya-junit.py
new file mode 100755
index 0000000000..4ac7951f9b
--- /dev/null
+++ b/.github/scripts/tests/transform-ya-junit.py
@@ -0,0 +1,209 @@
+#!/usr/bin/env python3
+import argparse
+import re
+import json
+import os
+import sys
+from xml.etree import ElementTree as ET
+from mute_utils import mute_target, pattern_to_re
+from junit_utils import add_junit_link_property, is_faulty_testcase
+
+
+def log_print(*args, **kwargs):
+ print(*args, file=sys.stderr, **kwargs)
+
+
+class YaMuteCheck:
+ def __init__(self):
+ self.regexps = set()
+
+ def add_unittest(self, fn):
+ with open(fn, "r") as fp:
+ for line in fp:
+ line = line.strip()
+ path, rest = line.split("/")
+ path = path.replace("-", "/")
+ rest = rest.replace("::", ".")
+ self.populate(f"{path}/{rest}")
+
+ def add_functest(self, fn):
+ with open(fn, "r") as fp:
+ for line in fp:
+ line = line.strip()
+ line = line.replace("::", ".")
+ self.populate(line)
+
+ def populate(self, line):
+ pattern = pattern_to_re(line)
+
+ try:
+ self.regexps.add(re.compile(pattern))
+ except re.error:
+ log_print(f"Unable to compile regex {pattern!r}")
+
+ def __call__(self, suitename, testname):
+ for r in self.regexps:
+ if r.match(f"{suitename}/{testname}"):
+ return True
+ return False
+
+
+class YTestReportTrace:
+ def __init__(self, out_root):
+ self.out_root = out_root
+ self.traces = {}
+
+ def load(self, subdir):
+ test_results_dir = f"{subdir}/test-results/"
+ for folder in os.listdir(os.path.join(self.out_root, test_results_dir)):
+ fn = os.path.join(self.out_root, test_results_dir, folder, "ytest.report.trace")
+
+ if not os.path.isfile(fn):
+ continue
+
+ with open(fn, "r") as fp:
+ for line in fp:
+ event = json.loads(line.strip())
+ if event["name"] == "subtest-finished":
+ event = event["value"]
+ cls = event["class"]
+ subtest = event["subtest"]
+ cls = cls.replace("::", ".")
+ self.traces[(cls, subtest)] = event
+
+ def has(self, cls, name):
+ return (cls, name) in self.traces
+
+ def get_logs(self, cls, name):
+ trace = self.traces.get((cls, name))
+
+ if not trace:
+ return {}
+
+ logs = trace["logs"]
+
+ result = {}
+ for k, path in logs.items():
+ if k == "logsdir":
+ continue
+
+ result[k] = path.replace("$(BUILD_ROOT)", self.out_root)
+
+ return result
+
+
+def filter_empty_logs(logs):
+ result = {}
+ for k, v in logs.items():
+ if os.stat(v).st_size == 0:
+ continue
+ result[k] = v
+ return result
+
+
+def save_log(build_root, fn, out_dir, log_url_prefix, trunc_size):
+ fpath = os.path.relpath(fn, build_root)
+
+ if out_dir is not None:
+ out_fn = os.path.join(out_dir, fpath)
+ fsize = os.stat(fn).st_size
+
+ out_fn_dir = os.path.dirname(out_fn)
+
+ if not os.path.isdir(out_fn_dir):
+ os.makedirs(out_fn_dir, 0o700)
+
+ if trunc_size and fsize > trunc_size:
+ with open(fn, "rb") as in_fp:
+ in_fp.seek(fsize - trunc_size)
+ log_print(f"truncate {out_fn} to {trunc_size}")
+ with open(out_fn, "wb") as out_fp:
+ while 1:
+ buf = in_fp.read(8192)
+ if not buf:
+ break
+ out_fp.write(buf)
+ else:
+ os.symlink(fn, out_fn)
+
+ return f"{log_url_prefix}{fpath}"
+
+
+def transform(fp, mute_check: YaMuteCheck, ya_out_dir, save_inplace, log_url_prefix, log_out_dir, log_trunc_size):
+ tree = ET.parse(fp)
+ root = tree.getroot()
+
+ for suite in root.findall("testsuite"):
+ suite_name = suite.get("name")
+ traces = YTestReportTrace(ya_out_dir)
+ traces.load(suite_name)
+
+ for case in suite.findall("testcase"):
+ test_name = case.get("name")
+ case.set("classname", suite_name)
+
+ is_fail = is_faulty_testcase(case)
+
+ if mute_check(suite_name, test_name):
+ log_print("mute", suite_name, test_name)
+ mute_target(case)
+
+ if is_fail and "." in test_name:
+ test_cls, test_method = test_name.rsplit(".", maxsplit=1)
+ logs = filter_empty_logs(traces.get_logs(test_cls, test_method))
+
+ if logs:
+ log_print(f"add {list(logs.keys())!r} properties for {test_cls}.{test_method}")
+ for name, fn in logs.items():
+ url = save_log(ya_out_dir, fn, log_out_dir, log_url_prefix, log_trunc_size)
+ add_junit_link_property(case, name, url)
+
+ if save_inplace:
+ tree.write(fp.name)
+ else:
+ ET.indent(root)
+ print(ET.tostring(root, encoding="unicode"))
+
+
+def main():
+ parser = argparse.ArgumentParser()
+ parser.add_argument(
+ "-i", action="store_true", dest="save_inplace", default=False, help="modify input file in-place"
+ )
+ parser.add_argument("--mu", help="unittest mute config")
+ parser.add_argument("--mf", help="functional test mute config")
+ parser.add_argument("--log-url-prefix", default="./", help="url prefix for logs")
+ parser.add_argument("--log-out-dir", help="symlink logs to specific directory")
+ parser.add_argument(
+ "--log-truncate-size",
+ dest="log_trunc_size",
+ type=int,
+ default=134217728,
+ help="truncate log after specific size, 0 disables truncation",
+ )
+ parser.add_argument("--ya-out", help="ya make output dir (for searching logs and artifacts)")
+ parser.add_argument("in_file", type=argparse.FileType("r"))
+
+ args = parser.parse_args()
+
+ mute_check = YaMuteCheck()
+
+ if args.mu:
+ mute_check.add_unittest(args.mu)
+
+ if args.mf:
+ mute_check.add_functest(args.mf)
+
+ transform(
+ args.in_file,
+ mute_check,
+ args.ya_out,
+ args.save_inplace,
+ args.log_url_prefix,
+ args.log_out_dir,
+ args.log_trunc_size,
+ )
+
+
+if __name__ == "__main__":
+ main()
diff --git a/.github/workflows/build_and_test_ya.yml b/.github/workflows/build_and_test_ya.yml
new file mode 100644
index 0000000000..6d16be296f
--- /dev/null
+++ b/.github/workflows/build_and_test_ya.yml
@@ -0,0 +1,72 @@
+name: Ya-Build-and-Test
+
+on:
+ workflow_call:
+ inputs:
+ build_target:
+ type: string
+ default: "ydb/"
+ description: "limit build and test to specific target"
+ sanitizer:
+ type: string
+ default: "none"
+ description: "sanitizer type"
+ runner_kind:
+ type: string
+ required: true
+ description: "self-hosted or provisioned"
+ runner_label:
+ type: string
+ default: "linux"
+ description: "runner label"
+ run_build:
+ type: boolean
+ default: true
+ description: "run build"
+ run_tests:
+ type: boolean
+ default: true
+ description: "run tests"
+ log_suffix:
+ type: string
+ required: true
+ description: "suffix for current build. uses as testmo source and s3 subfolder"
+
+
+jobs:
+ main:
+ name: Build and test
+ runs-on: [ self-hosted, "${{ inputs.runner_kind }}", "${{ inputs.runner_label }}" ]
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v3
+
+ - name: Prepare s3cmd
+ uses: ./.github/actions/s3cmd
+ with:
+ s3_bucket: ${{ vars.AWS_BUCKET }}
+ s3_endpoint: ${{ vars.AWS_ENDPOINT }}
+ s3_key_id: ${{ secrets.AWS_KEY_ID }}
+ s3_key_secret: ${{ secrets.AWS_KEY_VALUE }}
+ log_suffix: ${{ inputs.log_suffix }}
+
+ - name: Build
+ uses: ./.github/actions/build_ya
+ if: inputs.run_build
+ with:
+ build_target: ${{ inputs.build_target }}
+ sanitizer: ${{ inputs.sanitizer }}
+ bazel_remote_uri: ${{ vars.REMOTE_CACHE_URL_YA || '' }}
+ bazel_remote_username: ${{ secrets.REMOTE_CACHE_USERNAME }}
+ bazel_remote_password: ${{ secrets.REMOTE_CACHE_PASSWORD }}
+
+ - name: Run tests
+ uses: ./.github/actions/test_ya
+ if: inputs.run_tests
+ with:
+ build_target: ${{ inputs.build_target }}
+ sanitizer: ${{ inputs.sanitizer }}
+ log_suffix: ${{ inputs.log_suffix }}
+ testman_token: ${{ secrets.TESTMO_TOKEN }}
+ testman_url: ${{ vars.TESTMO_URL }}
+ testman_project_id: ${{ vars.TESTMO_PROJECT_ID }}
diff --git a/.github/workflows/build_and_test_ya_ondemand.yml b/.github/workflows/build_and_test_ya_ondemand.yml
new file mode 100644
index 0000000000..6ede1a42d5
--- /dev/null
+++ b/.github/workflows/build_and_test_ya_ondemand.yml
@@ -0,0 +1,107 @@
+name: Ya-Build-and-Test-On-demand
+
+on:
+ workflow_dispatch:
+ inputs:
+ image:
+ type: string
+ default: fd8earpjmhevh8h6ug5o
+ description: "VM image"
+ build_target:
+ type: string
+ default: "ydb/"
+ description: "limit build and test to specific target"
+ sanitizer:
+ type: choice
+ default: "none"
+ description: "sanitizer type"
+ options:
+ - none
+ - address
+ - memory
+ - thread
+ - undefined
+ - leak
+ run_build:
+ type: boolean
+ default: true
+ description: "run build"
+ run_tests:
+ type: boolean
+ default: true
+ description: "run tests"
+
+jobs:
+ provide-runner:
+ name: Start self-hosted YC runner
+ timeout-minutes: 5
+ runs-on: ubuntu-latest
+ outputs:
+ label: ${{ steps.start-yc-runner.outputs.label }}
+ instance-id: ${{ steps.start-yc-runner.outputs.instance-id }}
+ steps:
+ - name: Start YC runner
+ id: start-yc-runner
+ uses: yc-actions/yc-github-runner@v1
+ with:
+ mode: start
+ yc-sa-json-credentials: ${{ secrets.YC_SA_JSON_CREDENTIALS }}
+ github-token: ${{ secrets.GH_PERSONAL_ACCESS_TOKEN }}
+ folder-id: ${{ secrets.YC_FOLDER }}
+ image-id: ${{ inputs.image }}
+ disk-size: ${{ vars.DISK_SIZE && vars.DISK_SIZE || '1023GB' }}
+ disk-type: network-ssd-nonreplicated
+ cores: 32
+ memory: 128GB
+ core-fraction: 100
+ zone-id: ru-central1-b
+ subnet-id: ${{ secrets.YC_SUBNET }}
+
+ prepare-vm:
+ name: Prepare runner
+ needs: provide-runner
+ runs-on: [ self-hosted, "${{ needs.provide-runner.outputs.label }}" ]
+ steps:
+ - name: Checkout PR
+ uses: actions/checkout@v3
+ if: github.event.pull_request.head.sha != ''
+ with:
+ ref: ${{ github.event.pull_request.head.sha }}
+ - name: Checkout
+ uses: actions/checkout@v3
+ if: github.event.pull_request.head.sha == ''
+ - name: Prepare VM
+ uses: ./.github/actions/prepare_vm
+
+ main:
+ uses: ./.github/workflows/build_and_test_ya.yml
+ needs:
+ - provide-runner
+ - prepare-vm
+ with:
+ runner_kind: self-hosted
+ runner_label: ${{ needs.provide-runner.outputs.label }}
+ build_target: ${{ inputs.build_target }}
+ sanitizer: ${{ inputs.sanitizer }}
+ run_build: ${{ inputs.run_build }}
+ run_tests: ${{ inputs.run_tests }}
+ log_suffix: ya-x86-64${{ inputs.sanitizer != 'none' && format('-{1}', inputs.sanitizer) }}
+ secrets: inherit
+
+ release-runner:
+ name: Release self-hosted YC runner if provided on-demand
+ needs:
+ - provide-runner # required to get output from the start-runner job
+ - main # required to wait when the main job is done
+ runs-on: ubuntu-latest
+ if: always()
+ steps:
+ - name: Stop YC runner
+ uses: yc-actions/yc-github-runner@v1
+ with:
+ mode: stop
+ yc-sa-json-credentials: ${{ secrets.YC_SA_JSON_CREDENTIALS }}
+ github-token: ${{ secrets.GH_PERSONAL_ACCESS_TOKEN }}
+ label: ${{ needs.provide-runner.outputs.label }}
+ instance-id: ${{ needs.provide-runner.outputs.instance-id }}
+
diff --git a/.github/workflows/build_and_test_ya_provisioned.yml b/.github/workflows/build_and_test_ya_provisioned.yml
new file mode 100644
index 0000000000..4e8b1509fd
--- /dev/null
+++ b/.github/workflows/build_and_test_ya_provisioned.yml
@@ -0,0 +1,45 @@
+name: Ya-Build-and-Test-Provisioned
+
+on:
+ workflow_dispatch:
+ inputs:
+ build_target:
+ type: string
+ default: "ydb/"
+ description: "limit build and test to specific target"
+ sanitizer:
+ type: choice
+ default: "none"
+ description: "sanitizer type"
+ options:
+ - none
+ - address
+ - memory
+ - thread
+ - undefined
+ - leak
+ runner_label:
+ type: string
+ default: "linux"
+ description: "runner label"
+ run_build:
+ type: boolean
+ default: true
+ description: "run build"
+ run_tests:
+ type: boolean
+ default: true
+ description: "run tests"
+
+jobs:
+ main:
+ uses: ./.github/workflows/build_and_test_ya.yml
+ with:
+ runner_kind: provisioned
+ runner_label: ${{ inputs.runner_label }}
+ build_target: ${{ inputs.build_target }}
+ sanitizer: ${{ inputs.sanitizer }}
+ run_build: ${{ inputs.run_build }}
+ run_tests: ${{ inputs.run_tests }}
+ log_suffix: ya-${{ inputs.sanitizer != 'none' && format('{0}-{1}', inputs.runner_label, inputs.sanitizer) || inputs.runner_label }}
+ secrets: inherit
diff --git a/.mapping.json b/.mapping.json
index 5075538ec7..7f672f345c 100644
--- a/.mapping.json
+++ b/.mapping.json
@@ -1,7 +1,10 @@
{
".github/actions/build/action.yml":"ydb/github_toplevel/.github/actions/build/action.yml",
+ ".github/actions/build_ya/action.yml":"ydb/github_toplevel/.github/actions/build_ya/action.yml",
".github/actions/prepare_vm/action.yaml":"ydb/github_toplevel/.github/actions/prepare_vm/action.yaml",
+ ".github/actions/s3cmd/action.yml":"ydb/github_toplevel/.github/actions/s3cmd/action.yml",
".github/actions/test/action.yml":"ydb/github_toplevel/.github/actions/test/action.yml",
+ ".github/actions/test_ya/action.yml":"ydb/github_toplevel/.github/actions/test_ya/action.yml",
".github/check_dirs.sh":"ydb/github_toplevel/.github/check_dirs.sh",
".github/config/muted_functest.txt":"ydb/github_toplevel/.github/config/muted_functest.txt",
".github/config/muted_shard.txt":"ydb/github_toplevel/.github/config/muted_shard.txt",
@@ -26,9 +29,13 @@
".github/scripts/tests/mute_utils.py":"ydb/github_toplevel/.github/scripts/tests/mute_utils.py",
".github/scripts/tests/pytest-postprocess.py":"ydb/github_toplevel/.github/scripts/tests/pytest-postprocess.py",
".github/scripts/tests/templates/summary.html":"ydb/github_toplevel/.github/scripts/tests/templates/summary.html",
+ ".github/scripts/tests/transform-ya-junit.py":"ydb/github_toplevel/.github/scripts/tests/transform-ya-junit.py",
".github/workflows/allowed_dirs.yml":"ydb/github_toplevel/.github/workflows/allowed_dirs.yml",
".github/workflows/build_and_test_ondemand.yml":"ydb/github_toplevel/.github/workflows/build_and_test_ondemand.yml",
".github/workflows/build_and_test_provisioned.yml":"ydb/github_toplevel/.github/workflows/build_and_test_provisioned.yml",
+ ".github/workflows/build_and_test_ya.yml":"ydb/github_toplevel/.github/workflows/build_and_test_ya.yml",
+ ".github/workflows/build_and_test_ya_ondemand.yml":"ydb/github_toplevel/.github/workflows/build_and_test_ya_ondemand.yml",
+ ".github/workflows/build_and_test_ya_provisioned.yml":"ydb/github_toplevel/.github/workflows/build_and_test_ya_provisioned.yml",
".github/workflows/docker_publish.yml":"ydb/github_toplevel/.github/workflows/docker_publish.yml",
".github/workflows/docs_build.yaml":"ydb/github_toplevel/.github/workflows/docs_build.yaml",
".github/workflows/docs_release.yaml":"ydb/github_toplevel/.github/workflows/docs_release.yaml",