Skip to content
Open
Show file tree
Hide file tree
Changes from 12 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
190 changes: 190 additions & 0 deletions .github/scripts/package-integrated-test-local-images.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,190 @@
#!/usr/bin/env bash

set -euo pipefail

usage() {
cat <<'EOF'
Usage: package-integrated-test-local-images.sh [options]

Create one tarball containing all local :latest Docker images referenced by the
matrix cases in .github/workflows/integrated-test.yml.

Options:
--workflow FILE Workflow to inspect. Default: .github/workflows/integrated-test.yml
--compose-root DIR Compose root. Default: shenyu-integrated-test
--case NAME Package images for one workflow matrix case. Repeatable.
--output FILE Output tar path. Default: ./artifacts/integrated-test-local-images.tar
--exclude-admin Exclude apache/shenyu-admin:latest.
--exclude-image IMG Exclude a specific image. Repeatable.
--exclude-file FILE Read excluded images from a file, one per line.
--image-regex REGEX Local image regex. Default: ^(apache/shenyu-|shenyu-).+:latest$
--dry-run Print the images that would be packaged
-h, --help Show this help
EOF
}

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

repo_root() {
git rev-parse --show-toplevel 2>/dev/null || pwd
}

contains_exact() {
local needle="$1"
shift || true
local item
for item in "$@"; do
if [ "$item" = "$needle" ]; then
return 0
fi
done
return 1
}

workflow="$(repo_root)/.github/workflows/integrated-test.yml"
compose_root="$(repo_root)/shenyu-integrated-test"
output="$(repo_root)/artifacts/integrated-test-local-images.tar"
image_regex='^(apache/shenyu-|shenyu-).+:latest$'
dry_run=0
exclude_images=()
selected_cases=()

while [ "$#" -gt 0 ]; do
case "$1" in
--workflow)
workflow="$2"
shift 2
;;
--compose-root)
compose_root="$2"
shift 2
;;
--case)
selected_cases+=("$2")
shift 2
;;
--output)
output="$2"
shift 2
;;
--exclude-admin)
exclude_images+=("apache/shenyu-admin:latest")
shift
;;
--exclude-image)
exclude_images+=("$2")
shift 2
;;
--exclude-file)
[ -f "$2" ] || die "exclude file not found: $2"
while IFS= read -r line || [ -n "$line" ]; do
case "$line" in
''|\#*)
continue
;;
*)
exclude_images+=("$line")
;;
esac
done < "$2"
shift 2
;;
--image-regex)
image_regex="$2"
shift 2
;;
--dry-run)
dry_run=1
shift
;;
-h|--help)
usage
exit 0
;;
*)
die "unknown argument: $1"
;;
esac
done

command -v docker >/dev/null 2>&1 || die "docker is required"
[ -f "$workflow" ] || die "workflow not found: $workflow"
[ -d "$compose_root" ] || die "compose root not found: $compose_root"

tmp_cases="$(mktemp "${TMPDIR:-/tmp}/shenyu-it-cases.XXXXXX")"
tmp_cases_selected="$(mktemp "${TMPDIR:-/tmp}/shenyu-it-cases-selected.XXXXXX")"
tmp_images="$(mktemp "${TMPDIR:-/tmp}/shenyu-it-images.XXXXXX")"
trap 'rm -f "$tmp_cases" "$tmp_cases_selected" "$tmp_images"' EXIT

awk '
$1 == "case:" { in_case = 1; next }
in_case && $1 == "runs-on:" { exit }
in_case && $1 == "-" { print $2 }
' "$workflow" > "$tmp_cases"

[ -s "$tmp_cases" ] || die "no matrix cases found in $workflow"

if [ "${#selected_cases[@]}" -gt 0 ]; then
for selected_case in "${selected_cases[@]}"; do
if grep -Fxq "$selected_case" "$tmp_cases"; then
printf '%s\n' "$selected_case" >> "$tmp_cases_selected"
else
die "matrix case not found in $workflow: $selected_case"
fi
done
sort -u "$tmp_cases_selected" -o "$tmp_cases_selected"
mv "$tmp_cases_selected" "$tmp_cases"
fi

while IFS= read -r case_name; do
compose_file="${compose_root%/}/${case_name}/docker-compose.yml"
[ -f "$compose_file" ] || die "compose file not found for ${case_name}: ${compose_file}"

docker compose -f "$compose_file" config --images 2>/dev/null \
| grep -E "$image_regex" \
>> "$tmp_images" || true
done < "$tmp_cases"

sort -u "$tmp_images" -o "$tmp_images"

if [ "${#exclude_images[@]}" -gt 0 ]; then
tmp_filtered="$(mktemp "${TMPDIR:-/tmp}/shenyu-it-images-filtered.XXXXXX")"
trap 'rm -f "$tmp_cases" "$tmp_cases_selected" "$tmp_images" "$tmp_filtered"' EXIT

while IFS= read -r image; do
if contains_exact "$image" "${exclude_images[@]}"; then
continue
fi
printf '%s\n' "$image"
done < "$tmp_images" > "$tmp_filtered"

