RTECO-945: Wire jf apk commands and e2e tests - #3561
Conversation
7af2722 to
ac81485
Compare
18c3b05 to
89e6093
Compare
89e6093 to
7177b09
Compare
7177b09 to
bcfba32
Compare
ee511cf to
dcc6d06
Compare
7f9c899 to
213f8f6
Compare
0214c4f to
98397ae
Compare
|
All contributors have signed the CLA ✍️ ✅ |
1a9f22a to
0277d99
Compare
b994bb9 to
c488334
Compare
8c534d2 to
a0db8ca
Compare
a0db8ca to
db5e2a4
Compare
- Wire jf apk add/upgrade/upload/update and jf setup apk into the CLI - Add Alpine APK e2e tests: build-info, release-bundle creation, build-promote, arch auto-detect from .PKGINFO, indexable-path layout - Add selective-retry e2e runner script and apk-tools v2/v3 CI matrix - Bump build-info-go, jfrog-cli-core, jfrog-cli-artifactory to Alpine builds Co-authored-by: Cursor <cursoragent@cursor.com>
Consume the Artifactory implementation that validates explicit APK repository selections before execution.
| } else { | ||
| serverDetails, err = coreConfig.GetDefaultServerConf() | ||
| if err != nil { | ||
| log.Warn("No JFrog server configured — skipping credential injection. Run: jf c add") |
There was a problem hiding this comment.
coreConfig.GetDefaultServerConf() returns (nil, nil) when no server is configured at all (the common case for a user who hasn't run jf c add), so this err != nil branch won't actually fire there and serverDetails stays nil silently. Worth double-checking what this warning is meant to cover.
| } | ||
| cmd := alpinecommand.NewApkCommand(subcmd). | ||
| SetArgs(filteredArgs). | ||
| SetServerDetails(serverDetails). |
There was a problem hiding this comment.
SetServerDetails(serverDetails) is called unconditionally here, even when serverDetails is nil (see the fallback branch above). NixCmd just above (line 2128-2130) guards this with if err == nil && serverDetails != nil. Should ApkCmd follow the same guard for consistency / to avoid passing a nil server details struct downstream?
| $creds 2>&1 | tee /tmp/apk-out.log | ||
|
|
||
| # Collect the top-level names of tests that failed this attempt. | ||
| fails=$(grep -Eo '^--- FAIL: [A-Za-z0-9_]+' /tmp/apk-out.log | awk '{print $3}' | sort -u | tr '\n' '|' | sed 's/|$//') |
There was a problem hiding this comment.
This only checks for literal --- FAIL: lines in the captured output — it doesn't check docker run's own exit code. If the test binary crashes/panics or the container gets OOM-killed before printing any --- FAIL: line, $fails stays empty and the step reports "All Alpine tests passed" on that attempt. Might be worth capturing ${PIPESTATUS[0]} (or splitting the pipe) and treating a non-zero docker exit as a failure too.
|
|
||
| // TestApkAdd_ArtifactoryUnreachable verifies that when Artifactory is unreachable | ||
| // jf apk add returns a clear error and does not silently fall back to the public CDN. | ||
| func TestApkAdd_ArtifactoryUnreachable(t *testing.T) { |
There was a problem hiding this comment.
This test body is identical to TestApkAdd_UnknownServerID above (same --server-id=nonexistent-server-id-xyz args) — it doesn't actually simulate an unreachable Artifactory server, it just re-tests the unknown-server-id path. Should this point at a real unreachable host/port instead (e.g. an invalid URL in a throwaway server config) to cover the case the name describes?
| depsWithChecksums, len(publishedBuildInfo.BuildInfo.Modules[0].Dependencies)) | ||
| // On a machine with a populated APK cache, checksums should be present. | ||
| // We assert at least the package itself has one. | ||
| assert.Greater(t, depsWithChecksums, 0, |
There was a problem hiding this comment.
This only asserts dep.Sha1 != "" || dep.Sha256 != "" — Md5 is never checked anywhere in this test. Per the checksum requirement (sha256/sha1/md5 all expected), can we add an assertion that at least one dep has a non-empty Md5 too?
| } | ||
| } | ||
| } | ||
| assert.True(t, hasProd, "at least one dependency should have scope 'prod'") |
There was a problem hiding this comment.
hasTransitive is computed but only logged at line 468-469, never asserted. Given the comment above says curl reliably brings in transitive deps (libcurl, musl, etc.), should this be assert.True(t, hasTransitive, ...) like the hasProd check right above it, rather than just a log line?
| } | ||
| hasTransitiveRequestedBy := false | ||
| for _, dep := range deps { | ||
| if len(dep.RequestedBy) > 0 && len(dep.RequestedBy[0]) > 0 { |
There was a problem hiding this comment.
This only checks that a RequestedBy chain is non-empty, not that its content actually identifies the correct parent (e.g. that libcurl's chain contains curl:<version>). Could tighten this to assert on the actual parent ID rather than just presence.
| "apk fetch <packages...> [jf-flags]", | ||
| "apk search <pattern> [jf-flags]", | ||
| "apk del <packages...>", | ||
| "apk info [packages...]", |
There was a problem hiding this comment.
This Usage list (and the subcommand list in GetArguments() below) only documents upload/add/upgrade/update/fetch/search/del/info. apk_test.go's TestApkPassthroughCommands explicitly exercises fix, audit, version, and stats as supported passthrough subcommands — should those be documented here too so jf apk --help reflects everything that's actually supported?
| BuildName, BuildNumber, module, Project, serverId, | ||
| }, | ||
| Apk: { | ||
| serverId, repo, apkAlpineVersion, branch, apkArch, BuildName, BuildNumber, module, Project, user, password, |
There was a problem hiding this comment.
This reuses the shared branch flag, whose Usage text (line 1855) says "[Mandatory] Branch name to filter.". For jf apk upload, --branch is actually optional and defaults to "main" (per apkUploadSubCmd in buildtools/cli.go). Since this flag's help text is shared across commands, jf apk upload --help will show a misleading "[Mandatory]" for an optional flag — might need a per-command override or a tweaked shared description.

Summary
Wires the Alpine APK integration into the JFrog CLI frontend: registers
jf apksubcommands, adds CLI flags, package aliasing (Ghost Frog), and a comprehensive e2e test suite. This is the user-facing entry point for the full Alpine APK feature.Depends on:
What Changed
buildtools/cli.goApkCmd()— dispatchesjf apk config,jf apk upload, and all nativeapksubcommands (add,upgrade, etc.)--repo,--server-id,--alpine-version,--user,--password,--build-name,--build-number,--module,--project) before forwarding remaining args to nativeapk--server-id: if--server-idis explicitly provided but not found in the config, the command errors immediately — consistent withjf npm,jf pip,jf mvn, etc.--server-idis omitted (allowsjf apk addto work without Artifactory for basic usage)utils/cliutils/commandsflags.goApkflag group:--repo,--server-id,--alpine-version,--user,--password,--build-name,--build-number,--module,--projectdocs/buildtools/apkcommand/help.goGetDescription(),GetAIDescription(),Usage,GetArguments()forjf apkhelp text and AI help coveragepackagealias/packagealias.goapkas a Ghost Frog package alias sojf apk add curlworks identically tojfrog apk add curl— consistent withnpm,pip,mvn, etc.apk_test.goFull end-to-end test suite (35 test cases) covering:
NoBuildFlags,WithBuildFlags,BuildNameFromEnvVarsDepIDFormat,DepChecksums,DepRequestedBy,TransitiveDepsScopeProduction,ScopeTransitiveMissingRepo,InvalidRepo,UnknownServerID,ArtifactoryUnreachable,VirtualRepoAggregatesUpload,UploadWithBuildInfo,CIVCSPropertiesStampedConfig,ConfigMissingServerIDEnvVarsFiltered,EnvVarsIncludedMultiPackageInstall,MultiPackageBuildInfoIdempotentAddApkBinaryMissing.github/workflows/apkTests.ymlCI workflow that runs all
TestApk*tests against a matrix of Alpine versions (v3.18,v3.19,v3.20,v3.21):ubuntu-24.04(where Go 1.26 is available)alpine:<version>Docker container to get a realapkbinaryinstall-local-artifactoryworkflow_callandworkflow_dispatchscripts/test-apk-local.shHelper script for running Alpine APK e2e tests locally on macOS via Docker (mounts the repo and
~/.jfrogconfig into agolang:alpinecontainer).Design Notes
--repois optional: Consistent withjf npm installandjf pip install, omitting--repodoes not block build-info collection. Checksums are always available from the APK database (C:field). AQL enrichment (for SHA-256/MD5) is skipped when no repo is specified.Test infrastructure: Tests require the
apkbinary (Alpine Linux). The workflow compiles a static Linux binary on the host and runs it inside Alpine Docker containers, avoiding Go version constraints in Alpine package repos.AI help coverage:
jf apkis wired throughcorecommon.ResolveDescriptionto satisfy theTestAIHelpCoverageGeneratedcheck.