diff --git a/.cursor/skills/release-notes/SKILL.md b/.cursor/skills/release-notes/SKILL.md
index 4f4903ab2..1dc3a911d 100644
--- a/.cursor/skills/release-notes/SKILL.md
+++ b/.cursor/skills/release-notes/SKILL.md
@@ -36,14 +36,14 @@ git --no-pager log --pretty="* %%s" --no-merges %TAGNAME%..HEAD
## Формат файла release-notes
-В начале записывается заголовок "Версия <НомерВерсии>. Какая сейчас конкретно версия ты должен посмотреть в файле Jenkinsfile в параметре VersionPrefix и взять его.
+В начале записывается заголовок "Версия <НомерВерсии>". Какая сейчас конкретно версия ты должен посмотреть в файле .github/workflows/dist.yml в параметре VersionPrefix и взять его.
Далее идет перечень сделанных задач, как описано выше.
Задачи разбиваются на две группы: исправление ошибок и новые возможности. Соответственно в release notes добавляются два раздела уровня "заголовок 2" для "Новые возможности" и "Исправление ошибок". Если задач по какой-то категории нет (например, были только исправления, а новых фич не было), то соответствующий раздел не добавляется в файл совсем.
## Instructions
-1. Определи текущую выпускаемую версию, прочитав файл Jenkinsfile и его параметр VersionPrefix в самом начале
+1. Определи текущую выпускаемую версию, прочитав файл .github/workflows/dist.yml и его параметр VersionPrefix в самом начале
2. Определи тег предыдущей версии. Для этого запроси его у пользователя, если тег не был сразу задан в промпте
3. Выполни команду gitlog, как показано выше, для получения истории коммитов между версиями
4. Составь дайджест изменений и запиши их в install/release-notes.md
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
new file mode 100644
index 000000000..c1c6dfd92
--- /dev/null
+++ b/.github/workflows/build.yml
@@ -0,0 +1,196 @@
+# Сборка и тесты OneScript для веток и PR.
+# Сборка дистрибутивов - в dist.yml, публикация - в release.yml.
+
+name: Build
+
+on:
+ push:
+ branches: ['**']
+ pull_request:
+ workflow_dispatch:
+
+concurrency:
+ group: build-${{ github.ref }}
+ cancel-in-progress: ${{ github.event_name == 'pull_request' }}
+
+permissions:
+ contents: read
+
+env:
+ DOTNET_NOLOGO: 'true'
+ DOTNET_CLI_TELEMETRY_OPTOUT: 'true'
+ # Тесты рассчитаны на русскую Windows с форматами дат из NLS,
+ # а .NET на новых Windows по умолчанию берет форматы из ICU
+ DOTNET_SYSTEM_GLOBALIZATION_USENLS: 'true'
+ # На develop и release-ветках упавшие тесты не валят сборку
+ TESTS_FAIL_BUILD: ${{ github.event_name == 'pull_request' || !contains(fromJSON('["refs/heads/develop", "refs/heads/release/preview", "refs/heads/release/latest", "refs/heads/release/lts"]'), github.ref) }}
+
+jobs:
+ dist:
+ name: Distribution
+ uses: ./.github/workflows/dist.yml
+
+ windows-testing:
+ name: Windows testing
+ needs: dist
+ runs-on: windows-latest
+ timeout-minutes: 60
+ env:
+ OSCRIPT_CONFIG: systemlanguage=ru
+ MSBUILDDEBUGPATH: ${{ github.workspace }}\msbuild-debug
+ defaults:
+ run:
+ shell: cmd
+ steps:
+ - uses: actions/checkout@v7
+ - uses: actions/setup-dotnet@v6
+ with:
+ dotnet-version: '8.0.x'
+ - uses: microsoft/setup-msbuild@v3
+ - name: Russian locale
+ shell: pwsh
+ run: Set-Culture ru-RU
+ - uses: actions/download-artifact@v8
+ with:
+ name: buildResults
+ path: built
+ - uses: actions/download-artifact@v8
+ with:
+ name: nativeApiTestsDll
+ path: tests/native-api
+ - uses: actions/download-artifact@v8
+ with:
+ name: testComponent
+ path: tests/component
+
+ - name: Test
+ run: |
+ chcp 65001 > nul
+ msbuild Build.csproj /t:Test
+
+ - name: Test results
+ if: ${{ !cancelled() }}
+ uses: EnricoMi/publish-unit-test-result-action/windows@v2
+ with:
+ check_name: Windows testing
+ files: tests/*.xml
+ check_run: false
+ comment_mode: off
+ action_fail: ${{ env.TESTS_FAIL_BUILD }}
+ action_fail_on_inconclusive: true
+ - if: ${{ !cancelled() }}
+ uses: actions/upload-artifact@v7
+ with:
+ name: wintests
+ path: tests/*.xml
+ - if: failure()
+ uses: actions/upload-artifact@v7
+ with:
+ name: msbuild-debug-windows-testing
+ path: msbuild-debug/
+ if-no-files-found: ignore
+
+ linux-testing:
+ name: Linux testing
+ needs: dist
+ runs-on: ubuntu-latest
+ timeout-minutes: 60
+ steps:
+ # Событие запуска для отчета о тестах в PR (test-results.yml)
+ - uses: actions/upload-artifact@v7
+ with:
+ name: event-file
+ path: ${{ github.event_path }}
+ retention-days: 3
+ - uses: actions/checkout@v7
+ - uses: actions/download-artifact@v8
+ with:
+ name: buildResults
+ path: built
+ - uses: actions/download-artifact@v8
+ with:
+ name: nativeApiSo
+ path: output/na-proxy
+ - uses: actions/download-artifact@v8
+ with:
+ name: nativeApiTestsSo
+ path: output/na-tests
+ - uses: actions/download-artifact@v8
+ with:
+ name: testComponent
+ path: tests/component
+
+ - name: Test
+ run: |
+ cp output/na-proxy/*.so built/linux-x64/bin/
+ mkdir -p tests/native-api/build64 lintests
+ cp output/na-tests/*.so tests/native-api/build64/
+ docker run --rm -u "$(id -u):$(id -g)" -e HOME=/tmp -e OSCRIPT_CONFIG=systemlanguage=ru \
+ -v "$PWD:/w" -w /w/tests mcr.microsoft.com/dotnet/sdk:6.0 \
+ dotnet ../built/linux-x64/bin/oscript.dll testrunner.os -runall . xddReportPath ../lintests || true
+
+ - name: Test results
+ if: ${{ !cancelled() }}
+ uses: EnricoMi/publish-unit-test-result-action@v2
+ with:
+ check_name: Linux testing
+ files: lintests/*.xml
+ check_run: false
+ comment_mode: off
+ action_fail: ${{ env.TESTS_FAIL_BUILD }}
+ action_fail_on_inconclusive: true
+ - if: ${{ !cancelled() }}
+ uses: actions/upload-artifact@v7
+ with:
+ name: lintests
+ path: lintests/*.xml
+
+ macos-testing:
+ name: macOS testing
+ needs: dist
+ runs-on: macos-latest
+ timeout-minutes: 60
+ steps:
+ - uses: actions/checkout@v7
+ - uses: actions/download-artifact@v8
+ with:
+ name: buildResults
+ path: built
+ - uses: actions/download-artifact@v8
+ with:
+ name: nativeApiDylib
+ path: built/osx-arm64/bin
+ - uses: actions/download-artifact@v8
+ with:
+ name: nativeApiTestsDylib
+ path: tests/native-api/build64
+ - uses: actions/download-artifact@v8
+ with:
+ name: testComponent
+ path: tests/component
+
+ # Тот же oscript, что попадет в дистрибутив osx-arm64
+ - name: Test
+ env:
+ OSCRIPT_CONFIG: systemlanguage=ru
+ run: |
+ chmod +x built/osx-arm64/bin/oscript
+ mkdir -p mactests
+ cd tests
+ ../built/osx-arm64/bin/oscript testrunner.os -runall . xddReportPath ../mactests || true
+
+ - name: Test results
+ if: ${{ !cancelled() }}
+ uses: EnricoMi/publish-unit-test-result-action/macos@v2
+ with:
+ check_name: macOS testing
+ files: mactests/*.xml
+ check_run: false
+ comment_mode: off
+ action_fail: ${{ env.TESTS_FAIL_BUILD }}
+ action_fail_on_inconclusive: true
+ - if: ${{ !cancelled() }}
+ uses: actions/upload-artifact@v7
+ with:
+ name: mactests
+ path: mactests/*.xml
diff --git a/.github/workflows/dist.yml b/.github/workflows/dist.yml
new file mode 100644
index 000000000..a21a1e982
--- /dev/null
+++ b/.github/workflows/dist.yml
@@ -0,0 +1,235 @@
+# Сборка дистрибутивов OneScript без тестов: вызывается из build.yml (с тестами) и release.yml (публикация)
+
+name: Distribution
+
+on:
+ workflow_call:
+ outputs:
+ version:
+ value: ${{ jobs.windows-build.outputs.version }}
+
+permissions:
+ contents: read
+
+env:
+ VersionPrefix: '2.3.0'
+ VersionSuffix: 'dev+${{ github.run_number }}'
+ BUILD_NUMBER: ${{ github.run_number }}
+ DOTNET_NOLOGO: 'true'
+ DOTNET_CLI_TELEMETRY_OPTOUT: 'true'
+ # Документация рассчитана на русскую Windows с форматами дат из NLS,
+ # а .NET на новых Windows по умолчанию берет форматы из ICU
+ DOTNET_SYSTEM_GLOBALIZATION_USENLS: 'true'
+
+jobs:
+ windows-build:
+ name: Windows Build
+ runs-on: windows-latest
+ timeout-minutes: 60
+ env:
+ # MSBuild кладет сюда отчеты о падении своих процессов (MSBuild_*.failure.txt, например при MSB4166)
+ MSBUILDDEBUGPATH: ${{ github.workspace }}\msbuild-debug
+ defaults:
+ run:
+ shell: cmd
+ outputs:
+ version: ${{ steps.version.outputs.version }}
+ steps:
+ - name: Check release version
+ if: github.event_name == 'release'
+ shell: bash
+ run: |
+ FULL_VERSION="$VersionPrefix${VersionSuffix:+-$VersionSuffix}"
+ if [ "$GITHUB_REF_NAME" != "v$FULL_VERSION" ]; then
+ echo "::error::Тег $GITHUB_REF_NAME не совпадает с версией сборки $FULL_VERSION (VersionPrefix и VersionSuffix в dist.yml)"
+ exit 1
+ fi
+
+ - uses: actions/checkout@v7
+ - uses: actions/setup-dotnet@v6
+ with:
+ dotnet-version: '8.0.x'
+ - uses: microsoft/setup-msbuild@v3
+ - name: Russian locale
+ shell: pwsh
+ run: Set-Culture ru-RU
+
+ - name: Restore
+ run: |
+ chcp 65001 > nul
+ msbuild src/1Script.sln /t:restore
+ - name: Publish documenter
+ run: |
+ chcp 65001 > nul
+ dotnet publish src/OneScriptDocumenter/OneScriptDocumenter.csproj -c Release -o doctool
+ - name: Build
+ run: |
+ chcp 65001 > nul
+ msbuild Build.csproj /t:CleanAll;PrepareDistributionFiles;CreateNuget
+ # Тестовая .NET-компонента для addin.os и enum.os: Build.csproj ее не собирает, а post-build кладет ее в tests/component
+ - name: Build test component
+ run: |
+ chcp 65001 > nul
+ dotnet build src/Component/Component.csproj -c Release -p:SolutionDir=%GITHUB_WORKSPACE%\src\
+
+ # Версия едет вместе с дистрибутивами: по ней release.yml публикует сборку develop
+ - name: Version
+ id: version
+ shell: bash
+ run: |
+ FULL_VERSION="$VersionPrefix${VersionSuffix:+-$VersionSuffix}"
+ echo "$FULL_VERSION" > built/version.txt
+ echo "version=$FULL_VERSION" >> "$GITHUB_OUTPUT"
+
+ - uses: actions/upload-artifact@v7
+ with:
+ name: buildResults
+ path: built/
+ include-hidden-files: true
+ retention-days: 3
+ - uses: actions/upload-artifact@v7
+ with:
+ name: vscode
+ path: built/vscode/
+ retention-days: 3
+ - uses: actions/upload-artifact@v7
+ with:
+ name: nativeApiTestsDll
+ path: tests/native-api/bin*/*.dll
+ retention-days: 3
+ - uses: actions/upload-artifact@v7
+ with:
+ name: testComponent
+ path: tests/component/Component.dll
+ retention-days: 3
+ - if: failure()
+ uses: actions/upload-artifact@v7
+ with:
+ name: msbuild-debug-windows-build
+ path: msbuild-debug/
+ if-no-files-found: ignore
+
+ linux-build:
+ name: Linux Build
+ runs-on: ubuntu-latest
+ timeout-minutes: 30
+ steps:
+ - uses: actions/checkout@v7
+ # Сборка в контейнере вручную, а не через container: в ubuntu 18.04 не запускается node из actions
+ - name: Build native API
+ run: |
+ mkdir -p output
+ docker run --rm -u "$(id -u):$(id -g)" -v "$PWD:/w" -w /w oscript/onescript-builder:gcc sh -ec '
+ mkdir -p built/tmp/na-proxy built/tmp/na-tests
+ cd src/ScriptEngine.NativeApi && ./build.sh && cp *.so ../../built/tmp/na-proxy && cd ../..
+ cd tests/native-api && ./build.sh && cp *.so ../../built/tmp/na-tests && cd ../..
+ cp -Rv built/tmp/* output/
+ '
+ - uses: actions/upload-artifact@v7
+ with:
+ name: nativeApiSo
+ path: output/na-proxy/*.so
+ retention-days: 3
+ - uses: actions/upload-artifact@v7
+ with:
+ name: nativeApiTestsSo
+ path: output/na-tests/*.so
+ retention-days: 3
+
+ macos-build:
+ name: macOS Build
+ runs-on: macos-latest
+ timeout-minutes: 30
+ steps:
+ - uses: actions/checkout@v7
+ # Универсальные библиотеки, сразу arm64 и x86_64. Политика 3.5 - для CMake 4 со старым cmake_minimum_required
+ - name: Build native API
+ run: |
+ for project in src/ScriptEngine.NativeApi tests/native-api; do
+ cmake -S $project -B build/$project -D CMAKE_BUILD_TYPE=Release -D CMAKE_POLICY_VERSION_MINIMUM=3.5
+ cmake --build build/$project
+ done
+ mkdir -p output/na-proxy output/na-tests
+ cp build/src/ScriptEngine.NativeApi/*.dylib output/na-proxy/
+ cp build/tests/native-api/*.dylib output/na-tests/
+ lipo -info output/*/*.dylib
+ # Apple Silicon не загружает неподписанные библиотеки, а линковщик подписывает не все части универсальной.
+ # На раннере SIP выключен, поэтому подпись проверяется явно
+ codesign -f -s - output/*/*.dylib
+ codesign -v output/*/*.dylib
+ - uses: actions/upload-artifact@v7
+ with:
+ name: nativeApiDylib
+ path: output/na-proxy/*.dylib
+ retention-days: 3
+ - uses: actions/upload-artifact@v7
+ with:
+ name: nativeApiTestsDylib
+ path: output/na-tests/*.dylib
+ retention-days: 3
+
+ vscode-debugger:
+ name: VSCode debugger Build
+ needs: windows-build
+ runs-on: ubuntu-latest
+ timeout-minutes: 15
+ steps:
+ - uses: actions/download-artifact@v8
+ with:
+ name: vscode
+ path: built/vscode
+ - uses: actions/setup-node@v7
+ with:
+ node-version: '22'
+ - name: Package
+ run: |
+ npm install @vscode/vsce@4.0.0
+ cd built/vscode && ../../node_modules/.bin/vsce package
+ - uses: actions/upload-artifact@v7
+ with:
+ name: vsix
+ path: built/vscode/*.vsix
+
+ packaging:
+ name: Packaging
+ needs: [windows-build, linux-build, macos-build]
+ runs-on: windows-latest
+ timeout-minutes: 30
+ defaults:
+ run:
+ shell: cmd
+ steps:
+ - uses: actions/checkout@v7
+ - uses: actions/setup-dotnet@v6
+ with:
+ dotnet-version: '8.0.x'
+ - uses: microsoft/setup-msbuild@v3
+ - name: Russian locale
+ shell: pwsh
+ run: Set-Culture ru-RU
+ - uses: actions/download-artifact@v8
+ with:
+ name: buildResults
+ path: built
+ - uses: actions/download-artifact@v8
+ with:
+ name: nativeApiSo
+ path: output/na-proxy
+ - uses: actions/download-artifact@v8
+ with:
+ name: nativeApiDylib
+ path: output/na-mac
+
+ - name: Pack
+ run: |
+ chcp 65001 > nul
+ xcopy output\na-proxy\*64.so built\linux-x64\bin\ /F || exit /b
+ xcopy output\na-mac\*.dylib built\osx-x64\bin\ /F || exit /b
+ xcopy output\na-mac\*.dylib built\osx-arm64\bin\ /F || exit /b
+ msbuild Build.csproj /t:PackDistributions
+
+ - uses: actions/upload-artifact@v7
+ with:
+ name: dist
+ path: built/
+ include-hidden-files: true
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
new file mode 100644
index 000000000..9cbcefd37
--- /dev/null
+++ b/.github/workflows/release.yml
@@ -0,0 +1,295 @@
+# Публикация OneScript.
+# Релиз на GitHub: сборка без тестов (dist.yml), дистрибутивы кладутся в релиз,
+# сайт забирает их по вебхуку, затем NuGet и Docker.
+# develop: после успешной сборки Build ее дистрибутивы выкладываются в пре-релиз night-build.
+# Публикация на сайт, в NuGet и Docker Hub идет только в EvilBeaver/OneScript и требует секретов.
+
+name: Release
+
+on:
+ release:
+ types: [published]
+ workflow_run:
+ workflows: [Build]
+ types: [completed]
+ branches: [develop, release/lts]
+
+# Публикации одного канала не идут параллельно, чтобы файлы night-build не перемешивались
+concurrency:
+ group: release-${{ github.event_name == 'release' && github.ref || github.event.workflow_run.head_branch }}
+
+permissions:
+ contents: read
+
+env:
+ # Сборка develop публикуется из прогона Build, релиз - из своего
+ BUILD_RUN_ID: ${{ github.event.workflow_run.id || github.run_id }}
+ BUILD_SHA: ${{ github.event.workflow_run.head_sha || github.sha }}
+
+jobs:
+ build:
+ name: Build
+ if: github.event_name == 'release'
+ uses: ./.github/workflows/dist.yml
+
+ # Дистрибутивы кладутся в релиз на GitHub: при публикации релиза — в него,
+ # при сборке develop — в постоянный пре-релиз night-build, который каждая сборка перезаписывает
+ github-release:
+ name: Publishing to GitHub release
+ needs: build
+ if: >-
+ !cancelled() && (
+ (github.event_name == 'release' && needs.build.result == 'success') ||
+ (github.repository == 'EvilBeaver/OneScript' && github.event_name == 'workflow_run' &&
+ github.event.workflow_run.event == 'push' && github.event.workflow_run.conclusion == 'success' &&
+ github.event.workflow_run.head_branch == 'develop'))
+ runs-on: ubuntu-latest
+ timeout-minutes: 15
+ permissions:
+ contents: write
+ actions: read
+ env:
+ GH_TOKEN: ${{ github.token }}
+ GH_REPO: ${{ github.repository }}
+ outputs:
+ channel: ${{ steps.release.outputs.channel }}
+ version: ${{ steps.release.outputs.version }}
+ steps:
+ - uses: actions/download-artifact@v8
+ with:
+ name: dist
+ path: built
+ run-id: ${{ env.BUILD_RUN_ID }}
+ github-token: ${{ github.token }}
+ - uses: actions/download-artifact@v8
+ with:
+ name: vsix
+ path: built/vscode
+ run-id: ${{ env.BUILD_RUN_ID }}
+ github-token: ${{ github.token }}
+
+ - name: Release
+ id: release
+ env:
+ PRERELEASE: ${{ github.event.release.prerelease }}
+ run: |
+ FULL_VERSION=$(cat built/version.txt)
+ if [ "$GITHUB_EVENT_NAME" = release ]; then
+ TAG="$GITHUB_REF_NAME"
+ case "$TAG" in
+ v1.*) CHANNEL= ;;
+ *) if [ "$PRERELEASE" = true ]; then CHANNEL=preview; else CHANNEL=latest; fi ;;
+ esac
+ else
+ TAG=night-build
+ CHANNEL=night-build
+ # Тег переносится на собранный коммит, файлы прошлой сборки удаляются
+ gh api "repos/$GH_REPO/git/refs/tags/$TAG" -X PATCH -f sha="$BUILD_SHA" -F force=true > /dev/null \
+ || gh api "repos/$GH_REPO/git/refs" -f ref="refs/tags/$TAG" -f sha="$BUILD_SHA" > /dev/null
+ NOTES="Сборка develop $FULL_VERSION, коммит $BUILD_SHA"
+ if gh release view "$TAG" > /dev/null 2>&1; then
+ gh release edit "$TAG" --notes "$NOTES"
+ gh release view "$TAG" --json assets --jq '.assets[].name' | while read -r name; do
+ gh release delete-asset "$TAG" "$name" --yes
+ done
+ else
+ gh release create "$TAG" --prerelease --title "Night build" --notes "$NOTES" --verify-tag
+ fi
+ fi
+ echo "tag=$TAG" >> "$GITHUB_OUTPUT"
+ echo "channel=$CHANNEL" >> "$GITHUB_OUTPUT"
+ echo "version=$FULL_VERSION" >> "$GITHUB_OUTPUT"
+
+ # Все файлы дистрибутива: сайт забирает их отсюда
+ - name: Upload
+ env:
+ TAG: ${{ steps.release.outputs.tag }}
+ run: |
+ mkdir release
+ for f in built/*.zip built/vscode/*.vsix; do
+ case "$(basename "$f")" in
+ mddoc*.zip) ;;
+ *) cp "$f" release/ ;;
+ esac
+ done
+ gh release upload "$TAG" release/* --clobber
+
+ - name: Site payload
+ env:
+ TAG: ${{ steps.release.outputs.tag }}
+ CHANNEL: ${{ steps.release.outputs.channel }}
+ FULL_VERSION: ${{ steps.release.outputs.version }}
+ run: |
+ REPO_URL="$GITHUB_SERVER_URL/$GITHUB_REPOSITORY"
+ gh api "repos/$GH_REPO/releases/tags/$TAG" --jq '.assets[] | [.name, .browser_download_url] | @tsv' > assets.tsv
+ for f in release/*; do
+ name=$(basename "$f")
+ url=$(awk -F '\t' -v n="$name" '$1 == n { print $2 }' assets.tsv)
+ if [ -z "$url" ]; then
+ echo "::error::Файла $name нет в релизе $TAG"
+ exit 1
+ fi
+ size=$(stat -c %s "$f")
+ sha=$(sha256sum "$f" | cut -d' ' -f1)
+ rid=${name#OneScript-"$FULL_VERSION"-}
+ rid=${rid%.zip}
+ case "$name" in
+ *.vsix) kind=vsix; os=; arch= ;;
+ OneScript-*.zip)
+ case "$rid" in
+ fdd-*) kind=fdd; os= ;;
+ *) kind=scd; os=${rid%-*} ;;
+ esac
+ arch=${rid##*-} ;;
+ *) kind=other; os=; arch= ;;
+ esac
+ jq -n --arg name "$name" --arg kind "$kind" --arg os "$os" --arg arch "$arch" \
+ --arg url "$url" --argjson size "$size" --arg sha256 "$sha" \
+ '{name: $name, kind: $kind, os: (if $os == "" then null else $os end),
+ arch: (if $arch == "" then null else $arch end), url: $url, size: $size, sha256: $sha256}'
+ done | jq -s \
+ --arg channel "$CHANNEL" --arg version "$FULL_VERSION" --arg commit "$BUILD_SHA" \
+ --arg run "$REPO_URL/actions/runs/$BUILD_RUN_ID" --arg release "$REPO_URL/releases/tag/$TAG" \
+ --arg notes "https://raw.githubusercontent.com/$GITHUB_REPOSITORY/$BUILD_SHA/install/release-notes.md" \
+ '{channel: $channel, version: $version,
+ versionDir: (if $channel == "night-build" then null else ($version | gsub("\\."; "_")) end),
+ commit: $commit, run: $run, release: $release,
+ releaseNotes: (if $channel == "night-build" then null else $notes end),
+ files: .}' > site-payload.json
+ cat site-payload.json
+ - uses: actions/upload-artifact@v7
+ with:
+ name: site-payload
+ path: site-payload.json
+ retention-days: 30
+
+ # Сайт сам забирает файлы из релиза по ссылкам из вебхука
+ publish-site:
+ name: Publishing to oscript.io
+ needs: github-release
+ if: github.repository == 'EvilBeaver/OneScript' && needs.github-release.outputs.channel != ''
+ runs-on: ubuntu-latest
+ timeout-minutes: 30
+ steps:
+ - uses: actions/download-artifact@v8
+ with:
+ name: site-payload
+ - name: Webhook
+ env:
+ SITE_WEBHOOK_URL: ${{ secrets.SITE_WEBHOOK_URL }}
+ SITE_WEBHOOK_SECRET: ${{ secrets.SITE_WEBHOOK_SECRET }}
+ run: |
+ SIGNATURE=$(openssl dgst -sha256 -hmac "$SITE_WEBHOOK_SECRET" -r site-payload.json | cut -d' ' -f1)
+ # Сайт отвечает, когда файлы уже на месте: следом Build v2 ставит движок с сайта через ovm
+ curl --fail-with-body -sS --max-time 1200 \
+ -H 'Content-Type: application/json' \
+ -H "X-OneScript-Signature-256: sha256=$SIGNATURE" \
+ --data-binary @site-payload.json "$SITE_WEBHOOK_URL"
+
+ publish-nuget:
+ name: Publishing artifacts to clouds
+ needs: publish-site
+ if: >-
+ github.repository == 'EvilBeaver/OneScript' && github.event_name == 'release' &&
+ !startsWith(github.ref, 'refs/tags/v1.')
+ runs-on: windows-latest
+ timeout-minutes: 15
+ defaults:
+ run:
+ shell: cmd
+ steps:
+ - uses: actions/checkout@v7
+ - uses: actions/setup-dotnet@v6
+ with:
+ dotnet-version: '8.0.x'
+ - uses: microsoft/setup-msbuild@v3
+ - uses: actions/download-artifact@v8
+ with:
+ name: buildResults
+ path: built
+ - name: Push
+ env:
+ NUGET_TOKEN: ${{ secrets.NUGET_TOKEN }}
+ run: |
+ chcp 65001 > nul
+ msbuild Build.csproj /t:PublishNuget /p:NugetToken=%NUGET_TOKEN%
+
+ docker-v1:
+ name: Build v1
+ needs: build
+ if: >-
+ !cancelled() && github.repository == 'EvilBeaver/OneScript' && (
+ (github.event_name == 'release' && startsWith(github.ref, 'refs/tags/v1.') && needs.build.result == 'success') ||
+ (github.event_name == 'workflow_run' && github.event.workflow_run.event == 'push' &&
+ github.event.workflow_run.conclusion == 'success' && github.event.workflow_run.head_branch == 'release/lts'))
+ runs-on: ubuntu-latest
+ timeout-minutes: 30
+ steps:
+ - uses: actions/checkout@v7
+ with:
+ ref: ${{ env.BUILD_SHA }}
+ - name: Version
+ id: version
+ run: |
+ if [ "$GITHUB_EVENT_NAME" = release ]; then
+ # тег v1.9.4 -> версия для ovm 1.9.4
+ echo "codename=$GITHUB_REF_NAME" >> "$GITHUB_OUTPUT"
+ echo "engine=${GITHUB_REF_NAME#v}" >> "$GITHUB_OUTPUT"
+ else
+ echo "codename=lts" >> "$GITHUB_OUTPUT"
+ echo "engine=lts" >> "$GITHUB_OUTPUT"
+ fi
+ - uses: docker/setup-buildx-action@v4
+ - uses: docker/login-action@v4
+ with:
+ username: ${{ secrets.DOCKERHUB_USERNAME }}
+ password: ${{ secrets.DOCKERHUB_TOKEN }}
+ - uses: docker/build-push-action@v7
+ with:
+ context: .
+ file: install/builders/base-image/Dockerfile_v1
+ build-args: VERSION=${{ steps.version.outputs.engine }}
+ tags: evilbeaver/onescript:${{ steps.version.outputs.codename }}
+ # --pull и --no-cache: обновлять базовые образы и заново ставить движок через ovm
+ pull: true
+ no-cache: true
+ push: true
+
+ docker-v2:
+ name: Build v2
+ # Образ ставит движок через ovm с сайта, поэтому после публикации
+ needs: [github-release, publish-site]
+ if: >-
+ github.repository == 'EvilBeaver/OneScript' &&
+ (github.event_name == 'workflow_run' ||
+ (github.event_name == 'release' && !github.event.release.prerelease && !startsWith(github.ref, 'refs/tags/v1.')))
+ runs-on: ubuntu-latest
+ timeout-minutes: 30
+ steps:
+ - uses: actions/checkout@v7
+ with:
+ ref: ${{ env.BUILD_SHA }}
+ - name: Version
+ id: version
+ env:
+ FULL_VERSION: ${{ needs.github-release.outputs.version }}
+ # для v2 тег образа совпадает с версией для ovm: dev или 2.2.0
+ run: |
+ case "$FULL_VERSION" in
+ *-*) echo "codename=dev" >> "$GITHUB_OUTPUT" ;;
+ *) echo "codename=$FULL_VERSION" >> "$GITHUB_OUTPUT" ;;
+ esac
+ - uses: docker/setup-buildx-action@v4
+ - uses: docker/login-action@v4
+ with:
+ username: ${{ secrets.DOCKERHUB_USERNAME }}
+ password: ${{ secrets.DOCKERHUB_TOKEN }}
+ - uses: docker/build-push-action@v7
+ with:
+ context: .
+ file: install/builders/base-image/Dockerfile_v2
+ build-args: VERSION=${{ steps.version.outputs.codename }}
+ tags: evilbeaver/onescript:${{ steps.version.outputs.codename }}
+ pull: true
+ no-cache: true
+ push: true
diff --git a/.github/workflows/test-results.yml b/.github/workflows/test-results.yml
new file mode 100644
index 000000000..30767dea2
--- /dev/null
+++ b/.github/workflows/test-results.yml
@@ -0,0 +1,48 @@
+# Отчет о тестах после Build: комментарий в PR со сводкой и проверка с упавшими тестами.
+# Отдельный workflow, потому что у PR из форков токен в Build только на чтение.
+
+name: Test results
+
+on:
+ workflow_run:
+ workflows: [Build]
+ types: [completed]
+
+permissions: {}
+
+jobs:
+ test-results:
+ name: Test results
+ if: github.event.workflow_run.conclusion != 'skipped' && github.event.workflow_run.conclusion != 'cancelled'
+ runs-on: ubuntu-latest
+ timeout-minutes: 10
+ permissions:
+ actions: read
+ checks: write
+ contents: read
+ issues: read
+ pull-requests: write
+ steps:
+ - uses: actions/download-artifact@v8
+ with:
+ pattern: '*tests'
+ path: artifacts
+ run-id: ${{ github.event.workflow_run.id }}
+ github-token: ${{ github.token }}
+ - uses: actions/download-artifact@v8
+ with:
+ name: event-file
+ path: artifacts/event-file
+ run-id: ${{ github.event.workflow_run.id }}
+ github-token: ${{ github.token }}
+
+ - uses: EnricoMi/publish-unit-test-result-action@v2
+ with:
+ commit: ${{ github.event.workflow_run.head_sha }}
+ event_file: artifacts/event-file/event.json
+ event_name: ${{ github.event.workflow_run.event }}
+ files: artifacts/*tests/*.xml
+ check_name: Test results
+ comment_title: Результаты тестов
+ # Только упавшие тесты, без списков всех и пропущенных
+ check_run_annotations: none
diff --git a/Jenkinsfile b/Jenkinsfile
deleted file mode 100644
index 717207d9e..000000000
--- a/Jenkinsfile
+++ /dev/null
@@ -1,460 +0,0 @@
-
-pipeline {
-
- agent none
-
- // Сборки одной ветки идут по очереди: параллельные публикации night-build
- // через rsync --delete оставляли в папке файлы двух сборок, и сайт отдавал 404
- options { disableConcurrentBuilds() }
-
- environment {
- VersionPrefix = '2.3.0'
- VersionSuffix = 'dev'+"+${BUILD_NUMBER}"
- outputEnc = '65001'
- }
-
- stages {
- stage('Build'){
- parallel {
- stage('Windows Build') {
- agent { label 'windows' }
-
- options { skipDefaultCheckout() }
-
- // пути к инструментам доступны только когда
- // нода уже определена
- environment {
- NugetPath = "${tool 'nuget'}"
- StandardLibraryPacks = "${tool 'os_stdlib'}"
- // MSBuild кладет сюда отчеты о падении своих процессов (MSBuild_*.failure.txt, например при MSB4166),
- // по умолчанию они остаются во временной папке пользователя на агенте и в сборку не попадают
- MSBUILDDEBUGPATH = "${env.WORKSPACE}/msbuild-debug"
- }
-
- steps {
- dir('msbuild-debug') { deleteDir() }
-
- // в среде Multibranch Pipeline Jenkins первращает имена веток в папки
- // а для веток Gitflow вида release/* экранирует в слэш в %2F
- // При этом MSBuild, видя urlEncoding, разэкранирует его обратно, ломая путь (появляется слэш, где не надо)
- //
- // Поэтому, применяем костыль с кастомным workspace
- // см. https://issues.jenkins-ci.org/browse/JENKINS-34564
- //
- // А еще Jenkins под Windows постоянно добавляет в конец папки какую-то мусорную строку.
- // Для этого отсекаем все, что находится после последнего дефиса
- // см. https://issues.jenkins-ci.org/browse/JENKINS-40072
-
- ws(env.WORKSPACE.replaceAll("%", "_").replaceAll(/(-[^-]+$)/, ""))
- {
- step([$class: 'WsCleanup'])
- checkout scm
-
- bat "chcp $outputEnc > nul\r\n\"${tool 'MSBuild'}\" src/1Script.sln /t:restore && mkdir doctool"
- bat "chcp $outputEnc > nul\r\n dotnet publish src/OneScriptDocumenter/OneScriptDocumenter.csproj -c Release -o doctool"
- bat "chcp $outputEnc > nul\r\n\"${tool 'MSBuild'}\" Build.csproj /t:CleanAll;PrepareDistributionFiles;CreateNuget"
-
- stash includes: 'built/**', name: 'buildResults'
- stash includes: 'tests/native-api/bin*/*.dll', name: 'nativeApiTestsDll'
- }
- }
- post {
- failure {
- archiveArtifacts artifacts: 'msbuild-debug/**', allowEmptyArchive: true
- }
- }
- }
-
- stage('Linux Build') {
- agent {
- docker {
- image 'oscript/onescript-builder:gcc'
- label 'linux'
- }
- }
-
- steps {
- sh 'mkdir -p built/tmp/na-proxy && mkdir -p built/tmp/na-tests'
- dir('src/ScriptEngine.NativeApi') {
- sh './build.sh'
- sh 'cp *.so ../../built/tmp/na-proxy'
- }
- dir('tests/native-api') {
- sh './build.sh'
- sh 'cp *.so ../../built/tmp/na-tests'
- }
- dir('output') {
- sh 'cp -Rv ../built/tmp/* .'
- }
- stash includes: 'output/na-proxy/*.so', name: 'nativeApiSo'
- stash includes: 'output/na-tests/*.so', name: 'nativeApiTestsSo'
- }
- }
- }
- }
- stage('VSCode debugger Build') {
- agent {
- docker {
- image 'node:22-alpine3.20'
- label 'linux'
- }
- }
-
- steps {
- unstash 'buildResults'
- sh 'npm install @vscode/vsce'
- script {
- def vsceBin = pwd() + "/node_modules/.bin/vsce"
- sh "cd built/vscode && ${vsceBin} package"
- archiveArtifacts artifacts: 'built/vscode/*.vsix', fingerprint: true
- stash includes: 'built/vscode/*.vsix', name: 'vsix'
- }
- }
- }
-
- stage('Testing'){
- parallel{
- stage('Windows testing') {
- agent { label 'windows' }
- options { skipDefaultCheckout() }
- environment {
- OSCRIPT_CONFIG = 'systemlanguage=ru'
- // MSBuild кладет сюда отчеты о падении своих процессов (MSBuild_*.failure.txt, например при MSB4166),
- // по умолчанию они остаются во временной папке пользователя на агенте и в сборку не попадают
- MSBUILDDEBUGPATH = "${env.WORKSPACE}/msbuild-debug"
- }
- steps {
- dir('msbuild-debug') { deleteDir() }
- ws(env.WORKSPACE.replaceAll("%", "_").replaceAll(/(-[^-]+$)/, ""))
- {
- step([$class: 'WsCleanup'])
- checkout scm
-
- dir('install/build'){
- deleteDir()
- }
- unstash 'buildResults'
- unstash 'nativeApiTestsDll'
- bat "chcp $outputEnc > nul\r\n\"${tool 'MSBuild'}\" Build.csproj /t:Test"
-
- publishTestResults('tests/*.xml')
- }
- }
- post {
- failure {
- archiveArtifacts artifacts: 'msbuild-debug/**', allowEmptyArchive: true
- }
- }
- }
-
- stage('Linux testing') {
- agent{
- docker {
- image 'mcr.microsoft.com/dotnet/sdk:6.0'
- label 'linux'
- }
- }
- environment {
- OSCRIPT_CONFIG = 'systemlanguage=ru'
- }
-
- steps {
-
- dir('built'){
- deleteDir()
- }
-
- unstash 'buildResults'
- unstash 'nativeApiSo'
- unstash 'nativeApiTestsSo'
-
- sh 'cp output/na-proxy/*.so ./built/linux-x64/bin/'
- sh 'mkdir -p tests/native-api/build64 && cp output/na-tests/*.so ./tests/native-api/build64/'
-
- sh '''\
- if [ ! -d lintests ]; then
- mkdir lintests
- fi
- rm lintests/*.xml -f
- cd tests
- dotnet ../built/linux-x64/bin/oscript.dll testrunner.os -runall . xddReportPath ../lintests || true
- exit 0
- '''.stripIndent()
-
- publishTestResults('lintests/*.xml')
- archiveArtifacts artifacts: 'lintests/*.xml', fingerprint: true
- }
- }
- }
- }
-
- stage('Packaging') {
- agent { label 'windows' }
-
- options { skipDefaultCheckout() }
-
- steps {
- ws(env.WORKSPACE.replaceAll("%", "_").replaceAll(/(-[^-]+$)/, ""))
- {
- step([$class: 'WsCleanup'])
- checkout scm
-
- dir('built'){
- deleteDir()
- }
-
- unstash 'buildResults'
- unstash 'nativeApiSo'
-
- bat '''
- chcp 65001 > nul
- dir output\\na-proxy
- xcopy output\\na-proxy\\*64.so built\\linux-x64\\bin\\ /F
- '''.stripIndent()
-
- bat "chcp $outputEnc > nul\r\n\"${tool 'MSBuild'}\" Build.csproj /t:PackDistributions"
-
- archiveArtifacts artifacts: 'built/**', fingerprint: true
- stash includes: 'built/**', name: 'dist'
- }
- }
- }
-
- stage ('Publishing night-build') {
- when {
- beforeAgent true
- anyOf {
- branch 'develop';
- }
- }
- agent { label 'master' }
- options { skipDefaultCheckout() }
-
- steps {
- cleanWs()
-
- unstash 'dist'
- unstash 'vsix'
-
- publishRelease('night-build', false)
- }
- }
-
- stage ('Publishing preview') {
- when {
- beforeAgent true
- anyOf {
- branch 'release/preview';
- }
- }
- agent { label 'master' }
- options { skipDefaultCheckout() }
-
- steps {
- cleanWs()
- checkout scm // чтобы получить файл release-notes
- unstash 'dist'
- unstash 'vsix'
-
- // Положит описание для сайта
- publishReleaseNotes('preview')
-
- // Положит файлы дистрибутива в целевую папку
- publishRelease('preview', true)
- }
- }
-
- stage ('Publishing latest') {
- when {
- beforeAgent true
- anyOf {
- branch 'release/latest';
- }
- }
- agent { label 'master' }
- options { skipDefaultCheckout() }
-
- steps {
- cleanWs()
- checkout scm // чтобы получить файл release-notes
- unstash 'dist'
- unstash 'vsix'
-
- // Положит описание для сайта
- publishReleaseNotes('latest')
-
- // Положит файлы дистрибутива в целевую папку
- publishRelease('latest', true)
- }
- }
-
- stage ('Publishing artifacts to clouds') {
- when {
- beforeAgent true
- anyOf {
- branch 'release/latest';
- branch 'release/preview';
- }
- }
-
- agent { label 'windows' }
-
- steps{
-
- unstash 'buildResults'
-
- withCredentials([string(credentialsId: 'NuGetToken', variable: 'NUGET_TOKEN')]) {
- bat "chcp $outputEnc > nul\r\n\"${tool 'MSBuild'}\" Build.csproj /t:PublishNuget /p:NugetToken=$NUGET_TOKEN"
- }
- }
- }
-
- stage ('Publishing docker-images') {
- parallel {
- stage('Build v1') {
- agent { label 'linux' }
- when {
- beforeAgent true
- anyOf {
- branch 'release/lts'
- expression {
- return env.TAG_NAME && env.TAG_NAME.startsWith('v1.')
- }
- }
- }
- steps {
- script {
- def codename = env.TAG_NAME ? env.TAG_NAME : 'lts'
- // тег v1.9.4 -> версия для ovm 1.9.4
- def engineVersion = env.TAG_NAME ? env.TAG_NAME.replaceFirst(/^v/, '') : 'lts'
- publishDockerImage('v1', codename, engineVersion)
- }
- }
- }
-
- stage('Build v2') {
- agent { label 'linux' }
- when {
- beforeAgent true
- anyOf {
- branch 'develop'
- branch 'release/latest'
- }
- }
- steps {
- script {
- def codename = ''
- if (env.VersionSuffix != null && !env.VersionSuffix.isEmpty()) {
- codename = 'dev'
- }
- else
- {
- codename = fullVersionNumber()
- }
-
- // для v2 тег образа совпадает с версией для ovm: dev или 2.2.0
- publishDockerImage('v2', codename, codename)
- }
- }
- }
- }
- }
- }
-}
-
-def testsShouldFailBuild() {
- if (env.CHANGE_ID) {
- return true
- }
-
- switch (env.BRANCH_NAME) {
- case 'develop':
- case 'release/preview':
- case 'release/latest':
- case 'release/lts':
- return false
- default:
- return true
- }
-}
-
-def publishTestResults(String pattern) {
- def failBuild = testsShouldFailBuild()
- def results = junit testResults: pattern, skipMarkingBuildUnstable: failBuild
- if (failBuild && results.failCount > 0) {
- error("${results.failCount} test(s) failed")
- }
-}
-
-def fullVersionNumber() {
- def version = env.VersionPrefix
- if (env.VersionSuffix != null && !env.VersionSuffix.isEmpty())
- {
- version = version + "-${env.VersionSuffix}"
- }
-
- return version
-}
-
-def underscoredVersion() {
- return fullVersionNumber().replaceAll("\\.", "_")
-}
-
-def publishRelease(codename, isNumbered) {
- dir('targetContent') {
- sh """
- ZIPS=../built
- NUGET=../built/nuget
- VSIX=../built/vscode
- mv \$ZIPS/*.zip ./
- mv \$VSIX/*.vsix ./
-
- TARGET="/var/www/oscript.io/download/versions/${codename}/"
- mkdir -p \$TARGET
- sudo rsync -rv --delete --exclude mddoc*.zip --exclude *.src.rpm . \$TARGET
- """.stripIndent()
-
- if (isNumbered) {
-
- def version = underscoredVersion()
-
- sh """
- TARGET="/var/www/oscript.io/download/versions/${version}/"
- sudo mkdir -p \$TARGET
- sudo rsync -rv --delete --exclude mddoc*.zip --exclude *.src.rpm . \$TARGET
- """.stripIndent()
- }
- }
-}
-
-def publishReleaseNotes(codename) {
- dir('markdownContent') {
- def version=underscoredVersion()
- def targetDir='/var/www/oscript.io/markdown/versions'
-
- sh """
- cp ../install/release-notes.md "./${codename}.md"
- cp ../install/release-notes.md "./${version}.md"
-
- sudo rsync -rv . ${targetDir}
- """.stripIndent()
- }
-}
-
-def publishDockerImage(flavour, codename, engineVersion) {
- def imageName = "evilbeaver/onescript:${codename}"
-
- // Временно, см. #1752: в buildkit с runc 1.4.3 на ядре сервера не запускается ни один RUN.
- // v0.30.0 собран с runc 1.3.5. Убрать, когда выйдет buildkit с runc 1.5.1+
- def buildkitVersion = 'v0.30.0'
- def builder = "onescript-buildkit-${buildkitVersion}"
- sh "docker buildx inspect ${builder} > /dev/null 2>&1 || docker buildx create --name ${builder} --driver docker-container --driver-opt image=moby/buildkit:${buildkitVersion}"
-
- // --no-cache: слой с ovm install не меняется между сборками и иначе берется из кэша агента
- // --pull: обновлять базовые образы (ovm, aspnet, mono)
- docker.build(
- imageName,
- "--builder ${builder} --load --pull --no-cache --build-arg VERSION=${engineVersion} -f install/builders/base-image/Dockerfile_${flavour} ."
- ).push()
-}
-
diff --git a/README-EN.md b/README-EN.md
index 36c6e80cb..cf5c6df4c 100644
--- a/README-EN.md
+++ b/README-EN.md
@@ -1,6 +1,6 @@
# OneScript #
-[](https://t.me/oscript_library) [](https://build.oscript.io/job/1Script/job/develop/) [](https://build.oscript.io/job/1Script/job/master/)
+[](https://t.me/oscript_library) [](https://github.com/EvilBeaver/OneScript/actions/workflows/build.yml?query=branch%3Adevelop) [](https://github.com/EvilBeaver/OneScript/actions/workflows/build.yml?query=branch%3Arelease%2Flatest)
## The project is an independent cross-platform implementation of a virtual machine that executes scripts written in the 1C:Enterprise language ##
diff --git a/README.md b/README.md
index 55b917ba8..f105ccb71 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,6 @@
# OneScript #
-[](https://t.me/oscript_library) [](https://build.oscript.io/job/1Script/job/develop/) [](https://build.oscript.io/job/1Script/job/master/)
+[](https://t.me/oscript_library) [](https://github.com/EvilBeaver/OneScript/actions/workflows/build.yml?query=branch%3Adevelop) [](https://github.com/EvilBeaver/OneScript/actions/workflows/build.yml?query=branch%3Arelease%2Flatest)
## Проект является независимой кросс-платформенной реализацией виртуальной машины, исполняющей скрипты на языке 1С:Предприятие ##
diff --git a/src/1Script.sln b/src/1Script.sln
index 86f35f9b1..1d67e4097 100644
--- a/src/1Script.sln
+++ b/src/1Script.sln
@@ -20,7 +20,10 @@ EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{D14BF321-348C-46B8-B96A-43A22BA7AC10}"
ProjectSection(SolutionItems) = preProject
..\Build.csproj = ..\Build.csproj
- ..\Jenkinsfile = ..\Jenkinsfile
+ ..\.github\workflows\build.yml = ..\.github\workflows\build.yml
+ ..\.github\workflows\release.yml = ..\.github\workflows\release.yml
+ ..\.github\workflows\dist.yml = ..\.github\workflows\dist.yml
+ ..\.github\workflows\test-results.yml = ..\.github\workflows\test-results.yml
oscommon.targets = oscommon.targets
EndProjectSection
EndProject
diff --git a/src/OneScript.StandardLibrary/NativeApi/NativeApiKernel.cs b/src/OneScript.StandardLibrary/NativeApi/NativeApiKernel.cs
index 7af4c3998..a04b62b61 100644
--- a/src/OneScript.StandardLibrary/NativeApi/NativeApiKernel.cs
+++ b/src/OneScript.StandardLibrary/NativeApi/NativeApiKernel.cs
@@ -15,31 +15,36 @@ namespace OneScript.StandardLibrary.NativeApi
///
public class NativeApiKernel
{
- private const string KernelDll = "kernel32.dll";
public static bool IsLinux
{
get => System.Environment.OSVersion.Platform == PlatformID.Unix;
}
- private const String KernelWin = "kernel32.dll";
- private const String KernelLin = "libdl.so.2";
+ internal static bool IsMacOS => RuntimeInformation.IsOSPlatform(OSPlatform.OSX);
+
+ ///
+ /// Операционная система в манифесте библиотеки внешних компонент
+ ///
+ internal static string OsName => IsMacOS ? "MacOS" : IsLinux ? "Linux" : "Windows";
+
+ internal static string LibraryExtension => IsMacOS ? ".dylib" : IsLinux ? ".so" : ".dll";
public static IntPtr LoadLibrary(string filename)
{
- return IsLinux ? LinuxLoad(filename, 1) : WindowsLoad(filename);
+ return NativeLibrary.TryLoad(filename, out var module) ? module : IntPtr.Zero;
}
public static IntPtr GetProcAddress(IntPtr module, string procName)
{
- var pointer = IsLinux ? LinuxProc(module, procName) : WindowsProc(module, procName);
- return pointer != IntPtr.Zero
+ return NativeLibrary.TryGetExport(module, procName, out var pointer)
? pointer
: throw new ApplicationException($"Function pointer for {procName} not obtained.");
}
public static bool FreeLibrary(IntPtr module)
{
- return IsLinux ? LinuxFree(module) == 0 : WindowsFree(module);
+ NativeLibrary.Free(module);
+ return true;
}
///
@@ -50,23 +55,5 @@ public static void Shutdown()
{
NativeApiFactory.Shutdown();
}
-
- [DllImport(KernelWin, SetLastError = true, CharSet = CharSet.Unicode, EntryPoint = "LoadLibrary")]
- protected static extern IntPtr WindowsLoad(string lpLibFileName);
-
- [DllImport(KernelWin, SetLastError = true, ExactSpelling = true, CharSet = CharSet.Ansi, EntryPoint = "GetProcAddress")]
- protected static extern IntPtr WindowsProc(IntPtr module, string procName);
-
- [DllImport(KernelWin, SetLastError = true, EntryPoint = "FreeLibrary")]
- protected static extern bool WindowsFree(IntPtr module);
-
- [DllImport(KernelLin, EntryPoint = "dlopen")]
- protected static extern IntPtr LinuxLoad(string filename, int flags);
-
- [DllImport(KernelLin, EntryPoint = "dlsym")]
- protected static extern IntPtr LinuxProc(IntPtr handle, string symbol);
-
- [DllImport(KernelLin, EntryPoint = "dlclose")]
- protected static extern int LinuxFree(IntPtr handle);
}
}
diff --git a/src/OneScript.StandardLibrary/NativeApi/NativeApiPackage.cs b/src/OneScript.StandardLibrary/NativeApi/NativeApiPackage.cs
index 8f6c9580f..cce090d93 100644
--- a/src/OneScript.StandardLibrary/NativeApi/NativeApiPackage.cs
+++ b/src/OneScript.StandardLibrary/NativeApi/NativeApiPackage.cs
@@ -7,6 +7,7 @@ This Source Code Form is subject to the terms of the
using System;
using System.IO;
+using System.Runtime.InteropServices;
using System.Xml;
using Ionic.Zip;
using OneScript.Exceptions;
@@ -27,9 +28,20 @@ public static bool IsZip(Stream stream)
return (BitConverter.ToInt32(bytes, 0) == ZIP_LEAD_BYTES);
}
- private static bool Is64BitProcess()
+ // Архитектура процесса в обозначениях манифеста: по размеру указателя arm64 не отличить от x86_64
+ private static string ProcessArch()
{
- return IntPtr.Size == 8;
+ if (RuntimeInformation.ProcessArchitecture == Architecture.Arm64)
+ return "ARM64";
+
+ return IntPtr.Size == 8 ? "x86_64" : "i386";
+ }
+
+ // Универсальная библиотека под macOS подходит и для arm64, и для x86_64
+ private static bool IsSuitableArch(string arch, string thisArch)
+ {
+ return string.Equals(arch, thisArch, StringComparison.OrdinalIgnoreCase)
+ || NativeApiKernel.IsMacOS && string.Equals(arch, "Universal", StringComparison.OrdinalIgnoreCase);
}
public static void Extract(Stream stream, String tempfile)
@@ -54,13 +66,13 @@ private static String GetEntryName(ZipFile zip)
stream.Seek(0, 0);
using (var reader = XmlReader.Create(stream))
{
- var thisOs = NativeApiProxy.IsLinux ? "Linux" : "Windows";
- var thisArch = Is64BitProcess() ? "x86_64" : "i386";
+ var thisOs = NativeApiKernel.OsName;
+ var thisArch = ProcessArch();
while (reader.ReadToFollowing("component"))
{
var attrOs = reader.GetAttribute("os");
var attrArch = reader.GetAttribute("arch");
- if (string.Equals(attrArch, thisArch, StringComparison.OrdinalIgnoreCase)
+ if (IsSuitableArch(attrArch, thisArch)
&& string.Equals(attrOs, thisOs, StringComparison.OrdinalIgnoreCase))
return reader.GetAttribute("path");
}
diff --git a/src/OneScript.StandardLibrary/NativeApi/NativeApiProxy.cs b/src/OneScript.StandardLibrary/NativeApi/NativeApiProxy.cs
index f3871766d..8e0b36795 100644
--- a/src/OneScript.StandardLibrary/NativeApi/NativeApiProxy.cs
+++ b/src/OneScript.StandardLibrary/NativeApi/NativeApiProxy.cs
@@ -190,7 +190,7 @@ static NativeApiProxy()
string filename = System.IO.Path.GetDirectoryName(location)
+ System.IO.Path.DirectorySeparatorChar + "ScriptEngine.NativeApi"
+ (IntPtr.Size == 8 ? "64" : "32")
- + (NativeApiKernel.IsLinux ? ".so" : ".dll");
+ + NativeApiKernel.LibraryExtension;
IntPtr module = NativeApiKernel.LoadLibrary(filename);
if (module == IntPtr.Zero)
{
diff --git a/src/ScriptEngine.NativeApi/CMakeLists.txt b/src/ScriptEngine.NativeApi/CMakeLists.txt
index 50d45b1d0..d236b74af 100644
--- a/src/ScriptEngine.NativeApi/CMakeLists.txt
+++ b/src/ScriptEngine.NativeApi/CMakeLists.txt
@@ -11,7 +11,11 @@ add_library(${TARGET} SHARED
target_compile_definitions(${TARGET} PRIVATE UNICODE _UNICODE)
target_include_directories(${TARGET} PRIVATE include)
-if (UNIX)
+if (APPLE)
+ # Одна библиотека и для osx-arm64, и для osx-x64
+ set(MySuffix "64")
+ set_target_properties(${TARGET} PROPERTIES PREFIX "" OSX_ARCHITECTURES "arm64;x86_64")
+elseif (UNIX)
if (TARGET_PLATFORM_32)
set(MySuffix "32")
set(CMAKE_LIBRARY_PATH "/usr/lib/i386-linux-gnu" CACHE PATH "")
diff --git a/src/ScriptEngine/ScriptingEngine.cs b/src/ScriptEngine/ScriptingEngine.cs
index 5b8340900..ec7a7e079 100644
--- a/src/ScriptEngine/ScriptingEngine.cs
+++ b/src/ScriptEngine/ScriptingEngine.cs
@@ -5,6 +5,7 @@ This Source Code Form is subject to the terms of the
at http://mozilla.org/MPL/2.0/.
----------------------------------------------------------*/
using System;
+using System.Runtime.InteropServices;
using OneScript.Compilation;
using OneScript.Contexts;
using OneScript.DependencyInjection;
@@ -125,18 +126,13 @@ public ICompilerFrontend GetCompilerService()
var compiler = scope.Resolve();
compiler.SharedSymbols = _runtimeEnvironment.GetSymbolTable();
- switch (System.Environment.OSVersion.Platform)
- {
- case PlatformID.Unix:
- compiler.PreprocessorDefinitions.Add("Linux");
- break;
- case PlatformID.MacOSX:
- compiler.PreprocessorDefinitions.Add("MacOS");
- break;
- case PlatformID.Win32NT:
- compiler.PreprocessorDefinitions.Add("Windows");
- break;
- }
+ // Environment.OSVersion.Platform на macOS возвращает Unix, а не MacOSX
+ if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
+ compiler.PreprocessorDefinitions.Add("Windows");
+ else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
+ compiler.PreprocessorDefinitions.Add("MacOS");
+ else
+ compiler.PreprocessorDefinitions.Add("Linux");
compiler.GenerateDebugCode = ProduceExtraCode.HasFlag(CodeGenerationFlags.DebugCode);
compiler.GenerateCodeStat = ProduceExtraCode.HasFlag(CodeGenerationFlags.CodeStatistics);
diff --git a/tests/directives.os b/tests/directives.os
index 619e1c9d0..db5669579 100644
--- a/tests/directives.os
+++ b/tests/directives.os
@@ -10,6 +10,7 @@
ВсеТесты.Добавить("ТестДолжен_ПроверитьЧтоИспользоватьНеКомпилируетсяЕслиНачалсяКод");
ВсеТесты.Добавить("ТестДолжен_ПроверитьЧтоМногострочныеДирективыНеКомпилируются");
ВсеТесты.Добавить("ТестДолжен_ПроверитьЧтоИсключенныеСтрокиПропускаются");
+ ВсеТесты.Добавить("ТестДолжен_ПроверитьСимволОперационнойСистемы");
Возврат ВсеТесты;
@@ -26,6 +27,28 @@
КонецФункции
+Функция ТестДолжен_ПроверитьСимволОперационнойСистемы() Экспорт
+
+ Определены = Новый Массив;
+ #Если Windows Тогда
+ Определены.Добавить("Windows");
+ #КонецЕсли
+ #Если Linux Тогда
+ Определены.Добавить("Linux");
+ #КонецЕсли
+ #Если MacOS Тогда
+ Определены.Добавить("MacOS");
+ #КонецЕсли
+
+ // ТипПлатформы определяет систему сам, по ядру: Windows_x86_64, Linux_x86_64, MacOS_x86_64
+ Платформа = Строка(Новый СистемнаяИнформация().ТипПлатформы);
+ Ожидаемый = Лев(Платформа, СтрНайти(Платформа, "_") - 1);
+
+ юТест.ПроверитьРавенство(1, Определены.Количество(), "Определен один символ операционной системы");
+ юТест.ПроверитьРавенство(Ожидаемый, Определены[0]);
+
+КонецФункции
+
Функция ФайлКомпилируется(Знач ПутьКФайлу, Знач ИмяПодключения = "НеПодключится")
Попытка
diff --git a/tests/formatting.os b/tests/formatting.os
index 62744d923..768182804 100644
--- a/tests/formatting.os
+++ b/tests/formatting.os
@@ -18,7 +18,7 @@
ВсеТесты.Добавить("ТестДолжен_ПроверитьФорматированиеБольшойРазрядности");
ВсеТесты.Добавить("ТестДолжен_ПроверитьФорматированиеПустаяДата");
ВсеТесты.Добавить("ТестДолжен_ПроверитьФорматированиеЛокальнаяДата");
- #Если Не Linux Тогда
+ #Если Windows Тогда
//TODO: https://github.com/EvilBeaver/OneScript/issues/1228
ВсеТесты.Добавить("ТестДолжен_ПроверитьФорматированиеЛокальнаяДатаВремя");
ВсеТесты.Добавить("ТестДолжен_ПроверитьФорматированиеДлинныйФорматЛокальнойДаты");
diff --git a/tests/native-api.os b/tests/native-api.os
index f360f4434..5a4a36653 100644
--- a/tests/native-api.os
+++ b/tests/native-api.os
@@ -32,10 +32,8 @@
#Если Windows Тогда
ЭтоWindows = Истина;
- #ИначеЕсли Linux Тогда
- ЭтоWindows = Ложь;
#Иначе
- Возврат Новый Массив; // под макос не тестируем
+ ЭтоWindows = Ложь;
#КонецЕсли
Возврат ВсеТесты;
@@ -55,6 +53,8 @@
ПутьБиблиотеки = ОбъединитьПути(Каталог, "ScriptEngine.NativeApi32.so");
ИначеЕсли СистемнаяИнформация.ТипПлатформы = ТипПлатформы.Linux_x86_64 Тогда
ПутьБиблиотеки = ОбъединитьПути(Каталог, "ScriptEngine.NativeApi64.so");
+ ИначеЕсли СистемнаяИнформация.ТипПлатформы = ТипПлатформы.MacOS_x86_64 Тогда
+ ПутьБиблиотеки = ОбъединитьПути(Каталог, "ScriptEngine.NativeApi64.dylib");
Иначе
ПутьБиблиотеки = "";
КонецЕсли;
@@ -85,6 +85,8 @@
ПутьБиблиотеки = ОбъединитьПути(КаталогСборок, "build32", "AddInNativeLin32.so");
ИначеЕсли СистемнаяИнформация.ТипПлатформы = ТипПлатформы.Linux_x86_64 Тогда
ПутьБиблиотеки = ОбъединитьПути(КаталогСборок, "build64", "AddInNativeLin64.so");
+ ИначеЕсли СистемнаяИнформация.ТипПлатформы = ТипПлатформы.MacOS_x86_64 Тогда
+ ПутьБиблиотеки = ОбъединитьПути(КаталогСборок, "build64", "AddInNativeMac.dylib");
Иначе
ВызватьИсключение "Неподдерживаемый тип платформы: " + СистемнаяИнформация.ТипПлатформы;
КонецЕсли;
@@ -115,6 +117,7 @@
Каталог = ТекущийСценарий().Каталог + "/native-api/";
МасивФайлов.Добавить("build32/AddInNativeLin32.so");
МасивФайлов.Добавить("build64/AddInNativeLin64.so");
+ МасивФайлов.Добавить("build64/AddInNativeMac.dylib");
КонецЕсли;
ЗаписьZIP.Добавить(Каталог + "MANIFEST.XML", РежимСохраненияПутейZIP.НеСохранятьПути);
diff --git a/tests/native-api/AddInNative.cpp b/tests/native-api/AddInNative.cpp
index 5ecbe870a..460efa2ad 100644
--- a/tests/native-api/AddInNative.cpp
+++ b/tests/native-api/AddInNative.cpp
@@ -11,6 +11,7 @@
#include
#include
#include
+#include
#endif
#include
diff --git a/tests/native-api/CMakeLists.txt b/tests/native-api/CMakeLists.txt
index b1bc69220..112d32a68 100644
--- a/tests/native-api/CMakeLists.txt
+++ b/tests/native-api/CMakeLists.txt
@@ -21,7 +21,11 @@ include_directories(${CMAKE_SOURCE_DIR}/include)
SET (CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH} ${CMAKE_SOURCE_DIR})
SET(AddInDef_SRC)
-if (UNIX)
+if (APPLE)
+ # Одна библиотека и для arm64, и для x86_64
+ set(CMAKE_OSX_ARCHITECTURES "arm64;x86_64")
+ set(MySuffix "Mac")
+elseif (UNIX)
if (TARGET_PLATFORM_32)
set(CMAKE_CXX_FLAGS "-m32 ${CMAKE_CXX_FLAGS}")
set(MySuffix "Lin32")
diff --git a/tests/native-api/MANIFEST.XML b/tests/native-api/MANIFEST.XML
index 03bb40552..c47eac462 100644
--- a/tests/native-api/MANIFEST.XML
+++ b/tests/native-api/MANIFEST.XML
@@ -4,4 +4,5 @@
+
diff --git a/tests/preprocessor/excluded.os b/tests/preprocessor/excluded.os
index 2674374db..a8021b516 100644
--- a/tests/preprocessor/excluded.os
+++ b/tests/preprocessor/excluded.os
@@ -2,7 +2,7 @@
!!
#КонецЕсли
-#Если Windows ИЛИ Linux Тогда //!! ok
+#Если Windows ИЛИ Linux ИЛИ MacOS Тогда //!! ok
#ИначеЕсли НЕ MacOS Тогда //??
!!
diff --git a/tests/sysinfo.os b/tests/sysinfo.os
index 0e63bf5a3..51f759d07 100644
--- a/tests/sysinfo.os
+++ b/tests/sysinfo.os
@@ -103,11 +103,19 @@
юТест.ПроверитьРавенство(СИ.ТипПлатформы, ТипПлатформы.Windows_x86);
КонецЕсли;
Иначе
+ #Если MacOS Тогда
+ Если Си.Это64БитнаяОперационнаяСистема Тогда
+ юТест.ПроверитьРавенство(СИ.ТипПлатформы, ТипПлатформы.MacOS_x86_64);
+ Иначе
+ юТест.ПроверитьРавенство(СИ.ТипПлатформы, ТипПлатформы.MacOS_x86);
+ КонецЕсли;
+ #Иначе
Если Си.Это64БитнаяОперационнаяСистема Тогда
юТест.ПроверитьРавенство(СИ.ТипПлатформы, ТипПлатформы.Linux_x86_64);
Иначе
юТест.ПроверитьРавенство(СИ.ТипПлатформы, ТипПлатформы.Linux_x86);
КонецЕсли;
+ #КонецЕсли
КонецЕсли;
КонецПроцедуры
diff --git a/tests/testrunner.os b/tests/testrunner.os
index 7214f48e7..70e1b6a52 100644
--- a/tests/testrunner.os
+++ b/tests/testrunner.os
@@ -486,13 +486,19 @@
КонецЕсли;
Сообщить("Не удалось загрузить тест "+ПолноеИмяТестовогоСлучая+Символы.ПС+
текстОшибки);
+ ДобавитьНеЗагруженныйНабор(ПолноеИмяТестовогоСлучая, ИмяКлассаТеста, текстОшибки, СтрокаОшибкиВФайле(ИнфоОшибки, ПолноеИмяТестовогоСлучая));
Рез = Ложь;
РезультатТестирования = ЗначенияСостоянияТестов.Сломался;
Продолжить;
КонецПопытки;
- МассивТестовыхСлучаев = ПолучитьТестовыеСлучаи(Тест, ПолноеИмяТестовогоСлучая);
- Если МассивТестовыхСлучаев = Неопределено Тогда
+ ОшибкаЗагрузки = Неопределено;
+ МассивТестовыхСлучаев = ПолучитьТестовыеСлучаи(Тест, ПолноеИмяТестовогоСлучая, ОшибкаЗагрузки);
+ Если ОшибкаЗагрузки <> Неопределено Тогда
+ ДобавитьНеЗагруженныйНабор(ПолноеИмяТестовогоСлучая, ИмяКлассаТеста, ОшибкаЗагрузки);
+ Рез = Ложь;
+ Продолжить;
+ ИначеЕсли МассивТестовыхСлучаев = Неопределено Тогда
Сообщить("Нет тестовых случаев в файле " + Файл.ПолноеИмя);
Продолжить;
КонецЕсли;
@@ -548,6 +554,23 @@
Возврат Рез;
КонецФункции
+// Незагруженный набор - упавший тест, а не молча пропущенный файл: попадает в итог и в отчет
+Процедура ДобавитьНеЗагруженныйНабор(ПолноеИмя, ИмяКласса, ТекстОшибки, СтрокаОшибки = Неопределено)
+
+ ОписаниеТеста = Новый Структура;
+ ОписаниеТеста.Вставить("ТестОбъект", Неопределено);
+ ОписаниеТеста.Вставить("ИмяКласса", ИмяКласса);
+ ОписаниеТеста.Вставить("ПолноеИмя", ПолноеИмя);
+ ОписаниеТеста.Вставить("Параметры", Неопределено);
+ ОписаниеТеста.Вставить("ИмяМетода", "ЗагрузкаНабораТестов");
+ ОписаниеТеста.Вставить("ОшибкаЗагрузки", ТекстОшибки);
+ ОписаниеТеста.Вставить("СтрокаОшибкиЗагрузки", СтрокаОшибки);
+
+ НаборТестов.Добавить(ОписаниеТеста);
+ РезультатТестирования = ЗначенияСостоянияТестов.Сломался;
+
+КонецПроцедуры
+
Функция ВыполнитьВсеТесты()
Если НаборТестов.Количество() > 0 Тогда
НаборОшибок = Новый Соответствие;
@@ -562,7 +585,9 @@
Для Сч = 0 По НаборТестов.Количество() - 1 Цикл
ОписаниеТеста = НаборТестов[Сч];
+ НачалоТеста = ТекущаяУниверсальнаяДатаВМиллисекундах();
НовыйРезультатТестирования = ВыполнитьТест(ОписаниеТеста, Сч);
+ ОписаниеТеста.Вставить("Длительность", (ТекущаяУниверсальнаяДатаВМиллисекундах() - НачалоТеста) / 1000);
РезультатТестирования = ЗапомнитьСамоеХудшееСостояние(РезультатТестирования, НовыйРезультатТестирования);
КонецЦикла;
@@ -649,6 +674,14 @@
ФайлТеста = Новый Файл(ПутьНабора);
ЗаписьXML.ЗаписатьАтрибут("name", ИмяНабора);
+
+ ДлительностьНабора = 0;
+ Для Каждого ОписаниеТеста Из НаборТестов Цикл
+ Если ОписаниеТеста.Свойство("Длительность") Тогда
+ ДлительностьНабора = ДлительностьНабора + ОписаниеТеста.Длительность;
+ КонецЕсли;
+ КонецЦикла;
+ ЗаписьXML.ЗаписатьАтрибут("time", XMLСтрока(ДлительностьНабора));
ЗаписьXML.ЗаписатьНачалоЭлемента("properties");
ЗаписьXML.ЗаписатьКонецЭлемента();
@@ -677,6 +710,10 @@
ЗаписьXML.ЗаписатьНачалоЭлемента("testcase");
ЗаписьXML.ЗаписатьАтрибут("classname", ИмяТекущегоТеста(ОписаниеТеста.ПолноеИмя));
ЗаписьXML.ЗаписатьАтрибут("name", ОписаниеТеста.ИмяМетода);
+ ЗаписьXML.ЗаписатьАтрибут("file", ПутьОтКорняРепозитория(ОписаниеТеста.ПолноеИмя));
+ Если ОписаниеТеста.Свойство("Длительность") Тогда
+ ЗаписьXML.ЗаписатьАтрибут("time", XMLСтрока(ОписаниеТеста.Длительность));
+ КонецЕсли;
СтруктураОшибки = НаборОшибок.Получить(ОписаниеТеста);
@@ -685,6 +722,10 @@
КонецЕсли;
Если СтруктураОшибки <> Неопределено Тогда
+ Если СтруктураОшибки.Свойство("СтрокаВФайле") И СтруктураОшибки.СтрокаВФайле <> Неопределено Тогда
+ ЗаписьXML.ЗаписатьАтрибут("line", XMLСтрока(СтруктураОшибки.СтрокаВФайле));
+ КонецЕсли;
+
СтрокаРезультат = ?(СтруктураОшибки.СостояниеВыполнения = ЗначенияСостоянияТестов.Сломался, "failure", "skipped");
ЗаписьXML.ЗаписатьАтрибут("status", СтрокаРезультат);
@@ -704,6 +745,43 @@
КонецПроцедуры
+// Путь теста от каталога над testrunner, то есть от корня репозитория: по нему отчет показывает ошибку у файла
+Функция ПутьОтКорняРепозитория(Знач ПолноеИмя)
+ Корень = Новый Файл(ТекущийСценарий().Каталог).Путь;
+ Если Не СтрНачинаетсяС(ПолноеИмя, Корень) Тогда
+ Возврат ПолноеИмя;
+ КонецЕсли;
+ Возврат СтрЗаменить(Сред(ПолноеИмя, СтрДлина(Корень) + 1), "\", "/");
+КонецФункции
+
+// Строка файла теста, на которой случилась ошибка
+Функция СтрокаОшибкиВФайле(Знач ИнфоОшибки, Знач ПутьФайла)
+
+ Если ИнфоОшибки = Неопределено Тогда
+ Возврат Неопределено;
+ КонецЕсли;
+
+ Стек = ИнфоОшибки.ПолучитьСтекВызовов();
+ Если Стек <> Неопределено Тогда
+ Для Каждого Кадр Из Стек Цикл
+ Если Кадр.ИмяМодуля = ПутьФайла Тогда
+ Возврат Кадр.НомерСтроки;
+ КонецЕсли;
+ КонецЦикла;
+ КонецЕсли;
+
+ // У ошибки компиляции стека нет: место - в самой ошибке или в ее причине
+ Пока ИнфоОшибки <> Неопределено Цикл
+ Если ИнфоОшибки.ИмяМодуля = ПутьФайла И ИнфоОшибки.НомерСтроки > 0 Тогда
+ Возврат ИнфоОшибки.НомерСтроки;
+ КонецЕсли;
+ ИнфоОшибки = ИнфоОшибки.Причина;
+ КонецЦикла;
+
+ Возврат Неопределено;
+
+КонецФункции
+
Функция ПутьФайлаОтчетаТестированияВФорматеJUnitXML()
Возврат ?(ЗначениеЗаполнено(ПутьЛогФайлаJUnit), ПутьЛогФайлаJUnit, ТекущийКаталог());
КонецФункции
@@ -719,6 +797,11 @@
Тест = ОписаниеТеста.ТестОбъект;
ИмяМетода = ОписаниеТеста.ИмяМетода;
+ Если ОписаниеТеста.Свойство("ОшибкаЗагрузки") Тогда
+ ПоказатьИнформациюПоТесту(ОписаниеТеста, Сч, ИмяМетода);
+ Возврат ВывестиОшибкуВыполненияТеста(ЗначенияСостоянияТестов.Сломался, "Набор тестов не загружен", ОписаниеТеста, ОписаниеТеста.ОшибкаЗагрузки, Неопределено);
+ КонецЕсли;
+
Успешно = ВыполнитьПроцедуруТестовогоСлучая(Тест, "ПередЗапускомТеста", ИмяМетода, ОписаниеТеста);
Если Не Успешно Тогда
Рез = ЗначенияСостоянияТестов.Сломался;
@@ -777,6 +860,10 @@
Функция ВывестиОшибкуВыполненияТеста(СостояниеВыполнения, ПредставлениеОшибки, ОписаниеТеста, текстОшибки, ИнфоОшибки)
ИмяМетода = ОписаниеТеста.ИмяМетода;
+ СтрокаВФайле = СтрокаОшибкиВФайле(ИнфоОшибки, ОписаниеТеста.ПолноеИмя);
+ Если СтрокаВФайле = Неопределено И ОписаниеТеста.Свойство("СтрокаОшибкиЗагрузки") Тогда
+ СтрокаВФайле = ОписаниеТеста.СтрокаОшибкиЗагрузки;
+ КонецЕсли;
сообщение = ?(ПредставлениеОшибки="", "", ПредставлениеОшибки + Символы.ПС) +
"Тест: <" + ИмяМетода + ">" + Символы.ПС +
@@ -819,6 +906,7 @@
СтруктураОшибки.Вставить("Описание", текстОшибки);
СтруктураОшибки.Вставить("ИнфоОшибки", стИнфоОшибки);
СтруктураОшибки.Вставить("ПолныйПуть", ОписаниеТеста.ПолноеИмя);
+ СтруктураОшибки.Вставить("СтрокаВФайле", СтрокаВФайле);
Если СостояниеВыполнения = ЗначенияСостоянияТестов.Сломался Тогда
НаборОшибок.Вставить(ОписаниеТеста, СтруктураОшибки);
@@ -851,7 +939,7 @@
Возврат Успешно;
КонецФункции
-Функция ПолучитьТестовыеСлучаи(ТестОбъект, ПолноеИмяОбъекта)
+Функция ПолучитьТестовыеСлучаи(ТестОбъект, ПолноеИмяОбъекта, ОшибкаЗагрузки = Неопределено)
Попытка
@@ -866,7 +954,7 @@
текстОшибки = ?(ВыводитьОшибкиПодробно, ИнформацияОбОшибке().ПодробноеОписаниеОшибки(), ОписаниеОшибки());
- ВывестиОшибку("Набор тестов не загружен: " + ПолноеИмяОбъекта + "
+ ОшибкаЗагрузки = ВывестиОшибку("Набор тестов не загружен: " + ПолноеИмяОбъекта + "
| Ошибка получения списка тестовых случаев: " + текстОшибки);
ТестОбъект = Неопределено;
@@ -878,14 +966,14 @@
Если ТипЗнч(МассивТестовыхСлучаев) <> Тип("Массив") Тогда
- ВывестиОшибку("Набор тестов не загружен: " + ПолноеИмяОбъекта + "
+ ОшибкаЗагрузки = ВывестиОшибку("Набор тестов не загружен: " + ПолноеИмяОбъекта + "
| Ошибка получения списка тестовых случаев: вместо массива имен тестовых случаев получен объект <" + Строка(ТипЗнч(МассивТестовыхСлучаев)) + ">");
ТестОбъект = Неопределено;
Возврат Неопределено;
КонецЕсли;
- Если НЕ ПроверитьМассивТестовыхСлучаев(МассивТестовыхСлучаев, ТестОбъект, ПолноеИмяОбъекта) Тогда
+ Если НЕ ПроверитьМассивТестовыхСлучаев(МассивТестовыхСлучаев, ТестОбъект, ПолноеИмяОбъекта, ОшибкаЗагрузки) Тогда
Возврат Неопределено;
КонецЕсли;
@@ -893,19 +981,19 @@
КонецФункции
-Функция ПроверитьМассивТестовыхСлучаев(МассивТестовыхСлучаев, ТестОбъект, ПолноеИмяОбъекта)
+Функция ПроверитьМассивТестовыхСлучаев(МассивТестовыхСлучаев, ТестОбъект, ПолноеИмяОбъекта, ОшибкаЗагрузки)
Для каждого данныеТеста из МассивТестовыхСлучаев Цикл
Если ТипЗнч(данныеТеста) = Тип("Строка") Тогда
Продолжить;
КонецЕсли;
Если ТипЗнч(данныеТеста) <> Тип("Структура") Тогда
- ВывестиОшибку("Набор тестов не загружен: " + ПолноеИмяОбъекта + "
+ ОшибкаЗагрузки = ВывестиОшибку("Набор тестов не загружен: " + ПолноеИмяОбъекта + "
| Ошибка получения структуры описания тестового случая: " + ОписаниеОшибки());
Возврат Ложь;
КонецЕсли;
Если НЕ данныеТеста.Свойство("ИмяТеста") Тогда
- ВывестиОшибку("Набор тестов не загружен: " + ПолноеИмяОбъекта + "
+ ОшибкаЗагрузки = ВывестиОшибку("Набор тестов не загружен: " + ПолноеИмяОбъекта + "
| Не задано имя теста в структуре описания тестового случая: " + ОписаниеОшибки());
Возврат Ложь;
КонецЕсли;