Skip to content

RTECO-945: Wire jf apk commands and e2e tests - #3561

Open
naveenku-jfrog wants to merge 2 commits into
masterfrom
RTECO-alpine
Open

RTECO-945: Wire jf apk commands and e2e tests#3561
naveenku-jfrog wants to merge 2 commits into
masterfrom
RTECO-alpine

Conversation

@naveenku-jfrog

@naveenku-jfrog naveenku-jfrog commented Jun 19, 2026

Copy link
Copy Markdown
Collaborator

Summary

Wires the Alpine APK integration into the JFrog CLI frontend: registers jf apk subcommands, 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.go

  • ApkCmd() — dispatches jf apk config, jf apk upload, and all native apk subcommands (add, upgrade, etc.)
  • Extracts JFrog-specific flags (--repo, --server-id, --alpine-version, --user, --password, --build-name, --build-number, --module, --project) before forwarding remaining args to native apk
  • Fail-fast on unknown --server-id: if --server-id is explicitly provided but not found in the config, the command errors immediately — consistent with jf npm, jf pip, jf mvn, etc.
  • Falls back to the default server silently when --server-id is omitted (allows jf apk add to work without Artifactory for basic usage)

utils/cliutils/commandsflags.go

  • New Apk flag group: --repo, --server-id, --alpine-version, --user, --password, --build-name, --build-number, --module, --project

docs/buildtools/apkcommand/help.go

  • GetDescription(), GetAIDescription(), Usage, GetArguments() for jf apk help text and AI help coverage

packagealias/packagealias.go

  • Registers apk as a Ghost Frog package alias so jf apk add curl works identically to jfrog apk add curl — consistent with npm, pip, mvn, etc.

apk_test.go

Full end-to-end test suite (35 test cases) covering:

Category Tests
Basic build-info NoBuildFlags, WithBuildFlags, BuildNameFromEnvVars
Dependency collection DepIDFormat, DepChecksums, DepRequestedBy, TransitiveDeps
Scopes ScopeProduction, ScopeTransitive
Repo / server config MissingRepo, InvalidRepo, UnknownServerID, ArtifactoryUnreachable, VirtualRepoAggregates
Upload Upload, UploadWithBuildInfo, CIVCSPropertiesStamped
Config Config, ConfigMissingServerID
Env vars EnvVarsFiltered, EnvVarsIncluded
Multi-package MultiPackageInstall, MultiPackageBuildInfo
Idempotency IdempotentAdd
Error handling ApkBinaryMissing

.github/workflows/apkTests.yml

CI workflow that runs all TestApk* tests against a matrix of Alpine versions (v3.18, v3.19, v3.20, v3.21):

  • Compiles the test binary on ubuntu-24.04 (where Go 1.26 is available)
  • Runs the pre-built static binary inside each alpine:<version> Docker container to get a real apk binary
  • Spins up a local Artifactory instance via install-local-artifactory
  • Triggered via workflow_call and workflow_dispatch

scripts/test-apk-local.sh

Helper script for running Alpine APK e2e tests locally on macOS via Docker (mounts the repo and ~/.jfrog config into a golang:alpine container).


Design Notes

--repo is optional: Consistent with jf npm install and jf pip install, omitting --repo does 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 apk binary (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 apk is wired through corecommon.ResolveDescription to satisfy the TestAIHelpCoverageGenerated check.

@github-actions

github-actions Bot commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

All contributors have signed the CLA ✍️ ✅
Posted by the CLA Assistant Lite bot.

@naveenku-jfrog naveenku-jfrog changed the title Rteco alpine RTECO-945: Wire jf apk commands and e2e tests Jul 14, 2026
- 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>
@github-actions

Copy link
Copy Markdown
Contributor

👍 Frogbot scanned this pull request and did not find any new security issues.


Consume the Artifactory implementation that validates explicit APK repository selections before execution.
Comment thread buildtools/cli.go
} else {
serverDetails, err = coreConfig.GetDefaultServerConf()
if err != nil {
log.Warn("No JFrog server configured — skipping credential injection. Run: jf c add")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Comment thread buildtools/cli.go
}
cmd := alpinecommand.NewApkCommand(subcmd).
SetArgs(filteredArgs).
SetServerDetails(serverDetails).

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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/|$//')

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Comment thread apk_test.go

// 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) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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?

Comment thread apk_test.go
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,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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?

Comment thread apk_test.go
}
}
}
assert.True(t, hasProd, "at least one dependency should have scope 'prod'")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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?

Comment thread apk_test.go
}
hasTransitiveRequestedBy := false
for _, dep := range deps {
if len(dep.RequestedBy) > 0 && len(dep.RequestedBy[0]) > 0 {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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...]",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants