initial commit

This commit is contained in:
Rob Westgeest 2026-06-30 20:45:25 +02:00
commit 2346cf156b
23 changed files with 758 additions and 0 deletions

2
.claude/git/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
*
!.gitignore

2
.claude/npm/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
*
!.gitignore

4
.claude/settings.json Normal file
View File

@ -0,0 +1,4 @@
{
"packages": [
]
}

View File

@ -0,0 +1,24 @@
---
name: task-breakdown
description: "Break down complex tasks into test lists Use when: planning work, decomposing features, tracking task progress, or organizing multi-step implementations. Attach file locations and implementation details as multi line comment after test description."
---
# Task Breakdown & Progress Tracking
This skill provides the workflow for decomposing complex tasks into tracked subtasks and managing their lifecycle using simple test lists
## Core Principle
**Always write a list of test names as individual comments in the test file**
The executing agent will use this list to implement
## Workflow
### 1. Break Down a Task
Ask the user clarifying questions. One question at a time. Make a test list with the user. Each test should fail.
Ask the user clarifications about the domain concepts and api. Write the decision in the test file as well
Add the minimal amount of functionality, only what the test requires.

View File

@ -0,0 +1,34 @@
---
name: task-execution
description: "Execute pre-broken-down tasks using the test list. Use when: inheriting a task list, picking the next task to work on, reading task context before implementation, or discovering new subtasks during implementation."
---
# Task Execution & Progress Tracking
This skill provides the workflow for **executing** tasks that have already been broken down by the `task-breakdown` skill. It complements TDD workflows by keeping task state in sync with implementation progress.
## Core Principles
**Always use test list**
Turn the comment into the name of the Test, delete the comment. Delete the sample implementation, use it as inspiration, but beware that details may have changed.
**Work together with user**
- Ask user to review when tests are green before committing.
- Ask the user clarifiying questions when in doubt or when the test passes in the red phase.
- Ask user permission to proceed to the next test
## Relationship to Other Skills
| Skill | Role |
|-------|------|
| `task-breakdown` | Decomposes features into tracked subtasks (planning phase) |
| `task-execution` | Executes pre-broken-down tasks (implementation phase) |
| `tdd-minimalism` | Ensures minimal implementations during the Red-Green-Refactor cycle |
| `test-focus-isolation` | Ensures each test fails for only one reason |
| `testcase-common-setup` | Reduces test duplication via fixtures |
Use `task-breakdown` first to plan, then `task-execution` to implement, with `tdd-minimalism` and test skills guiding the actual coding.

View File

