diff --git a/.github/workflows/build-exes-impl.yml b/.github/workflows/build-exes-impl.yml index ad504de..c0bc6f3 100644 --- a/.github/workflows/build-exes-impl.yml +++ b/.github/workflows/build-exes-impl.yml @@ -28,11 +28,29 @@ on: required: true default: "INFO" type: string + tmate_debugging: + description: "Enable tmate debugging (https://github.com/marketplace/actions/debugging-with-tmate)" + required: true + type: string + unit_tests: + description: "Run unit tests on the built executables." + required: true + type: string unit_test_args: description: "CLI args to pass verbatim to pytest (unit tests)." required: false type: string default: "" + integration_tests: + description: "Run integration tests on the built executables." + required: true + type: string + integration_test_args: + description: > + CLI args to pass verbatim to pytest (integration tests). + required: false + type: string + default: "" executable_name: description: > Template parameter. @@ -140,6 +158,59 @@ jobs: echo "sha is: $sha" echo "sha=$sha" >> $GITHUB_OUTPUT + cache-app-data: + permissions: + # No write permission + contents: read + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v5 + with: + ref: ${{ inputs.ref }} + + - name: Set up python + uses: actions/setup-python@v6 + with: + python-version: ${{ inputs.python-version }} + + - name: Set up poetry + uses: hpcflow/github-support/setup-poetry@main + with: + version: ${{ inputs.poetry-version }} + + - name: Cache dependencies + uses: hpcflow/github-support/init-cache@main + with: + name: test + version: ${{ inputs.python-version }} + + - name: Install dependencies + run: | + poetry install --without dev,pyinstaller + + - name: Set data dir # in case we have a custom tag to use + if: inputs.config_data_dir != '' + run: | + poetry run ${{ inputs.executable_name }} config set data_dir ${{ inputs.config_data_dir }} + + - name: Set program dir # in case we have a custom tag to use + if: inputs.config_program_dir != '' + run: | + poetry run ${{ inputs.executable_name }} config set program_dir ${{ inputs.config_program_dir }} + + - name: Cache all app data and programs + run: | + poetry run ${{ inputs.executable_name }} data cache --all + poetry run ${{ inputs.executable_name }} program cache --all + + - name: Upload all cached app data/programs + id: upload-cached-app-data + uses: actions/upload-artifact@v6 + with: + name: ${{ inputs.executable_name }}-app-data-cache + path: ~/.cache/${{ inputs.executable_name }} + windows: name: Build Windows Executables if: inputs.build_windows == 'true' @@ -147,11 +218,18 @@ jobs: success: ${{ steps.upload-file.outcome == 'success' || steps.upload-folder.outcome == 'success' }} file: ${{ steps.upload-file.outputs.artifact-url }} folder: ${{ steps.upload-folder.outputs.artifact-url }} - needs: status + needs: [status, cache-app-data] runs-on: windows-latest steps: - name: Checkout uses: actions/checkout@v6 + + - name: Setup tmate session + if: inputs.tmate_debugging == 'true' + uses: mxschmitt/action-tmate@v3 + with: + detached: true + - name: Set up python ${{ inputs.python-version }} uses: actions/setup-python@v6 with: @@ -161,6 +239,13 @@ jobs: with: name: build-exe version: ${{ inputs.python-version }} + + - name: Download prepared cached app data + uses: actions/download-artifact@v7 + with: + name: ${{ inputs.executable_name }}-app-data-cache + path: ${{ inputs.executable_name }}-app-data-cache + - name: Set up poetry uses: hpcflow/github-support/setup-poetry@main with: @@ -169,6 +254,13 @@ jobs: - name: Install dependencies run: poetry install --without dev + - name: Configure the app's Python environment # this allows us to run integration tests that use `script_data_in/out: "direct"` + id: configure_python_env + run: | + poetry run ${{ inputs.executable_name }} env setup python --use-current + $result = (poetry run ${{ inputs.executable_name }} env info source_file -l python) + "env_source_file=$result" | Out-File -FilePath $env:GITHUB_OUTPUT -Append -Encoding utf8 + - name: Build with pyinstaller for Windows (file) id: win_onefile if: inputs.build_onefile == 'true' @@ -211,41 +303,41 @@ jobs: name: ${{ inputs.executable_name }}-${{ needs.status.outputs.version }}-win-build path: ${{ inputs.pyinstaller_dir }}/build/${{ inputs.executable_name }}-${{ needs.status.outputs.version }}-win - - name: Set data dir (file) # in case we have a custom tag to use - if: steps.win_onefile.outcome == 'success' && inputs.config_data_dir != '' - run: | - ${{ inputs.pyinstaller_dir }}/dist/onefile/${{ inputs.executable_name }}-${{ needs.status.outputs.version }}-win.exe config set data_dir ${{ inputs.config_data_dir }} - - - name: Set program dir (file) # in case we have a custom tag to use - if: steps.win_onefile.outcome == 'success' && inputs.config_program_dir != '' - run: | - ${{ inputs.pyinstaller_dir }}/dist/onefile/${{ inputs.executable_name }}-${{ needs.status.outputs.version }}-win.exe config set program_dir ${{ inputs.config_program_dir }} - - - name: Set data dir (folder) # in case we have a custom tag to use - if: steps.win_onedir.outcome == 'success' && inputs.config_data_dir != '' - run: | - ${{ inputs.pyinstaller_dir }}/dist/onedir/${{ inputs.executable_name }}-${{ needs.status.outputs.version }}-win-dir/${{ inputs.executable_name }}-${{ needs.status.outputs.version }}-win-dir.exe config set data_dir ${{ inputs.config_data_dir }} - - - name: Set program dir (folder) # in case we have a custom tag to use - if: steps.win_onedir.outcome == 'success' && inputs.config_program_dir != '' + - name: Install cached app data + env: + PYTHONUTF8: 1 run: | - ${{ inputs.pyinstaller_dir }}/dist/onedir/${{ inputs.executable_name }}-${{ needs.status.outputs.version }}-win-dir/${{ inputs.executable_name }}-${{ needs.status.outputs.version }}-win-dir.exe config set program_dir ${{ inputs.config_program_dir }} + poetry run ${{ inputs.executable_name }} data install-cache ${{ inputs.executable_name }}-app-data-cache/data + poetry run ${{ inputs.executable_name }} data --list + poetry run ${{ inputs.executable_name }} program install-cache ${{ inputs.executable_name }}-app-data-cache/programs + poetry run ${{ inputs.executable_name }} program --list - name: Run test suite on the frozen app (file) - if: steps.win_onefile.outcome == 'success' + if: steps.win_onefile.outcome == 'success' && inputs.unit_tests == 'true' env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} PYTHONUNBUFFERED: ok + PYTHONUTF8: 1 run: | - ${{ inputs.pyinstaller_dir }}/dist/onefile/${{ inputs.executable_name }}-${{ needs.status.outputs.version }}-win.exe test ${{ inputs.unit_test_args }} + ${{ inputs.pyinstaller_dir }}/dist/onefile/${{ inputs.executable_name }}-${{ needs.status.outputs.version }}-win.exe test --with-env-source ${{ steps.configure_python_env.outputs.env_source_file }} ${{ inputs.unit_test_args }} - name: Run test suite on the frozen app (folder) - if: steps.win_onedir.outcome == 'success' + if: steps.win_onedir.outcome == 'success' && inputs.unit_tests == 'true' env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} PYTHONUNBUFFERED: ok + PYTHONUTF8: 1 run: | - ${{ inputs.pyinstaller_dir }}/dist/onedir/${{ inputs.executable_name }}-${{ needs.status.outputs.version }}-win-dir/${{ inputs.executable_name }}-${{ needs.status.outputs.version }}-win-dir.exe test ${{ inputs.unit_test_args }} + ${{ inputs.pyinstaller_dir }}/dist/onedir/${{ inputs.executable_name }}-${{ needs.status.outputs.version }}-win-dir/${{ inputs.executable_name }}-${{ needs.status.outputs.version }}-win-dir.exe test --with-env-source ${{ steps.configure_python_env.outputs.env_source_file }} ${{ inputs.unit_test_args }} + + - name: Run integration test suite on the frozen app (file) # tests are more likely to fail in the one-file build than the one-dir build, so just run integration tests with the one-file build + if: steps.win_onefile.outcome == 'success' && inputs.integration_tests == 'true' + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + PYTHONUNBUFFERED: ok + PYTHONUTF8: 1 + run: | + ${{ inputs.pyinstaller_dir }}/dist/onefile/${{ inputs.executable_name }}-${{ needs.status.outputs.version }}-win.exe test --with-env-source ${{ steps.configure_python_env.outputs.env_source_file }} ${{ inputs.integration_test_args }} --integration macos: name: Build macOS Executables @@ -254,11 +346,18 @@ jobs: success: ${{ steps.upload-file.outcome == 'success' || steps.upload-folder.outcome == 'success' }} file: ${{ steps.upload-file.outputs.artifact-url }} folder: ${{ steps.upload-folder.outputs.artifact-url }} - needs: status + needs: [status, cache-app-data] runs-on: macos-latest steps: - name: Checkout uses: actions/checkout@v6 + + - name: Setup tmate session + if: inputs.tmate_debugging == 'true' + uses: mxschmitt/action-tmate@v3 + with: + detached: true + - name: Set up python ${{ inputs.python-version }} uses: actions/setup-python@v6 with: @@ -268,6 +367,13 @@ jobs: with: name: build-exe version: ${{ inputs.python-version }} + + - name: Download prepared cached app data + uses: actions/download-artifact@v7 + with: + name: ${{ inputs.executable_name }}-app-data-cache + path: ${{ inputs.executable_name }}-app-data-cache + - name: Set up poetry uses: hpcflow/github-support/setup-poetry@main with: @@ -276,6 +382,13 @@ jobs: - name: Install dependencies run: poetry install --without dev + - name: Configure the app's Python environment # this allows us to run integration tests that use `script_data_in/out: "direct"` + id: configure_python_env + run: | + poetry run ${{ inputs.executable_name }} env setup python --use-current + result=$(poetry run ${{ inputs.executable_name }} env info source_file -l python) + echo "env_source_file=$result" >> "$GITHUB_OUTPUT" + - name: Build with pyinstaller for macOS (file) id: mac_onefile if: inputs.build_onefile == 'true' @@ -318,41 +431,36 @@ jobs: name: ${{ inputs.executable_name }}-${{ needs.status.outputs.version }}-macOS-build path: ${{ inputs.pyinstaller_dir }}/build/${{ inputs.executable_name }}-${{ needs.status.outputs.version }}-macOS - - name: Set data dir (file) # in case we have a custom tag to use - if: steps.mac_onefile.outcome == 'success' && inputs.config_data_dir != '' - run: | - ${{ inputs.pyinstaller_dir }}/dist/onefile/${{ inputs.executable_name }}-${{ needs.status.outputs.version }}-macOS config set data_dir ${{ inputs.config_data_dir }} - - - name: Set program dir (file) # in case we have a custom tag to use - if: steps.mac_onefile.outcome == 'success' && inputs.config_program_dir != '' + - name: Install cached app data run: | - ${{ inputs.pyinstaller_dir }}/dist/onefile/${{ inputs.executable_name }}-${{ needs.status.outputs.version }}-macOS config set program_dir ${{ inputs.config_program_dir }} - - - name: Set data dir (folder) # in case we have a custom tag to use - if: steps.mac_onedir.outcome == 'success' && inputs.config_data_dir != '' - run: | - ${{ inputs.pyinstaller_dir }}/dist/onedir/${{ inputs.executable_name }}-${{ needs.status.outputs.version }}-macOS-dir/${{ inputs.executable_name }}-${{ needs.status.outputs.version }}-macOS-dir config set data_dir ${{ inputs.config_data_dir }} - - - name: Set program dir (folder) # in case we have a custom tag to use - if: steps.mac_onedir.outcome == 'success' && inputs.config_program_dir != '' - run: | - ${{ inputs.pyinstaller_dir }}/dist/onedir/${{ inputs.executable_name }}-${{ needs.status.outputs.version }}-macOS-dir/${{ inputs.executable_name }}-${{ needs.status.outputs.version }}-macOS-dir config set program_dir ${{ inputs.config_program_dir }} + poetry run ${{ inputs.executable_name }} data install-cache ${{ inputs.executable_name }}-app-data-cache/data + poetry run ${{ inputs.executable_name }} data --list + poetry run ${{ inputs.executable_name }} program install-cache ${{ inputs.executable_name }}-app-data-cache/programs + poetry run ${{ inputs.executable_name }} program --list - name: Run test suite on the frozen app (file) - if: steps.mac_onefile.outcome == 'success' + if: steps.mac_onefile.outcome == 'success' && inputs.unit_tests == 'true' env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} PYTHONUNBUFFERED: ok run: | - ${{ inputs.pyinstaller_dir }}/dist/onefile/${{ inputs.executable_name }}-${{ needs.status.outputs.version }}-macOS test ${{ inputs.unit_test_args }} + ${{ inputs.pyinstaller_dir }}/dist/onefile/${{ inputs.executable_name }}-${{ needs.status.outputs.version }}-macOS test --with-env-source ${{ steps.configure_python_env.outputs.env_source_file }} ${{ inputs.unit_test_args }} - name: Run test suite on the frozen app (folder) - if: steps.mac_onedir.outcome == 'success' + if: steps.mac_onedir.outcome == 'success' && inputs.unit_tests == 'true' env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} PYTHONUNBUFFERED: ok run: | - ${{ inputs.pyinstaller_dir }}/dist/onedir/${{ inputs.executable_name }}-${{ needs.status.outputs.version }}-macOS-dir/${{ inputs.executable_name }}-${{ needs.status.outputs.version }}-macOS-dir test ${{ inputs.unit_test_args }} + ${{ inputs.pyinstaller_dir }}/dist/onedir/${{ inputs.executable_name }}-${{ needs.status.outputs.version }}-macOS-dir/${{ inputs.executable_name }}-${{ needs.status.outputs.version }}-macOS-dir test --with-env-source ${{ steps.configure_python_env.outputs.env_source_file }} ${{ inputs.unit_test_args }} + + - name: Run integration test suite on the frozen app (file) # tests are more likely to fail in the one-file build than the one-dir build, so just run integration tests with the one-file build + if: steps.mac_onefile.outcome == 'success' && inputs.integration_tests == 'true' + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + PYTHONUNBUFFERED: ok + run: | + ${{ inputs.pyinstaller_dir }}/dist/onefile/${{ inputs.executable_name }}-${{ needs.status.outputs.version }}-macOS test --with-env-source ${{ steps.configure_python_env.outputs.env_source_file }} ${{ inputs.integration_test_args }} --integration linux: name: Build Linux (Rocky Linux 8) Executables @@ -361,54 +469,86 @@ jobs: success: ${{ steps.upload-file.outcome == 'success' || steps.upload-folder.outcome == 'success' }} file: ${{ steps.upload-file.outputs.artifact-url }} folder: ${{ steps.upload-folder.outputs.artifact-url }} - needs: status + needs: [status, cache-app-data] runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v6 + + - name: Setup tmate session + if: inputs.tmate_debugging == 'true' + uses: mxschmitt/action-tmate@v3 + with: + detached: true + - name: Cache dependencies uses: hpcflow/github-support/init-cache@0.3 with: name: build-exe version: ${{ inputs.python-version }} + - name: Download prepared cached app data + uses: actions/download-artifact@v7 + with: + name: ${{ inputs.executable_name }}-app-data-cache + path: ${{ inputs.executable_name }}-app-data-cache + + - name: Store user and group IDs + run: | + echo "UID=$(id -u)" >> $GITHUB_ENV + echo "GID=$(id -g)" >> $GITHUB_ENV + - name: Build executable (file) within Docker id: linux_onefile if: inputs.build_onefile == 'true' uses: addnab/docker-run-action@v3 with: - image: ghcr.io/hpcflow/rockylinux8-python:latest - options: -v ${{ github.workspace }}:/home --env GH_TOKEN=${{ secrets.GITHUB_TOKEN }} + image: ghcr.io/hpcflow/rockylinux8-python:latest # most of the options are just so we can debug (via tmate) when we have a custom pytest --basetemp directory + options: | + -v ${{ github.workspace }}:/home + -u ${{ env.UID }}:${{ env.GID }} + --env HOME=/home + --env XDG_DATA_HOME=/home/.local/share + --env XDG_CACHE_HOME=/home/.cache + --env GH_TOKEN=${{ secrets.GITHUB_TOKEN }} + --env UNIT_TESTS=${{ inputs.unit_tests }} + --env INTEGRATION_TESTS=${{ inputs.integration_tests }} run: | + set -e # exit on first failure + # set up poetry cd /home poetry config virtualenvs.in-project true poetry install --without dev + # Configure the app's Python environment + # this allows us to run integration tests that use `script_data_in/out: "direct"` + poetry run ${{ inputs.executable_name }} env setup python --use-current + ENV_SOURCE_FILE=$(poetry run ${{ inputs.executable_name }} env info source_file -l python) + echo "ENV_SOURCE_FILE=${ENV_SOURCE_FILE}" + # build with pyinstaller for Rocky Linux (file) cd ${{ inputs.pyinstaller_dir }} ./make.sh ${{ inputs.executable_name }}-${{ needs.status.outputs.version }}-linux ${{ inputs.logLevel }} onefile cd .. - # Set data dir in case we have a custom tag to use - if [[ -n "${{ inputs.config_data_dir }}" ]]; then - echo "config_data_dir is not empty: ${{ inputs.config_data_dir }}" - ${{ inputs.pyinstaller_dir }}/dist/onefile/${{ inputs.executable_name }}-${{ needs.status.outputs.version }}-linux config set data_dir ${{ inputs.config_data_dir }} - else - echo "config_data_dir is empty, skipping command" - fi + # install cache data + poetry run ${{ inputs.executable_name }} data install-cache ${{ inputs.executable_name }}-app-data-cache/data + poetry run ${{ inputs.executable_name }} data --list + poetry run ${{ inputs.executable_name }} program install-cache ${{ inputs.executable_name }}-app-data-cache/programs + poetry run ${{ inputs.executable_name }} program --list - # Set program dir in case we have a custom tag to use - if [[ -n "${{ inputs.config_program_dir }}" ]]; then - echo "config_program_dir is not empty: ${{ inputs.config_program_dir }}" - ${{ inputs.pyinstaller_dir }}/dist/onefile/${{ inputs.executable_name }}-${{ needs.status.outputs.version }}-linux config set program_dir ${{ inputs.config_program_dir }} - else - echo "config_program_dir is empty, skipping command" + export PYTHONUNBUFFERED=ok + if [ "$UNIT_TESTS" = "true" ]; then + # run test suite on the frozen app (file) + ${{ inputs.pyinstaller_dir }}/dist/onefile/${{ inputs.executable_name }}-${{ needs.status.outputs.version }}-linux test --with-env-source ${ENV_SOURCE_FILE} ${{ inputs.unit_test_args }} fi - export PYTHONUNBUFFERED=ok - # run test suite on the frozen app (file) - ${{ inputs.pyinstaller_dir }}/dist/onefile/${{ inputs.executable_name }}-${{ needs.status.outputs.version }}-linux test ${{ inputs.unit_test_args }} + if [ "$INTEGRATION_TESTS" == "true" ]; then + # run integration test suite on the frozen app (file) + # tests are more likely to fail in the one-file build than the one-dir build, so just run integration tests with the one-file build + ${{ inputs.pyinstaller_dir }}/dist/onefile/${{ inputs.executable_name }}-${{ needs.status.outputs.version }}-linux test --with-env-source ${ENV_SOURCE_FILE} ${{ inputs.integration_test_args }} --integration + fi - name: Build executable (folder) within Docker id: linux_onedir @@ -418,35 +558,35 @@ jobs: image: ghcr.io/hpcflow/rockylinux8-python:latest options: -v ${{ github.workspace }}:/home --env GH_TOKEN=${{ secrets.GITHUB_TOKEN }} run: | + set -e # exit on first failure + # set up poetry cd /home poetry config virtualenvs.in-project true poetry install --without dev + # Configure the app's Python environment + # this allows us to run integration tests that use `script_data_in/out: "direct"` + poetry run ${{ inputs.executable_name }} env setup python --use-current + ENV_SOURCE_FILE=$(poetry run ${{ inputs.executable_name }} env info source_file -l python) + echo "ENV_SOURCE_FILE=${ENV_SOURCE_FILE}" + # build with pyinstaller for Rocky Linux (folder) cd ${{ inputs.pyinstaller_dir }} ./make.sh ${{ inputs.executable_name }}-${{ needs.status.outputs.version }}-linux-dir ${{ inputs.logLevel }} onedir cd .. - # Set data dir in case we have a custom tag to use - if [[ -n "${{ inputs.config_data_dir }}" ]]; then - echo "config_data_dir is not empty: ${{ inputs.config_data_dir }}" - ${{ inputs.pyinstaller_dir }}/dist/onedir/${{ inputs.executable_name }}-${{ needs.status.outputs.version }}-linux-dir/${{ inputs.executable_name }}-${{ needs.status.outputs.version }}-linux-dir config set data_dir ${{ inputs.config_data_dir }} - else - echo "config_data_dir is empty, skipping command" - fi - - # Set program dir in case we have a custom tag to use - if [[ -n "${{ inputs.config_program_dir }}" ]]; then - echo "config_program_dir is not empty: ${{ inputs.config_program_dir }}" - ${{ inputs.pyinstaller_dir }}/dist/onedir/${{ inputs.executable_name }}-${{ needs.status.outputs.version }}-linux-dir/${{ inputs.executable_name }}-${{ needs.status.outputs.version }}-linux-dir config set program_dir ${{ inputs.config_program_dir }} - else - echo "config_program_dir is empty, skipping command" - fi + # install cache data + poetry run ${{ inputs.executable_name }} data install-cache ${{ inputs.executable_name }}-app-data-cache/data + poetry run ${{ inputs.executable_name }} data --list + poetry run ${{ inputs.executable_name }} program install-cache ${{ inputs.executable_name }}-app-data-cache/programs + poetry run ${{ inputs.executable_name }} program --list export PYTHONUNBUFFERED=ok - # run test suite on the frozen app (folder) - ${{ inputs.pyinstaller_dir }}/dist/onedir/${{ inputs.executable_name }}-${{ needs.status.outputs.version }}-linux-dir/${{ inputs.executable_name }}-${{ needs.status.outputs.version }}-linux-dir test ${{ inputs.unit_test_args }} + if [ "$UNIT_TESTS" == "true" ]; then + # run test suite on the frozen app (folder) + ${{ inputs.pyinstaller_dir }}/dist/onedir/${{ inputs.executable_name }}-${{ needs.status.outputs.version }}-linux-dir/${{ inputs.executable_name }}-${{ needs.status.outputs.version }}-linux-dir test --with-env-source ${ENV_SOURCE_FILE} ${{ inputs.unit_test_args }} + fi - name: Upload executable artifact (file) id: upload-file diff --git a/.github/workflows/release-impl.yml b/.github/workflows/release-impl.yml index ecf73eb..257db97 100644 --- a/.github/workflows/release-impl.yml +++ b/.github/workflows/release-impl.yml @@ -288,8 +288,51 @@ jobs: name: CHANGELOG_increment path: CHANGELOG_increment.md + cache-app-data: + permissions: + # No write permission + contents: read + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v5 + with: + ref: ${{ inputs.ref }} + + - name: Set up python + uses: actions/setup-python@v6 + with: + python-version: ${{ inputs.python-version }} + + - name: Set up poetry + uses: hpcflow/github-support/setup-poetry@main + with: + version: ${{ inputs.poetry-version }} + + - name: Cache dependencies + uses: hpcflow/github-support/init-cache@main + with: + name: test + version: ${{ inputs.python-version }} + + - name: Install dependencies + run: | + poetry install --without dev,pyinstaller + + - name: Cache all app data and programs + run: | + poetry run ${{ inputs.executable_name }} data cache --all + poetry run ${{ inputs.executable_name }} program cache --all + + - name: Upload all cached app data/programs + id: upload-cached-app-data + uses: actions/upload-artifact@v6 + with: + name: ${{ inputs.executable_name }}-app-data-cache + path: ~/.cache/${{ inputs.executable_name }} + build-executables: - needs: bump-version + needs: [bump-version, cache-app-data] strategy: fail-fast: false matrix: @@ -303,6 +346,11 @@ jobs: executable_os: macOS runs-on: ${{ matrix.os }} + env: + BUILT_EXE_BASE_NAME: ${{ inputs.executable_name }}-${{ needs.bump-version.outputs.new_tag }} + BUILT_EXE_PATH_DIR: ${{ inputs.pyinstaller_dir }}/dist/onedir/${{ inputs.executable_name }}-${{ needs.bump-version.outputs.new_tag }}-${{ matrix.executable_os }}-dir/${{ inputs.executable_name }}-${{ needs.bump-version.outputs.new_tag }}-${{ matrix.executable_os }}-dir${{ matrix.executable_ext }} + BUILT_EXE_PATH_DIR_ZIPPED: ${{ inputs.pyinstaller_dir }}/dist/onedir/${{ inputs.executable_name }}-${{ needs.bump-version.outputs.new_tag }}-${{ matrix.executable_os }}-dir.zip + BUILT_EXE_PATH_FILE: ${{ inputs.pyinstaller_dir }}/dist/onefile/${{ inputs.executable_name }}-${{ needs.bump-version.outputs.new_tag }}-${{ matrix.executable_os }}${{ matrix.executable_ext }} steps: - name: Checkout uses: actions/checkout@v6 @@ -317,6 +365,13 @@ jobs: with: name: build version: ${{ inputs.python-version }} + + - name: Download prepared cached app data + uses: actions/download-artifact@v7 + with: + name: ${{ inputs.executable_name }}-app-data-cache + path: ${{ inputs.executable_name }}-app-data-cache + - name: Set up poetry uses: hpcflow/github-support/setup-poetry@main with: @@ -330,74 +385,87 @@ jobs: working-directory: ${{ inputs.pyinstaller_dir }} run: ./make.sh $TARGET INFO 'onefile' env: - TARGET: ${{ inputs.executable_name }}-${{ needs.bump-version.outputs.new_tag }}-${{ matrix.executable_os }} + TARGET: ${{ env.BUILT_EXE_BASE_NAME }}-${{ matrix.executable_os }} - name: Build with pyinstaller (non-Windows, folder) if: runner.os != 'Windows' working-directory: ${{ inputs.pyinstaller_dir }} run: ./make.sh $TARGET INFO 'onedir' env: - TARGET: ${{ inputs.executable_name }}-${{ needs.bump-version.outputs.new_tag}}-${{ matrix.executable_os }}-dir + TARGET: ${{ env.BUILT_EXE_BASE_NAME }}-${{ matrix.executable_os }}-dir - name: Build with pyinstaller (Windows, file) if: runner.os == 'Windows' working-directory: ${{ inputs.pyinstaller_dir }} run: ./make.ps1 -ExeName $Env:TARGET -LogLevel INFO -BuildType 'onefile' env: - TARGET: ${{ inputs.executable_name }}-${{ needs.bump-version.outputs.new_tag }}-${{ matrix.executable_os }} + TARGET: ${{ env.BUILT_EXE_BASE_NAME }}-${{ matrix.executable_os }} - name: Build with pyinstaller (Windows, folder) if: runner.os == 'Windows' working-directory: ${{ inputs.pyinstaller_dir }} run: ./make.ps1 -ExeName $Env:TARGET -LogLevel INFO -BuildType 'onedir' env: - TARGET: ${{ inputs.executable_name }}-${{ needs.bump-version.outputs.new_tag }}-${{ matrix.executable_os }}-dir + TARGET: ${{ env.BUILT_EXE_BASE_NAME }}-${{ matrix.executable_os }}-dir - name: Version check (file) uses: hpcflow/github-support/compare@0.3 with: expected: "${{ inputs.app_name }}, version ${{ needs.bump-version.outputs.version }}" - command: ${{ inputs.pyinstaller_dir }}/dist/onefile/${{ inputs.executable_name }}-${{ needs.bump-version.outputs.new_tag }}-${{ matrix.executable_os }}${{ matrix.executable_ext }} --version + command: ${{ env.BUILT_EXE_PATH_FILE }} --version - name: Version check (folder) uses: hpcflow/github-support/compare@0.3 with: expected: "${{ inputs.app_name }}, version ${{ needs.bump-version.outputs.version }}" - command: ${{ inputs.pyinstaller_dir }}/dist/onedir/${{ inputs.executable_name }}-${{ needs.bump-version.outputs.new_tag }}-${{ matrix.executable_os }}-dir/${{ inputs.executable_name }}-${{ needs.bump-version.outputs.new_tag }}-${{ matrix.executable_os }}-dir${{ matrix.executable_ext }} --version + command: ${{ env.BUILT_EXE_PATH_DIR }} --version + + - name: Install cached app data + env: + PYTHONUTF8: 1 + run: | + ${{ env.BUILT_EXE_PATH_DIR }} data install-cache ${{ inputs.executable_name }}-app-data-cache/data + ${{ env.BUILT_EXE_PATH_DIR }} data --list + ${{ env.BUILT_EXE_PATH_DIR }} program install-cache ${{ inputs.executable_name }}-app-data-cache/programs + ${{ env.BUILT_EXE_PATH_DIR }} program --list - name: Run test suite on the frozen app (folder) env: GH_TOKEN: ${{ secrets.general-token }} run: | - ${{ inputs.pyinstaller_dir }}/dist/onedir/${{ inputs.executable_name }}-${{ needs.bump-version.outputs.new_tag }}-${{ matrix.executable_os }}-dir/${{ inputs.executable_name }}-${{ needs.bump-version.outputs.new_tag }}-${{ matrix.executable_os }}-dir${{ matrix.executable_ext }} test + ${{ env.BUILT_EXE_PATH_DIR }} test - name: Compress folder (windows, folder) if: runner.os == 'Windows' working-directory: ${{ inputs.pyinstaller_dir }} - run: ./compress.ps1 -ExeName '${{ inputs.executable_name }}-${{ needs.bump-version.outputs.new_tag }}-${{ matrix.executable_os }}-dir' -BuildType 'onedir' + run: ./compress.ps1 -ExeName '${{ env.BUILT_EXE_BASE_NAME }}-${{ matrix.executable_os }}-dir' -BuildType 'onedir' - name: Compress folder (non-windows, folder) if: runner.os != 'Windows' working-directory: ${{ inputs.pyinstaller_dir }} run: ./compress.sh $TARGET 'onedir' env: - TARGET: ${{ inputs.executable_name }}-${{ needs.bump-version.outputs.new_tag }}-${{ matrix.executable_os }}-dir + TARGET: ${{ env.BUILT_EXE_BASE_NAME }}-${{ matrix.executable_os }}-dir - name: Upload executable artifact (file) uses: actions/upload-artifact@v6 with: - name: ${{ inputs.executable_name }}-${{ needs.bump-version.outputs.new_tag }}-${{ matrix.executable_os }}${{ matrix.executable_ext }} - path: ${{ inputs.pyinstaller_dir }}/dist/onefile/${{ inputs.executable_name }}-${{ needs.bump-version.outputs.new_tag }}-${{ matrix.executable_os }}${{ matrix.executable_ext }} + name: ${{ env.BUILT_EXE_BASE_NAME }}-${{ matrix.executable_os }}${{ matrix.executable_ext }} + path: ${{ env.BUILT_EXE_PATH_FILE }} - name: Upload executable artifact (compressed folder) uses: actions/upload-artifact@v6 with: - name: ${{ inputs.executable_name }}-${{ needs.bump-version.outputs.new_tag }}-${{ matrix.executable_os }}-dir.zip - path: ${{ inputs.pyinstaller_dir }}/dist/onedir/${{ inputs.executable_name }}-${{ needs.bump-version.outputs.new_tag }}-${{ matrix.executable_os }}-dir.zip + name: ${{ env.BUILT_EXE_BASE_NAME }}-${{ matrix.executable_os }}-dir.zip + path: ${{ env.BUILT_EXE_PATH_DIR_ZIPPED }} build-executables-linux: runs-on: ubuntu-latest - needs: bump-version + needs: [bump-version, cache-app-data] + env: + BUILT_EXE_PATH_DIR: ${{ inputs.pyinstaller_dir }}/dist/onedir/${{ inputs.executable_name }}-${{ needs.bump-version.outputs.new_tag }}-linux-dir/${{ inputs.executable_name }}-${{ needs.bump-version.outputs.new_tag }}-linux-dir + BUILT_EXE_PATH_DIR_ZIPPED: ${{ inputs.pyinstaller_dir }}/dist/onedir/${{ inputs.executable_name }}-${{ needs.bump-version.outputs.new_tag }}-linux-dir.zip + BUILT_EXE_PATH_FILE: ${{ inputs.pyinstaller_dir }}/dist/onefile/${{ inputs.executable_name }}-${{ needs.bump-version.outputs.new_tag }}-linux steps: - name: Checkout uses: actions/checkout@v6 @@ -409,6 +477,12 @@ jobs: name: build version: ${{ inputs.python-version }} + - name: Download prepared cached app data + uses: actions/download-artifact@v7 + with: + name: ${{ inputs.executable_name }}-app-data-cache + path: ${{ inputs.executable_name }}-app-data-cache + - name: Build executables within Docker uses: addnab/docker-run-action@v3 with: @@ -419,53 +493,58 @@ jobs: cd /home poetry config virtualenvs.in-project true poetry install --without dev - base="${{ inputs.executable_name }}-${{ needs.bump-version.outputs.new_tag }}" vers_expected="${{ inputs.app_name }}, version ${{ needs.bump-version.outputs.version }}" # build with pyinstaller for Rocky Linux (file) cd ${{ inputs.pyinstaller_dir }} - ./make.sh ${base}-linux INFO onefile + ./make.sh ${{ env.BUILT_EXE_BASE_NAME }}-linux INFO onefile cd .. # version check (file) - vers=$(${{ inputs.pyinstaller_dir }}/dist/onefile/${base}-linux --version) + vers=$(${{ env.BUILT_EXE_PATH_FILE }} --version) echo $vers echo $vers_expected [ "$vers" = "$vers_expected" ] + # install cache data + ${{ env.BUILT_EXE_PATH_FILE }} data install-cache ${{ inputs.executable_name }}-app-data-cache/data + ${{ env.BUILT_EXE_PATH_FILE }} data --list + ${{ env.BUILT_EXE_PATH_FILE }} program install-cache ${{ inputs.executable_name }}-app-data-cache/programs + ${{ env.BUILT_EXE_PATH_FILE }} program --list + # run test suite on the frozen app (file) - ${{ inputs.pyinstaller_dir }}/dist/onefile/${base}-linux test + ${{ env.BUILT_EXE_PATH_FILE }} test # build with pyinstaller for Rocky Linux (folder) cd ${{ inputs.pyinstaller_dir }} - ./make.sh ${base}-linux-dir INFO onedir + ./make.sh ${{ env.BUILT_EXE_BASE_NAME }}-linux-dir INFO onedir cd .. # version check (folder) - vers=$(${{ inputs.pyinstaller_dir }}/dist/onedir/${base}-linux-dir/${base}-linux-dir --version) + vers=$(${{ env.BUILT_EXE_PATH_DIR }} --version) echo $vers echo $vers_expected [ "$vers" = "$vers_expected" ] # run test suite on the frozen app (folder) - ${{ inputs.pyinstaller_dir }}/dist/onedir/${base}-linux-dir/${base}-linux-dir test + ${{ env.BUILT_EXE_PATH_DIR }} test # Compress folder (folder) cd ${{ inputs.pyinstaller_dir }} - ./compress.sh ${base}-linux-dir 'onedir' + ./compress.sh ${{ env.BUILT_EXE_BASE_NAME }}-linux-dir 'onedir' cd .. - name: Upload executable artifact (file) uses: actions/upload-artifact@v6 with: - name: ${{ inputs.executable_name }}-${{ needs.bump-version.outputs.new_tag }}-linux - path: ${{ inputs.pyinstaller_dir }}/dist/onefile/${{ inputs.executable_name }}-${{ needs.bump-version.outputs.new_tag }}-linux + name: ${{ env.BUILT_EXE_BASE_NAME }}-linux + path: ${{ env.BUILT_EXE_PATH_FILE }} - name: Upload executable artifact (compressed folder) uses: actions/upload-artifact@v6 with: - name: ${{ inputs.executable_name }}-${{ needs.bump-version.outputs.new_tag }}-linux-dir.zip - path: ${{ inputs.pyinstaller_dir }}/dist/onedir/${{ inputs.executable_name }}-${{ needs.bump-version.outputs.new_tag }}-linux-dir.zip + name: ${{ env.BUILT_EXE_BASE_NAME }}-linux-dir.zip + path: ${{ inputs.pyinstaller_dir }}/dist/onedir/${{ env.BUILT_EXE_BASE_NAME }}-linux-dir.zip make-workflow-benchmark: needs: bump-version diff --git a/.github/workflows/test-impl.yml b/.github/workflows/test-impl.yml index 2f1e123..ed03a85 100644 --- a/.github/workflows/test-impl.yml +++ b/.github/workflows/test-impl.yml @@ -203,7 +203,7 @@ jobs: uses: hpcflow/github-support/init-cache@main with: name: test - version: ${{ matrix.python-version }} + version: "3.13" - name: Install dependencies timeout-minutes: ${{ inputs.install-timeout-minutes }}