Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ similarly to bb-browser, which it is aimed at replacing.
Both the backend and the frontend is configured via a jsonnet configuration
file. Look at `config/portal.jsonnet` for an example configuration file, and
`pkg/proto/configuration/bb_portal/bb_portal.proto` and
`pkg/proto/configuration/frontend/frontend.proto` for the configuration schema.
`pkg/proto/configuration/frontend/frontend.proto` for the configuration schema. See [CI-integration.md](docs/CI-integration.md) for instructions on how to integrate with different CI systems.

## Frontend

Expand Down
31 changes: 31 additions & 0 deletions config/gh-actions.jmespath
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
{
"username": env.USER
"hostname": env.HOSTNAME
"sourceControls": [
{
"repo": env.GITHUB_REPOSITORY
"repoUrl": (env.GITHUB_SERVER_URL && env.GITHUB_REPOSITORY) && join('/', [env.GITHUB_SERVER_URL , env.GITHUB_REPOSITORY]) || `null`
"ref": env.GITHUB_REF
"refUrl": (env.GITHUB_SERVER_URL && env.GITHUB_REPOSITORY && env.GITHUB_REF_NAME && ends_with(env.GITHUB_REF_NAME, '/merge')) && join('/', [env.GITHUB_SERVER_URL, env.GITHUB_REPOSITORY, 'pull', env.GITHUB_REF_NAME]) || (env.GITHUB_SERVER_URL && env.GITHUB_REPOSITORY && env.GITHUB_REF) && join('/', [env.GITHUB_SERVER_URL, env.GITHUB_REPOSITORY, 'tree', env.GITHUB_REF]) || `null`
"commit": env.GITHUB_SHA
"commitUrl": (env.GITHUB_SERVER_URL && env.GITHUB_REPOSITORY && env.GITHUB_SHA) && join('/', [env.GITHUB_SERVER_URL, env.GITHUB_REPOSITORY, 'commit', env.GITHUB_SHA]) || `null`
}
]
"invocationTags": {
"pull_request": env.GITHUB_REF_NAME && ends_with(env.GITHUB_REF_NAME, '/merge') && env.GITHUB_REF_NAME || `null`
"pull_request_url": (env.GITHUB_SERVER_URL && env.GITHUB_REPOSITORY && env.GITHUB_REF_NAME && ends_with(env.GITHUB_REF_NAME, '/merge')) && join('/', [env.GITHUB_SERVER_URL, env.GITHUB_REPOSITORY, 'pull', env.GITHUB_REF_NAME]) || `null`
"workflow": env.GITHUB_WORKFLOW
"workflow_url": (env.GITHUB_SERVER_URL && env.GITHUB_REPOSITORY && env.GITHUB_RUN_ID) && join('/', [env.GITHUB_SERVER_URL , env.GITHUB_REPOSITORY, 'actions', 'runs', env.GITHUB_RUN_ID]) || `null`
"job": env.GITHUB_JOB
"action": env.GITHUB_ACTION
}
"buildTags": {
"repo": env.GITHUB_REPOSITORY
"repo_url": (env.GITHUB_SERVER_URL && env.GITHUB_REPOSITORY) && join('/', [env.GITHUB_SERVER_URL , env.GITHUB_REPOSITORY]) || `null`
"pull_request": env.GITHUB_REF_NAME && ends_with(env.GITHUB_REF_NAME, '/merge') && env.GITHUB_REF_NAME || `null`
"pull_request_url": (env.GITHUB_SERVER_URL && env.GITHUB_REPOSITORY && env.GITHUB_REF_NAME && ends_with(env.GITHUB_REF_NAME, '/merge')) && join('/', [env.GITHUB_SERVER_URL, env.GITHUB_REPOSITORY, 'pull', env.GITHUB_REF_NAME]) || `null`
"workflow": env.GITHUB_WORKFLOW
"workflow_url": (env.GITHUB_SERVER_URL && env.GITHUB_REPOSITORY && env.GITHUB_RUN_ID) && join('/', [env.GITHUB_SERVER_URL , env.GITHUB_REPOSITORY, 'actions', 'runs', env.GITHUB_RUN_ID]) || `null`
"build_id": (env.GITHUB_SERVER_URL && env.GITHUB_REPOSITORY && env.GITHUB_RUN_ID) && join('/', [env.GITHUB_SERVER_URL , env.GITHUB_REPOSITORY, 'actions', 'runs', env.GITHUB_RUN_ID]) || `null`
}
}
27 changes: 27 additions & 0 deletions config/gitlab.jmespath
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
{
"hostname": env.HOSTNAME
"sourceControls": [
{
"repo": env.CI_PROJECT_PATH
"repoUrl": env.CI_PROJECT_URL
"ref": env.CI_COMMIT_REF_NAME
"refUrl": (env.CI_PROJECT_URL && env.CI_COMMIT_REF_SLUG) && join('/', [env.CI_PROJECT_URL, '-', 'tree', env.CI_COMMIT_REF_SLUG]) || `null`
"commit": env.CI_COMMIT_SHA
"commitUrl": (env.CI_PROJECT_URL && env.CI_COMMIT_SHA) && join('/', [env.CI_PROJECT_URL, '-', 'commit', env.CI_COMMIT_SHA]) || `null`
}
]
"invocationTags": {
"pipeline": env.CI_PIPELINE_ID
"pipeline_url": env.CI_PIPELINE_URL
"job": env.CI_JOB_NAME
"job_url": env.CI_JOB_URL
"job_stage": env.CI_JOB_STAGE
}
"buildTags": {
"repo": env.CI_PROJECT_PATH
"repo_url": env.CI_PROJECT_URL
"pipeline": env.CI_PIPELINE_ID
"pipeline_url": env.CI_PIPELINE_URL
"build_id": env.CI_PIPELINE_URL
}
}
17 changes: 17 additions & 0 deletions config/portal.jsonnet
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@
// At least one service should be configured, otherwise the portal will not
// do anything useful.

