feat: add artifact_proxy server (#222)
This commit is contained in:
@@ -0,0 +1,62 @@
|
||||
name: Deploy Artifacts Proxy
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
paths:
|
||||
- .github/workflows/deploy_artifacts_proxy.yaml
|
||||
- packages/artifacts_proxy/**"
|
||||
|
||||
env:
|
||||
PROJECT_ID: code-push-prod
|
||||
SERVICE: artifacts-proxy
|
||||
REGION: us-central1
|
||||
|
||||
jobs:
|
||||
deploy:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
defaults:
|
||||
run:
|
||||
working-directory: packages/artifacts_proxy
|
||||
|
||||
name: ☁️ Artifacts Proxy
|
||||
|
||||
steps:
|
||||
- name: 📚 Git Checkout
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
- uses: dart-lang/setup-dart@v1
|
||||
|
||||
- name: Setup Cloud SDK
|
||||
uses: google-github-actions/setup-gcloud@v0.2.0
|
||||
with:
|
||||
project_id: ${{ env.PROJECT_ID }}
|
||||
service_account_key: ${{ secrets.CLOUD_RUN_SA_PROD }}
|
||||
export_default_credentials: true
|
||||
|
||||
- name: Authorize Docker Push
|
||||
run: gcloud auth configure-docker
|
||||
|
||||
- name: Build and Push Container
|
||||
run: |-
|
||||
docker build -t gcr.io/${{ env.PROJECT_ID }}/${{ env.SERVICE }}:${{ github.sha }} .
|
||||
docker push gcr.io/${{ env.PROJECT_ID }}/${{ env.SERVICE }}:${{ github.sha }}
|
||||
|
||||
- name: Deploy to Cloud Run
|
||||
id: deploy
|
||||
uses: google-github-actions/deploy-cloudrun@v0.4.0
|
||||
with:
|
||||
service: ${{ env.SERVICE }}
|
||||
image: gcr.io/${{ env.PROJECT_ID }}/${{ env.SERVICE }}:${{ github.sha }}
|
||||
region: ${{ env.REGION }}
|
||||
|
||||
- name: Show Output
|
||||
run: echo ${{ steps.deploy.outputs.url }}
|
||||
|
||||
- name: Ping
|
||||
run: curl "${{ steps.deploy.outputs.url }}"
|
||||
@@ -32,10 +32,13 @@ jobs:
|
||||
id: needs_dart_build
|
||||
with:
|
||||
filters: |
|
||||
artifacts_proxy:
|
||||
- ./.github/actions/dart_package
|
||||
- packages/artifacts_proxy/**
|
||||
shorebird_cli:
|
||||
- ./.github/actions/dart_package
|
||||
- packages/shorebird_cli/**
|
||||
- packages/shorebird_code_push_client/**
|
||||
- packages/shorebird_code_push_client/**
|
||||
shorebird_code_push_client:
|
||||
- ./.github/actions/dart_package
|
||||
- packages/shorebird_code_push_client/**
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
.dockerignore
|
||||
Dockerfile
|
||||
build/
|
||||
.dart_tool/
|
||||
.git/
|
||||
.github/
|
||||
.gitignore
|
||||
.idea/
|
||||
.packages
|
||||
coverage/
|
||||
@@ -0,0 +1,6 @@
|
||||
# https://dart.dev/guides/libraries/private-files
|
||||
# Created by `dart pub`
|
||||
.dart_tool/
|
||||
|
||||
# Test related files
|
||||
coverage/
|
||||
@@ -0,0 +1,23 @@
|
||||
# Official Dart image: https://hub.docker.com/_/dart
|
||||
# Specify the Dart SDK base image version using dart:<version> (ex: dart:2.12)
|
||||
FROM dart:stable AS build
|
||||
|
||||
# Resolve app dependencies.
|
||||
WORKDIR /app
|
||||
|
||||
# Copy app source code and AOT compile it.
|
||||
COPY . .
|
||||
|
||||
# Ensure packages are still up-to-date if anything has changed
|
||||
RUN dart pub get --offline
|
||||
RUN dart compile exe bin/server.dart -o bin/server
|
||||
|
||||
# Build minimal serving image from AOT-compiled `/server` and required system
|
||||
# libraries and configuration files stored in `/runtime/` from the build stage.
|
||||
FROM scratch
|
||||
COPY --from=build /runtime/ /
|
||||
COPY --from=build /app/bin/server /app/bin/
|
||||
|
||||
# Start server.
|
||||
EXPOSE 8080
|
||||
CMD ["/app/bin/server"]
|
||||
@@ -0,0 +1,26 @@
|
||||
# Artifact Proxy
|
||||
|
||||
This is a tool for proxying Flutter artifacts from a derived Flutter engine
|
||||
revision back to the base Flutter engine revision. This is useful for
|
||||
when you need to modify _some_ of the Flutter artifacts but not all of them.
|
||||
|
||||
This is a development tool which map requests to Google
|
||||
Storage (either Shorebird's bucket or the official Flutter buckets).
|
||||
|
||||
## Usage
|
||||
|
||||
Uses `config.yaml` to configure the engine revisions and artifact overrides.
|
||||
|
||||
```bash
|
||||
# Run locally with hot-reload enabled.
|
||||
DEV=true dart --enable-vm-service run bin/server.dart
|
||||
```
|
||||
|
||||
And then in a separate terminal:
|
||||
|
||||
```
|
||||
FLUTTER_STORAGE_BASE_URL=http://localhost:8080 flutter precache -a
|
||||
```
|
||||
|
||||
You should use a separate checkout of Flutter when running this, so you don't
|
||||
poison the cache of your main Flutter checkout.
|
||||
@@ -0,0 +1 @@
|
||||
include: package:very_good_analysis/analysis_options.4.0.0.yaml
|
||||
@@ -0,0 +1,32 @@
|
||||
// ignore_for_file: avoid_print
|
||||
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:artifact_proxy/artifact_proxy.dart';
|
||||
import 'package:shelf/shelf.dart';
|
||||
import 'package:shelf/shelf_io.dart' as shelf_io;
|
||||
import 'package:shelf_hotreload/shelf_hotreload.dart';
|
||||
import 'package:yaml/yaml.dart';
|
||||
|
||||
Future<void> main() async {
|
||||
const configPath = 'config.yaml';
|
||||
final isDev = Platform.environment['DEV'] == 'true';
|
||||
final config = loadYaml(File(configPath).readAsStringSync()) as Map;
|
||||
final handler = artifactProxyHandler(config: config);
|
||||
final ip = InternetAddress.anyIPv6;
|
||||
final port = int.parse(Platform.environment['PORT'] ?? '8080');
|
||||
|
||||
// Hot-reload is enabled when the DEBUG environment variable is set to true.
|
||||
if (isDev) return withHotreload(() => serve(handler, ip, port));
|
||||
|
||||
await serve(handler, ip, port);
|
||||
}
|
||||
|
||||
Future<HttpServer> serve(Handler proxy, InternetAddress ip, int port) async {
|
||||
const pipeline = Pipeline();
|
||||
final handler = pipeline.addMiddleware(logRequests()).addHandler(proxy);
|
||||
final server = await shelf_io.serve(handler, ip, port);
|
||||
print('Serving at http://localhost:${server.port}');
|
||||
server.autoCompress = true;
|
||||
return server;
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
engine_mappings:
|
||||
79f4c5321a581f580a9bda01ec372cbf4a53aa53:
|
||||
flutter_engine_revision: 9aa7816315095c86410527932918c718cb35e7d6
|
||||
shorebird_storage_bucket: download.shorebird.dev
|
||||
shorebird_artifact_overrides:
|
||||
# artifacts.zip
|
||||
- flutter_infra_release/flutter/$engine/android-arm-64-release/artifacts.zip
|
||||
- flutter_infra_release/flutter/$engine/android-arm-release/artifacts.zip
|
||||
- flutter_infra_release/flutter/$engine/android-x64-release/artifacts.zip
|
||||
|
||||
# embedding release
|
||||
- download.flutter.io/io/flutter/flutter_embedding_release/1.0.0-$engine/flutter_embedding_release-1.0.0-$engine.pom
|
||||
- download.flutter.io/io/flutter/flutter_embedding_release/1.0.0-$engine/flutter_embedding_release-1.0.0-$engine.jar
|
||||
|
||||
# arm64_v8a release
|
||||
- download.flutter.io/io/flutter/arm64_v8a_release/1.0.0-$engine/arm64_v8a_release-1.0.0-$engine.pom
|
||||
- download.flutter.io/io/flutter/arm64_v8a_release/1.0.0-$engine/arm64_v8a_release-1.0.0-$engine.jar
|
||||
|
||||
# armeabi_v7a release
|
||||
- download.flutter.io/io/flutter/armeabi_v7a_release/1.0.0-$engine/armeabi_v7a_release-1.0.0-$engine.pom
|
||||
- download.flutter.io/io/flutter/armeabi_v7a_release/1.0.0-$engine/armeabi_v7a_release-1.0.0-$engine.jar
|
||||
|
||||
# x86_64 release
|
||||
- download.flutter.io/io/flutter/x86_64_release/1.0.0-$engine/x86_64_release-1.0.0-$engine.pom
|
||||
- download.flutter.io/io/flutter/x86_64_release/1.0.0-$engine/x86_64_release-1.0.0-$engine.jar
|
||||
@@ -0,0 +1,88 @@
|
||||
// ignore_for_file: avoid_print
|
||||
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:shelf/shelf.dart';
|
||||
|
||||
/// A [Handler] that proxies artifact requests to the correct location.
|
||||
/// This is determined based on the [config].
|
||||
Handler artifactProxyHandler({required Map<dynamic, dynamic> config}) {
|
||||
final engineMappings = config['engine_mappings'] as Map;
|
||||
final shorebirdEngineRevisions = engineMappings.keys.cast<String>();
|
||||
|
||||
return (Request request) {
|
||||
final path = request.url.path;
|
||||
final shorebirdEngineRevision = shorebirdEngineRevisions.firstWhereOrNull(
|
||||
path.contains,
|
||||
);
|
||||
|
||||
final normalizedPath = shorebirdEngineRevision != null
|
||||
? path.replaceAll(shorebirdEngineRevision, r'$engine')
|
||||
: path;
|
||||
|
||||
if (shorebirdEngineRevision == null) {
|
||||
final location = getFlutterArtifactLocation(artifactPath: normalizedPath);
|
||||
print('No engine revision detected, forwarding to: $location');
|
||||
return Response.found(location);
|
||||
}
|
||||
|
||||
final engineMapping = engineMappings[shorebirdEngineRevision] as Map;
|
||||
final shorebirdOverrides =
|
||||
engineMapping['shorebird_artifact_overrides'] as List;
|
||||
final flutterEngineRevision =
|
||||
engineMapping['flutter_engine_revision'] as String;
|
||||
final shorebirdStorageBucket =
|
||||
engineMapping['shorebird_storage_bucket'] as String;
|
||||
final shouldOverride = shorebirdOverrides.contains(normalizedPath);
|
||||
|
||||
if (shouldOverride) {
|
||||
final location = getShorebirdArtifactLocation(
|
||||
artifactPath: normalizedPath,
|
||||
engine: shorebirdEngineRevision,
|
||||
bucket: shorebirdStorageBucket,
|
||||
);
|
||||
print('Shorebird artifact detected, forwarding to: $location');
|
||||
return Response.found(location);
|
||||
}
|
||||
|
||||
final location = getFlutterArtifactLocation(
|
||||
artifactPath: normalizedPath,
|
||||
engine: flutterEngineRevision,
|
||||
);
|
||||
print('Flutter artifact detected, forwarding to: $location');
|
||||
return Response.found(location);
|
||||
};
|
||||
}
|
||||
|
||||
/// Returns the location of the artifact at [artifactPath] using the
|
||||
/// specified [engine] revision for original Flutter artifacts.
|
||||
String getFlutterArtifactLocation({
|
||||
required String artifactPath,
|
||||
String? engine,
|
||||
}) {
|
||||
final adjustedPath = engine != null
|
||||
? artifactPath.replaceAll(r'$engine', engine)
|
||||
: artifactPath;
|
||||
|
||||
final isChromeInfra = adjustedPath.contains('flutter_infra_release/cipd');
|
||||
|
||||
/// TODO(felangel): remove this after 3.8 is released.
|
||||
if (isChromeInfra) {
|
||||
return adjustedPath.replaceAll(
|
||||
'flutter_infra_release/cipd',
|
||||
'https://chrome-infra-packages.appspot.com/dl',
|
||||
);
|
||||
}
|
||||
|
||||
return 'https://storage.googleapis.com/$adjustedPath';
|
||||
}
|
||||
|
||||
/// Returns the location of the artifact at [artifactPath] using the
|
||||
/// specified [engine] revision for Shorebird artifacts.
|
||||
String getShorebirdArtifactLocation({
|
||||
required String artifactPath,
|
||||
required String engine,
|
||||
required String bucket,
|
||||
}) {
|
||||
final adjustedPath = artifactPath.replaceAll(r'$engine', engine);
|
||||
return 'https://storage.googleapis.com/$bucket/$adjustedPath';
|
||||
}
|
||||
@@ -0,0 +1,405 @@
|
||||
# Generated by pub
|
||||
# See https://dart.dev/tools/pub/glossary#lockfile
|
||||
packages:
|
||||
_fe_analyzer_shared:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: _fe_analyzer_shared
|
||||
sha256: a36ec4843dc30ea6bf652bf25e3448db6c5e8bcf4aa55f063a5d1dad216d8214
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "58.0.0"
|
||||
analyzer:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: analyzer
|
||||
sha256: cc4242565347e98424ce9945c819c192ec0838cb9d1f6aa4a97cc96becbc5b27
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "5.10.0"
|
||||
args:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: args
|
||||
sha256: "4cab82a83ffef80b262ddedf47a0a8e56ee6fbf7fe21e6e768b02792034dd440"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.4.0"
|
||||
async:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: async
|
||||
sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.11.0"
|
||||
boolean_selector:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: boolean_selector
|
||||
sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.1"
|
||||
collection:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: collection
|
||||
sha256: "4a07be6cb69c84d677a6c3096fcf960cc3285a8330b4603e0d463d15d9bd934c"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.17.1"
|
||||
convert:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: convert
|
||||
sha256: "0f08b14755d163f6e2134cb58222dd25ea2a2ee8a195e53983d57c075324d592"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.1.1"
|
||||
coverage:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: coverage
|
||||
sha256: "2fb815080e44a09b85e0f2ca8a820b15053982b2e714b59267719e8a9ff17097"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.6.3"
|
||||
crypto:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: crypto
|
||||
sha256: aa274aa7774f8964e4f4f38cc994db7b6158dd36e9187aaceaddc994b35c6c67
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.0.2"
|
||||
file:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: file
|
||||
sha256: "1b92bec4fc2a72f59a8e15af5f52cd441e4a7860b49499d69dfa817af20e925d"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "6.1.4"
|
||||
frontend_server_client:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: frontend_server_client
|
||||
sha256: "408e3ca148b31c20282ad6f37ebfa6f4bdc8fede5b74bc2f08d9d92b55db3612"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.2.0"
|
||||
glob:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: glob
|
||||
sha256: "4515b5b6ddb505ebdd242a5f2cc5d22d3d6a80013789debfbda7777f47ea308c"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.1"
|
||||
hotreloader:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: hotreloader
|
||||
sha256: "728c0613556c1d153f7e7f4a367cffacc3f5a677d7f6497a1c2b35add4e6dacf"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.0.6"
|
||||
http_multi_server:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: http_multi_server
|
||||
sha256: "97486f20f9c2f7be8f514851703d0119c3596d14ea63227af6f7a481ef2b2f8b"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.2.1"
|
||||
http_parser:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: http_parser
|
||||
sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.0.2"
|
||||
io:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: io
|
||||
sha256: "2ec25704aba361659e10e3e5f5d672068d332fc8ac516421d483a11e5cbd061e"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.4"
|
||||
js:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: js
|
||||
sha256: f2c445dce49627136094980615a031419f7f3eb393237e4ecd97ac15dea343f3
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.6.7"
|
||||
logging:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: logging
|
||||
sha256: "04094f2eb032cbb06c6f6e8d3607edcfcb0455e2bb6cbc010cb01171dcb64e6d"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.1.1"
|
||||
matcher:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: matcher
|
||||
sha256: "6501fbd55da300384b768785b83e5ce66991266cec21af89ab9ae7f5ce1c4cbb"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.12.15"
|
||||
meta:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: meta
|
||||
sha256: "3c74dbf8763d36539f114c799d8a2d87343b5067e9d796ca22b5eb8437090ee3"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.9.1"
|
||||
mime:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: mime
|
||||
sha256: e4ff8e8564c03f255408decd16e7899da1733852a9110a58fe6d1b817684a63e
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.4"
|
||||
mocktail:
|
||||
dependency: "direct dev"
|
||||
description:
|
||||
name: mocktail
|
||||
sha256: "80a996cd9a69284b3dc521ce185ffe9150cde69767c2d3a0720147d93c0cef53"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.3.0"
|
||||
node_preamble:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: node_preamble
|
||||
sha256: "6e7eac89047ab8a8d26cf16127b5ed26de65209847630400f9aefd7cd5c730db"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.2"
|
||||
package_config:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: package_config
|
||||
sha256: "1c5b77ccc91e4823a5af61ee74e6b972db1ef98c2ff5a18d3161c982a55448bd"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.0"
|
||||
path:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: path
|
||||
sha256: "8829d8a55c13fc0e37127c29fedf290c102f4e40ae94ada574091fe0ff96c917"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.8.3"
|
||||
pool:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: pool
|
||||
sha256: "20fe868b6314b322ea036ba325e6fc0711a22948856475e2c2b6306e8ab39c2a"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.5.1"
|
||||
pub_semver:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: pub_semver
|
||||
sha256: "307de764d305289ff24ad257ad5c5793ce56d04947599ad68b3baa124105fc17"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.3"
|
||||
shelf:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: shelf
|
||||
sha256: c24a96135a2ccd62c64b69315a14adc5c3419df63b4d7c05832a346fdb73682c
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.4.0"
|
||||
shelf_hotreload:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: shelf_hotreload
|
||||
sha256: "5e7a68273d64a095384325d769c6a4885ea15c6aafee361098c0d8a5ecb5dcf6"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.4.0"
|
||||
shelf_packages_handler:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: shelf_packages_handler
|
||||
sha256: aef74dc9195746a384843102142ab65b6a4735bb3beea791e63527b88cc83306
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.0.1"
|
||||
shelf_static:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: shelf_static
|
||||
sha256: e792b76b96a36d4a41b819da593aff4bdd413576b3ba6150df5d8d9996d2e74c
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.1.1"
|
||||
shelf_web_socket:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: shelf_web_socket
|
||||
sha256: a988c0e8d8ffbdb8a28aa7ec8e449c260f3deb808781fe1284d22c5bba7156e8
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.3"
|
||||
source_map_stack_trace:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: source_map_stack_trace
|
||||
sha256: "84cf769ad83aa6bb61e0aa5a18e53aea683395f196a6f39c4c881fb90ed4f7ae"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.1"
|
||||
source_maps:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: source_maps
|
||||
sha256: "708b3f6b97248e5781f493b765c3337db11c5d2c81c3094f10904bfa8004c703"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.10.12"
|
||||
source_span:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: source_span
|
||||
sha256: dd904f795d4b4f3b870833847c461801f6750a9fa8e61ea5ac53f9422b31f250
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.9.1"
|
||||
stack_trace:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: stack_trace
|
||||
sha256: c3c7d8edb15bee7f0f74debd4b9c5f3c2ea86766fe4178eb2a18eb30a0bdaed5
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.11.0"
|
||||
stream_channel:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: stream_channel
|
||||
sha256: "83615bee9045c1d322bbbd1ba209b7a749c2cbcdcb3fdd1df8eb488b3279c1c8"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.1"
|
||||
stream_transform:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: stream_transform
|
||||
sha256: "14a00e794c7c11aa145a170587321aedce29769c08d7f58b1d141da75e3b1c6f"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.0"
|
||||
string_scanner:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: string_scanner
|
||||
sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.2.0"
|
||||
term_glyph:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: term_glyph
|
||||
sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.2.1"
|
||||
test:
|
||||
dependency: "direct dev"
|
||||
description:
|
||||
name: test
|
||||
sha256: "3dac9aecf2c3991d09b9cdde4f98ded7b30804a88a0d7e4e7e1678e78d6b97f4"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.24.1"
|
||||
test_api:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: test_api
|
||||
sha256: eb6ac1540b26de412b3403a163d919ba86f6a973fe6cc50ae3541b80092fdcfb
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.5.1"
|
||||
test_core:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: test_core
|
||||
sha256: "5138dbffb77b2289ecb12b81c11ba46036590b72a64a7a90d6ffb880f1a29e93"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.5.1"
|
||||
typed_data:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: typed_data
|
||||
sha256: "26f87ade979c47a150c9eaab93ccd2bebe70a27dc0b4b29517f2904f04eb11a5"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.3.1"
|
||||
very_good_analysis:
|
||||
dependency: "direct dev"
|
||||
description:
|
||||
name: very_good_analysis
|
||||
sha256: ebc48c51db35beeeec8c414e32f7bd78e612bd7f5992ccb0d46e19edaeb40b08
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.0.0+1"
|
||||
vm_service:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: vm_service
|
||||
sha256: f6deed8ed625c52864792459709183da231ebf66ff0cf09e69b573227c377efe
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "11.3.0"
|
||||
watcher:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: watcher
|
||||
sha256: "6a7f46926b01ce81bfc339da6a7f20afbe7733eff9846f6d6a5466aa4c6667c0"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.2"
|
||||
web_socket_channel:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: web_socket_channel
|
||||
sha256: ca49c0bc209c687b887f30527fb6a9d80040b072cc2990f34b9bec3e7663101b
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.3.0"
|
||||
webkit_inspection_protocol:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: webkit_inspection_protocol
|
||||
sha256: "67d3a8b6c79e1987d19d848b0892e582dbb0c66c57cc1fef58a177dd2aa2823d"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.2.0"
|
||||
yaml:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: yaml
|
||||
sha256: "23812a9b125b48d4007117254bca50abb6c712352927eece9e155207b1db2370"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.1.1"
|
||||
sdks:
|
||||
dart: ">=2.19.5 <3.0.0"
|
||||
@@ -0,0 +1,19 @@
|
||||
name: artifact_proxy
|
||||
description: Intercept and proxy Flutter artifact requests.
|
||||
version: 1.0.0
|
||||
repository: https://github.com/shorebirdtech/shorebird/
|
||||
publish_to: "none"
|
||||
|
||||
environment:
|
||||
sdk: ">=2.19.5 <3.0.0"
|
||||
|
||||
dependencies:
|
||||
collection: ^1.17.1
|
||||
shelf: ^1.4.0
|
||||
shelf_hotreload: ^1.4.0
|
||||
yaml: ^3.1.1
|
||||
|
||||
dev_dependencies:
|
||||
mocktail: ^0.3.0
|
||||
test: ^1.19.2
|
||||
very_good_analysis: ^4.0.0
|
||||
@@ -0,0 +1,96 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:artifact_proxy/artifact_proxy.dart';
|
||||
import 'package:shelf/shelf.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
||||
void main() {
|
||||
const shorebirdEngineRevision = 'ff32625d5bda6d3eb2eb131e30a4c26ed4960002';
|
||||
const flutterEngineRevision = 'ec975089acb540fc60752606a3d3ba809dd1528b';
|
||||
const shorebirdStorageBucket = 'download.shorebird.dev';
|
||||
const config = {
|
||||
'engine_mappings': {
|
||||
shorebirdEngineRevision: {
|
||||
'flutter_engine_revision': flutterEngineRevision,
|
||||
'shorebird_storage_bucket': shorebirdStorageBucket,
|
||||
'shorebird_artifact_overrides': [
|
||||
r'flutter_infra_release/flutter/$engine/android-x64-release/artifacts.zip'
|
||||
]
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Request buildRequest(String path) {
|
||||
return Request('GET', Uri.parse('http://localhost').replace(path: path));
|
||||
}
|
||||
|
||||
Matcher isRedirectTo(String location) {
|
||||
return isA<Response>()
|
||||
.having((r) => r.statusCode, 'status code', HttpStatus.found)
|
||||
.having((r) => r.headers['location'], 'location', location);
|
||||
}
|
||||
|
||||
group('artifactProxy', () {
|
||||
test(
|
||||
'should proxy to Flutter artifacts '
|
||||
'when no engine revision is detected', () async {
|
||||
const path = 'path/with/no/revision/foo.zip';
|
||||
final handler = artifactProxyHandler(config: config);
|
||||
final request = buildRequest(path);
|
||||
final response = await handler(request);
|
||||
expect(
|
||||
response,
|
||||
isRedirectTo('https://storage.googleapis.com/$path'),
|
||||
);
|
||||
});
|
||||
|
||||
test(
|
||||
'should proxy to Shorebird artifacts '
|
||||
'when an engine revision is detected', () async {
|
||||
const path =
|
||||
'flutter_infra_release/flutter/$shorebirdEngineRevision/android-x64-release/artifacts.zip';
|
||||
final handler = artifactProxyHandler(config: config);
|
||||
final request = buildRequest(path);
|
||||
final response = await handler(request);
|
||||
expect(
|
||||
response,
|
||||
isRedirectTo(
|
||||
'https://storage.googleapis.com/$shorebirdStorageBucket/$path',
|
||||
),
|
||||
);
|
||||
});
|
||||
|
||||
test(
|
||||
'should proxy to Flutter '
|
||||
'when no shorebird override is found', () async {
|
||||
const path =
|
||||
'flutter_infra_release/flutter/$shorebirdEngineRevision/unknown/artifacts.zip';
|
||||
final handler = artifactProxyHandler(config: config);
|
||||
final request = buildRequest(path);
|
||||
final response = await handler(request);
|
||||
expect(
|
||||
response,
|
||||
isRedirectTo(
|
||||
'https://storage.googleapis.com/${path.replaceFirst(shorebirdEngineRevision, flutterEngineRevision)}',
|
||||
),
|
||||
);
|
||||
});
|
||||
|
||||
test(
|
||||
'should proxy to Flutter '
|
||||
'when no shorebird override is found '
|
||||
'and path is chrome infra', () async {
|
||||
const path =
|
||||
'/flutter_infra_release/cipd/flutter/web/canvaskit_bundle/+/ztaLvbs5GPmlAwUosC7VVp7EQnNVknRpNuKdv7vmzaAC';
|
||||
final handler = artifactProxyHandler(config: config);
|
||||
final request = buildRequest(path);
|
||||
final response = await handler(request);
|
||||
expect(
|
||||
response,
|
||||
isRedirectTo(
|
||||
'https://chrome-infra-packages.appspot.com/dl/flutter/web/canvaskit_bundle/+/ztaLvbs5GPmlAwUosC7VVp7EQnNVknRpNuKdv7vmzaAC',
|
||||
),
|
||||
);
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -316,7 +316,7 @@ shorebird channels create --name MyChannel
|
||||
**Sample**
|
||||
|
||||
```
|
||||
shorebird channels create --name MyChannel
|
||||
shorebird channels create --name MyChannel
|
||||
|
||||
🚀 Ready to create a new channel!
|
||||
|
||||
|
||||
Reference in New Issue
Block a user