diff --git a/.github/actions/golang/Dockerfile b/.github/actions/golang/Dockerfile index 5abbafc..83f2c65 100644 --- a/.github/actions/golang/Dockerfile +++ b/.github/actions/golang/Dockerfile @@ -1,6 +1,4 @@ -FROM golang:1.12 - -RUN curl -sfL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | sh -s -- -b $(go env GOPATH)/bin v1.17.1 +FROM golang:1.24 RUN apt-get update && \ apt-get install -y jq diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 5179a4e..9f886ba 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -9,14 +9,21 @@ on: - develop name: Lint +permissions: + contents: read + # Optional: allow read access to pull request. Use with `only-new-issues` option. + # pull-requests: read + jobs: - lint: + golangci: + name: lint runs-on: ubuntu-latest steps: - - uses: actions/checkout@v1 - - name: lint - uses: ./.github/actions/golang - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - args: lint \ No newline at end of file + - uses: actions/checkout@v4 + - uses: actions/setup-go@v5 + with: + go-version: 1.24 + - name: golangci-lint + uses: golangci/golangci-lint-action@v6 + with: + version: v1.64.5 \ No newline at end of file diff --git a/.gitignore b/.gitignore index 3fba88f..c70868b 100644 --- a/.gitignore +++ b/.gitignore @@ -3,4 +3,8 @@ CHANGELOG.md dist test-results.txt -coverage.txt \ No newline at end of file +coverage.txt + +.terraform/ +level.tfstate +level.tfstate.backup diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..7a2ad16 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "bootstrap"] + path = bootstrap + url = git@github.com:gabeduke/cloudrun-bootstrap.git diff --git a/.gitpod.yml b/.gitpod.yml index 2b0c146..920243b 100644 --- a/.gitpod.yml +++ b/.gitpod.yml @@ -7,9 +7,13 @@ ports: # List the start up tasks. You can start them in parallel in multiple terminals. See https://www.gitpod.io/docs/44_config_start_tasks/ tasks: - - init: echo 'init' # runs during prebuild + - name: Init + init: echo 'init' # runs during prebuild command: go mod download - - command: go run main.go - name: Serve - - openMode: split-bottom - command: until curl -w '\n' --connect-timeout 5 --max-time 10 --retry 5 --retry-delay 0 --retry-connrefused --retry-max-time 40 localhost:8080/api/v1/level ; do echo "retrying.." && sleep 5 ; done \ No newline at end of file + - name: Serve + command: go run main.go + - openMode: tab-after + name: e2e + command: | + gp await-port 8080 + curl -w '\n' localhost:8080/api/v1/level \ No newline at end of file diff --git a/.release b/.release index 79728fe..4a4127c 100644 --- a/.release +++ b/.release @@ -1 +1 @@ -1.0.24 +1.0.25 diff --git a/Makefile b/Makefile index aafebbd..d10af6f 100644 --- a/Makefile +++ b/Makefile @@ -1,50 +1,81 @@ +include $(CURDIR)/bootstrap/Makefile +SERVICE_NAME := level +VAR_FILE := $(CURDIR)/level.tfvars + # Docker config TAG ?= latest IMG ?= level REGISTRY ?= dukeman DOCKER_IMG = $(REGISTRY)/$(IMG):$(TAG) PORT = 8080 +MODULE = github.com/gabeduke/level .DEFAULT_GOAL = help -.PHONY: help fmt test lint docker-build +########################################################## +##@ APP +########################################################## +.PHONY: build dev run + +build: swagger ## build container + DOCKER_BUILDKIT=1 docker build -t $(DOCKER_IMG) . + +dev: swagger ## run program in dev mode + $(info INFO serving API in 'dev' mode) + LOG_LEVEL=debug go run main.go + +run: docker ## run project in container + docker run -p $(PORT):8080 -it $(DOCKER_IMG) + +########################################################## +##@ TEST +########################################################## +.PHONY: fmt test lint -fmt: ## fmt project +fmt: ## fmt project go fmt ./... -test: ## test project +test: ## test project go test ./... -race -coverprofile=coverage.txt -covermode=atomic -lint: ## lint project +lint: ## lint project golangci-lint run -swagger: swagger-init swagger-static swagger-readme ## rebuild swagger docs +########################################################## +##@ DOCS +########################################################## +.PHONY: docs swagger swagger-init swagger-static swagger-readme + +docs: ## Serve package godocs + $(info http://localhost:6060/pkg/$(MODULE)) + godoc -http=localhost:6060 + +swagger: swagger-init swagger-static swagger-readme ## rebuild swagger docs swagger-init: - swag init + $(info INFO init swagger) + @swag init swagger-static: - docker run --rm -v ${PWD}:/local --user $(shell id -u):$(shell id -u) \ + $(info INFO generating swagger static files) + @docker run --rm -v ${PWD}:/local --user $(shell id -u):$(shell id -u) \ swaggerapi/swagger-codegen-cli generate \ -i /local/docs/swagger.yaml \ -l html2 \ -o /local/docs swagger-readme: - docker run --rm \ + $(info INFO generating swagger readme) + @docker run --rm \ --user $(shell id -u):$(shell id -u) \ --volume $(shell pwd):/app \ --workdir /app \ node npx markdown-swagger /app/docs/swagger.yaml /app/README.md -build: swagger ## build container - DOCKER_BUILDKIT=1 docker build -t $(DOCKER_IMG) . - -dev: swagger ## run program in dev mode - go run main.go - -run: docker ## run project in container - docker run -p $(PORT):8080 -it $(DOCKER_IMG) +########################################################## +##@ UTIL +########################################################## +.PHONY: help -help: - @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' \ No newline at end of file +help: ## show help + @awk 'BEGIN {FS = ":.*##"; printf "\nUsage:\n make \033[36m\033[0m\n"} /^[a-zA-Z_-]+:.*?##/ { printf " \033[36m%-15s\033[0m %s\n", $$1, $$2 } /^##@/ { printf "\n\033[1m%s\033[0m\n", substr($$0, 5) } ' $(MAKEFILE_LIST) diff --git a/README.md b/README.md index 133e04e..874e771 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,6 @@ ![](https://github.com/gabeduke/level/workflows/Test/badge.svg) ![](https://github.com/gabeduke/level/workflows/Lint/badge.svg) ![](https://github.com/gabeduke/level/workflows/Fmt/badge.svg) -![](https://github.com/gabeduke/level/workflows/Tag/badge.svg) -![](https://github.com/gabeduke/level/workflows/Release/badge.svg) [![codecov](https://codecov.io/gh/gabeduke/level/branch/master/graph/badge.svg)](https://codecov.io/gh/gabeduke/level) # Level @@ -16,11 +14,12 @@ Level is an API to query readings from the National Water Service. Readings can More detailed docs can be found [HERE](https://gabeduke.github.io/level/) - Endpoint | Method | Auth? | Description - ----------- | ------ | ----- | -------------------- - `/healthz` | GET | No | get health - `/level` | GET | No | get level by station - `/stations` | GET | No | get stations + Endpoint | Method | Auth? | Description + ----------- | ------ | ----- | ----------------------- + `/healthz` | GET | No | get health + `/level` | GET | No | get level by station + `/slack` | POST | No | return a slack response + `/stations` | GET | No | get stations ## Run @@ -37,4 +36,11 @@ Try out the API for free on Google Cloud Run: `make dev` will run the project in Go dev mode +### Bootstrap (terraform) +```bash +git submodule update +make init +make import +make apply +``` diff --git a/bootstrap b/bootstrap new file mode 160000 index 0000000..62d384b --- /dev/null +++ b/bootstrap @@ -0,0 +1 @@ +Subproject commit 62d384b07a4220ec2b31befca19e098152673f5d diff --git a/cloudbuild.yaml b/cloudbuild.yaml new file mode 100644 index 0000000..636c99b --- /dev/null +++ b/cloudbuild.yaml @@ -0,0 +1,21 @@ +steps: + # Build the container image + - name: 'gcr.io/cloud-builders/docker' + args: ['build', '-t', 'gcr.io/leetcloud-173303/github.com/gabeduke/level:snapshot-$BRANCH_NAME', '.'] + # Push the image to Container Registry + - name: 'gcr.io/cloud-builders/docker' + args: ['push', 'gcr.io/leetcloud-173303/github.com/gabeduke/level:snapshot-$BRANCH_NAME'] + # Deploy image to Cloud Run + - name: 'gcr.io/cloud-builders/gcloud' + args: + - 'run' + - 'deploy' + - 'level' + - '--image' + - 'gcr.io/leetcloud-173303/github.com/gabeduke/level:snapshot-$BRANCH_NAME' + - '--region' + - 'us-east1' + - '--platform' + - 'managed' +images: + - gcr.io/leetcloud-173303/github.com/gabeduke/level diff --git a/docs/.swagger-codegen/VERSION b/docs/.swagger-codegen/VERSION index 855ff95..b385137 100644 --- a/docs/.swagger-codegen/VERSION +++ b/docs/.swagger-codegen/VERSION @@ -1 +1 @@ -2.4.0-SNAPSHOT \ No newline at end of file +2.4.12 \ No newline at end of file diff --git a/docs/docs.go b/docs/docs.go index 19d2de0..7134b5e 100644 --- a/docs/docs.go +++ b/docs/docs.go @@ -1,6 +1,6 @@ // GENERATED BY THE COMMAND ABOVE; DO NOT EDIT // This file was generated by swaggo/swag at -// 2019-10-22 23:31:48.136136717 -0400 EDT m=+0.234164654 +// 2020-01-26 21:20:29.289308664 -0500 EST m=+0.083412855 package docs @@ -71,8 +71,30 @@ var doc = `{ ], "responses": { "200": {}, - "417": { - "description": "Expectation Failed", + "424": { + "description": "Failed Dependency", + "schema": { + "$ref": "#/definitions/httputil.HTTPError" + } + } + } + } + }, + "/slack": { + "post": { + "description": "return a slack response", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "summary": "return a slack response", + "operationId": "slack", + "responses": { + "200": {}, + "424": { + "description": "Failed Dependency", "schema": { "$ref": "#/definitions/httputil.HTTPError" } @@ -93,8 +115,8 @@ var doc = `{ "operationId": "stations", "responses": { "200": {}, - "417": { - "description": "Expectation Failed", + "424": { + "description": "Failed Dependency", "schema": { "$ref": "#/definitions/httputil.HTTPError" } diff --git a/docs/index.html b/docs/index.html index 8557077..ca66d1e 100644 --- a/docs/index.html +++ b/docs/index.html @@ -696,7 +696,7 @@ + + + + + + + +
+
+
+
+

