diff --git a/.github/scripts/find_changed_modules.gsh b/.github/scripts/find_changed_modules.gsh new file mode 100644 index 0000000..fe9762a --- /dev/null +++ b/.github/scripts/find_changed_modules.gsh @@ -0,0 +1,119 @@ +import ( + "encoding/json" + "fmt" + "io/fs" + "os" + "path/filepath" + "sort" +) + +func formulaDir(module, changedPath string) string { + dir := filepath.dir(changedPath) + for dir.hasPrefix(module + "/") { + matches := filepath.glob(filepath.join(dir, "*_llar.gox"))! + if matches.len > 0 { + return dir + } + dir = filepath.dir(dir) + } + return "" +} + +func hasFormula(module string) (bool, error) { + found := false + err := filepath.walkDir(module, (_, entry, err) => { + if err != nil { + return err + } + if !entry.isDir && entry.name.hasSuffix("_llar.gox") { + found = true + return fs.SkipAll + } + return nil + }) + if os.isNotExist(err) { + return false, nil + } + return found, err +} + +baseSHA := $BASE_SHA +defaultBranch := $DEFAULT_BRANCH +eventName := $EVENT_NAME +headSHA := $HEAD_SHA +refName := $REF_NAME + +var diffBase string +if eventName == "pull_request" { + capout => { git "merge-base", baseSHA, headSHA } + lastErr! + diffBase = output.trimSpace +} else if refName == defaultBranch { + diffBase = baseSHA +} else { + capout => { git "merge-base", "origin/"+defaultBranch, headSHA } + lastErr! + diffBase = output.trimSpace +} + +capout => { + git "diff", "--name-only", "--diff-filter=ACDMRT", "-z", diffBase, headSHA +} +lastErr! + +var modules map[string]bool = {} +var formulaDirs map[string]map[string]bool = {} +for changedPath in output.split("\x00") { + parts := changedPath.splitN("/", 3) + if parts.len < 3 { + continue + } + module := parts[0] + "/" + parts[1] + _, err := os.stat(filepath.join(module, "versions.json")) + if err != nil { + if !os.isNotExist(err) { + panic err + } + has := hasFormula(module)! + if has { + panic fmt.Sprintf("module %s is missing versions.json", module) + } + continue + } + modules[module] = true + + dir := formulaDir(module, changedPath) + if dir != "" { + dirs := formulaDirs[module] + if dirs == nil { + dirs = {} + formulaDirs[module] = dirs + } + dirs[dir] = true + } +} + +changedModules := []string([]) +changedModules <- [module for module, _ in modules]... +sort.strings changedModules + +for module in changedModules { + dirs := formulaDirs[module] + if len(dirs) > 1 { + changedDirs := [dir for dir, _ in dirs] + sort.strings changedDirs + panic fmt.Sprintf("module %s changes multiple Formula directories: %s; llar test cannot validate multiple fromVer ranges yet", module, changedDirs.join(", ")) + } +} + +// TODO: When changed modules depend on each other, test only the leaf modules +// in their dependency graph. +modulesJSON := json.marshal(changedModules)! + +outputFile := os.openFile($GITHUB_OUTPUT, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)! +defer outputFile.close() +fmt.fprintf! outputFile, "modules=%s\nhas_modules=%t\n", modulesJSON, changedModules.len > 0 + +summaryFile := os.openFile($GITHUB_STEP_SUMMARY, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)! +defer summaryFile.close() +fmt.fprintf! summaryFile, "Changed modules: %s\n", modulesJSON diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index dad4618..7b1f1fc 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -25,38 +25,23 @@ jobs: with: fetch-depth: 0 + - name: Set up Go + uses: actions/setup-go@v7 + with: + go-version: 1.24.0 + cache: false + - name: Find changed modules id: modules - shell: bash env: BASE_SHA: ${{ github.event.pull_request.base.sha || github.event.before }} + DEFAULT_BRANCH: ${{ github.event.repository.default_branch }} + EVENT_NAME: ${{ github.event_name }} HEAD_SHA: ${{ github.event.pull_request.head.sha || github.event.after }} + REF_NAME: ${{ github.ref_name }} run: | - changed_modules=() - - changed_paths=(git diff --name-only --diff-filter=ACMRT -z "$BASE_SHA" "$HEAD_SHA") - if ! git cat-file -e "${BASE_SHA}^{commit}" 2>/dev/null; then - # A first branch push has no previous commit. For example, GitHub - # supplies an all-zero `before` SHA when creating a new branch. - changed_paths=(git ls-tree -r -z --name-only "$HEAD_SHA") - fi - - while IFS= read -r -d '' path; do - IFS=/ read -r owner repo _ <<< "$path" - module="$owner/$repo" - if [[ -f "$module/versions.json" ]]; then - changed_modules+=("$module") - fi - done < <("${changed_paths[@]}") - - modules_json="$({ printf '%s\n' "${changed_modules[@]}" | sort -u; } | jq -Rsc 'split("\n") | map(select(length > 0))')" - echo "modules=$modules_json" >> "$GITHUB_OUTPUT" - if [[ "$modules_json" == "[]" ]]; then - echo "has_modules=false" >> "$GITHUB_OUTPUT" - else - echo "has_modules=true" >> "$GITHUB_OUTPUT" - fi - echo "Changed modules: $modules_json" >> "$GITHUB_STEP_SUMMARY" + go install -tags=linknamefix -ldflags="-checklinkname=0" github.com/goplus/ixgo/cmd/ixgo@v1.1.1 + "$(go env GOPATH)/bin/ixgo" run .github/scripts/find_changed_modules.gsh test: name: ${{ matrix.module }} (${{ matrix.goos }}-${{ matrix.goarch }})