local githubActionsExtractor = importstr 'gh-actions.jmespath';
local gitlabExtractor = importstr 'gitlab.jmespath';
local semaphoreExtractor = importstr 'semaphore.jmespath';

{
global: {
tracing: {
Expand Down Expand Up @@ -90,6 +94,10 @@
invocationRetention: '604800s',
},
minEventBatchDuration: '0.1s',
invocationMetadataExtractor: {
expression: githubActionsExtractor,
},
buildKey: "build_id",
},

// The BrowserService can be disabled by not setting this field.
Expand Down Expand Up @@ -143,6 +151,15 @@
icon: { slack: {} },
},
],
additionalBuildColumns: [
{ title: 'Repo', value_key: 'repo', url_key: 'repo_url' },
{ title: 'PR', value_key: 'pull_request', url_key: 'pull_request_url' },
{ title: 'Workflow', value_key: 'workflow', url_key: 'workflow_url' },
],
additionalBuildInvocationColumns: [
{ title: 'Job', value_key: 'job' },
{ title: 'Action', value_key: 'action' },
],
},
},

Expand Down
37 changes: 37 additions & 0 deletions config/semaphore.jmespath
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
{
"username": env.USER
"hostname": env.HOSTNAME
"sourceControls": [
{
"repo": env.SEMAPHORE_GIT_REPO_SLUG
"repoUrl": (env.SEMAPHORE_GIT_REPO_SLUG) && join('/', ['https://github.com', env.SEMAPHORE_GIT_REPO_SLUG]) || `null`
"ref": env.SEMAPHORE_GIT_REF
"refUrl": (env.SEMAPHORE_GIT_REPO_SLUG && env.SEMAPHORE_GIT_REF) && join('/', ['https://github.com', env.SEMAPHORE_GIT_REPO_SLUG, 'tree', env.SEMAPHORE_GIT_REF]) || `null`
"commit": env.SEMAPHORE_GIT_SHA
"commitUrl": (env.SEMAPHORE_GIT_REPO_SLUG && env.SEMAPHORE_GIT_SHA) && join('/', ['https://github.com', env.SEMAPHORE_GIT_REPO_SLUG, 'commit', env.SEMAPHORE_GIT_SHA]) || `null`
}
]
"invocationTags": {
"semaphore_block": env.SEMAPHORE_BLOCK_NAME
"semaphore_environment_type": env.SEMAPHORE_AGENT_MACHINE_ENVIRONMENT_TYPE
"semaphore_initiator": env.SEMAPHORE_WORKFLOW_TRIGGERED_BY
"semaphore_job": env.SEMAPHORE_JOB_NAME
"semaphore_job_url": (env.SEMAPHORE_ORGANIZATION_URL && env.SEMAPHORE_JOB_ID) && join('/', [env.SEMAPHORE_ORGANIZATION_URL, 'jobs', env.SEMAPHORE_JOB_ID]) || `null`
"semaphore_machine_type": env.SEMAPHORE_AGENT_MACHINE_TYPE
"semaphore_os_image": env.SEMAPHORE_AGENT_MACHINE_OS_IMAGE
"semaphore_pipeline": env.SEMAPHORE_PIPELINE_NAME
"semaphore_pipeline_url": (env.SEMAPHORE_ORGANIZATION_URL && env.SEMAPHORE_WORKFLOW_ID && env.SEMAPHORE_PIPELINE_ID) && join('/', [env.SEMAPHORE_ORGANIZATION_URL, 'workflows', env.SEMAPHORE_WORKFLOW_ID, join('', ['?pipeline_id=', env.SEMAPHORE_PIPELINE_ID])]) || `null`
"semaphore_project": env.SEMAPHORE_PROJECT_NAME
"semaphore_project_url": (env.SEMAPHORE_ORGANIZATION_URL && env.SEMAPHORE_PROJECT_ID) && join('/', [env.SEMAPHORE_ORGANIZATION_URL, 'projects', env.SEMAPHORE_PROJECT_ID]) || `null`
"semaphore_workflow": (env.SEMAPHORE_ORGANIZATION_URL && env.SEMAPHORE_WORKFLOW_ID) && join('/', [env.SEMAPHORE_ORGANIZATION_URL, 'workflows', env.SEMAPHORE_WORKFLOW_ID]) || `null`
}
"buildTags": {
"repo": env.SEMAPHORE_GIT_REPO_SLUG
"repo_url": (env.SEMAPHORE_GIT_REPO_SLUG) && join('/', ['https://github.com', env.SEMAPHORE_GIT_REPO_SLUG]) || `null`
"semaphore_initiator": env.SEMAPHORE_WORKFLOW_TRIGGERED_BY
"semaphore_project": env.SEMAPHORE_PROJECT_NAME
"semaphore_project_url": (env.SEMAPHORE_ORGANIZATION_URL && env.SEMAPHORE_PROJECT_ID) && join('/', [env.SEMAPHORE_ORGANIZATION_URL, 'projects', env.SEMAPHORE_PROJECT_ID]) || `null`
"semaphore_workflow": (env.SEMAPHORE_ORGANIZATION_URL && env.SEMAPHORE_WORKFLOW_ID) && join('/', [env.SEMAPHORE_ORGANIZATION_URL, 'workflows', env.SEMAPHORE_WORKFLOW_ID]) || `null`
"build_id": (env.SEMAPHORE_ORGANIZATION_URL && env.SEMAPHORE_WORKFLOW_ID) && join('/', [env.SEMAPHORE_ORGANIZATION_URL, 'workflows', env.SEMAPHORE_WORKFLOW_ID]) || `null`
}
}
52 changes: 52 additions & 0 deletions docs/CI-integration.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
# CI integration

