From 31c29fa9c43d7fb5948aff31f0f5238fd341cba4 Mon Sep 17 00:00:00 2001 From: bsouza Date: Thu, 12 Sep 2024 16:51:42 +0000 Subject: [PATCH 1/9] Fix check for shell completion Signed-off-by: bsouza --- jfrog-token/run.sh | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/jfrog-token/run.sh b/jfrog-token/run.sh index 52b35139..d2113d99 100644 --- a/jfrog-token/run.sh +++ b/jfrog-token/run.sh @@ -96,20 +96,19 @@ echo "📦 Configuring JFrog CLI completion..." SHELLNAME=$(grep "^$USER" /etc/passwd | awk -F':' '{print $7}' | awk -F'/' '{print $NF}') # Generate the completion script jf completion $SHELLNAME --install +begin_stanza="# BEGIN: jf CLI shell completion (added by coder module jfrog-token)" # Add the completion script to the user's shell profile if [ "$SHELLNAME" == "bash" ] && [ -f ~/.bashrc ]; then - if ! grep -q "# jf CLI shell completion" ~/.bashrc; then - echo "" >> ~/.bashrc - echo "# BEGIN: jf CLI shell completion (added by coder module jfrog-token)" >> ~/.bashrc + if ! grep -q "$begin_stanza" ~/.bashrc; then + printf "%s\n" "$begin_stanza" >> ~/.bashrc echo 'source "$HOME/.jfrog/jfrog_bash_completion"' >> ~/.bashrc echo "# END: jf CLI shell completion" >> ~/.bashrc else echo "🥳 ~/.bashrc already contains jf CLI shell completion configuration, skipping." fi elif [ "$SHELLNAME" == "zsh" ] && [ -f ~/.zshrc ]; then - if ! grep -q "# jf CLI shell completion" ~/.zshrc; then - echo "" >> ~/.zshrc - echo "# BEGIN: jf CLI shell completion (added by coder module jfrog-token)" >> ~/.zshrc + if ! grep -q "$begin_stanza" ~/.zshrc; then + printf "\n%s\n" "$begin_stanza" >> ~/.zshrc echo "autoload -Uz compinit" >> ~/.zshrc echo "compinit" >> ~/.zshrc echo 'source "$HOME/.jfrog/jfrog_zsh_completion"' >> ~/.zshrc From 646adbcc5134760a863e2615c9a7f7df5e17d3d2 Mon Sep 17 00:00:00 2001 From: bsouza Date: Sun, 15 Sep 2024 23:12:01 +0000 Subject: [PATCH 2/9] Support for multiple repos --- jfrog-token/.npmrc.tftpl | 5 ++ jfrog-token/main.test.ts | 102 ++++++++++++++++++++++++++++++++++--- jfrog-token/main.tf | 88 ++++++++++++++++++++++---------- jfrog-token/pip.conf.tftpl | 6 +++ jfrog-token/run.sh | 51 +++++++++++-------- 5 files changed, 198 insertions(+), 54 deletions(-) create mode 100644 jfrog-token/.npmrc.tftpl create mode 100644 jfrog-token/pip.conf.tftpl diff --git a/jfrog-token/.npmrc.tftpl b/jfrog-token/.npmrc.tftpl new file mode 100644 index 00000000..8bb9fb8f --- /dev/null +++ b/jfrog-token/.npmrc.tftpl @@ -0,0 +1,5 @@ +email=${ARTIFACTORY_EMAIL} +%{ for REPO in REPOS ~} +${REPO.SCOPE}registry=${JFROG_URL}/artifactory/api/npm/${REPO.NAME} +//${JFROG_HOST}/artifactory/api/npm/${REPO.NAME}/:_authToken=${ARTIFACTORY_ACCESS_TOKEN} +%{ endfor ~} diff --git a/jfrog-token/main.test.ts b/jfrog-token/main.test.ts index b3b8df98..d71a4862 100644 --- a/jfrog-token/main.test.ts +++ b/jfrog-token/main.test.ts @@ -1,8 +1,10 @@ import { serve } from "bun"; -import { describe } from "bun:test"; +import { describe, expect, it } from "bun:test"; import { createJSONResponse, + findResourceInstance, runTerraformInit, + runTerraformApply, testRequiredVariables, } from "../test"; @@ -32,10 +34,98 @@ describe("jfrog-token", async () => { port: 0, }); - testRequiredVariables(import.meta.dir, { - agent_id: "some-agent-id", - jfrog_url: "http://" + fakeFrogHost.hostname + ":" + fakeFrogHost.port, - artifactory_access_token: "XXXX", - package_managers: "{}", + const fakeFrogHostAndPort = `${fakeFrogHost.hostname}:${fakeFrogHost.port}`; + const fakeFrogUrl = `http://${fakeFrogHostAndPort}`; + + it("can run apply with required variables", async () => { + testRequiredVariables(import.meta.dir, { + agent_id: "some-agent-id", + jfrog_url: fakeFrogUrl, + artifactory_access_token: "XXXX", + package_managers: "{}", + }); + }); + + it("generates an npmrc with scoped repos", async () => { + const state = await runTerraformApply(import.meta.dir, { + agent_id: "some-agent-id", + jfrog_url: fakeFrogUrl, + artifactory_access_token: "XXXX", + package_managers: JSON.stringify({ + npm: ["global", "@foo:foo", "@bar:bar"], + }), + }); + const coderScript = findResourceInstance(state, "coder_script"); + const npmrcStanza = `cat << EOF > ~/.npmrc +email=default@example.com +registry=${fakeFrogUrl}/artifactory/api/npm/global +//${fakeFrogHostAndPort}/artifactory/api/npm/global/:_authToken=xxx +@foo:registry=${fakeFrogUrl}/artifactory/api/npm/foo +//${fakeFrogHostAndPort}/artifactory/api/npm/foo/:_authToken=xxx +@bar:registry=${fakeFrogUrl}/artifactory/api/npm/bar +//${fakeFrogHostAndPort}/artifactory/api/npm/bar/:_authToken=xxx + +EOF`; + expect(coderScript.script).toContain(npmrcStanza); + expect(coderScript.script).toContain('jf npmc --global --repo-resolve "global"'); + expect(coderScript.script).toContain('if [ -z "YES" ]; then\n not_configured npm'); + }); + + it("generates a pip config with extra-indexes", async () => { + const state = await runTerraformApply(import.meta.dir, { + agent_id: "some-agent-id", + jfrog_url: fakeFrogUrl, + artifactory_access_token: "XXXX", + package_managers: JSON.stringify({ + pypi: ["global", "foo", "bar"], + }), + }); + const coderScript = findResourceInstance(state, "coder_script"); + const pipStanza = `cat << EOF > ~/.pip/pip.conf +[global] +index-url = https://default:xxx@${fakeFrogHostAndPort}/artifactory/api/pypi/global/simple +extra-index-url = + https://default:xxx@${fakeFrogHostAndPort}/artifactory/api/pypi/foo/simple + https://default:xxx@${fakeFrogHostAndPort}/artifactory/api/pypi/bar/simple + +EOF`; + expect(coderScript.script).toContain(pipStanza); + expect(coderScript.script).toContain('jf pipc --global --repo-resolve "global"'); + expect(coderScript.script).toContain('if [ -z "YES" ]; then\n not_configured pypi'); + }); + + it("registers multiple docker repos", async () => { + const state = await runTerraformApply(import.meta.dir, { + agent_id: "some-agent-id", + jfrog_url: fakeFrogUrl, + artifactory_access_token: "XXXX", + package_managers: JSON.stringify({ + docker: ["foo.jfrog.io", "bar.jfrog.io", "baz.jfrog.io"], + }), + }); + const coderScript = findResourceInstance(state, "coder_script"); + const dockerStanza = `register_docker "foo.jfrog.io" +register_docker "bar.jfrog.io" +register_docker "baz.jfrog.io"`; + expect(coderScript.script).toContain(dockerStanza); + expect(coderScript.script).toContain('if [ -z "YES" ]; then\n not_configured docker'); + }); + + it("sets goproxy with multiple repos", async () => { + const state = await runTerraformApply(import.meta.dir, { + agent_id: "some-agent-id", + jfrog_url: fakeFrogUrl, + artifactory_access_token: "XXXX", + package_managers: JSON.stringify({ + go: ["foo", "bar", "baz"], + }), + }); + const proxyEnv = findResourceInstance(state, "coder_env", "goproxy"); + const proxies = `https://default:xxx@${fakeFrogHostAndPort}/artifactory/api/go/foo,https://default:xxx@${fakeFrogHostAndPort}/artifactory/api/go/bar,https://default:xxx@${fakeFrogHostAndPort}/artifactory/api/go/baz`; + expect(proxyEnv["value"]).toEqual(proxies); + + const coderScript = findResourceInstance(state, "coder_script"); + expect(coderScript.script).toContain('jf goc --global --repo-resolve "foo"'); + expect(coderScript.script).toContain('if [ -z "YES" ]; then\n not_configured go'); }); }); diff --git a/jfrog-token/main.tf b/jfrog-token/main.tf index 90dad613..f6f5f5b0 100644 --- a/jfrog-token/main.tf +++ b/jfrog-token/main.tf @@ -80,23 +80,51 @@ variable "configure_code_server" { } variable "package_managers" { - type = map(string) - description = < /dev/null 2>&1; then echo "✅ JFrog CLI is already installed, skipping installation." @@ -11,8 +26,7 @@ else sudo chmod 755 /usr/local/bin/jf fi -# The jf CLI checks $CI when determining whether to use interactive -# flows. +# The jf CLI checks $CI when determining whether to use interactive flows. export CI=true # Authenticate JFrog CLI with Artifactory. echo "${ARTIFACTORY_ACCESS_TOKEN}" | jf c add --access-token-stdin --url "${JFROG_URL}" --overwrite "${JFROG_SERVER_ID}" @@ -20,52 +34,47 @@ echo "${ARTIFACTORY_ACCESS_TOKEN}" | jf c add --access-token-stdin --url "${JFRO jf c use "${JFROG_SERVER_ID}" # Configure npm to use the Artifactory "npm" repository. -if [ -z "${REPOSITORY_NPM}" ]; then - echo "🤔 no npm repository is set, skipping npm configuration." - echo "You can configure an npm repository by providing the a key for 'npm' in the 'package_managers' input." +if [ -z "${HAS_NPM}" ]; then + not_configured npm else echo "📦 Configuring npm..." jf npmc --global --repo-resolve "${REPOSITORY_NPM}" cat << EOF > ~/.npmrc -email=${ARTIFACTORY_EMAIL} -registry=${JFROG_URL}/artifactory/api/npm/${REPOSITORY_NPM} +${NPMRC} EOF - echo "//${JFROG_HOST}/artifactory/api/npm/${REPOSITORY_NPM}/:_authToken=${ARTIFACTORY_ACCESS_TOKEN}" >> ~/.npmrc + echo "🥳 Configuration complete!" fi # Configure the `pip` to use the Artifactory "python" repository. -if [ -z "${REPOSITORY_PYPI}" ]; then - echo "🤔 no pypi repository is set, skipping pip configuration." - echo "You can configure a pypi repository by providing the a key for 'pypi' in the 'package_managers' input." +if [ -z "${HAS_PYPI}" ]; then + not_configured pypi else echo "🐍 Configuring pip..." jf pipc --global --repo-resolve "${REPOSITORY_PYPI}" mkdir -p ~/.pip cat << EOF > ~/.pip/pip.conf -[global] -index-url = https://${ARTIFACTORY_USERNAME}:${ARTIFACTORY_ACCESS_TOKEN}@${JFROG_HOST}/artifactory/api/pypi/${REPOSITORY_PYPI}/simple +${PIP_CONF} EOF + echo "🥳 Configuration complete!" fi # Configure Artifactory "go" repository. -if [ -z "${REPOSITORY_GO}" ]; then - echo "🤔 no go repository is set, skipping go configuration." - echo "You can configure a go repository by providing the a key for 'go' in the 'package_managers' input." +if [ -z "${HAS_GO}" ]; then + not_configured go else echo "🐹 Configuring go..." jf goc --global --repo-resolve "${REPOSITORY_GO}" + echo "🥳 Configuration complete!" fi -echo "🥳 Configuration complete!" # Configure the JFrog CLI to use the Artifactory "docker" repository. -if [ -z "${REPOSITORY_DOCKER}" ]; then - echo "🤔 no docker repository is set, skipping docker configuration." - echo "You can configure a docker repository by providing the a key for 'docker' in the 'package_managers' input." +if [ -z "${HAS_DOCKER}" ]; then + not_configured docker else if command -v docker > /dev/null 2>&1; then echo "🔑 Configuring 🐳 docker credentials..." mkdir -p ~/.docker - echo -n "${ARTIFACTORY_ACCESS_TOKEN}" | docker login ${JFROG_HOST} --username ${ARTIFACTORY_USERNAME} --password-stdin + ${REGISTER_DOCKER} else echo "🤔 no docker is installed, skipping docker configuration." fi From 0361847bbdaf1fc7ef06d05a06d3b41015594db8 Mon Sep 17 00:00:00 2001 From: Brent Souza Date: Mon, 16 Sep 2024 17:38:47 -0400 Subject: [PATCH 3/9] Fix function syntax --- jfrog-token/run.sh | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/jfrog-token/run.sh b/jfrog-token/run.sh index 41e0b1d2..4c68ca15 100644 --- a/jfrog-token/run.sh +++ b/jfrog-token/run.sh @@ -2,17 +2,17 @@ BOLD='\033[0;1m' -func not_configured(){ +not_configured(){ type=$1 echo "🤔 no $type repository is set, skipping $type configuration." echo "You can configure a $type repository by providing a key for '$type' in the 'package_managers' input." } -func done(){ +config_complete(){ echo "🥳 Configuration complete!" } -func register_docker(){ +register_docker(){ repo=$1 echo -n "${ARTIFACTORY_ACCESS_TOKEN}" | docker login "$repo" --username ${ARTIFACTORY_USERNAME} --password-stdin } @@ -42,7 +42,7 @@ else cat << EOF > ~/.npmrc ${NPMRC} EOF - echo "🥳 Configuration complete!" + config_complete fi # Configure the `pip` to use the Artifactory "python" repository. @@ -55,7 +55,7 @@ else cat << EOF > ~/.pip/pip.conf ${PIP_CONF} EOF - echo "🥳 Configuration complete!" + config_complete fi # Configure Artifactory "go" repository. @@ -64,7 +64,7 @@ if [ -z "${HAS_GO}" ]; then else echo "🐹 Configuring go..." jf goc --global --repo-resolve "${REPOSITORY_GO}" - echo "🥳 Configuration complete!" + config_complete fi # Configure the JFrog CLI to use the Artifactory "docker" repository. From b6c0d5843873d6f402deb8ac3d4d65fd689bcfd6 Mon Sep 17 00:00:00 2001 From: bsouza Date: Fri, 20 Sep 2024 13:28:01 +0000 Subject: [PATCH 4/9] Update readme and port to jfrog-oauth --- jfrog-oauth/.npmrc.tftpl | 5 +++ jfrog-oauth/README.md | 21 +++++----- jfrog-oauth/main.tf | 86 ++++++++++++++++++++++++++------------ jfrog-oauth/pip.conf.tftpl | 6 +++ jfrog-oauth/run.sh | 61 +++++++++++++++------------ jfrog-token/README.md | 31 +++++++------- 6 files changed, 132 insertions(+), 78 deletions(-) create mode 100644 jfrog-oauth/.npmrc.tftpl create mode 100644 jfrog-oauth/pip.conf.tftpl diff --git a/jfrog-oauth/.npmrc.tftpl b/jfrog-oauth/.npmrc.tftpl new file mode 100644 index 00000000..8bb9fb8f --- /dev/null +++ b/jfrog-oauth/.npmrc.tftpl @@ -0,0 +1,5 @@ +email=${ARTIFACTORY_EMAIL} +%{ for REPO in REPOS ~} +${REPO.SCOPE}registry=${JFROG_URL}/artifactory/api/npm/${REPO.NAME} +//${JFROG_HOST}/artifactory/api/npm/${REPO.NAME}/:_authToken=${ARTIFACTORY_ACCESS_TOKEN} +%{ endfor ~} diff --git a/jfrog-oauth/README.md b/jfrog-oauth/README.md index b7f9d58f..2f60b1fa 100644 --- a/jfrog-oauth/README.md +++ b/jfrog-oauth/README.md @@ -17,15 +17,16 @@ Install the JF CLI and authenticate package managers with Artifactory using OAut ```tf module "jfrog" { source = "registry.coder.com/modules/jfrog-oauth/coder" - version = "1.0.15" + version = "2.0.0" agent_id = coder_agent.example.id jfrog_url = "https://example.jfrog.io" username_field = "username" # If you are using GitHub to login to both Coder and Artifactory, use username_field = "username" package_managers = { - "npm" : "npm", - "go" : "go", - "pypi" : "pypi" + npm = ["npm", "@scoped:npm-scoped"] + go = ["go", "another-go-repo"] + pypi = ["pypi", "extra-index-pypi"] + docker = ["example-docker-staging.jfrog.io", "example-docker-production.jfrog.io"] } } ``` @@ -44,13 +45,13 @@ Configure the Python pip package manager to fetch packages from Artifactory whil ```tf module "jfrog" { source = "registry.coder.com/modules/jfrog-oauth/coder" - version = "1.0.15" + version = "2.0.0" agent_id = coder_agent.example.id jfrog_url = "https://example.jfrog.io" username_field = "email" package_managers = { - "pypi" : "pypi" + pypi = ["pypi"] } } ``` @@ -72,15 +73,15 @@ The [JFrog extension](https://open-vsx.org/extension/JFrog/jfrog-vscode-extensio ```tf module "jfrog" { source = "registry.coder.com/modules/jfrog-oauth/coder" - version = "1.0.15" + version = "2.0.0" agent_id = coder_agent.example.id jfrog_url = "https://example.jfrog.io" username_field = "username" # If you are using GitHub to login to both Coder and Artifactory, use username_field = "username" configure_code_server = true # Add JFrog extension configuration for code-server package_managers = { - "npm" : "npm", - "go" : "go", - "pypi" : "pypi" + npm = ["npm"] + go = ["go"] + pypi = ["pypi"] } } ``` diff --git a/jfrog-oauth/main.tf b/jfrog-oauth/main.tf index 767235a1..953a5567 100644 --- a/jfrog-oauth/main.tf +++ b/jfrog-oauth/main.tf @@ -53,23 +53,51 @@ variable "configure_code_server" { } variable "package_managers" { - type = map(string) - description = < /dev/null 2>&1; then echo "✅ JFrog CLI is already installed, skipping installation." @@ -20,52 +35,47 @@ echo "${ARTIFACTORY_ACCESS_TOKEN}" | jf c add --access-token-stdin --url "${JFRO jf c use "${JFROG_SERVER_ID}" # Configure npm to use the Artifactory "npm" repository. -if [ -z "${REPOSITORY_NPM}" ]; then - echo "🤔 no npm repository is set, skipping npm configuration." - echo "You can configure an npm repository by providing the a key for 'npm' in the 'package_managers' input." +if [ -z "${HAS_NPM}" ]; then + not_configured npm else echo "📦 Configuring npm..." jf npmc --global --repo-resolve "${REPOSITORY_NPM}" cat << EOF > ~/.npmrc -email=${ARTIFACTORY_EMAIL} -registry=${JFROG_URL}/artifactory/api/npm/${REPOSITORY_NPM} +${NPMRC} EOF - echo "//${JFROG_HOST}/artifactory/api/npm/${REPOSITORY_NPM}/:_authToken=${ARTIFACTORY_ACCESS_TOKEN}" >> ~/.npmrc + config_complete fi # Configure the `pip` to use the Artifactory "python" repository. -if [ -z "${REPOSITORY_PYPI}" ]; then - echo "🤔 no pypi repository is set, skipping pip configuration." - echo "You can configure a pypi repository by providing the a key for 'pypi' in the 'package_managers' input." +if [ -z "${HAS_PYPI}" ]; then + not_configured pypi else - echo "📦 Configuring pip..." + echo "🐍 Configuring pip..." jf pipc --global --repo-resolve "${REPOSITORY_PYPI}" mkdir -p ~/.pip cat << EOF > ~/.pip/pip.conf -[global] -index-url = https://${ARTIFACTORY_USERNAME}:${ARTIFACTORY_ACCESS_TOKEN}@${JFROG_HOST}/artifactory/api/pypi/${REPOSITORY_PYPI}/simple +${PIP_CONF} EOF + config_complete fi # Configure Artifactory "go" repository. -if [ -z "${REPOSITORY_GO}" ]; then - echo "🤔 no go repository is set, skipping go configuration." - echo "You can configure a go repository by providing the a key for 'go' in the 'package_managers' input." +if [ -z "${HAS_GO}" ]; then + not_configured go else echo "🐹 Configuring go..." jf goc --global --repo-resolve "${REPOSITORY_GO}" + config_complete fi -echo "🥳 Configuration complete!" # Configure the JFrog CLI to use the Artifactory "docker" repository. -if [ -z "${REPOSITORY_DOCKER}" ]; then - echo "🤔 no docker repository is set, skipping docker configuration." - echo "You can configure a docker repository by providing the a key for 'docker' in the 'package_managers' input." +if [ -z "${HAS_DOCKER}" ]; then + not_configured docker else if command -v docker > /dev/null 2>&1; then echo "🔑 Configuring 🐳 docker credentials..." mkdir -p ~/.docker - echo -n "${ARTIFACTORY_ACCESS_TOKEN}" | docker login ${JFROG_HOST} --username ${ARTIFACTORY_USERNAME} --password-stdin + ${REGISTER_DOCKER} else echo "🤔 no docker is installed, skipping docker configuration." fi @@ -96,20 +106,19 @@ echo "📦 Configuring JFrog CLI completion..." SHELLNAME=$(grep "^$USER" /etc/passwd | awk -F':' '{print $7}' | awk -F'/' '{print $NF}') # Generate the completion script jf completion $SHELLNAME --install +begin_stanza="# BEGIN: jf CLI shell completion (added by coder module jfrog-oauth)" # Add the completion script to the user's shell profile if [ "$SHELLNAME" == "bash" ] && [ -f ~/.bashrc ]; then - if ! grep -q "# jf CLI shell completion" ~/.bashrc; then - echo "" >> ~/.bashrc - echo "# BEGIN: jf CLI shell completion (added by coder module jfrog-oauth)" >> ~/.bashrc + if ! grep -q "$begin_stanza" ~/.bashrc; then + printf "%s\n" "$begin_stanza" >> ~/.bashrc echo 'source "$HOME/.jfrog/jfrog_bash_completion"' >> ~/.bashrc echo "# END: jf CLI shell completion" >> ~/.bashrc else echo "🥳 ~/.bashrc already contains jf CLI shell completion configuration, skipping." fi elif [ "$SHELLNAME" == "zsh" ] && [ -f ~/.zshrc ]; then - if ! grep -q "# jf CLI shell completion" ~/.zshrc; then - echo "" >> ~/.zshrc - echo "# BEGIN: jf CLI shell completion (added by coder module jfrog-oauth)" >> ~/.zshrc + if ! grep -q "$begin_stanza" ~/.zshrc; then + printf "\n%s\n" "$begin_stanza" >> ~/.zshrc echo "autoload -Uz compinit" >> ~/.zshrc echo "compinit" >> ~/.zshrc echo 'source "$HOME/.jfrog/jfrog_zsh_completion"' >> ~/.zshrc diff --git a/jfrog-token/README.md b/jfrog-token/README.md index f903f90d..172d0c01 100644 --- a/jfrog-token/README.md +++ b/jfrog-token/README.md @@ -15,14 +15,15 @@ Install the JF CLI and authenticate package managers with Artifactory using Arti ```tf module "jfrog" { source = "registry.coder.com/modules/jfrog-token/coder" - version = "1.0.15" + version = "2.0.0" agent_id = coder_agent.example.id jfrog_url = "https://XXXX.jfrog.io" artifactory_access_token = var.artifactory_access_token package_managers = { - "npm" : "npm", - "go" : "go", - "pypi" : "pypi" + npm = ["npm", "@scoped:npm-scoped"] + go = ["go", "another-go-repo"] + pypi = ["pypi", "extra-index-pypi"] + docker = ["example-docker-staging.jfrog.io", "example-docker-production.jfrog.io"] } } ``` @@ -41,14 +42,14 @@ For detailed instructions, please see this [guide](https://coder.com/docs/v2/lat ```tf module "jfrog" { source = "registry.coder.com/modules/jfrog-token/coder" - version = "1.0.15" + version = "2.0.0" agent_id = coder_agent.example.id jfrog_url = "https://YYYY.jfrog.io" artifactory_access_token = var.artifactory_access_token # An admin access token package_managers = { - "npm" : "npm-local", - "go" : "go-local", - "pypi" : "pypi-local" + npm = ["npm-local"] + go = ["go-local"] + pypi = ["pypi-local"] } } ``` @@ -74,15 +75,15 @@ The [JFrog extension](https://open-vsx.org/extension/JFrog/jfrog-vscode-extensio ```tf module "jfrog" { source = "registry.coder.com/modules/jfrog-token/coder" - version = "1.0.15" + version = "2.0.0" agent_id = coder_agent.example.id jfrog_url = "https://XXXX.jfrog.io" artifactory_access_token = var.artifactory_access_token configure_code_server = true # Add JFrog extension configuration for code-server package_managers = { - "npm" : "npm", - "go" : "go", - "pypi" : "pypi" + npm = ["npm"] + go = ["go"] + pypi = ["pypi"] } } ``` @@ -94,15 +95,13 @@ data "coder_workspace" "me" {} module "jfrog" { source = "registry.coder.com/modules/jfrog-token/coder" - version = "1.0.15" + version = "2.0.0" agent_id = coder_agent.example.id jfrog_url = "https://XXXX.jfrog.io" artifactory_access_token = var.artifactory_access_token token_description = "Token for Coder workspace: ${data.coder_workspace_owner.me.name}/${data.coder_workspace.me.name}" package_managers = { - "npm" : "npm", - "go" : "go", - "pypi" : "pypi" + npm = ["npm"] } } ``` From fd5ba0fab9d150a3de5d73d0c3bc769db05dfd53 Mon Sep 17 00:00:00 2001 From: bsouza Date: Fri, 20 Sep 2024 13:43:39 +0000 Subject: [PATCH 5/9] Port tests to oauth module and fix errors --- jfrog-oauth/main.test.ts | 100 +++++++++++++++++++++++++++++++++++---- jfrog-oauth/main.tf | 6 +-- 2 files changed, 94 insertions(+), 12 deletions(-) diff --git a/jfrog-oauth/main.test.ts b/jfrog-oauth/main.test.ts index 3397eebb..40ea77ba 100644 --- a/jfrog-oauth/main.test.ts +++ b/jfrog-oauth/main.test.ts @@ -1,19 +1,101 @@ -import { serve } from "bun"; -import { describe } from "bun:test"; +import { describe, expect, it } from "bun:test"; import { - createJSONResponse, + findResourceInstance, runTerraformInit, + runTerraformApply, testRequiredVariables, } from "../test"; describe("jfrog-oauth", async () => { await runTerraformInit(import.meta.dir); - testRequiredVariables(import.meta.dir, { - agent_id: "some-agent-id", - jfrog_url: "http://localhost:8081", - package_managers: "{}", + const fakeFrogHostAndPort = "localhost:8081"; + const fakeFrogUrl = `http://${fakeFrogHostAndPort}`; + + it("can run apply with required variables", async () => { + testRequiredVariables(import.meta.dir, { + agent_id: "some-agent-id", + jfrog_url: fakeFrogUrl, + package_managers: "{}", + }); }); -}); -//TODO add more tests + it("generates an npmrc with scoped repos", async () => { + const state = await runTerraformApply(import.meta.dir, { + agent_id: "some-agent-id", + jfrog_url: fakeFrogUrl, + package_managers: JSON.stringify({ + npm: ["global", "@foo:foo", "@bar:bar"], + }), + }); + const coderScript = findResourceInstance(state, "coder_script"); + const npmrcStanza = `cat << EOF > ~/.npmrc +email=default@example.com +registry=${fakeFrogUrl}/artifactory/api/npm/global +//${fakeFrogHostAndPort}/artifactory/api/npm/global/:_authToken= +@foo:registry=${fakeFrogUrl}/artifactory/api/npm/foo +//${fakeFrogHostAndPort}/artifactory/api/npm/foo/:_authToken= +@bar:registry=${fakeFrogUrl}/artifactory/api/npm/bar +//${fakeFrogHostAndPort}/artifactory/api/npm/bar/:_authToken= + +EOF`; + expect(coderScript.script).toContain(npmrcStanza); + expect(coderScript.script).toContain('jf npmc --global --repo-resolve "global"'); + expect(coderScript.script).toContain('if [ -z "YES" ]; then\n not_configured npm'); + }); + + it("generates a pip config with extra-indexes", async () => { + const state = await runTerraformApply(import.meta.dir, { + agent_id: "some-agent-id", + jfrog_url: fakeFrogUrl, + package_managers: JSON.stringify({ + pypi: ["global", "foo", "bar"], + }), + }); + const coderScript = findResourceInstance(state, "coder_script"); + const pipStanza = `cat << EOF > ~/.pip/pip.conf +[global] +index-url = https://default:@${fakeFrogHostAndPort}/artifactory/api/pypi/global/simple +extra-index-url = + https://default:@${fakeFrogHostAndPort}/artifactory/api/pypi/foo/simple + https://default:@${fakeFrogHostAndPort}/artifactory/api/pypi/bar/simple + +EOF`; + expect(coderScript.script).toContain(pipStanza); + expect(coderScript.script).toContain('jf pipc --global --repo-resolve "global"'); + expect(coderScript.script).toContain('if [ -z "YES" ]; then\n not_configured pypi'); + }); + + it("registers multiple docker repos", async () => { + const state = await runTerraformApply(import.meta.dir, { + agent_id: "some-agent-id", + jfrog_url: fakeFrogUrl, + package_managers: JSON.stringify({ + docker: ["foo.jfrog.io", "bar.jfrog.io", "baz.jfrog.io"], + }), + }); + const coderScript = findResourceInstance(state, "coder_script"); + const dockerStanza = `register_docker "foo.jfrog.io" +register_docker "bar.jfrog.io" +register_docker "baz.jfrog.io"`; + expect(coderScript.script).toContain(dockerStanza); + expect(coderScript.script).toContain('if [ -z "YES" ]; then\n not_configured docker'); + }); + + it("sets goproxy with multiple repos", async () => { + const state = await runTerraformApply(import.meta.dir, { + agent_id: "some-agent-id", + jfrog_url: fakeFrogUrl, + package_managers: JSON.stringify({ + go: ["foo", "bar", "baz"], + }), + }); + const proxyEnv = findResourceInstance(state, "coder_env", "goproxy"); + const proxies = `https://default:@${fakeFrogHostAndPort}/artifactory/api/go/foo,https://default:@${fakeFrogHostAndPort}/artifactory/api/go/bar,https://default:@${fakeFrogHostAndPort}/artifactory/api/go/baz`; + expect(proxyEnv["value"]).toEqual(proxies); + + const coderScript = findResourceInstance(state, "coder_script"); + expect(coderScript.script).toContain('jf goc --global --repo-resolve "foo"'); + expect(coderScript.script).toContain('if [ -z "YES" ]; then\n not_configured go'); + }); +}); diff --git a/jfrog-oauth/main.tf b/jfrog-oauth/main.tf index 953a5567..c5c32b2a 100644 --- a/jfrog-oauth/main.tf +++ b/jfrog-oauth/main.tf @@ -74,7 +74,7 @@ variable "package_managers" { locals { # The username field to use for artifactory username = var.username_field == "email" ? data.coder_workspace_owner.me.email : data.coder_workspace_owner.me.name - jfrog_host = replace(var.jfrog_url, "https://", "") + jfrog_host = split("://", var.jfrog_url)[1] common_values = { JFROG_URL = var.jfrog_url JFROG_HOST = local.jfrog_host @@ -114,7 +114,7 @@ resource "coder_script" "jfrog" { script = templatefile("${path.module}/run.sh", merge( local.common_values, { - CONFIGURE_CODE_SERVER = var.configure_code_server + CONFIGURE_CODE_SERVER = var.configure_code_server HAS_NPM = length(var.package_managers.npm) == 0 ? "" : "YES" NPMRC = local.npmrc REPOSITORY_NPM = try(element(var.package_managers.npm, 0), "") @@ -157,7 +157,7 @@ resource "coder_env" "goproxy" { name = "GOPROXY" value = join(",", [ for repo in var.package_managers.go : - "https://${local.username}:${artifactory_scoped_token.me.access_token}@${local.jfrog_host}/artifactory/api/go/${repo}" + "https://${local.username}:${data.coder_external_auth.jfrog.access_token}@${local.jfrog_host}/artifactory/api/go/${repo}" ]) } From 67c1d63ab5e0dcc67ac120d7bd9a6fba11a9c2e5 Mon Sep 17 00:00:00 2001 From: bsouza Date: Fri, 20 Sep 2024 13:49:34 +0000 Subject: [PATCH 6/9] Fix formatting --- jfrog-oauth/main.test.ts | 30 ++++++++++++++++++++++-------- jfrog-oauth/run.sh | 6 +++--- jfrog-token/README.md | 2 +- jfrog-token/main.test.ts | 30 ++++++++++++++++++++++-------- jfrog-token/run.sh | 6 +++--- 5 files changed, 51 insertions(+), 23 deletions(-) diff --git a/jfrog-oauth/main.test.ts b/jfrog-oauth/main.test.ts index 40ea77ba..7e2ab6ed 100644 --- a/jfrog-oauth/main.test.ts +++ b/jfrog-oauth/main.test.ts @@ -40,8 +40,12 @@ registry=${fakeFrogUrl}/artifactory/api/npm/global EOF`; expect(coderScript.script).toContain(npmrcStanza); - expect(coderScript.script).toContain('jf npmc --global --repo-resolve "global"'); - expect(coderScript.script).toContain('if [ -z "YES" ]; then\n not_configured npm'); + expect(coderScript.script).toContain( + 'jf npmc --global --repo-resolve "global"', + ); + expect(coderScript.script).toContain( + 'if [ -z "YES" ]; then\n not_configured npm', + ); }); it("generates a pip config with extra-indexes", async () => { @@ -62,8 +66,12 @@ extra-index-url = EOF`; expect(coderScript.script).toContain(pipStanza); - expect(coderScript.script).toContain('jf pipc --global --repo-resolve "global"'); - expect(coderScript.script).toContain('if [ -z "YES" ]; then\n not_configured pypi'); + expect(coderScript.script).toContain( + 'jf pipc --global --repo-resolve "global"', + ); + expect(coderScript.script).toContain( + 'if [ -z "YES" ]; then\n not_configured pypi', + ); }); it("registers multiple docker repos", async () => { @@ -79,7 +87,9 @@ EOF`; register_docker "bar.jfrog.io" register_docker "baz.jfrog.io"`; expect(coderScript.script).toContain(dockerStanza); - expect(coderScript.script).toContain('if [ -z "YES" ]; then\n not_configured docker'); + expect(coderScript.script).toContain( + 'if [ -z "YES" ]; then\n not_configured docker', + ); }); it("sets goproxy with multiple repos", async () => { @@ -93,9 +103,13 @@ register_docker "baz.jfrog.io"`; const proxyEnv = findResourceInstance(state, "coder_env", "goproxy"); const proxies = `https://default:@${fakeFrogHostAndPort}/artifactory/api/go/foo,https://default:@${fakeFrogHostAndPort}/artifactory/api/go/bar,https://default:@${fakeFrogHostAndPort}/artifactory/api/go/baz`; expect(proxyEnv["value"]).toEqual(proxies); - + const coderScript = findResourceInstance(state, "coder_script"); - expect(coderScript.script).toContain('jf goc --global --repo-resolve "foo"'); - expect(coderScript.script).toContain('if [ -z "YES" ]; then\n not_configured go'); + expect(coderScript.script).toContain( + 'jf goc --global --repo-resolve "foo"', + ); + expect(coderScript.script).toContain( + 'if [ -z "YES" ]; then\n not_configured go', + ); }); }); diff --git a/jfrog-oauth/run.sh b/jfrog-oauth/run.sh index ba553952..7d36e47c 100644 --- a/jfrog-oauth/run.sh +++ b/jfrog-oauth/run.sh @@ -2,17 +2,17 @@ BOLD='\033[0;1m' -not_configured(){ +not_configured() { type=$1 echo "🤔 no $type repository is set, skipping $type configuration." echo "You can configure a $type repository by providing a key for '$type' in the 'package_managers' input." } -config_complete(){ +config_complete() { echo "🥳 Configuration complete!" } -register_docker(){ +register_docker() { repo=$1 echo -n "${ARTIFACTORY_ACCESS_TOKEN}" | docker login "$repo" --username ${ARTIFACTORY_USERNAME} --password-stdin } diff --git a/jfrog-token/README.md b/jfrog-token/README.md index 172d0c01..652451f6 100644 --- a/jfrog-token/README.md +++ b/jfrog-token/README.md @@ -101,7 +101,7 @@ module "jfrog" { artifactory_access_token = var.artifactory_access_token token_description = "Token for Coder workspace: ${data.coder_workspace_owner.me.name}/${data.coder_workspace.me.name}" package_managers = { - npm = ["npm"] + npm = ["npm"] } } ``` diff --git a/jfrog-token/main.test.ts b/jfrog-token/main.test.ts index d71a4862..af367108 100644 --- a/jfrog-token/main.test.ts +++ b/jfrog-token/main.test.ts @@ -67,8 +67,12 @@ registry=${fakeFrogUrl}/artifactory/api/npm/global EOF`; expect(coderScript.script).toContain(npmrcStanza); - expect(coderScript.script).toContain('jf npmc --global --repo-resolve "global"'); - expect(coderScript.script).toContain('if [ -z "YES" ]; then\n not_configured npm'); + expect(coderScript.script).toContain( + 'jf npmc --global --repo-resolve "global"', + ); + expect(coderScript.script).toContain( + 'if [ -z "YES" ]; then\n not_configured npm', + ); }); it("generates a pip config with extra-indexes", async () => { @@ -90,8 +94,12 @@ extra-index-url = EOF`; expect(coderScript.script).toContain(pipStanza); - expect(coderScript.script).toContain('jf pipc --global --repo-resolve "global"'); - expect(coderScript.script).toContain('if [ -z "YES" ]; then\n not_configured pypi'); + expect(coderScript.script).toContain( + 'jf pipc --global --repo-resolve "global"', + ); + expect(coderScript.script).toContain( + 'if [ -z "YES" ]; then\n not_configured pypi', + ); }); it("registers multiple docker repos", async () => { @@ -108,7 +116,9 @@ EOF`; register_docker "bar.jfrog.io" register_docker "baz.jfrog.io"`; expect(coderScript.script).toContain(dockerStanza); - expect(coderScript.script).toContain('if [ -z "YES" ]; then\n not_configured docker'); + expect(coderScript.script).toContain( + 'if [ -z "YES" ]; then\n not_configured docker', + ); }); it("sets goproxy with multiple repos", async () => { @@ -123,9 +133,13 @@ register_docker "baz.jfrog.io"`; const proxyEnv = findResourceInstance(state, "coder_env", "goproxy"); const proxies = `https://default:xxx@${fakeFrogHostAndPort}/artifactory/api/go/foo,https://default:xxx@${fakeFrogHostAndPort}/artifactory/api/go/bar,https://default:xxx@${fakeFrogHostAndPort}/artifactory/api/go/baz`; expect(proxyEnv["value"]).toEqual(proxies); - + const coderScript = findResourceInstance(state, "coder_script"); - expect(coderScript.script).toContain('jf goc --global --repo-resolve "foo"'); - expect(coderScript.script).toContain('if [ -z "YES" ]; then\n not_configured go'); + expect(coderScript.script).toContain( + 'jf goc --global --repo-resolve "foo"', + ); + expect(coderScript.script).toContain( + 'if [ -z "YES" ]; then\n not_configured go', + ); }); }); diff --git a/jfrog-token/run.sh b/jfrog-token/run.sh index 4c68ca15..d3a1a74c 100644 --- a/jfrog-token/run.sh +++ b/jfrog-token/run.sh @@ -2,17 +2,17 @@ BOLD='\033[0;1m' -not_configured(){ +not_configured() { type=$1 echo "🤔 no $type repository is set, skipping $type configuration." echo "You can configure a $type repository by providing a key for '$type' in the 'package_managers' input." } -config_complete(){ +config_complete() { echo "🥳 Configuration complete!" } -register_docker(){ +register_docker() { repo=$1 echo -n "${ARTIFACTORY_ACCESS_TOKEN}" | docker login "$repo" --username ${ARTIFACTORY_USERNAME} --password-stdin } From 4b0ac2a6fb96e967e7c6c4e7cececaa1b23fe645 Mon Sep 17 00:00:00 2001 From: Muhammad Atif Ali Date: Fri, 20 Sep 2024 19:51:02 +0500 Subject: [PATCH 7/9] `bun fmt` --- jfrog-oauth/main.tf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jfrog-oauth/main.tf b/jfrog-oauth/main.tf index c5c32b2a..0bc22568 100644 --- a/jfrog-oauth/main.tf +++ b/jfrog-oauth/main.tf @@ -112,7 +112,7 @@ resource "coder_script" "jfrog" { display_name = "jfrog" icon = "/icon/jfrog.svg" script = templatefile("${path.module}/run.sh", merge( - local.common_values, + local.common_values, { CONFIGURE_CODE_SERVER = var.configure_code_server HAS_NPM = length(var.package_managers.npm) == 0 ? "" : "YES" From d06cd4a2e40d7001319fef10b0ffec691d6d87ca Mon Sep 17 00:00:00 2001 From: bsouza Date: Fri, 20 Sep 2024 21:22:47 +0000 Subject: [PATCH 8/9] Address review items - Fix versions in readme - Make expected test values readable - Support typed vars for testing --- jfrog-oauth/README.md | 6 ++-- jfrog-oauth/main.test.ts | 56 ++++++++++++++++++++++-------------- jfrog-token/README.md | 8 +++--- jfrog-token/main.test.ts | 62 ++++++++++++++++++++++++++-------------- terraform_validate.sh | 26 ++++++++--------- test.ts | 14 ++++----- 6 files changed, 103 insertions(+), 69 deletions(-) diff --git a/jfrog-oauth/README.md b/jfrog-oauth/README.md index 2f60b1fa..4423a740 100644 --- a/jfrog-oauth/README.md +++ b/jfrog-oauth/README.md @@ -17,7 +17,7 @@ Install the JF CLI and authenticate package managers with Artifactory using OAut ```tf module "jfrog" { source = "registry.coder.com/modules/jfrog-oauth/coder" - version = "2.0.0" + version = "1.0.19" agent_id = coder_agent.example.id jfrog_url = "https://example.jfrog.io" username_field = "username" # If you are using GitHub to login to both Coder and Artifactory, use username_field = "username" @@ -45,7 +45,7 @@ Configure the Python pip package manager to fetch packages from Artifactory whil ```tf module "jfrog" { source = "registry.coder.com/modules/jfrog-oauth/coder" - version = "2.0.0" + version = "1.0.19" agent_id = coder_agent.example.id jfrog_url = "https://example.jfrog.io" username_field = "email" @@ -73,7 +73,7 @@ The [JFrog extension](https://open-vsx.org/extension/JFrog/jfrog-vscode-extensio ```tf module "jfrog" { source = "registry.coder.com/modules/jfrog-oauth/coder" - version = "2.0.0" + version = "1.0.19" agent_id = coder_agent.example.id jfrog_url = "https://example.jfrog.io" username_field = "username" # If you are using GitHub to login to both Coder and Artifactory, use username_field = "username" diff --git a/jfrog-oauth/main.test.ts b/jfrog-oauth/main.test.ts index 7e2ab6ed..da8b9bf6 100644 --- a/jfrog-oauth/main.test.ts +++ b/jfrog-oauth/main.test.ts @@ -7,13 +7,25 @@ import { } from "../test"; describe("jfrog-oauth", async () => { + type TestVariables = { + agent_id: string; + jfrog_url: string; + package_managers: string; + + username_field?: string; + jfrog_server_id?: string; + external_auth_id?: string; + configure_code_server?: boolean; + }; + await runTerraformInit(import.meta.dir); - const fakeFrogHostAndPort = "localhost:8081"; - const fakeFrogUrl = `http://${fakeFrogHostAndPort}`; + const fakeFrogApi = "localhost:8081/artifactory/api"; + const fakeFrogUrl = "http://localhost:8081"; + const user = "default"; it("can run apply with required variables", async () => { - testRequiredVariables(import.meta.dir, { + testRequiredVariables(import.meta.dir, { agent_id: "some-agent-id", jfrog_url: fakeFrogUrl, package_managers: "{}", @@ -21,7 +33,7 @@ describe("jfrog-oauth", async () => { }); it("generates an npmrc with scoped repos", async () => { - const state = await runTerraformApply(import.meta.dir, { + const state = await runTerraformApply(import.meta.dir, { agent_id: "some-agent-id", jfrog_url: fakeFrogUrl, package_managers: JSON.stringify({ @@ -30,13 +42,13 @@ describe("jfrog-oauth", async () => { }); const coderScript = findResourceInstance(state, "coder_script"); const npmrcStanza = `cat << EOF > ~/.npmrc -email=default@example.com -registry=${fakeFrogUrl}/artifactory/api/npm/global -//${fakeFrogHostAndPort}/artifactory/api/npm/global/:_authToken= -@foo:registry=${fakeFrogUrl}/artifactory/api/npm/foo -//${fakeFrogHostAndPort}/artifactory/api/npm/foo/:_authToken= -@bar:registry=${fakeFrogUrl}/artifactory/api/npm/bar -//${fakeFrogHostAndPort}/artifactory/api/npm/bar/:_authToken= +email=${user}@example.com +registry=http://${fakeFrogApi}/npm/global +//${fakeFrogApi}/npm/global/:_authToken= +@foo:registry=http://${fakeFrogApi}/npm/foo +//${fakeFrogApi}/npm/foo/:_authToken= +@bar:registry=http://${fakeFrogApi}/npm/bar +//${fakeFrogApi}/npm/bar/:_authToken= EOF`; expect(coderScript.script).toContain(npmrcStanza); @@ -49,7 +61,7 @@ EOF`; }); it("generates a pip config with extra-indexes", async () => { - const state = await runTerraformApply(import.meta.dir, { + const state = await runTerraformApply(import.meta.dir, { agent_id: "some-agent-id", jfrog_url: fakeFrogUrl, package_managers: JSON.stringify({ @@ -59,10 +71,10 @@ EOF`; const coderScript = findResourceInstance(state, "coder_script"); const pipStanza = `cat << EOF > ~/.pip/pip.conf [global] -index-url = https://default:@${fakeFrogHostAndPort}/artifactory/api/pypi/global/simple +index-url = https://${user}:@${fakeFrogApi}/pypi/global/simple extra-index-url = - https://default:@${fakeFrogHostAndPort}/artifactory/api/pypi/foo/simple - https://default:@${fakeFrogHostAndPort}/artifactory/api/pypi/bar/simple + https://${user}:@${fakeFrogApi}/pypi/foo/simple + https://${user}:@${fakeFrogApi}/pypi/bar/simple EOF`; expect(coderScript.script).toContain(pipStanza); @@ -75,7 +87,7 @@ EOF`; }); it("registers multiple docker repos", async () => { - const state = await runTerraformApply(import.meta.dir, { + const state = await runTerraformApply(import.meta.dir, { agent_id: "some-agent-id", jfrog_url: fakeFrogUrl, package_managers: JSON.stringify({ @@ -83,9 +95,9 @@ EOF`; }), }); const coderScript = findResourceInstance(state, "coder_script"); - const dockerStanza = `register_docker "foo.jfrog.io" -register_docker "bar.jfrog.io" -register_docker "baz.jfrog.io"`; + const dockerStanza = ["foo", "bar", "baz"] + .map((r) => `register_docker "${r}.jfrog.io"`) + .join("\n"); expect(coderScript.script).toContain(dockerStanza); expect(coderScript.script).toContain( 'if [ -z "YES" ]; then\n not_configured docker', @@ -93,7 +105,7 @@ register_docker "baz.jfrog.io"`; }); it("sets goproxy with multiple repos", async () => { - const state = await runTerraformApply(import.meta.dir, { + const state = await runTerraformApply(import.meta.dir, { agent_id: "some-agent-id", jfrog_url: fakeFrogUrl, package_managers: JSON.stringify({ @@ -101,7 +113,9 @@ register_docker "baz.jfrog.io"`; }), }); const proxyEnv = findResourceInstance(state, "coder_env", "goproxy"); - const proxies = `https://default:@${fakeFrogHostAndPort}/artifactory/api/go/foo,https://default:@${fakeFrogHostAndPort}/artifactory/api/go/bar,https://default:@${fakeFrogHostAndPort}/artifactory/api/go/baz`; + const proxies = ["foo", "bar", "baz"] + .map((r) => `https://${user}:@${fakeFrogApi}/go/${r}`) + .join(","); expect(proxyEnv["value"]).toEqual(proxies); const coderScript = findResourceInstance(state, "coder_script"); diff --git a/jfrog-token/README.md b/jfrog-token/README.md index 652451f6..146dc7f7 100644 --- a/jfrog-token/README.md +++ b/jfrog-token/README.md @@ -15,7 +15,7 @@ Install the JF CLI and authenticate package managers with Artifactory using Arti ```tf module "jfrog" { source = "registry.coder.com/modules/jfrog-token/coder" - version = "2.0.0" + version = "1.0.19" agent_id = coder_agent.example.id jfrog_url = "https://XXXX.jfrog.io" artifactory_access_token = var.artifactory_access_token @@ -42,7 +42,7 @@ For detailed instructions, please see this [guide](https://coder.com/docs/v2/lat ```tf module "jfrog" { source = "registry.coder.com/modules/jfrog-token/coder" - version = "2.0.0" + version = "1.0.19" agent_id = coder_agent.example.id jfrog_url = "https://YYYY.jfrog.io" artifactory_access_token = var.artifactory_access_token # An admin access token @@ -75,7 +75,7 @@ The [JFrog extension](https://open-vsx.org/extension/JFrog/jfrog-vscode-extensio ```tf module "jfrog" { source = "registry.coder.com/modules/jfrog-token/coder" - version = "2.0.0" + version = "1.0.19" agent_id = coder_agent.example.id jfrog_url = "https://XXXX.jfrog.io" artifactory_access_token = var.artifactory_access_token @@ -95,7 +95,7 @@ data "coder_workspace" "me" {} module "jfrog" { source = "registry.coder.com/modules/jfrog-token/coder" - version = "2.0.0" + version = "1.0.19" agent_id = coder_agent.example.id jfrog_url = "https://XXXX.jfrog.io" artifactory_access_token = var.artifactory_access_token diff --git a/jfrog-token/main.test.ts b/jfrog-token/main.test.ts index af367108..799d2bd2 100644 --- a/jfrog-token/main.test.ts +++ b/jfrog-token/main.test.ts @@ -7,8 +7,24 @@ import { runTerraformApply, testRequiredVariables, } from "../test"; +import { Test } from "test"; describe("jfrog-token", async () => { + type TestVariables = { + agent_id: string; + jfrog_url: string; + artifactory_access_token: string; + package_managers: string; + + token_description?: string; + check_license?: boolean; + refreshable?: boolean; + expires_in?: number; + username_field?: string; + jfrog_server_id?: string; + configure_code_server?: boolean; + }; + await runTerraformInit(import.meta.dir); // Run a fake JFrog server so the provider can initialize @@ -34,11 +50,13 @@ describe("jfrog-token", async () => { port: 0, }); - const fakeFrogHostAndPort = `${fakeFrogHost.hostname}:${fakeFrogHost.port}`; - const fakeFrogUrl = `http://${fakeFrogHostAndPort}`; + const fakeFrogApi = `${fakeFrogHost.hostname}:${fakeFrogHost.port}/artifactory/api`; + const fakeFrogUrl = `http://${fakeFrogHost.hostname}:${fakeFrogHost.port}`; + const user = "default"; + const token = "xxx"; it("can run apply with required variables", async () => { - testRequiredVariables(import.meta.dir, { + testRequiredVariables(import.meta.dir, { agent_id: "some-agent-id", jfrog_url: fakeFrogUrl, artifactory_access_token: "XXXX", @@ -47,7 +65,7 @@ describe("jfrog-token", async () => { }); it("generates an npmrc with scoped repos", async () => { - const state = await runTerraformApply(import.meta.dir, { + const state = await runTerraformApply(import.meta.dir, { agent_id: "some-agent-id", jfrog_url: fakeFrogUrl, artifactory_access_token: "XXXX", @@ -57,13 +75,13 @@ describe("jfrog-token", async () => { }); const coderScript = findResourceInstance(state, "coder_script"); const npmrcStanza = `cat << EOF > ~/.npmrc -email=default@example.com -registry=${fakeFrogUrl}/artifactory/api/npm/global -//${fakeFrogHostAndPort}/artifactory/api/npm/global/:_authToken=xxx -@foo:registry=${fakeFrogUrl}/artifactory/api/npm/foo -//${fakeFrogHostAndPort}/artifactory/api/npm/foo/:_authToken=xxx -@bar:registry=${fakeFrogUrl}/artifactory/api/npm/bar -//${fakeFrogHostAndPort}/artifactory/api/npm/bar/:_authToken=xxx +email=${user}@example.com +registry=http://${fakeFrogApi}/npm/global +//${fakeFrogApi}/npm/global/:_authToken=xxx +@foo:registry=http://${fakeFrogApi}/npm/foo +//${fakeFrogApi}/npm/foo/:_authToken=xxx +@bar:registry=http://${fakeFrogApi}/npm/bar +//${fakeFrogApi}/npm/bar/:_authToken=xxx EOF`; expect(coderScript.script).toContain(npmrcStanza); @@ -76,7 +94,7 @@ EOF`; }); it("generates a pip config with extra-indexes", async () => { - const state = await runTerraformApply(import.meta.dir, { + const state = await runTerraformApply(import.meta.dir, { agent_id: "some-agent-id", jfrog_url: fakeFrogUrl, artifactory_access_token: "XXXX", @@ -87,10 +105,10 @@ EOF`; const coderScript = findResourceInstance(state, "coder_script"); const pipStanza = `cat << EOF > ~/.pip/pip.conf [global] -index-url = https://default:xxx@${fakeFrogHostAndPort}/artifactory/api/pypi/global/simple +index-url = https://${user}:${token}@${fakeFrogApi}/pypi/global/simple extra-index-url = - https://default:xxx@${fakeFrogHostAndPort}/artifactory/api/pypi/foo/simple - https://default:xxx@${fakeFrogHostAndPort}/artifactory/api/pypi/bar/simple + https://${user}:${token}@${fakeFrogApi}/pypi/foo/simple + https://${user}:${token}@${fakeFrogApi}/pypi/bar/simple EOF`; expect(coderScript.script).toContain(pipStanza); @@ -103,7 +121,7 @@ EOF`; }); it("registers multiple docker repos", async () => { - const state = await runTerraformApply(import.meta.dir, { + const state = await runTerraformApply(import.meta.dir, { agent_id: "some-agent-id", jfrog_url: fakeFrogUrl, artifactory_access_token: "XXXX", @@ -112,9 +130,9 @@ EOF`; }), }); const coderScript = findResourceInstance(state, "coder_script"); - const dockerStanza = `register_docker "foo.jfrog.io" -register_docker "bar.jfrog.io" -register_docker "baz.jfrog.io"`; + const dockerStanza = ["foo", "bar", "baz"] + .map((r) => `register_docker "${r}.jfrog.io"`) + .join("\n"); expect(coderScript.script).toContain(dockerStanza); expect(coderScript.script).toContain( 'if [ -z "YES" ]; then\n not_configured docker', @@ -122,7 +140,7 @@ register_docker "baz.jfrog.io"`; }); it("sets goproxy with multiple repos", async () => { - const state = await runTerraformApply(import.meta.dir, { + const state = await runTerraformApply(import.meta.dir, { agent_id: "some-agent-id", jfrog_url: fakeFrogUrl, artifactory_access_token: "XXXX", @@ -131,7 +149,9 @@ register_docker "baz.jfrog.io"`; }), }); const proxyEnv = findResourceInstance(state, "coder_env", "goproxy"); - const proxies = `https://default:xxx@${fakeFrogHostAndPort}/artifactory/api/go/foo,https://default:xxx@${fakeFrogHostAndPort}/artifactory/api/go/bar,https://default:xxx@${fakeFrogHostAndPort}/artifactory/api/go/baz`; + const proxies = ["foo", "bar", "baz"] + .map((r) => `https://${user}:${token}@${fakeFrogApi}/go/${r}`) + .join(","); expect(proxyEnv["value"]).toEqual(proxies); const coderScript = findResourceInstance(state, "coder_script"); diff --git a/terraform_validate.sh b/terraform_validate.sh index 292c94c7..492e65ae 100755 --- a/terraform_validate.sh +++ b/terraform_validate.sh @@ -4,25 +4,25 @@ set -euo pipefail # Function to run terraform init and validate in a directory run_terraform() { - local dir="$1" - echo "Running terraform init and validate in $dir" - pushd "$dir" - terraform init -upgrade - terraform validate - popd + local dir="$1" + echo "Running terraform init and validate in $dir" + pushd "$dir" + terraform init -upgrade + terraform validate + popd } # Main script main() { - # Get the directory of the script - script_dir=$(dirname "$(readlink -f "$0")") + # Get the directory of the script + script_dir=$(dirname "$(readlink -f "$0")") - # Get all subdirectories in the repository - subdirs=$(find "$script_dir" -mindepth 1 -maxdepth 1 -type d -not -name ".*" | sort) + # Get all subdirectories in the repository + subdirs=$(find "$script_dir" -mindepth 1 -maxdepth 1 -type d -not -name ".*" | sort) - for dir in $subdirs; do - run_terraform "$dir" - done + for dir in $subdirs; do + run_terraform "$dir" + done } # Run the main script diff --git a/test.ts b/test.ts index 6bdf9d91..dd1b1c68 100644 --- a/test.ts +++ b/test.ts @@ -108,6 +108,8 @@ export interface TerraformState { resources: [TerraformStateResource, ...TerraformStateResource[]]; } +type TerraformVariables = Record; + export interface CoderScriptAttributes { script: string; agent_id: string; @@ -145,9 +147,9 @@ export const findResourceInstance = ( * Creates a test-case for each variable provided and ensures that the apply * fails without it. */ -export const testRequiredVariables = >( +export const testRequiredVariables = ( dir: string, - vars: TVars, + vars: Readonly, ) => { // Ensures that all required variables are provided. it("required variables", async () => { @@ -158,7 +160,7 @@ export const testRequiredVariables = >( varNames.forEach((varName) => { // Ensures that every variable provided is required! it("missing variable " + varName, async () => { - const localVars: Record = {}; + const localVars: TerraformVariables = {}; varNames.forEach((otherVarName) => { if (otherVarName !== varName) { localVars[otherVarName] = vars[otherVarName]; @@ -187,11 +189,9 @@ export const testRequiredVariables = >( * fine to run in parallel with other instances of this function, as it uses a * random state file. */ -export const runTerraformApply = async < - TVars extends Readonly>, ->( +export const runTerraformApply = async ( dir: string, - vars: TVars, + vars: Readonly, env?: Record, ): Promise => { const stateFile = `${dir}/${crypto.randomUUID()}.tfstate`; From 149cb2f3b2348b3c36c3de9785fcc0ea2d07ef28 Mon Sep 17 00:00:00 2001 From: bsouza Date: Fri, 20 Sep 2024 21:34:47 +0000 Subject: [PATCH 9/9] Remove accidental import --- jfrog-token/main.test.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/jfrog-token/main.test.ts b/jfrog-token/main.test.ts index 799d2bd2..a6fe6bcb 100644 --- a/jfrog-token/main.test.ts +++ b/jfrog-token/main.test.ts @@ -7,7 +7,6 @@ import { runTerraformApply, testRequiredVariables, } from "../test"; -import { Test } from "test"; describe("jfrog-token", async () => { type TestVariables = {