Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
2d498c9
Modified README file with my version text
sjamesjr Aug 5, 2025
e32f197
added workflow with test checks for pull requests
sjamesjr Aug 5, 2025
d2cb333
modified last step of ci workflow
sjamesjr Aug 5, 2025
88f310e
added unit tests to auth.go file and adjusted workflow accordingly
sjamesjr Aug 5, 2025
ac4685f
created unittests.go file
sjamesjr Aug 5, 2025
60d34dc
Modified ci.yml to run all unit tests
sjamesjr Aug 6, 2025
bba56b2
breaking code in auth.go file per assignment
sjamesjr Aug 6, 2025
3cc1245
Fixed code as per assignment
sjamesjr Aug 6, 2025
7413864
code fixes to unittests.go file
sjamesjr Aug 6, 2025
3e818b9
modified code to resolve CI test errors
sjamesjr Aug 6, 2025
d3729a8
added cover tag to go test command in ci.yml file
sjamesjr Aug 6, 2025
61350ce
Added test badge to README
sjamesjr Aug 6, 2025
bf0d879
URL fix to ci.yml file to show test badge
sjamesjr Aug 6, 2025
a5bf2aa
added job to ci.yml file to test Go code format
sjamesjr Aug 6, 2025
42ef061
Fixed bug in code in ci.yml file to allow style format checks to work
sjamesjr Aug 6, 2025
99c3625
Add staticcheck lining to ci.yml
sjamesjr Aug 6, 2025
1f6694d
removed unused function
sjamesjr Aug 6, 2025
92a4f64
added gosec install to ci.yml file
sjamesjr Aug 6, 2025
8f466cc
added step to run Gosec check in ci.yml file
sjamesjr Aug 6, 2025
0940ec8
code/bug fixes from issues revealed in go sec test
sjamesjr Aug 6, 2025
0e79884
code fixes for errors revealed in workflow check
sjamesjr Aug 6, 2025
dff1015
ran go fmt, formatted code
sjamesjr Aug 6, 2025
81eb402
code fix, formatting check in ci.yml
sjamesjr Aug 6, 2025
78e73cf
code fix to exclude vendor directories in ci.yml file
sjamesjr Aug 6, 2025
f16fca1
created cd.yml file to automate code deployment
sjamesjr Aug 6, 2025
f98787e
adjusted cd.yml
sjamesjr Aug 8, 2025
062584d
created apprunner.yml file
sjamesjr Aug 8, 2025
3595642
bug fix apprunner.yml file
sjamesjr Aug 8, 2025
e83514b
made adjustments the Docker and cd.yml files
sjamesjr Aug 8, 2025
4e24505
refactor apprunner file ext
sjamesjr Aug 8, 2025
8ca6fd1
Dynamic adjustments to cd.yml code
sjamesjr Aug 8, 2025
39ebff4
name additions for ECR and ECS services in cd.yml file
sjamesjr Aug 8, 2025
ee4be3f
bug fix to cd.yml file. Remove ECS jobs
sjamesjr Aug 8, 2025
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
4 changes: 4 additions & 0 deletions .env
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@

PORT="8080"


10 changes: 10 additions & 0 deletions .github/workflows/apprunner.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
version: 1.0
runtime: go
runtime-version: 1.22
build:
commands:
- go build -mod=vendor -o server .
run:
command: ./server
network:
port: 8080
59 changes: 59 additions & 0 deletions .github/workflows/cd.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
# This workflow name is for display in GitHub's UI.
name: Dynamic CD for ECS

# This specifies when the workflow should run.
# We'll trigger on pushes to the main branch and on pull requests.
# This helps with dynamic tagging and allows for checks on PRs.
on:
push:
branches: [main]
pull_request:
branches: [main]

# A simple set of global environment variables for easy configuration.
env:
AWS_REGION: us-east-1 # The AWS region where your resources are located.
ECR_REPOSITORY: notely-repo # The name of your ECR repository.
ECS_CLUSTER: notely-cluster # The name of your ECS cluster.
ECS_SERVICE: notely-service # The name of your ECS service.
ECS_TASK_DEFINITION: notely-deployment.json # The path to your task definition file.
CONTAINER_NAME: notely-container # The name of the container in your task definition.

jobs:
deploy:
name: Deploy to Amazon ECS
# This ensures the job only runs on push events, not pull requests.
if: github.event_name == 'push'
runs-on: ubuntu-latest
permissions:
id-token: write # This is required for requesting the JWT for OIDC
contents: read
steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v4
with:
# Use a GitHub secret for your IAM role ARN to keep it secure.
role-to-assume: ${{ secrets.AWS_IAM_ROLE_ARN }}
aws-region: ${{ env.AWS_REGION }}

- name: Login to Amazon ECR
id: login-ecr
uses: aws-actions/amazon-ecr-login@v2

- name: Build and push Docker image
id: build-image
env:
ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }}
# The image tag is now a combination of the repository and the git commit SHA.
# This makes every image tag unique and traceable.
IMAGE_TAG: ${{ github.sha }}
run: |
# The `run` command is a multi-line script.
# It builds the image and tags it with the dynamic ECR registry URL and the git SHA.
# It then pushes the image to ECR.
docker build -t $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG .
docker push $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG

58 changes: 58 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
name: ci

on:
pull_request:
branches: [main]

jobs:
tests:
name: Tests
runs-on: ubuntu-latest

