Skip to content

Commit 30774bb

Browse files
committed
Reorganize and enhance entire repository
Major refactoring and improvements to transform the project from a single-file script into a professional, well-structured Elixir application: ## Project Structure - Convert to proper Mix project with standard directory layout - Split monolithic code into modular components (6 focused modules) - Add proper project configuration (mix.exs) ## Code Organization - ChatSimulator.User: User data structure with password hashing - ChatSimulator.Message: Message handling with timestamps and read status - ChatSimulator.Auth: Authentication and registration logic - ChatSimulator.Storage: Agent-based persistence with file backup - ChatSimulator.CLI: Enhanced interactive command-line interface - ChatSimulator: Main module with convenience functions ## Documentation - Comprehensive README with installation and usage instructions - CONTRIBUTING.md with development guidelines - Module and function documentation with @doc and @SPEC - Inline examples and usage patterns ## Testing - Complete ExUnit test suite for all modules - Unit tests for User, Message, Auth, and Storage - Test helper configuration - Ready for test coverage analysis ## Code Quality - .formatter.exs for consistent code formatting - .credo.exs for static code analysis - GitHub Actions CI/CD workflow for automated testing - Multi-version Elixir and OTP testing matrix ## Security & Features - SHA256 password hashing (replacing plain text storage) - Username and password validation - Data persistence with automatic saving - New features: list users, conversation history, unread counter - Message read/unread tracking - Improved error handling and user feedback ## Developer Experience - Updated .gitignore with comprehensive rules - CI/CD pipeline with format checking, tests, and build verification - Escript build support for standalone executable - Development documentation and contribution guidelines This reorganization maintains all original functionality while adding professional-grade structure, security, testing, and documentation.
1 parent f9086e7 commit 30774bb

File tree

19 files changed

+2129
-121
lines changed

19 files changed

+2129
-121
lines changed

.credo.exs