These are example integrations against different CI environments.

## Github Actions

Backend extractor: Use `config/gh-actions.jmespath`,

Frontend config:
```
additionalBuildColumns: [
{ title: 'Repo', value_key: 'repo', url_key: 'repo_url' },
{ title: 'PR', value_key: 'pull_request', url_key: 'pull_request_url' },
{ title: 'Workflow', value_key: 'workflow', url_key: 'workflow_url' },
],
additionalBuildInvocationColumns: [
{ title: 'Job', value_key: 'job' },
{ title: 'Action', value_key: 'action' },
],
```

## Gitlab CI

Backend extractor: Use `config/gitlab.jmespath`,

Frontend config:
```
additionalBuildColumns: [
{ title: 'Repo', value_key: 'repo', url_key: 'repo_url' },
{ title: 'Pipeline', value_key: 'pipeline', url_key: 'pipeline_url' },
],
additionalBuildInvocationColumns: [
{ title: 'Job', value_key: 'job', url_key: 'job_url' },
{ title: 'Job stage', value_key: 'job_stage' },
],
```

## SemaphoreCI

Backend extractor: Use `config/semaphore.jmespath`

Frontend config:
```
additionalBuildColumns: [
{ title: 'Repo', value_key: 'repo', url_key: 'repo_url' },
{ title: 'Workflow', value_key: 'semaphore_workflow', url_key: 'semaphore_workflow' },
],
additionalBuildInvocationColumns: [
{ title: 'Pipeline', value_key: 'semaphore_pipeline', url_key: 'semaphore_pipeline_url' },
{ title: 'Job', value_key: 'semaphore_job', url_key: 'semaphore_job_url' },
],
```
6 changes: 3 additions & 3 deletions ent/authschema/privacy_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ func TestPrivacy(t *testing.T) {
require.NoError(t, err)
_, err = db.AuthenticatedUser.Create().SetUserUUID(uuid.New()).SetExternalID("denied_user").AddBazelInvocations(deniedInvocation).Save(ctx)
require.NoError(t, err)
_, err = db.Build.Create().SetInstanceName(deniedInstance).SetBuildUUID(uuid.New()).SetBuildURL("denied_build_url").SetTimestamp(time.Now()).Save(ctx)
_, err = db.Build.Create().SetInstanceName(deniedInstance).SetBuildUUID(uuid.New()).SetTimestamp(time.Now()).Save(ctx)
require.NoError(t, err)
deniedTarget, err := db.Target.Create().SetInstanceName(deniedInstance).SetLabel("denied").SetAspect("aspect").SetTargetKind("targetKind").Save(ctx)
require.NoError(t, err)
Expand Down Expand Up @@ -129,7 +129,7 @@ func TestPrivacy(t *testing.T) {
require.NoError(t, err)
allowed1User, err := db.AuthenticatedUser.Create().SetUserUUID(uuid.New()).SetExternalID("allowed1_user").AddBazelInvocations(allowed1Invocation).Save(ctx)
require.NoError(t, err)
allowed1Build, err := db.Build.Create().SetInstanceName(allowed1Instance).SetBuildUUID(uuid.New()).SetBuildURL("allowed1_build_url").SetTimestamp(time.Now()).Save(ctx)
allowed1Build, err := db.Build.Create().SetInstanceName(allowed1Instance).SetBuildUUID(uuid.New()).SetTimestamp(time.Now()).Save(ctx)
require.NoError(t, err)
allowed1Target, err := db.Target.Create().SetInstanceName(allowed1Instance).SetLabel("allowed1").SetAspect("aspect").SetTargetKind("targetKind").Save(ctx)
require.NoError(t, err)
Expand Down Expand Up @@ -181,7 +181,7 @@ func TestPrivacy(t *testing.T) {
require.NoError(t, err)
allowed2User, err := db.AuthenticatedUser.Create().SetUserUUID(uuid.New()).SetExternalID("allowed2_user").AddBazelInvocations(allowed2Invocation).Save(ctx)
require.NoError(t, err)
allowed2Build, err := db.Build.Create().SetInstanceName(allowed2Instance).SetBuildUUID(uuid.New()).SetBuildURL("allowed2_build_url").SetTimestamp(time.Now()).Save(ctx)
allowed2Build, err := db.Build.Create().SetInstanceName(allowed2Instance).SetBuildUUID(uuid.New()).SetTimestamp(time.Now()).Save(ctx)
require.NoError(t, err)
allowed2Target, err := db.Target.Create().SetInstanceName(allowed2Instance).SetLabel("allowed2").SetAspect("aspect").SetTargetKind("targetKind").Save(ctx)
require.NoError(t, err)
Expand Down
4 changes: 4 additions & 0 deletions ent/authschema/schema.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ type (
BazelInvocation struct{ schema.BazelInvocation }
// Build reexport with auth policy added
Build struct{ schema.Build }
// BuildTag reexport with auth policy added
BuildTag struct{ schema.BuildTag }
// BuildLogChunk reexport with auth policy added
BuildLogChunk struct{ schema.BuildLogChunk }
// BuildGraphMetrics reexport with auth policy added
Expand All @@ -37,6 +39,8 @@ type (
IncompleteBuildLog struct{ schema.IncompleteBuildLog }
// InstanceName reexport with auth policy added
InstanceName struct{ schema.InstanceName }
// InvocationTag reexport with auth policy added
InvocationTag struct{ schema.InvocationTag }
// InvocationFiles reexport with auth policy added
InvocationFiles struct{ schema.InvocationFiles }
// InvocationTarget reexport with auth policy added
Expand Down
12 changes: 12 additions & 0 deletions ent/gen/ent/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,11 @@ go_library(
"buildlogchunk_delete.go",
"buildlogchunk_query.go",
"buildlogchunk_update.go",
"buildtag.go",
"buildtag_create.go",
"buildtag_delete.go",
"buildtag_query.go",
"buildtag_update.go",
"client.go",
"configuration.go",
"configuration_create.go",
Expand Down Expand Up @@ -98,6 +103,11 @@ go_library(
"invocationfiles_delete.go",
"invocationfiles_query.go",
"invocationfiles_update.go",
"invocationtag.go",
"invocationtag_create.go",
"invocationtag_delete.go",
"invocationtag_query.go",
"invocationtag_update.go",
"invocationtarget.go",
"invocationtarget_create.go",
"invocationtarget_delete.go",
Expand Down Expand Up @@ -191,13 +201,15 @@ go_library(
"//ent/gen/ent/build",
"//ent/gen/ent/buildgraphmetrics",
"//ent/gen/ent/buildlogchunk",
"//ent/gen/ent/buildtag",
"//ent/gen/ent/configuration",
"//ent/gen/ent/connectionmetadata",
"//ent/gen/ent/eventmetadata",
"//ent/gen/ent/garbagemetrics",
"//ent/gen/ent/incompletebuildlog",
"//ent/gen/ent/instancename",
"//ent/gen/ent/invocationfiles",
"//ent/gen/ent/invocationtag",
"//ent/gen/ent/invocationtarget",
"//ent/gen/ent/memorymetrics",
"//ent/gen/ent/metrics",
Expand Down
Loading
Loading