From 1f50dcd83405d82af997aea128e6c6f6f5585c81 Mon Sep 17 00:00:00 2001 From: Daniel Lee Date: Tue, 17 Oct 2023 17:34:51 -0700 Subject: [PATCH] Add app hosting builder image PiperOrigin-RevId: 574312263 Change-Id: I4d2c0ad6b751151cb93a316dd36a28afaf61e308 --- builders/BUILD.bazel | 1 + builders/firebase/apphosting/BUILD.bazel | 18 +++ builders/firebase/apphosting/README.md | 25 +++++ .../apphosting/acceptance/BUILD.bazel | 34 ++++++ .../apphosting/acceptance/acceptance.go | 24 ++++ .../apphosting/acceptance/config.yaml | 25 +++++ .../apphosting/acceptance/nodejs_test.go | 105 ++++++++++++++++++ builders/firebase/apphosting/builder.toml | 43 +++++++ 8 files changed, 275 insertions(+) create mode 100644 builders/firebase/apphosting/BUILD.bazel create mode 100644 builders/firebase/apphosting/README.md create mode 100644 builders/firebase/apphosting/acceptance/BUILD.bazel create mode 100644 builders/firebase/apphosting/acceptance/acceptance.go create mode 100644 builders/firebase/apphosting/acceptance/config.yaml create mode 100644 builders/firebase/apphosting/acceptance/nodejs_test.go create mode 100644 builders/firebase/apphosting/builder.toml diff --git a/builders/BUILD.bazel b/builders/BUILD.bazel index c12459609..8c6e40792 100644 --- a/builders/BUILD.bazel +++ b/builders/BUILD.bazel @@ -46,6 +46,7 @@ package_group( package_group( name = "nodejs_builders", packages = [ + "//builders/firebase/apphosting", "//builders/gcp/base", "//builders/nodejs", ], diff --git a/builders/firebase/apphosting/BUILD.bazel b/builders/firebase/apphosting/BUILD.bazel new file mode 100644 index 000000000..e425c7c74 --- /dev/null +++ b/builders/firebase/apphosting/BUILD.bazel @@ -0,0 +1,18 @@ +load("//tools:defs.bzl", "builder") + +licenses(["notice"]) + +package(default_visibility = [ + "//builders/firebase/apphosting/acceptance:__pkg__", +]) + +builder( + name = "builder", + buildpacks = [ + "//cmd/nodejs/npm:npm.tgz", + "//cmd/nodejs/pnpm:pnpm.tgz", + "//cmd/nodejs/runtime:runtime.tgz", + "//cmd/nodejs/yarn:yarn.tgz", + ], + image = "firebase/apphosting", +) diff --git a/builders/firebase/apphosting/README.md b/builders/firebase/apphosting/README.md new file mode 100644 index 000000000..7abbdf06d --- /dev/null +++ b/builders/firebase/apphosting/README.md @@ -0,0 +1,25 @@ +# The Firebase App Hosting Builder +This directory contains the definition of the Firebase App Hosting builder. + +IMPORTANT: Firebase "App Hosting" is a new product name from Firebase and unrelated to "apphosting" a.k.a. App Engine. + +## Build the Image +To build the builder image, run: + +```bash +bazel build //builders/firebase/apphosting:builder.image +``` + +## Build a Test Application +To build the sample application [generic/simple](../../testdata/nodejs/generic/simple/), run: + +```bash +pack build sample-nodejs --builder gcp/firebase/apphosting --path builders/testdata/nodejs/generic/simple/ --trust-builder -v +``` + +## Acceptance Tests +To run the acceptance tests across all the products, run: + +```bash +bazel test //builders/firebase/apphosting/acceptance:nodejs_test +``` \ No newline at end of file diff --git a/builders/firebase/apphosting/acceptance/BUILD.bazel b/builders/firebase/apphosting/acceptance/BUILD.bazel new file mode 100644 index 000000000..4f19e3975 --- /dev/null +++ b/builders/firebase/apphosting/acceptance/BUILD.bazel @@ -0,0 +1,34 @@ +load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test") + +licenses(["notice"]) + +exports_files(["config.yaml"]) + +go_library( + name = "acceptance", + srcs = ["acceptance.go"], + importpath = "github.com/GoogleCloudPlatform/buildpacks/" + package_name(), +) + +go_test( + name = "nodejs_test", + size = "enormous", + srcs = ["nodejs_test.go"], + args = [ + "-test-data=$(location //builders/testdata/nodejs:generic)", + "-structure-test-config=$(location :config.yaml)", + "-builder-source=$(location //builders/firebase/apphosting:builder.tar)", + "-builder-prefix=firebase-apphosting-nodejs-test-", + ], + data = [ + ":config.yaml", + "//builders/firebase/apphosting:builder.tar", + "//builders/testdata/nodejs:generic", + ], + embed = [":acceptance"], + rundir = ".", + tags = [ + "local", + ], + deps = ["//internal/acceptance"], +) diff --git a/builders/firebase/apphosting/acceptance/acceptance.go b/builders/firebase/apphosting/acceptance/acceptance.go new file mode 100644 index 000000000..6a9ae0c0d --- /dev/null +++ b/builders/firebase/apphosting/acceptance/acceptance.go @@ -0,0 +1,24 @@ +// Copyright 2023 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Package acceptance implements acceptance tests for a buildpack builder. +package acceptance + +const ( + // Buildpack identifiers used to verify that buildpacks were or were not used. + nodeNPM = "google.nodejs.npm" + nodePNPM = "google.nodejs.pnpm" + nodeRuntime = "google.nodejs.runtime" + nodeYarn = "google.nodejs.yarn" +) diff --git a/builders/firebase/apphosting/acceptance/config.yaml b/builders/firebase/apphosting/acceptance/config.yaml new file mode 100644 index 000000000..e91016a42 --- /dev/null +++ b/builders/firebase/apphosting/acceptance/config.yaml @@ -0,0 +1,25 @@ +# Copyright 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Test container structure using a centigrate image with a custom entrypoint. +# See https://github.com/GoogleContainerTools/container-structure-test for the configuration format. + +schemaVersion: '2.0.0' + +metadataTest: + envVars: + - key: PORT + value: 8080 + entrypoint: ['/cnb/process/web'] + cmd: [] diff --git a/builders/firebase/apphosting/acceptance/nodejs_test.go b/builders/firebase/apphosting/acceptance/nodejs_test.go new file mode 100644 index 000000000..c4329f48b --- /dev/null +++ b/builders/firebase/apphosting/acceptance/nodejs_test.go @@ -0,0 +1,105 @@ +// Copyright 2023 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +package acceptance + +import ( + "testing" + + "github.com/GoogleCloudPlatform/buildpacks/internal/acceptance" +) + +func init() { + acceptance.DefineFlags() +} + +func TestAcceptanceNodeJs(t *testing.T) { + imageCtx, cleanup := acceptance.ProvisionImages(t) + t.Cleanup(cleanup) + + testCases := []acceptance.Test{ + { + Name: "simple application", + App: "simple", + MustUse: []string{nodeRuntime, nodeNPM}, + EnableCacheTest: true, + }, + { + // Tests a specific versions of Node.js available on dl.google.com. + Name: "runtime version 16.17.1", + App: "simple", + Path: "/version?want=16.17.1", + Env: []string{"GOOGLE_NODEJS_VERSION=16.17.1"}, + MustUse: []string{nodeRuntime}, + }, + { + Name: "yarn", + App: "yarn", + MustUse: []string{nodeRuntime, nodeYarn}, + MustNotUse: []string{nodeNPM, nodePNPM}, + }, + { + Name: "pnpm", + App: "pnpm", + MustUse: []string{nodeRuntime, nodePNPM}, + MustNotUse: []string{nodeNPM, nodeYarn}, + }, + { + Name: "runtime version with npm ci", + App: "simple", + Path: "/version?want=16.18.1", + Env: []string{"GOOGLE_RUNTIME_VERSION=16.18.1"}, + MustUse: []string{nodeRuntime, nodeNPM}, + MustNotUse: []string{nodePNPM, nodeYarn}, + }, + { + Name: "NPM version specified", + // npm@8 requires nodejs@12+ + VersionInclusionConstraint: ">= 12.0.0", + App: "npm_version_specified", + MustOutput: []string{"npm --version\n\n8.3.1"}, + Path: "/version?want=8.3.1", + }, + } + for _, tc := range acceptance.FilterTests(t, imageCtx, testCases) { + tc := tc + t.Run(tc.Name, func(t *testing.T) { + t.Parallel() + + acceptance.TestApp(t, imageCtx, tc) + }) + } +} + +func TestFailuresNodeJs(t *testing.T) { + imageCtx, cleanup := acceptance.ProvisionImages(t) + t.Cleanup(cleanup) + + testCases := []acceptance.FailureTest{ + { + Name: "bad runtime version", + App: "simple", + Env: []string{"GOOGLE_RUNTIME_VERSION=BAD_NEWS_BEARS"}, + MustMatch: "invalid Node.js version specified", + }, + } + + for _, tc := range testCases { + tc := tc + t.Run(tc.Name, func(t *testing.T) { + t.Parallel() + + acceptance.TestBuildFailure(t, imageCtx, tc) + }) + } +} diff --git a/builders/firebase/apphosting/builder.toml b/builders/firebase/apphosting/builder.toml new file mode 100644 index 000000000..0066ddb34 --- /dev/null +++ b/builders/firebase/apphosting/builder.toml @@ -0,0 +1,43 @@ +description = "Builder for Firebase App Hosting" + +[[buildpacks]] + id = "google.nodejs.npm" + uri = "npm.tgz" + +[[buildpacks]] + id = "google.nodejs.runtime" + uri = "runtime.tgz" + +[[buildpacks]] + id = "google.nodejs.yarn" + uri = "yarn.tgz" + +[[buildpacks]] + id = "google.nodejs.pnpm" + uri = "pnpm.tgz" + +[[order]] + [[order.group]] + id = "google.nodejs.runtime" + [[order.group]] + id = "google.nodejs.yarn" + +[[order]] + [[order.group]] + id = "google.nodejs.runtime" + [[order.group]] + id = "google.nodejs.pnpm" + +[[order]] + [[order.group]] + id = "google.nodejs.runtime" + [[order.group]] + id = "google.nodejs.npm" + +[stack] + id = "google.min.22" + build-image = "gcr.io/gae-runtimes/buildpacks/stacks/google-min-22/build" + run-image = "gcr.io/gae-runtimes/buildpacks/stacks/google-min-22/run" + +[lifecycle] + version = "0.17.0" \ No newline at end of file