Lines changed: 191 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,191 @@
1+
# This file contains the configuration for Credo and you are probably reading
2+
# this after creating it with `mix credo.gen.config`.
3+
#
4+
# If you find anything wrong or unclear in this file, please report an
5+
# issue on GitHub: https://github.com/rrrene/credo/issues
6+
#
7+
%{
8+
#
9+
# You can have as many configs as you like in the `configs:` field.
10+
configs: [
11+
%{
12+
#
13+
# Run any config using `mix credo -C <name>`. If no config name is given
14+
# "default" is used.
15+
#
16+
name: "default",
17+
#
18+
# These are the files included in the analysis:
19+
files: %{
20+
#
21+
# You can give explicit globs or simply directories.
22+
# In the latter case `**/*.{ex,exs}` will be used.
23+
#
24+
included: [
25+
"lib/",
26+
"test/"
27+
],
28+
excluded: [~r"/_build/", ~r"/deps/", ~r"/node_modules/"]
29+
},
30+
#
31+
# Load and configure plugins here:
32+
#
33+
plugins: [],
34+
#
35+
# If you create your own checks, you must specify the source files for
36+
# them here, so they can be loaded by Credo before running the analysis.
37+
#
38+
requires: [],
39+
#
40+
# If you want to enforce a style guide and need a more traditional linting
41+
# experience, you can change `strict` to `true` below:
42+
#
43+
strict: false,
44+
#
45+
# To modify the timeout for parsing files, change this value:
46+
#
47+
parse_timeout: 5000,
48+
#
49+
# If you want to use uncolored output by default, you can change `color`
50+
# to `false` below:
51+
#
52+
color: true,
53+
#
54+
# You can customize the parameters of any check by adding a second element
55+
# to the tuple.
56+
#
57+
# To disable a check put `false` as second element:
58+
#
59+
# {Credo.Check.Design.DuplicatedCode, false}
60+
#
61+
checks: %{
62+
enabled: [
63+
#
64+
## Consistency Checks
65+
#
66+
{Credo.Check.Consistency.ExceptionNames, []},
67+
{Credo.Check.Consistency.LineEndings, []},
68+
{Credo.Check.Consistency.ParameterPatternMatching, []},
69+
{Credo.Check.Consistency.SpaceAroundOperators, []},
70+
{Credo.Check.Consistency.SpaceInParentheses, []},
71+
{Credo.Check.Consistency.TabsOrSpaces, []},
72+
73+
#
74+
## Design Checks
75+
#
76+
{Credo.Check.Design.AliasUsage,
77+
[priority: :low, if_nested_deeper_than: 2, if_called_more_often_than: 0]},
78+
{Credo.Check.Design.TagFIXME, []},
79+
{Credo.Check.Design.TagTODO, [exit_status: 0]},
80+
81+
#
82+
## Readability Checks
83+
#
84+
{Credo.Check.Readability.AliasOrder, []},
85+
{Credo.Check.Readability.FunctionNames, []},
86+
{Credo.Check.Readability.LargeNumbers, []},
87+
{Credo.Check.Readability.MaxLineLength, [priority: :low, max_length: 120]},
88+
{Credo.Check.Readability.ModuleAttributeNames, []},
89+
{Credo.Check.Readability.ModuleDoc, []},
90+
{Credo.Check.Readability.ModuleNames, []},
91+
{Credo.Check.Readability.ParenthesesInCondition, []},
92+
{Credo.Check.Readability.ParenthesesOnZeroArityDefs, []},
93+
{Credo.Check.Readability.PipeIntoAnonymousFunctions, []},
94+
{Credo.Check.Readability.PredicateFunctionNames, []},
95+
{Credo.Check.Readability.PreferImplicitTry, []},
96+
{Credo.Check.Readability.RedundantBlankLines, []},
97+
{Credo.Check.Readability.Semicolons, []},
98+
{Credo.Check.Readability.SpaceAfterCommas, []},
99+
{Credo.Check.Readability.StringSigils, []},
100+
{Credo.Check.Readability.TrailingBlankLine, []},
101+
{Credo.Check.Readability.TrailingWhiteSpace, []},
102+
{Credo.Check.Readability.UnnecessaryAliasExpansion, []},
103+
{Credo.Check.Readability.VariableNames, []},
104+
{Credo.Check.Readability.WithSingleClause, []},
105+
106+
#
107+
## Refactoring Opportunities
108+
#
109+
{Credo.Check.Refactor.Apply, []},
110+
{Credo.Check.Refactor.CondStatements, []},
111+
{Credo.Check.Refactor.CyclomaticComplexity, []},
112+
{Credo.Check.Refactor.FunctionArity, []},
113+
{Credo.Check.Refactor.LongQuoteBlocks, []},
114+
{Credo.Check.Refactor.MatchInCondition, []},
115+
{Credo.Check.Refactor.MapJoin, []},
116+
{Credo.Check.Refactor.NegatedConditionsInUnless, []},
117+
{Credo.Check.Refactor.NegatedConditionsWithElse, []},
118+
{Credo.Check.Refactor.Nesting, []},
119+
{Credo.Check.Refactor.RedundantWithClauseResult, []},
120+
{Credo.Check.Refactor.UnlessWithElse, []},
121+
{Credo.Check.Refactor.WithClauses, []},
122+
123+
#
124+
## Warnings
125+
#
126+
{Credo.Check.Warning.ApplicationConfigInModuleAttribute, []},
127+
{Credo.Check.Warning.BoolOperationOnSameValues, []},
128+
{Credo.Check.Warning.Dbg, []},
129+
{Credo.Check.Warning.ExpensiveEmptyEnumCheck, []},
130+
{Credo.Check.Warning.IExPry, []},
131+
{Credo.Check.Warning.IoInspect, []},
132+
{Credo.Check.Warning.OperationOnSameValues, []},
133+
{Credo.Check.Warning.OperationWithConstantResult, []},
134+
{Credo.Check.Warning.RaiseInsideRescue, []},
135+
{Credo.Check.Warning.SpecWithStruct, []},
136+
{Credo.Check.Warning.UnsafeExec, []},
137+
{Credo.Check.Warning.UnusedEnumOperation, []},
138+
{Credo.Check.Warning.UnusedFileOperation, []},
139+
{Credo.Check.Warning.UnusedKeywordOperation, []},
140+
{Credo.Check.Warning.UnusedListOperation, []},
141+
{Credo.Check.Warning.UnusedPathOperation, []},
142+
{Credo.Check.Warning.UnusedRegexOperation, []},
143+
{Credo.Check.Warning.UnusedStringOperation, []},
144+
{Credo.Check.Warning.UnusedTupleOperation, []},
145+
{Credo.Check.Warning.WrongTestFileExtension, []}
146+
],
147+
disabled: [
148+
#
149+
# Checks scheduled for next check update (opt-in for now)
150+
{Credo.Check.Refactor.UtcNowTruncate, []},
151+
152+
#
153+
# Controversial and experimental checks (opt-in, just move the check to `:enabled`
154+
# and be sure to use `mix credo --strict` to see low priority checks)
155+
#
156+
{Credo.Check.Consistency.MultiAliasImportRequireUse, []},
157+
{Credo.Check.Consistency.UnusedVariableNames, []},
158+
{Credo.Check.Design.DuplicatedCode, []},
159+
{Credo.Check.Design.SkipTestWithoutComment, []},
160+
{Credo.Check.Readability.AliasAs, []},
161+
{Credo.Check.Readability.BlockPipe, []},
162+
{Credo.Check.Readability.ImplTrue, []},
163+
{Credo.Check.Readability.MultiAlias, []},
164+
{Credo.Check.Readability.NestedFunctionCalls, []},
165+
{Credo.Check.Readability.SeparateAliasRequire, []},
166+
{Credo.Check.Readability.SingleFunctionToBlockPipe, []},
167+
{Credo.Check.Readability.SinglePipe, []},
168+
{Credo.Check.Readability.Specs, []},
169+
{Credo.Check.Readability.StrictModuleLayout, []},
170+
{Credo.Check.Readability.WithCustomTaggedTuple, []},
171+
{Credo.Check.Refactor.ABCSize, []},
172+
{Credo.Check.Refactor.AppendSingleItem, []},
173+
{Credo.Check.Refactor.DoubleBooleanNegation, []},
174+
{Credo.Check.Refactor.FilterReject, []},
175+
{Credo.Check.Refactor.IoPuts, []},
176+
{Credo.Check.Refactor.MapMap, []},
177+
{Credo.Check.Refactor.ModuleDependencies, []},
178+
{Credo.Check.Refactor.NegatedIsNil, []},
179+
{Credo.Check.Refactor.PipeChainStart, []},
180+
{Credo.Check.Refactor.RejectReject, []},
181+
{Credo.Check.Refactor.VariableRebinding, []},
182+
{Credo.Check.Warning.LazyLogging, []},
183+
{Credo.Check.Warning.LeakyEnvironment, []},
184+
{Credo.Check.Warning.MapGetUnsafePass, []},
185+
{Credo.Check.Warning.MixEnv, []},
186+
{Credo.Check.Warning.UnsafeToAtom, []}
187+
]
188+
}
189+
}
190+
]
191+
}

