diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index f36ed334..44745029 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -80,3 +80,22 @@ jobs: SublimeText/UnitTesting - uses: "./UnitTesting/actions/run-tests" - uses: "./UnitTesting/actions/run-syntax-tests" + + test-package-control-extra-packages: + strategy: + fail-fast: false + matrix: + st-version: [3, 4] + os: ["ubuntu-latest", "macOS-latest", "windows-latest"] + runs-on: ${{ matrix.os }} + steps: + - uses: actions/checkout@v6 + - uses: "./actions/setup" + with: + sublime-text-version: ${{ matrix.st-version }} + extra-packages: | + A File Icon + - name: Check package installed by Package Control + run: test -f "${SUBLIME_TEXT_PACKAGES%/}/../Installed Packages/A File Icon.sublime-package" + shell: bash + - uses: "./actions/run-tests" diff --git a/README.md b/README.md index b11109cc..b33a0610 100644 --- a/README.md +++ b/README.md @@ -336,6 +336,14 @@ jobs: - uses: codecov/codecov-action@v4 ``` +`extra-packages` takes one package per line, in one of these forms: + +- `user/repo@ref` or `Package Name:user/repo@ref` clones the package from GitHub. + `@ref` is a branch, a tag or a tag prefix (e.g. `st3-`). Without it, the latest `x.y.z` tag is used. +- `Package Name` (no `/`) lets Package Control install the package, + picking the latest release compatible with the Sublime Text build. + Requires `install-package-control: true` (the default). + Check [this](https://github.com/randy3k/UnitTesting-example) for further examples. diff --git a/actions/setup/action.yaml b/actions/setup/action.yaml index 08edd100..b41783f9 100644 --- a/actions/setup/action.yaml +++ b/actions/setup/action.yaml @@ -48,6 +48,9 @@ inputs: or just `user/repo@ref` if the repo name is the same as the package name. `@ref` could be either a branch name, a tag name , or a prefix of tags e.g. `st3-` or simply left empty. If an exact match is not found, the latest tag is determined by semver x.y.z. + A line with just a package name (no `/`), e.g. `A File Icon`, installs the package via + Package Control, which picks the latest release compatible with the Sublime Text build. + This requires `install-package-control` to be enabled. required: false display: description: internal and experimental only @@ -214,6 +217,7 @@ runs: fi # Install extra packages to to Packages/ + PC_PACKAGES="" while read -r x; do if [[ "$x" =~ ^(.*):(.*)/([^@]*)@?(.*)$ ]]; then PKG="${BASH_REMATCH[1]}" @@ -225,12 +229,29 @@ runs: USER="${BASH_REMATCH[1]}" REPO="${BASH_REMATCH[2]}" SHA="${BASH_REMATCH[3]}" + elif [ -n "$x" ]; then + # Plain package name, installed by Package Control + PC_PACKAGES+="$x"$'\n' + continue else continue fi InstallPackage "$PKG" "https://github.com/$USER/$REPO" "$SHA" done <<< "${{ inputs.extra-packages }}" + # Pass packages to be installed by Package Control to the next step + if [ -n "$PC_PACKAGES" ]; then + if [ "${{ inputs.install-package-control }}" != "true" ]; then + echo "::error::extra-packages lists packages to install via Package Control, but install-package-control is disabled." + exit 1 + fi + { + echo "UNITTESTING_PC_PACKAGES<> "$GITHUB_ENV" + fi + # Install UnitTesting to Packages/UnitTesting if not yet exists if [ ! -d "$SUBLIME_TEXT_PACKAGES/UnitTesting" ]; then echo "Copy action's 'UnitTesting' to $SUBLIME_TEXT_PACKAGES/UnitTesting" diff --git a/actions/setup/install_package_control.ps1 b/actions/setup/install_package_control.ps1 index affed857..e7d8ef23 100644 --- a/actions/setup/install_package_control.ps1 +++ b/actions/setup/install_package_control.ps1 @@ -26,6 +26,22 @@ if (-not (Test-Path $PC_SETTINGS)) { "{`"auto_upgrade`": false, `"ignore_vcs_packages`": true, `"remove_orphaned`": false, `"submit_usage`": false }" | Out-File -filepath $PC_SETTINGS -encoding utf8 } +# let Package Control install packages listed in `installed_packages` on startup +if ($env:UNITTESTING_PC_PACKAGES) { + Write-Verbose "Adding packages to be installed by Package Control:" + $settings = Get-Content -Raw $PC_SETTINGS | ConvertFrom-Json + $names = @($settings.installed_packages | Where-Object { $_ }) + foreach ($name in $env:UNITTESTING_PC_PACKAGES -split "`r?`n") { + $name = $name.Trim() + if ($name -and $names -notcontains $name) { + Write-Verbose " $name" + $names += $name + } + } + $settings | Add-Member -NotePropertyName installed_packages -NotePropertyValue $names -Force + $settings | ConvertTo-Json | Out-File -filepath $PC_SETTINGS -encoding utf8 +} + $PCH_PATH = "$STP\0_install_package_control_helper" New-Item -itemtype directory $PCH_PATH -force >$null diff --git a/actions/setup/install_package_control.sh b/actions/setup/install_package_control.sh index 7144a2ab..d3965451 100644 --- a/actions/setup/install_package_control.sh +++ b/actions/setup/install_package_control.sh @@ -55,6 +55,29 @@ if [ ! -f "$STP/User/Package Control.sublime-settings" ]; then echo '{"auto_upgrade": false, "ignore_vcs_packages": true, "remove_orphaned": false, "submit_usage": false }' > "$STP/User/Package Control.sublime-settings" fi +# let Package Control install packages listed in `installed_packages` on startup +if [ -n "$UNITTESTING_PC_PACKAGES" ]; then + echo Adding packages to be installed by Package Control: + printf '%s' "$UNITTESTING_PC_PACKAGES" | sed 's/^/ /' + python3 -B - "$STP/User/Package Control.sublime-settings" <<'EOF' +import json +import os +import sys + +path = sys.argv[1] +with open(path, encoding="utf-8") as f: + settings = json.load(f) +names = settings.get("installed_packages", []) +for name in os.environ["UNITTESTING_PC_PACKAGES"].splitlines(): + name = name.strip() + if name and name not in names: + names.append(name) +settings["installed_packages"] = names +with open(path, "w", encoding="utf-8") as f: + json.dump(settings, f, indent=4) +EOF +fi + PCH_PATH="$STP/0_install_package_control_helper" if [ ! -d "$PCH_PATH" ]; then diff --git a/actions/setup/install_package_control_helper.py b/actions/setup/install_package_control_helper.py index b22b714e..f996409e 100644 --- a/actions/setup/install_package_control_helper.py +++ b/actions/setup/install_package_control_helper.py @@ -44,12 +44,48 @@ def check_package_control(): Wait for Package Control to be loaded. """ if "Package Control" in sys.modules: - sublime.set_timeout(check_libraries, 2000) + sublime.set_timeout(check_packages, 2000) else: sublime.set_timeout(check_package_control, 2000) num_retries = 0 + def retry(callback): + """ + Schedule another check, return False if out of retries. + """ + nonlocal num_retries + + if num_retries < 20: + num_retries += 1 + sublime.set_timeout(callback, 2000) + return True + + return False + + def check_packages(): + """ + Wait for Package Control to install missing packages. + + PC4 automatically installs packages listed in `installed_packages` + at startup, before installing missing libraries. + """ + package_control = sys.modules["Package Control"].package_control + manager = package_control.package_manager.PackageManager() + settings = sublime.load_settings("Package Control.sublime-settings") + missing_packages = set(settings.get("installed_packages", [])) - manager.list_packages() + if not missing_packages: + check_libraries() + return + + if retry(check_packages): + return + + log.write("missing packages:" + "\n") + log.write("\n".join("- " + name for name in sorted(missing_packages)) + "\n") + touch("failed") + kill_subl(restart=False) + def check_libraries(): """ Wait for Package Control to finish bootstrapping. @@ -61,17 +97,13 @@ def check_libraries(): manager = package_control.package_manager.PackageManager() missing_libraries = manager.find_missing_libraries() if missing_libraries: - nonlocal num_retries - - if num_retries < 10: - num_retries += 1 - sublime.set_timeout(check_libraries, 2000) + if retry(check_libraries): return log.write("missing libraries:" + "\n") log.write( "\n".join( - "- {lib.name} for Python {lib.python_version}".format(lib) + "- {lib.name} for Python {lib.python_version}".format(lib=lib) for lib in sorted(missing_libraries) ) + "\n"