diff --git a/BUILD.bazel b/BUILD.bazel index 969543af..30d3dc11 100644 --- a/BUILD.bazel +++ b/BUILD.bazel @@ -6,9 +6,12 @@ load("@bazel_skylib//rules:build_test.bzl", "build_test") load("@build_bazel_rules_nodejs//:index.bzl", "pkg_npm") load("@npm_rules_js//:defs.bzl", "npm_link_all_packages") load("//tools:publish.bzl", "publish_files") +load("//tools/publish:npm_publish.bzl", "npm_publish") load("//tools/stamping:stamp_package.bzl", "stamp_package") load("//:index.bzl", "link_prerender_component", "prerender_component", "prerender_component_publish_files") +exports_files([".npmrc"], visibility = ["//visibility:public"]) + ts_config( name = "tsconfig", src = "tsconfig.json", @@ -41,6 +44,11 @@ npm_package( # See: https://github.com/dgp1130/rules_prerender/issues/48#issuecomment-1425257276 include_external_repositories = ["rules_prerender"], ) +npm_publish( + name = "rules_prerender_pkg_publish", + package = ":rules_prerender_pkg", + npmrc = ".npmrc", +) npm_link_package( name = "node_modules/rules_prerender", src = ":rules_prerender_pkg", diff --git a/packages/rules_prerender/declarative_shadow_dom/BUILD.bazel b/packages/rules_prerender/declarative_shadow_dom/BUILD.bazel index 18099149..7549af6a 100644 --- a/packages/rules_prerender/declarative_shadow_dom/BUILD.bazel +++ b/packages/rules_prerender/declarative_shadow_dom/BUILD.bazel @@ -10,6 +10,7 @@ load( load("//tools:jasmine.bzl", "jasmine_node_test") load("//tools:publish.bzl", "publish_files") load("//tools:typescript.bzl", "ts_project") +load("//tools/publish:npm_publish.bzl", "npm_publish") load("//tools/stamping:stamp_package.bzl", "stamp_package") publish_files( @@ -37,6 +38,11 @@ npm_package( # See: https://github.com/dgp1130/rules_prerender/issues/48#issuecomment-1425257276 include_external_repositories = ["rules_prerender"], ) +npm_publish( + name = "pkg_publish", + package = ":pkg", + npmrc = "//:.npmrc", +) prerender_component( name = "declarative_shadow_dom", diff --git a/tools/publish/BUILD.bazel b/tools/publish/BUILD.bazel new file mode 100644 index 00000000..253d6228 --- /dev/null +++ b/tools/publish/BUILD.bazel @@ -0,0 +1,8 @@ +load("@bazel_skylib//:bzl_library.bzl", "bzl_library") + +exports_files(["npm_publish.sh"], visibility = ["//visibility:public"]) + +bzl_library( + name = "npm_publish", + srcs = ["npm_publish.bzl"], +) diff --git a/tools/publish/npm_publish.bzl b/tools/publish/npm_publish.bzl new file mode 100644 index 00000000..7907f6ba --- /dev/null +++ b/tools/publish/npm_publish.bzl @@ -0,0 +1,59 @@ +load("@aspect_bazel_lib//lib:copy_to_bin.bzl", "copy_to_bin") +load("@aspect_rules_js//npm:providers.bzl", "NpmPackageInfo") +load("@bazel_skylib//rules:build_test.bzl", "build_test") +load("//common:label.bzl", "absolute", "file_path_of") + +def npm_publish(name, package, npmrc, testonly = None, visibility = None): + """Publishes the given `npm_package()` to NPM. + + Generates a binary which, when run, publishes the given package to NPM. + Authentication information should be provided via `_authToken` in the + provided `.npmrc` file. Also generates a test to make sure the binary builds + successfully, since this it is very likely nothing else will depend on this. + + Args: + name: Name of this target. + package: The `npm_package()` to publish. + npmrc: The `.npmrc` file containing authentication information. + testonly: https://bazel.build/reference/be/common-definitions#common-attributes + visibility: https://bazel.build/reference/be/common-definitions#common-attributes + """ + # For some reason we need to `copy_to_bin()` for the directory to show up in + # `sh_binary()` runfiles? TBH, I don't understand why this is necessary. + package_bin = "%s_package" % name + copy_to_bin( + name = package_bin, + srcs = [package], + testonly = testonly, + ) + + # Merge the `.npmrc` and package together, then run `npm publish`. + # Authentication information should be in the `.npmrc`. + native.sh_binary( + name = name, + srcs = [Label("//tools/publish:npm_publish.sh")], + data = [package_bin, npmrc, "@pnpm//:pnpm"], + args = [ + "rules_prerender/%s" % _normalize(file_path_of(absolute(package))), + "rules_prerender/%s" % _normalize(file_path_of(absolute(npmrc))), + "pnpm/pnpm.sh", + ], + deps = ["@bazel_tools//tools/bash/runfiles"], + testonly = testonly, + visibility = visibility, + ) + + # Always generate a test so the release process doesn't attempt to run + # multiple publish binaries only to find that the second one fails to build. + build_test( + name = "%s_test" % name, + targets = [":%s" % name], + ) + +# Bash runfiles is very particular about file paths, extra `./` paths are not +# allowed. +def _normalize(path): + normalized = path.replace("/./", "/") + if normalized.startswith("./"): + return normalized[2:] + return normalized diff --git a/tools/publish/npm_publish.sh b/tools/publish/npm_publish.sh new file mode 100755 index 00000000..32f627a3 --- /dev/null +++ b/tools/publish/npm_publish.sh @@ -0,0 +1,30 @@ +# --- begin runfiles.bash initialization v2 --- +# Copy-pasted from the Bazel Bash runfiles library v2. +set -uo pipefail; set +e; f=bazel_tools/tools/bash/runfiles/runfiles.bash +source "${RUNFILES_DIR:-/dev/null}/$f" 2>/dev/null || \ + source "$(grep -sm1 "^$f " "${RUNFILES_MANIFEST_FILE:-/dev/null}" | cut -f2- -d' ')" 2>/dev/null || \ + source "$0.runfiles/$f" 2>/dev/null || \ + source "$(grep -sm1 "^$f " "$0.runfiles_manifest" | cut -f2- -d' ')" 2>/dev/null || \ + source "$(grep -sm1 "^$f " "$0.exe.runfiles_manifest" | cut -f2- -d' ')" 2>/dev/null || \ + { echo>&2 "ERROR: cannot find $f"; exit 1; }; f=; set -e +# --- end runfiles.bash initialization v2 --- + +# Resolve arguments. +readonly PACKAGE="$(rlocation ${1})" +readonly NPMRC="$(rlocation ${2})" +readonly NPM="$(rlocation ${3})" + +# Make sure there isn't already an `.npmrc` file in the package. +if [[ -f "${PACKAGE}/.npmrc" ]]; then + echo ".npmrc already exists in `${PACKAGE}`, expected it not to." >&2 + exit 1 +fi + +# Merge the package and the `.npmrc` in the temporary staging directory. +readonly STAGING_DIRECTORY=$(mktemp -d) +cp -r ${PACKAGE}/* "${STAGING_DIRECTORY}" +cp "${NPMRC}" "${STAGING_DIRECTORY}/.npmrc" + +# Publish to NPM. Use `--no-git-checks` to ignore the `.git/` state, which is +# still discovered by NPM, even within a Bazel context. +"${NPM}" publish "${STAGING_DIRECTORY}" --no-git-checks --access public