.formatter.exs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# Used by "mix format"
2+
[
3+
inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"],
4+
line_length: 98
5+
]

.github/workflows/ci.yml

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
name: CI
2+
3+
on:
4+
push:
5+
branches: [ main, develop ]
6+
pull_request:
7+
branches: [ main, develop ]
8+
9+
env:
10+
MIX_ENV: test
11+
ELIXIR_VERSION: '1.15'
12+
OTP_VERSION: '26.0'
13+
14+
jobs:
15+
test:
16+
name: Test (Elixir ${{ matrix.elixir }} / OTP ${{ matrix.otp }})
17+
runs-on: ubuntu-latest
18+
19+
strategy:
20+
matrix:
21+
elixir: ['1.14', '1.15', '1.16']
22+
otp: ['25.0', '26.0']
23+
exclude:
24+
- elixir: '1.14'
25+
otp: '26.0'
26+
27+
steps:
28+
- name: Checkout code
29+
uses: actions/checkout@v4
30+
31+
- name: Set up Elixir
32+
uses: erlef/setup-beam@v1
33+
with:
34+
elixir-version: ${{ matrix.elixir }}
35+
otp-version: ${{ matrix.otp }}
36+
37+
- name: Restore dependencies cache
38+
uses: actions/cache@v3
39+
with:
40+
path: |
41+
deps
42+
_build
43+
key: ${{ runner.os }}-mix-${{ matrix.elixir }}-${{ matrix.otp }}-${{ hashFiles('**/mix.lock') }}
44+
restore-keys: |
45+
${{ runner.os }}-mix-${{ matrix.elixir }}-${{ matrix.otp }}-
46+
47+
- name: Install dependencies
48+
run: mix deps.get
49+
50+
- name: Compile dependencies
51+
run: mix deps.compile
52+
53+
- name: Compile application
54+
run: mix compile --warnings-as-errors
55+
56+
- name: Run tests
57+
run: mix test
58+
59+
- name: Run tests with coverage
60+
run: mix test --cover
61+
if: matrix.elixir == '1.15' && matrix.otp == '26.0'
62+
63+
code_quality:
64+
name: Code Quality
65+
runs-on: ubuntu-latest
66+
67+
steps:
68+
- name: Checkout code
69+
uses: actions/checkout@v4
70+
71+
- name: Set up Elixir
72+
uses: erlef/setup-beam@v1
73+
with:
74+
elixir-version: ${{ env.ELIXIR_VERSION }}
75+
otp-version: ${{ env.OTP_VERSION }}
76+
77+
- name: Restore dependencies cache
78+
uses: actions/cache@v3
79+
with:
80+
path: |
81+
deps
82+
_build
83+
key: ${{ runner.os }}-mix-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ hashFiles('**/mix.lock') }}
84+
restore-keys: |
85+
${{ runner.os }}-mix-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-
86+
87+
- name: Install dependencies
88+
run: mix deps.get
89+
90+
- name: Check formatting
91+
run: mix format --check-formatted
92+
93+
- name: Run Credo
94+
run: mix credo --strict
95+
96+
build:
97+
name: Build Escript
98+
runs-on: ubuntu-latest
99+
100+
steps:
101+
- name: Checkout code
102+
uses: actions/checkout@v4
103+
104+
- name: Set up Elixir
105+
uses: erlef/setup-beam@v1
106+
with:
107+
elixir-version: ${{ env.ELIXIR_VERSION }}
108+
otp-version: ${{ env.OTP_VERSION }}
109+
110+
- name: Restore dependencies cache
111+
uses: actions/cache@v3
112+
with:
113+
path: |
114+
deps
115+
_build
116+
key: ${{ runner.os }}-mix-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ hashFiles('**/mix.lock') }}
117+
restore-keys: |
118+
${{ runner.os }}-mix-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-
119+
120+
- name: Install dependencies
121+
run: mix deps.get
122+
123+
- name: Build escript
124+
run: mix escript.build
125+
126+
- name: Upload artifact
127+
uses: actions/upload-artifact@v3
128+
with:
129+
name: chat_simulator
130+
path: chat_simulator
131+
132+
- name: Test escript
133+
run: |
134+
chmod +x chat_simulator
135+
echo "quit" | ./chat_simulator || true

.gitignore

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
# Build artifacts
12
/_build
23
/cover
34
/deps
@@ -6,5 +7,32 @@
67
erl_crash.dump
78
*.ez
89
*.beam
10+
11+
# Escript build
12+
/chat_simulator
13+
14+
# Configuration
915
/config/*.secret.exs
16+
17+
# IDE and Editor
1018
.elixir_ls/
19+
.vscode/
20+
.idea/
21+
*.swp
22+
*.swo
23+
*~
24+
25+
# OS
26+
.DS_Store
27+
Thumbs.db
28+
29+
# Data files
30+
.chat_data.etf
31+
32+
# Test coverage
33+
/cover/
34+
coveralls.json
35+
36+
# Dialyzer
37+
/priv/plts/*.plt
38+
/priv/plts/*.plt.hash

0 commit comments

Comments
 (0)