Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
19 changes: 19 additions & 0 deletions .github/workflows/auto-build-publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,20 +26,35 @@ jobs:
cli-version: [ "latest", "2.66.0" ]
runs-on: ${{ matrix.os }}-latest
steps:
- name: Skip macOS - JGC-413
if: matrix.os == 'macos'
run: |
echo "::warning::JGC-413 - Skip until artifactory bootstrap in osx is fixed"
exit 0

- name: Checkout Repository
if: matrix.os != 'macos'
uses: actions/checkout@v6
with:
ref: ${{ github.event.pull_request.head.sha }}

# This repo is a Node action and has no go.mod. install-go-with-cache@main
# reads go.mod when go-version is unset (#28), which fails Setup Go immediately.
# local-rt-setup (used by install-local-artifactory) requires Go 1.24+.
- name: Setup Go with cache
if: matrix.os != 'macos'
uses: jfrog/.github/actions/install-go-with-cache@main
with:
go-version: "1.24"

- name: Install local Artifactory
if: matrix.os != 'macos'
uses: jfrog/.github/actions/install-local-artifactory@main
with:
RTLIC: ${{ secrets.RTLIC }}

- name: Post Step to Test the Auto Build-Publish post step
if: matrix.os != 'macos'
uses: gacts/run-and-post-run@v1
with:
post: |
Expand All @@ -57,6 +72,7 @@ jobs:
fi

- name: Setup JFrog CLI
if: matrix.os != 'macos'
id: setup-jfrog-cli
uses: ./
with:
Expand All @@ -67,6 +83,7 @@ jobs:
JF_PASSWORD: password

- name: Create NPM Remote Repository JSON
if: matrix.os != 'macos'
uses: jsdaniell/create-json@v1.2.3
with:
name: "npm-remote-template.json"
Expand All @@ -78,10 +95,12 @@ jobs:
}'

- name: Configure Artifactory NPM Remote Repository
if: matrix.os != 'macos'
run: jf rt repo-create npm-remote-template.json
shell: bash

- name: Add npm modules to local build-info
if: matrix.os != 'macos'
run: |
jf npm-config --repo-resolve npm-remote
jf npm install
2 changes: 2 additions & 0 deletions .github/workflows/frogbot-scan-repository.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ jobs:
steps:
- name: Setup Go with cache
uses: jfrog/.github/actions/install-go-with-cache@main
with:
go-version: "1.24"

- uses: jfrog/frogbot@v2
env:
Expand Down
12 changes: 11 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,8 @@ It is also possible to set the latest JFrog CLI version by adding the _version_
version: latest
```

Do not combine `version: latest` with `download-repository`. See [Downloading JFrog CLI from Artifactory](#downloading-jfrog-cli-from-artifactory).

| Important: Only JFrog CLI versions 1.46.4 or above are supported. |
|-------------------------------------------------------------------|

Expand Down Expand Up @@ -417,10 +419,17 @@ In this example, each job builds and publishes a different service from the mono

If your agent has no Internet access, you can configure the workflow to download JFrog CLI from a [remote repository](https://www.jfrog.com/confluence/display/JFROG/Remote+Repositories) in your JFrog Artifactory, which is configured to proxy the official download URL.

> [!NOTE]
> With `download-repository`, prefer a concrete `version: X.Y.Z` over `latest`.
>
> `latest` is not resolved to a version number. It becomes the literal path segment `[RELEASE]` in the download URL (`v2/[RELEASE]/jfrog-cli-.../jfrog`), and a generic repository serves that path like any other. If the repository has **Store Artifacts Locally** enabled (the default), the binary returned for that path is cached under it, so later runs can keep receiving that same binary instead of a newer CLI. A concrete version avoids this, because every version has its own immutable path.
>
> Jobs that can reach the internet and want the newest CLI: omit `download-repository`.

Here's how you do this:

1. Create a remote repository in Artifactory. Name the repository jfrog-cli-remote and set its URL to https://releases.jfrog.io/artifactory/jfrog-cli/
2. Set _download-repository_ input to jfrog-cli-remote:
2. Set _download-repository_ input to jfrog-cli-remote and pin `version`:

```yml
- uses: jfrog/setup-jfrog-cli@v4
Expand All @@ -430,6 +439,7 @@ Here's how you do this:
JF_ACCESS_TOKEN: ${{ secrets.JF_ACCESS_TOKEN }}

