Skip to content

Commit 9f988bd

Browse files
bharathkkbnilcolor
andauthored
feat: add function labels support (#60) (#62)
* feat: add function labels support (#60) * feat: add function labels support * fix: apply changes based on code review * Document label input in readme Co-authored-by: Alexey Blinov <nilcolor@gmail.com>
1 parent 48ee7cd commit 9f988bd

File tree

6 files changed

+66
-19
lines changed

6 files changed

+66
-19
lines changed

README.md

+2
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,8 @@ steps:
6767

6868
- `env_vars_file`: (Optional) Path to a local YAML file with definitions for all environment variables. An example env_vars_file can be found [here](tests/env-var-files/test.good.yaml). Only one of env_vars or env_vars_file can be specified.
6969

70+
- `labels`: (Optional) List of key-value pairs to set as function labels in the form label1=VALUE1,label2=VALUE2.
71+
7072
- `source_dir`: (Optional) Source directory for the function. Defaults to current directory.
7173

7274
- `project_id`: (Optional) ID of the Google Cloud project. If provided, this

action.yaml

+8-3
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ inputs:
2525
formatted private key which can be exported from the Cloud Console. The
2626
value can be raw or base64-encoded.
2727
required: false
28-
28+
2929
name:
3030
description: |-
3131
Name of the Cloud Function.
@@ -55,15 +55,20 @@ inputs:
5555
description: |-
5656
List of key-value pairs to set as environment variables in the form KEY1=VALUE1,KEY2=VALUE2. Only one of env_vars or env_vars_file can be specified.
5757
required: false
58-
58+
5959
env_vars_file:
6060
description: |-
6161
Path to a local YAML file with definitions for all environment variables. Only one of env_vars or env_vars_file can be specified.
6262
required: false
6363

64+
labels:
65+
description: |-
66+
List of key-value pairs to set as function labels in the form label1=VALUE1,label2=VALUE2.
67+
required: false
68+
6469
entry_point:
6570
description: |-
66-
Name of a function (as defined in source code) that will be executed. Defaults to the resource name suffix, if not specified.
71+
Name of a function (as defined in source code) that will be executed. Defaults to the resource name suffix, if not specified.
6772
required: false
6873

6974
runtime:

src/cloudFunction.ts

+21-15
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ import { cloudfunctions_v1 } from 'googleapis';
1818
import fs from 'fs';
1919
import YAML from 'yaml';
2020

21-
export type EnvVar = {
21+
export type KVPair = {
2222
[key: string]: string;
2323
};
2424

@@ -40,6 +40,7 @@ export type EnvVar = {
4040
* @param eventTriggerType Specifies which action should trigger the function.
4141
* @param eventTriggerResource Specifies which resource from eventTrigger is observed.
4242
* @param eventTriggerService The hostname of the service that should be observed.
43+
* @param labels List of key-value pairs to set as function labels.
4344
*/
4445

4546
export type CloudFunctionOptions = {
@@ -59,6 +60,7 @@ export type CloudFunctionOptions = {
5960
eventTriggerType?: string;
6061
eventTriggerResource?: string;
6162
eventTriggerService?: string;
63+
labels?: string;
6264
};
6365

6466
/**
@@ -121,14 +123,18 @@ export class CloudFunction {
121123
// Parse env vars
122124
let envVars;
123125
if (opts?.envVars) {
124-
envVars = this.parseEnvVars(opts.envVars);
126+
envVars = this.parseKVPairs(opts.envVars);
125127
request.environmentVariables = envVars;
126128
}
127129
if (opts?.envVarsFile) {
128130
envVars = this.parseEnvVarsFile(opts.envVarsFile);
129131
request.environmentVariables = envVars;
130132
}
131133

134+
if (opts?.labels) {
135+
request.labels = this.parseKVPairs(opts.labels);
136+
}
137+
132138
this.request = request;
133139
this.name = opts.name;
134140
this.sourceDir = opts.sourceDir ? opts.sourceDir : './';
@@ -144,24 +150,24 @@ export class CloudFunction {
144150
}
145151

146152
/**
147-
* Parses a string of the format `KEY1=VALUE1`.
153+
* Parses a string of the format `KEY1=VALUE1,KEY2=VALUE2`.
148154
*
149-
* @param envVarInput Env var string to parse.
155+
* @param values String with key/value pairs to parse.
150156
* @returns map of type {KEY1:VALUE1}
151157
*/
152-
protected parseEnvVars(envVarInput: string): EnvVar {
153-
const envVarList = envVarInput.split(',');
154-
const envVars: EnvVar = {};
155-
envVarList.forEach((envVar) => {
156-
if (!envVar.includes('=')) {
158+
protected parseKVPairs(values: string): KVPair {
159+
const valuePairs = values.split(',');
160+
const kvPairs: KVPair = {};
161+
valuePairs.forEach((pair) => {
162+
if (!pair.includes('=')) {
157163
throw new TypeError(
158-
`Env Vars must be in "KEY1=VALUE1,KEY2=VALUE2" format, received ${envVar}`,
164+
`The expected data format should be "KEY1=VALUE1", got "${pair}" while parsing "${values}"`,
159165
);
160166
}
161-
const keyValue = envVar.split('=');
162-
envVars[keyValue[0]] = keyValue[1];
167+
const keyValue = pair.split('=');
168+
kvPairs[keyValue[0]] = keyValue[1];
163169
});
164-
return envVars;
170+
return kvPairs;
165171
}
166172

167173
/**
@@ -170,9 +176,9 @@ export class CloudFunction {
170176
* @param envVarsFile env var file path.
171177
* @returns map of type {KEY1:VALUE1}
172178
*/
173-
protected parseEnvVarsFile(envVarFilePath: string): EnvVar {
179+
protected parseEnvVarsFile(envVarFilePath: string): KVPair {
174180
const content = fs.readFileSync(envVarFilePath, 'utf-8');
175-
const yamlContent = YAML.parse(content) as EnvVar;
181+
const yamlContent = YAML.parse(content) as KVPair;
176182
for (const [key, val] of Object.entries(yamlContent)) {
177183
if (typeof key !== 'string' || typeof val !== 'string') {
178184
throw new Error(

src/cloudFunctionClient.ts

+1
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,7 @@ export class CloudFunctionClient {
238238
'eventTrigger.eventType',
239239
'eventTrigger.resource',
240240
'eventTrigger.service',
241+
'labels',
241242
];
242243
const updateFunctionRequest: cloudfunctions_v1.Params$Resource$Projects$Locations$Functions$Patch = {
243244
updateMask: updateMasks.join(','),

src/main.ts

+2
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ async function run(): Promise<void> {
3838
const eventTriggerType = core.getInput('event_trigger_type');
3939
const eventTriggerResource = core.getInput('event_trigger_resource');
4040
const eventTriggerService = core.getInput('event_trigger_service');
41+
const labels = core.getInput('labels');
4142

4243
// Create Cloud Functions client
4344
const client = new CloudFunctionClient(region, { projectId, credentials });
@@ -59,6 +60,7 @@ async function run(): Promise<void> {
5960
eventTriggerService,
6061
vpcConnector,
6162
serviceAccountEmail,
63+
labels,
6264
});
6365

6466
// Deploy function

tests/cloudFunction.test.ts

+32-1
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,28 @@ describe('CloudFunction', function () {
2525
expect(cf.request.environmentVariables?.KEY1).equal('VALUE1');
2626
});
2727

28+
it('creates an http function with one label', function () {
29+
const labels = 'label1=value1';
30+
const cf = new CloudFunction({ name, runtime, parent, labels });
31+
expect(cf.request.name).equal(`${parent}/functions/${name}`);
32+
expect(cf.request.runtime).equal(runtime);
33+
expect(cf.request.httpsTrigger).not.to.be.null;
34+
expect(cf.request.labels?.label1).equal('value1');
35+
});
36+
37+
it('creates an http function with two labels', function () {
38+
const labels = 'label1=value1,label2=value2';
39+
const cf = new CloudFunction({ name, runtime, parent, labels });
40+
expect(cf.request.name).equal(`${parent}/functions/${name}`);
41+
expect(cf.request.runtime).equal(runtime);
42+
expect(cf.request.httpsTrigger).not.to.be.null;
43+
expect(cf.request.labels?.label1).equal('value1');
44+
expect(cf.request.labels?.label2).equal('value2');
45+
});
46+
2847
it('creates a http function with optionals', function () {
2948
const envVars = 'KEY1=VALUE1';
49+
const labels = 'label1=value1';
3050
const funcOptions = {
3151
name: name,
3252
description: 'foo',
@@ -40,6 +60,7 @@ describe('CloudFunction', function () {
4060
timeout: '500',
4161
maxInstances: 10,
4262
availableMemoryMb: 512,
63+
labels: labels,
4364
};
4465
const cf = new CloudFunction(funcOptions);
4566
expect(cf.request.name).equal(`${parent}/functions/${name}`);
@@ -56,6 +77,7 @@ describe('CloudFunction', function () {
5677
expect(cf.request.availableMemoryMb).equal(funcOptions.availableMemoryMb);
5778
expect(cf.request.httpsTrigger).not.to.be.null;
5879
expect(cf.request.environmentVariables?.KEY1).equal('VALUE1');
80+
expect(cf.request.labels?.label1).equal('value1');
5981
});
6082

6183
it('creates a http function with three envVars', function () {
@@ -74,7 +96,16 @@ describe('CloudFunction', function () {
7496
expect(function () {
7597
new CloudFunction({ name, runtime, parent, envVars });
7698
}).to.throw(
77-
'Env Vars must be in "KEY1=VALUE1,KEY2=VALUE2" format, received KEY1',
99+
'The expected data format should be "KEY1=VALUE1", got "KEY1" while parsing "KEY1,VALUE1"',
100+
);
101+
});
102+
103+
it('throws an error with bad labels', function () {
104+
const envVars = 'label1=value1,label2';
105+
expect(function () {
106+
new CloudFunction({ name, runtime, parent, envVars });
107+
}).to.throw(
108+
'The expected data format should be "KEY1=VALUE1", got "label2" while parsing "label1=value1,label2"',
78109
);
79110
});
80111

0 commit comments

Comments
 (0)