-
Notifications
You must be signed in to change notification settings - Fork 109
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
feat(laboratory): scope environment variables to target #6500
base: main
Are you sure you want to change the base?
Conversation
📝 WalkthroughSummary by CodeRabbit
WalkthroughThis pull request introduces a new scoping mechanism for Laboratory Environment Variables, ensuring they are specific to each Target rather than being shared globally. The implementation transitions from using a static key in local storage to a structure that supports versioned entries through a new Changes
Possibly related PRs
📜 Recent review detailsConfiguration used: CodeRabbit UI 📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
⏰ Context from checks skipped due to timeout of 90000ms (4)
Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media? 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
📚 Storybook DeploymentThe latest changes are available as preview in: https://f6cf5a80.hive-storybook.pages.dev |
🐋 This PR was built and pushed to the following Docker images: Targets: Platforms: Image Tag: Docker Bake metadata{
"app": {
"buildx.build.provenance": {
"buildType": "https://mobyproject.org/buildkit@v1",
"materials": [
{
"uri": "pkg:docker/[email protected]?platform=linux%2Farm64",
"digest": {
"sha256": "f5a0871ab03b035c58bdb3007c3d177b001c2145c18e81817b71624dcf7d8bff"
}
}
],
"invocation": {
"configSource": {
"entryPoint": "services.dockerfile"
},
"parameters": {
"frontend": "dockerfile.v0",
"args": {
"build-arg:HEALTHCHECK_CMD": "wget --spider -q http://127.0.0.1:${PORT}/api/health",
"build-arg:IMAGE_DESCRIPTION": "The app of the GraphQL Hive project.",
"build-arg:IMAGE_TITLE": "graphql-hive/app",
"build-arg:PORT": "3000",
"build-arg:RELEASE": "8a1c77f9b1566ad7b9c083096f037f8d7016ccab",
"build-arg:SERVICE_DIR_NAME": "@hive/app",
"context:dist": "local:dist",
"context:shared": "local:shared",
"frontend.caps": "moby.buildkit.frontend.contexts+forward",
"local-sessionid:context": "v4dxzzj3i8m6vdnjmtxpxh1ox",
"local-sessionid:dockerfile": "v4dxzzj3i8m6vdnjmtxpxh1ox",
"local-sessionid:shared": "v4dxzzj3i8m6vdnjmtxpxh1ox"
},
"locals": [
{
"name": "context"
},
{
"name": "dist"
},
{
"name": "dockerfile"
},
{
"name": "shared"
}
]
},
"environment": {
"platform": "linux/arm64"
}
}
},
"buildx.build.ref": "builder-bf5a90c8-9a8c-4791-8413-f17b284c4c49/builder-bf5a90c8-9a8c-4791-8413-f17b284c4c490/u03pvsacfj78c7ta2vikymg5h",
"containerimage.config.digest": "sha256:bf56e10fa64afae845e6eb49dd3da78de7a6d8983f74778b252fb4f6aa77568f",
"containerimage.descriptor": {
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
"digest": "sha256:567b09287f4a980c67cdf49ab54a19932e685cc91da8b21d8f22a4b3feb1a2af",
"size": 2075,
"platform": {
"architecture": "arm64",
"os": "linux"
}
},
"containerimage.digest": "sha256:567b09287f4a980c67cdf49ab54a19932e685cc91da8b21d8f22a4b3feb1a2af",
"image.name": "ghcr.io/graphql-hive/app:8a1c77f9b1566ad7b9c083096f037f8d7016ccab-arm64,ghcr.io/graphql-hive/app:console_994-arm64"
},
"buildx.build.warnings": [
{
"vertex": "sha256:59a8da04ea58a18a470e2c684d98bcf4c0dda6f1910759e2051c3d7ab1a2f119",
"level": 1,
"short": "TGVnYWN5S2V5VmFsdWVGb3JtYXQ6ICJFTlYga2V5PXZhbHVlIiBzaG91bGQgYmUgdXNlZCBpbnN0ZWFkIG9mIGxlZ2FjeSAiRU5WIGtleSB2YWx1ZSIgZm9ybWF0IChsaW5lIDEyKQ==",
"detail": [
"TGVnYWN5IGtleS92YWx1ZSBmb3JtYXQgd2l0aCB3aGl0ZXNwYWNlIHNlcGFyYXRvciBzaG91bGQgbm90IGJlIHVzZWQ="
],
"url": "https://docs.docker.com/go/dockerfile/rule/legacy-key-value-format/",
"sourceInfo": {
"filename": "migrations.dockerfile",
"data": "RlJPTSBub2RlOjIyLjEzLjAtc2xpbQoKUlVOIGFwdC1nZXQgdXBkYXRlICYmIGFwdC1nZXQgaW5zdGFsbCAteSBjYS1jZXJ0aWZpY2F0ZXMKCldPUktESVIgL3Vzci9zcmMvYXBwCgpDT1BZIC0tZnJvbT1kaXN0IC4gL3Vzci9zcmMvYXBwLwpDT1BZIC0tZnJvbT1zaGFyZWQgLiAvCgpFTlYgRU5WSVJPTk1FTlQgcHJvZHVjdGlvbgpFTlYgTk9ERV9FTlYgcHJvZHVjdGlvbgpFTlYgUkVMRUFTRSAkUkVMRUFTRQoKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLmxpY2Vuc2VzPU1JVApMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UudGl0bGU9JElNQUdFX1RJVExFCkxBQkVMIG9yZy5vcGVuY29udGFpbmVycy5pbWFnZS52ZXJzaW9uPSRSRUxFQVNFCkxBQkVMIG9yZy5vcGVuY29udGFpbmVycy5pbWFnZS5kZXNjcmlwdGlvbj0kSU1BR0VfREVTQ1JJUFRJT04KTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLmF1dGhvcnM9IlRoZSBHdWlsZCIKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLnZlbmRvcj0iS2FtaWwgS2lzaWVsYSIKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLnVybD0iaHR0cHM6Ly9naXRodWIuY29tL2dyYXBocWwtaGl2ZS9wbGF0Zm9ybSIKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLnNvdXJjZT0iaHR0cHM6Ly9naXRodWIuY29tL2dyYXBocWwtaGl2ZS9wbGF0Zm9ybSIKCkVOVFJZUE9JTlQgWyAiL2VudHJ5cG9pbnQuc2giIF0K",
"language": "Dockerfile"
},
"range": [
{
"start": {
"line": 12
},
"end": {
"line": 12
}
}
]
},
{
"vertex": "sha256:59a8da04ea58a18a470e2c684d98bcf4c0dda6f1910759e2051c3d7ab1a2f119",
"level": 1,
"short": "VW5kZWZpbmVkVmFyOiBVc2FnZSBvZiB1bmRlZmluZWQgdmFyaWFibGUgJyRJTUFHRV9ERVNDUklQVElPTicgKGxpbmUgMTcp",
"detail": [
"VmFyaWFibGVzIHNob3VsZCBiZSBkZWZpbmVkIGJlZm9yZSB0aGVpciB1c2U="
],
"url": "https://docs.docker.com/go/dockerfile/rule/undefined-var/",
"sourceInfo": {
"filename": "migrations.dockerfile",
"data": "RlJPTSBub2RlOjIyLjEzLjAtc2xpbQoKUlVOIGFwdC1nZXQgdXBkYXRlICYmIGFwdC1nZXQgaW5zdGFsbCAteSBjYS1jZXJ0aWZpY2F0ZXMKCldPUktESVIgL3Vzci9zcmMvYXBwCgpDT1BZIC0tZnJvbT1kaXN0IC4gL3Vzci9zcmMvYXBwLwpDT1BZIC0tZnJvbT1zaGFyZWQgLiAvCgpFTlYgRU5WSVJPTk1FTlQgcHJvZHVjdGlvbgpFTlYgTk9ERV9FTlYgcHJvZHVjdGlvbgpFTlYgUkVMRUFTRSAkUkVMRUFTRQoKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLmxpY2Vuc2VzPU1JVApMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UudGl0bGU9JElNQUdFX1RJVExFCkxBQkVMIG9yZy5vcGVuY29udGFpbmVycy5pbWFnZS52ZXJzaW9uPSRSRUxFQVNFCkxBQkVMIG9yZy5vcGVuY29udGFpbmVycy5pbWFnZS5kZXNjcmlwdGlvbj0kSU1BR0VfREVTQ1JJUFRJT04KTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLmF1dGhvcnM9IlRoZSBHdWlsZCIKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLnZlbmRvcj0iS2FtaWwgS2lzaWVsYSIKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLnVybD0iaHR0cHM6Ly9naXRodWIuY29tL2dyYXBocWwtaGl2ZS9wbGF0Zm9ybSIKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLnNvdXJjZT0iaHR0cHM6Ly9naXRodWIuY29tL2dyYXBocWwtaGl2ZS9wbGF0Zm9ybSIKCkVOVFJZUE9JTlQgWyAiL2VudHJ5cG9pbnQuc2giIF0K",
"language": "Dockerfile"
},
"range": [
{
"start": {
"line": 17
},
"end": {
"line": 17
}
}
]
},
{
"vertex": "sha256:d0db291ada70c43c405b5a7efff7caa1e79023b12f45120693673b05a92a3446",
"level": 1,
"short": "VW5kZWZpbmVkVmFyOiBVc2FnZSBvZiB1bmRlZmluZWQgdmFyaWFibGUgJyRSRUxFQVNFJyAobGluZSAxMyk=",
"detail": [
"VmFyaWFibGVzIHNob3VsZCBiZSBkZWZpbmVkIGJlZm9yZSB0aGVpciB1c2U="
],
"url": "https://docs.docker.com/go/dockerfile/rule/undefined-var/",
"sourceInfo": {
"filename": "services.dockerfile",
"data": "RlJPTSBub2RlOjIyLjEzLjAtc2xpbQoKUlVOIGFwdC1nZXQgdXBkYXRlICYmIGFwdC1nZXQgaW5zdGFsbCAteSB3Z2V0IGNhLWNlcnRpZmljYXRlcyAmJiBybSAtcmYgL3Zhci9saWIvYXB0L2xpc3RzLyoKCkFSRyBTRVJWSUNFX0RJUl9OQU1FCldPUktESVIgL3Vzci9zcmMvYXBwLyRTRVJWSUNFX0RJUl9OQU1FCgpDT1BZIC0tZnJvbT1kaXN0IC4gL3Vzci9zcmMvYXBwLyRTRVJWSUNFX0RJUl9OQU1FLwpDT1BZIC0tZnJvbT1zaGFyZWQgLiAvCgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UubGljZW5zZXM9TUlUCkxBQkVMIG9yZy5vcGVuY29udGFpbmVycy5pbWFnZS50aXRsZT0kSU1BR0VfVElUTEUKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLnZlcnNpb249JFJFTEVBU0UKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLmRlc2NyaXB0aW9uPSRJTUFHRV9ERVNDUklQVElPTgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UuYXV0aG9ycz0iVGhlIEd1aWxkIgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UudmVuZG9yPSJLYW1pbCBLaXNpZWxhIgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UudXJsPSJodHRwczovL2dpdGh1Yi5jb20vZ3JhcGhxbC1oaXZlL3BsYXRmb3JtIgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2Uuc291cmNlPSJodHRwczovL2dpdGh1Yi5jb20vZ3JhcGhxbC1oaXZlL3BsYXRmb3JtIgoKRU5WIEVOVklST05NRU5UIHByb2R1Y3Rpb24KRU5WIFJFTEVBU0UgJFJFTEVBU0UKRU5WIFBPUlQgJFBPUlQKCkhFQUxUSENIRUNLIC0taW50ZXJ2YWw9NXMgXAogIC0tdGltZW91dD01cyBcCiAgLS1zdGFydC1wZXJpb2Q9NXMgXAogIC0tcmV0cmllcz02IFwKICBDTUQgJEhFQUxUSENIRUNLX0NNRAoKRU5UUllQT0lOVCBbICIvZW50cnlwb2ludC5zaCIgXQo=",
"language": "Dockerfile"
},
"range": [
{
"start": {
"line": 13
},
"end": {
"line": 13
}
}
]
},
{
"vertex": "sha256:d0db291ada70c43c405b5a7efff7caa1e79023b12f45120693673b05a92a3446",
"level": 1,
"short": "VW5kZWZpbmVkVmFyOiBVc2FnZSBvZiB1bmRlZmluZWQgdmFyaWFibGUgJyRJTUFHRV9ERVNDUklQVElPTicgKGxpbmUgMTQp",
"detail": [
"VmFyaWFibGVzIHNob3VsZCBiZSBkZWZpbmVkIGJlZm9yZSB0aGVpciB1c2U="
],
"url": "https://docs.docker.com/go/dockerfile/rule/undefined-var/",
"sourceInfo": {
"filename": "services.dockerfile",
"data": "RlJPTSBub2RlOjIyLjEzLjAtc2xpbQoKUlVOIGFwdC1nZXQgdXBkYXRlICYmIGFwdC1nZXQgaW5zdGFsbCAteSB3Z2V0IGNhLWNlcnRpZmljYXRlcyAmJiBybSAtcmYgL3Zhci9saWIvYXB0L2xpc3RzLyoKCkFSRyBTRVJWSUNFX0RJUl9OQU1FCldPUktESVIgL3Vzci9zcmMvYXBwLyRTRVJWSUNFX0RJUl9OQU1FCgpDT1BZIC0tZnJvbT1kaXN0IC4gL3Vzci9zcmMvYXBwLyRTRVJWSUNFX0RJUl9OQU1FLwpDT1BZIC0tZnJvbT1zaGFyZWQgLiAvCgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UubGljZW5zZXM9TUlUCkxBQkVMIG9yZy5vcGVuY29udGFpbmVycy5pbWFnZS50aXRsZT0kSU1BR0VfVElUTEUKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLnZlcnNpb249JFJFTEVBU0UKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLmRlc2NyaXB0aW9uPSRJTUFHRV9ERVNDUklQVElPTgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UuYXV0aG9ycz0iVGhlIEd1aWxkIgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UudmVuZG9yPSJLYW1pbCBLaXNpZWxhIgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UudXJsPSJodHRwczovL2dpdGh1Yi5jb20vZ3JhcGhxbC1oaXZlL3BsYXRmb3JtIgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2Uuc291cmNlPSJodHRwczovL2dpdGh1Yi5jb20vZ3JhcGhxbC1oaXZlL3BsYXRmb3JtIgoKRU5WIEVOVklST05NRU5UIHByb2R1Y3Rpb24KRU5WIFJFTEVBU0UgJFJFTEVBU0UKRU5WIFBPUlQgJFBPUlQKCkhFQUxUSENIRUNLIC0taW50ZXJ2YWw9NXMgXAogIC0tdGltZW91dD01cyBcCiAgLS1zdGFydC1wZXJpb2Q9NXMgXAogIC0tcmV0cmllcz02IFwKICBDTUQgJEhFQUxUSENIRUNLX0NNRAoKRU5UUllQT0lOVCBbICIvZW50cnlwb2ludC5zaCIgXQo=",
"language": "Dockerfile"
},
"range": [
{
"start": {
"line": 14
},
"end": {
"line": 14
}
}
]
},
{
"vertex": "sha256:d0db291ada70c43c405b5a7efff7caa1e79023b12f45120693673b05a92a3446",
"level": 1,
"short": "TGVnYWN5S2V5VmFsdWVGb3JtYXQ6ICJFTlYga2V5PXZhbHVlIiBzaG91bGQgYmUgdXNlZCBpbnN0ZWFkIG9mIGxlZ2FjeSAiRU5WIGtleSB2YWx1ZSIgZm9ybWF0IChsaW5lIDIwKQ==",
"detail": [
"TGVnYWN5IGtleS92YWx1ZSBmb3JtYXQgd2l0aCB3aGl0ZXNwYWNlIHNlcGFyYXRvciBzaG91bGQgbm90IGJlIHVzZWQ="
],
"url": "https://docs.docker.com/go/dockerfile/rule/legacy-key-value-format/",
"sourceInfo": {
"filename": "services.dockerfile",
"data": "RlJPTSBub2RlOjIyLjEzLjAtc2xpbQoKUlVOIGFwdC1nZXQgdXBkYXRlICYmIGFwdC1nZXQgaW5zdGFsbCAteSB3Z2V0IGNhLWNlcnRpZmljYXRlcyAmJiBybSAtcmYgL3Zhci9saWIvYXB0L2xpc3RzLyoKCkFSRyBTRVJWSUNFX0RJUl9OQU1FCldPUktESVIgL3Vzci9zcmMvYXBwLyRTRVJWSUNFX0RJUl9OQU1FCgpDT1BZIC0tZnJvbT1kaXN0IC4gL3Vzci9zcmMvYXBwLyRTRVJWSUNFX0RJUl9OQU1FLwpDT1BZIC0tZnJvbT1zaGFyZWQgLiAvCgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UubGljZW5zZXM9TUlUCkxBQkVMIG9yZy5vcGVuY29udGFpbmVycy5pbWFnZS50aXRsZT0kSU1BR0VfVElUTEUKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLnZlcnNpb249JFJFTEVBU0UKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLmRlc2NyaXB0aW9uPSRJTUFHRV9ERVNDUklQVElPTgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UuYXV0aG9ycz0iVGhlIEd1aWxkIgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UudmVuZG9yPSJLYW1pbCBLaXNpZWxhIgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UudXJsPSJodHRwczovL2dpdGh1Yi5jb20vZ3JhcGhxbC1oaXZlL3BsYXRmb3JtIgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2Uuc291cmNlPSJodHRwczovL2dpdGh1Yi5jb20vZ3JhcGhxbC1oaXZlL3BsYXRmb3JtIgoKRU5WIEVOVklST05NRU5UIHByb2R1Y3Rpb24KRU5WIFJFTEVBU0UgJFJFTEVBU0UKRU5WIFBPUlQgJFBPUlQKCkhFQUxUSENIRUNLIC0taW50ZXJ2YWw9NXMgXAogIC0tdGltZW91dD01cyBcCiAgLS1zdGFydC1wZXJpb2Q9NXMgXAogIC0tcmV0cmllcz02IFwKICBDTUQgJEhFQUxUSENIRUNLX0NNRAoKRU5UUllQT0lOVCBbICIvZW50cnlwb2ludC5zaCIgXQo=",
"language": "Dockerfile"
},
"range": [
{
"start": {
"line": 20
},
"end": {
"line": 20
}
}
]
},
{
"vertex": "sha256:d0db291ada70c43c405b5a7efff7caa1e79023b12f45120693673b05a92a3446",
"level": 1,
"short": "TGVnYWN5S2V5VmFsdWVGb3JtYXQ6ICJFTlYga2V5PXZhbHVlIiBzaG91bGQgYmUgdXNlZCBpbnN0ZWFkIG9mIGxlZ2FjeSAiRU5WIGtleSB2YWx1ZSIgZm9ybWF0IChsaW5lIDIxKQ==",
"detail": [
"TGVnYWN5IGtleS92YWx1ZSBmb3JtYXQgd2l0aCB3aGl0ZXNwYWNlIHNlcGFyYXRvciBzaG91bGQgbm90IGJlIHVzZWQ="
],
"url": "https://docs.docker.com/go/dockerfile/rule/legacy-key-value-format/",
"sourceInfo": {
"filename": "services.dockerfile",
"data": "RlJPTSBub2RlOjIyLjEzLjAtc2xpbQoKUlVOIGFwdC1nZXQgdXBkYXRlICYmIGFwdC1nZXQgaW5zdGFsbCAteSB3Z2V0IGNhLWNlcnRpZmljYXRlcyAmJiBybSAtcmYgL3Zhci9saWIvYXB0L2xpc3RzLyoKCkFSRyBTRVJWSUNFX0RJUl9OQU1FCldPUktESVIgL3Vzci9zcmMvYXBwLyRTRVJWSUNFX0RJUl9OQU1FCgpDT1BZIC0tZnJvbT1kaXN0IC4gL3Vzci9zcmMvYXBwLyRTRVJWSUNFX0RJUl9OQU1FLwpDT1BZIC0tZnJvbT1zaGFyZWQgLiAvCgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UubGljZW5zZXM9TUlUCkxBQkVMIG9yZy5vcGVuY29udGFpbmVycy5pbWFnZS50aXRsZT0kSU1BR0VfVElUTEUKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLnZlcnNpb249JFJFTEVBU0UKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLmRlc2NyaXB0aW9uPSRJTUFHRV9ERVNDUklQVElPTgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UuYXV0aG9ycz0iVGhlIEd1aWxkIgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UudmVuZG9yPSJLYW1pbCBLaXNpZWxhIgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UudXJsPSJodHRwczovL2dpdGh1Yi5jb20vZ3JhcGhxbC1oaXZlL3BsYXRmb3JtIgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2Uuc291cmNlPSJodHRwczovL2dpdGh1Yi5jb20vZ3JhcGhxbC1oaXZlL3BsYXRmb3JtIgoKRU5WIEVOVklST05NRU5UIHByb2R1Y3Rpb24KRU5WIFJFTEVBU0UgJFJFTEVBU0UKRU5WIFBPUlQgJFBPUlQKCkhFQUxUSENIRUNLIC0taW50ZXJ2YWw9NXMgXAogIC0tdGltZW91dD01cyBcCiAgLS1zdGFydC1wZXJpb2Q9NXMgXAogIC0tcmV0cmllcz02IFwKICBDTUQgJEhFQUxUSENIRUNLX0NNRAoKRU5UUllQT0lOVCBbICIvZW50cnlwb2ludC5zaCIgXQo=",
"language": "Dockerfile"
},
"range": [
{
"start": {
"line": 21
},
"end": {
"line": 21
}
}
]
},
{
"vertex": "sha256:d0db291ada70c43c405b5a7efff7caa1e79023b12f45120693673b05a92a3446",
"level": 1,
"short": "VW5kZWZpbmVkVmFyOiBVc2FnZSBvZiB1bmRlZmluZWQgdmFyaWFibGUgJyRQT1JUJyAobGluZSAyMik=",
"detail": [
"VmFyaWFibGVzIHNob3VsZCBiZSBkZWZpbmVkIGJlZm9yZSB0aGVpciB1c2U="
],
"url": "https://docs.docker.com/go/dockerfile/rule/undefined-var/",
"sourceInfo": {
"filename": "services.dockerfile",
"data": "RlJPTSBub2RlOjIyLjEzLjAtc2xpbQoKUlVOIGFwdC1nZXQgdXBkYXRlICYmIGFwdC1nZXQgaW5zdGFsbCAteSB3Z2V0IGNhLWNlcnRpZmljYXRlcyAmJiBybSAtcmYgL3Zhci9saWIvYXB0L2xpc3RzLyoKCkFSRyBTRVJWSUNFX0RJUl9OQU1FCldPUktESVIgL3Vzci9zcmMvYXBwLyRTRVJWSUNFX0RJUl9OQU1FCgpDT1BZIC0tZnJvbT1kaXN0IC4gL3Vzci9zcmMvYXBwLyRTRVJWSUNFX0RJUl9OQU1FLwpDT1BZIC0tZnJvbT1zaGFyZWQgLiAvCgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UubGljZW5zZXM9TUlUCkxBQkVMIG9yZy5vcGVuY29udGFpbmVycy5pbWFnZS50aXRsZT0kSU1BR0VfVElUTEUKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLnZlcnNpb249JFJFTEVBU0UKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLmRlc2NyaXB0aW9uPSRJTUFHRV9ERVNDUklQVElPTgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UuYXV0aG9ycz0iVGhlIEd1aWxkIgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UudmVuZG9yPSJLYW1pbCBLaXNpZWxhIgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UudXJsPSJodHRwczovL2dpdGh1Yi5jb20vZ3JhcGhxbC1oaXZlL3BsYXRmb3JtIgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2Uuc291cmNlPSJodHRwczovL2dpdGh1Yi5jb20vZ3JhcGhxbC1oaXZlL3BsYXRmb3JtIgoKRU5WIEVOVklST05NRU5UIHByb2R1Y3Rpb24KRU5WIFJFTEVBU0UgJFJFTEVBU0UKRU5WIFBPUlQgJFBPUlQKCkhFQUxUSENIRUNLIC0taW50ZXJ2YWw9NXMgXAogIC0tdGltZW91dD01cyBcCiAgLS1zdGFydC1wZXJpb2Q9NXMgXAogIC0tcmV0cmllcz02IFwKICBDTUQgJEhFQUxUSENIRUNLX0NNRAoKRU5UUllQT0lOVCBbICIvZW50cnlwb2ludC5zaCIgXQo=",
"language": "Dockerfile"
},
"range": [
{
"start": {
"line": 22
},
"end": {
"line": 22
}
}
]
},
{
"vertex": "sha256:59a8da04ea58a18a470e2c684d98bcf4c0dda6f1910759e2051c3d7ab1a2f119",
"level": 1,
"short": "VW5kZWZpbmVkVmFyOiBVc2FnZSBvZiB1bmRlZmluZWQgdmFyaWFibGUgJyRJTUFHRV9USVRMRScgKGxpbmUgMTUp",
"detail": [
"VmFyaWFibGVzIHNob3VsZCBiZSBkZWZpbmVkIGJlZm9yZSB0aGVpciB1c2U="
],
"url": "https://docs.docker.com/go/dockerfile/rule/undefined-var/",
"sourceInfo": {
"filename": "migrations.dockerfile",
"data": "RlJPTSBub2RlOjIyLjEzLjAtc2xpbQoKUlVOIGFwdC1nZXQgdXBkYXRlICYmIGFwdC1nZXQgaW5zdGFsbCAteSBjYS1jZXJ0aWZpY2F0ZXMKCldPUktESVIgL3Vzci9zcmMvYXBwCgpDT1BZIC0tZnJvbT1kaXN0IC4gL3Vzci9zcmMvYXBwLwpDT1BZIC0tZnJvbT1zaGFyZWQgLiAvCgpFTlYgRU5WSVJPTk1FTlQgcHJvZHVjdGlvbgpFTlYgTk9ERV9FTlYgcHJvZHVjdGlvbgpFTlYgUkVMRUFTRSAkUkVMRUFTRQoKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLmxpY2Vuc2VzPU1JVApMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UudGl0bGU9JElNQUdFX1RJVExFCkxBQkVMIG9yZy5vcGVuY29udGFpbmVycy5pbWFnZS52ZXJzaW9uPSRSRUxFQVNFCkxBQkVMIG9yZy5vcGVuY29udGFpbmVycy5pbWFnZS5kZXNjcmlwdGlvbj0kSU1BR0VfREVTQ1JJUFRJT04KTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLmF1dGhvcnM9IlRoZSBHdWlsZCIKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLnZlbmRvcj0iS2FtaWwgS2lzaWVsYSIKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLnVybD0iaHR0cHM6Ly9naXRodWIuY29tL2dyYXBocWwtaGl2ZS9wbGF0Zm9ybSIKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLnNvdXJjZT0iaHR0cHM6Ly9naXRodWIuY29tL2dyYXBocWwtaGl2ZS9wbGF0Zm9ybSIKCkVOVFJZUE9JTlQgWyAiL2VudHJ5cG9pbnQuc2giIF0K",
"language": "Dockerfile"
},
"range": [
{
"start": {
"line": 15
},
"end": {
"line": 15
}
}
]
},
{
"vertex": "sha256:d0db291ada70c43c405b5a7efff7caa1e79023b12f45120693673b05a92a3446",
"level": 1,
"short": "VW5kZWZpbmVkVmFyOiBVc2FnZSBvZiB1bmRlZmluZWQgdmFyaWFibGUgJyRSRUxFQVNFJyAobGluZSAyMSk=",
"detail": [
"VmFyaWFibGVzIHNob3VsZCBiZSBkZWZpbmVkIGJlZm9yZSB0aGVpciB1c2U="
],
"url": "https://docs.docker.com/go/dockerfile/rule/undefined-var/",
"sourceInfo": {
"filename": "services.dockerfile",
"data": "RlJPTSBub2RlOjIyLjEzLjAtc2xpbQoKUlVOIGFwdC1nZXQgdXBkYXRlICYmIGFwdC1nZXQgaW5zdGFsbCAteSB3Z2V0IGNhLWNlcnRpZmljYXRlcyAmJiBybSAtcmYgL3Zhci9saWIvYXB0L2xpc3RzLyoKCkFSRyBTRVJWSUNFX0RJUl9OQU1FCldPUktESVIgL3Vzci9zcmMvYXBwLyRTRVJWSUNFX0RJUl9OQU1FCgpDT1BZIC0tZnJvbT1kaXN0IC4gL3Vzci9zcmMvYXBwLyRTRVJWSUNFX0RJUl9OQU1FLwpDT1BZIC0tZnJvbT1zaGFyZWQgLiAvCgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UubGljZW5zZXM9TUlUCkxBQkVMIG9yZy5vcGVuY29udGFpbmVycy5pbWFnZS50aXRsZT0kSU1BR0VfVElUTEUKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLnZlcnNpb249JFJFTEVBU0UKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLmRlc2NyaXB0aW9uPSRJTUFHRV9ERVNDUklQVElPTgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UuYXV0aG9ycz0iVGhlIEd1aWxkIgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UudmVuZG9yPSJLYW1pbCBLaXNpZWxhIgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UudXJsPSJodHRwczovL2dpdGh1Yi5jb20vZ3JhcGhxbC1oaXZlL3BsYXRmb3JtIgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2Uuc291cmNlPSJodHRwczovL2dpdGh1Yi5jb20vZ3JhcGhxbC1oaXZlL3BsYXRmb3JtIgoKRU5WIEVOVklST05NRU5UIHByb2R1Y3Rpb24KRU5WIFJFTEVBU0UgJFJFTEVBU0UKRU5WIFBPUlQgJFBPUlQKCkhFQUxUSENIRUNLIC0taW50ZXJ2YWw9NXMgXAogIC0tdGltZW91dD01cyBcCiAgLS1zdGFydC1wZXJpb2Q9NXMgXAogIC0tcmV0cmllcz02IFwKICBDTUQgJEhFQUxUSENIRUNLX0NNRAoKRU5UUllQT0lOVCBbICIvZW50cnlwb2ludC5zaCIgXQo=",
"language": "Dockerfile"
},
"range": [
{
"start": {
"line": 21
},
"end": {
"line": 21
}
}
]
},
{
"vertex": "sha256:59a8da04ea58a18a470e2c684d98bcf4c0dda6f1910759e2051c3d7ab1a2f119",
"level": 1,
"short": "TGVnYWN5S2V5VmFsdWVGb3JtYXQ6ICJFTlYga2V5PXZhbHVlIiBzaG91bGQgYmUgdXNlZCBpbnN0ZWFkIG9mIGxlZ2FjeSAiRU5WIGtleSB2YWx1ZSIgZm9ybWF0IChsaW5lIDExKQ==",
"detail": [
"TGVnYWN5IGtleS92YWx1ZSBmb3JtYXQgd2l0aCB3aGl0ZXNwYWNlIHNlcGFyYXRvciBzaG91bGQgbm90IGJlIHVzZWQ="
],
"url": "https://docs.docker.com/go/dockerfile/rule/legacy-key-value-format/",
"sourceInfo": {
"filename": "migrations.dockerfile",
"data": "RlJPTSBub2RlOjIyLjEzLjAtc2xpbQoKUlVOIGFwdC1nZXQgdXBkYXRlICYmIGFwdC1nZXQgaW5zdGFsbCAteSBjYS1jZXJ0aWZpY2F0ZXMKCldPUktESVIgL3Vzci9zcmMvYXBwCgpDT1BZIC0tZnJvbT1kaXN0IC4gL3Vzci9zcmMvYXBwLwpDT1BZIC0tZnJvbT1zaGFyZWQgLiAvCgpFTlYgRU5WSVJPTk1FTlQgcHJvZHVjdGlvbgpFTlYgTk9ERV9FTlYgcHJvZHVjdGlvbgpFTlYgUkVMRUFTRSAkUkVMRUFTRQoKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLmxpY2Vuc2VzPU1JVApMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UudGl0bGU9JElNQUdFX1RJVExFCkxBQkVMIG9yZy5vcGVuY29udGFpbmVycy5pbWFnZS52ZXJzaW9uPSRSRUxFQVNFCkxBQkVMIG9yZy5vcGVuY29udGFpbmVycy5pbWFnZS5kZXNjcmlwdGlvbj0kSU1BR0VfREVTQ1JJUFRJT04KTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLmF1dGhvcnM9IlRoZSBHdWlsZCIKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLnZlbmRvcj0iS2FtaWwgS2lzaWVsYSIKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLnVybD0iaHR0cHM6Ly9naXRodWIuY29tL2dyYXBocWwtaGl2ZS9wbGF0Zm9ybSIKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLnNvdXJjZT0iaHR0cHM6Ly9naXRodWIuY29tL2dyYXBocWwtaGl2ZS9wbGF0Zm9ybSIKCkVOVFJZUE9JTlQgWyAiL2VudHJ5cG9pbnQuc2giIF0K",
"language": "Dockerfile"
},
"range": [
{
"start": {
"line": 11
},
"end": {
"line": 11
}
}
]
},
{
"vertex": "sha256:59a8da04ea58a18a470e2c684d98bcf4c0dda6f1910759e2051c3d7ab1a2f119",
"level": 1,
"short": "VW5kZWZpbmVkVmFyOiBVc2FnZSBvZiB1bmRlZmluZWQgdmFyaWFibGUgJyRSRUxFQVNFJyAobGluZSAxMik=",
"detail": [
"VmFyaWFibGVzIHNob3VsZCBiZSBkZWZpbmVkIGJlZm9yZSB0aGVpciB1c2U="
],
"url": "https://docs.docker.com/go/dockerfile/rule/undefined-var/",
"sourceInfo": {
"filename": "migrations.dockerfile",
"data": "RlJPTSBub2RlOjIyLjEzLjAtc2xpbQoKUlVOIGFwdC1nZXQgdXBkYXRlICYmIGFwdC1nZXQgaW5zdGFsbCAteSBjYS1jZXJ0aWZpY2F0ZXMKCldPUktESVIgL3Vzci9zcmMvYXBwCgpDT1BZIC0tZnJvbT1kaXN0IC4gL3Vzci9zcmMvYXBwLwpDT1BZIC0tZnJvbT1zaGFyZWQgLiAvCgpFTlYgRU5WSVJPTk1FTlQgcHJvZHVjdGlvbgpFTlYgTk9ERV9FTlYgcHJvZHVjdGlvbgpFTlYgUkVMRUFTRSAkUkVMRUFTRQoKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLmxpY2Vuc2VzPU1JVApMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UudGl0bGU9JElNQUdFX1RJVExFCkxBQkVMIG9yZy5vcGVuY29udGFpbmVycy5pbWFnZS52ZXJzaW9uPSRSRUxFQVNFCkxBQkVMIG9yZy5vcGVuY29udGFpbmVycy5pbWFnZS5kZXNjcmlwdGlvbj0kSU1BR0VfREVTQ1JJUFRJT04KTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLmF1dGhvcnM9IlRoZSBHdWlsZCIKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLnZlbmRvcj0iS2FtaWwgS2lzaWVsYSIKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLnVybD0iaHR0cHM6Ly9naXRodWIuY29tL2dyYXBocWwtaGl2ZS9wbGF0Zm9ybSIKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLnNvdXJjZT0iaHR0cHM6Ly9naXRodWIuY29tL2dyYXBocWwtaGl2ZS9wbGF0Zm9ybSIKCkVOVFJZUE9JTlQgWyAiL2VudHJ5cG9pbnQuc2giIF0K",
"language": "Dockerfile"
},
"range": [
{
"start": {
"line": 12
},
"end": {
"line": 12
}
}
]
},
{
"vertex": "sha256:d0db291ada70c43c405b5a7efff7caa1e79023b12f45120693673b05a92a3446",
"level": 1,
"short": "VW5kZWZpbmVkVmFyOiBVc2FnZSBvZiB1bmRlZmluZWQgdmFyaWFibGUgJyRJTUFHRV9USVRMRScgKGxpbmUgMTIp",
"detail": [
"VmFyaWFibGVzIHNob3VsZCBiZSBkZWZpbmVkIGJlZm9yZSB0aGVpciB1c2U="
],
"url": "https://docs.docker.com/go/dockerfile/rule/undefined-var/",
"sourceInfo": {
"filename": "services.dockerfile",
"data": "RlJPTSBub2RlOjIyLjEzLjAtc2xpbQoKUlVOIGFwdC1nZXQgdXBkYXRlICYmIGFwdC1nZXQgaW5zdGFsbCAteSB3Z2V0IGNhLWNlcnRpZmljYXRlcyAmJiBybSAtcmYgL3Zhci9saWIvYXB0L2xpc3RzLyoKCkFSRyBTRVJWSUNFX0RJUl9OQU1FCldPUktESVIgL3Vzci9zcmMvYXBwLyRTRVJWSUNFX0RJUl9OQU1FCgpDT1BZIC0tZnJvbT1kaXN0IC4gL3Vzci9zcmMvYXBwLyRTRVJWSUNFX0RJUl9OQU1FLwpDT1BZIC0tZnJvbT1zaGFyZWQgLiAvCgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UubGljZW5zZXM9TUlUCkxBQkVMIG9yZy5vcGVuY29udGFpbmVycy5pbWFnZS50aXRsZT0kSU1BR0VfVElUTEUKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLnZlcnNpb249JFJFTEVBU0UKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLmRlc2NyaXB0aW9uPSRJTUFHRV9ERVNDUklQVElPTgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UuYXV0aG9ycz0iVGhlIEd1aWxkIgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UudmVuZG9yPSJLYW1pbCBLaXNpZWxhIgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UudXJsPSJodHRwczovL2dpdGh1Yi5jb20vZ3JhcGhxbC1oaXZlL3BsYXRmb3JtIgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2Uuc291cmNlPSJodHRwczovL2dpdGh1Yi5jb20vZ3JhcGhxbC1oaXZlL3BsYXRmb3JtIgoKRU5WIEVOVklST05NRU5UIHByb2R1Y3Rpb24KRU5WIFJFTEVBU0UgJFJFTEVBU0UKRU5WIFBPUlQgJFBPUlQKCkhFQUxUSENIRUNLIC0taW50ZXJ2YWw9NXMgXAogIC0tdGltZW91dD01cyBcCiAgLS1zdGFydC1wZXJpb2Q9NXMgXAogIC0tcmV0cmllcz02IFwKICBDTUQgJEhFQUxUSENIRUNLX0NNRAoKRU5UUllQT0lOVCBbICIvZW50cnlwb2ludC5zaCIgXQo=",
"language": "Dockerfile"
},
"range": [
{
"start": {
"line": 12
},
"end": {
"line": 12
}
}
]
},
{
"vertex": "sha256:d0db291ada70c43c405b5a7efff7caa1e79023b12f45120693673b05a92a3446",
"level": 1,
"short": "TGVnYWN5S2V5VmFsdWVGb3JtYXQ6ICJFTlYga2V5PXZhbHVlIiBzaG91bGQgYmUgdXNlZCBpbnN0ZWFkIG9mIGxlZ2FjeSAiRU5WIGtleSB2YWx1ZSIgZm9ybWF0IChsaW5lIDIyKQ==",
"detail": [
"TGVnYWN5IGtleS92YWx1ZSBmb3JtYXQgd2l0aCB3aGl0ZXNwYWNlIHNlcGFyYXRvciBzaG91bGQgbm90IGJlIHVzZWQ="
],
"url": "https://docs.docker.com/go/dockerfile/rule/legacy-key-value-format/",
"sourceInfo": {
"filename": "services.dockerfile",
"data": "RlJPTSBub2RlOjIyLjEzLjAtc2xpbQoKUlVOIGFwdC1nZXQgdXBkYXRlICYmIGFwdC1nZXQgaW5zdGFsbCAteSB3Z2V0IGNhLWNlcnRpZmljYXRlcyAmJiBybSAtcmYgL3Zhci9saWIvYXB0L2xpc3RzLyoKCkFSRyBTRVJWSUNFX0RJUl9OQU1FCldPUktESVIgL3Vzci9zcmMvYXBwLyRTRVJWSUNFX0RJUl9OQU1FCgpDT1BZIC0tZnJvbT1kaXN0IC4gL3Vzci9zcmMvYXBwLyRTRVJWSUNFX0RJUl9OQU1FLwpDT1BZIC0tZnJvbT1zaGFyZWQgLiAvCgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UubGljZW5zZXM9TUlUCkxBQkVMIG9yZy5vcGVuY29udGFpbmVycy5pbWFnZS50aXRsZT0kSU1BR0VfVElUTEUKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLnZlcnNpb249JFJFTEVBU0UKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLmRlc2NyaXB0aW9uPSRJTUFHRV9ERVNDUklQVElPTgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UuYXV0aG9ycz0iVGhlIEd1aWxkIgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UudmVuZG9yPSJLYW1pbCBLaXNpZWxhIgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UudXJsPSJodHRwczovL2dpdGh1Yi5jb20vZ3JhcGhxbC1oaXZlL3BsYXRmb3JtIgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2Uuc291cmNlPSJodHRwczovL2dpdGh1Yi5jb20vZ3JhcGhxbC1oaXZlL3BsYXRmb3JtIgoKRU5WIEVOVklST05NRU5UIHByb2R1Y3Rpb24KRU5WIFJFTEVBU0UgJFJFTEVBU0UKRU5WIFBPUlQgJFBPUlQKCkhFQUxUSENIRUNLIC0taW50ZXJ2YWw9NXMgXAogIC0tdGltZW91dD01cyBcCiAgLS1zdGFydC1wZXJpb2Q9NXMgXAogIC0tcmV0cmllcz02IFwKICBDTUQgJEhFQUxUSENIRUNLX0NNRAoKRU5UUllQT0lOVCBbICIvZW50cnlwb2ludC5zaCIgXQo=",
"language": "Dockerfile"
},
"range": [
{
"start": {
"line": 22
},
"end": {
"line": 22
}
}
]
},
{
"vertex": "sha256:59a8da04ea58a18a470e2c684d98bcf4c0dda6f1910759e2051c3d7ab1a2f119",
"level": 1,
"short": "TGVnYWN5S2V5VmFsdWVGb3JtYXQ6ICJFTlYga2V5PXZhbHVlIiBzaG91bGQgYmUgdXNlZCBpbnN0ZWFkIG9mIGxlZ2FjeSAiRU5WIGtleSB2YWx1ZSIgZm9ybWF0IChsaW5lIDEwKQ==",
"detail": [
"TGVnYWN5IGtleS92YWx1ZSBmb3JtYXQgd2l0aCB3aGl0ZXNwYWNlIHNlcGFyYXRvciBzaG91bGQgbm90IGJlIHVzZWQ="
],
"url": "https://docs.docker.com/go/dockerfile/rule/legacy-key-value-format/",
"sourceInfo": {
"filename": "migrations.dockerfile",
"data": "RlJPTSBub2RlOjIyLjEzLjAtc2xpbQoKUlVOIGFwdC1nZXQgdXBkYXRlICYmIGFwdC1nZXQgaW5zdGFsbCAteSBjYS1jZXJ0aWZpY2F0ZXMKCldPUktESVIgL3Vzci9zcmMvYXBwCgpDT1BZIC0tZnJvbT1kaXN0IC4gL3Vzci9zcmMvYXBwLwpDT1BZIC0tZnJvbT1zaGFyZWQgLiAvCgpFTlYgRU5WSVJPTk1FTlQgcHJvZHVjdGlvbgpFTlYgTk9ERV9FTlYgcHJvZHVjdGlvbgpFTlYgUkVMRUFTRSAkUkVMRUFTRQoKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLmxpY2Vuc2VzPU1JVApMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UudGl0bGU9JElNQUdFX1RJVExFCkxBQkVMIG9yZy5vcGVuY29udGFpbmVycy5pbWFnZS52ZXJzaW9uPSRSRUxFQVNFCkxBQkVMIG9yZy5vcGVuY29udGFpbmVycy5pbWFnZS5kZXNjcmlwdGlvbj0kSU1BR0VfREVTQ1JJUFRJT04KTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLmF1dGhvcnM9IlRoZSBHdWlsZCIKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLnZlbmRvcj0iS2FtaWwgS2lzaWVsYSIKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLnVybD0iaHR0cHM6Ly9naXRodWIuY29tL2dyYXBocWwtaGl2ZS9wbGF0Zm9ybSIKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLnNvdXJjZT0iaHR0cHM6Ly9naXRodWIuY29tL2dyYXBocWwtaGl2ZS9wbGF0Zm9ybSIKCkVOVFJZUE9JTlQgWyAiL2VudHJ5cG9pbnQuc2giIF0K",
"language": "Dockerfile"
},
"range": [
{
"start": {
"line": 10
},
"end": {
"line": 10
}
}
]
}
],
"composition-federation-2": {
"buildx.build.provenance": {
"buildType": "https://mobyproject.org/buildkit@v1",
"materials": [
{
"uri": "pkg:docker/[email protected]?platform=linux%2Farm64",
"digest": {
"sha256": "f5a0871ab03b035c58bdb3007c3d177b001c2145c18e81817b71624dcf7d8bff"
}
}
],
"invocation": {
"configSource": {
"entryPoint": "services.dockerfile"
},
"parameters": {
"frontend": "dockerfile.v0",
"args": {
"build-arg:HEALTHCHECK_CMD": "wget --spider -q http://127.0.0.1:${PORT}/_readiness",
"build-arg:IMAGE_DESCRIPTION": "Federation 2 Composition Service for GraphQL Hive.",
"build-arg:IMAGE_TITLE": "graphql-hive/composition-federation-2",
"build-arg:PORT": "3069",
"build-arg:RELEASE": "8a1c77f9b1566ad7b9c083096f037f8d7016ccab",
"build-arg:SERVICE_DIR_NAME": "@hive/external-composition",
"context:dist": "local:dist",
"context:shared": "local:shared",
"frontend.caps": "moby.buildkit.frontend.contexts+forward",
"local-sessionid:context": "v4dxzzj3i8m6vdnjmtxpxh1ox",
"local-sessionid:dockerfile": "v4dxzzj3i8m6vdnjmtxpxh1ox",
"local-sessionid:shared": "v4dxzzj3i8m6vdnjmtxpxh1ox"
},
"locals": [
{
"name": "context"
},
{
"name": "dist"
},
{
"name": "dockerfile"
},
{
"name": "shared"
}
]
},
"environment": {
"platform": "linux/arm64"
}
}
},
"buildx.build.ref": "builder-bf5a90c8-9a8c-4791-8413-f17b284c4c49/builder-bf5a90c8-9a8c-4791-8413-f17b284c4c490/6ikd82ghrz98nsrj7e6u0p4bc",
"containerimage.config.digest": "sha256:f7bbb4ad4cae5468c997ae6533c30d729863381884fe3cbf63f0f71d86173fb6",
"containerimage.descriptor": {
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
"digest": "sha256:82df5c1e33f9d594b0a591350b8fdf17f0c0079429300da46a906787684772d5",
"size": 2075,
"platform": {
"architecture": "arm64",
"os": "linux"
}
},
"containerimage.digest": "sha256:82df5c1e33f9d594b0a591350b8fdf17f0c0079429300da46a906787684772d5",
"image.name": "ghcr.io/graphql-hive/composition-federation-2:8a1c77f9b1566ad7b9c083096f037f8d7016ccab-arm64,ghcr.io/graphql-hive/composition-federation-2:console_994-arm64"
},
"emails": {
"buildx.build.provenance": {
"buildType": "https://mobyproject.org/buildkit@v1",
"materials": [
{
"uri": "pkg:docker/[email protected]?platform=linux%2Farm64",
"digest": {
"sha256": "f5a0871ab03b035c58bdb3007c3d177b001c2145c18e81817b71624dcf7d8bff"
}
}
],
"invocation": {
"configSource": {
"entryPoint": "services.dockerfile"
},
"parameters": {
"frontend": "dockerfile.v0",
"args": {
"build-arg:HEALTHCHECK_CMD": "wget --spider -q http://127.0.0.1:${PORT}/_readiness",
"build-arg:IMAGE_DESCRIPTION": "The emails service of the GraphQL Hive project.",
"build-arg:IMAGE_TITLE": "graphql-hive/emails",
"build-arg:PORT": "3006",
"build-arg:RELEASE": "8a1c77f9b1566ad7b9c083096f037f8d7016ccab",
"build-arg:SERVICE_DIR_NAME": "@hive/emails",
"context:dist": "local:dist",
"context:shared": "local:shared",
"frontend.caps": "moby.buildkit.frontend.contexts+forward",
"local-sessionid:context": "v4dxzzj3i8m6vdnjmtxpxh1ox",
"local-sessionid:dockerfile": "v4dxzzj3i8m6vdnjmtxpxh1ox",
"local-sessionid:shared": "v4dxzzj3i8m6vdnjmtxpxh1ox"
},
"locals": [
{
"name": "context"
},
{
"name": "dist"
},
{
"name": "dockerfile"
},
{
"name": "shared"
}
]
},
"environment": {
"platform": "linux/arm64"
}
}
},
"buildx.build.ref": "builder-bf5a90c8-9a8c-4791-8413-f17b284c4c49/builder-bf5a90c8-9a8c-4791-8413-f17b284c4c490/r86bu5c5n617ka3c4t0s7k5di",
"containerimage.config.digest": "sha256:17ee283b92e1e9a29e0772135fea4e3349d0b0e16207aa0da85718478bff6952",
"containerimage.descriptor": {
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
"digest": "sha256:e74466e6f42535138e85759bf7513b37eec70590fc1f1a04d83a366c8073ccb8",
"size": 2075,
"platform": {
"architecture": "arm64",
"os": "linux"
}
},
"containerimage.digest": "sha256:e74466e6f42535138e85759bf7513b37eec70590fc1f1a04d83a366c8073ccb8",
"image.name": "ghcr.io/graphql-hive/emails:8a1c77f9b1566ad7b9c083096f037f8d7016ccab-arm64,ghcr.io/graphql-hive/emails:console_994-arm64"
},
"policy": {
"buildx.build.provenance": {
"buildType": "https://mobyproject.org/buildkit@v1",
"materials": [
{
"uri": "pkg:docker/[email protected]?platform=linux%2Farm64",
"digest": {
"sha256": "f5a0871ab03b035c58bdb3007c3d177b001c2145c18e81817b71624dcf7d8bff"
}
}
],
"invocation": {
"configSource": {
"entryPoint": "services.dockerfile"
},
"parameters": {
"frontend": "dockerfile.v0",
"args": {
"build-arg:HEALTHCHECK_CMD": "wget --spider -q http://127.0.0.1:${PORT}/_readiness",
"build-arg:IMAGE_DESCRIPTION": "The policy service of the GraphQL Hive project.",
"build-arg:IMAGE_TITLE": "graphql-hive/policy",
"build-arg:PORT": "3012",
"build-arg:RELEASE": "8a1c77f9b1566ad7b9c083096f037f8d7016ccab",
"build-arg:SERVICE_DIR_NAME": "@hive/policy",
"context:dist": "local:dist",
"context:shared": "local:shared",
"frontend.caps": "moby.buildkit.frontend.contexts+forward",
"local-sessionid:context": "v4dxzzj3i8m6vdnjmtxpxh1ox",
"local-sessionid:dockerfile": "v4dxzzj3i8m6vdnjmtxpxh1ox",
"local-sessionid:shared": "v4dxzzj3i8m6vdnjmtxpxh1ox"
},
"locals": [
{
"name": "context"
},
{
"name": "dist"
},
{
"name": "dockerfile"
},
{
"name": "shared"
}
]
},
"environment": {
"platform": "linux/arm64"
}
}
},
"buildx.build.ref": "builder-bf5a90c8-9a8c-4791-8413-f17b284c4c49/builder-bf5a90c8-9a8c-4791-8413-f17b284c4c490/m20s74xf3ri8kic0pd2d65oe8",
"containerimage.config.digest": "sha256:9e2386a323842267b26d61b4ae1a1eacb84593a3218651702fc93b28672b1552",
"containerimage.descriptor": {
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
"digest": "sha256:420eda98eae5b3ab63aafd51a0fc0db48c98c9f144fc673cbe717637e5cf0544",
"size": 2075,
"platform": {
"architecture": "arm64",
"os": "linux"
}
},
"containerimage.digest": "sha256:420eda98eae5b3ab63aafd51a0fc0db48c98c9f144fc673cbe717637e5cf0544",
"image.name": "ghcr.io/graphql-hive/policy:8a1c77f9b1566ad7b9c083096f037f8d7016ccab-arm64,ghcr.io/graphql-hive/policy:console_994-arm64"
},
"rate-limit": {
"buildx.build.provenance": {
"buildType": "https://mobyproject.org/buildkit@v1",
"materials": [
{
"uri": "pkg:docker/[email protected]?platform=linux%2Farm64",
"digest": {
"sha256": "f5a0871ab03b035c58bdb3007c3d177b001c2145c18e81817b71624dcf7d8bff"
}
}
],
"invocation": {
"configSource": {
"entryPoint": "services.dockerfile"
},
"parameters": {
"frontend": "dockerfile.v0",
"args": {
"build-arg:HEALTHCHECK_CMD": "wget --spider -q http://127.0.0.1:${PORT}/_readiness",
"build-arg:IMAGE_DESCRIPTION": "The rate limit service of the GraphQL Hive project.",
"build-arg:IMAGE_TITLE": "graphql-hive/rate-limit",
"build-arg:PORT": "3009",
"build-arg:RELEASE": "8a1c77f9b1566ad7b9c083096f037f8d7016ccab",
"build-arg:SERVICE_DIR_NAME": "@hive/rate-limit",
"context:dist": "local:dist",
"context:shared": "local:shared",
"frontend.caps": "moby.buildkit.frontend.contexts+forward",
"local-sessionid:context": "v4dxzzj3i8m6vdnjmtxpxh1ox",
"local-sessionid:dockerfile": "v4dxzzj3i8m6vdnjmtxpxh1ox",
"local-sessionid:shared": "v4dxzzj3i8m6vdnjmtxpxh1ox"
},
"locals": [
{
"name": "context"
},
{
"name": "dist"
},
{
"name": "dockerfile"
},
{
"name": "shared"
}
]
},
"environment": {
"platform": "linux/arm64"
}
}
},
"buildx.build.ref": "builder-bf5a90c8-9a8c-4791-8413-f17b284c4c49/builder-bf5a90c8-9a8c-4791-8413-f17b284c4c490/7yhxz5ir9olk2htsv28itllh2",
"containerimage.config.digest": "sha256:7192d0984e6aa43af5233b751516efb376ce68b70c553ad5402fce2dd6c7414f",
"containerimage.descriptor": {
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
"digest": "sha256:5cdc0ae55b092101f8615851da7e6dda2576d2d07768b8eb48bf21b908863d21",
"size": 2075,
"platform": {
"architecture": "arm64",
"os": "linux"
}
},
"containerimage.digest": "sha256:5cdc0ae55b092101f8615851da7e6dda2576d2d07768b8eb48bf21b908863d21",
"image.name": "ghcr.io/graphql-hive/rate-limit:8a1c77f9b1566ad7b9c083096f037f8d7016ccab-arm64,ghcr.io/graphql-hive/rate-limit:console_994-arm64"
},
"schema": {
"buildx.build.provenance": {
"buildType": "https://mobyproject.org/buildkit@v1",
"materials": [
{
"uri": "pkg:docker/[email protected]?platform=linux%2Farm64",
"digest": {
"sha256": "f5a0871ab03b035c58bdb3007c3d177b001c2145c18e81817b71624dcf7d8bff"
}
}
],
"invocation": {
"configSource": {
"entryPoint": "services.dockerfile"
},
"parameters": {
"frontend": "dockerfile.v0",
"args": {
"build-arg:HEALTHCHECK_CMD": "wget --spider -q http://127.0.0.1:${PORT}/_readiness",
"build-arg:IMAGE_DESCRIPTION": "The schema service of the GraphQL Hive project.",
"build-arg:IMAGE_TITLE": "graphql-hive/schema",
"build-arg:PORT": "3002",
"build-arg:RELEASE": "8a1c77f9b1566ad7b9c083096f037f8d7016ccab",
"build-arg:SERVICE_DIR_NAME": "@hive/schema",
"context:dist": "local:dist",
"context:shared": "local:shared",
"frontend.caps": "moby.buildkit.frontend.contexts+forward",
"local-sessionid:context": "v4dxzzj3i8m6vdnjmtxpxh1ox",
"local-sessionid:dockerfile": "v4dxzzj3i8m6vdnjmtxpxh1ox",
"local-sessionid:shared": "v4dxzzj3i8m6vdnjmtxpxh1ox"
},
"locals": [
{
"name": "context"
},
{
"name": "dist"
},
{
"name": "dockerfile"
},
{
"name": "shared"
}
]
},
"environment": {
"platform": "linux/arm64"
}
}
},
"buildx.build.ref": "builder-bf5a90c8-9a8c-4791-8413-f17b284c4c49/builder-bf5a90c8-9a8c-4791-8413-f17b284c4c490/l3xwvl2hkfzlgq6mkij45gpss",
"containerimage.config.digest": "sha256:c8c93b87d3f5b0f7e4006eb1e8f7aa408fd0527559c064b7d0716042a471c54a",
"containerimage.descriptor": {
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
"digest": "sha256:6d3d8584a9e1e5693be1686a9d8267ee9e1d48568ed4a0bee428e3ac7b6739b5",
"size": 2075,
"platform": {
"architecture": "arm64",
"os": "linux"
}
},
"containerimage.digest": "sha256:6d3d8584a9e1e5693be1686a9d8267ee9e1d48568ed4a0bee428e3ac7b6739b5",
"image.name": "ghcr.io/graphql-hive/schema:8a1c77f9b1566ad7b9c083096f037f8d7016ccab-arm64,ghcr.io/graphql-hive/schema:console_994-arm64"
},
"server": {
"buildx.build.provenance": {
"buildType": "https://mobyproject.org/buildkit@v1",
"materials": [
{
"uri": "pkg:docker/[email protected]?platform=linux%2Farm64",
"digest": {
"sha256": "f5a0871ab03b035c58bdb3007c3d177b001c2145c18e81817b71624dcf7d8bff"
}
}
],
"invocation": {
"configSource": {
"entryPoint": "services.dockerfile"
},
"parameters": {
"frontend": "dockerfile.v0",
"args": {
"build-arg:HEALTHCHECK_CMD": "wget --spider -q http://127.0.0.1:${PORT}/_readiness",
"build-arg:IMAGE_DESCRIPTION": "The server service of the GraphQL Hive project.",
"build-arg:IMAGE_TITLE": "graphql-hive/server",
"build-arg:PORT": "3001",
"build-arg:RELEASE": "8a1c77f9b1566ad7b9c083096f037f8d7016ccab",
"build-arg:SERVICE_DIR_NAME": "@hive/server",
"context:dist": "local:dist",
"context:shared": "local:shared",
"frontend.caps": "moby.buildkit.frontend.contexts+forward",
"local-sessionid:context": "v4dxzzj3i8m6vdnjmtxpxh1ox",
"local-sessionid:dockerfile": "v4dxzzj3i8m6vdnjmtxpxh1ox",
"local-sessionid:shared": "v4dxzzj3i8m6vdnjmtxpxh1ox"
},
"locals": [
{
"name": "context"
},
{
"name": "dist"
},
{
"name": "dockerfile"
},
{
"name": "shared"
}
]
},
"environment": {
"platform": "linux/arm64"
}
}
},
"buildx.build.ref": "builder-bf5a90c8-9a8c-4791-8413-f17b284c4c49/builder-bf5a90c8-9a8c-4791-8413-f17b284c4c490/yrc5mxa0umfbver31s99pw4vn",
"containerimage.config.digest": "sha256:982dc5f6870494c9e9e2933a6c31e9bfe5bf44c38b078cc1631c94cdc5ca17b8",
"containerimage.descriptor": {
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
"digest": "sha256:888f477cd86e247e096997b7141ba4e4dc96067ea142521b793dc07268275490",
"size": 2076,
"platform": {
"architecture": "arm64",
"os": "linux"
}
},
"containerimage.digest": "sha256:888f477cd86e247e096997b7141ba4e4dc96067ea142521b793dc07268275490",
"image.name": "ghcr.io/graphql-hive/server:8a1c77f9b1566ad7b9c083096f037f8d7016ccab-arm64,ghcr.io/graphql-hive/server:console_994-arm64"
},
"storage": {
"buildx.build.provenance": {
"buildType": "https://mobyproject.org/buildkit@v1",
"materials": [
{
"uri": "pkg:docker/[email protected]?platform=linux%2Farm64",
"digest": {
"sha256": "f5a0871ab03b035c58bdb3007c3d177b001c2145c18e81817b71624dcf7d8bff"
}
}
],
"invocation": {
"configSource": {
"entryPoint": "migrations.dockerfile"
},
"parameters": {
"frontend": "dockerfile.v0",
"args": {
"build-arg:IMAGE_DESCRIPTION": "The migrations service of the GraphQL Hive project.",
"build-arg:IMAGE_TITLE": "graphql-hive/storage",
"build-arg:RELEASE": "8a1c77f9b1566ad7b9c083096f037f8d7016ccab",
"context:dist": "local:dist",
"context:shared": "local:shared",
"frontend.caps": "moby.buildkit.frontend.contexts+forward",
"local-sessionid:context": "v4dxzzj3i8m6vdnjmtxpxh1ox",
"local-sessionid:dockerfile": "v4dxzzj3i8m6vdnjmtxpxh1ox",
"local-sessionid:shared": "v4dxzzj3i8m6vdnjmtxpxh1ox"
},
"locals": [
{
"name": "context"
},
{
"name": "dist"
},
{
"name": "dockerfile"
},
{
"name": "shared"
}
]
},
"environment": {
"platform": "linux/arm64"
}
}
},
"buildx.build.ref": "builder-bf5a90c8-9a8c-4791-8413-f17b284c4c49/builder-bf5a90c8-9a8c-4791-8413-f17b284c4c490/u9tib12z1szfy3yt1m0q8t2rn",
"containerimage.config.digest": "sha256:14afd993f5555b7fec46b3c86ba11016a9f8352cc72e2e3c3b56ee76eff9e51a",
"containerimage.descriptor": {
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
"digest": "sha256:52c67e5c0c16f31cd943ab21865d01600418f928a6357785ea323df0dd1896fa",
"size": 2075,
"platform": {
"architecture": "arm64",
"os": "linux"
}
},
"containerimage.digest": "sha256:52c67e5c0c16f31cd943ab21865d01600418f928a6357785ea323df0dd1896fa",
"image.name": "ghcr.io/graphql-hive/storage:8a1c77f9b1566ad7b9c083096f037f8d7016ccab-arm64,ghcr.io/graphql-hive/storage:console_994-arm64"
},
"stripe-billing": {
"buildx.build.provenance": {
"buildType": "https://mobyproject.org/buildkit@v1",
"materials": [
{
"uri": "pkg:docker/[email protected]?platform=linux%2Farm64",
"digest": {
"sha256": "f5a0871ab03b035c58bdb3007c3d177b001c2145c18e81817b71624dcf7d8bff"
}
}
],
"invocation": {
"configSource": {
"entryPoint": "services.dockerfile"
},
"parameters": {
"frontend": "dockerfile.v0",
"args": {
"build-arg:HEALTHCHECK_CMD": "wget --spider -q http://127.0.0.1:${PORT}/_readiness",
"build-arg:IMAGE_DESCRIPTION": "The stripe billing service of the GraphQL Hive project.",
"build-arg:IMAGE_TITLE": "graphql-hive/stripe-billing",
"build-arg:PORT": "3010",
"build-arg:RELEASE": "8a1c77f9b1566ad7b9c083096f037f8d7016ccab",
"build-arg:SERVICE_DIR_NAME": "@hive/stripe-billing",
"context:dist": "local:dist",
"context:shared": "local:shared",
"frontend.caps": "moby.buildkit.frontend.contexts+forward",
"local-sessionid:context": "v4dxzzj3i8m6vdnjmtxpxh1ox",
"local-sessionid:dockerfile": "v4dxzzj3i8m6vdnjmtxpxh1ox",
"local-sessionid:shared": "v4dxzzj3i8m6vdnjmtxpxh1ox"
},
"locals": [
{
"name": "context"
},
{
"name": "dist"
},
{
"name": "dockerfile"
},
{
"name": "shared"
}
]
},
"environment": {
"platform": "linux/arm64"
}
}
},
"buildx.build.ref": "builder-bf5a90c8-9a8c-4791-8413-f17b284c4c49/builder-bf5a90c8-9a8c-4791-8413-f17b284c4c490/t3q9oifapf7wsukhc0pq3k5kd",
"containerimage.config.digest": "sha256:e7000c9149854d646c9d804a5f3e6935b06b0f759cd9175fa40eaf75d961bb4b",
"containerimage.descriptor": {
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
"digest": "sha256:61da472461916ebf6012074d6dc2ac11548501b33126564edce869d05d5969d7",
"size": 2075,
"platform": {
"architecture": "arm64",
"os": "linux"
}
},
"containerimage.digest": "sha256:61da472461916ebf6012074d6dc2ac11548501b33126564edce869d05d5969d7",
"image.name": "ghcr.io/graphql-hive/stripe-billing:8a1c77f9b1566ad7b9c083096f037f8d7016ccab-arm64,ghcr.io/graphql-hive/stripe-billing:console_994-arm64"
},
"tokens": {
"buildx.build.provenance": {
"buildType": "https://mobyproject.org/buildkit@v1",
"materials": [
{
"uri": "pkg:docker/[email protected]?platform=linux%2Farm64",
"digest": {
"sha256": "f5a0871ab03b035c58bdb3007c3d177b001c2145c18e81817b71624dcf7d8bff"
}
}
],
"invocation": {
"configSource": {
"entryPoint": "services.dockerfile"
},
"parameters": {
"frontend": "dockerfile.v0",
"args": {
"build-arg:HEALTHCHECK_CMD": "wget --spider -q http://127.0.0.1:${PORT}/_readiness",
"build-arg:IMAGE_DESCRIPTION": "The tokens service of the GraphQL Hive project.",
"build-arg:IMAGE_TITLE": "graphql-hive/tokens",
"build-arg:PORT": "3003",
"build-arg:RELEASE": "8a1c77f9b1566ad7b9c083096f037f8d7016ccab",
"build-arg:SERVICE_DIR_NAME": "@hive/tokens",
"context:dist": "local:dist",
"context:shared": "local:shared",
"frontend.caps": "moby.buildkit.frontend.contexts+forward",
"local-sessionid:context": "v4dxzzj3i8m6vdnjmtxpxh1ox",
"local-sessionid:dockerfile": "v4dxzzj3i8m6vdnjmtxpxh1ox",
"local-sessionid:shared": "v4dxzzj3i8m6vdnjmtxpxh1ox"
},
"locals": [
{
"name": "context"
},
{
"name": "dist"
},
{
"name": "dockerfile"
},
{
"name": "shared"
}
]
},
"environment": {
"platform": "linux/arm64"
}
}
},
"buildx.build.ref": "builder-bf5a90c8-9a8c-4791-8413-f17b284c4c49/builder-bf5a90c8-9a8c-4791-8413-f17b284c4c490/cl2t796dlu4i4omm6adef6raq",
"containerimage.config.digest": "sha256:f8671d55db6ad7270a0e90572f46ece82563198a2d4d53640bf7f27b8f8de730",
"containerimage.descriptor": {
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
"digest": "sha256:a14a8d6d489094d077812d45236644ea4d9da81cbba8bda626cdeffb256c7982",
"size": 2075,
"platform": {
"architecture": "arm64",
"os": "linux"
}
},
"containerimage.digest": "sha256:a14a8d6d489094d077812d45236644ea4d9da81cbba8bda626cdeffb256c7982",
"image.name": "ghcr.io/graphql-hive/tokens:8a1c77f9b1566ad7b9c083096f037f8d7016ccab-arm64,ghcr.io/graphql-hive/tokens:console_994-arm64"
},
"usage": {
"buildx.build.provenance": {
"buildType": "https://mobyproject.org/buildkit@v1",
"materials": [
{
"uri": "pkg:docker/[email protected]?platform=linux%2Farm64",
"digest": {
"sha256": "f5a0871ab03b035c58bdb3007c3d177b001c2145c18e81817b71624dcf7d8bff"
}
}
],
"invocation": {
"configSource": {
"entryPoint": "services.dockerfile"
},
"parameters": {
"frontend": "dockerfile.v0",
"args": {
"build-arg:HEALTHCHECK_CMD": "wget --spider -q http://127.0.0.1:${PORT}/_readiness",
"build-arg:IMAGE_DESCRIPTION": "The usage ingestor service of the GraphQL Hive project.",
"build-arg:IMAGE_TITLE": "graphql-hive/usage",
"build-arg:PORT": "3006",
"build-arg:RELEASE": "8a1c77f9b1566ad7b9c083096f037f8d7016ccab",
"build-arg:SERVICE_DIR_NAME": "@hive/usage",
"context:dist": "local:dist",
"context:shared": "local:shared",
"frontend.caps": "moby.buildkit.frontend.contexts+forward",
"local-sessionid:context": "v4dxzzj3i8m6vdnjmtxpxh1ox",
"local-sessionid:dockerfile": "v4dxzzj3i8m6vdnjmtxpxh1ox",
"local-sessionid:shared": "v4dxzzj3i8m6vdnjmtxpxh1ox"
},
"locals": [
{
"name": "context"
},
{
"name": "dist"
},
{
"name": "dockerfile"
},
{
"name": "shared"
}
]
},
"environment": {
"platform": "linux/arm64"
}
}
},
"buildx.build.ref": "builder-bf5a90c8-9a8c-4791-8413-f17b284c4c49/builder-bf5a90c8-9a8c-4791-8413-f17b284c4c490/tt7g10roheynmnbdi5spk20dq",
"containerimage.config.digest": "sha256:30aa66781cce978287971b2e74db318b8eabe82b95eb7d3634ec1cc5ee63f8f0",
"containerimage.descriptor": {
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
"digest": "sha256:48eff8bcf0d0fb095d27f5879297dba21644c6bb80fd5b89b04d689467ae0df2",
"size": 2075,
"platform": {
"architecture": "arm64",
"os": "linux"
}
},
"containerimage.digest": "sha256:48eff8bcf0d0fb095d27f5879297dba21644c6bb80fd5b89b04d689467ae0df2",
"image.name": "ghcr.io/graphql-hive/usage:8a1c77f9b1566ad7b9c083096f037f8d7016ccab-arm64,ghcr.io/graphql-hive/usage:console_994-arm64"
},
"usage-estimator": {
"buildx.build.provenance": {
"buildType": "https://mobyproject.org/buildkit@v1",
"materials": [
{
"uri": "pkg:docker/[email protected]?platform=linux%2Farm64",
"digest": {
"sha256": "f5a0871ab03b035c58bdb3007c3d177b001c2145c18e81817b71624dcf7d8bff"
}
}
],
"invocation": {
"configSource": {
"entryPoint": "services.dockerfile"
},
"parameters": {
"frontend": "dockerfile.v0",
"args": {
"build-arg:HEALTHCHECK_CMD": "wget --spider -q http://127.0.0.1:${PORT}/_readiness",
"build-arg:IMAGE_DESCRIPTION": "The usage estimator service of the GraphQL Hive project.",
"build-arg:IMAGE_TITLE": "graphql-hive/usage-estimator",
"build-arg:PORT": "3008",
"build-arg:RELEASE": "8a1c77f9b1566ad7b9c083096f037f8d7016ccab",
"build-arg:SERVICE_DIR_NAME": "@hive/usage-estimator",
"context:dist": "local:dist",
"context:shared": "local:shared",
"frontend.caps": "moby.buildkit.frontend.contexts+forward",
"local-sessionid:context": "v4dxzzj3i8m6vdnjmtxpxh1ox",
"local-sessionid:dockerfile": "v4dxzzj3i8m6vdnjmtxpxh1ox",
"local-sessionid:shared": "v4dxzzj3i8m6vdnjmtxpxh1ox"
},
"locals": [
{
"name": "context"
},
{
"name": "dist"
},
{
"name": "dockerfile"
},
{
"name": "shared"
}
]
},
"environment": {
"platform": "linux/arm64"
}
}
},
"buildx.build.ref": "builder-bf5a90c8-9a8c-4791-8413-f17b284c4c49/builder-bf5a90c8-9a8c-4791-8413-f17b284c4c490/jr39o6110vfmd0mpruztqdzoh",
"containerimage.config.digest": "sha256:e5dc1dd8dfe645ee1cf3249f14e85939cae30a6416aab8f19bc629f376f8d66b",
"containerimage.descriptor": {
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
"digest": "sha256:889ab2802807bbfaef1c1b5f0a4172c714702ce51931dd4e6af1663decd6756e",
"size": 2075,
"platform": {
"architecture": "arm64",
"os": "linux"
}
},
"containerimage.digest": "sha256:889ab2802807bbfaef1c1b5f0a4172c714702ce51931dd4e6af1663decd6756e",
"image.name": "ghcr.io/graphql-hive/usage-estimator:8a1c77f9b1566ad7b9c083096f037f8d7016ccab-arm64,ghcr.io/graphql-hive/usage-estimator:console_994-arm64"
},
"usage-ingestor": {
"buildx.build.provenance": {
"buildType": "https://mobyproject.org/buildkit@v1",
"materials": [
{
"uri": "pkg:docker/[email protected]?platform=linux%2Farm64",
"digest": {
"sha256": "f5a0871ab03b035c58bdb3007c3d177b001c2145c18e81817b71624dcf7d8bff"
}
}
],
"invocation": {
"configSource": {
"entryPoint": "services.dockerfile"
},
"parameters": {
"frontend": "dockerfile.v0",
"args": {
"build-arg:HEALTHCHECK_CMD": "wget --spider -q http://127.0.0.1:${PORT}/_readiness",
"build-arg:IMAGE_DESCRIPTION": "The usage ingestor service of the GraphQL Hive project.",
"build-arg:IMAGE_TITLE": "graphql-hive/usage-ingestor",
"build-arg:PORT": "3007",
"build-arg:RELEASE": "8a1c77f9b1566ad7b9c083096f037f8d7016ccab",
"build-arg:SERVICE_DIR_NAME": "@hive/usage-ingestor",
"context:dist": "local:dist",
"context:shared": "local:shared",
"frontend.caps": "moby.buildkit.frontend.contexts+forward",
"local-sessionid:context": "v4dxzzj3i8m6vdnjmtxpxh1ox",
"local-sessionid:dockerfile": "v4dxzzj3i8m6vdnjmtxpxh1ox",
"local-sessionid:shared": "v4dxzzj3i8m6vdnjmtxpxh1ox"
},
"locals": [
{
"name": "context"
},
{
"name": "dist"
},
{
"name": "dockerfile"
},
{
"name": "shared"
}
]
},
"environment": {
"platform": "linux/arm64"
}
}
},
"buildx.build.ref": "builder-bf5a90c8-9a8c-4791-8413-f17b284c4c49/builder-bf5a90c8-9a8c-4791-8413-f17b284c4c490/x4m5rtg5loioo4580zkztpa7o",
"containerimage.config.digest": "sha256:eb9e161d1127b5c3888578059cc26f0aa30c0c81f7a845e23d176090cef259dd",
"containerimage.descriptor": {
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
"digest": "sha256:37052072df60cb124efb9c1beb5dadcba010312a695e82a18476cfe300b3ecb3",
"size": 2075,
"platform": {
"architecture": "arm64",
"os": "linux"
}
},
"containerimage.digest": "sha256:37052072df60cb124efb9c1beb5dadcba010312a695e82a18476cfe300b3ecb3",
"image.name": "ghcr.io/graphql-hive/usage-ingestor:8a1c77f9b1566ad7b9c083096f037f8d7016ccab-arm64,ghcr.io/graphql-hive/usage-ingestor:console_994-arm64"
},
"webhooks": {
"buildx.build.provenance": {
"buildType": "https://mobyproject.org/buildkit@v1",
"materials": [
{
"uri": "pkg:docker/[email protected]?platform=linux%2Farm64",
"digest": {
"sha256": "f5a0871ab03b035c58bdb3007c3d177b001c2145c18e81817b71624dcf7d8bff"
}
}
],
"invocation": {
"configSource": {
"entryPoint": "services.dockerfile"
},
"parameters": {
"frontend": "dockerfile.v0",
"args": {
"build-arg:HEALTHCHECK_CMD": "wget --spider -q http://127.0.0.1:${PORT}/_readiness",
"build-arg:IMAGE_DESCRIPTION": "The webhooks ingestor service of the GraphQL Hive project.",
"build-arg:IMAGE_TITLE": "graphql-hive/webhooks",
"build-arg:PORT": "3005",
"build-arg:RELEASE": "8a1c77f9b1566ad7b9c083096f037f8d7016ccab",
"build-arg:SERVICE_DIR_NAME": "@hive/webhooks",
"context:dist": "local:dist",
"context:shared": "local:shared",
"frontend.caps": "moby.buildkit.frontend.contexts+forward",
"local-sessionid:context": "v4dxzzj3i8m6vdnjmtxpxh1ox",
"local-sessionid:dockerfile": "v4dxzzj3i8m6vdnjmtxpxh1ox",
"local-sessionid:shared": "v4dxzzj3i8m6vdnjmtxpxh1ox"
},
"locals": [
{
"name": "context"
},
{
"name": "dist"
},
{
"name": "dockerfile"
},
{
"name": "shared"
}
]
},
"environment": {
"platform": "linux/arm64"
}
}
},
"buildx.build.ref": "builder-bf5a90c8-9a8c-4791-8413-f17b284c4c49/builder-bf5a90c8-9a8c-4791-8413-f17b284c4c490/ybr52jgi8w35jjvpu3d3usgvz",
"containerimage.config.digest": "sha256:3ebab1fa92bfdf6f33e74b8f2a0de0fa876e524829e763a1a4fb6ae3ea199c09",
"containerimage.descriptor": {
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
"digest": "sha256:de8f2c4cef2b1fbd6ef4fc31694c700e749a0032117a9b89b619feb0d640742a",
"size": 2075,
"platform": {
"architecture": "arm64",
"os": "linux"
}
},
"containerimage.digest": "sha256:de8f2c4cef2b1fbd6ef4fc31694c700e749a0032117a9b89b619feb0d640742a",
"image.name": "ghcr.io/graphql-hive/webhooks:8a1c77f9b1566ad7b9c083096f037f8d7016ccab-arm64,ghcr.io/graphql-hive/webhooks:console_994-arm64"
}
} |
This comment was marked as resolved.
This comment was marked as resolved.
Still need to add an E2E test but rest is generally ready for review. |
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.
Actionable comments posted: 0
🧹 Nitpick comments (12)
packages/web/app/src/lib/hooks/use-local-storage.ts (2)
4-5
: Good approach to support both string and versioned specs.
Allowing thekey
parameter to be either a string or aVersionedEntrySpec
provides flexibility for future scaling while preserving backward compatibility. Consider documenting this change prominently to avoid confusion about passing arrays vs. single keys.
14-14
: Clarify usage of the first versioned entry key.
Storing toversionedEntry[0].key
effectively treats the earliest spec as canonical, but if additional spec entries exist, you may want a clearer rationale for always writing only to the first entry. If you plan to keep multiple versions, consider how you might handle writes across them.packages/web/app/src/lib/versioned-entry.ts (2)
41-92
: Check the removal logic for prior entries.
By default,previousEntriesPolicy
isignore
, but if set toremove
, previous entries are immediately removed (lines 75–77). In scenarios where the user wants to copy forward without deleting, a dedicated policy or approach may be beneficial. Currently, “ignore” might already solve copying-only use cases, but adding an explicit “copyOnly” policy could block unintentional removals.
105-115
: Local and memory-based implementations are straightforward.
BothkeyValueStoreLocalStorage
andcreateKeyValueStoreMemory
are well-structured. Keep in mind potential synchronization or concurrency issues (e.g., if localStorage is modified across tabs). For the memory store, mention lifespan or disposal strategy in docs if used for ephemeral testing.Also applies to: 117-117, 119-129
packages/web/app/src/lib/hooks/use-local-storage-json.ts (3)
8-8
: Similar pattern for versioned key logic.
Wrapping astring
in an array forVersionedEntrySpec
is a neat trick to unify the usage. Continually ensure the approach remains intuitive for future maintainers.
55-55
: Storing JSON with the first spec key.
As withuseLocalStorage
, writing toversionedEntry[0].key
is consistent, but double-check if multiple version keys must be updated or if the rest should remain.
75-75
: Explicit union for key input is valuable.
type KeyInput = string | VersionedEntrySpec;
clarifies permissible usage. Document typical usage patterns, so others know how to pass either a simple key string or a fully versioned spec.Also applies to: 80-80
packages/web/app/src/lib/versioned-entry.spec.ts (2)
22-52
: Enhance test descriptions for better clarity.While the test cases are comprehensive, the descriptions could be more descriptive to better communicate the test scenarios.
Consider updating the test descriptions to be more explicit about what's being tested. For example:
- // Returns null if spec key is missing in db + // Should return null when the specified key is not present in the database { spec: [{ key:a }], databaseBefore: {}, databaseAfter: {}, value: null }, { spec: [{ key:a }], databaseBefore: {b}, databaseAfter: {b}, value: null }, - // Returns value if spec key is present in db + // Should return the value when the specified key exists in the database { spec: [{ key:a }], databaseBefore: {a}, databaseAfter: {a}, value: a },
54-60
: Add assertions for database state validation.The test could benefit from more specific assertions about the database state.
Consider adding assertions to validate specific aspects of the database state:
({ databaseBefore, databaseAfter, spec, value, previousEntriesPolicy }) => { const readVersionedEntryMemory = readVersionedEntry(createKeyValueStoreMemory(databaseBefore)); const valueActual = readVersionedEntryMemory({spec, previousEntriesPolicy}) - expect(databaseBefore).toEqual(databaseAfter) + // Assert specific aspects of the database state + expect(Object.keys(databaseBefore).length).toEqual(Object.keys(databaseAfter).length) + expect(Object.keys(databaseAfter)).toContain(spec[0].key) expect(valueActual).toEqual(value) },cypress/e2e/laboratory-preflight.cy.ts (1)
61-61
: Address the TODO comment for target ID inclusion.The TODO comment indicates that this test needs to be updated to include a target ID, which aligns with the new target-scoped environment variables feature.
Would you like me to help implement the test update to include the target ID? This would ensure the test properly validates the new scoping mechanism.
packages/web/app/src/lib/preflight/graphiql-plugin.tsx (1)
154-159
: Remove redundant TODO comment.The TODO comment appears to be obsolete as the implementation already includes the updated key.
- // todo - // 'hive:laboratory:isPreflightEnabled', 'hive:laboratory:isPreflightScriptEnabled',.changeset/rich-terms-knock.md (1)
13-13
: Add missing comma for better readability.A comma is needed after "For an indefinite period of time" to improve readability.
-For an indefinite period of time we will support the following migration when you load Laboratory on any target. +For an indefinite period of time, we will support the following migration when you load Laboratory on any target.🧰 Tools
🪛 LanguageTool
[uncategorized] ~13-~13: Possible missing comma found.
Context: ...Anything!) For an indefinite period of time we will support the following migration...(AI_HYDRA_LEO_MISSING_COMMA)
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (7)
.changeset/rich-terms-knock.md
(1 hunks)cypress/e2e/laboratory-preflight.cy.ts
(1 hunks)packages/web/app/src/lib/hooks/use-local-storage-json.ts
(3 hunks)packages/web/app/src/lib/hooks/use-local-storage.ts
(1 hunks)packages/web/app/src/lib/preflight/graphiql-plugin.tsx
(1 hunks)packages/web/app/src/lib/versioned-entry.spec.ts
(1 hunks)packages/web/app/src/lib/versioned-entry.ts
(1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
`.changeset/**`: A special folder with the files created/man...
.changeset/**
: A special folder with the files created/managed by Changesets tool.
In PRs that already includes this file, please make sure that the content of the markdown file includes:
- Full description of the change
- A link to the relevant GitHub issues (if any)
- Example with before/after
- If the change is of type
major
, please ensure that the content have content about migration with before/after.
.changeset/rich-terms-knock.md
🪛 LanguageTool
.changeset/rich-terms-knock.md
[uncategorized] ~13-~13: Possible missing comma found.
Context: ...Anything!) For an indefinite period of time we will support the following migration...
(AI_HYDRA_LEO_MISSING_COMMA)
⏰ Context from checks skipped due to timeout of 90000ms (9)
- GitHub Check: alpha / npm / snapshot
- GitHub Check: static-analysis / analyze (typescript)
- GitHub Check: typescript / typecheck
- GitHub Check: storybook-preview / deployment
- GitHub Check: static-analysis / analyze (javascript)
- GitHub Check: build / dockerize (linux/arm64)
- GitHub Check: build / dockerize (linux/amd64)
- GitHub Check: alpha / cli-artifacts
- GitHub Check: code-style / eslint-and-prettier
🔇 Additional comments (12)
packages/web/app/src/lib/hooks/use-local-storage.ts (2)
2-2
: No issues with the new import.
The import ofreadVersionedEntryLocalStorage
andVersionedEntrySpec
is properly aligned with the feature for versioned local storage.
8-8
: Ensure consistent fallback if null is returned by the reader.
readVersionedEntryLocalStorage
can returnnull
, so verifying the fallback todefaultValue
upon initialization is crucial. This appears to be handled properly in theuseState
initializer, but consider logging or tracing null returns for diagnostic clarity.packages/web/app/src/lib/versioned-entry.ts (3)
5-9
: Interface definition looks solid.
TheKeyValueStore
contract is simple and extensible. Consider adding async variants in the future if remote or asynchronous storage is required.
17-24
: Versioned spec design is flexible for future migrations.
The tuple-basedVersionedEntrySpec
and theEntrySpec
layout leave room for schema-based upgrades. Document the expected usage pattern to guide future contributors on adding advanced migrations.
94-100
: Policies are concise and clear.
PreviousEntriesPolicy
and the associatedas const
usage is a good pattern, making the policy keys less error-prone. If you anticipate more than two modes, consider enumerating them more extensively.packages/web/app/src/lib/hooks/use-local-storage-json.ts (3)
4-4
: Import aligns with versioned entry usage.
ImportingreadVersionedEntryLocalStorage
andVersionedEntrySpec
here follows the same pattern as inuse-local-storage.ts
. Consistency is good across hooks.
30-30
: Consistent usage of versioned reading.
UsingreadVersionedEntryLocalStorage
ensures the JSON-based hook also benefits from the same migration logic. This maintains parity between plain and JSON-storing hooks.
66-68
: Good type enforcement strategy.
Separating the parameter signature by whether the schema has a default is a sophisticated approach. This ensures users supply a default when schema defaults are missing, preventing accidental undefined usage.packages/web/app/src/lib/versioned-entry.spec.ts (1)
9-15
: LGTM! Well-structured test case interface.The TestCase interface is well-designed, clearly defining the expected state before and after operations, along with the necessary inputs and outputs.
packages/web/app/src/lib/preflight/graphiql-plugin.tsx (1)
160-166
: LGTM! Well-implemented target-scoped environment variables.The implementation correctly handles both target-specific and legacy environment variable storage, supporting the migration strategy outlined in the changeset.
.changeset/rich-terms-knock.md (2)
1-3
: LGTM! Correct changeset metadata.The changeset correctly specifies a minor version bump for the 'hive' package.
5-20
: LGTM! Clear and comprehensive migration documentation.The changeset provides excellent documentation of the changes and migration strategy:
- Clear explanation of the previous behavior
- Detailed description of the new target-scoped approach
- Well-documented migration strategy with clear steps
🧰 Tools
🪛 LanguageTool
[uncategorized] ~13-~13: Possible missing comma found.
Context: ...Anything!) For an indefinite period of time we will support the following migration...(AI_HYDRA_LEO_MISSING_COMMA)
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.
Actionable comments posted: 4
🧹 Nitpick comments (1)
packages/web/app/src/lib/hooks/use-local-storage.ts (1)
8-17
: Consider memoizing the initial value computation.The
getInitialValue
callback is recreated wheneverversionedEntrySerialized
ordefaultValue
changes, which triggers the effect and re-sets the value. While this is correct, we could optimize it further.- const getInitialValue = useCallback(() => { + const getInitialValue = useMemo(() => { const value = readVersionedEntryLocalStorage({ spec: versionedEntry }); return value ?? defaultValue; - }, [versionedEntrySerialized, defaultValue]); + }, [versionedEntrySerialized, defaultValue]); const [value, setValue] = useState(getInitialValue()); useEffect(() => { - setValue(getInitialValue()); + setValue(getInitialValue); }, [getInitialValue]);
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (5)
cypress.config.ts
(2 hunks)cypress/e2e/laboratory-environment-variables.cy.ts
(1 hunks)integration-tests/testkit/seed.ts
(1 hunks)packages/web/app/src/lib/hooks/use-local-storage.ts
(1 hunks)packages/web/app/src/lib/preflight/graphiql-plugin.tsx
(2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- packages/web/app/src/lib/preflight/graphiql-plugin.tsx
🧰 Additional context used
📓 Path-based instructions (1)
`integration-tests/**`: integration tests for ensuring featu...
integration-tests/**
: integration tests for ensuring features and important flows are running. Usually, changes to thepackages/
directory will affect this. In ideal flow, each PR should include integration tests.
integration-tests/testkit/seed.ts
🪛 Biome (1.9.4)
cypress/e2e/laboratory-environment-variables.cy.ts
[error] 75-75: Don't focus the test.
The 'only' method is often used for debugging or during implementation. It should be removed before deploying to production.
Consider removing 'only' to ensure all tests are executed.
Unsafe fix: Remove focus from test.
(lint/suspicious/noFocusedTests)
[error] 19-26: Do not export from a test file.
(lint/suspicious/noExportsInTest)
⏰ Context from checks skipped due to timeout of 90000ms (10)
- GitHub Check: alpha / npm / snapshot
- GitHub Check: test / unit
- GitHub Check: typescript / typecheck
- GitHub Check: storybook-preview / deployment
- GitHub Check: static-analysis / analyze (typescript)
- GitHub Check: static-analysis / analyze (javascript)
- GitHub Check: build / dockerize (linux/arm64)
- GitHub Check: build / dockerize (linux/amd64)
- GitHub Check: code-style / eslint-and-prettier
- GitHub Check: alpha / cli-artifacts
🔇 Additional comments (4)
packages/web/app/src/lib/hooks/use-local-storage.ts (1)
4-6
: LGTM! The key handling logic is well-implemented.The implementation correctly handles both string and versioned keys, with proper type safety and key serialization.
cypress.config.ts (2)
26-26
: LGTM! Smart retry configuration.The retry configuration intelligently adapts based on the CI environment, which helps reduce test execution time in local development while maintaining reliability in CI.
36-40
: LGTM! Well-structured target mapping.The target mapping correctly computes paths for each environment, which is essential for the laboratory environment variables scoping feature.
integration-tests/testkit/seed.ts (1)
214-217
: LGTM! Comprehensive target path computation.The implementation correctly computes the path for each target by combining organization, project, and target slugs. This is essential for the laboratory environment variables scoping feature.
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.
Actionable comments posted: 1
🔭 Outside diff range comments (1)
packages/web/app/src/lib/preflight/graphiql-plugin.tsx (1)
187-202
: 🛠️ Refactor suggestionImprove error handling for invalid environment variables JSON.
Currently, invalid JSON in environment variables is silently replaced with an empty object, which could lead to data loss.
Consider these improvements:
- Preserve the invalid JSON string.
- Show an error message to the user.
- Allow the user to fix the JSON manually.
- () => ({}), + (error) => { + toast({ + title: 'Invalid Environment Variables', + description: 'Please fix the JSON syntax in your environment variables.', + variant: 'destructive', + }); + return resultEnvironmentVariablesDecoded; + }
🧹 Nitpick comments (3)
cypress/e2e/laboratory-environment-variables.cy.ts (1)
74-79
: Add more test coverage for environment variables.The current test suite covers basic scenarios. Consider adding tests for:
- Multiple targets with different environment variables
- Overriding global variables with target-specific ones
- Error handling for invalid JSON
- Migration scenarios
Would you like me to generate the additional test cases?
Also applies to: 81-87, 89-97
cypress/support/testkit.ts (1)
1-40
: Enhance error handling in cookie persistence.While the cookie persistence implementation is good, consider adding error handling for cases where cookies don't exist or have unexpected values.
export function persistAuthenticationCookies() { const ctx = { cookies: [] as Cypress.Cookie[], }; before(() => { + // Add timeout to prevent infinite wait + const timeout = { timeout: 10000 }; - cy.getCookie('sRefreshToken').should('exist'); + cy.getCookie('sRefreshToken', timeout) + .should('exist') + .then(cookie => { + if (!cookie?.value) { + throw new Error('Refresh token is empty'); + } + }); cy.visit('/'); cy.wait(2000); - cy.getCookie('sAccessToken').should('exist'); - cy.getCookie('sFrontToken').should('exist'); - cy.getCookie('st-last-access-token-update').should('exist'); + cy.getCookie('sAccessToken', timeout).should('exist'); + cy.getCookie('sFrontToken', timeout).should('exist'); + cy.getCookie('st-last-access-token-update', timeout).should('exist');package.json (1)
80-80
: Consider pinning the cypress-localstorage-commands version.Using
^2.2.7
allows minor version updates which could introduce breaking changes in tests.- "cypress-localstorage-commands": "^2.2.7", + "cypress-localstorage-commands": "2.2.7",
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
pnpm-lock.yaml
is excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (7)
cypress.config.ts
(2 hunks)cypress/e2e/laboratory-environment-variables.cy.ts
(1 hunks)cypress/e2e/laboratory-preflight.cy.ts
(2 hunks)cypress/support/e2e.ts
(1 hunks)cypress/support/testkit.ts
(1 hunks)package.json
(1 hunks)packages/web/app/src/lib/preflight/graphiql-plugin.tsx
(2 hunks)
✅ Files skipped from review due to trivial changes (1)
- cypress/support/e2e.ts
🧰 Additional context used
🪛 Biome (1.9.4)
cypress/e2e/laboratory-environment-variables.cy.ts
[error] 25-32: Do not export from a test file.
(lint/suspicious/noExportsInTest)
⏰ Context from checks skipped due to timeout of 90000ms (10)
- GitHub Check: alpha / npm / snapshot
- GitHub Check: test / unit
- GitHub Check: typescript / typecheck
- GitHub Check: storybook-preview / deployment
- GitHub Check: static-analysis / analyze (typescript)
- GitHub Check: static-analysis / analyze (javascript)
- GitHub Check: build / dockerize (linux/arm64)
- GitHub Check: code-style / eslint-and-prettier
- GitHub Check: build / dockerize (linux/amd64)
- GitHub Check: alpha / cli-artifacts
🔇 Additional comments (9)
cypress.config.ts (4)
4-4
: LGTM! Good addition of local storage commands plugin.The cypress-localstorage-commands plugin will help manage environment variables in local storage during tests.
27-27
: Good conditional retry configuration.Setting retries based on CI environment is a good practice as it helps balance between test reliability in CI and fast feedback in local development.
29-30
: LGTM! Proper integration of local storage commands.The plugin is correctly integrated into the Cypress configuration.
39-43
: LGTM! Well-structured target data.The targets object provides a clear and organized way to access different environment targets in tests.
cypress/e2e/laboratory-environment-variables.cy.ts (2)
25-32
: Move storage key constant to a utility file.The
environmentVariablesStorageKey
object should be moved to a utility file since it's being exported from a test file.🧰 Tools
🪛 Biome (1.9.4)
[error] 25-32: Do not export from a test file.
(lint/suspicious/noExportsInTest)
34-37
: LGTM! Well-structured test data.The test data is clearly defined and includes both object and JSON string formats.
cypress/e2e/laboratory-preflight.cy.ts (2)
20-22
: LGTM! Improved context object naming.The rename from
data
toctx
better represents the object's purpose as a test context.
61-63
: LGTM! Consistent usage of target slug.The target slug is correctly accessed through the context object.
packages/web/app/src/lib/preflight/graphiql-plugin.tsx (1)
166-172
: LGTM! Well-structured storage key implementation.The array of storage keys is properly ordered with scoped key before global key, ensuring correct fallback behavior.
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.
Actionable comments posted: 2
♻️ Duplicate comments (1)
cypress/e2e/laboratory-environment-variables.cy.ts (1)
47-72
: 🛠️ Refactor suggestionEnhance test coverage.
The current test suite only covers basic scenarios. Consider adding tests for:
- Multiple targets with different environment variables
- Overriding global variables with target-specific ones
- Error handling for invalid JSON
- Migration scenarios
Would you like me to generate the additional test cases?
🧹 Nitpick comments (2)
cypress/e2e/laboratory-environment-variables.cy.ts (1)
8-11
: Consider using typed test data.The
data
object could benefit from TypeScript interfaces to ensure type safety and improve maintainability.+interface TestData { + envars: Record<string, string>; + envarsJson: string; +} + -const data = { +const data: TestData = { envars: { foo: '123' }, envarsJson: '{"foo":"123"}', };cypress/support/testkit.ts (1)
31-70
: Optimize cookie persistence logic.The cookie persistence logic has several areas for improvement:
- The 2-second wait is arbitrary and could be flaky
- Cookie operations could be batched
- Error handling could be improved
export function persistAuthenticationCookies() { const ctx = { cookies: [] as Cypress.Cookie[], }; before(() => { cy.getCookie('sRefreshToken').should('exist'); cy.visit('/'); - cy.wait(2000); + // Wait for the application to be ready + cy.get('[data-cy="app-ready"]').should('exist'); - cy.getCookie('sAccessToken').should('exist'); - cy.getCookie('sFrontToken').should('exist'); - cy.getCookie('st-last-access-token-update').should('exist'); + const requiredCookies = [ + 'sAccessToken', + 'sFrontToken', + 'sRefreshToken', + 'st-last-access-token-update' + ]; - cy.getCookie('sAccessToken').then(sAccessToken => { - ctx.cookies.push(sAccessToken); - }); - cy.getCookie('sFrontToken').then(sFrontToken => { - ctx.cookies.push(sFrontToken); - }); - cy.getCookie('sRefreshToken').then(sRefreshToken => { - ctx.cookies.push(sRefreshToken); - }); + // Verify all required cookies exist + requiredCookies.forEach(cookieName => { + cy.getCookie(cookieName).should('exist'); + }); - cy.getCookie('st-last-access-token-update').then(stLastAccessTokenUpdate => { - ctx.cookies.push(stLastAccessTokenUpdate); + // Batch collect all cookies + cy.wrap(requiredCookies).each(cookieName => { + cy.getCookie(cookieName).then(cookie => { + if (cookie) { + ctx.cookies.push(cookie); + } else { + throw new Error(`Required cookie ${cookieName} not found`); + } + }); }); - cy.clearCookie('st-last-access-token-update'); - cy.clearCookie('sRefreshToken'); - cy.clearCookie('sAccessToken'); - cy.clearCookie('sFrontToken'); + // Batch clear all cookies + requiredCookies.forEach(cookieName => { + cy.clearCookie(cookieName); + }); });
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
cypress/e2e/laboratory-environment-variables.cy.ts
(1 hunks)cypress/support/testkit.ts
(1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (9)
- GitHub Check: alpha / npm / snapshot
- GitHub Check: typescript / typecheck
- GitHub Check: static-analysis / analyze (typescript)
- GitHub Check: storybook-preview / deployment
- GitHub Check: static-analysis / analyze (javascript)
- GitHub Check: build / dockerize (linux/arm64)
- GitHub Check: build / dockerize (linux/amd64)
- GitHub Check: code-style / eslint-and-prettier
- GitHub Check: alpha / cli-artifacts
🔇 Additional comments (1)
cypress/e2e/laboratory-environment-variables.cy.ts (1)
30-33
: Uncomment and utilize production target test.The commented-out production target test function suggests incomplete test coverage. Consider implementing tests for both development and production targets to ensure proper isolation.
Would you like me to generate additional test cases that cover both development and production targets?
Struggled today with Cypress but ultimately got tests running how I wanted:
Will think through the rest of test cases next week. E.g. on edit in modal only scoped should be written to. |
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.
Actionable comments posted: 1
♻️ Duplicate comments (1)
cypress/support/testkit.ts (1)
5-12
:⚠️ Potential issueAddress TODOs in storage key implementation.
The storage key implementation has two unaddressed TODOs:
- Importing from core utility lib
- Handling the silent global case with optional target ID
Apply this diff to address the TODOs:
-// todo: instead of copying this, import it from core utility lib. -export const environmentVariablesStorageKey = { - // todo: optional target effectively gives this the possibility of being silently global - // which feels subtle and thus likely to introduce hard to trace defects. Should we abort instead? - scoped: (targetId?: string) => - `hive/targetId:${targetId ?? '__null__'}/laboratory/environment-variables`, - global: 'hive:laboratory:environment', -}; +import { environmentVariablesStorageKey as coreStorageKey } from '../../core/utility'; + +export const environmentVariablesStorageKey = { + scoped: (targetId: string) => { + if (!targetId) { + throw new Error('Target ID is required for scoped environment variables'); + } + return coreStorageKey.scoped(targetId); + }, + global: coreStorageKey.global, +};
🧹 Nitpick comments (7)
cypress/e2e/laboratory-environment-variables.cy.ts (3)
8-11
: Enhance test data with more comprehensive cases.The test data is currently minimal. Consider adding more test cases to cover different scenarios:
- Complex environment variables with nested objects
- Multiple variables
- Special characters
- Empty objects
const data = { - envars: { foo: '123' }, - envarsJson: '{"foo":"123"}', + envars: { + simple: { foo: '123' }, + complex: { nested: { key: 'value' }, array: [1, 2, 3] }, + special: { 'key-with-dash': 'value' }, + empty: {} + }, + envarsJson: { + simple: '{"foo":"123"}', + complex: '{"nested":{"key":"value"},"array":[1,2,3]}', + special: '{"key-with-dash":"value"}', + empty: '{}' + } };
32-33
: Remove or implement commented code.The commented production target navigation function suggests a potential need for testing with production targets. Either implement these tests or remove the commented code.
const visitTargetDevelopment = () => cy.visit(`${ctx.targetDevelopment.path}/laboratory`); -// const visitTargetProduction = () => cy.visit(`${ctx.targetProduction.path}/laboratory`);
37-41
: Improve code formatting to avoid prettier-ignore.The code uses prettier-ignore comments to handle long lines. Consider breaking down the lines for better readability without disabling formatting.
-const storageGlobalGet = () => cy.getLocalStorage(environmentVariablesStorageKey.global); -const storageGlobalSet = (value: string) => cy.setLocalStorage(environmentVariablesStorageKey.global, value); // prettier-ignore - -const storageTargetDevelopmentGet = () => cy.getLocalStorage(environmentVariablesStorageKey.scoped(ctx.targetDevelopment.id)); // prettier-ignore -const storageTargetDevelopmentSet = (value: string) => cy.setLocalStorage(environmentVariablesStorageKey.scoped(ctx.targetDevelopment.id), value); // prettier-ignore +const storageGlobalGet = () => + cy.getLocalStorage(environmentVariablesStorageKey.global); + +const storageGlobalSet = (value: string) => + cy.setLocalStorage(environmentVariablesStorageKey.global, value); + +const storageTargetDevelopmentGet = () => + cy.getLocalStorage( + environmentVariablesStorageKey.scoped(ctx.targetDevelopment.id) + ); + +const storageTargetDevelopmentSet = (value: string) => + cy.setLocalStorage( + environmentVariablesStorageKey.scoped(ctx.targetDevelopment.id), + value + );cypress/support/testkit.ts (2)
14-31
: Address TODO about scoping selectors.The selectors object has a TODO about scoping to laboratory. This should be addressed to improve maintainability.
-// todo: Once other PRs are merged these selectors will be scoped to a place for laboratory. -export const selectors = { +export const laboratorySelectors = { editorEnvironmentVariables: '[data-cy="preflight-editor-mini"]', buttonGraphiQLPreflight: '[aria-label*="Preflight Script"]', buttonModalCy: 'preflight-modal-button', // ... rest of the selectors };Then update the imports in test files:
-import { selectors } from '../support/testkit'; +import { laboratorySelectors as selectors } from '../support/testkit';
33-72
: Improve error handling in cookie persistence.The cookie persistence implementation could be more robust with better error handling and logging.
export function persistAuthenticationCookies() { const ctx = { cookies: [] as Cypress.Cookie[], + errors: [] as Error[], }; before(() => { - cy.getCookie('sRefreshToken').should('exist'); + cy.getCookie('sRefreshToken') + .should('exist') + .catch(error => { + ctx.errors.push(new Error(`Refresh token not found: ${error.message}`)); + }); cy.visit('/'); cy.wait(2000); - cy.getCookie('sAccessToken').should('exist'); - cy.getCookie('sFrontToken').should('exist'); - cy.getCookie('st-last-access-token-update').should('exist'); + const requiredCookies = [ + 'sAccessToken', + 'sFrontToken', + 'st-last-access-token-update' + ]; + + requiredCookies.forEach(cookieName => { + cy.getCookie(cookieName) + .should('exist') + .catch(error => { + ctx.errors.push(new Error(`${cookieName} not found: ${error.message}`)); + }); + }); + + if (ctx.errors.length > 0) { + throw new Error( + `Authentication setup failed:\n${ctx.errors.map(e => e.message).join('\n')}` + ); + } // ... rest of the implementation }); }integration-tests/testkit/seed.ts (2)
65-69
: Add JSDoc documentation to Target interface.The Target interface would benefit from documentation explaining its purpose and properties.
+/** + * Represents a target in the system. + */ export interface Target { + /** Unique identifier for the target */ id: string + /** Full path to access the target in the UI */ path: string + /** URL-friendly identifier for the target */ slug: string }
220-224
: Make path construction more maintainable.The path construction is hardcoded in the mapping function. Consider extracting it to a utility function for better maintainability.
+const constructTargetPath = ( + organizationSlug: string, + projectSlug: string, + targetSlug: string +) => `/${organizationSlug}/${projectSlug}/${targetSlug}`; + const targets = projectResult.createProject.ok!.createdTargets.map(_ => ({ ..._, - path: `/${organization.slug}/${project.slug}/${_.slug}`, + path: constructTargetPath(organization.slug, project.slug, _.slug), }));
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
pnpm-lock.yaml
is excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (4)
cypress/e2e/laboratory-environment-variables.cy.ts
(1 hunks)cypress/support/testkit.ts
(1 hunks)integration-tests/testkit/seed.ts
(2 hunks)package.json
(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- package.json
🧰 Additional context used
📓 Path-based instructions (1)
`integration-tests/**`: integration tests for ensuring featu...
integration-tests/**
: integration tests for ensuring features and important flows are running. Usually, changes to thepackages/
directory will affect this. In ideal flow, each PR should include integration tests.
integration-tests/testkit/seed.ts
⏰ Context from checks skipped due to timeout of 90000ms (11)
- GitHub Check: alpha / npm / snapshot
- GitHub Check: test / unit
- GitHub Check: typescript / typecheck
- GitHub Check: static-analysis / analyze (typescript)
- GitHub Check: static-analysis / analyze (javascript)
- GitHub Check: storybook-preview / deployment
- GitHub Check: build / dockerize (linux/arm64)
- GitHub Check: test / db-migrations
- GitHub Check: build / dockerize (linux/amd64)
- GitHub Check: code-style / eslint-and-prettier
- GitHub Check: alpha / cli-artifacts
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.
Actionable comments posted: 0
♻️ Duplicate comments (2)
cypress/e2e/laboratory-environment-variables.cy.ts (1)
105-123
: 🛠️ Refactor suggestionMove the Monaco editor utility to a shared file.
The TODO comment and static analysis hint both suggest moving this utility function out of the test file.
Create a new file
cypress/support/monaco-editor.ts
and move the implementation there:// cypress/support/monaco-editor.ts export function setMonacoEditorContents(editorCyName: string, text: string) { // Implementation... }Then update the import in the test file:
+import { setMonacoEditorContents } from '../support/monaco-editor'; -// todo: in another PR this utility is factored out into a shared file -export function setMonacoEditorContents(editorCyName: string, text: string) { - // Implementation... -}🧰 Tools
🪛 Biome (1.9.4)
[error] 106-123: Do not export from a test file.
(lint/suspicious/noExportsInTest)
cypress/support/testkit.ts (1)
5-12
:⚠️ Potential issueAddress TODOs and improve error handling in storage key utility.
The storage key utility has two TODOs that should be addressed:
- Import from core utility lib instead of copying
- Handle the silent global case
Apply this diff to improve error handling:
-// todo: instead of copying this, import it from core utility lib. export const environmentVariablesStorageKey = { - // todo: optional target effectively gives this the possibility of being silently global - // which feels subtle and thus likely to introduce hard to trace defects. Should we abort instead? - scoped: (targetId?: string) => - `hive/targetId:${targetId ?? '__null__'}/laboratory/environment-variables`, + scoped: (targetId: string) => { + if (!targetId) { + throw new Error('Target ID is required for scoped environment variables'); + } + return `hive/targetId:${targetId}/laboratory/environment-variables`; + }, global: 'hive:laboratory:environment', };
🧹 Nitpick comments (2)
cypress/e2e/laboratory-environment-variables.cy.ts (1)
8-13
: Consider using TypeScript'sas const
assertion for test data.The test data object could benefit from being more strictly typed to catch potential typos and ensure data consistency.
-const data = { +const data = { globalEnvars: { foo: '123' }, globalEnvarsJson: '{"foo":"123"}', scopedEnvars: { bar: '456' }, targetEnvarsJson: '{"bar":"456"}', -}; +} as const;cypress/support/testkit.ts (1)
33-72
: Improve cookie persistence implementation.The cookie persistence implementation has a few potential issues:
- Hard-coded wait time
- Redundant cookie existence checks
- Manual cookie management
Consider these improvements:
export function persistAuthenticationCookies() { const ctx = { cookies: [] as Cypress.Cookie[], }; before(() => { - cy.getCookie('sRefreshToken').should('exist'); cy.visit('/'); - cy.wait(2000); + // Wait for specific condition instead of arbitrary time + cy.get('[data-cy="app-loaded"]').should('exist'); - cy.getCookie('sAccessToken').should('exist'); - cy.getCookie('sFrontToken').should('exist'); - cy.getCookie('st-last-access-token-update').should('exist'); + const requiredCookies = [ + 'sAccessToken', + 'sFrontToken', + 'sRefreshToken', + 'st-last-access-token-update' + ]; - cy.getCookie('sAccessToken').then(sAccessToken => { - ctx.cookies.push(sAccessToken); - }); - cy.getCookie('sFrontToken').then(sFrontToken => { - ctx.cookies.push(sFrontToken); - }); - cy.getCookie('sRefreshToken').then(sRefreshToken => { - ctx.cookies.push(sRefreshToken); - }); - cy.getCookie('st-last-access-token-update').then(stLastAccessTokenUpdate => { - ctx.cookies.push(stLastAccessTokenUpdate); + // Verify all required cookies exist + requiredCookies.forEach(cookieName => { + cy.getCookie(cookieName).should('exist'); }); - cy.clearCookie('st-last-access-token-update'); - cy.clearCookie('sRefreshToken'); - cy.clearCookie('sAccessToken'); - cy.clearCookie('sFrontToken'); + // Store all cookies at once + cy.getAllCookies().then(cookies => { + ctx.cookies = cookies.filter(cookie => + requiredCookies.includes(cookie.name) + ); + }); + + // Clear all cookies at once + cy.clearCookies(); }); beforeEach(() => { ctx.cookies.forEach(cookie => { cy.setCookie(cookie.name, cookie.value, cookie); }); }); }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
pnpm-lock.yaml
is excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (3)
cypress/e2e/laboratory-environment-variables.cy.ts
(1 hunks)cypress/e2e/laboratory-preflight.cy.ts
(2 hunks)cypress/support/testkit.ts
(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- cypress/e2e/laboratory-preflight.cy.ts
🧰 Additional context used
🪛 Biome (1.9.4)
cypress/e2e/laboratory-environment-variables.cy.ts
[error] 106-123: Do not export from a test file.
(lint/suspicious/noExportsInTest)
⏰ Context from checks skipped due to timeout of 90000ms (11)
- GitHub Check: alpha / npm / snapshot
- GitHub Check: static-analysis / analyze (typescript)
- GitHub Check: test / unit
- GitHub Check: typescript / typecheck
- GitHub Check: static-analysis / analyze (javascript)
- GitHub Check: storybook-preview / deployment
- GitHub Check: build / dockerize (linux/arm64)
- GitHub Check: build / dockerize (linux/amd64)
- GitHub Check: code-style / eslint-and-prettier
- GitHub Check: alpha / cli-artifacts
- GitHub Check: Mend Security Check
🔇 Additional comments (1)
cypress/e2e/laboratory-environment-variables.cy.ts (1)
47-49
: Uncomment and utilize the production target storage functions.The commented-out functions for production target storage suggest incomplete test coverage for production target scenarios.
Consider adding test cases that verify environment variable behavior across different targets:
it('maintains separate environment variables for different targets', () => { const devVars = { dev: 'value' }; const prodVars = { prod: 'value' }; storageTargetDevelopmentSet(JSON.stringify(devVars)); storageTargetProductionSet(JSON.stringify(prodVars)); visitTargetDevelopment(); openPreflightTab(); cy.contains(JSON.stringify(devVars)); visitTargetProduction(); openPreflightTab(); cy.contains(JSON.stringify(prodVars)); });
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.
Actionable comments posted: 1
🧹 Nitpick comments (3)
packages/web/app/src/lib/hooks/use-local-storage.ts (1)
16-25
: Consider memoizingversionedEntry
to optimize performance.The
getInitialValue
callback depends onversionedEntrySerialized
, which is recalculated on every render. Consider memoizingversionedEntry
and its serialized form to prevent unnecessary callback recreations.+ const versionedEntry = useMemo( + () => (typeof key === 'string' ? [{ key }] : key) as VersionedEntrySpec, + [key], + ); + const versionedEntrySerialized = useMemo( + () => serializeVersionedEntrySpec(versionedEntry), + [versionedEntry], + ); - const versionedEntry: VersionedEntrySpec = typeof key === 'string' ? [{ key }] : key; - const versionedEntrySerialized = serializeVersionedEntrySpec(versionedEntry);packages/web/app/src/lib/versioned-entry.ts (2)
22-28
: Consider adding JSDoc comments for future schema migration.The
EntrySpec
interface has TODO comments about future schema migration. Consider adding JSDoc comments to better document the planned features.interface EntrySpec { key: string; - // todo once we have use-case - // schema: - // fromPrevious: + /** @todo Add schema validation for entry values */ + // schema?: Schema; + /** @todo Add migration function for previous versions */ + // fromPrevious?: (value: string) => string; }
124-134
: Consider adding error handling for memory store operations.The memory store implementation might benefit from error handling for edge cases (e.g., invalid keys or values).
export const createKeyValueStoreMemory = (database: KeyValueStoreDatabase): KeyValueStore => ({ get(key) { + if (typeof key !== 'string') { + throw new Error('Invalid key type'); + } return database[key] ?? null; }, set(key, value) { + if (typeof key !== 'string' || typeof value !== 'string') { + throw new Error('Invalid key or value type'); + } database[key] = value; }, remove(key) { + if (typeof key !== 'string') { + throw new Error('Invalid key type'); + } delete database[key]; }, });
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
packages/web/app/src/lib/hooks/use-local-storage.ts
(1 hunks)packages/web/app/src/lib/versioned-entry.ts
(1 hunks)
🧰 Additional context used
🧠 Learnings (1)
packages/web/app/src/lib/hooks/use-local-storage.ts (1)
Learnt from: jasonkuhrt
PR: graphql-hive/console#6500
File: packages/web/app/src/lib/hooks/use-local-storage.ts:19-25
Timestamp: 2025-02-14T19:38:19.025Z
Learning: In React's useCallback, only include dependencies that are directly used within the callback's implementation. Depending on another callback (that has its own dependencies) when its implementation isn't used can lead to unnecessary callback recreations.
⏰ Context from checks skipped due to timeout of 90000ms (10)
- GitHub Check: alpha / npm / snapshot
- GitHub Check: test / unit
- GitHub Check: typescript / typecheck
- GitHub Check: static-analysis / analyze (typescript)
- GitHub Check: storybook-preview / deployment
- GitHub Check: static-analysis / analyze (javascript)
- GitHub Check: build / dockerize (linux/arm64)
- GitHub Check: build / dockerize (linux/amd64)
- GitHub Check: alpha / cli-artifacts
- GitHub Check: code-style / eslint-and-prettier
🔇 Additional comments (3)
packages/web/app/src/lib/hooks/use-local-storage.ts (2)
9-15
: LGTM! Clean implementation of versioned entry handling.The conversion from string key to
VersionedEntrySpec
and the serialization logic is well-implemented.
27-33
: LGTM! Correct dependency in the setter callback.The
set
callback now correctly depends onversionedEntryLatestSerialized
instead ofgetInitialValue
, aligning with the learning from previous reviews about including only directly used dependencies.packages/web/app/src/lib/versioned-entry.ts (1)
5-11
: LGTM! Well-defined interface for key-value storage.The
KeyValueStore
interface provides a clean abstraction for storage operations.
for (const { entry, index } of spec.map((entry, index) => ({ entry, index }))) { | ||
const value = keyValueStore.get(entry.key); | ||
searchResults.push({ entry, value, index }); | ||
// Note: Once we have schemas, we should not remove here, wait until _after_ successful migration | ||
if (index > 0 && previousEntriesPolicy === PreviousEntriesPolicy.remove) { | ||
keyValueStore.remove(entry.key); | ||
} | ||
} |
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.
💡 Verification agent
🧩 Analysis chain
Consider deferring removal until after successful migration.
The code removes previous entries before potential schema migration, as noted in the comment. This could lead to data loss if migration fails.
🏁 Script executed:
#!/bin/bash
# Search for any schema migration implementations or tests
rg -g '!node_modules' -A 5 'schema.*migration|migration.*schema'
Length of output: 14789
Action: Defer Removal Until Post-Migration Success
The current implementation in packages/web/app/src/lib/versioned-entry.ts
(lines 76–83) immediately calls keyValueStore.remove(entry.key)
when previousEntriesPolicy
is remove
. Although there is active migration logic (e.g., in packages/migrations/src/actions/2024.07.23T09.36.00.schema-cleanup-tracker.ts
), prematurely removing entries may lead to data loss if the accompanying schema migration fails.
Recommendations:
- Remove the immediate key removal: Defer calling
keyValueStore.remove(entry.key)
until after a successful migration. - Integrate into the migration pipeline: Consider moving this removal step into a post-migration hook to ensure the operation only occurs after migration success.
Background
This change makes Laboratory environment variables scoped to target.
Description
The application layer changes are minimal by design. The approach taken is to factor out an "engine" for reading versionable entries with automatic migration. Migration is trivial right now given its simply key read migrations with no concern about value contents. Code is written to facilitate addition of schema migration logic later, namely a few comments at key locations.
Checklist