Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 2 additions & 3 deletions docs/flutter-upgrade.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,14 +47,13 @@ version and leaves it absent.
Execute in Bash,

```bash
find ~/.vfox/cache/flutter/v-3.47.0 -name .vfox-manifest -print -delete
rm "$(vfox info --format '{{.Path}}' flutter@3.47.0)/.vfox-manifest"
```

### Windows 11

Assume that PowerShell 7 is already installed. Execute in PowerShell 7,

```powershell
Get-ChildItem "$env:USERPROFILE\.vfox\cache\flutter\v-3.47.0" -Recurse -Force -Filter .vfox-manifest |
Remove-Item
Remove-Item "$(vfox info --format '{{.Path}}' flutter@3.47.0)/.vfox-manifest"
```
2 changes: 1 addition & 1 deletion metadata.lua
Original file line number Diff line number Diff line change
Expand Up @@ -24,5 +24,5 @@ NOTE:
PLUGIN.minRuntimeVersion = "0.3.0"
-- Some things that need user to be attention!
PLUGIN.notes = {
"Do NOT run `flutter upgrade` (or `flutter downgrade`, `flutter channel`, or any in-place git operation) inside a vfox-managed Flutter SDK. It mutates the SDK in place and vfox will silently hand you the wrong version on the next `vfox use`. Change versions with `vfox install flutter@<version>` and `vfox use flutter@<version>`. This plugin detects such drift and prints a warning with the restore commands on the next `vfox use`.",
"See https://github.com/version-fox/vfox-flutter/blob/main/README.md for documentation.",
}
5 changes: 2 additions & 3 deletions tests/e2e/linux/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,13 @@ FROM ubuntu:26.04
ENV DEBIAN_FRONTEND=noninteractive

RUN <<EOF
set -eux
set -o errexit -o nounset -o xtrace
apt-get update
apt-get install --assume-yes \
curl \
git \
golang \
libglu1-mesa \
unzip \
jq \
zip
EOF

Expand Down
54 changes: 54 additions & 0 deletions tests/e2e/linux/config.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
#!/usr/bin/env bash
# Single source of truth for matrix defaults. Sourced, not executed:
# source "$here/config.sh"
#
# NOTE: tests/e2e/windows/lib.ps1 duplicates DEFAULT_OFFICIAL_VERSION and
# DEFAULT_OHOS_VERSION (bash and PowerShell share no config format).
# Bump both sides together.

if [[ -n "${VFOX_E2E_CONFIG_SH:-}" ]]; then
return 0 2>/dev/null || exit 0
fi
VFOX_E2E_CONFIG_SH=1

DEFAULT_OFFICIAL_VERSION="3.47.4"
DEFAULT_OHOS_VERSION="3.41.10-ohos-1.0.0"
DEFAULT_MIRROR_CN="https://storage.flutter-io.cn"

# resolve_flutter_version <official|ohos> honours $FLUTTER_VERSION / $OHOS_VERSION.
resolve_flutter_version() {
local flavor="$1"
local version=""
case "$flavor" in
official) version="${FLUTTER_VERSION:-$DEFAULT_OFFICIAL_VERSION}" ;;
ohos) version="${OHOS_VERSION:-$DEFAULT_OHOS_VERSION}" ;;
*)
echo "FAIL unknown flavor $flavor" >&2
return 1
;;
esac
printf '%s' "$version"
}

# default_flavours <amd64|arm64>: ohos has no arm64 artefacts, so arm64 runs
# official only (same rule as the Windows matrix).
default_flavours() {
if [[ "$1" == "arm64" ]]; then
echo "official"
else
echo "official ohos"
fi
}

default_mirrors() {
if [[ "$1" == "arm64" ]]; then
echo "default"
else
echo "default $DEFAULT_MIRROR_CN"
fi
}

# releases_index_for_mirror <mirror> <linux|windows>
releases_index_for_mirror() {
printf '%s/flutter_infra_release/releases/releases_%s.json' "${1%/}" "$2"
}
108 changes: 56 additions & 52 deletions tests/e2e/linux/e2e.sh
Original file line number Diff line number Diff line change
@@ -1,66 +1,70 @@
#!/usr/bin/env bash
set -euo pipefail
# Host-side matrix runner: build the image once, then fan out one container
# per (vfox version x flavor x mirror) combination, at most $max_jobs at a
# time. Logs are prefixed so parallel runs stay readable.
set -o errexit -o nounset -o pipefail

here="$(dirname "${BASH_SOURCE[0]}")"
repo="$(cd "$here/../../.." && pwd)"

