diff --git a/ci/macos_ci.vsh b/ci/macos_ci.vsh new file mode 100644 index 0000000000..e640c5aab1 --- /dev/null +++ b/ci/macos_ci.vsh @@ -0,0 +1,212 @@ +import os + +enum Command { + build_v + test_symlink + test_cross_compilation + build_with_cstrict + all_code_is_formatted + run_sanitizers + build_using_v + verify_v_test_works + install_iconv + test_pure_v_math_module + self_tests + build_examples + build_tetris_autofree + build_blog_autofree + build_examples_prod + v_doctor + v_self_compilation_usecache + v_self_compilation_parallel_cc + test_password_input + test_readline + test_vlib_skip_unused +} + +fn main() { + if os.args.len < 2 { + println('Usage: v run macos_ci.vsh ') + return + } + arg := os.args[1] + if arg == 'all' { + $for x in Command.values { + println(get_step_name(x.value)) + run_step(x.value) + } + return + } + step := Command.from_string(arg) or { + eprintln('Unknown step: ${arg}') + exit(1) + } + run_step(step) +} + +fn run_step(step Command) { + println('Running ${step}...') + match step { + .build_v { build_v() } + .test_symlink { test_symlink() } + .test_cross_compilation { test_cross_compilation() } + .build_with_cstrict { build_with_cstrict() } + .all_code_is_formatted { all_code_is_formatted() } + .run_sanitizers { run_sanitizers() } + .build_using_v { build_using_v() } + .verify_v_test_works { verify_v_test_works() } + .install_iconv { install_iconv() } + .test_pure_v_math_module { test_pure_v_math_module() } + .self_tests { self_tests() } + .build_examples { build_examples() } + .build_tetris_autofree { build_tetris_autofree() } + .build_blog_autofree { build_blog_autofree() } + .build_examples_prod { build_examples_prod() } + .v_doctor { v_doctor() } + .v_self_compilation_usecache { v_self_compilation_usecache() } + .v_self_compilation_parallel_cc { v_self_compilation_parallel_cc() } + .test_password_input { test_password_input() } + .test_readline { test_readline() } + .test_vlib_skip_unused { test_vlib_skip_unused() } + } +} + + +// Helper function to execute commands and exit if they fail +fn exec(command string) { + result := os.execute(command) + //or { + //eprintln('Command failed: $command\nError: $err') + //exit(1) + //} + if result.exit_code != 0 { + eprintln('Command failed with code ${result.exit_code}: $command\nOutput: ${result.output}') + exit(1) + } + println(result.output) +} + +// Map enum values to human readable step names +fn get_step_name(step Command) string { + return match step { + .build_v { 'Build V' } + .test_symlink { 'Test symlink' } + .test_cross_compilation { 'Test cross compilation to Linux' } + .build_with_cstrict { 'Build V with -cstrict' } + .all_code_is_formatted { 'All code is formatted' } + .run_sanitizers { 'Run sanitizers' } + .build_using_v { 'Build V using V' } + .verify_v_test_works { 'Verify `v test` works' } + .install_iconv { 'Install iconv for encoding.iconv' } + .test_pure_v_math_module { 'Test pure V math module' } + .self_tests { 'Self tests' } + .build_examples { 'Build examples' } + .build_tetris_autofree { 'Build tetris with -autofree' } + .build_blog_autofree { 'Build blog tutorial with -autofree' } + .build_examples_prod { 'Build examples with -prod' } + .v_doctor { 'v doctor' } + .v_self_compilation_usecache { 'V self compilation with -usecache' } + .v_self_compilation_parallel_cc { 'V self compilation with -parallel-cc' } + .test_password_input { 'Test password input' } + .test_readline { 'Test readline' } + .test_vlib_skip_unused { 'Test vlib modules with -skip-unused' } + } +} + +// Step functions +fn build_v() { + exec('make -j4') + exec('./v symlink') +} + +fn test_symlink() { + exec('v symlink') +} + +fn test_cross_compilation() { + exec('v -o hw -os linux examples/hello_world.v && ls -la hw && file hw') + exec('v -d use_openssl -o ve -os linux examples/veb/veb_example.v && ls -la ve && file ve') +} + +fn build_with_cstrict() { + exec('v -cg -cstrict -o v cmd/v') +} + +fn all_code_is_formatted() { + exec('VJOBS=1 v test-cleancode') +} + +fn run_sanitizers() { + exec('v -o v2 cmd/v -cflags -fsanitize=undefined') + exec('UBSAN_OPTIONS=print_stacktrace=1:halt_on_error=1 ./v2 -o v.c cmd/v') +} + +fn build_using_v() { + exec('v -o v2 cmd/v') + exec('./v2 -o v3 cmd/v') +} + +fn verify_v_test_works() { + exec('echo \$VFLAGS') + exec('v cmd/tools/test_if_v_test_system_works.v') + exec('./cmd/tools/test_if_v_test_system_works') +} + +fn install_iconv() { + exec('brew install libiconv') +} + +fn test_pure_v_math_module() { + exec('v -exclude @vlib/math/*.c.v test vlib/math/') +} + +fn self_tests() { + exec('VJOBS=1 v test-self vlib') +} + +fn build_examples() { + exec('v build-examples') +} + +fn build_tetris_autofree() { + exec('v -autofree -o tetris examples/tetris/tetris.v') +} + +fn build_blog_autofree() { + exec('v -autofree -o blog tutorials/building_a_simple_web_blog_with_vweb/code/blog') +} + +fn build_examples_prod() { + exec('v -prod examples/news_fetcher.v') +} + +fn v_doctor() { + exec('v doctor') +} + +fn v_self_compilation_usecache() { + exec('unset VFLAGS') + exec('v -usecache examples/hello_world.v && examples/hello_world') + exec('v -o v2 -usecache cmd/v') + exec('./v2 -o v3 -usecache cmd/v') + exec('./v3 version') + exec('./v3 -o tetris -usecache examples/tetris/tetris.v') +} + +fn v_self_compilation_parallel_cc() { + exec('v -o v2 -parallel-cc cmd/v') +} + +fn test_password_input() { + exec('v test examples/password/') +} + +fn test_readline() { + exec('v test examples/readline/') +} + +fn test_vlib_skip_unused() { + exec('v -skip-unused test vlib/builtin/ vlib/math vlib/flag/ vlib/os/ vlib/strconv/') +} + + diff --git a/ci/macos_ci.yml b/ci/macos_ci.yml new file mode 100644 index 0000000000..0a8568c116 --- /dev/null +++ b/ci/macos_ci.yml @@ -0,0 +1,77 @@ +name: CI macOS + +on: + push: + paths-ignore: + - '**.md' + - '**.yml' + - '!**/macos_ci.yml' + - 'cmd/tools/**' + - '!cmd/tools/builders/**.v' + pull_request: + paths-ignore: + - '**.md' + - '**.yml' + - '!**/macos_ci.yml' + - 'cmd/tools/**' + - '!cmd/tools/builders/**.v' + +concurrency: + group: ${{ github.workflow }}-${{ github.ref == 'refs/heads/master' && github.sha || github.ref }} + cancel-in-progress: true + +jobs: + clang: + strategy: + matrix: + os: [macos-14] + fail-fast: false + runs-on: ${{ matrix.os }} + timeout-minutes: 121 + env: + VFLAGS: -cc clang + steps: + - uses: actions/checkout@v4 + - name: Build V + run: v run macos_ci.vsh build_v + - name: Test symlink + run: v run macos_ci.vsh test_symlink + - name: Test cross compilation to Linux + run: v run macos_ci.vsh test_cross_compilation + - name: Build V with -cstrict + run: v run macos_ci.vsh build_with_cstrict + - name: All code is formatted + run: v run macos_ci.vsh all_code_is_formatted + - name: Run sanitizers + run: v run macos_ci.vsh run_sanitizers + - name: Build V using V + run: v run macos_ci.vsh build_using_v + - name: Verify `v test` works + run: v run macos_ci.vsh verify_v_test_works + - name: Install iconv for encoding.iconv + run: v run macos_ci.vsh install_iconv + - name: Test pure V math module + run: v run macos_ci.vsh test_pure_v_math_module + - name: Self tests + run: v run macos_ci.vsh self_tests + - name: Build examples + run: v run macos_ci.vsh build_examples + - name: Build tetris with -autofree + run: v run macos_ci.vsh build_tetris_autofree + - name: Build blog tutorial with -autofree + run: v run macos_ci.vsh build_blog_autofree + - name: Build examples with -prod + run: v run macos_ci.vsh build_examples_prod + - name: v doctor + run: v run macos_ci.vsh v_doctor + - name: V self compilation with -usecache + run: v run macos_ci.vsh v_self_compilation_usecache + - name: V self compilation with -parallel-cc + run: v run macos_ci.vsh v_self_compilation_parallel_cc + - name: Test password input + run: v run macos_ci.vsh test_password_input + - name: Test readline + run: v run macos_ci.vsh test_readline + - name: Test vlib modules with -skip-unused + run: v run macos_ci.vsh test_vlib_skip_unused +