Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support file path in job body #742

Merged
merged 6 commits into from
Aug 14, 2024
Merged

Support file path in job body #742

merged 6 commits into from
Aug 14, 2024

Conversation

midigofrank
Copy link
Contributor

@midigofrank midigofrank commented Aug 9, 2024

Short Description

Support file paths in job body

Related issue

Fixes #285

Implementation Details

When the path is present in the body, we load the file's content into another key content. So essentially, it becomes:
{ path: './bodyPath.js', content: 'content fron bodyPath.js' }

The YAML.vistor function does all the magic here.
While traversing the nodes, we check if the current node is the job body. We know that it's the job body by moving up the path tree until we find a node with the key jobs. Here's how the path tree looks like:

[
  Document {
    ....
    contents: YAMLMap { items: [Array], range: [Array] },
    range: [ 0, 972, 972 ]
  },
  YAMLMap { items: [ [Pair], [Pair] ], range: [ 0, 972, 972 ] },
  Pair {
    key: Scalar {
      value: 'workflows',
      ...
    },
    value: YAMLMap { items: [Array], range: [Array] }
  },
  YAMLMap { items: [ [Pair] ], range: [ 74, 972, 972 ] },
  Pair {
    key: Scalar {
      value: 'DHIS2-to-Sheets',
      ...
    },
    value: YAMLMap { items: [Array], range: [Array] }
  },
  YAMLMap {
    items: [ [Pair], [Pair], [Pair], [Pair] ],
    range: [ 95, 972, 972 ]
  },
  Pair {
    key: Scalar {
      value: 'jobs',
      ...
    },
    value: YAMLMap { items: [Array], range: [Array] }
  },
  YAMLMap { items: [ [Pair], [Pair] ], range: [ 133, 526, 526 ] },
  Pair {
    key: Scalar {
      value: 'Upload-to-Google-Sheet',
      ...
    },
    value: YAMLMap { items: [Array], range: [Array] }
  },
  YAMLMap {
    items: [ [Pair], [Pair], [Pair] ],
    range: [ 363, 526, 526 ]
  }
]

When you pull, we merge the StateJob.id into the SpecJob.id of the current state and spec in place. We then keep track of all the jobs in a single place. The id here is guaranteed to be unique.
These "old spec jobs" are what we use to match the "new spec job".

QA Notes

List any considerations/cases/advice for testing/QA here.

Checklist before requesting a review

  • I have performed a self-review of my code
  • I have added unit tests
  • Changesets have been added (if there are production code changes)

@midigofrank midigofrank self-assigned this Aug 9, 2024
Copy link
Member

@taylordowns2000 taylordowns2000 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looks great @midigofrank , can you:

  1. update test/fixtures.ts to include relative paths? (and ensure the tests work properly)
  2. edit https://github.com/OpenFn/docs/blob/main/docs/deploy/portability.md?plain=1#L31 to show the new format?

don't worry about shifting the current spec to "old versions"—i'll clean that up myself once your PR is open on docs

@midigofrank
Copy link
Contributor Author

looks great @midigofrank , can you:

  1. update test/fixtures.ts to include relative paths? (and ensure the tests work properly)
  2. edit https://github.com/OpenFn/docs/blob/main/docs/deploy/portability.md?plain=1#L31 to show the new format?

don't worry about shifting the current spec to "old versions"—i'll clean that up myself once your PR is open on docs

@taylordowns2000 the test/fixtures.ts are only used in testing the stateTransform functionality. State transform happens waay after the relative paths have been used to load the body.

What I can test however is that if the body is in the form:

body: 
  content: "some content"

Then the tests would still pass

Copy link
Collaborator

@josephjclark josephjclark left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @midigofrank, sorry I've been so late getting back to you on this. A few comments from me!

I'm getting more and more worried about complexity in deploy. If we have time I'd love to see some fresh unit tests on the new functions.

'@openfn/deploy': minor
---

Support file paths for job body
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we have a slightly more user friendly release note for the CLI? Just needs a bit more context. Deploy: allow job body to be loaded from a file path in workflow.yaml would probably do

path.resolve(config.statePath),
JSON.stringify(state, null, 2)
);
// defer writing to disk until we have the spec
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need for this comment to stay in the source, it's a bit confusing without the diff tbh

@@ -91,7 +91,7 @@ function writeState(config: DeployConfig, nextState: {}): Promise<void> {
export async function getSpec(path: string) {
try {
const body = await readFile(path, 'utf8');
return parseAndValidate(body);
return await parseAndValidate(body, path);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't return and await please!

An async function returns a promise, so you can just return the parseAndValidate promise straight out of the function

const jobs: SpecJob[] = [];

try {
const [state, spec] = await Promise.all([
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You don't think this is cleaner?

const state = await  getState(config.statePath)
const spec = await getSpec(config.specPath)

Up to you!

import path from 'path';

// Helper to create and clean up temporary test files
const createTempFile = async (t, content: string, ext = 'txt') => {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hmm. There is a very clean file system mock in use in this repo which would make these tests a lot nicer IMO.

We use mock-fs

It can get a bit hairy when it blocks out node modules, but that can be worked around. See the mockFs helper in cli/test/util.ts (you can't import that into deploy but feel free to duplicate it )

There's some simple example usage in runtime/test/repo/ensure-repo.test.ts

Not neccessary if you're struggling for time, but strongly recommended

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Niice, I'll change it

export function parseAndValidate(input: string): {
export async function parseAndValidate(
input: string,
specPath: string
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you should default specPath to '.' - that way you don't break unit tests which don't use it

return jobs;
}

export async function updatePulledSpecJobBodyPath(
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can I ask for a better function name here? And maybe on addSpecJobBodyPath ?

This is really complex stuff and it's taken me ages to get any kind of feeling for what's happening here 😅

Basically what these functions are doing is pulling out job bodies from the newly pulled spec and writing them to disk if the state (?) includes a path. Right?

So something like extractJobsToDisk might be a better name for addSpecJobBodyPath

Probably updatePulledSpecJobBodyPath should be moved to a new file packages/deploy/src/pull.ts, since it only affects pulls the context helps understandability. A name like syncRemoteSpec or something might be a good general name for what this is trying to do

@stuartc stuartc merged commit b7fc4d0 into main Aug 14, 2024
6 checks passed
@stuartc stuartc deleted the support-file-path branch August 14, 2024 08:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Status: Done
Development

Successfully merging this pull request may close these issues.

Support paths to job files in project.yaml
4 participants