Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Tooling and CI set up + 1st four exercises #25

Merged
merged 24 commits into from
Sep 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
41c644f
hello-word, leap, configuration updates
gvrooyen Aug 23, 2024
4f70d44
Add workflow in test.yml
gvrooyen Aug 23, 2024
27d56ac
Modified CI workflow to build Odin from source
gvrooyen Aug 23, 2024
c7fb86e
Completed difference-of-squares, added format-all
gvrooyen Aug 24, 2024
6d31497
Formatted source, added formatting to webhook
gvrooyen Aug 24, 2024
aa92d6e
Added step to push autoformatting changes
gvrooyen Aug 24, 2024
92817bc
Modified test.yml to not fail on no formatting
gvrooyen Aug 24, 2024
17ef99f
Added missing dashes in argument
gvrooyen Aug 24, 2024
5cf8060
Fixed bin/verify-exercises
gvrooyen Aug 24, 2024
0024848
Added the "grains" exercise
gvrooyen Aug 25, 2024
48c2bbe
Updated README; fixed test verification
gvrooyen Aug 25, 2024
11a21ff
Formatted config files with configlet
gvrooyen Aug 26, 2024
3ffcf58
Fixed testing bug that clobbered stub solutions
gvrooyen Aug 26, 2024
97b7017
Small code fixes. Updated README.
gvrooyen Aug 26, 2024
fd4c5d1
Added resistor-color exercise. Updated README.
gvrooyen Aug 26, 2024
cfbb1b8
Fixed and tested the test.yml action
gvrooyen Aug 27, 2024
deb0858
Implemented the resistor-color exercise
gvrooyen Aug 27, 2024
3ea8588
Removed configlet dependency in test.yml
gvrooyen Aug 27, 2024
9cd2286
Moved the exercise checklist to a linked GH issue
gvrooyen Aug 28, 2024
2a8d7cc
Test runner now checks that stub solution fails
gvrooyen Aug 28, 2024
0d5ecdd
Fixed incorrect stubs, added panics for stub procs
gvrooyen Aug 28, 2024
585abb5
Removed fancy terminal color commands
gvrooyen Aug 28, 2024
5f81ce0
Added support for skipping and unskipping tests
gvrooyen Aug 29, 2024
1bf9d9c
Removed mention of NotImplemented in the README
gvrooyen Aug 30, 2024
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
37 changes: 15 additions & 22 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -1,19 +1,6 @@
# This workflow will do a clean install of the dependencies and run tests across different versions
#
# Replace <track> with the track name
# Replace <image-name> with an image to run the jobs on
# Replace <action to setup tooling> with a github action to setup tooling on the image
# Replace <install dependencies> with a cli command to install the dependencies
#
# Find Github Actions to setup tooling here:
# - https://github.com/actions/?q=setup&type=&language=
# - https://github.com/actions/starter-workflows/tree/main/ci
# - https://github.com/marketplace?type=actions&query=setup
#
# Requires scripts:
# - bin/test

name: <track> / Test
# This workflow creates an Odin environment and runs all tests for all exercises.

name: odin/Test

on:
push:
Expand All @@ -23,17 +10,23 @@ on:

jobs:
ci:
runs-on: <image-name>
runs-on: ubuntu-22.04

steps:
- name: Update packages
run: sudo apt update

- name: Install Clang
run: sudo apt -y install clang

- name: Checkout repository
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332

- name: Use <setup tooling>
uses: <action to setup tooling>

- name: Install project dependencies
run: <install dependencies>
- name: Setup Odin
uses: laytan/setup-odin@41f9612bfec760bbb68b05b5747f319afe7c48d8
with:
token: ${{ secrets.GITHUB_TOKEN }}
llvm-version: 14

- name: Verify all exercises
run: bin/verify-exercises
210 changes: 106 additions & 104 deletions README.md
gvrooyen marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -1,106 +1,108 @@
# Odin