steps:
- name: Check out code
uses: actions/checkout@v4

- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: "1.23.0"

- name: Run All Tests
run: go test -cover ./...

- name: Install gosec
run: go install github.com/securego/gosec/v2/cmd/gosec@latest

- name: Gosec check
run: gosec ./...

style:
name: Style
runs-on: ubuntu-latest

steps:
- name: Check out code
uses: actions/checkout@v4

- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: "1.23.0"

- name: Check formatting
run: |
go_fmt_result=$(find . -path ./vendor -prune -o -name '*.go' -print0 | xargs -0 gofmt -l)
if [[ -n "$go_fmt_result" ]]; then
echo "The following files are not formatted correctly:"
echo "$go_fmt_result"
exit 1
fi

- name: Install staticcheck
run: go install honnef.co/go/tools/cmd/staticcheck@latest

- name: Run Staticcheck
run: staticcheck ./...


4 changes: 0 additions & 4 deletions .gitignore

This file was deleted.

3 changes: 3 additions & 0 deletions .idea/.gitignore

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions .idea/inspectionProfiles/profiles_settings.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 10 additions & 0 deletions .idea/learn-cicd-starter .iml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 7 additions & 0 deletions .idea/misc.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions .idea/modules.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions .idea/vcs.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

31 changes: 27 additions & 4 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,7 +1,30 @@
FROM --platform=linux/amd64 debian:stable-slim
# Use a specific Go version (1.22) as the build environment.
FROM golang:1.22-alpine AS builder

RUN apt-get update && apt-get install -y ca-certificates
# Set the working directory
WORKDIR /app

ADD notely /usr/bin/notely
# Copy go.mod and go.sum and download dependencies
COPY go.mod go.sum ./
RUN go mod download

CMD ["notely"]
# Copy the source code
COPY . .

# Build the application binary
RUN CGO_ENABLED=0 go build -o server .

# Final stage: create a small, efficient image to run the binary
FROM alpine:latest

# Set the working directory
WORKDIR /app

# Copy the compiled binary from the builder stage
COPY --from=builder /app/server ./server

# Expose the port your application listens on
EXPOSE 8080

# Command to run the application
CMD ["./server"]
6 changes: 5 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
# learn-cicd-starter (Notely)
![Test Badge](https://github.com/sjamesjr/learn-cicd-starter/actions/workflows/ci.yml/badge.svg)

go ver# learn-cicd-starter (Notely)

This repo contains the starter code for the "Notely" application for the "Learn CICD" course on [Boot.dev](https://boot.dev).

Expand All @@ -21,3 +23,5 @@ go build -o notely && ./notely
*This starts the server in non-database mode.* It will serve a simple webpage at `http://localhost:8080`.

You do *not* need to set up a database or any interactivity on the webpage yet. Instructions for that will come later in the course!

Sam James's version of Boot.dev's Notely app
2 changes: 2 additions & 0 deletions go1.21.2.darwin-amd64.pkg
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
<a href="https://go.dev/dl/go1.21.2.darwin-amd64.pkg">Moved Permanently</a>.

2 changes: 1 addition & 1 deletion internal/auth/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ func GetAPIKey(headers http.Header) (string, error) {
if authHeader == "" {
return "", ErrNoAuthHeaderIncluded
}
splitAuth := strings.Split(authHeader, " ")
splitAuth := strings.Split(authHeader, " ") // Fix the code
if len(splitAuth) < 2 || splitAuth[0] != "ApiKey" {
return "", errors.New("malformed authorization header")
}
Expand Down
39 changes: 39 additions & 0 deletions internal/auth/unittests.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package auth

import (
"errors"
"net/http"
"testing"
)

func TestGetAPIKey_Success(t *testing.T) {
headers := http.Header{}
expectedKey := "secret-key-123"
headers.Set("Authorization", "ApiKey "+expectedKey)

key, err := GetAPIKey(headers)
if err != nil {
t.Fatalf("expected no error, got %v", err)
}

if key != expectedKey {
t.Errorf("expected key %q, got %q", expectedKey, key)
}
}

func TestGetAPIKey_MissingHeader(t *testing.T) {
headers := http.Header{}

key, err := GetAPIKey(headers)
if err == nil {
t.Fatal("expected error, got nil")
}

if key != "" {
t.Errorf("expected empty key, got %q", key)
}

if !errors.Is(err, ErrNoAuthHeaderIncluded) {
t.Errorf("expected error %v, got %v", ErrNoAuthHeaderIncluded, err)
}
}
4 changes: 3 additions & 1 deletion json.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,5 +30,7 @@ func respondWithJSON(w http.ResponseWriter, code int, payload interface{}) {
return
}
w.WriteHeader(code)
w.Write(dat)
if _, err := w.Write(dat); err != nil {
log.Printf("error writing response: %v", err)
}
}
6 changes: 4 additions & 2 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"log"
"net/http"
"os"
"time"

"github.com/go-chi/chi"
"github.com/go-chi/cors"
Expand Down Expand Up @@ -89,8 +90,9 @@ func main() {

router.Mount("/v1", v1Router)
srv := &http.Server{
Addr: ":" + port,
Handler: router,
Addr: ":" + port,
Handler: router,
ReadHeaderTimeout: 5 * time.Second,
}

log.Printf("Serving on port: %s\n", port)
Expand Down
Binary file added notely
Binary file not shown.