Skip to content

Commit

Permalink
Allow using 'jf' in addition to 'jfrog' (#63)
Browse files Browse the repository at this point in the history
  • Loading branch information
yahavi authored Mar 21, 2022
1 parent 31c9076 commit 126069f
Show file tree
Hide file tree
Showing 10 changed files with 299 additions and 140 deletions.
95 changes: 53 additions & 42 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -1,46 +1,57 @@
name: 'Test'
name: "Test"
on: [push, pull_request]

jobs:
test:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, windows-latest, macOS-latest]
version: ['', 'latest', '2.11.1']
fail-fast: false
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Setup JFrog CLI
if: matrix.version != ''
uses: ./
with:
version: ${{ matrix.version }}
env:
JF_ARTIFACTORY_LOCAL: eyJ2ZXJzaW9uIjoxLCJ1cmwiOiJodHRwOi8vMTI3LjAuMC4xOjgwODEvYXJ0aWZhY3RvcnkvIiwidXNlciI6ImFkbWluIiwicGFzc3dvcmQiOiJBUEI3REVaUlBpSHFIRFRRb2tMa3g5aGh6S1QiLCJzZXJ2ZXJJZCI6ImxvY2FsIn0=
- name: Setup default JFrog CLI
if: matrix.version == ''
uses: ./
env:
JF_ARTIFACTORY_LOCAL: eyJ2ZXJzaW9uIjoxLCJ1cmwiOiJodHRwOi8vMTI3LjAuMC4xOjgwODEvYXJ0aWZhY3RvcnkvIiwidXNlciI6ImFkbWluIiwicGFzc3dvcmQiOiJBUEI3REVaUlBpSHFIRFRRb2tMa3g5aGh6S1QiLCJzZXJ2ZXJJZCI6ImxvY2FsIn0=
- name: Version # Check that the correct CLI version was downloaded
run: jfrog --version
- name: Sanity # Check local server successfully configured
run: jfrog c show local
- name: Check build URL
uses: wei/curl@master
with:
args: -I ${JFROG_CLI_BUILD_URL}
if: runner.os == 'Linux'
- name: Setup NodeJS # Download NodeJS to allow running the tests on macOS
uses: actions/setup-node@v1
with:
node-version: '12.x'
- name: Check action environment
run: node scripts/check-env.js
- name: Install
run: npm i
- name: Unit tests
run: npm t
test:
runs-on: ${{ matrix.os }}
env:
JF_ENV_LOCAL: eyJ2ZXJzaW9uIjoxLCJ1cmwiOiJodHRwOi8vMTI3LjAuMC4xOjgwODEvYXJ0aWZhY3RvcnkvIiwidXNlciI6ImFkbWluIiwicGFzc3dvcmQiOiJBUEI3REVaUlBpSHFIRFRRb2tMa3g5aGh6S1QiLCJzZXJ2ZXJJZCI6ImxvY2FsIn0=

strategy:
matrix:
os: [ubuntu-latest, windows-latest, macOS-latest]
version: ["", "latest", "1.29.0"]
fail-fast: false
steps:
# Checkout and install prerequisites
- name: Checkout
uses: actions/checkout@v2
- name: Setup NodeJS
uses: actions/setup-node@v1
with:
node-version: "14.x"

# Run action according to the input version
- name: Setup JFrog CLI
if: matrix.version != ''
uses: ./
with:
version: ${{ matrix.version }}
- name: Setup default JFrog CLI
if: matrix.version == ''
uses: ./

# Run --version
- name: Check versions
run: jf --version && jfrog --version

# Check local server successfully configured
- name: Sanity
run: jf c show local || jfrog rt config show local

# Check build URL
- name: Check build URL
uses: wei/curl@master
with:
args: -I ${JFROG_CLI_BUILD_URL}
if: runner.os == 'Linux'

# Check environment variables
- name: Check action environment
run: node scripts/check-env.js

# Install and run tests
- name: Install
run: npm i
- name: Unit tests
run: npm t
54 changes: 27 additions & 27 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
This GitHub Action downloads, installs and configures JFrog CLI, so that it can be used as part of the workflow.

