Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
Signed-off-by: Chirayu Kapoor <[email protected]>
  • Loading branch information
chiukapoor committed May 29, 2024
0 parents commit b2d4011
Show file tree
Hide file tree
Showing 10 changed files with 322 additions and 0 deletions.
24 changes: 24 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Exclude the GitHub Actions workflows
.github/

# Exclude Git repository files
.git
.gitignore

# Exclude Go test files
stack/stack_test.go

# Exclude local Go build files and caches
*.exe
*.exe~
*.dll
*.so
*.dylib
*.test
*.out

# Exclude any local environment files
.env

Dockerfile
README.md
31 changes: 31 additions & 0 deletions .github/workflows/docker-image.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
name: Build and Push Docker Image

on:
workflow_run:
workflows: ["Go Test"]
types:
- completed

jobs:
build:

if: ${{ github.event.workflow_run.conclusion == 'success' }}
runs-on: ubuntu-latest

steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Build Docker image
run: docker build -t ${{ secrets.DOCKER_USER }}/go-stack:${{ github.sha }} .
- name: Tag for latest
run: docker tag ${{ secrets.DOCKER_USER }}/go-stack:${{ github.sha }} ${{ secrets.DOCKER_USER }}/go-stack:latest

- name: Log in to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKER_USER }}
password: ${{ secrets.DOCKER_PASSWORD }}

- name: Push Docker images
run: docker push --all-tags ${{ secrets.DOCKER_USER }}/go-stack
27 changes: 27 additions & 0 deletions .github/workflows/go-test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
name: Go Test

on:
push:
branches: [ main ]
pull_request:
branches: [ main ]

jobs:
test:

runs-on: ubuntu-latest

steps:
- name: Checkout repository
uses: actions/checkout@v4

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

- name: Install dependencies
run: go mod tidy

- name: Run tests
run: go test -v ./...
20 changes: 20 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Use an official Golang runtime as a parent image
FROM golang:1.22

# Set the Current Working Directory inside the container
WORKDIR /app

# Copy go.mod and go.sum files
COPY go.mod go.sum ./

# Download all dependencies. Dependencies will be cached if the go.mod and go.sum files are not changed
RUN go mod download

# Copy the local package files to the container’s workspace
COPY . .

# Build the Go app
RUN go build -o main .

# Run the executable
ENTRYPOINT ["./main"]
19 changes: 19 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
MIT License

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
53 changes: 53 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# go-stack

[![Build Status](https://github.com/chiukapoor/go-stack/actions/workflows/docker-image.yml/badge.svg)](https://github.com/chiukapoor/go-stack/actions)
[![License](https://img.shields.io/github/license/chiukapoor/go-stack)](https://github.com/chiukapoor/go-stack/blob/main/LICENSE)
[![Docker Repository](https://img.shields.io/badge/docker-repo-blue)](https://hub.docker.com/r/csociety/go-stack)


## Description

This repository contains a simple implementation of a thread-safe stack in Go. It includes concurrent push and pop operations, unit tests, and a Dockerfile for containerization.

## Features

- Concurrency support
- Dockerized
- Kubernetes-ready
- CI/CD with GitHub Actions

## Getting Started

### Prerequisites

- Go 1.22 or later
- Docker

### Running the Application

#### Locally

```bash
go run main.go
```

#### Docker

```bash
docker run csociety/go-stack
```

#### Kubernetes

```yaml
apiVersion: v1
kind: Pod
metadata:
name: go-stack
labels:
app: go-stack
spec:
containers:
- name: go-stack
image: csociety/go-stack:latest
```
3 changes: 3 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module github.com/chiukapoor/go-stack

go 1.22.3
44 changes: 44 additions & 0 deletions main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package main

import (
"fmt"
"sync"

"github.com/chiukapoor/go-stack/stack"
)

func main() {
stack := &stack.Stack{
Nums: []int{},
}

var wg sync.WaitGroup

// Start 50 goroutines to push items to the stack
for i := 0; i < 50; i++ {
wg.Add(1)
go func(i int) {
defer wg.Done()
stack.Push(i)
fmt.Printf("Pushed: %d\n", i)
}(i)
}

// Start 25 goroutines to pop items from the stack
for i := 0; i < 25; i++ {
wg.Add(1)
go func() {
defer wg.Done()
item, err := stack.Pop()
if err != nil {
fmt.Println("Pop error:", err)
} else {
fmt.Printf("Popped: %d\n", item)
}
}()
}

wg.Wait()

fmt.Println("Final Stack:", stack.Nums)
}
36 changes: 36 additions & 0 deletions stack/stack.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package stack

import (
"errors"
"sync"
)

// Stack is represented as a struct of list, it has three functions: Pop, Push, and IsEmpty
type Stack struct {
Nums []int
lock sync.Mutex
}

// Pop removes the top item from the stack and returns it
func (s *Stack) Pop() (int, error) {
s.lock.Lock()
defer s.lock.Unlock()
if s.IsEmpty() {
return 0, errors.New("empty stack")
}
item := s.Nums[len(s.Nums)-1]
s.Nums = s.Nums[:len(s.Nums)-1]
return item, nil
}

// Push adds an item to the stack
func (s *Stack) Push(num int) {
s.lock.Lock()
defer s.lock.Unlock()
s.Nums = append(s.Nums, num)
}

// IsEmpty checks if the stack is empty
func (s *Stack) IsEmpty() bool {
return len(s.Nums) == 0
}
65 changes: 65 additions & 0 deletions stack/stack_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package stack

import (
"testing"
)

func TestPush(t *testing.T) {
stack := &Stack{}

stack.Push(1)
if len(stack.Nums) != 1 {
t.Errorf("expected stack size 1, got %d", len(stack.Nums))
}

stack.Push(2)
if len(stack.Nums) != 2 {
t.Errorf("expected stack size 2, got %d", len(stack.Nums))
}
}

func TestPop(t *testing.T) {
stack := &Stack{}

stack.Push(1)
stack.Push(2)

item, err := stack.Pop()
if err != nil {
t.Errorf("unexpected error: %v", err)
}
if item != 2 {
t.Errorf("expected 2, got %d", item)
}

item, err = stack.Pop()
if err != nil {
t.Errorf("unexpected error: %v", err)
}
if item != 1 {
t.Errorf("expected 1, got %d", item)
}

_, err = stack.Pop()
if err == nil {
t.Errorf("expected error, got nil")
}
}

func TestIsEmpty(t *testing.T) {
stack := &Stack{}

if !stack.IsEmpty() {
t.Errorf("expected stack to be empty")
}

stack.Push(1)
if stack.IsEmpty() {
t.Errorf("expected stack to be non-empty")
}

stack.Pop()
if !stack.IsEmpty() {
t.Errorf("expected stack to be empty")
}
}

0 comments on commit b2d4011

Please sign in to comment.