-
Notifications
You must be signed in to change notification settings - Fork 327
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
Implementing reading Data Links #9215
Merged
Merged
Changes from all commits
Commits
Show all changes
50 commits
Select commit
Hold shift + click to select a range
be298ff
initial data link structure
radeusgd 9fa95e9
fix imports
radeusgd c62de9d
update schema
radeusgd 9d70e63
remove version for now
radeusgd f65e8d0
basic infra for datalinks + S3 - draft
radeusgd 2e99238
parsing the data link
radeusgd f0f9eb5
imports
radeusgd d2cf16f
first tests
radeusgd 9f0f5b7
recognize `.datalink` filetype
radeusgd 4594c2e
make method static
radeusgd 2d4cd2d
split type name from registered name
radeusgd 7d312c1
more datalinks
radeusgd 628a43a
add stub for testing schema
radeusgd ccf3e75
try actual test
radeusgd 2e28de9
fix regex for S3 paths validity
radeusgd 3d15fa3
incl max S3 key limit
radeusgd 6c68437
remove print no longer necessary
radeusgd 871c884
add tests for other cases
radeusgd 92ea3e6
add example http datalink
radeusgd b070d69
update tests after rebasing on AJV PR
radeusgd bf459f8
add missing type field (AJV was complaining), run prettier on schema
radeusgd 9a8c10d
javafmt
radeusgd 8dba0bc
fix
radeusgd be1931a
allow formats to register if they provide datalink JSON parsing logic…
radeusgd cf3769a
simplify schema
radeusgd 9c78e75
update schema: move libraryName requirement to bottom, add comment
radeusgd 1900f62
add more http datalinks, update tests
radeusgd adfee59
report validation errors in tests more clearly
radeusgd 14512e2
update schema, add negative test
radeusgd fdf1d7a
common test setup
radeusgd fa04a22
implement and test HTTP datalink
radeusgd eeb084b
switch to `from` conversions for parsing the format
radeusgd 792144b
update codeowners
radeusgd 6079937
javafmt
radeusgd 5f0fdcf
fix asset type mapping
radeusgd cd242b5
add test for a datalink
radeusgd 95154fa
implement reading data links from Cloud
radeusgd 0e9cb02
CR: both teams can approve tests changes in datalink schema
radeusgd a42ee1c
CR: move a helper to a better place
radeusgd 81f9e40
changelog
radeusgd cf59f7f
fix import and name
radeusgd b04bbe5
Merge branch 'develop' into wip/radeusgd/9123-first-data-links
radeusgd a08fca2
fixing TS lints
radeusgd 253970f
fix path
radeusgd 36d13e0
fixing lints 2
radeusgd a316ca0
prettier
radeusgd 5bf71b3
Merge branch 'develop' into wip/radeusgd/9123-first-data-links
radeusgd 32a03dc
fix import
radeusgd 21d4471
make dir test more stable to changes of files
radeusgd f958447
Merge branch 'develop' into wip/radeusgd/9123-first-data-links
radeusgd File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
66 changes: 66 additions & 0 deletions
66
app/ide-desktop/lib/dashboard/src/data/__tests__/dataLinkSchema.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
/** @file Tests ensuring consistency of example data-link files with the schema. */ | ||
|
||
import * as fs from 'node:fs' | ||
import * as path from 'node:path' | ||
|
||
import * as v from 'vitest' | ||
|
||
import * as validateDataLink from '#/utilities/validateDataLink' | ||
|
||
v.test('correctly rejects invalid values as not matching the schema', () => { | ||
v.expect(validateDataLink.validateDataLink({})).toBe(false) | ||
v.expect(validateDataLink.validateDataLink('foobar')).toBe(false) | ||
v.expect(validateDataLink.validateDataLink({ foo: 'BAR' })).toBe(false) | ||
}) | ||
|
||
/** Load and parse a data-link description. */ | ||
function loadDataLinkFile(dataLinkPath: string): unknown { | ||
const text: string = fs.readFileSync(dataLinkPath, { encoding: 'utf-8' }) | ||
return JSON.parse(text) | ||
} | ||
|
||
/** Check if the given data-link description matches the schema, reporting any errors. */ | ||
function testSchema(json: unknown, fileName: string): void { | ||
const validate = validateDataLink.validateDataLink | ||
if (!validate(json)) { | ||
v.assert.fail(`Failed to validate ${fileName}:\n${JSON.stringify(validate.errors, null, 2)}`) | ||
} | ||
} | ||
|
||
// We need to go up from `app/ide-desktop/lib/dashboard/` to the root of the repo | ||
const REPO_ROOT = '../../../../' | ||
const BASE_DATA_LINKS_ROOT = path.resolve(REPO_ROOT, 'test/Base_Tests/data/datalinks/') | ||
const S3_DATA_LINKS_ROOT = path.resolve(REPO_ROOT, 'test/AWS_Tests/data/') | ||
|
||
v.test('correctly validates example HTTP .datalink files with the schema', () => { | ||
const schemas = [ | ||
'example-http.datalink', | ||
'example-http-format-explicit-default.datalink', | ||
'example-http-format-delimited.datalink', | ||
'example-http-format-json.datalink', | ||
] | ||
for (const schema of schemas) { | ||
const json = loadDataLinkFile(path.resolve(BASE_DATA_LINKS_ROOT, schema)) | ||
testSchema(json, schema) | ||
} | ||
}) | ||
|
||
v.test('rejects invalid schemas (Base)', () => { | ||
const invalidSchemas = ['example-http-format-invalid.datalink'] | ||
for (const schema of invalidSchemas) { | ||
const json = loadDataLinkFile(path.resolve(BASE_DATA_LINKS_ROOT, schema)) | ||
v.expect(validateDataLink.validateDataLink(json)).toBe(false) | ||
} | ||
}) | ||
|
||
v.test('correctly validates example S3 .datalink files with the schema', () => { | ||
const schemas = [ | ||
'simple.datalink', | ||
'credentials-with-secrets.datalink', | ||
'format-delimited.datalink', | ||
] | ||
for (const schema of schemas) { | ||
const json = loadDataLinkFile(path.resolve(S3_DATA_LINKS_ROOT, schema)) | ||
testSchema(json, schema) | ||
} | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
24 changes: 24 additions & 0 deletions
24
distribution/lib/Standard/AWS/0.0.0-dev/src/Internal/Data_Link_Helpers.enso
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
private | ||
|
||
from Standard.Base import all | ||
import Standard.Base.Errors.Illegal_State.Illegal_State | ||
from Standard.Base.Enso_Cloud.Public_Utils import get_required_field | ||
from Standard.Base.Enso_Cloud.Data_Link import parse_secure_value | ||
|
||
import project.AWS_Credential.AWS_Credential | ||
|
||
## PRIVATE | ||
Decodes the JSON representation of `AWS_Credential` as defined in `dataLinkSchema.json#/$defs/AwsAuth`. | ||
decode_aws_credential json -> AWS_Credential | Nothing = | ||
case get_required_field "type" json of | ||
"aws_auth" -> case get_required_field "subType" json of | ||
"default" -> Nothing | ||
"profile" -> | ||
profile = get_required_field "profile" json | ||
AWS_Credential.Profile profile | ||
"access_key" -> | ||
access_key_id = get_required_field "accessKeyId" json |> parse_secure_value | ||
secret_access_key = get_required_field "secretAccessKey" json |> parse_secure_value | ||
AWS_Credential.Key access_key_id secret_access_key | ||
unexpected -> Error.throw (Illegal_State.Error "Unexpected subType inside of `auth` field of a datalink: "+unexpected.to_text) | ||
unexpected -> Error.throw (Illegal_State.Error "Unexpected type inside of `auth` field of a datalink: "+unexpected.to_text) |
26 changes: 26 additions & 0 deletions
26
distribution/lib/Standard/AWS/0.0.0-dev/src/S3/S3_Data_Link.enso
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
from Standard.Base import all | ||
from Standard.Base.Enso_Cloud.Public_Utils import get_required_field | ||
from Standard.Base.Enso_Cloud.Data_Link import parse_format | ||
|
||
import project.AWS_Credential.AWS_Credential | ||
import project.S3.S3_File.S3_File | ||
from project.Internal.Data_Link_Helpers import decode_aws_credential | ||
|
||
## PRIVATE | ||
type S3_Data_Link | ||
## PRIVATE | ||
Value (uri : Text) format (credentials : AWS_Credential | Nothing) | ||
|
||
## PRIVATE | ||
parse json -> S3_Data_Link = | ||
uri = get_required_field "uri" json | ||
auth = decode_aws_credential (get_required_field "auth" json) | ||
format = parse_format (json.get "format" Nothing) | ||
S3_Data_Link.Value uri format auth | ||
|
||
## PRIVATE | ||
as_file self -> S3_File = S3_File.new self.uri self.credentials | ||
|
||
## PRIVATE | ||
read self (on_problems : Problem_Behavior) = | ||
self.as_file.read self.format on_problems |
93 changes: 93 additions & 0 deletions
93
distribution/lib/Standard/Base/0.0.0-dev/src/Enso_Cloud/Data_Link.enso
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
import project.Any.Any | ||
import project.Data.Json.JS_Object | ||
import project.Data.Text.Encoding.Encoding | ||
import project.Data.Text.Text | ||
import project.Enso_Cloud.Enso_Secret.Enso_Secret | ||
import project.Error.Error | ||
import project.Errors.Illegal_State.Illegal_State | ||
import project.Errors.Problem_Behavior.Problem_Behavior | ||
import project.Errors.Unimplemented.Unimplemented | ||
import project.Nothing.Nothing | ||
import project.System.File.File | ||
import project.System.File.Generic.Writable_File.Writable_File | ||
import project.System.File_Format.Auto_Detect | ||
import project.System.File_Format.Infer | ||
import project.System.File_Format.JSON_Format | ||
import project.System.File_Format_Metadata.File_Format_Metadata | ||
import project.System.Input_Stream.Input_Stream | ||
from project.Enso_Cloud.Public_Utils import get_required_field | ||
|
||
polyglot java import org.enso.base.enso_cloud.DataLinkSPI | ||
polyglot java import org.enso.base.file_format.FileFormatSPI | ||
|
||
## PRIVATE | ||
A file format for reading data links. | ||
type Data_Link_Format | ||
## PRIVATE | ||
If the File_Format supports reading from the file, return a configured instance. | ||
for_read : File_Format_Metadata -> Data_Link_Format | Nothing | ||
for_read file:File_Format_Metadata = | ||
case file.guess_extension of | ||
".datalink" -> Data_Link_Format | ||
_ -> Nothing | ||
|
||
## PRIVATE | ||
Currently writing data links is not supported. | ||
for_file_write : Writable_File -> Nothing | ||
for_file_write file = | ||
_ = file | ||
Nothing | ||
|
||
## PRIVATE | ||
Implements the `File.read` for this `File_Format` | ||
read : File -> Problem_Behavior -> Any | ||
read self file on_problems = | ||
json = JSON_Format.read file on_problems | ||
read_datalink json on_problems | ||
|
||
## PRIVATE | ||
Implements decoding the format from a stream. | ||
read_stream : Input_Stream -> File_Format_Metadata -> Any | ||
read_stream self stream:Input_Stream (metadata : File_Format_Metadata) = | ||
json = JSON_Format.read_stream stream metadata | ||
read_datalink json Problem_Behavior.Report_Error | ||
|
||
## PRIVATE | ||
interpret_json_as_datalink json = | ||
typ = get_required_field "type" json | ||
case DataLinkSPI.findDataLinkType typ of | ||
Nothing -> | ||
library_name = get_required_field "libraryName" json | ||
Error.throw (Illegal_State.Error "The data link for "+typ+" is provided by the library "+library_name+" which is not loaded. Please import the library, and if necessary, restart the project.") | ||
data_link_type -> | ||
data_link_type.parse json | ||
|
||
## PRIVATE | ||
read_datalink json on_problems = | ||
data_link_instance = interpret_json_as_datalink json | ||
data_link_instance.read on_problems | ||
|
||
## PRIVATE | ||
parse_secure_value (json : Text | JS_Object) -> Text | Enso_Secret = | ||
case json of | ||
raw_text : Text -> raw_text | ||
_ : JS_Object -> | ||
case get_required_field "type" json of | ||
"secret" -> | ||
secret_path = get_required_field "secretPath" json | ||
_ = secret_path | ||
Unimplemented.throw "Reading secrets from a path is not implemented yet, see: https://github.com/enso-org/enso/issues/9048" | ||
other -> Error.throw (Illegal_State.Error "Unexpected value inside of a data-link: "+other+".") | ||
|
||
## PRIVATE | ||
parse_format json = case json of | ||
Nothing -> Auto_Detect | ||
_ : JS_Object -> case get_required_field "subType" json of | ||
"default" -> Auto_Detect | ||
sub_type : Text -> | ||
format_type = FileFormatSPI.findFormatForDataLinkSubType sub_type | ||
if format_type.is_nothing then Error.throw (Illegal_State.Error "Unknown format inside of a datalink: "+sub_type+". Perhaps the library providing that format needs to be imported?") else | ||
format_type.from json | ||
other -> | ||
Error.throw (Illegal_State.Error "Expected `subType` to be a string, but got: "+other.to_display_text+".") | ||
other -> Error.throw (Illegal_State.Error "Unexpected value inside of a data-link `format` field: "+other.to_display_text+".") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
10 changes: 10 additions & 0 deletions
10
distribution/lib/Standard/Base/0.0.0-dev/src/Enso_Cloud/Public_Utils.enso
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
import project.Enso_Cloud.Errors.Enso_Cloud_Error | ||
import project.Error.Error | ||
import project.Data.Json.JS_Object | ||
|
||
## PRIVATE | ||
A helper that extracts a field from a response and handles unexpected | ||
response structure. | ||
get_required_field key js_object = case js_object of | ||
_ : JS_Object -> js_object.get key if_missing=(Error.throw (Enso_Cloud_Error.Invalid_Response_Payload "Missing required field `"+key+"` in "+js_object.to_display_text+".")) | ||
_ -> Error.throw (Enso_Cloud_Error.Invalid_Response_Payload "Expected a JSON object, but got "+js_object.to_display_text+".") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The S3 bucket name can only contain lowercase letters, digits,
.
and-
. It has to be at least 3 characters long and at most 63 characters long.There are a few more restrictions - e.g. it cannot start with
-
, it cannot contain double--
etc. But I thought that just checking the simple ones is enough - it's just a basic sanity check - even if the bucket name is valid, the bucket could not exist / be not accessible anyway, so this does not need to be comprehensive.The bucket key can be arbitrary, but it has a limit of 1024 bytes, so the length limit is a heuristic of that.