Official Exercism forum thread about this track: https://forum.exercism.org/t/new-track-odin-programming-language/7379

Borring concepts from other C-based/C-adjacent language tracks:
- https://github.com/exercism/c
- https://github.com/exercism/zig

## TODO

- Figure out how to build an Odin test runner (currently using bash script for this)
- [Highlight.js support for Odin](https://github.com/highlightjs/highlight.js/blob/main/SUPPORTED_LANGUAGES.md)

## Odin Docs

- [Odin website](http://odin-lang.org)
- [Odin GitHub](https://github.com/odin-lang/Odin)
- [Odin examples](https://github.com/odin-lang/examples)
- [Odin language server](https://github.com/DanielGavin/ols)

## Exercism Docs

- https://exercism.org/docs/building/tracks/new/request-new
- https://exercism.org/docs/building/tracks/new/add-first-exercise
- https://exercism.org/docs/building/tracks/new/add-initial-exercises
- https://exercism.org/docs/building/tracks/new/setup-continuous-integration
- https://exercism.org/docs/building/tooling/test-runners
- https://github.com/exercism/generic-track
- https://github.com/exercism/problem-specifications

## Example Nix Config

```nix
{ pkgs }:
let
inherit (pkgs) lib;

# TODO: Building odinfmt requires the nighly build of Odin itself
new_pkgs = import
(pkgs.fetchFromGitHub {
owner = "NixOS";
repo = "nixpkgs";
rev = "ef66aec42b5f9035a675496e9a7fe57b63505646";
# sha256 = lib.fakeSha256;
sha256 = "1j1ywwk1wzcd60dbam3pif8z0v695ssmm8g4aw9j01wl36pds31a";
})
{ };

odin = new_pkgs.odin;
in
{
deps = [
odin
pkgs.ruby
pkgs.gh
pkgs.just
pkgs.jq
];
}
```

*Below is the previous generic track readme; will modify later.*

---

# Exercism Odin Track

[![Configlet](https://github.com/exercism/odin/actions/workflows/configlet.yml/badge.svg)](https://github.com/exercism/odin/actions/workflows/configlet.yml) [![.github/workflows/test.yml](https://github.com/exercism/odin/actions/workflows/test.yml/badge.svg)](https://github.com/exercism/odin/actions/workflows/test.yml)

Exercism exercises in Odin.

## Testing

To test the exercises, run `./bin/test`.
This command will iterate over all exercises and check to see if their exemplar/example implementation passes all the tests.

### Track linting

[`configlet`](https://exercism.org/docs/building/configlet) is an Exercism-wide tool for working with tracks. You can download it by running:

```shell
./bin/fetch-configlet
```

Run its [`lint` command](https://exercism.org/docs/building/configlet/lint) to verify if all exercises have all the necessary files and if config files are correct:

```shell
$ ./bin/configlet lint

The lint command is under development.
Please re-run this command regularly to see if your track passes the latest linting rules.

Basic linting finished successfully:
- config.json exists and is valid JSON
- config.json has these valid fields:
language, slug, active, blurb, version, status, online_editor, key_features, tags
- Every concept has the required .md files
- Every concept has a valid links.json file
- Every concept has a valid .meta/config.json file
- Every concept exercise has the required .md files
- Every concept exercise has a valid .meta/config.json file
- Every practice exercise has the required .md files
- Every practice exercise has a valid .meta/config.json file
- Required track docs are present
- Required shared exercise docs are present
```
<br>

Hi. &nbsp;👋🏽 &nbsp;👋 &nbsp;**We are happy you are here.**&nbsp; 🎉&nbsp;🌟

<br>

**`exercism/odin`** is one of many programming language tracks on [Exercism](exercism-website).
This repo holds all the instructions, tests, code, and support files for Odin _exercises_ currently under development or implemented and available for students.

🌟 &nbsp;&nbsp;Track exercises support the `dev-2024-08` release of Odin.

Exercises are grouped into **concept** exercises which teach the Odin syllabus, which will eventually live [here][odin-syllabus], and **practice** exercises, which are unlocked by progressing in the syllabus tree &nbsp;🌴&nbsp;.
Concept exercises are constrained to a small set of language or syntax features.
Practice exercises are open-ended, and can be used to practice concepts learned, try out new techniques, and _play_. These two exercise groupings can be found in the track [config.json][config-json], and under the `odin/exercises` directory.

<br><br>

<div>
<span>
<img align="left" height="60" width="85" src="https://user-images.githubusercontent.com/5923094/204436863-2ebf34d1-4b16-486b-9e0a-add36f4c09c1.svg">
</span>
<span align="left">

🌟🌟&nbsp; Please take a moment to read our [Code of Conduct][exercism-code-of-conduct]&nbsp;🌟🌟&nbsp;
It might also be helpful to look at [Being a Good Community Member][being-a-good-community-member] & [The words that we use][the-words-that-we-use].

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Some defined roles in our community: [Contributors][exercism-contributors] **|** [Mentors][exercism-mentors] **|** [Maintainers][exercism-track-maintainers] **|** [Admins][exercism-admins]

</span></div>

<br>
<img align="left" width="95" height="90" src="https://github.com/exercism/website-icons/blob/main/exercises/boutique-suggestions.svg">

Here to suggest a new feature or new exercise?? **Hooray!** &nbsp;🎉 &nbsp;
We'd love if you did that via our [Exercism Community Forum][exercism-forum] where there is a [dedicated thread][odin-thread] for the new Odin track.
Please read [Suggesting Exercise Improvements][suggesting-improvements] & [Chesterton's Fence][chestertons-fence].
_Thoughtful suggestions will likely result in faster & more enthusiastic responses from volunteers._

<br>
<img align="left" width="85" height="80" src="https://github.com/exercism/website-icons/blob/main/exercises/word-search.svg">

✨&nbsp;🦄&nbsp; _**Want to jump directly into Exercism specifications & detail?**_
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[Structure][exercism-track-structure] **|** [Tasks][exercism-tasks] **|** [Concepts][exercism-concepts] **|** [Concept Exercises][concept-exercises] **|** [Practice Exercises][practice-exercises] **|** [Presentation][exercise-presentation]
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[Writing Style Guide][exercism-writing-style] **|** [Markdown Specification][exercism-markdown-specification] (_✨ version in [contributing][website-contributing-section] on exercism.org_)

<br>
<br>

## Contributing an Exercise
If you are interested in contributing a new exercise, please have a look at [this issue][odin-backlog] to see which exercises are waiting on implementation.
Leave a comment in the issue to notify other contributors which exercise you plan to implement.

The `bin/` subdirectory contains several scripts to help you contribute exercises that will run correctly on Exercism:

- `configlet` is a tool to help track maintainers with the maintenance of their track.
Fetch it by running the `bin/fetch-configlet` script.
Run `bin/configlet lint` to verify that the track is properly structured.
- `bin/fetch-ols-odinfmt.sh` will fetch the Odin language server (`ols`) that can assist with verifying Odin code directly in your IDE.
`odinfmt` is a tool that can format Odin code according to the specification in `odinfmt.json`.
Please run `odinfmt` before pushing your changes to the repository.
whenever new code is pushed to the repository.
- `bin/format-all.sh` will run `odinfmt` on all `.odin` files in the repository.
- `bin/run-test.sh` runs the tests for a specific exercise, or for all exercises if no exercise name is provided.
- `bin/verify-exercises` checks the integrity of all exercises, including tests.
It is used by the build system whenever new code is pushed to the repository.
- `bin/configlet` can be used to generate a new exercise. More details follow below.

### Creating a New Exercise
- Run `bin/configlet create --practice-exercise <slug>` to automatically generate the exercise skeleton in the `exercises/practice/<slug>/` directory and to update `config.json` to reference the new exercise.
You can add `--author <your_exercism_username>` as option to mark yourself as the creator of this exercise (or add it later in the exercise's `.meta/config.json` file.)
- Add a solution stub at the exercise's `<slug>.odin` file.
This is what students will begin with when they start the exercise.
It should make it as easy as possible to understand what they need to solve, without revealing too much of the solution.
Stub functions should usually panic, e.g. `#panic("Please implement the <stub> function.")`.
- Add tests to `<slug>_test.odin`.
Verify that the slug solution would fail _all_ tests.
- Implement a reference solution at `.meta/<slug>_example.odin`.
- Use `bin/run_test.sh <slug>` to verify that your reference solution passes.

[being-a-good-community-member]: https://github.com/exercism/docs/tree/main/community/good-member
[chestertons-fence]: https://github.com/exercism/docs/blob/main/community/good-member/chestertons-fence.md
[concept-exercises]: https://github.com/exercism/docs/blob/main/building/tracks/concept-exercises.md
[config-json]: https://github.com/exercism/odin/blob/main/config.json
[exercise-presentation]: https://github.com/exercism/docs/blob/main/building/tracks/presentation.md
[exercism-admins]: https://github.com/exercism/docs/blob/main/community/administrators.md
[exercism-code-of-conduct]: https://exercism.org/docs/using/legal/code-of-conduct
[exercism-concepts]: https://github.com/exercism/docs/blob/main/building/tracks/concepts.md
[exercism-contributors]: https://github.com/exercism/docs/blob/main/community/contributors.md
[exercism-forum]: https://forum.exercism.org/
[exercism-markdown-specification]: https://github.com/exercism/docs/blob/main/building/markdown/markdown.md
[exercism-mentors]: https://github.com/exercism/docs/tree/main/mentoring
[exercism-tasks]: https://exercism.org/docs/building/product/tasks
[exercism-track-maintainers]: https://github.com/exercism/docs/blob/main/community/maintainers.md
[exercism-track-structure]: https://github.com/exercism/docs/tree/main/building/tracks
[exercism-website]: https://exercism.org/
[exercism-writing-style]: https://github.com/exercism/docs/blob/main/building/markdown/style-guide.md
[freeing-maintainers]: https://exercism.org/blog/freeing-our-maintainers
[practice-exercises]: https://github.com/exercism/docs/blob/main/building/tracks/practice-exercises.md
[prs]: https://github.com/exercism/docs/blob/main/community/good-member/pull-requests.md
[odin-backlog]: https://github.com/exercism/odin/issues/26
[odin-release]: https://github.com/odin-lang/Odin/releases/tag/dev-2024-08
[odin-syllabus]: https://exercism.org/tracks/odin/concepts
[odin-thread]: https://forum.exercism.org/t/new-track-odin-programming-language/7379
[suggesting-improvements]: https://github.com/exercism/docs/blob/main/community/good-member/suggesting-exercise-improvements.md
[the-words-that-we-use]: https://github.com/exercism/docs/blob/main/community/good-member/words.md
[website-contributing-section]: https://exercism.org/docs/building
4 changes: 2 additions & 2 deletions bin/fetch-ols-odinfmt.sh
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#!/bin/bash

# version="refs/heads/master"
version="46892948312c14b44600ae9f557e86bd8c792343"
version="e2f4f96cd46b70360f3caa58acc4af14eb0e8688"
bin_dir="bin"
name="ols"

Expand Down Expand Up @@ -35,4 +35,4 @@ mv odinfmt ..
popd > /dev/null

rm -rf $tarball_dir
rm -f $tarball_path
rm -f $tarball_path
6 changes: 6 additions & 0 deletions bin/format-all.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#!/bin/bash

# Runs `odinfmt` on all .odin files in the current tree.

find . -type f -name "*.odin" -exec odinfmt -w {} \;
echo "All Odin files have been formatted."
6 changes: 3 additions & 3 deletions bin/gen-exercise.sh
Original file line number Diff line number Diff line change
Expand Up @@ -99,8 +99,8 @@ EOL
# Make the example file a simple copy of the solution file
cp ${solution_file} ${example_file}

echo "Formatting new Odin files:"
bin/odinfmt -w ${exercises_path}
# echo "Formatting new Odin files:"
# bin/odinfmt -w ${exercises_path}
gvrooyen marked this conversation as resolved.
Show resolved Hide resolved

echo "Be sure to implement the following files:"
echo -e "\t${solution_file}"
Expand All @@ -110,4 +110,4 @@ EOL

echo "Running configlet lint:"
bin/configlet lint
fi
fi
61 changes: 47 additions & 14 deletions bin/run-test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,12 @@ function run_test() {
meta=".meta"
exercise_name="${1}"
exercise_path="${exercises_path}/${exercise_name}"
tmp_path=`mktemp -d`

echo "$exercise_name / $exercise_path"
gvrooyen marked this conversation as resolved.
Show resolved Hide resolved

if [ -n "${exercise_name}" ] && [ -d "${exercise_path}" ]; then
echo "Running test for exercise: ${exercise_name}"
echo -e "Running test for exercise: ${exercise_name}\n"

# Turn something like "hello-world" into "hello_world"
exercise_safe_name=$(echo $exercise_name | to_snake_case)
Expand All @@ -31,20 +34,42 @@ function run_test() {
# "exercises/practice/.meta/hello_world_example.odin"
example_file="${exercise_path}/${meta}/${exercise_safe_name}_example.odin"

# Move the blank solution file into the meta directory for a bit
mv ${solution_file} ${exercise_path}/${meta}

# Copy the example file into the main directory
cp ${example_file} ${solution_file}

# Run the tests using the example file
odin test ${exercise_path}
# Copy the example file into the temporary directory
cp ${example_file} ${tmp_path}/${exercise_safe_name}.odin

# Unskip all tests and write the processed test file to the temporary directory.
# The test file for the exercise often has several of the tests skippped initially, so that
# students can do test-driven development by enabling the next test, possibly see it fail,
# and then refining their solution. However, the test runner used by contributors and the CI
# pipeline always needs to run all tests.
#
# In Odin, a test can be skipped by commenting out the `@(test)` annotation preceding the
# test procedure. Here we unskip the test by searching for `\\ @(test)` lines and replacing
# them with `@test`.
sed s/"\/\/ @(test)"/"@(test)"/ ${test_file} > ${tmp_path}/${exercise_safe_name}_test.odin

# Move the blank solution file back into the main directory
mv "${exercise_path}/${meta}/${exercise_safe_name}.odin" ${solution_file}
# Run the tests using the example file to verify that it is a valid solution.
odin test ${tmp_path}

echo -e "Checking that the stub solution *fails* the tests\n"

# Copy the stub solution to the temporary directory
cp ${solution_file} ${tmp_path}/${exercise_safe_name}.odin

# Run the test. If it passes, exit with a message and an error.
# TODO: Check that the stub fails _all_ the tests.
# We only check for a single failed test here -- the stub solution could solve all the cases
# but only fail on the most complicated one. Since the purpose of this test is mostly to
# double-check that the example didn't accidentally get duplicated as the stub, this isn't
# too critical for now.

if odin test ${tmp_path} ; then
echo -e '\nERROR: The stub solution must not pass the tests!\n'
exit 1
else
echo -e '\nSUCCESS: The stub solution failed the tests above as expected.\n'
fi

# Remove the built executable
rm -f ${exercise_name}
else
echo "Running all tests"
for exercise in $(ls $exercises_path)
Expand All @@ -54,4 +79,12 @@ function run_test() {
fi
}

run_test $@
# Delete the temp directory
function cleanup {
rm -rf ${tmp_path}
}

# Register the cleanup function to be called on the EXIT signal
trap cleanup EXIT

run_test $@
Loading