mirror of
https://github.com/oven-sh/bun
synced 2026-02-02 15:08:46 +00:00
Update ci_info with more CI detection (#23708)
Fixes ENG-21481 Updates ci_info to include more CIs. It makes it codegen the ci detection based on the json from the ci-info package. Also it supports setting CI=true to force ci detected. --------- Co-authored-by: pfg <pfg@pfg.pw> Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
This commit is contained in:
@@ -782,6 +782,13 @@ fn addInternalImports(b: *Build, mod: *Module, opts: *BunBuildOptions) void {
|
||||
mod.addImport("cpp", cppImport);
|
||||
cppImport.addImport("bun", mod);
|
||||
}
|
||||
{
|
||||
const ciInfoImport = b.createModule(.{
|
||||
.root_source_file = (std.Build.LazyPath{ .cwd_relative = opts.codegen_path }).path(b, "ci_info.zig"),
|
||||
});
|
||||
mod.addImport("ci_info", ciInfoImport);
|
||||
ciInfoImport.addImport("bun", mod);
|
||||
}
|
||||
inline for (.{
|
||||
.{ .import = "completions-bash", .file = b.path("completions/bun.bash") },
|
||||
.{ .import = "completions-zsh", .file = b.path("completions/bun.zsh") },
|
||||
|
||||
@@ -317,6 +317,10 @@ set(BUN_CPP_OUTPUTS
|
||||
${CODEGEN_PATH}/cpp.zig
|
||||
)
|
||||
|
||||
set(BUN_CI_INFO_OUTPUTS
|
||||
${CODEGEN_PATH}/ci_info.zig
|
||||
)
|
||||
|
||||
register_command(
|
||||
TARGET
|
||||
bun-cppbind
|
||||
@@ -334,6 +338,21 @@ register_command(
|
||||
${BUN_CPP_OUTPUTS}
|
||||
)
|
||||
|
||||
register_command(
|
||||
TARGET
|
||||
bun-ci-info
|
||||
COMMENT
|
||||
"Generating CI info"
|
||||
COMMAND
|
||||
${BUN_EXECUTABLE}
|
||||
${CWD}/src/codegen/ci_info.ts
|
||||
${CODEGEN_PATH}/ci_info.zig
|
||||
SOURCES
|
||||
${BUN_JAVASCRIPT_CODEGEN_SOURCES}
|
||||
OUTPUTS
|
||||
${BUN_CI_INFO_OUTPUTS}
|
||||
)
|
||||
|
||||
register_command(
|
||||
TARGET
|
||||
bun-js-modules
|
||||
@@ -612,6 +631,7 @@ set(BUN_ZIG_GENERATED_SOURCES
|
||||
${BUN_ZIG_GENERATED_CLASSES_OUTPUTS}
|
||||
${BUN_JAVASCRIPT_OUTPUTS}
|
||||
${BUN_CPP_OUTPUTS}
|
||||
${BUN_CI_INFO_OUTPUTS}
|
||||
${BUN_BINDGENV2_ZIG_OUTPUTS}
|
||||
)
|
||||
|
||||
|
||||
@@ -278,7 +278,7 @@ fn genericExtend(this: *ScopeFunctions, globalThis: *JSGlobalObject, cfg: bun_te
|
||||
}
|
||||
|
||||
fn errorInCI(globalThis: *jsc.JSGlobalObject, signature: []const u8) bun.JSError!void {
|
||||
if (bun.detectCI()) |_| {
|
||||
if (bun.ci.isCI()) {
|
||||
return globalThis.throwPretty("{s} is disabled in CI environments to prevent accidentally skipping tests. To override, set the environment variable CI=false.", .{signature});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -744,7 +744,7 @@ pub const Expect = struct {
|
||||
}
|
||||
|
||||
if (needs_write) {
|
||||
if (bun.detectCI()) |_| {
|
||||
if (bun.ci.isCI()) {
|
||||
if (!update) {
|
||||
const signature = comptime getSignature(fn_name, "", false);
|
||||
// Only creating new snapshots can reach here (updating with mismatches errors earlier with diff)
|
||||
|
||||
@@ -501,7 +501,7 @@ pub fn captureTestLineNumber(callframe: *jsc.CallFrame, globalThis: *JSGlobalObj
|
||||
}
|
||||
|
||||
pub fn errorInCI(globalObject: *jsc.JSGlobalObject, message: []const u8) bun.JSError!void {
|
||||
if (bun.detectCI()) |_| {
|
||||
if (bun.ci.isCI()) {
|
||||
return globalObject.throwPretty("{s}\nTo override, set the environment variable CI=false.", .{message});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -86,7 +86,7 @@ pub const Snapshots = struct {
|
||||
|
||||
// doesn't exist. append to file bytes and add to hashmap.
|
||||
// Prevent snapshot creation in CI environments unless --update-snapshots is used
|
||||
if (bun.detectCI()) |_| {
|
||||
if (bun.ci.isCI()) {
|
||||
if (!this.update_snapshots) {
|
||||
// Store the snapshot name for error reporting
|
||||
if (this.last_error_snapshot_name) |old_name| {
|
||||
|
||||
@@ -174,7 +174,7 @@ pub const JSTerminated = error{
|
||||
|
||||
pub const JSOOM = OOM || JSError;
|
||||
|
||||
pub const detectCI = @import("./ci_info.zig").detectCI;
|
||||
pub const ci = @import("./ci_info.zig");
|
||||
|
||||
/// Cross-platform system APIs
|
||||
pub const sys = @import("./sys.zig");
|
||||
|
||||
431
src/ci_info.zig
431
src/ci_info.zig
@@ -1,422 +1,27 @@
|
||||
// A modified port of ci-info@4.0.0 (https://github.com/watson/ci-info)
|
||||
// Only gets the CI name, `isPR` is not implemented.
|
||||
// Main implementation is in src/codegen/ci_info.ts
|
||||
|
||||
// Names are changed to match what `npm publish` uses
|
||||
// https://github.com/npm/cli/blob/63d6a732c3c0e9c19fd4d147eaa5cc27c29b168d/workspaces/config/lib/definitions/definitions.js#L2129
|
||||
// `name.toLowerCase().split(' ').join('-')`
|
||||
var detectCIOnce = bun.once(detectUncached);
|
||||
var isCIOnce = bun.once(isCIUncached);
|
||||
|
||||
var ci_name: ?[]const u8 = null;
|
||||
|
||||
pub fn detectCI() ?[]const u8 {
|
||||
const ci = ci_name orelse ci_name: {
|
||||
CI.once.call();
|
||||
break :ci_name ci_name.?;
|
||||
};
|
||||
|
||||
return if (ci.len == 0) null else ci;
|
||||
/// returns true if the current process is running in a CI environment
|
||||
pub fn isCI() bool {
|
||||
return isCIOnce.call(.{});
|
||||
}
|
||||
|
||||
const CI = enum {
|
||||
@"agola-ci",
|
||||
appcircle,
|
||||
appveyor,
|
||||
@"aws-codebuild",
|
||||
@"azure-pipelines",
|
||||
bamboo,
|
||||
@"bitbucket-pipelines",
|
||||
bitrise,
|
||||
buddy,
|
||||
buildkite,
|
||||
circleci,
|
||||
@"cirrus-ci",
|
||||
codefresh,
|
||||
codemagic,
|
||||
codeship,
|
||||
drone,
|
||||
dsari,
|
||||
earthly,
|
||||
@"expo-application-services",
|
||||
gerrit,
|
||||
@"gitea-actions",
|
||||
@"github-actions",
|
||||
@"gitlab-ci",
|
||||
gocd,
|
||||
@"google-cloud-build",
|
||||
@"harness-ci",
|
||||
// heroku,
|
||||
hudson,
|
||||
jenkins,
|
||||
layerci,
|
||||
@"magnum-ci",
|
||||
@"netlify-ci",
|
||||
nevercode,
|
||||
prow,
|
||||
releasehub,
|
||||
render,
|
||||
@"sail-ci",
|
||||
screwdriver,
|
||||
semaphore,
|
||||
sourcehut,
|
||||
@"strider-cd",
|
||||
taskcluster,
|
||||
teamcity,
|
||||
@"travis-ci",
|
||||
vela,
|
||||
vercel,
|
||||
@"visual-studio-app-center",
|
||||
woodpecker,
|
||||
@"xcode-cloud",
|
||||
@"xcode-server",
|
||||
/// returns the CI name, or null if the CI name could not be determined. note that this can be null even if `isCI` is true.
|
||||
pub fn detectCIName() ?[]const u8 {
|
||||
return detectCIOnce.call(.{});
|
||||
}
|
||||
|
||||
pub var once = std.once(struct {
|
||||
pub fn once() void {
|
||||
var name: []const u8 = "";
|
||||
defer ci_name = name;
|
||||
|
||||
if (bun.env_var.CI.get()) |ci| {
|
||||
if (!ci) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Special case Heroku
|
||||
if (bun.env_var.NODE.get()) |node| {
|
||||
if (strings.containsComptime(node, "/app/.heroku/node/bin/node")) {
|
||||
name = "heroku";
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
ci: for (CI.array.values, 0..) |item, i| {
|
||||
const any, const pairs = item;
|
||||
|
||||
pairs: for (pairs) |pair| {
|
||||
const key, const value = pair;
|
||||
|
||||
if (bun.getenvZ(key)) |env| {
|
||||
if (value.len == 0 or bun.strings.eqlLong(env, value, true)) {
|
||||
if (!any) continue :pairs;
|
||||
|
||||
name = @tagName(Array.Indexer.keyForIndex(i));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!any) continue :ci;
|
||||
}
|
||||
|
||||
if (!any) {
|
||||
name = @tagName(Array.Indexer.keyForIndex(i));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}.once);
|
||||
|
||||
pub const Array = std.EnumArray(CI, struct { bool, []const [2][:0]const u8 });
|
||||
|
||||
pub const array = Array.init(.{
|
||||
.@"agola-ci" = .{
|
||||
false,
|
||||
&.{
|
||||
.{ "AGOLA_GIT_REF", "" },
|
||||
},
|
||||
},
|
||||
.appcircle = .{
|
||||
false,
|
||||
&.{
|
||||
.{ "AC_APPCIRCLE", "" },
|
||||
},
|
||||
},
|
||||
.appveyor = .{
|
||||
false,
|
||||
&.{
|
||||
.{ "APPVEYOR", "" },
|
||||
},
|
||||
},
|
||||
.@"aws-codebuild" = .{
|
||||
false,
|
||||
&.{
|
||||
.{ "CODEBUILD_BUILD_ARN", "" },
|
||||
},
|
||||
},
|
||||
.@"azure-pipelines" = .{
|
||||
false,
|
||||
&.{
|
||||
.{ "TF_BUILD", "" },
|
||||
},
|
||||
},
|
||||
.bamboo = .{
|
||||
false,
|
||||
&.{
|
||||
.{ "bamboo_planKey", "" },
|
||||
},
|
||||
},
|
||||
.@"bitbucket-pipelines" = .{
|
||||
false,
|
||||
&.{
|
||||
.{ "BITBUCKET_COMMIT", "" },
|
||||
},
|
||||
},
|
||||
.bitrise = .{
|
||||
false,
|
||||
&.{
|
||||
.{ "BITRISE_IO", "" },
|
||||
},
|
||||
},
|
||||
.buddy = .{
|
||||
false,
|
||||
&.{
|
||||
.{ "BUDDY_WORKSPACE_ID", "" },
|
||||
},
|
||||
},
|
||||
.buildkite = .{
|
||||
false,
|
||||
&.{
|
||||
.{ "BUILDKITE", "" },
|
||||
},
|
||||
},
|
||||
.circleci = .{
|
||||
false,
|
||||
&.{
|
||||
.{ "CIRCLECI", "" },
|
||||
},
|
||||
},
|
||||
.@"cirrus-ci" = .{
|
||||
false,
|
||||
&.{
|
||||
.{ "CIRRUS_CI", "" },
|
||||
},
|
||||
},
|
||||
.codefresh = .{
|
||||
false,
|
||||
&.{
|
||||
.{ "CF_BUILD_ID", "" },
|
||||
},
|
||||
},
|
||||
.codemagic = .{
|
||||
false,
|
||||
&.{
|
||||
.{ "CM_BUILD_ID", "" },
|
||||
},
|
||||
},
|
||||
.codeship = .{
|
||||
false,
|
||||
&.{
|
||||
.{ "CI_NAME", "codeship" },
|
||||
},
|
||||
},
|
||||
.drone = .{
|
||||
false,
|
||||
&.{
|
||||
.{ "DRONE", "" },
|
||||
},
|
||||
},
|
||||
.dsari = .{
|
||||
false,
|
||||
&.{
|
||||
.{ "DSARI", "" },
|
||||
},
|
||||
},
|
||||
.earthly = .{
|
||||
false,
|
||||
&.{
|
||||
.{ "EARTHLY_CI", "" },
|
||||
},
|
||||
},
|
||||
.@"expo-application-services" = .{
|
||||
false,
|
||||
&.{
|
||||
.{ "EAS_BUILD", "" },
|
||||
},
|
||||
},
|
||||
.gerrit = .{
|
||||
false,
|
||||
&.{
|
||||
.{ "GERRIT_PROJECT", "" },
|
||||
},
|
||||
},
|
||||
.@"gitea-actions" = .{
|
||||
false,
|
||||
&.{
|
||||
.{ "GITEA_ACTIONS", "" },
|
||||
},
|
||||
},
|
||||
.@"github-actions" = .{
|
||||
false,
|
||||
&.{
|
||||
.{ "GITHUB_ACTIONS", "" },
|
||||
},
|
||||
},
|
||||
.@"gitlab-ci" = .{
|
||||
false,
|
||||
&.{
|
||||
.{ "GITLAB_CI", "" },
|
||||
},
|
||||
},
|
||||
.gocd = .{
|
||||
false,
|
||||
&.{
|
||||
.{ "GO_PIPELINE_LABEL", "" },
|
||||
},
|
||||
},
|
||||
.@"google-cloud-build" = .{
|
||||
false,
|
||||
&.{
|
||||
.{ "BUILDER_OUTPUT", "" },
|
||||
},
|
||||
},
|
||||
.@"harness-ci" = .{
|
||||
false,
|
||||
&.{
|
||||
.{ "HARNESS_BUILD_ID", "" },
|
||||
},
|
||||
},
|
||||
.hudson = .{
|
||||
false,
|
||||
&.{
|
||||
.{ "HUDSON_URL", "" },
|
||||
},
|
||||
},
|
||||
.jenkins = .{
|
||||
false,
|
||||
&.{
|
||||
.{ "JENKINS_URL", "" },
|
||||
.{ "BUILD_ID", "" },
|
||||
},
|
||||
},
|
||||
.layerci = .{
|
||||
false,
|
||||
&.{
|
||||
.{ "LAYERCI", "" },
|
||||
},
|
||||
},
|
||||
.@"magnum-ci" = .{
|
||||
false,
|
||||
&.{
|
||||
.{ "MAGNUM", "" },
|
||||
},
|
||||
},
|
||||
.@"netlify-ci" = .{
|
||||
false,
|
||||
&.{
|
||||
.{ "NETLIFY", "" },
|
||||
},
|
||||
},
|
||||
.nevercode = .{
|
||||
false,
|
||||
&.{
|
||||
.{ "NEVERCODE", "" },
|
||||
},
|
||||
},
|
||||
.prow = .{
|
||||
false,
|
||||
&.{
|
||||
.{ "PROW_JOB_ID", "" },
|
||||
},
|
||||
},
|
||||
.releasehub = .{
|
||||
false,
|
||||
&.{
|
||||
.{ "RELEASE_BUILD_ID", "" },
|
||||
},
|
||||
},
|
||||
.render = .{
|
||||
false,
|
||||
&.{
|
||||
.{ "RENDER", "" },
|
||||
},
|
||||
},
|
||||
.@"sail-ci" = .{
|
||||
false,
|
||||
&.{
|
||||
.{ "SAILCI", "" },
|
||||
},
|
||||
},
|
||||
.screwdriver = .{
|
||||
false,
|
||||
&.{
|
||||
.{ "SCREWDRIVER", "" },
|
||||
},
|
||||
},
|
||||
.semaphore = .{
|
||||
false,
|
||||
&.{
|
||||
.{ "SEMAPHORE", "" },
|
||||
},
|
||||
},
|
||||
.sourcehut = .{
|
||||
false,
|
||||
&.{
|
||||
.{ "CI_NAME", "sourcehut" },
|
||||
},
|
||||
},
|
||||
.@"strider-cd" = .{
|
||||
false,
|
||||
&.{
|
||||
.{ "STRIDER", "" },
|
||||
},
|
||||
},
|
||||
.taskcluster = .{
|
||||
false,
|
||||
&.{
|
||||
.{ "TASK_ID", "" },
|
||||
.{ "RUN_ID", "" },
|
||||
},
|
||||
},
|
||||
.teamcity = .{
|
||||
false,
|
||||
&.{
|
||||
.{ "TEAMCITY_VERSION", "" },
|
||||
},
|
||||
},
|
||||
.@"travis-ci" = .{
|
||||
false,
|
||||
&.{
|
||||
.{ "TRAVIS", "" },
|
||||
},
|
||||
},
|
||||
.vela = .{
|
||||
false,
|
||||
&.{
|
||||
.{ "VELA", "" },
|
||||
},
|
||||
},
|
||||
.vercel = .{
|
||||
true,
|
||||
&.{
|
||||
.{ "NOW_BUILDER", "" },
|
||||
.{ "VERCEL", "" },
|
||||
},
|
||||
},
|
||||
.@"visual-studio-app-center" = .{
|
||||
false,
|
||||
&.{
|
||||
.{ "APPCENTER_BUILD_ID", "" },
|
||||
},
|
||||
},
|
||||
.woodpecker = .{
|
||||
false,
|
||||
&.{
|
||||
.{ "CI", "woodpecker" },
|
||||
},
|
||||
},
|
||||
.@"xcode-cloud" = .{
|
||||
false,
|
||||
&.{
|
||||
.{ "CI_XCODE_PROJECT", "" },
|
||||
},
|
||||
},
|
||||
.@"xcode-server" = .{
|
||||
false,
|
||||
&.{
|
||||
.{ "XCS", "" },
|
||||
},
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const std = @import("std");
|
||||
fn isCIUncached() bool {
|
||||
return bun.env_var.CI.get() orelse generated.isCIUncachedGenerated() or detectCIName() != null;
|
||||
}
|
||||
fn detectUncached() ?[]const u8 {
|
||||
if (bun.env_var.CI.get() == false) return null;
|
||||
return generated.detectUncachedGenerated();
|
||||
}
|
||||
|
||||
const bun = @import("bun");
|
||||
const strings = bun.strings;
|
||||
const generated = @import("ci_info");
|
||||
|
||||
@@ -1272,7 +1272,7 @@ pub const PublishCommand = struct {
|
||||
if (auth_type) |auth| @tagName(auth) else "web"
|
||||
else
|
||||
"legacy";
|
||||
const ci_name = bun.detectCI();
|
||||
const ci_name = bun.ci.detectCIName();
|
||||
|
||||
{
|
||||
headers.count("accept", "*/*");
|
||||
@@ -1299,14 +1299,7 @@ pub const PublishCommand = struct {
|
||||
}
|
||||
headers.count("npm-command", "publish");
|
||||
|
||||
try print_writer.print("{s} {s} {s} workspaces/{}{s}{s}", .{
|
||||
Global.user_agent,
|
||||
Global.os_name,
|
||||
Global.arch_name,
|
||||
uses_workspaces,
|
||||
if (ci_name != null) " ci/" else "",
|
||||
ci_name orelse "",
|
||||
});
|
||||
try print_writer.print("{s} {s} {s} workspaces/{}{s}{s}", .{ Global.user_agent, Global.os_name, Global.arch_name, uses_workspaces, if (ci_name != null) " ci/" else "", ci_name orelse "" });
|
||||
// headers.count("user-agent", "npm/10.8.3 node/v24.3.0 darwin arm64 workspaces/false");
|
||||
headers.count("user-agent", print_buf.items);
|
||||
print_buf.clearRetainingCapacity();
|
||||
@@ -1348,14 +1341,7 @@ pub const PublishCommand = struct {
|
||||
}
|
||||
headers.append("npm-command", "publish");
|
||||
|
||||
try print_writer.print("{s} {s} {s} workspaces/{}{s}{s}", .{
|
||||
Global.user_agent,
|
||||
Global.os_name,
|
||||
Global.arch_name,
|
||||
uses_workspaces,
|
||||
if (ci_name != null) " ci/" else "",
|
||||
ci_name orelse "",
|
||||
});
|
||||
try print_writer.print("{s} {s} {s} workspaces/{}{s}{s}", .{ Global.user_agent, Global.os_name, Global.arch_name, uses_workspaces, if (ci_name != null) " ci/" else "", ci_name orelse "" });
|
||||
// headers.append("user-agent", "npm/10.8.3 node/v24.3.0 darwin arm64 workspaces/false");
|
||||
headers.append("user-agent", print_buf.items);
|
||||
print_buf.clearRetainingCapacity();
|
||||
|
||||
454
src/codegen/ci_info.ts
Normal file
454
src/codegen/ci_info.ts
Normal file
@@ -0,0 +1,454 @@
|
||||
type Vendor = {
|
||||
name: string;
|
||||
constant: string;
|
||||
env: EnvMatch;
|
||||
pr?: unknown;
|
||||
};
|
||||
type EnvMatch =
|
||||
| string
|
||||
| EnvMatch[]
|
||||
| {
|
||||
env: string;
|
||||
includes: string;
|
||||
}
|
||||
| {
|
||||
any: string[];
|
||||
}
|
||||
| Record<string, string>;
|
||||
|
||||
// The vendors list is copied from https://github.com/watson/ci-info/blob/master/vendors.json
|
||||
// The extras list is copied and edited from https://github.com/watson/ci-info/blob/master/index.js line `exports.isCI = !!(...)`
|
||||
// To update, copy the JSON again.
|
||||
/*
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2016 Thomas Watson Steen
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
const extras: string[] = [
|
||||
"BUILD_ID", // Jenkins, Cloudbees
|
||||
"BUILD_NUMBER", // Jenkins, TeamCity
|
||||
"CI", // Travis CI, CircleCI, Cirrus CI, Gitlab CI, Appveyor, CodeShip, dsari, Cloudflare Pages/Workers
|
||||
"CI_APP_ID", // Appflow
|
||||
"CI_BUILD_ID", // Appflow
|
||||
"CI_BUILD_NUMBER", // Appflow
|
||||
"CI_NAME", // Codeship and others
|
||||
"CONTINUOUS_INTEGRATION", // Travis CI, Cirrus CI
|
||||
"RUN_ID", // TaskCluster, dsari
|
||||
];
|
||||
const vendors: Vendor[] = [
|
||||
{
|
||||
"name": "Agola CI",
|
||||
"constant": "AGOLA",
|
||||
"env": "AGOLA_GIT_REF",
|
||||
"pr": "AGOLA_PULL_REQUEST_ID",
|
||||
},
|
||||
{
|
||||
"name": "Appcircle",
|
||||
"constant": "APPCIRCLE",
|
||||
"env": "AC_APPCIRCLE",
|
||||
"pr": {
|
||||
"env": "AC_GIT_PR",
|
||||
"ne": "false",
|
||||
},
|
||||
},
|
||||
{
|
||||
"name": "AppVeyor",
|
||||
"constant": "APPVEYOR",
|
||||
"env": "APPVEYOR",
|
||||
"pr": "APPVEYOR_PULL_REQUEST_NUMBER",
|
||||
},
|
||||
{
|
||||
"name": "AWS CodeBuild",
|
||||
"constant": "CODEBUILD",
|
||||
"env": "CODEBUILD_BUILD_ARN",
|
||||
"pr": {
|
||||
"env": "CODEBUILD_WEBHOOK_EVENT",
|
||||
"any": ["PULL_REQUEST_CREATED", "PULL_REQUEST_UPDATED", "PULL_REQUEST_REOPENED"],
|
||||
},
|
||||
},
|
||||
{
|
||||
"name": "Azure Pipelines",
|
||||
"constant": "AZURE_PIPELINES",
|
||||
"env": "TF_BUILD",
|
||||
"pr": {
|
||||
"BUILD_REASON": "PullRequest",
|
||||
},
|
||||
},
|
||||
{
|
||||
"name": "Bamboo",
|
||||
"constant": "BAMBOO",
|
||||
"env": "bamboo_planKey",
|
||||
},
|
||||
{
|
||||
"name": "Bitbucket Pipelines",
|
||||
"constant": "BITBUCKET",
|
||||
"env": "BITBUCKET_COMMIT",
|
||||
"pr": "BITBUCKET_PR_ID",
|
||||
},
|
||||
{
|
||||
"name": "Bitrise",
|
||||
"constant": "BITRISE",
|
||||
"env": "BITRISE_IO",
|
||||
"pr": "BITRISE_PULL_REQUEST",
|
||||
},
|
||||
{
|
||||
"name": "Buddy",
|
||||
"constant": "BUDDY",
|
||||
"env": "BUDDY_WORKSPACE_ID",
|
||||
"pr": "BUDDY_EXECUTION_PULL_REQUEST_ID",
|
||||
},
|
||||
{
|
||||
"name": "Buildkite",
|
||||
"constant": "BUILDKITE",
|
||||
"env": "BUILDKITE",
|
||||
"pr": {
|
||||
"env": "BUILDKITE_PULL_REQUEST",
|
||||
"ne": "false",
|
||||
},
|
||||
},
|
||||
{
|
||||
"name": "CircleCI",
|
||||
"constant": "CIRCLE",
|
||||
"env": "CIRCLECI",
|
||||
"pr": "CIRCLE_PULL_REQUEST",
|
||||
},
|
||||
{
|
||||
"name": "Cirrus CI",
|
||||
"constant": "CIRRUS",
|
||||
"env": "CIRRUS_CI",
|
||||
"pr": "CIRRUS_PR",
|
||||
},
|
||||
{
|
||||
"name": "Cloudflare Pages",
|
||||
"constant": "CLOUDFLARE_PAGES",
|
||||
"env": "CF_PAGES",
|
||||
},
|
||||
{
|
||||
"name": "Cloudflare Workers",
|
||||
"constant": "CLOUDFLARE_WORKERS",
|
||||
"env": "WORKERS_CI",
|
||||
},
|
||||
{
|
||||
"name": "Codefresh",
|
||||
"constant": "CODEFRESH",
|
||||
"env": "CF_BUILD_ID",
|
||||
"pr": {
|
||||
"any": ["CF_PULL_REQUEST_NUMBER", "CF_PULL_REQUEST_ID"],
|
||||
},
|
||||
},
|
||||
{
|
||||
"name": "Codemagic",
|
||||
"constant": "CODEMAGIC",
|
||||
"env": "CM_BUILD_ID",
|
||||
"pr": "CM_PULL_REQUEST",
|
||||
},
|
||||
{
|
||||
"name": "Codeship",
|
||||
"constant": "CODESHIP",
|
||||
"env": {
|
||||
"CI_NAME": "codeship",
|
||||
},
|
||||
},
|
||||
{
|
||||
"name": "Drone",
|
||||
"constant": "DRONE",
|
||||
"env": "DRONE",
|
||||
"pr": {
|
||||
"DRONE_BUILD_EVENT": "pull_request",
|
||||
},
|
||||
},
|
||||
{
|
||||
"name": "dsari",
|
||||
"constant": "DSARI",
|
||||
"env": "DSARI",
|
||||
},
|
||||
{
|
||||
"name": "Earthly",
|
||||
"constant": "EARTHLY",
|
||||
"env": "EARTHLY_CI",
|
||||
},
|
||||
{
|
||||
"name": "Expo Application Services",
|
||||
"constant": "EAS",
|
||||
"env": "EAS_BUILD",
|
||||
},
|
||||
{
|
||||
"name": "Gerrit",
|
||||
"constant": "GERRIT",
|
||||
"env": "GERRIT_PROJECT",
|
||||
},
|
||||
{
|
||||
"name": "Gitea Actions",
|
||||
"constant": "GITEA_ACTIONS",
|
||||
"env": "GITEA_ACTIONS",
|
||||
},
|
||||
{
|
||||
"name": "GitHub Actions",
|
||||
"constant": "GITHUB_ACTIONS",
|
||||
"env": "GITHUB_ACTIONS",
|
||||
"pr": {
|
||||
"GITHUB_EVENT_NAME": "pull_request",
|
||||
},
|
||||
},
|
||||
{
|
||||
"name": "GitLab CI",
|
||||
"constant": "GITLAB",
|
||||
"env": "GITLAB_CI",
|
||||
"pr": "CI_MERGE_REQUEST_ID",
|
||||
},
|
||||
{
|
||||
"name": "GoCD",
|
||||
"constant": "GOCD",
|
||||
"env": "GO_PIPELINE_LABEL",
|
||||
},
|
||||
{
|
||||
"name": "Google Cloud Build",
|
||||
"constant": "GOOGLE_CLOUD_BUILD",
|
||||
"env": "BUILDER_OUTPUT",
|
||||
},
|
||||
{
|
||||
"name": "Harness CI",
|
||||
"constant": "HARNESS",
|
||||
"env": "HARNESS_BUILD_ID",
|
||||
},
|
||||
{
|
||||
"name": "Heroku",
|
||||
"constant": "HEROKU",
|
||||
"env": {
|
||||
"env": "NODE",
|
||||
"includes": "/app/.heroku/node/bin/node",
|
||||
},
|
||||
},
|
||||
{
|
||||
"name": "Hudson",
|
||||
"constant": "HUDSON",
|
||||
"env": "HUDSON_URL",
|
||||
},
|
||||
{
|
||||
"name": "Jenkins",
|
||||
"constant": "JENKINS",
|
||||
"env": ["JENKINS_URL", "BUILD_ID"],
|
||||
"pr": {
|
||||
"any": ["ghprbPullId", "CHANGE_ID"],
|
||||
},
|
||||
},
|
||||
{
|
||||
"name": "LayerCI",
|
||||
"constant": "LAYERCI",
|
||||
"env": "LAYERCI",
|
||||
"pr": "LAYERCI_PULL_REQUEST",
|
||||
},
|
||||
{
|
||||
"name": "Magnum CI",
|
||||
"constant": "MAGNUM",
|
||||
"env": "MAGNUM",
|
||||
},
|
||||
{
|
||||
"name": "Netlify CI",
|
||||
"constant": "NETLIFY",
|
||||
"env": "NETLIFY",
|
||||
"pr": {
|
||||
"env": "PULL_REQUEST",
|
||||
"ne": "false",
|
||||
},
|
||||
},
|
||||
{
|
||||
"name": "Nevercode",
|
||||
"constant": "NEVERCODE",
|
||||
"env": "NEVERCODE",
|
||||
"pr": {
|
||||
"env": "NEVERCODE_PULL_REQUEST",
|
||||
"ne": "false",
|
||||
},
|
||||
},
|
||||
{
|
||||
"name": "Prow",
|
||||
"constant": "PROW",
|
||||
"env": "PROW_JOB_ID",
|
||||
},
|
||||
{
|
||||
"name": "ReleaseHub",
|
||||
"constant": "RELEASEHUB",
|
||||
"env": "RELEASE_BUILD_ID",
|
||||
},
|
||||
{
|
||||
"name": "Render",
|
||||
"constant": "RENDER",
|
||||
"env": "RENDER",
|
||||
"pr": {
|
||||
"IS_PULL_REQUEST": "true",
|
||||
},
|
||||
},
|
||||
{
|
||||
"name": "Sail CI",
|
||||
"constant": "SAIL",
|
||||
"env": "SAILCI",
|
||||
"pr": "SAIL_PULL_REQUEST_NUMBER",
|
||||
},
|
||||
{
|
||||
"name": "Screwdriver",
|
||||
"constant": "SCREWDRIVER",
|
||||
"env": "SCREWDRIVER",
|
||||
"pr": {
|
||||
"env": "SD_PULL_REQUEST",
|
||||
"ne": "false",
|
||||
},
|
||||
},
|
||||
{
|
||||
"name": "Semaphore",
|
||||
"constant": "SEMAPHORE",
|
||||
"env": "SEMAPHORE",
|
||||
"pr": "PULL_REQUEST_NUMBER",
|
||||
},
|
||||
{
|
||||
"name": "Sourcehut",
|
||||
"constant": "SOURCEHUT",
|
||||
"env": {
|
||||
"CI_NAME": "sourcehut",
|
||||
},
|
||||
},
|
||||
{
|
||||
"name": "Strider CD",
|
||||
"constant": "STRIDER",
|
||||
"env": "STRIDER",
|
||||
},
|
||||
{
|
||||
"name": "TaskCluster",
|
||||
"constant": "TASKCLUSTER",
|
||||
"env": ["TASK_ID", "RUN_ID"],
|
||||
},
|
||||
{
|
||||
"name": "TeamCity",
|
||||
"constant": "TEAMCITY",
|
||||
"env": "TEAMCITY_VERSION",
|
||||
},
|
||||
{
|
||||
"name": "Travis CI",
|
||||
"constant": "TRAVIS",
|
||||
"env": "TRAVIS",
|
||||
"pr": {
|
||||
"env": "TRAVIS_PULL_REQUEST",
|
||||
"ne": "false",
|
||||
},
|
||||
},
|
||||
{
|
||||
"name": "Vela",
|
||||
"constant": "VELA",
|
||||
"env": "VELA",
|
||||
"pr": {
|
||||
"VELA_PULL_REQUEST": "1",
|
||||
},
|
||||
},
|
||||
{
|
||||
"name": "Vercel",
|
||||
"constant": "VERCEL",
|
||||
"env": {
|
||||
"any": ["NOW_BUILDER", "VERCEL"],
|
||||
},
|
||||
"pr": "VERCEL_GIT_PULL_REQUEST_ID",
|
||||
},
|
||||
{
|
||||
"name": "Visual Studio App Center",
|
||||
"constant": "APPCENTER",
|
||||
"env": "APPCENTER_BUILD_ID",
|
||||
},
|
||||
{
|
||||
"name": "Woodpecker",
|
||||
"constant": "WOODPECKER",
|
||||
"env": {
|
||||
"CI": "woodpecker",
|
||||
},
|
||||
"pr": {
|
||||
"CI_BUILD_EVENT": "pull_request",
|
||||
},
|
||||
},
|
||||
{
|
||||
"name": "Xcode Cloud",
|
||||
"constant": "XCODE_CLOUD",
|
||||
"env": "CI_XCODE_PROJECT",
|
||||
"pr": "CI_PULL_REQUEST_NUMBER",
|
||||
},
|
||||
{
|
||||
"name": "Xcode Server",
|
||||
"constant": "XCODE_SERVER",
|
||||
"env": "XCS",
|
||||
},
|
||||
];
|
||||
|
||||
function genEnvCondition(env: EnvMatch): string {
|
||||
if (typeof env === "string") {
|
||||
return `bun.getenvZ(${JSON.stringify(env)}) != null`;
|
||||
} else if (Array.isArray(env)) {
|
||||
return env
|
||||
.map(itm => {
|
||||
const res = genEnvCondition(itm);
|
||||
if (res.includes(" or ")) return `(${res})`;
|
||||
return res;
|
||||
})
|
||||
.join(" and ");
|
||||
} else if (typeof env === "object") {
|
||||
if ("env" in env) {
|
||||
return `bun.strings.containsComptime(bun.getenvZ(${JSON.stringify(env.env)}) orelse "", ${JSON.stringify(env.includes)})`;
|
||||
} else if ("any" in env) {
|
||||
return (env.any as string[]).map(genEnvCondition).join(" or ");
|
||||
} else {
|
||||
return Object.entries(env)
|
||||
.map(
|
||||
([key, value]) =>
|
||||
`bun.strings.eqlComptime(bun.getenvZ(${JSON.stringify(key)}) orelse "", ${JSON.stringify(value)})`,
|
||||
)
|
||||
.join(" and ");
|
||||
}
|
||||
} else throw new Error("Not implemented");
|
||||
}
|
||||
|
||||
let codegen: string[] = [];
|
||||
codegen.push(`/// Generated by src/codegen/ci_info.ts\n`);
|
||||
codegen.push(`pub fn isCIUncachedGenerated() bool {\n`);
|
||||
for (const extra of extras) {
|
||||
codegen.push(` if (${genEnvCondition(extra)}) return true;\n`);
|
||||
}
|
||||
codegen.push(` return false;\n`);
|
||||
codegen.push(`}\n`);
|
||||
codegen.push(`\n`);
|
||||
codegen.push(`/// Generated by src/codegen/ci_info.ts\n`);
|
||||
codegen.push(`pub fn detectUncachedGenerated() ?[]const u8 {\n`);
|
||||
for (const vendor of vendors) {
|
||||
// Names are changed to match what `npm publish` uses
|
||||
// https://github.com/npm/cli/blob/63d6a732c3c0e9c19fd4d147eaa5cc27c29b168d/workspaces/config/lib/definitions/definitions.js#L2129
|
||||
const npm_style_name = vendor.name.toLowerCase().replaceAll(" ", "-");
|
||||
codegen.push(` if (${genEnvCondition(vendor.env)}) return ${JSON.stringify(npm_style_name)};\n`);
|
||||
}
|
||||
codegen.push(` return null;\n`);
|
||||
codegen.push(`}\n`);
|
||||
codegen.push(`\n`);
|
||||
codegen.push(`const bun = @import("bun");\n`);
|
||||
const result = codegen.join("");
|
||||
|
||||
if (import.meta.main) {
|
||||
const args = process.argv.slice(2);
|
||||
const out = args[0];
|
||||
if (out) {
|
||||
await Bun.write(out, result);
|
||||
} else {
|
||||
console.log(result);
|
||||
}
|
||||
}
|
||||
@@ -97,7 +97,6 @@ pub const JENKINS_URL = New(kind.string, "JENKINS_URL", .{});
|
||||
/// `MIMALLOC_VERBOSE`, documented here: https://microsoft.github.io/mimalloc/environment.html
|
||||
pub const MI_VERBOSE = New(kind.boolean, "MI_VERBOSE", .{ .default = false });
|
||||
pub const NO_COLOR = New(kind.boolean, "NO_COLOR", .{ .default = false });
|
||||
pub const NODE = New(kind.string, "NODE", .{});
|
||||
pub const NODE_CHANNEL_FD = New(kind.string, "NODE_CHANNEL_FD", .{});
|
||||
pub const NODE_PRESERVE_SYMLINKS_MAIN = New(kind.boolean, "NODE_PRESERVE_SYMLINKS_MAIN", .{ .default = false });
|
||||
pub const NODE_USE_SYSTEM_CA = New(kind.boolean, "NODE_USE_SYSTEM_CA", .{ .default = false });
|
||||
|
||||
@@ -20,7 +20,7 @@ pub fn whoami(allocator: std.mem.Allocator, manager: *PackageManager) WhoamiErro
|
||||
}
|
||||
|
||||
const auth_type = if (manager.options.publish_config.auth_type) |auth_type| @tagName(auth_type) else "web";
|
||||
const ci_name = bun.detectCI();
|
||||
const ci_name = bun.ci.detectCIName();
|
||||
|
||||
var print_buf = std.array_list.Managed(u8).init(allocator);
|
||||
defer print_buf.deinit();
|
||||
@@ -69,14 +69,7 @@ pub fn whoami(allocator: std.mem.Allocator, manager: *PackageManager) WhoamiErro
|
||||
headers.append("npm-auth-type", auth_type);
|
||||
headers.append("npm-command", "whoami");
|
||||
|
||||
try print_writer.print("{s} {s} {s} workspaces/{}{s}{s}", .{
|
||||
Global.user_agent,
|
||||
Global.os_name,
|
||||
Global.arch_name,
|
||||
false,
|
||||
if (ci_name != null) " ci/" else "",
|
||||
ci_name orelse "",
|
||||
});
|
||||
try print_writer.print("{s} {s} {s} workspaces/{}{s}{s}", .{ Global.user_agent, Global.os_name, Global.arch_name, false, if (ci_name != null) " ci/" else "", ci_name orelse "" });
|
||||
headers.append("user-agent", print_buf.items);
|
||||
print_buf.clearRetainingCapacity();
|
||||
|
||||
|
||||
5
test/cli/env/ci-info.fixture.ts
vendored
Normal file
5
test/cli/env/ci-info.fixture.ts
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
import { test, expect } from "bun:test";
|
||||
|
||||
test.only("only", () => {
|
||||
expect(1 + 1).toBe(2);
|
||||
});
|
||||
48
test/cli/env/ci-info.test.ts
vendored
Normal file
48
test/cli/env/ci-info.test.ts
vendored
Normal file
@@ -0,0 +1,48 @@
|
||||
import { describe, expect, test } from "bun:test";
|
||||
import { bunEnv, bunExe } from "../../harness";
|
||||
|
||||
const cleanEnv = { ...bunEnv };
|
||||
delete cleanEnv.GITHUB_ACTIONS;
|
||||
delete cleanEnv.GITLAB_CI;
|
||||
delete cleanEnv.CIRCLECI;
|
||||
delete cleanEnv.TRAVIS;
|
||||
delete cleanEnv.BUILDKITE;
|
||||
delete cleanEnv.JENKINS_URL;
|
||||
delete cleanEnv.BUILD_ID;
|
||||
delete cleanEnv.CI;
|
||||
|
||||
async function performTest(env: Record<string, string | undefined>, result: "deny-only" | "allow-only") {
|
||||
await using proc = Bun.spawn({
|
||||
cmd: [bunExe(), "test", "./ci-info.fixture.ts"],
|
||||
env,
|
||||
cwd: import.meta.dir,
|
||||
stdout: "pipe",
|
||||
stderr: "pipe",
|
||||
});
|
||||
|
||||
const [stdout, stderr, exitCode] = await Promise.all([proc.stdout.text(), proc.stderr.text(), proc.exited]);
|
||||
|
||||
// test.only should work (not throw) when CI=false
|
||||
if (result === "deny-only") {
|
||||
expect(stderr).toContain(".only is disabled in CI environments");
|
||||
expect(exitCode).toBe(1);
|
||||
} else {
|
||||
expect(stderr).toContain("1 pass");
|
||||
expect(exitCode).toBe(0);
|
||||
}
|
||||
}
|
||||
|
||||
describe("CI detection", () => {
|
||||
test("Without CI env vars, test.only should work", async () => {
|
||||
await performTest(cleanEnv, "allow-only");
|
||||
});
|
||||
test("CI=false disables CI detection even with GITHUB_ACTIONS=true", async () => {
|
||||
await performTest({ ...cleanEnv, CI: "false", GITHUB_ACTIONS: "true" }, "allow-only");
|
||||
});
|
||||
test("CI=true enables CI detection even with no CI env vars", async () => {
|
||||
await performTest({ ...cleanEnv, CI: "true" }, "deny-only");
|
||||
});
|
||||
test("CI=true enables CI detection with GITHUB_ACTIONS=true", async () => {
|
||||
await performTest({ ...cleanEnv, CI: "true", GITHUB_ACTIONS: "true" }, "deny-only");
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user