mv "$tmp_filtered" "$tmp_images"
fi

[ -s "$tmp_images" ] || die "no matching local images found"

if [ "$dry_run" -eq 1 ]; then
cat "$tmp_images"
exit 0
fi

while IFS= read -r image; do
docker image inspect "$image" >/dev/null 2>&1 || die "local image not found: $image"
done < "$tmp_images"

mkdir -p "$(dirname "$output")"

images=()
while IFS= read -r image; do
images+=("$image")
done < "$tmp_images"

docker save -o "$output" "${images[@]}"
cp "$tmp_images" "${output}.manifest.txt"

count="$(wc -l < "$tmp_images" | tr -d ' ')"
echo "packaged ${count} images into ${output}"
echo "manifest written to ${output}.manifest.txt"
145 changes: 145 additions & 0 deletions .github/scripts/package-shenyu-maven-snapshots.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
#!/usr/bin/env bash

set -euo pipefail

usage() {
cat <<'EOF'
Usage: package-shenyu-maven-snapshots.sh [options]

Package local org/apache/shenyu SNAPSHOT artifacts from ~/.m2/repository into
one tarball that can be extracted into another runner's Maven repository.

Options:
--repo DIR Maven repository root. Default: $HOME/.m2/repository
--group-path DIR Group path under the repository. Default: org/apache/shenyu
--version VER Snapshot version to package. Default: parsed from ./pom.xml
--output FILE Output tar.gz path. Default: ./artifacts/shenyu-maven-snapshots.tar.gz
--include-local-metadata
Include _remote.repositories and maven-metadata-local.xml
for compatibility fallback. Default: disabled
--dry-run Print the files that would be packaged
-h, --help Show this help
EOF
}

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

repo_root() {
git rev-parse --show-toplevel 2>/dev/null || pwd
}

parse_version() {
local root
root="$(repo_root)"

perl -0777 -ne '
if (m{<artifactId>\s*shenyu\s*</artifactId>.*?<version>\s*([^<]+)\s*</version>}s) {
print $1;
exit 0;
}
exit 1;
' "$root/pom.xml"
}

repo="${HOME}/.m2/repository"
group_path="org/apache/shenyu"
version=""
output=""
dry_run=0
include_local_metadata=0

while [ "$#" -gt 0 ]; do
case "$1" in
--repo)
repo="$2"
shift 2
;;
--group-path)
group_path="$2"
shift 2
;;
--version)
version="$2"
shift 2
;;
--output)
output="$2"
shift 2
;;
--include-local-metadata)
include_local_metadata=1
shift
;;
--dry-run)
dry_run=1
shift
;;
-h|--help)
usage
exit 0
;;
*)
die "unknown argument: $1"
;;
esac
done

[ -d "$repo" ] || die "maven repository not found: $repo"

if [ -z "$version" ]; then
version="$(parse_version)" || die "failed to parse project version from pom.xml"
fi

if [ -z "$output" ]; then
output="$(repo_root)/artifacts/shenyu-maven-snapshots.tar.gz"
fi

search_root="${repo%/}/${group_path}"
[ -d "$search_root" ] || die "group path not found in repository: $search_root"

tmp_list="$(mktemp "${TMPDIR:-/tmp}/shenyu-maven-snapshots.XXXXXX")"
trap 'rm -f "$tmp_list"' EXIT

find "$search_root" -type d -path "*/${version}" | while IFS= read -r version_dir; do
find "$version_dir" -maxdepth 1 -type f \
\( -name '*.pom' -o -name '*.jar' \) \
! -name '*-sources.jar' \
! -name '*-javadoc.jar' \
! -name '*.lastUpdated' \
| while IFS= read -r artifact_file; do
printf '%s\n' "${artifact_file#${repo%/}/}"
done

if [ "$include_local_metadata" -eq 1 ]; then
metadata="${version_dir}/_remote.repositories"
if [ -f "$metadata" ]; then
printf '%s\n' "${metadata#${repo%/}/}"
fi

artifact_dir="$(dirname "$version_dir")"
metadata="${artifact_dir}/maven-metadata-local.xml"
if [ -f "$metadata" ]; then
printf '%s\n' "${metadata#${repo%/}/}"
fi
fi
done | sort -u > "$tmp_list"

if [ ! -s "$tmp_list" ]; then
die "no ${version} artifacts found under ${search_root}"
fi

if [ "$dry_run" -eq 1 ]; then
cat "$tmp_list"
exit 0
fi

mkdir -p "$(dirname "$output")"
tar -C "$repo" -czf "$output" -T "$tmp_list"
cp "$tmp_list" "${output}.manifest.txt"

count="$(wc -l < "$tmp_list" | tr -d ' ')"
echo "packaged ${count} paths into ${output}"
echo "manifest written to ${output}.manifest.txt"
4 changes: 4 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@

name: ci

concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true

on:
pull_request:
push:
Expand Down
4 changes: 4 additions & 0 deletions .github/workflows/codeql-analysis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@

name: "CodeQL"

concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true

on:
push:
branches:
Expand Down
Loading
Loading