From 85f5e350c104582a36945a4b66abdd29b42123bf Mon Sep 17 00:00:00 2001 From: Gabriel Fontes Date: Thu, 14 Oct 2021 15:13:09 -0300 Subject: [PATCH] feat: add environment-variables support (#114) * feat: support for setting environment variables * chore: Update dist Co-authored-by: GitHub Actions --- README.md | 4 ++++ action.yml | 3 +++ dist/index.js | 40 ++++++++++++++++++++++++++++++++++++++++ index.js | 40 ++++++++++++++++++++++++++++++++++++++++ index.test.js | 44 ++++++++++++++++++++++++++++++++++++++------ 5 files changed, 125 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 1cf738a8..d955608d 100644 --- a/README.md +++ b/README.md @@ -24,6 +24,7 @@ To insert the image URI `amazon/amazon-ecs-sample:latest` as the image for the ` task-definition: task-definition.json container-name: web image: amazon/amazon-ecs-sample:latest + environment-variables: "LOG_LEVEL=info" - name: Deploy to Amazon ECS service uses: aws-actions/amazon-ecs-deploy-task-definition@v1 @@ -46,6 +47,9 @@ input of the second: task-definition: task-definition.json container-name: web image: amazon/amazon-ecs-sample-1:latest + environment-variables: | + LOG_LEVEL=info + ENVIRONMENT=prod - name: Modify Amazon ECS task definition with second container id: render-app-container diff --git a/action.yml b/action.yml index 5f6ae11a..5fe875ca 100644 --- a/action.yml +++ b/action.yml @@ -13,6 +13,9 @@ inputs: image: description: 'The URI of the container image to insert into the ECS task definition' required: true + environment-variables: + description: 'Variables to add to the container. Each variable is of the form KEY=value, you can specify multiple variables with multi-line YAML strings.' + required: false outputs: task-definition: description: 'The path to the rendered task definition file' diff --git a/dist/index.js b/dist/index.js index 2402db8d..ddd1020b 100644 --- a/dist/index.js +++ b/dist/index.js @@ -1193,6 +1193,8 @@ async function run() { const containerName = core.getInput('container-name', { required: true }); const imageURI = core.getInput('image', { required: true }); + const environmentVariables = core.getInput('environment-variables', { required: false }); + // Parse the task definition const taskDefPath = path.isAbsolute(taskDefinitionFile) ? taskDefinitionFile : @@ -1214,6 +1216,44 @@ async function run() { } containerDef.image = imageURI; + if (environmentVariables) { + + // If environment array is missing, create it + if (!Array.isArray(containerDef.environment)) { + containerDef.environment = []; + } + + // Get pairs by splitting on newlines + environmentVariables.split('\n').forEach(function (line) { + // Trim whitespace + const trimmedLine = line.trim(); + // Skip if empty + if (trimmedLine.length === 0) { return; } + // Split on = + const separatorIdx = trimmedLine.indexOf("="); + // If there's nowhere to split + if (separatorIdx === -1) { + throw new Error(`Cannot parse the environment variable '${trimmedLine}'. Environment variable pairs must be of the form NAME=value.`); + } + // Build object + const variable = { + name: trimmedLine.substring(0, separatorIdx), + value: trimmedLine.substring(separatorIdx + 1), + }; + + // Search container definition environment for one matching name + const variableDef = containerDef.environment.find((e) => e.name == variable.name); + if (variableDef) { + // If found, update + variableDef.value = variable.value; + } else { + // Else, create + containerDef.environment.push(variable); + } + }) + } + + // Write out a new task definition file var updatedTaskDefFile = tmp.fileSync({ tmpdir: process.env.RUNNER_TEMP, diff --git a/index.js b/index.js index ec9b78c8..99bb717d 100644 --- a/index.js +++ b/index.js @@ -10,6 +10,8 @@ async function run() { const containerName = core.getInput('container-name', { required: true }); const imageURI = core.getInput('image', { required: true }); + const environmentVariables = core.getInput('environment-variables', { required: false }); + // Parse the task definition const taskDefPath = path.isAbsolute(taskDefinitionFile) ? taskDefinitionFile : @@ -31,6 +33,44 @@ async function run() { } containerDef.image = imageURI; + if (environmentVariables) { + + // If environment array is missing, create it + if (!Array.isArray(containerDef.environment)) { + containerDef.environment = []; + } + + // Get pairs by splitting on newlines + environmentVariables.split('\n').forEach(function (line) { + // Trim whitespace + const trimmedLine = line.trim(); + // Skip if empty + if (trimmedLine.length === 0) { return; } + // Split on = + const separatorIdx = trimmedLine.indexOf("="); + // If there's nowhere to split + if (separatorIdx === -1) { + throw new Error(`Cannot parse the environment variable '${trimmedLine}'. Environment variable pairs must be of the form NAME=value.`); + } + // Build object + const variable = { + name: trimmedLine.substring(0, separatorIdx), + value: trimmedLine.substring(separatorIdx + 1), + }; + + // Search container definition environment for one matching name + const variableDef = containerDef.environment.find((e) => e.name == variable.name); + if (variableDef) { + // If found, update + variableDef.value = variable.value; + } else { + // Else, create + containerDef.environment.push(variable); + } + }) + } + + // Write out a new task definition file var updatedTaskDefFile = tmp.fileSync({ tmpdir: process.env.RUNNER_TEMP, diff --git a/index.test.js b/index.test.js index 379d5706..a1f89ffe 100644 --- a/index.test.js +++ b/index.test.js @@ -16,7 +16,8 @@ describe('Render task definition', () => { .fn() .mockReturnValueOnce('task-definition.json') // task-definition .mockReturnValueOnce('web') // container-name - .mockReturnValueOnce('nginx:latest'); // image + .mockReturnValueOnce('nginx:latest') // image + .mockReturnValueOnce('FOO=bar\nHELLO=world'); // environment-variables process.env = Object.assign(process.env, { GITHUB_WORKSPACE: __dirname }); process.env = Object.assign(process.env, { RUNNER_TEMP: '/home/runner/work/_temp' }); @@ -32,7 +33,17 @@ describe('Render task definition', () => { containerDefinitions: [ { name: "web", - image: "some-other-image" + image: "some-other-image", + environment: [ + { + name: "FOO", + value: "not bar" + }, + { + name: "DONT-TOUCH", + value: "me" + } + ] }, { name: "sidecar", @@ -57,7 +68,21 @@ describe('Render task definition', () => { containerDefinitions: [ { name: "web", - image: "nginx:latest" + image: "nginx:latest", + environment: [ + { + name: "FOO", + value: "bar" + }, + { + name: "DONT-TOUCH", + value: "me" + }, + { + name: "HELLO", + value: "world" + } + ] }, { name: "sidecar", @@ -69,12 +94,13 @@ describe('Render task definition', () => { expect(core.setOutput).toHaveBeenNthCalledWith(1, 'task-definition', 'new-task-def-file-name'); }); - test('renders a task definition at an absolute path', async () => { + test('renders a task definition at an absolute path, and with initial environment empty', async () => { core.getInput = jest .fn() .mockReturnValueOnce('/hello/task-definition.json') // task-definition .mockReturnValueOnce('web') // container-name - .mockReturnValueOnce('nginx:latest'); // image + .mockReturnValueOnce('nginx:latest') // image + .mockReturnValueOnce('EXAMPLE=here'); // environment-variables jest.mock('/hello/task-definition.json', () => ({ family: 'task-def-family', containerDefinitions: [ @@ -100,7 +126,13 @@ describe('Render task definition', () => { containerDefinitions: [ { name: "web", - image: "nginx:latest" + image: "nginx:latest", + environment: [ + { + name: "EXAMPLE", + value: "here" + } + ] } ] }, null, 2)