with:
version: X.Y.Z
download-repository: jfrog-cli-remote
```
</details>
Expand Down
4 changes: 2 additions & 2 deletions action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@ description: "Install and configure JFrog CLI."
author: "JFrog"
inputs:
version:
description: "JFrog CLI Version"
description: "JFrog CLI Version. A concrete X.Y.Z is recommended when download-repository points to a remote repository that stores artifacts locally, since latest is requested as the v2/[RELEASE] path and can be served from cache."
default: "2.91.0"
required: false
download-repository:
description: "Remote repository in Artifactory pointing to 'https://releases.jfrog.io/artifactory/jfrog-cli'. Use this parameter in case you don't have an Internet access."
description: "Remote repository in Artifactory pointing to 'https://releases.jfrog.io/artifactory/jfrog-cli'. Use this parameter in case you don't have an Internet access. When the repository stores artifacts locally, prefer a concrete version over latest: latest is requested as the literal v2/[RELEASE] path, and the binary cached under that path can keep being served on later runs."
required: false
oidc-provider-name:
description: "Provider Name's value that was set in OpenId Connect integration in the JFrog platform."
Expand Down
19 changes: 16 additions & 3 deletions lib/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ class Utils {
let version = core.getInput(Utils.CLI_VERSION_ARG);
let cliRemote = core.getInput(Utils.CLI_REMOTE_ARG);
const isLatestVer = version === Utils.LATEST_CLI_VERSION;
Utils.logIfLatestDownloadedFromRemote(version, cliRemote);
if (!isLatestVer && (0, semver_1.lt)(version, this.MIN_CLI_VERSION)) {
throw new Error('Requested to download JFrog CLI version ' + version + ' but must be at least ' + this.MIN_CLI_VERSION);
}
Expand Down Expand Up @@ -168,6 +169,16 @@ class Utils {
}
return `${artifactoryUrl}/${downloadDetails.repository}/v${major}/${version}/${architecture}/${fileName}`;
}
/**
* Log when latest is resolved through an Artifactory repository.
* [RELEASE] is part of the artifact path, so a remote repository caches it like any other file
* and keeps serving the first version it resolved. Pin a concrete version instead.
*/
static logIfLatestDownloadedFromRemote(version, cliRemote) {
if (cliRemote && version === Utils.LATEST_CLI_VERSION) {
core.info(Utils.LATEST_FROM_REMOTE_INFO);
}
}
// Get Config Tokens created on your local machine using JFrog CLI.
// The Tokens configured with JF_ENV_ environment variables.
static getConfigTokens() {
Expand Down Expand Up @@ -470,7 +481,7 @@ class Utils {
}
/**
* If enable-package-alias is true and GITHUB_PATH is set, runs `jf package-alias install`
* and appends the alias bin directory to GITHUB_PATH so subsequent steps intercept mvn, npm, go, etc.
* and adds the alias bin directory to PATH via core.addPath so subsequent steps intercept mvn, npm, go, etc.
* On failure (e.g. older CLI without package-alias), logs a warning and does not fail the job.
*/
static setupPackageAliasIfRequested() {
Expand Down Expand Up @@ -513,8 +524,8 @@ class Utils {
return;
}
const aliasBinDir = Utils.getPackageAliasBinDir();
(0, fs_1.appendFileSync)(githubPath, aliasBinDir + '\n');
core.info('Package aliases installed and "' + aliasBinDir + '" appended to GITHUB_PATH.');
core.addPath(aliasBinDir);
core.info('Package aliases installed and "' + aliasBinDir + '" added to PATH.');
});
}
}
Expand All @@ -534,6 +545,8 @@ Utils.MIN_CLI_VERSION = '1.46.4';
Utils.LATEST_CLI_VERSION = 'latest';
// The value in the download URL to set to get the latest version
Utils.LATEST_RELEASE_VERSION = '[RELEASE]';
// Logged when version=latest is downloaded through a remote repository, which caches the literal [RELEASE] path
Utils.LATEST_FROM_REMOTE_INFO = 'download-repository is set with version=latest, so the CLI is requested from the literal path v2/[RELEASE] instead of a version number. If that repository stores artifacts locally, the binary cached under this path can keep being served on later runs. Use a concrete version to download from a per-version path, or omit download-repository if the runner can reach releases.jfrog.io.';
// Placeholder CLI version to use to keep 'latest' in cache.
Utils.LATEST_SEMVER = '100.100.100';
// The default server id name for separate env config
Expand Down
15 changes: 15 additions & 0 deletions src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ export class Utils {
public static readonly LATEST_CLI_VERSION: string = 'latest';
// The value in the download URL to set to get the latest version
private static readonly LATEST_RELEASE_VERSION: string = '[RELEASE]';
// Logged when version=latest is downloaded through a remote repository, which caches the literal [RELEASE] path
public static readonly LATEST_FROM_REMOTE_INFO: string =
'download-repository is set with version=latest, so the CLI is requested from the literal path v2/[RELEASE] instead of a version number. If that repository stores artifacts locally, the binary cached under this path can keep being served on later runs. Use a concrete version to download from a per-version path, or omit download-repository if the runner can reach releases.jfrog.io.';
// Placeholder CLI version to use to keep 'latest' in cache.
public static readonly LATEST_SEMVER: string = '100.100.100';
// The default server id name for separate env config
Expand Down Expand Up @@ -108,6 +111,7 @@ export class Utils {
let version: string = core.getInput(Utils.CLI_VERSION_ARG);
let cliRemote: string = core.getInput(Utils.CLI_REMOTE_ARG);
const isLatestVer: boolean = version === Utils.LATEST_CLI_VERSION;
Utils.logIfLatestDownloadedFromRemote(version, cliRemote);

if (!isLatestVer && lt(version, this.MIN_CLI_VERSION)) {
throw new Error('Requested to download JFrog CLI version ' + version + ' but must be at least ' + this.MIN_CLI_VERSION);
Expand Down Expand Up @@ -199,6 +203,17 @@ export class Utils {
return `${artifactoryUrl}/${downloadDetails.repository}/v${major}/${version}/${architecture}/${fileName}`;
}

/**
* Log when latest is resolved through an Artifactory repository.
* [RELEASE] is part of the artifact path, so a remote repository caches it like any other file
* and keeps serving the first version it resolved. Pin a concrete version instead.
*/
public static logIfLatestDownloadedFromRemote(version: string, cliRemote: string): void {
if (cliRemote && version === Utils.LATEST_CLI_VERSION) {
core.info(Utils.LATEST_FROM_REMOTE_INFO);
}
}

// Get Config Tokens created on your local machine using JFrog CLI.
// The Tokens configured with JF_ENV_ environment variables.
public static getConfigTokens(): Set<string> {
Expand Down
21 changes: 21 additions & 0 deletions test/main.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,27 @@ describe('JFrog CLI V2 URL Tests', () => {
});
});

describe('logIfLatestDownloadedFromRemote', () => {
beforeEach(() => {
(core.info as jest.Mock).mockClear();
});

test('Logs info when latest is downloaded from an Artifactory repository', () => {
Utils.logIfLatestDownloadedFromRemote(Utils.LATEST_CLI_VERSION, 'jfrog-cli-remote');
expect(core.info).toHaveBeenCalledWith(Utils.LATEST_FROM_REMOTE_INFO);
});

test('Does not log when version is pinned', () => {
Utils.logIfLatestDownloadedFromRemote('2.91.0', 'jfrog-cli-remote');
expect(core.info).not.toHaveBeenCalled();
});

test('Does not log when download-repository is unset', () => {
Utils.logIfLatestDownloadedFromRemote(Utils.LATEST_CLI_VERSION, '');
expect(core.info).not.toHaveBeenCalled();
});
});

test('Extract download details Tests', () => {
for (let config of [V1_CONFIG, V2_CONFIG]) {
process.env.JF_ENV_LOCAL = config;
Expand Down
Loading