diff --git a/.github/actions/release-rules/action.yml b/.github/actions/release-rules/action.yml new file mode 100644 index 0000000..5f156c0 --- /dev/null +++ b/.github/actions/release-rules/action.yml @@ -0,0 +1,36 @@ +name: Release Rules Checker +description: Determines release type based on the git ref and provided rules + +inputs: + release_tag_regex: + required: false + description: 'Regex to match the git tag to determine if this a release run of the workflow' + default: 'v[0-9]+(\.[0-9]+){0,2}' + prerelease_tag_regex: + required: false + description: 'Regex to match the git tag to determine if this a pre-release run of the workflow' + default: 'v[0-9]+(\.[0-9]+){0,2}(-([0-9a-zA-Z-]+(\.[0-9a-zA-Z-]+)*))?' + prefix: + required: false + description: "(Optional) prefix of git tags to use. Example: 'sdk/'" + default: '' +outputs: + release-type: + description: 'Type of the release. One of: [dev, pre-release, release]' + value: ${{ steps.tag-check.outputs.release-type }} + +runs: + using: composite + steps: + - run: | + release_regex='^refs/tags/${{ inputs.prefix }}${{ inputs.release_tag_regex }}$' + prerelease_regex='^refs/tags/${{ inputs.prefix }}${{ inputs.prerelease_tag_regex }}$' + if [[ '${{ github.event.ref }}' =~ ${release_regex} ]]; then + echo '::set-output name=release-type::release' + elif [[ '${{ github.event.ref }}' =~ ${prerelease_regex} ]]; then + echo '::set-output name=release-type::pre-release' + else + echo '::set-output name=release-type::dev' + fi + id: tag-check + shell: bash diff --git a/.github/workflows/fluentd-plugin.yaml b/.github/workflows/fluentd-plugin.yml similarity index 97% rename from .github/workflows/fluentd-plugin.yaml rename to .github/workflows/fluentd-plugin.yml index 2126fb1..c80070e 100644 --- a/.github/workflows/fluentd-plugin.yaml +++ b/.github/workflows/fluentd-plugin.yml @@ -9,7 +9,7 @@ on: branches: - main paths: - - ".github/workflows/fluentd-plugin.yaml" + - ".github/workflows/fluentd-plugin.yml" - "images/fluentd/**" # To make it possible to trigger e2e CI workflow for any arbitrary git ref diff --git a/.github/workflows/observation-service.yml b/.github/workflows/observation-service.yml index 6356421..d4278ac 100644 --- a/.github/workflows/observation-service.yml +++ b/.github/workflows/observation-service.yml @@ -67,4 +67,36 @@ jobs: go-version: ${{ env.GO_VERSION }} - name: Run Observation Service test + working-directory: observation-service run: make test-observation-service + + release-rules: + runs-on: ubuntu-latest + outputs: + release-type: ${{ steps.release-rules.outputs.release-type }} + steps: + - uses: actions/checkout@v2 + - id: release-rules + uses: ./.github/actions/release-rules + + release: + # Automatically publish release and pre-release artifacts. + # + # As for dev releases, make it possible to publish artifacts + # manually by approving 'deployment' in the 'manual' environment. + # + # Dev build can be released either from the 'main' branch or + # by running this workflow manually with `workflow_dispatch` event. + if: >- + contains('release,pre-release', needs.release-rules.outputs.release-type) + || ( github.event_name != 'pull_request' ) + || ( github.event.pull_request.head.repo.full_name == github.repository ) + needs: + - lint-go + - unit-tests-observation-service + - release-rules + uses: ./.github/workflows/release.yml + with: + environment: ${{ needs.release-rules.outputs.release-type == 'dev' && 'manual' || '' }} + secrets: + ghcr_token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..4980271 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,80 @@ +name: Services Release + +on: + workflow_call: + inputs: + container_registry: + type: string + required: false + default: ghcr.io + environment: + type: string + required: false + secrets: + ghcr_token: + required: true + +env: + ARTIFACT_RETENTION_DAYS: 7 + +jobs: + build-observation-service: + runs-on: ubuntu-latest + env: + APP_NAME: observation-service + DOCKER_FILE: Dockerfile.observation_service + outputs: + api-version: ${{ steps.build-image.outputs.api-version }} + steps: + - name: Check out code + uses: actions/checkout@v2 + with: + fetch-depth: 0 + + - name: Build Docker image + id: build-image + run: | + set -o pipefail + make BIN_NAME=$APP_NAME DOCKER_FILE=$DOCKER_FILE build-image | tee output.log + echo "::set-output name=api-version::$(sed -n 's%API version: \(.*\)%\1%p' output.log)" + + - name: Save Docker image + run: | + docker image save \ + --output observation-service.${{ steps.build-image.outputs.api-version }}.tar \ + observation-service:${{ steps.build-image.outputs.api-version }} + + - name: Publish Artifact + uses: actions/upload-artifact@v3 + with: + name: observation-service.${{ steps.build-image.outputs.api-version }}.tar + path: observation-service.${{ steps.build-image.outputs.api-version }}.tar + retention-days: ${{ env.ARTIFACT_RETENTION_DAYS }} + + publish-observation-service: + runs-on: ubuntu-latest + environment: ${{ inputs.environment }} + needs: + - build-observation-service + steps: + - name: Log in to the Container registry + uses: docker/login-action@v1 + with: + registry: ${{ inputs.container_registry }} + username: ${{ github.actor }} + password: ${{ secrets.ghcr_token }} + + - name: Download Docker image tar + uses: actions/download-artifact@v2 + with: + name: observation-service.${{ needs.build-observation-service.outputs.api-version }}.tar + + - name: Publish Docker Image + env: + DOCKER_REPOSITORY: ${{ inputs.container_registry }}/${{ github.repository }} + run: | + docker image load --input observation-service.${{ needs.build-observation-service.outputs.api-version }}.tar + docker tag \ + observation-service:${{ needs.build-observation-service.outputs.api-version }} \ + ${{ env.DOCKER_REPOSITORY }}/observation-service:${{ needs.build-observation-service.outputs.api-version }} + docker push ${{ env.DOCKER_REPOSITORY }}/observation-service:${{ needs.build-observation-service.outputs.api-version }} diff --git a/Dockerfile.observation_service b/Dockerfile.observation_service new file mode 100644 index 0000000..8993990 --- /dev/null +++ b/Dockerfile.observation_service @@ -0,0 +1,30 @@ +# ============================================================ +# Build stage 1: Build API +# ============================================================ +FROM golang:1.18-alpine as go-builder +ARG API_BIN_NAME=observation_service +ARG SERVICE_DIRECTORY=observation-service + +RUN apk update && apk add build-base + +COPY . /app +WORKDIR /app/${SERVICE_DIRECTORY} + +# Build Observation Service binary +RUN go mod tidy +RUN go build \ + -tags musl \ + -o bin/${API_BIN_NAME} \ + -v ./cmd/${SERVICE_DIRECTORY} + +# ============================================================ +# Build stage 2: Copy binary +# ============================================================ +FROM alpine:latest + +RUN mkdir -p /opt/observation_service + +COPY --from=go-builder ./bin/* /opt/observation_service/ + +WORKDIR /opt/observation_service +ENTRYPOINT [ "./observation-service" ] diff --git a/Makefile b/Makefile index 0738b4e..c3814ad 100644 --- a/Makefile +++ b/Makefile @@ -19,6 +19,16 @@ version: $(eval VERSION=$(if $(OVERWRITE_VERSION),$(OVERWRITE_VERSION),v$(shell scripts/vertagen/vertagen.sh))) @echo "API version:" $(VERSION) +# ================================== +# Build recipes +# ================================== + +.PHONY: build-image +build-image: version + @$(eval IMAGE_TAG = $(if $(DOCKER_REGISTRY),$(DOCKER_REGISTRY)/,)${BIN_NAME}:${VERSION}) + @echo "Building docker image: ${IMAGE_TAG}" + docker build --tag ${IMAGE_TAG} . -f ${DOCKER_FILE} + # ================================== # Code dependencies recipes # ================================== @@ -32,9 +42,6 @@ setup: @pre-commit install @pre-commit install-hooks -tidy-observation-service: - cd ${OBSERVATION_SVC_PATH} && go mod tidy - # ================================== # Linting recipes # ================================== @@ -43,7 +50,7 @@ tidy-observation-service: lint: lint-go lint-go: - @echo "> Linting Observation Service code..." + @echo "> Linting code..." cd ${OBSERVATION_SVC_PATH} && golangci-lint run --timeout 5m cd ${COMMON_MODULE_PATH} && golangci-lint run --timeout 5m @@ -54,25 +61,3 @@ lint-go: .PHONY: dependency-services dependency-services: cd infra/local && docker-compose up -d - -.PHONY: observation-service -observation-service: - cd observation-service && go run cmd/observation-service/main.go serve --config="config/example.yaml" - -# ================================== -# Build recipes -# ================================== - -build-fluentd-image: - cd images/fluentd && docker build -t observation-service-fluentd . - -# ================================== -# Test recipes -# ================================== - -test-observation-service: tidy-observation-service - @cd ${OBSERVATION_SVC_PATH} && go mod vendor - @echo "> Running Observation Service tests ..." - @cd ${OBSERVATION_SVC_PATH} && go test -v ./... -coverpkg ./... -gcflags=-l -race -coverprofile cover.out.tmp -tags unit,integration - @cd ${OBSERVATION_SVC_PATH} && cat cover.out.tmp | grep -v "api/api.go\|cmd\|.pb.go\|mock\|testutils\|server" > cover.out - @cd ${OBSERVATION_SVC_PATH} && go tool cover -func cover.out diff --git a/README.md b/README.md index 2609d6e..688abd6 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,7 @@ make dependency-services #### c. Setup Observation Service ```bash -make observation-service +cd observation-service && make observation-service ``` #### d. Sample Requests diff --git a/images/fluentd/fluent.conf b/images/fluentd/fluent.conf index cd51ae5..d6eee21 100644 --- a/images/fluentd/fluent.conf +++ b/images/fluentd/fluent.conf @@ -4,6 +4,7 @@ workers "#{ENV['FLUENTD_WORKER_COUNT']}" +# Accept HTTP input @type http port 9880 @@ -12,12 +13,14 @@ keepalive_timeout 10s +# Accept events on tcp socket @type forward port 24224 bind 0.0.0.0 +# Buffer and output to multiple sinks @type copy diff --git a/observation-service/Makefile b/observation-service/Makefile new file mode 100644 index 0000000..20cd48b --- /dev/null +++ b/observation-service/Makefile @@ -0,0 +1,54 @@ +export + +OBSERVATION_SVC_PATH=observation-service +OBSERVATION_SVC_BIN_NAME=$(if $(OBSERVATION_SVC_NAME),$(OBSERVATION_SVC_NAME),observation_service) + +# ================================== +# General +# ================================== + +.PHONY: vendor +vendor: + @echo "Fetching dependencies..." + go mod vendor + +.PHONY: version +version: + $(eval VERSION=$(if $(OVERWRITE_VERSION),$(OVERWRITE_VERSION),v$(shell ../scripts/vertagen/vertagen.sh))) + @echo "observation-service version:" $(VERSION) + +tidy: + go mod tidy + +# ================================== +# Build recipes +# ================================== + +build: version + @echo "Building binary..." + go build -o ./bin/${OBSERVATION_SVC_BIN_NAME} ./cmd/${OBSERVATION_SVC_PATH}/main.go + +.PHONY: build-image +build-image: vendor version + @$(eval IMAGE_TAG = $(if $(DOCKER_REGISTRY),$(DOCKER_REGISTRY)/,)${BIN_NAME}:${VERSION}) + @echo "Building docker image: ${IMAGE_TAG}" + docker build --tag ${IMAGE_TAG} . -f ${DOCKER_FILE} + +# ================================== +# Setup Services +# ================================== + +.PHONY: observation-service +observation-service: + go run cmd/observation-service/main.go serve --config="config/example.yaml" + +# ================================== +# Test recipes +# ================================== + +test-observation-service: tidy vendor + go mod vendor + @echo "> Running Observation Service tests ..." + go test -v ./... -coverpkg ./... -gcflags=-l -race -coverprofile cover.out.tmp -tags unit,integration + cat cover.out.tmp | grep -v "api/api.go\|cmd\|.pb.go\|mock\|testutils\|server" > cover.out + go tool cover -func cover.out