diff --git a/.github/workflows/bubbly.yaml b/.github/workflows/bubbly.yaml new file mode 100644 index 00000000..4d5a6ff5 --- /dev/null +++ b/.github/workflows/bubbly.yaml @@ -0,0 +1,72 @@ +## poc workflow for running bubbly + +on: + push: + branches: + - poc/bubbly-ci + +name: bubbly-poc +jobs: + bubbly-poc: + strategy: + matrix: + go-version: [1.16.2] + os: [ubuntu-latest] + runs-on: ${{ matrix.os }} + steps: + - name: Install Go + uses: actions/setup-go@v2 + with: + go-version: ${{ matrix.go-version }} + - name: Checkout code + uses: actions/checkout@v2 + - name: cache go mod + uses: actions/cache@v2 + with: + path: ~/go/pkg/mod + key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} + restore-keys: | + ${{ runner.os }}-go- + - name: Install Bubbly + run: go install + - name: Create release + run: bubbly release create + env: + BUBBLY_ADDR: https://api.bubbly.dev/api/v1/o/valocode + BUBBLY_TOKEN: ${{ secrets.BUBBLY_TOKEN }} + - name: Build Docker + run: docker build -t valocode/bubbly:latest . + - name: Bubbly eval docker + run: bubbly release eval docker + env: + BUBBLY_ADDR: https://api.bubbly.dev/api/v1/o/valocode + BUBBLY_TOKEN: ${{ secrets.BUBBLY_TOKEN }} + - name: Run unit tests + run: go test ./... -json | tee gotest-unit.json + - name: Bubbly eval unit tests + run: bubbly release eval unit_test + env: + BUBBLY_ADDR: https://api.bubbly.dev/api/v1/o/valocode + BUBBLY_TOKEN: ${{ secrets.BUBBLY_TOKEN }} + - name: Run integration tests + run: | + docker-compose up -d postgres bubbly + + # just sleep a bit to wait for the containers to start + sleep 1 + docker-compose logs + go test ./integration -tags=integration -count=1 -json | tee gotest-integration.json + - name: Bubbly eval integration tests + run: bubbly release eval integration_test + env: + BUBBLY_ADDR: https://api.bubbly.dev/api/v1/o/valocode + BUBBLY_TOKEN: ${{ secrets.BUBBLY_TOKEN }} + - name: Run Gosec Security Scanner + run: | + curl -sfL https://raw.githubusercontent.com/securego/gosec/master/install.sh | sh -s -- -b $(go env GOPATH)/bin latest + gosec -fmt json -no-fail -out gosec.json ./... + - name: Bubbly eval gosec + run: bubbly release eval gosec + env: + BUBBLY_ADDR: https://api.bubbly.dev/api/v1/o/valocode + BUBBLY_TOKEN: ${{ secrets.BUBBLY_TOKEN }} diff --git a/bubbly/builtin/schema.bubbly b/bubbly/builtin/schema.bubbly index ca090bba..658989ad 100644 --- a/bubbly/builtin/schema.bubbly +++ b/bubbly/builtin/schema.bubbly @@ -145,74 +145,109 @@ table "release" { join "project" { unique = true } } -// release_item is used to represent what we are releasing in a single release -// and can be of different types: git, artifact or release. -// Based on the type it should have a join to one of those tables -table "release_item" { - - // type should be one of git (commit), artifact or release - field "type" { - type = string +table "subrelease" { + join "release" { + alias = "parent" } - // Join to release. A release can have one or more release_items. - // A release_item can belong to only one release, because it can have - // criteria associated with it, which are specific to a release - join "release" { } + join "release" {} +} - // Join to the different item tables with a one-to-one relationship. - // Only at most and at least one of these joins should exist, based on the - // "type" field - join "commit" { - single = true - unique = true - } - join "artifact" { - single = true - unique = true - } - // TODO: this is a problem because this creates a second join from release_item - // to release... It could be solved by adding an alias - // join "release" { - // alias = "item_release" - // single = true - // unique = true - // } +table "release_commit" { + join "release" {} + join "commit" {} } +// release_item is used to represent what we are releasing in a single release +// and can be of different types: git, artifact or release. +// Based on the type it should have a join to one of those tables +// table "release_item" { + +// // type should be one of git (commit), artifact or release +// field "type" { +// type = string +// } + +// // Join to release. A release can have one or more release_items. +// // A release_item can belong to only one release, because it can have +// // criteria associated with it, which are specific to a release +// join "release" { } + +// // Join to the different item tables with a one-to-one relationship. +// // Only at most and at least one of these joins should exist, based on the +// // "type" field +// join "commit" { +// single = true +// unique = true +// } +// join "artifact" { +// single = true +// unique = true +// } +// // TODO: this is a problem because this creates a second join from release_item +// // to release... It could be solved by adding an alias +// // join "release" { +// // alias = "item_release" +// // single = true +// // unique = true +// // } +// } + // release_entry is used to record/log an event performed on a release, // such as running of unit tests, or the creation of an artifact. // release_entry is created by running a criteria and should contain the output // from the running of that event. // It has no unique fields, as release_entries should be append-only table "release_entry" { - // TODO: change to id?? should be "camel_case" naming... could provide a - // friendly name alternative? field "name" { type = string } - field "result" { - type = bool + // release_entry can be of different types, e.g. artifact, deploy, criteria + field "type" { + // required = true + type = string } - field "reason" { + field "time" { + // required = true type = string } - // TODO: what other fields do we want to store? Probably something saying - // *why* the criteria failed (a reason) and also perhaps the GraphQL - // query used so that we could fetch the data? E.g. - // field "query" { type = string} - // field "reason" { type = string} + join "criteria_result" { single = true } + join "artifact" { single = true } + join "deploy_env" { single = true } // Join to a release so that we can get all the entries for a release // (entry log) join "release" { } - // A release does not always have a release_criteria for each release_entry, - // and may have multiple release_criteria in case multiple entries have been - // logged - join "release_criteria" { } - // Join on the _resource criteria that created this entry release_entry - join "_resource" { } +} + +table "criteria_result" { + // Criteria specific + field "result" { + type = bool + } + // Criteria specific + field "reason" { + type = string + } +} + +table "deploy_env" { + // staging, prod, whatever + field "env" { + type = string + } +} + +table "release_artifact" { + field "name" { + type = string + unique = true + } + join "release" { + unique = true + } + join "artifact" {} } table "release_stage" { @@ -227,11 +262,13 @@ table "release_stage" { } table "release_criteria" { - field "entry_name" { + field "name" { type = string unique = true } join "release_stage" { } + // The result of evaluating the criteria creates a criteria result + join "criteria_result" {} // A release_criteria is unique per release join "release" { unique = true } } diff --git a/integration/testdata/release/resources/gotest.bubbly b/integration/testdata/release/resources/gotest.bubbly index f119622d..bd77f843 100644 --- a/integration/testdata/release/resources/gotest.bubbly +++ b/integration/testdata/release/resources/gotest.bubbly @@ -77,9 +77,3 @@ resource "pipeline" "gotest" { } } } - -// resource "run" "gotest" { -// spec { -// resource = "pipeline/gotest" -// } -// } diff --git a/release-v2.bubbly b/release-v2.bubbly new file mode 100644 index 00000000..eea43b8c --- /dev/null +++ b/release-v2.bubbly @@ -0,0 +1,73 @@ + +release { + project = "bubbly" + git {} + + dependency { + project = "bubbly" + release { + name = "github.com/valocode/bubbly" + version = "1.2.3" + } + // OR + artifact { + location = "docker://...." + } + } + + + artifact { + name = "bubbly" + location = "docker://...." + } + + + // stage "Artifact" { + // criteria "docker" { + // artifact { + // name = "bubbly" + // location = "docker://valocode/bubbly:latest" + // } + // } + // } + stage "Security" { + criteria "gosec" { + run "pipeline/gosec" { + input "file" { + value = "./gosec.json" + } + } + run "criteria/code-issue-high-severity" { + input "tool" { + value = "gosec" + } + } + } + } + stage "Testing" { + criteria "unit_test" { + run "pipeline/gotest" { + input "file" { + value = "./gotest-unit.json" + } + } + run "criteria/test-cases-pass" { + input "tool" { + value = "gotest" + } + } + } + criteria "integration_test" { + run "pipeline/gotest" { + input "file" { + value = "./gotest-integration.json" + } + } + run "criteria/test-cases-pass" { + input "tool" { + value = "gotest" + } + } + } + } +} diff --git a/release.bubbly b/release.bubbly new file mode 100644 index 00000000..80a8b327 --- /dev/null +++ b/release.bubbly @@ -0,0 +1,54 @@ + +release { + project = "bubbly" + git {} + + stage "Artifact" { + criteria "docker" { + artifact { + name = "bubbly" + location = "docker://valocode/bubbly:latest" + } + } + } + stage "Security" { + criteria "gosec" { + run "pipeline/gosec" { + input "file" { + value = "./gosec.json" + } + } + run "criteria/code-issue-high-severity" { + input "tool" { + value = "gosec" + } + } + } + } + stage "Testing" { + criteria "unit_test" { + run "pipeline/gotest" { + input "file" { + value = "./gotest-unit.json" + } + } + run "criteria/test-cases-pass" { + input "tool" { + value = "gotest" + } + } + } + criteria "integration_test" { + run "pipeline/gotest" { + input "file" { + value = "./gotest-integration.json" + } + } + run "criteria/test-cases-pass" { + input "tool" { + value = "gotest" + } + } + } + } +}