Skip to content

Commit 9834258

Browse files
authored
Merge branch 'konveyor:main' into main
2 parents 9f92b42 + b027ff8 commit 9834258

File tree

15 files changed

+517
-278
lines changed

15 files changed

+517
-278
lines changed

.github/workflows/koncur-test.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ jobs:
9696
EXIT_CODE=$?
9797
set -e
9898
echo "$OUTPUT"
99-
if [ $EXIT_CODE -ne 0 ] || echo "$OUTPUT" | grep -qE "(FAILED|Exit code mismatch)"; then
99+
if [ $EXIT_CODE -ne 0 ] || echo "$OUTPUT" | grep -qE "(FAILED|Exit code mismatch|exit code: 1|✗ Error)"; then
100100
echo "Koncur $test_name test failed (exit code: $EXIT_CODE)"
101101
FAILED=1
102102
else

.github/workflows/testing.yaml

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,15 @@ jobs:
5151
run: |
5252
podman build -t localhost/kantra:latest -f Dockerfile .
5353
go build -o kantra main.go
54-
54+
55+
- name: Extract containerless requirements from container
56+
run: |
57+
podman create --name kantra-extract localhost/kantra:latest
58+
podman cp kantra-extract:/usr/local/static-report .
59+
podman cp kantra-extract:/jdtls .
60+
podman cp kantra-extract:/opt/rulesets .
61+
podman rm kantra-extract
62+
5563
- name: Run unit tests
5664
run: |
5765
RUNNER_IMG=localhost/kantra:latest go test ./... -coverprofile=coverage.txt
@@ -108,7 +116,11 @@ jobs:
108116
- name: download kantra and run test
109117
run: |
110118
git clone https://github.com/konveyor/example-applications
111-
podman cp $(podman create --name kantra-download quay.io/konveyor/kantra:${{ inputs.tag }}):/usr/local/bin/kantra .
119+
podman create --name kantra-download quay.io/konveyor/kantra:${{ inputs.tag }}
120+
podman cp kantra-download:/usr/local/bin/kantra .
121+
podman cp kantra-download:/usr/local/static-report .
122+
podman cp kantra-download:/jdtls .
123+
podman cp kantra-download:/opt/rulesets .
112124
podman rm kantra-download
113125
./kantra analyze --input $(pwd)/example-applications/example-1/ \
114126
--output ./output/ --target cloud-readiness \

Dockerfile

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,8 @@ RUN echo -e "[almalinux9-appstream]" \
6969
"\nenabled = 1" \
7070
"\ngpgcheck = 0" > /etc/yum.repos.d/almalinux.repo
7171

72-
RUN microdnf -y install podman
72+
RUN microdnf -y install podman nodejs
73+
RUN npm install -g typescript-language-server typescript
7374
RUN echo mta:x:1001:0:1001 user:/home/mta:/sbin/nologin > /etc/passwd
7475
RUN echo mta:10000:5000 > /etc/subuid
7576
RUN echo mta:10000:5000 > /etc/subgid
@@ -85,9 +86,8 @@ RUN chown -R 0:1001 /usr/local/static-report
8586
COPY --from=builder /workspace/kantra /usr/local/bin/kantra
8687
COPY --from=builder /workspace/darwin-kantra /usr/local/bin/darwin-kantra
8788
COPY --from=builder /workspace/windows-kantra /usr/local/bin/windows-kantra
88-
COPY --from=rulesets /rulesets/default/generated /opt/rulesets
89+
COPY --from=rulesets /rulesets/stable /opt/rulesets
8990
COPY --from=rulesets /windup-rulesets/rules/rules-reviewed/openrewrite /opt/openrewrite
90-
COPY --from=static-report /usr/bin/js-bundle-generator /usr/local/bin
9191
COPY --from=static-report /usr/local/static-report /usr/local/static-report
9292
COPY --from=jaeger-builder /go/bin/all-in-one-linux /usr/local/bin/all-in-one-linux
9393
COPY --from=generic-provider /usr/local/bin/generic-external-provider /usr/local/bin/generic-external-provider

Dockerfile.windows

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ ARG VERSION=latest
22

33
FROM quay.io/konveyor/static-report:${VERSION} as static-report
44

5-
FROM mcr.microsoft.com/windows/servercore:ltsc2022 AS rulesets
5+
FROM mcr.microsoft.com/windows/servercore:ltsc2025 AS rulesets
66
SHELL ["powershell", "-Command", "$ErrorActionPreference = 'Stop'; $ProgressPreference = 'SilentlyContinue';"]
77