@ -0,0 +1,139 @@
---
name: tdd-minimalism
user-invocable: true
description: "Use when: implementing code to pass tests, writing minimal implementations, TDD workflow. Enforces strict minimalism by analyzing tests first and generating only the absolute minimum code needed. Prevents overengineering and anticipatory code. Run this skill before implementation on any failing test."
---
# TDD Minimalism Guardrails
This skill enforces strict Test-Driven Development discipline by ensuring implementations contain **only** the code that tests require—nothing more.
## Principle
Generate **only the absolute minimum** needed to pass tests. Anticipatory code, infrastructure for future scenarios, defensive checks, comments explaining future work, or over-engineered data structures all violate TDD and should be deleted before writing implementation code.
## Pre-Implementation Workflow
Before writing implementation code, ALWAYS execute this checklist:
### 1. Analyze the Test
- Read the test completely
- Identify exactly what methods/functions the test **calls**
- Identify exactly what the test **asserts**
- Document nothing else matters for this test
### 2. Define Minimal State
Ask: "What data must persist across the test's method calls to satisfy the assertions?"
- Only that data gets stored as member variables
- Everything else is deleted before writing code
### 3. Implement Only Tested Paths
- Implement **only** the specific code paths the test exercises
- **No conditional logic** unless the test verifies multiple branches
- **No utility methods or helper classes**
- **No defensive code** (null checks, boundary conditions the test doesn't trigger)
- **No comments explaining future features**
- **No includes** you don't use
### 4. Question Every Line
For each piece of code, ask: "Does this test directly exercise this line?"
- **No** → Delete it immediately
- **Yes** → Keep it
## Anti-Patterns to Eliminate
| ❌ Anti-Pattern | Why It's Wrong | ✅ Corrected |
| ---------------------------------------------------------- | ---------------------------------------- | -------------------------- |
| Store data in a map/vector when test uses only 1 item | Implements multi-item support not tested | Use single member variable |
| Add `if` checks for untested scenarios | Defensive code the test doesn't exercise | Return value directly |
| Include `#include <map>` when using `int` | Unused dependency | Remove it |
| Define `lastChoice` member when `select()` doesn't read it | Dead code | Remove unused members |
| Comment explaining "future work" or "TODO" | Out of scope for current test | No implementation comments |
| Use compound assignment (`+=`, `-=`) when test calls method only once | Anticipates future multi-call scenarios not covered by any test | Use simple assignment (`=`) instead |
| Create utility methods not called in test | Anticipatory code | Delete before commit |
## Red-Green-Refactor Phases
Each phase **must** include running the test suite to confirm the expected outcome. The test command is `./run_tests.sh` (or the project's equivalent).
### Red Phase (Writing Tests)
1. Write a test describing one specific behavior
2. **Run the test suite** (`./run_tests.sh`) — confirm the test **fails** (either fails to compile or fails at runtime on an assertion).
- **If the test passes**: The behavior is already covered by existing code. **STOP. Abort and discuss with the user.** Options include: the test is redundant (delete it), the test name/assertions are wrong, or the requirement changed. Do NOT proceed without user input.
- **If the test fails to compile**: Write the absolute minimum stubs (empty classes, empty method signatures) needed to make the code compile, then **run the test suite again** — confirm the test now **fails at runtime** on the assertion (`EXPECT_*`/`ASSERT_*`), not just on compilation. This validates the assertion logic is correct before implementing.
- **If the test fails at runtime**: You may proceed to the Green phase.
3. Keep scope narrow (single scenario, not edge cases)
4. Test only what's currently required by the story
### Green Phase (Implementation)
1. Implement **only** what the test directly calls
2. Use the simplest possible data types
3. Use the shortest possible logic
4. **Run the test suite** (`./run_tests.sh`) — confirm it **passes**
5. Reference this skill's anti-patterns table and eliminate violations before committing
6. **Present the implementation to the user for review** before committing or proceeding to the next test.
- Show the final state of all changed files (diff or summary)
- Ask explicitly: "Please review and approve before I proceed"
- Do NOT move to the next test, commit, or merge without explicit user approval
- If the user requests changes, make them and re-run the test suite before asking for review again
### Refactor Phase
1. Improve code clarity (rename variables, format nicely)
2. **Run the test suite** (`./run_tests.sh`) — confirm tests still **pass**
3. **Never** add functionality without a failing test first
4. **Never** add infrastructure for "future" requirements
## Post-Implementation Verification
After implementing and tests pass, run this verification:
- [ ] Can I remove any member variables? (Are they all accessed in at least one method?)
- [ ] Can I remove any `#include` directives? (Do I use everything I include?)
- [ ] Can I remove any conditional branches? (Does the test exercise all paths?)
- [ ] Can I remove any comments? (Are they implementation comments, not documentation?)
- [ ] Can I remove any method parameters? (Are they all used in the method?)
- [ ] Can I replace any compound assignment (`+=`, `-=`, etc.) with simple assignment (`=`) without changing test outcomes?
If you answer **yes** to any question, make those deletions immediately. Do not proceed to the next test/feature without eliminating unnecessary code.
## Example: The Vending Machine
**Test** (what it calls and asserts):
```cpp
machine.addChoice(Choice::Cola, 0); // Calls this
machine.assignProduct(Choice::Cola, Brand::Coke); // Calls this
EXPECT_EQ(machine.select(Choice::Cola), Brand::Coke); // Asserts this
```
**Minimal Implementation:**
```cpp
// Header: ONE member variable (lastBrand), because select() returns it
Brand lastBrand;
// Implementation
void addChoice(Choice, int) {} // Body empty; test calls but doesn't verify behavior
void assignProduct(Choice choice, Brand brand) { lastBrand = brand; }
std::optional<Brand> select(Choice choice) { return lastBrand; } // No if; test only selects once
```
**Eliminated Code:**
- ❌ `#include <map>` — Not using maps
- ❌ `std::map<Choice, Brand> productMap` — Test uses only one assignment
- ❌ `if (it != productMap.end())` — Test doesn't verify "choice not found" scenario
- ❌ Comments explaining future work — Out of test scope
- ❌ `Choice lastChoice``select()` doesn't read it; never used

View File

@ -0,0 +1,124 @@
---
name: tdd-test-refactoring
user-invocable: true
description: "Use during Green/Refactor phase to eliminate test duplication. Extracts shared setup into TEST_F fixtures, removes redundant expectations, and keeps tests minimal and focused. Run after tests pass but before committing."
---
# TDD Test Refactoring Patterns
This skill complements **tdd-minimalism** by focusing on **test code quality** during the Green and Refactor phases. After implementation is minimal and passing, apply these patterns to keep the test suite clean.
## Principle
Tests are code too — they accumulate duplication and cruft just like implementation. Each test should test **one distinct scenario** without repeating setup or expectations already covered by other tests.
## Refactoring Checklist
After tests pass (Green phase), review the test file for these patterns:
### 1. Extract Shared Setup into TEST_F
If multiple tests construct the same object(s) with the same configuration, extract the common setup into a fixture.
**Before:**
```cpp
TEST(VendingMachineTest, configured_machine_delivers_can) {
VendingMachine machine;
machine.Configure(Choice::Cola, Can::Coke);
EXPECT_EQ(machine.Deliver(Choice::Cola), Can::Coke);
}
TEST(VendingMachineTest, multiple_choices_deliver_different_cans) {
VendingMachine machine;
machine.Configure(Choice::Cola, Can::Coke);
machine.Configure(Choice::Fanta, Can::Orange);
EXPECT_EQ(machine.Deliver(Choice::Cola), Can::Coke);
EXPECT_EQ(machine.Deliver(Choice::Fanta), Can::Orange);
}
```
**After:**
```cpp
class VendingMachineTest : public ::testing::Test {
protected:
void SetUp() override {
machine.Configure(Choice::Cola, Can::Coke);
}
VendingMachine machine;
};
TEST_F(VendingMachineTest, configured_machine_delivers_can) {
EXPECT_EQ(machine.Deliver(Choice::Cola), Can::Coke);
}
TEST_F(VendingMachineTest, multiple_choices_deliver_different_cans) {
machine.Configure(Choice::Fanta, Can::Orange);
EXPECT_EQ(machine.Deliver(Choice::Cola), Can::Coke);
EXPECT_EQ(machine.Deliver(Choice::Fanta), Can::Orange);
}
```
**When to keep TEST instead of TEST_F:**
- The test needs a **different** or **empty** initial state (e.g., an unconfigured machine)
- The test's setup is entirely unique and not shared with any other test
### 2. Remove Redundant Expectations
If a test is a **strict superset** of another test (covers the same scenario plus more), the subset test may be redundant.
**Check:** Does the superset test already assert everything the subset test asserts?
| Scenario | Keep? |
|----------|-------|
| Superset test covers all assertions of subset | Consider removing subset if it adds no unique coverage |
| Superset test covers subset's assertions **plus** additional ones | Keep both if subset documents a specific edge case clearly |
| Tests cover different branches of the same logic | Keep both — they test different paths |
### 3. Name Tests by Scenario, Not by Order
Test names should describe **what scenario** they cover, not their sequence number.
| ❌ Bad | ✅ Good |
|--------|--------|
| `test1`, `test2`, `test3` | `choiceless_machine_deliver_nothing` |
| `first_test`, `second_test` | `configured_machine_delivers_can` |
| `test_feature_x` | `multiple_choices_deliver_different_cans` |
### 4. One Logical Assertion Per Test
Each test should verify **one behavior**. Avoid asserting unrelated things in the same test.
**When multiple assertions are OK:**
- They verify the **same result** from different angles (e.g., `.has_value()` and `== expected`)
- They verify a **post-condition** that naturally produces multiple observable effects
**When to split:**
- Assertions exercise **different code paths** or **different methods**
- One assertion failing hides whether the other would also fail
### 5. Keep Tests Independent
Tests must not depend on each other's side effects. Each test (or each fixture instance) starts fresh.
- ✅ Each `TEST_F` gets a **fresh** `SetUp()`
- ✅ No shared mutable state between tests
- ❌ No test ordering dependencies
## Post-Refactoring Verification
After applying test refactoring:
- [ ] Run the test suite — all tests still pass
- [ ] Run clang-format — all files comply
- [ ] No test is a complete subset of another (unless documenting a specific edge case)
- [ ] No duplicate setup code across tests using the same initial state
- [ ] Test names describe the scenario, not the sequence
## Relationship to tdd-minimalism
| Skill | Focus | When |
|-------|-------|------|
| tdd-minimalism | Implementation code — eliminate overengineering | Before writing implementation |
| tdd-test-refactoring | Test code — eliminate duplication and cruft | After tests pass, before commit |
Run **tdd-minimalism** before implementation. Run **tdd-test-refactoring** after tests pass but before committing.

View File

@ -0,0 +1,80 @@
---
name: test-focus-isolation
description: 'Refactor tests so each one fails for only one reason and asserts one conceptual behavior. Use when: reviewing/refactoring tests with overlapping assertions, duplicate checks, or tests that verify the same behavior as another test.'
---
# Test Focus Isolation
## When to Use
- Two or more tests assert the same outcome (e.g., both check Cola delivery)
- A test mixes assertions about different conceptual behaviors
- A failure could break multiple tests for the same root cause
- Reviewing test coverage and finding overlapping checks
## Principles
### 1. One Reason to Fail Per Test
Each test should fail for **exactly one root cause**. If the same assertion appears in multiple tests, a single bug breaks multiple tests — this wastes debugging time and reduces signal quality.
**Rule**: A specific behavior or assertion should appear in exactly **one** test.
**✗ Bad** — Both tests fail if Cola delivery breaks:
```cpp
TEST_F(suite, cola_delivery) {
EXPECT_EQ(vm.deliver(Choice::Cola), Brand::Coke);
}
TEST_F(suite, multiple_choices) {
EXPECT_EQ(vm.deliver(Choice::Cola), Brand::Coke); // ← duplicate
EXPECT_EQ(vm.deliver(Choice::FizzyOrange), Brand::Fanta);
}
```
**✓ Good** — Each behavior is tested once:
```cpp
TEST_F(suite, cola_delivery) {
EXPECT_EQ(vm.deliver(Choice::Cola), Brand::Coke);
}
TEST_F(suite, multiple_choices) {
// Only the NEW behavior this test introduces
EXPECT_EQ(vm.deliver(Choice::FizzyOrange), Brand::Fanta);
}
```
### 2. One Conceptual Assert Per Test
A test should verify **one conceptual behavior**. If a test checks two different things (e.g., Cola delivery AND FizzyOrange delivery), split it into two tests — unless the concept being tested is specifically "multiple choices work together."
**Rule**: Each test name should answer "yes/no" to a single question. The assertions inside should all serve that same question.
**✗ Bad** — Two behaviors in one test:
```cpp
TEST_F(suite, processes_orders) {
EXPECT_EQ(vm.deliver(Choice::Cola), Brand::Coke);
EXPECT_EQ(vm.deliver(Choice::FizzyOrange), Brand::Fanta);
}
```
**✓ Good** — Each test asks one question:
```cpp
TEST_F(suite, delivers_cola) {
EXPECT_EQ(vm.deliver(Choice::Cola), Brand::Coke);
}
TEST_F(suite, delivers_fizzy_orange) {
EXPECT_EQ(vm.deliver(Choice::FizzyOrange), Brand::Fanta);
}
```
**Exception**: If the concept being tested inherently involves multiple values (e.g., "supports multiple choices simultaneously"), it's acceptable to check all of them — because the test name communicates the multi-behavior concept.
## Procedure
1. **Scan tests for overlapping assertions** — grep for repeated `EXPECT_EQ`, `EXPECT_TRUE`, etc. across tests in the same suite.
2. **Identify the unique behavior** each test introduces — what does this test verify that no other test verifies?
3. **Remove duplicate assertions** — keep the assertion only in the test that best owns it. Delete it from the others.
4. **Rename tests** to clearly describe their singular behavior (e.g., `delivers_cola` instead of `configured_choice_delivers_correct_can`).
5. **Split tests** if a single test asserts multiple unrelated behaviors (unless the concept is multi-behavior by nature).
6. **Verify** — run the test suite to ensure coverage is preserved and tests pass.

View File

@ -0,0 +1,161 @@
---
name: testcase-common-setup
description: 'Use when: refactoring tests to eliminate duplication via test fixtures, extracting common setup into SetUp(), converting TEST() to TEST_F() in Google Test. Run this after adding new test cases that duplicate setup code.'
user-invocable: true
---
# Test Case Common Setup (Google Test)
This skill refactors Google Test suites by extracting duplicate setup code into a shared test fixture with `SetUp()`. Applying this skill makes tests more maintainable and reduces noise from repeated scaffolding.
## When to Use
- Multiple `TEST()` cases create the same object or call the same configuration
- A new test case requires copying setup lines from an existing test
- Reviewing test code and noticing the same 2+ lines repeated across every test
- After adding a new test that duplicates setup from existing tests
## Procedure
### 1. Identify Duplicated Setup
Scan all `TEST()` blocks in the test suite. Look for lines that are **identical** across every test — typically:
- Object creation: `VendingMachine vm;` (or similar SUT construction)
- Common configuration calls: `vm.configureSlot(...)`
- Pre-conditions that apply to all tests
### 2. Create a Test Fixture
Introduce a fixture class deriving from `::testing::Test`:
```cpp
class <TestSuiteName> : public ::testing::Test {
protected:
// Shared state goes here — typically the System Under Test
<Type> <variable>;
};
```
- Place it right after the includes, before the first test
- Declare shared variables as `protected` members
- Name the fixture after the test suite (e.g. `VendingMachineTest`)
### 3. Extract Shared Setup into `SetUp()`
Define `void SetUp() override` inside the fixture with the lines common to **all** tests:
```cpp
class <TestSuiteName> : public ::testing::Test {
protected:
<Type> <variable>;
void SetUp() override
{
// Lines that every test needs — extracted here once
<sharedSetupLine1>;
<sharedSetupLine2>;
}
};
```
Rules:
- Only move lines that appear in **every** test
- If a line only appears in some tests, leave it in the individual `TEST_F()` bodies
- Keep `SetUp()` focused — it runs before each test, so don't put expensive or test-specific logic there
### 4. Convert `TEST()` to `TEST_F()`
Replace every occurrence:
```cpp
// Before
TEST(<TestSuiteName>, <TestCaseName>)
{
<Type> <variable>; // ← now redundant
<sharedSetupLine1>; // ← now redundant (in SetUp)
...
}
// After
TEST_F(<TestSuiteName>, <TestCaseName>)
{
// Only test-specific code remains
...
}
```
- Remove the redundant object declaration from each test body
- Remove any lines now handled by `SetUp()`
- Remove configuration calls that were duplicates across all tests
### 5. Verify
Run the test suite to confirm all tests still pass:
```bash
./run_tests.sh
```
All tests must pass before considering the refactor complete.
## Example
Before — three tests with duplicated setup:
```cpp
TEST(VendingMachineTest, unconfigured_choice_dispenses_nothing)
{
VendingMachine vm;
EXPECT_EQ(vm.dispense(Choice::Cola), std::nullopt);
}
TEST(VendingMachineTest, configured_slot_dispenses_can)
{
VendingMachine vm;
vm.configureSlot(Choice::Cola, Can::Coke);
EXPECT_EQ(vm.dispense(Choice::Cola), Can::Coke);
}
TEST(VendingMachineTest, multiple_slots_dispense_correctly)
{
VendingMachine vm;
vm.configureSlot(Choice::FizzyOrange, Can::Fanta);
vm.configureSlot(Choice::Cola, Can::Coke);
EXPECT_EQ(vm.dispense(Choice::FizzyOrange), Can::Fanta);
}
```
After — fixture with `SetUp()`:
```cpp
class VendingMachineTest : public ::testing::Test {
protected:
VendingMachine vm;
void SetUp() override
{
vm.configureSlot(Choice::Cola, Can::Coke);
vm.configureSlot(Choice::FizzyOrange, Can::Fanta);
}
};
TEST_F(VendingMachineTest, unconfigured_choice_dispenses_nothing)
{
EXPECT_EQ(vm.dispense(Choice::Beer), std::nullopt);
}
TEST_F(VendingMachineTest, configured_slot_dispenses_can)
{
EXPECT_EQ(vm.dispense(Choice::Cola), Can::Coke);
}
TEST_F(VendingMachineTest, multiple_slots_dispense_correctly)
{
EXPECT_EQ(vm.dispense(Choice::FizzyOrange), Can::Fanta);
}
```
## References
- [Google Test: Test Fixtures](https://google.github.io/googletest/primer.html#same-data-multiple-tests)

12
.dockerignore Normal file
View File

@ -0,0 +1,12 @@
.git
**/bin
**/obj
**/target
.idea/
Dockerfile
.dockerignore
build.sh
run-local.sh
donstro/
README.md
rebuild.sh

8
.gitignore vendored Normal file
View File

@ -0,0 +1,8 @@
bin
packages
obj
*.userprefs
.idea
VendingMachine.sln.DotSettings.user
donstro/remote.secrets

1
.pi/skills Symbolic link
View File

@ -0,0 +1 @@
../.github/skills/

8
Dockerfile Normal file
View File

@ -0,0 +1,8 @@
FROM 525595969507.dkr.ecr.eu-central-1.amazonaws.com/qwan/csharp:latest
COPY --chown=experience:experience ./ vendingmachine
RUN cd vendingmachine &&\
git init . && git add . && git commit -am "initial commit" &&\
git remote add qwan /git/qwan/vendingmachine
USER experience

57
README.md Normal file
View File

@ -0,0 +1,57 @@
# Vending Machine C# - Test Driven Development exercise
## Building the Docker image
To build the course image:
```bash
./build.sh
```
To push it to AWS registry:
```bash
docker-login.sh
./build.sh push
```
## Set up for deployment
Add an SSH config for `course-server`:
```
Host course-server
Hostname ec2-3-65-110-13.eu-central-1.compute.amazonaws.com
IdentityFile ~/.ssh/<your key goes here>
User ubuntu
```
## Deployment
Deployment uses Donstro: https://github.com/rwestgeest/donstro
The docker-compose file describing the course instances can be found in `donstro/`
Deploy the composition to `course-server` using Donstro, first let the server login to AWS ECR (using `docker-login` from the course-infra repo):
```bash
docker-login.sh course-server
```
Then deploy:
```bash
donstro_single up
```
## stopping containers
donstro_single stop
## getting in a container
donstro_single exec cat bash
## cleanup volumes
donstro_single down -v
## Setting login passwords for the containers
TBD

View File

@ -0,0 +1,11 @@
namespace Vending.Tests;
[TestFixture]
public class TestVendingMachine
{
[Test]
public void ItFails()
{
Assert.That(0, Is.EqualTo(1));
}
}

View File

@ -0,0 +1,28 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<IsPackable>false</IsPackable>
<IsTestProject>true</IsTestProject>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="coverlet.collector" Version="6.0.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0" />
<PackageReference Include="NUnit" Version="3.14.0" />
<PackageReference Include="NUnit.Analyzers" Version="3.9.0" />
<PackageReference Include="NUnit3TestAdapter" Version="4.5.0" />
</ItemGroup>
<ItemGroup>
<Using Include="NUnit.Framework" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Vending\Vending.csproj" />
</ItemGroup>
</Project>

2
Vending/Program.cs Normal file
View File

@ -0,0 +1,2 @@
// See https://aka.ms/new-console-template for more information
Console.WriteLine("Hello, World!");

10
Vending/Vending.csproj Normal file
View File

@ -0,0 +1,10 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>

28
VendingMachine.sln Normal file
View File

@ -0,0 +1,28 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.0.31903.59
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Vending", "Vending\Vending.csproj", "{CFC6ADCF-20F2-4E9E-82E5-ABBF9F5FDB58}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Vending.Tests", "Vending.Tests\Vending.Tests.csproj", "{B041B730-AEEA-4A78-B605-19C36563402C}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{CFC6ADCF-20F2-4E9E-82E5-ABBF9F5FDB58}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{CFC6ADCF-20F2-4E9E-82E5-ABBF9F5FDB58}.Debug|Any CPU.Build.0 = Debug|Any CPU
{CFC6ADCF-20F2-4E9E-82E5-ABBF9F5FDB58}.Release|Any CPU.ActiveCfg = Release|Any CPU
{CFC6ADCF-20F2-4E9E-82E5-ABBF9F5FDB58}.Release|Any CPU.Build.0 = Release|Any CPU
{B041B730-AEEA-4A78-B605-19C36563402C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B041B730-AEEA-4A78-B605-19C36563402C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B041B730-AEEA-4A78-B605-19C36563402C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B041B730-AEEA-4A78-B605-19C36563402C}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
EndGlobal

23
buildspec.yml Normal file
View File

@ -0,0 +1,23 @@
version: 0.2
phases:
pre_build:
commands:
- echo Logging in to Amazon ECR...
- aws --version
- aws ecr get-login-password --region eu-central-1 | docker login --username AWS --password-stdin 525595969507.dkr.ecr.eu-central-1.amazonaws.com
- REPOSITORY_URI=525595969507.dkr.ecr.eu-central-1.amazonaws.com/qwan/vendingmachine_cs
- COMMIT_HASH=$(echo $CODEBUILD_RESOLVED_SOURCE_VERSION | cut -c 1-7)
- IMAGE_TAG=${COMMIT_HASH:=latest}
build:
commands:
- echo Build started on `date`
- echo Building the Docker image...
- docker build -t $REPOSITORY_URI:latest .
- docker tag $REPOSITORY_URI:latest $REPOSITORY_URI:$IMAGE_TAG
post_build:
commands:
- echo Build completed on `date`
- echo Pushing the Docker images...
- docker push $REPOSITORY_URI:latest
- docker push $REPOSITORY_URI:$IMAGE_TAG

BIN
external_libs/NMock2.dll Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.