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
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import { validateWorkflowStructure } from '../validation';

const workflowSchema = {
type: 'object',
properties: {
jobs: {
type: 'object',
additionalProperties: {
anyOf: [
{
type: 'object',
properties: {
type: { type: 'string', const: 'slack' },
params: {
type: 'object',
properties: {
webhook_url: { type: 'string', format: 'uri' },
message: { type: 'string' },
},
required: ['webhook_url', 'message'],
additionalProperties: false,
},
},
required: ['type', 'params'],
additionalProperties: false,
},
],
},
},
},
required: ['jobs'],
additionalProperties: false,
};

const workflowWithWebhookUrl = (webhookUrl: string): object => ({
jobs: {
notify: {
type: 'slack',
params: {
webhook_url: webhookUrl,
message: 'Build finished',
},
},
},
});

describe(validateWorkflowStructure, () => {
it('allows interpolated values for URI fields', () => {
expect(() => {
validateWorkflowStructure(
workflowWithWebhookUrl('${{ env.SLACK_WEBHOOK_URL }}'),
workflowSchema
);
}).not.toThrow();
});

it('still rejects invalid literal values for URI fields', () => {
expect(() => {
validateWorkflowStructure(workflowWithWebhookUrl('not a URL'), workflowSchema);
}).toThrow('must be a valid URI string');
});
});
12 changes: 8 additions & 4 deletions packages/eas-cli/src/commandUtils/workflow/validation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { InvalidEasJsonError, MissingEasJsonError } from '@expo/eas-json/build/e
import { CombinedError } from '@urql/core';
import { promises as fs } from 'fs';
import path from 'path';
import addFormats from 'ajv-formats';
import * as YAML from 'yaml';

import { validateWorkflowLocalCompositeFunctionsAsync } from './compositeFunctions';
Expand All @@ -15,9 +16,10 @@ import { ExpoGraphqlClient } from '../context/contextUtils/createGraphqlClient';
import { parsedYamlFromWorkflowContents } from './parse';

const jobTypesWithBuildProfile = new Set(['build', 'repack']);
const validateUri = addFormats.get('uri') as (value: string) => boolean;

const buildProfileIsInterpolated = (profileName: string): boolean => {
return profileName.includes('${{') && profileName.includes('}}');
const stringIsInterpolated = (value: string): boolean => {
return value.includes('${{') && value.includes('}}');
};

export async function validateWorkflowFileAsync(
Expand Down Expand Up @@ -113,7 +115,7 @@ async function validateWorkflowBuildJobsAsync(parsedYaml: any, projectDir: strin
job =>
!buildProfileNames.has(job.value.params.profile) &&
// If a profile name is interpolated, we can't check if it's valid until the workflow actually runs
!buildProfileIsInterpolated(job.value.params.profile)
!stringIsInterpolated(job.value.params.profile)
);

if (invalidBuildJobs.length > 0) {
Expand All @@ -139,10 +141,12 @@ function validateWorkflowJobTypes(parsedYaml: any, workflowJsonSchema: any): voi
}
}

function validateWorkflowStructure(parsedYaml: any, workflowJsonSchema: any): void {
export function validateWorkflowStructure(parsedYaml: any, workflowJsonSchema: any): void {
delete workflowJsonSchema['$schema'];

const ajv = createValidator();
// Interpolated values cannot be format-checked until the workflow runs.
ajv.addFormat('uri', value => stringIsInterpolated(value) || validateUri(value));
const validate = ajv.compile(workflowJsonSchema);
const result = validate(parsedYaml);

Expand Down
Loading