88
ENV GIT_VERSION 2.45.2
@@ -29,7 +29,7 @@ RUN $url = ('https://github.com/git-for-windows/git/releases/download/v{0}.windo
2929
ARG RULESETS_REF=main
3030
RUN C:\git\cmd\git.exe clone https://github.com/konveyor/rulesets -b $env:RULESETS_REF C:\rulesets
3131

32-
FROM golang:1.23-windowsservercore-ltsc2022 as builder
32+
FROM golang:1.25-windowsservercore-ltsc2025 as builder
3333

3434
WORKDIR /workspace
3535
# Copy the Go Modules manifests
@@ -49,19 +49,18 @@ ARG VERSION=latest
4949
ARG BUILD_COMMIT
5050
RUN go build -o kantra.exe main.go
5151

52-
FROM quay.io/konveyor/analyzer-lsp:${VERSION}
52+
FROM quay.io/konveyor/analyzer-lsp:${VERSION}-windowsservercore-ltsc2025
5353

5454
ENV DOTNET_PROVIDER_IMG=quay.io/konveyor/dotnet-external-provider:${VERSION}
5555

5656
# Set the working directory inside the container
5757
WORKDIR C:/app
5858

59-
RUN md C:\opt\rulesets\input C:\opt\rulesets\convert C:\opt\openrewrite C:\opt\input\rules\custom C:\opt\output C:\tmp\source-app C:\tmp\source-app\input
59+
RUN md C:\opt\rulesets\input C:\opt\rulesets\convert C:\opt\openrewrite C:\opt\input\rules\custom C:\tmp\source-app C:\tmp\source-app\input
6060

6161
# Copy the executable from the builder stage
6262
COPY --from=builder /workspace/kantra.exe .
6363
COPY --from=rulesets /rulesets/preview/dotnet /opt/rulesets
64-
COPY --from=static-report /usr/bin/js-bundle-generator .
6564
COPY --from=static-report /usr/local/static-report ./static-report
6665

6766
# Command to run the executable

cmd/analyze-bin.go

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -385,7 +385,7 @@ func (a *analyzeCommand) RunAnalysisContainerless(ctx context.Context) error {
385385

386386
startStaticReport := time.Now()
387387
operationalLog.Info("[TIMING] Starting static report generation")
388-
err = a.GenerateStaticReportContainerless(ctx, operationalLog)
388+
err = a.GenerateStaticReport(ctx, operationalLog)
389389
if err != nil {
390390
a.log.Error(err, "failed to generate static report")
391391
return err
@@ -966,7 +966,9 @@ func (a *analyzeCommand) buildStaticReportOutput(ctx context.Context, log *os.Fi
966966
return nil
967967
}
968968

969-
func (a *analyzeCommand) GenerateStaticReportContainerless(ctx context.Context, operationalLog logr.Logger) error {
969+
// GenerateStaticReport generates a static HTML report from analysis output.
970+
// This function is used by both containerless and hybrid execution modes.
971+
func (a *analyzeCommand) GenerateStaticReport(ctx context.Context, operationalLog logr.Logger) error {
970972
if a.skipStaticReport {
971973
return nil
972974
}
@@ -994,11 +996,11 @@ func (a *analyzeCommand) GenerateStaticReportContainerless(ctx context.Context,
994996
}
995997

996998
staticReportAnalyzePath := filepath.Join(a.kantraDir, "static-report")
997-
err = a.buildStaticReportFile(ctx, staticReportAnalyzePath, errors.Is(noDepFileErr, os.ErrNotExist))
999+
err = a.buildStaticReportOutput(ctx, staticReportLog)
9981000
if err != nil {
9991001
return err
10001002
}
1001-
err = a.buildStaticReportOutput(ctx, staticReportLog)
1003+
err = a.buildStaticReportFile(ctx, staticReportAnalyzePath, errors.Is(noDepFileErr, os.ErrNotExist))
10021004
if err != nil {
10031005
return err
10041006
}

cmd/analyze-bin_test.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1099,7 +1099,7 @@ func TestValidateContainerlessInput(t *testing.T) {
10991099
}
11001100
}
11011101

1102-
func TestGenerateStaticReportContainerlessSkipFlag(t *testing.T) {
1102+
func TestGenerateStaticReportSkipFlag(t *testing.T) {
11031103
log := logr.Discard()
11041104

11051105
tests := []struct {
@@ -1154,7 +1154,7 @@ func TestGenerateStaticReportContainerlessSkipFlag(t *testing.T) {
11541154

11551155
// Call the method
11561156
testLog := logr.Discard()
1157-
err = a.GenerateStaticReportContainerless(context.Background(), testLog)
1157+
err = a.GenerateStaticReport(context.Background(), testLog)
11581158

11591159
if tt.skipStaticReport {
11601160
// Should return nil immediately without doing anything
@@ -1219,7 +1219,7 @@ func TestSkipStaticReportFlagParsing(t *testing.T) {
12191219
}
12201220

12211221
testLog := logr.Discard()
1222-
err = a.GenerateStaticReportContainerless(ctx, testLog)
1222+
err = a.GenerateStaticReport(ctx, testLog)
12231223

12241224
if tt.skipStaticReport {
12251225
// Should return nil immediately

cmd/analyze-hybrid.go

Lines changed: 69 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -226,7 +226,8 @@ func (a *analyzeCommand) setupNetworkProvider(ctx context.Context, providerName
226226
providerSpecificConfig["lspServerName"] = providerName
227227
providerSpecificConfig["lspServerPath"] = JDTLSBinLocation
228228
providerSpecificConfig["bundles"] = JavaBundlesLocation
229-
providerSpecificConfig["depOpenSourceLabelsFile"] = "/usr/local/etc/maven.default.index"
229+
providerSpecificConfig["mavenIndexPath"] = MavenIndexPath
230+
providerSpecificConfig["depOpenSourceLabelsFile"] = DepOpenSourceLabels
230231
if a.mavenSettingsFile != "" {
231232
// Use container path where settings.xml is mounted (copied by getConfigVolumes)
232233
providerSpecificConfig["mavenSettingsFile"] = path.Join(util.ConfigMountPath, "settings.xml")
@@ -417,14 +418,15 @@ func (a *analyzeCommand) setupBuiltinProviderHybrid(ctx context.Context, additio
417418
}
418419

419420
builtinConfig := provider.Config{
420-
Name: "builtin",
421-
InitConfig: []provider.InitConfig{
422-
{
423-
Location: a.input,
424-
AnalysisMode: provider.AnalysisMode(a.mode),
425-
ProviderSpecificConfig: providerSpecificConfig,
426-
},
427-
},
421+
Name: "builtin",
422+
InitConfig: []provider.InitConfig{},
423+
}
424+
if !a.isFileInput {
425+
builtinConfig.InitConfig = append(builtinConfig.InitConfig, provider.InitConfig{
426+
Location: a.input,
427+
AnalysisMode: provider.AnalysisMode(a.mode),
428+
ProviderSpecificConfig: providerSpecificConfig,
429+
})
428430
}
429431

430432
// Set proxy if configured
@@ -592,6 +594,7 @@ func (a *analyzeCommand) RunAnalysisHybridInProcess(ctx context.Context) error {
592594
a.log.Info("loaded override provider settings", "file", a.overrideProviderSettings, "providers", len(overrideConfigs))
593595
}
594596

597+
providerToInputVolName := map[string]string{}
595598
// Start containerized providers if any
596599
if len(a.providersMap) > 0 {
597600
startProviderSetup := time.Now()
@@ -643,6 +646,7 @@ func (a *analyzeCommand) RunAnalysisHybridInProcess(ctx context.Context) error {
643646
type providerHealthResult struct {
644647
providerName string
645648
err error
649+
volName string
646650
}
647651
healthChan := make(chan providerHealthResult, len(a.providersMap))
648652

@@ -652,7 +656,7 @@ func (a *analyzeCommand) RunAnalysisHybridInProcess(ctx context.Context) error {
652656
provInit := provInit
653657
go func() {
654658
err := waitForProvider(ctx, provName, provInit.port, 30*time.Second, a.log)
655-
healthChan <- providerHealthResult{providerName: provName, err: err}
659+
healthChan <- providerHealthResult{providerName: provName, err: err, volName: volName}
656660
}()
657661
}
658662

@@ -662,6 +666,7 @@ func (a *analyzeCommand) RunAnalysisHybridInProcess(ctx context.Context) error {
662666
if result.err != nil {
663667
return fmt.Errorf("provider %s health check failed: %w", result.providerName, result.err)
664668
}
669+
providerToInputVolName[result.providerName] = result.volName
665670
}
666671

667672
a.log.Info("all providers are ready")
@@ -680,6 +685,13 @@ func (a *analyzeCommand) RunAnalysisHybridInProcess(ctx context.Context) error {
680685

681686
var additionalBuiltinConfigs []provider.InitConfig
682687

688+
hostRoot := a.input
689+
containerRoot := util.SourceMountPath
690+
if a.isFileInput {
691+
// For binary files, use parent directory as hostRoot
692+
hostRoot = filepath.Dir(a.input)
693+
containerRoot = path.Dir(util.SourceMountPath)
694+
}
683695
// Setup network-based provider clients for all configured providers
684696
for provName := range a.providersMap {
685697
a.log.Info("setting up network provider", "provider", provName)
@@ -699,38 +711,54 @@ func (a *analyzeCommand) RunAnalysisHybridInProcess(ctx context.Context) error {
699711
}
700712
providers[provName] = provClient
701713
providerLocations = append(providerLocations, locs...)
702-
additionalBuiltinConfigs = append(additionalBuiltinConfigs, configs...)
703-
}
704-
705-
// CRITICAL FIX: Transform container paths to host paths
706-
// The Java provider runs in a container and returns configs with container paths (/opt/input/source).
707-
// The builtin provider runs on the host and needs host paths (a.input).
708-
// We must transform these paths or builtin provider won't find any files!
709-
hostRoot := a.input
710-
containerRoot := util.SourceMountPath
711-
if a.isFileInput {
712-
// For binary files, use parent directory as hostRoot
713-
hostRoot = filepath.Dir(a.input)
714-
containerRoot = path.Dir(util.SourceMountPath)
715-
}
714+
// CRITICAL FIX: Transform container paths to host paths
715+
// The Java provider runs in a container and returns configs with container paths (/opt/input/source).
716+
// The builtin provider runs on the host and needs host paths (a.input).
717+
// We must transform these paths or builtin provider won't find any files!
718+
providerHostRoot := hostRoot
719+
if isBinaryAnalysis {
720+
cmd := exec.CommandContext(ctx, Settings.ContainerBinary, "volume", "inspect", providerToInputVolName[provName])
721+
o, err := cmd.Output()
722+
if err == nil {
723+
j := []map[string]any{}
724+
err = json.Unmarshal(o, &j)
725+
if len(j) == 1 {
726+
found := false
727+
if volPath, ok := j[0]["Mountpoint"]; ok {
728+
if _, err := os.Lstat(volPath.(string)); err == nil {
729+
providerHostRoot = volPath.(string)
730+
found = true
731+
}
732+
}
733+
if opt, ok := j[0]["Options"]; !found && ok {
734+
op, ok := opt.(map[string]any)
735+
if ok {
736+
if volPath, ok := op["device"]; ok {
737+
if _, err := os.Lstat(volPath.(string)); err == nil {
738+
providerHostRoot = volPath.(string)
739+
found = true
740+
}
741+
}
742+
}
743+
}
744+
}
745+
}
746+
}
716747

717-
transformedConfigs := make([]provider.InitConfig, len(additionalBuiltinConfigs))
718-
for i, conf := range additionalBuiltinConfigs {
719-
transformedConfigs[i] = conf
720-
// Replace container path prefix with host path
721-
if strings.HasPrefix(conf.Location, containerRoot) {
722-
rel := strings.TrimPrefix(conf.Location, containerRoot)
723-
rel = strings.TrimPrefix(rel, "/")
724-
if rel == "" {
725-
transformedConfigs[i].Location = hostRoot
726-
} else {
727-
transformedConfigs[i].Location = filepath.Join(hostRoot, rel)
748+
for _, c := range configs {
749+
if rel, err := filepath.Rel(containerRoot, c.Location); err == nil {
750+
if rel == "." {
751+
c.Location = providerHostRoot
752+
} else {
753+
c.Location = filepath.Join(providerHostRoot, filepath.FromSlash(rel))
754+
}
728755
}
756+
additionalBuiltinConfigs = append(additionalBuiltinConfigs, c)
729757
}
730758
}
731759

732760
// Setup builtin provider (always in-process)
733-
builtinProvider, builtinLocations, err := a.setupBuiltinProviderHybrid(ctx, transformedConfigs, analyzeLog, overrideConfigs, reporter)
761+
builtinProvider, builtinLocations, err := a.setupBuiltinProviderHybrid(ctx, additionalBuiltinConfigs, analyzeLog, overrideConfigs, reporter)
734762
if err != nil {
735763
errLog.Error(err, "unable to start builtin provider")
736764
return fmt.Errorf("unable to start builtin provider: %w", err)
@@ -938,21 +966,17 @@ func (a *analyzeCommand) RunAnalysisHybridInProcess(ctx context.Context) error {
938966
startStaticReport := time.Now()
939967
a.log.Info("[TIMING] Starting static report generation")
940968

941-
// Create static report log file for container output
942-
staticReportLogPath := filepath.Join(a.output, "static-report.log")
943-
staticReportLog, err := os.Create(staticReportLogPath)
944-
if err != nil {
945-
return fmt.Errorf("failed creating static report log file at %s: %w", staticReportLogPath, err)
946-
}
947-
defer staticReportLog.Close()
948-
949-
err = a.GenerateStaticReport(ctx, a.log, staticReportLog)
969+
err = a.GenerateStaticReport(ctx, a.log)
950970
if err != nil {
951971
a.log.Error(err, "failed to generate static report")
952972
return err
953973
}
954974
a.log.Info("[TIMING] Static report generation complete", "duration_ms", time.Since(startStaticReport).Milliseconds())
955975

976+
if err := a.getProviderLogs(ctx); err != nil {
977+
a.log.Error(err, "failed to get provider logs")
978+
}
979+
956980
// Print results summary (only in progress mode, not in --no-progress mode)
957981
progressMode.Println("\nResults:")
958982
reportPath := filepath.Join(a.output, "static-report", "index.html")

0 commit comments

Comments
 (0)