host_arch="$(uname -m)"
case "$host_arch" in
x86_64) host_arch="amd64" ;;
aarch64|arm64) host_arch="arm64" ;;
esac
arch="${ARCH:-$host_arch}"
platform="linux/$arch"
image="vfox-flutter-e2e:linux-$arch"

docker build --pull --platform "$platform" -f "$here/Dockerfile" -t "$image" "$repo"

foxes="${VFOX_VERSION:-latest main}"
default_flavours="official ohos"
default_mirrors="default https://storage.flutter-io.cn"
if [ "$arch" = arm64 ]; then
default_flavours="official"
default_mirrors="default"
fi
flavours="${FLAVOR:-$default_flavours}"
mirrors="${MIRROR:-$default_mirrors}"
mirror_explicit="${MIRROR:-}"

max_jobs=3
failed=0
here="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# shellcheck source=lib.sh
source "$here/lib.sh"
# shellcheck source=config.sh
source "$here/config.sh"

run_one() {
local vfox="$1"
local flavor="$2"
local mirror="$3"
local image="$1"
local platform="$2"
local vfox="$3"
local flavor="$4"
local mirror="$5"
local prefix="vfox $vfox, $flavor, mirror $mirror, $platform"
local env=("-e" "VFOX_VERSION=$vfox" "-e" "FLAVOR=$flavor")
if [ "$mirror" != default ]; then
env+=("-e" "FLUTTER_STORAGE_BASE_URL=$mirror")
local env=(--env "VFOX_VERSION=$vfox" --env "FLAVOR=$flavor")
if [[ "$mirror" != "default" ]]; then
env+=(--env "FLUTTER_STORAGE_BASE_URL=$mirror")
fi
docker run --rm --platform "$platform" "${env[@]}" "$image" 2>&1 | sed -e "s|^|[$prefix] |"
docker run --rm --platform "$platform" "${env[@]}" "$image" 2>&1 | sed --expression "s|^|[$prefix] |"
}

for vfox in $foxes; do
for flavor in $flavours; do
for mirror in $mirrors; do
if [ -z "$mirror_explicit" ] && [ "$mirror" != default ] && [ "$vfox" != latest ]; then
continue
fi
run_one "$vfox" "$flavor" "$mirror" &
while [ "$(jobs -p | wc -l)" -ge "$max_jobs" ]; do
if ! wait -n; then
failed=1
main() {
local repo arch platform image
repo="$(cd "$here/../../.." && pwd)"
arch="$(normalize_arch "${ARCH:-$(uname --machine)}")"
platform="linux/$arch"
image="vfox-flutter-e2e:linux-$arch"

docker build --pull --platform "$platform" --file "$here/Dockerfile" --tag "$image" "$repo"

# Space-separated env lists (e.g. FLAVOR="official ohos") are split
# into arrays up front, so the loops below need no word splitting.
# (read is a bash builtin with no long-option form for -r/-a.)
local -a foxes flavours mirrors
read -ra foxes <<< "${VFOX_VERSION:-latest main}"
read -ra flavours <<< "${FLAVOR:-$(default_flavours "$arch")}"
read -ra mirrors <<< "${MIRROR:-$(default_mirrors "$arch")}"
local mirror_explicit="${MIRROR:-}"
local max_jobs="${E2E_MAX_JOBS:-3}"
local failed=0

for vfox in "${foxes[@]}"; do
for flavor in "${flavours[@]}"; do
for mirror in "${mirrors[@]}"; do
# The mirror matrix only runs against latest vfox unless the
# caller explicitly pins MIRROR, to keep CI time bounded.
if [[ -z "$mirror_explicit" && "$mirror" != "default" && "$vfox" != "latest" ]]; then
continue
fi
run_one "$image" "$platform" "$vfox" "$flavor" "$mirror" &
while [[ "$(jobs -p | wc --lines)" -ge "$max_jobs" ]]; do
wait -n || failed=1
done
done
done
done
done

while [ "$(jobs -p | wc -l)" -gt 0 ]; do
if ! wait -n; then
failed=1
fi
done
while [[ "$(jobs -p | wc --lines)" -gt 0 ]]; do
wait -n || failed=1
done

return "$failed"
}

exit "$failed"
main "$@"
39 changes: 17 additions & 22 deletions tests/e2e/linux/install.sh
Original file line number Diff line number Diff line change
@@ -1,28 +1,23 @@
#!/usr/bin/env bash
set -eu
# Install and activate one Flutter version: `bash install.sh <version>`.
# Runs standalone (called as a subprocess by run.sh, like install.ps1).
set -o errexit -o nounset -o pipefail