slack

+

return a slack response

+
+
+
+

+

return a slack response

+

+
+
/slack
+

+

Usage and SDK Samples

+

+ + +
+
+
curl -X POST "https://localhost/slack"
+
+
+
import io.swagger.client.*;
+import io.swagger.client.auth.*;
+import io.swagger.client.model.*;
+import io.swagger.client.api.DefaultApi;
+
+import java.io.File;
+import java.util.*;
+
+public class DefaultApiExample {
+
+    public static void main(String[] args) {
+        
+        DefaultApi apiInstance = new DefaultApi();
+        try {
+            apiInstance.slack();
+        } catch (ApiException e) {
+            System.err.println("Exception when calling DefaultApi#slack");
+            e.printStackTrace();
+        }
+    }
+}
+
+ +
+
import io.swagger.client.api.DefaultApi;
+
+public class DefaultApiExample {
+
+    public static void main(String[] args) {
+        DefaultApi apiInstance = new DefaultApi();
+        try {
+            apiInstance.slack();
+        } catch (ApiException e) {
+            System.err.println("Exception when calling DefaultApi#slack");
+            e.printStackTrace();
+        }
+    }
+}
+
+ +
+

+DefaultApi *apiInstance = [[DefaultApi alloc] init];
+
+// return a slack response
+[apiInstance slackWithCompletionHandler: 
+              ^(NSError* error) {
+                            if (error) {
+                                NSLog(@"Error: %@", error);
+                            }
+                        }];
+
+
+ +
+
var LevelApi = require('level_api');
+
+var api = new LevelApi.DefaultApi()
+
+var callback = function(error, data, response) {
+  if (error) {
+    console.error(error);
+  } else {
+    console.log('API called successfully.');
+  }
+};
+api.slack(callback);
+
+
+ + +
+
using System;
+using System.Diagnostics;
+using IO.Swagger.Api;
+using IO.Swagger.Client;
+using IO.Swagger.Model;
+
+namespace Example
+{
+    public class slackExample
+    {
+        public void main()
+        {
+            
+            var apiInstance = new DefaultApi();
+
+            try
+            {
+                // return a slack response
+                apiInstance.slack();
+            }
+            catch (Exception e)
+            {
+                Debug.Print("Exception when calling DefaultApi.slack: " + e.Message );
+            }
+        }
+    }
+}
+
+
+ +
+
<?php
+require_once(__DIR__ . '/vendor/autoload.php');
+
+$api_instance = new Swagger\Client\Api\DefaultApi();
+
+try {
+    $api_instance->slack();
+} catch (Exception $e) {
+    echo 'Exception when calling DefaultApi->slack: ', $e->getMessage(), PHP_EOL;
+}
+?>
+
+ +
+
use Data::Dumper;
+use WWW::SwaggerClient::Configuration;
+use WWW::SwaggerClient::DefaultApi;
+
+my $api_instance = WWW::SwaggerClient::DefaultApi->new();
+
+eval { 
+    $api_instance->slack();
+};
+if ($@) {
+    warn "Exception when calling DefaultApi->slack: $@\n";
+}
+
+ +
+
from __future__ import print_statement
+import time
+import swagger_client
+from swagger_client.rest import ApiException
+from pprint import pprint
+
+# create an instance of the API class
+api_instance = swagger_client.DefaultApi()
+
+try: 
+    # return a slack response
+    api_instance.slack()
+except ApiException as e:
+    print("Exception when calling DefaultApi->slack: %s\n" % e)
+
+
+ +

Parameters

+ + + + + + +

Responses

+

Status: 200 -

+ + + +
+
+ +

Status: 424 - Failed Dependency

-
-
+
+
- +
@@ -1460,22 +1714,22 @@

Status: 200 -

-

Status: 417 - Expectation Failed

+

Status: 424 - Failed Dependency

-
-
+
+
- +
@@ -2712,6 +2966,12 @@

Status: 417 - Expectation Failed

return this.element; } + if (this.schema && this.schema.example) { + var exampleDiv = document.createElement('div'); + exampleDiv.innerHTML = '
\n example: ' + this.schema.example + '\n
'; + this.element.appendChild(exampleDiv.querySelector('.example')); + } + if (!this.isCollapsed) { this.appendChildren(this.element); } @@ -3238,7 +3498,7 @@

Status: 417 - Expectation Failed