In addition, the Action includes the following features, when using JFrog CLI to work with Artifactory.
* The connection details of the Artifactory servers used by JFrog CLI can be stored as secrets. Read more about it [here](#storing-artifactory-servers-details-as-secrets).
* The connection details of the JFrog platform used by JFrog CLI can be stored as secrets. Read more about it [here](#storing-JFrog-details-as-secrets).
* There's no need to add the *build name* and *build number* options and arguments to commands which accept them.
All build related operations will be automatically recorded with the *Workflow Name* as build name and *Run Number* as build number.

Expand All @@ -20,51 +20,51 @@ All build related operations will be automatically recorded with the *Workflow N

```yml
- uses: jfrog/setup-jfrog-cli@v2
- run: jfrog --version
- run: jf --version
```
## Storing Artifactory servers details as secrets
## Storing JFrog details as secrets
### General
The connection details of the Artifactory servers used by JFrog CLI can be stored as secrets.
The connection details of the JFrog platform used by JFrog CLI can be stored as secrets.
### Creating the configuration on your local machine
1. Make sure JFrog CLI version **1.29.0** or above is installed on your local machine by running ```jfrog -v```.
2. Configure the details of the Artifactory server by running ```jfrog c add```.
3. Export the details of the Artifactory server you configured, using the server ID you chose. Do this by running ```jfrog c export <SERVER ID>```.
1. Make sure JFrog CLI version **1.29.0** or above is installed on your local machine by running ```jf -v```.
2. Configure the details of the JFrog platform by running ```jf c add```.
3. Export the details of the JFrog platform you configured, using the server ID you chose. Do this by running ```jf c export <SERVER ID>```.
4. Copy the generated token to the clipboard and save it as a secret on GitHub.

### Using the secret in the workflow
To use the saved Artifactory server configuration in the workflow, all you need to do it to expose the secret to the workflow.
The secret should be exposed as an environment variable with the *JF_ARTIFACTORY_* prefix.
To use the saved JFrog platform configuration in the workflow, all you need to do it to expose the secret to the workflow.
The secret should be exposed as an environment variable with the *JF_ENV_* prefix.
Here's how you do this:
```yml
- uses: jfrog/setup-jfrog-cli@v2
env:
JF_ARTIFACTORY_1: ${{ secrets.JF_ARTIFACTORY_SECRET_1 }}
JF_ENV_1: ${{ secrets.JF_SECRET_ENV_1 }}
- run: |
# Ping the server
jfrog rt ping
jf rt ping
```
As you can see in the example above, we created a secret named *JF_ARTIFACTORY_SECRET_1* and we exposed it to the workflow
as the *JF_ARTIFACTORY_1* environment variable. That's it - the ping command will now ping the configured Artifactory server.
As you can see in the example above, we created a secret named *JF_SECRET_ENV_1* and we exposed it to the workflow
as the *JF_ENV_1* environment variable. That's it - the ping command will now ping the configured Artifactory server.

If you have multiple Artifactory servers configured as secrets, you can use all of the in the workflow as follows:
If you have multiple JFrog platform configurations as secrets, you can use all of the in the workflow as follows:
```yml
- uses: jfrog/setup-jfrog-cli@v2
env:
JF_ARTIFACTORY_1: ${{ secrets.JF_ARTIFACTORY_SECRET_1 }}
JF_ARTIFACTORY_2: ${{ secrets.JF_ARTIFACTORY_SECRET_2 }}
JF_ENV_1: ${{ secrets.JF_SECRET_ENV_1 }}
JF_ENV_2: ${{ secrets.JF_SECRET_ENV_2 }}
- run: |
# Set the Artifactory server to use by providing the server ID (configured by the 'jfrog c add' command).
jfrog c use local-1
# Ping local-1
jfrog rt ping
# Set the JFrog configuration to use by providing the server ID (configured by the 'jf c add' command).
jf c use local-1
# Ping local-1 Artifactory server
jf rt ping
# Now use the second sever configuration exposed to the Action.
jfrog c use local-2
# Ping local-2
jfrog rt ping
jf c use local-2
# Ping local-2 Xray server
jf xr ping
```
| Important: When exposing more than one Artifactory servers to the Action, you should always add the ```jfrog c use``` command to specify the server to use. |
| Important: When exposing more than one JFrog configuration to the Action, you should always add the ```jf c use``` command to specify the server to use. |
| --- |

## Setting the build name and build number when publishing build-info to Artifactory
Expand All @@ -76,9 +76,9 @@ In the following example, all downloaded files are registered as dependencies of
are registered as the build artifacts.
```yml
- run: |
jfrog rt dl artifacts/
jfrog rt u aether artifacts/
jfrog rt bp
jf rt dl artifacts/
jf rt u aether artifacts/
jf rt bp
```

## Setting JFrog CLI version
Expand Down
4 changes: 2 additions & 2 deletions lib/cleanup.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,8 @@ function cleanup() {
return __awaiter(this, void 0, void 0, function* () {
try {
core.startGroup('Cleanup JFrog CLI servers configuration');
let cliPath = yield utils_1.Utils.downloadCli();
yield utils_1.Utils.removeArtifactoryServers(cliPath);
yield utils_1.Utils.addCliToPath();
yield utils_1.Utils.removeJFrogServers();
}
catch (error) {
core.setFailed(error.message);
Expand Down
4 changes: 2 additions & 2 deletions lib/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,8 @@ function main() {
try {
core.startGroup('Setup JFrog CLI');
utils_1.Utils.setCliEnv();
let cliPath = yield utils_1.Utils.downloadCli();
yield utils_1.Utils.configArtifactoryServers(cliPath);
yield utils_1.Utils.addCliToPath();
yield utils_1.Utils.configJFrogServers();
}
catch (error) {
core.setFailed(error.message);
Expand Down
106 changes: 81 additions & 25 deletions lib/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,47 +37,92 @@ const os = __importStar(require("os"));
const path = __importStar(require("path"));
const semver = __importStar(require("semver"));
class Utils {
static downloadCli() {
static addCliToPath() {
return __awaiter(this, void 0, void 0, function* () {
let version = core.getInput(Utils.CLI_VERSION_ARG);
let major = version.split('.')[0];
if (version === this.LATEST_CLI_VERSION_ARG) {
version = '[RELEASE]';
version = Utils.LATEST_RELEASE_VERSION;
major = '2';
}
else if (semver.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);
}
let fileName = Utils.getCliExecutableName();
let cliDir = toolCache.find(fileName, version);
if (cliDir) {
core.addPath(cliDir);
return path.join(cliDir, fileName);
let jfFileName = Utils.getJfExecutableName();
let jfrogFileName = Utils.getJFrogExecutableName();
if (this.loadFromCache(jfFileName, jfrogFileName, version)) {
// Download is not needed
return;
}
let url = Utils.getCliUrl(major, version, fileName);
// Download JFrog CLI
let url = Utils.getCliUrl(major, version, jfrogFileName);
core.debug('Downloading JFrog CLI from ' + url);
let downloadDir = yield toolCache.downloadTool(url);
cliDir = yield toolCache.cacheFile(downloadDir, fileName, fileName, version);
let cliPath = path.join(cliDir, fileName);
// Cache 'jf' and 'jfrog' executables
yield this.cacheAndAddPath(downloadDir, version, jfFileName);
yield this.cacheAndAddPath(downloadDir, version, jfrogFileName);
});
}
/**
* Try to load the JFrog CLI executables from cache.
*
* @param jfFileName - 'jf' or 'jf.exe'
* @param jfrogFileName - 'jfrog' or 'jfrog.exe'
* @param version - JFrog CLI version
* @returns true if the CLI executable was loaded from cache and added to path
*/
static loadFromCache(jfFileName, jfrogFileName, version) {
if (version === Utils.LATEST_RELEASE_VERSION) {
return false;
}
let jfExecDir = toolCache.find(jfFileName, version);
let jfrogExecDir = toolCache.find(jfrogFileName, version);
if (jfExecDir && jfrogExecDir) {
core.addPath(jfExecDir);
core.addPath(jfrogExecDir);
return true;
}
return false;
}
/**
* Add JFrog CLI executables to cache and to the system path.
* @param downloadDir - The directory whereby the CLI was downloaded to
* @param version - JFrog CLI version
* @param fileName - 'jf', 'jfrog', 'jf.exe', or 'jfrog.exe'
*/
static cacheAndAddPath(downloadDir, version, fileName) {
return __awaiter(this, void 0, void 0, function* () {
let cliDir = yield toolCache.cacheFile(downloadDir, fileName, fileName, version);
if (!Utils.isWindows()) {
fs.chmodSync(cliPath, 0o555);
fs.chmodSync(path.join(cliDir, fileName), 0o555);
}
core.addPath(cliDir);
return cliPath;
});
}
static getCliUrl(major, version, fileName) {
let architecture = 'jfrog-cli-' + Utils.getArchitecture();
return 'https://releases.jfrog.io/artifactory/jfrog-cli/v' + major + '/' + version + '/' + architecture + '/' + fileName;
}
static getServerTokens() {
return Object.keys(process.env)
.filter((env) => env.match(Utils.SERVER_TOKEN_PREFIX))
.map((envKey) => process.env[envKey] || '');
let serverTokens = new Set(Object.keys(process.env)
.filter((envKey) => envKey.match(Utils.SERVER_TOKEN_PREFIX))
.filter((envKey) => process.env[envKey])
.map((envKey) => { var _a; return ((_a = process.env[envKey]) === null || _a === void 0 ? void 0 : _a.trim()) || ''; }));
let legacyServerTokens = new Set(Object.keys(process.env)
.filter((envKey) => envKey.match(Utils.SERVER_TOKEN_LEGACY_PREFIX))
.filter((envKey) => process.env[envKey])
.map((envKey) => { var _a; return ((_a = process.env[envKey]) === null || _a === void 0 ? void 0 : _a.trim()) || ''; }));
if (legacyServerTokens.size > 0) {
core.warning('The "JF_ARTIFACTORY_" prefix for environment variables is deprecated and is expected to be removed in v3. ' +
'Please use the "JF_ENV_" prefix instead. The environment variables value should not be changed.');
}
legacyServerTokens.forEach((serverToken) => serverTokens.add(serverToken));
return serverTokens;
}
static setCliEnv() {
core.exportVariable('JFROG_CLI_ENV_EXCLUDE', '*password*;*secret*;*key*;*token*;JF_ARTIFACTORY_*');
core.exportVariable('JFROG_CLI_ENV_EXCLUDE', '*password*;*secret*;*key*;*token*;*auth*;JF_ARTIFACTORY_*;JF_ENV_*');
core.exportVariable('JFROG_CLI_OFFER_CONFIG', 'false');
core.exportVariable('CI', 'true');
let buildNameEnv = process.env.GITHUB_WORKFLOW;
if (buildNameEnv) {
core.exportVariable('JFROG_CLI_BUILD_NAME', buildNameEnv);
Expand All @@ -89,7 +134,7 @@ class Utils {
core.exportVariable('JFROG_CLI_BUILD_URL', process.env.GITHUB_SERVER_URL + '/' + process.env.GITHUB_REPOSITORY + '/actions/runs/' + process.env.GITHUB_RUN_ID);
core.exportVariable('JFROG_CLI_USER_AGENT', Utils.USER_AGENT);
}
static configArtifactoryServers(cliPath) {
static configJFrogServers() {
return __awaiter(this, void 0, void 0, function* () {
let useOldConfig = Utils.useOldConfig();
if (useOldConfig) {
Expand All @@ -98,17 +143,17 @@ class Utils {
}
for (let serverToken of Utils.getServerTokens()) {
let importCmd = useOldConfig ? ['rt', 'c', 'import', serverToken] : ['c', 'import', serverToken];
yield Utils.runCli(cliPath, importCmd);
yield Utils.runCli(importCmd);
}
});
}
static removeArtifactoryServers(cliPath) {
static removeJFrogServers() {
return __awaiter(this, void 0, void 0, function* () {
if (Utils.useOldConfig()) {
yield Utils.runCli(cliPath, ['rt', 'c', 'clear', '--interactive=false']);
yield Utils.runCli(['rt', 'c', 'clear', '--interactive=false']);
}
else {
yield Utils.runCli(cliPath, ['c', 'rm', '--quiet']);
yield Utils.runCli(['c', 'rm', '--quiet']);
}
});
}
Expand All @@ -124,15 +169,24 @@ class Utils {
}
return os.arch().includes('64') ? 'linux-amd64' : 'linux-386';
}
static getCliExecutableName() {
static getJfExecutableName() {
return Utils.isWindows() ? 'jf.exe' : 'jf';
}
static getJFrogExecutableName() {
return Utils.isWindows() ? 'jfrog.exe' : 'jfrog';
}
static isWindows() {
return os.platform().startsWith('win');
}
static runCli(cliPath, args) {
/**
* Execute JFrog CLI command.
* This GitHub Action downloads the requested 'jfrog' executable and stores it as 'jfrog' and 'jf'.
* Therefore the 'jf' executable is expected to be in the path also for older CLI versions.
* @param args - CLI arguments
*/
static runCli(args) {
return __awaiter(this, void 0, void 0, function* () {
let res = yield exec_1.exec(cliPath, args);
let res = yield exec_1.exec('jf', args);
if (res !== core.ExitCode.Success) {
throw new Error('JFrog CLI exited with exit code ' + res);
}
Expand All @@ -152,9 +206,11 @@ class Utils {
}
exports.Utils = Utils;
Utils.USER_AGENT = 'setup-jfrog-cli-github-action/' + require('../package.json').version;
Utils.SERVER_TOKEN_PREFIX = /^JF_ARTIFACTORY_.*$/;
Utils.SERVER_TOKEN_LEGACY_PREFIX = /^JF_ARTIFACTORY_.*$/;
Utils.SERVER_TOKEN_PREFIX = /^JF_ENV_.*$/;
// Since 1.45.0, 'jfrog rt c' command changed to 'jfrog c add'
Utils.NEW_CONFIG_CLI_VERSION = '1.45.0';
Utils.CLI_VERSION_ARG = 'version';
Utils.MIN_CLI_VERSION = '1.29.0';
Utils.LATEST_CLI_VERSION_ARG = 'latest';
Utils.LATEST_RELEASE_VERSION = '[RELEASE]';
Loading

0 comments on commit 126069f

Please sign in to comment.