version="${1:?missing version}"
here="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# shellcheck source=lib.sh
source "$here/lib.sh"

eval "$(vfox activate bash)"

install_code=1
for attempt in 1 2 3; do
if vfox install flutter@"$version"; then
install_code=0
break
else
install_code=$?
fi
if [ "$attempt" -lt 3 ]; then
echo "retrying vfox install flutter@${version}, attempt ${attempt} exited ${install_code}"
sleep $((10 * attempt))
install_flutter_version() {
local version="$1"
activate_vfox
if ! retry "vfox install flutter@${version}" vfox install flutter@"$version"; then
die "vfox install flutter@${version} failed after ${E2E_RETRY_ATTEMPTS:-3} attempts"
fi
done
vfox use --global flutter@"$version"
activate_vfox
}

if [ "$install_code" -ne 0 ]; then
echo "FAIL vfox install flutter@${version} exited with code ${install_code}" >&2
exit 1
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
version="${1:?usage: install.sh <flutter-version>}"
install_flutter_version "$version"
fi

vfox use --global flutter@"$version"
eval "$(vfox activate bash)"
110 changes: 110 additions & 0 deletions tests/e2e/linux/lib.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
#!/usr/bin/env bash
# Shared helpers for the Linux container E2E suite. Sourced, not executed:
# source "$here/lib.sh"
#
# Layout (mirrors tests/e2e/windows):
# lib.sh - generic helpers (this file; no side effects when sourced)
# config.sh - default versions / flavours / mirrors
# setup.sh - install vfox and register the local flutter plugin
# install.sh - install one Flutter version with retries
# verify.sh - assert on the installed SDK (layout, drift, toolchain)
# run.sh - thin in-container orchestrator: setup -> install -> verify
# e2e.sh - host-side matrix runner (builds the image, fans out containers)

if [[ -n "${VFOX_E2E_LIB_SH:-}" ]]; then
return 0 2>/dev/null || exit 0
fi
VFOX_E2E_LIB_SH=1

die() {
echo "FAIL $*" >&2
exit 1
}

pass() {
echo "PASS $*"
}

# assert_contains <actual> <expected> <label>
# Prints PASS and returns 0 on match, prints FAIL and returns 1 otherwise.
# Callers running under `set -o errexit` abort on failure; callers that need to
# continue must guard the call with `if` / `||`.
assert_contains() {
local actual="$1"
local expected="$2"
local label="$3"
if [[ -z "$expected" ]]; then
echo "FAIL $label : the expected value is empty" >&2
return 1
fi
if printf '%s' "$actual" | grep --quiet --fixed-strings -- "$expected"; then
echo "PASS $label contains $expected"
return 0
fi
{
echo "FAIL $label is missing $expected"
echo "--- actual ---"
echo "$actual"
} >&2
return 1
}

# retry <label> <command...>
# Runs the command streaming its output (so `out=$(retry ...)` still
# captures it) and retries up to $E2E_RETRY_ATTEMPTS times with linear
# backoff. Progress notices go to stderr to stay out of captures.
retry() {
local label="$1"
shift
local max="${E2E_RETRY_ATTEMPTS:-3}"
local attempt=1
local code=1
while ((attempt <= max)); do
if "$@"; then
return 0
else
# NB: $code must be captured in the else branch. Reading $? after
# the whole `if` would yield the if-statement's own status (0).
code=$?
fi
if ((attempt < max)); then
echo "retrying ${label}, attempt ${attempt} exited ${code}" >&2
sleep $((10 * attempt))
fi
attempt=$((attempt + 1))
done
return "$code"
}

# require_env <NAME> prints the value or aborts; keeps "missing X" errors uniform.
require_env() {
local name="$1"
if [[ -z "${!name:-}" ]]; then
die "$name is not set"
fi
printf '%s' "${!name}"
}

# normalize_arch <uname -m | $ARCH alias> prints amd64|arm64 or fails.
normalize_arch() {
case "$1" in
x86_64 | amd64) echo amd64 ;;
aarch64 | arm64) echo arm64 ;;
*)
echo "FAIL unknown architecture $1" >&2
return 1
;;
esac
}

activate_vfox() {
# SC1090 cannot be fixed: vfox prints shell code at runtime, so there
# is no static file for shellcheck to follow.
# shellcheck disable=SC1090
eval "$(vfox activate bash)"
}

# sdk_dir prints the SDK root for the active flutter on PATH.
sdk_dir() {
(cd "$(dirname "$(command -v flutter)")"/.. && pwd)
}
Loading
Loading