diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 00000000..fdd3f45e --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +*.cr text eol=lf \ No newline at end of file diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index cdae9ab7..a8b4f2d0 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -8,60 +8,194 @@ on: env: FORCE_COLOR: 1 - EARTHLY_CI: 'true' - EARTHLY_ALLOW_PRIVILEGED: 'true' + LUCKY_ENV: test jobs: - specs: + check_format: + strategy: + fail-fast: false runs-on: ubuntu-latest + continue-on-error: false steps: - - uses: earthly/actions-setup@v1 + - uses: actions/checkout@v6 + - uses: crystal-lang/install-crystal@v1 with: - version: v0.8.0 - - uses: actions/checkout@v5 - - name: Run build - run: | - earthly +gh-action-essential + crystal: latest + - name: Install shards + run: shards install + - name: Format + run: crystal tool format --check - platform-specs: - needs: specs + platform_specs: + needs: check_format strategy: fail-fast: false matrix: include: - - {os: macos-latest} - - {os: windows-latest} + - { os: ubuntu-latest } + - { os: macos-latest } + - { os: windows-latest } runs-on: ${{matrix.os}} + continue-on-error: false steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - uses: crystal-lang/install-crystal@v1 with: crystal: latest - name: Install shards run: shards install - - name: Run specs - run: crystal spec --tag "~integration" + - name: Run unit and integration specs + run: crystal spec spec/integration/ spec/unit/ - integration-specs: - needs: specs - runs-on: ubuntu-latest + # NOTE: These e2e specs will take a while to run + browser_with_auth: + needs: [check_format, platform_specs] + strategy: + fail-fast: false + matrix: + include: + - { os: ubuntu-latest } + - { os: macos-latest } + # - { os: windows-latest } + runs-on: ${{matrix.os}} + continue-on-error: false steps: - - uses: earthly/actions-setup@v1 + - uses: actions/checkout@v6 + - name: Setup PostgreSQL + uses: ikalnytskyi/action-setup-postgres@v8 + with: + username: postgres + password: postgres + port: 5432 + postgres-version: 18 + - uses: actions/setup-node@v6 with: - version: v0.8.0 - - uses: actions/checkout@v5 - - name: Run build + node-version: 24 + - name: Enable Corepack (for yarn) run: | - earthly +gh-action-integration + corepack enable + corepack prepare yarn@1.22.22 --activate + yarn --version + - uses: crystal-lang/install-crystal@v1 + with: + crystal: latest + - name: Install shards + run: shards install --skip-postinstall --skip-executables + - name: Install LuckyCLI + run: crystal build src/lucky.cr + - name: Add current directory to PATH + run: echo "$PWD" >> "$GITHUB_PATH" + - name: Set SHARDS_OVERRIDE + run: echo "SHARDS_OVERRIDE=${GITHUB_WORKSPACE}/shard.override.yml" >> "$GITHUB_ENV" + - name: Run e2e Browser app with authentication flow + run: crystal spec spec/end_to_end/browser_with_auth_spec.cr - e2e-specs: - needs: integration-specs - runs-on: ubuntu-latest + browser_without_auth: + needs: [check_format, platform_specs] + strategy: + fail-fast: false + matrix: + include: + - { os: ubuntu-latest } + - { os: macos-latest } + # - { os: windows-latest } + runs-on: ${{matrix.os}} + continue-on-error: false steps: - - uses: earthly/actions-setup@v1 + - uses: actions/checkout@v6 + - name: Setup PostgreSQL + uses: ikalnytskyi/action-setup-postgres@v8 with: - version: v0.8.0 - - uses: actions/checkout@v5 - - name: Run build + username: postgres + password: postgres + port: 5432 + postgres-version: 18 + - uses: actions/setup-node@v6 + with: + node-version: 24 + - name: Enable Corepack (for yarn) run: | - earthly +gh-action-e2e + corepack enable + corepack prepare yarn@1.22.22 --activate + yarn --version + - uses: crystal-lang/install-crystal@v1 + with: + crystal: latest + - name: Install shards + run: shards install --skip-postinstall --skip-executables + - name: Install LuckyCLI + run: crystal build src/lucky.cr + - name: Add current directory to PATH + run: echo "$PWD" >> "$GITHUB_PATH" + - name: Set SHARDS_OVERRIDE + run: echo "SHARDS_OVERRIDE=${GITHUB_WORKSPACE}/shard.override.yml" >> "$GITHUB_ENV" + - name: Run e2e Browser app without authentication flow + run: crystal spec spec/end_to_end/browser_no_auth_spec.cr + + api_with_auth: + needs: [check_format, platform_specs] + strategy: + fail-fast: false + matrix: + include: + - { os: ubuntu-latest } + - { os: macos-latest } + # - { os: windows-latest } + runs-on: ${{matrix.os}} + continue-on-error: false + steps: + - uses: actions/checkout@v6 + - name: Setup PostgreSQL + uses: ikalnytskyi/action-setup-postgres@v8 + with: + username: postgres + password: postgres + port: 5432 + postgres-version: 18 + - uses: crystal-lang/install-crystal@v1 + with: + crystal: latest + - name: Install shards + run: shards install --skip-postinstall --skip-executables + - name: Install LuckyCLI + run: crystal build src/lucky.cr + - name: Add current directory to PATH + run: echo "$PWD" >> "$GITHUB_PATH" + - name: Set SHARDS_OVERRIDE + run: echo "SHARDS_OVERRIDE=${GITHUB_WORKSPACE}/shard.override.yml" >> "$GITHUB_ENV" + - name: Run e2e API app with authentication flow + run: crystal spec spec/end_to_end/api_with_auth_spec.cr + + api_without_auth: + needs: [check_format, platform_specs] + strategy: + fail-fast: false + matrix: + include: + - { os: ubuntu-latest } + - { os: macos-latest } + # - { os: windows-latest } + runs-on: ${{matrix.os}} + continue-on-error: false + steps: + - uses: actions/checkout@v6 + - name: Setup PostgreSQL + uses: ikalnytskyi/action-setup-postgres@v8 + with: + username: postgres + password: postgres + port: 5432 + postgres-version: 18 + - uses: crystal-lang/install-crystal@v1 + with: + crystal: latest + - name: Install shards + run: shards install --skip-postinstall --skip-executables + - name: Install LuckyCLI + run: crystal build src/lucky.cr -o lucky + - name: Add current directory to PATH + run: echo "$PWD" >> "$GITHUB_PATH" + - name: Set SHARDS_OVERRIDE + run: echo "SHARDS_OVERRIDE=${GITHUB_WORKSPACE}/shard.override.yml" >> "$GITHUB_ENV" + - name: Run e2e API app without authentication flow + run: crystal spec spec/end_to_end/api_no_auth_spec.cr diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index baad9eb9..e5f89e15 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -17,16 +17,12 @@ jobs: runs-on: ubuntu-latest env: FORCE_COLOR: 1 - EARTHLY_CI: 'true' steps: - - uses: earthly/actions-setup@v1 - with: - version: v0.8.0 - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - name: Build and package run: | mkdir -p bin - earthly --artifact +release-static/lucky ./bin/lucky + # TODO: needs build step sha256sum bin/lucky | awk '{print $1}' > ./bin/checksums.txt tar -czvf lucky-$GITHUB_REF_NAME-linux-amd64.tar.gz -C ./bin . - uses: actions/upload-artifact@v4 @@ -38,7 +34,7 @@ jobs: build-windows-amd64: runs-on: windows-latest steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - uses: crystal-lang/install-crystal@v1 - uses: ilammy/msvc-dev-cmd@v1 - name: Build and package @@ -58,7 +54,7 @@ jobs: - build-windows-amd64 runs-on: ubuntu-latest steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - uses: actions/download-artifact@v4 with: path: artifacts @@ -82,7 +78,7 @@ jobs: needs: release runs-on: ubuntu-latest steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - name: Generate app token id: generate-token uses: actions/create-github-app-token@v2 @@ -108,7 +104,7 @@ jobs: needs: release runs-on: ubuntu-latest steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - name: Generate app token id: generate-token uses: actions/create-github-app-token@v2 diff --git a/.github/workflows/weekly.yml b/.github/workflows/weekly.yml deleted file mode 100644 index ecf22998..00000000 --- a/.github/workflows/weekly.yml +++ /dev/null @@ -1,37 +0,0 @@ -name: Lucky CLI Weekly CI - -on: - schedule: - - cron: "0 1 * * MON" - workflow_dispatch: - -env: - FORCE_COLOR: 1 - EARTHLY_CI: 'true' - EARTHLY_ALLOW_PRIVILEGED: 'true' - -jobs: - integration-specs: - runs-on: ubuntu-latest - steps: - - uses: earthly/actions-setup@v1 - with: - version: v0.8.0 - - uses: actions/checkout@v5 - - name: Run build - run: | - earthly +gh-action-weekly - - e2e-security-specs: - runs-on: ubuntu-latest - steps: - - uses: earthly/actions-setup@v1 - with: - version: v0.8.0 - - uses: actions/checkout@v5 - - name: Run build - run: | - earthly +gh-action-e2e-security - env: - EARTHLY_SECRETS: "BRIGHT_TOKEN=${{ secrets.BRIGHT_API_KEY }},BRIGHT_PROJECT_ID=${{ secrets.BRIGHT_PROJECT_ID }}" - EARTHLY_BUILD_ARGS: "github_ref=${{ github.ref }},github_sha=${{ github.sha }},github_run_id=${{ github.run_id }}" diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 00000000..8e78515a --- /dev/null +++ b/Dockerfile @@ -0,0 +1,94 @@ +FROM crystallang/crystal:latest AS base +WORKDIR /app + +RUN apt-get update \ + && apt-get install -y postgresql-client ca-certificates curl gnupg libnss3 libnss3-dev wget \ + && mkdir -p /etc/apt/keyrings \ + && curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg \ + && echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_20.x nodistro main" | tee /etc/apt/sources.list.d/nodesource.list \ + && apt-get update \ + && apt-get install -y nodejs \ + && npm install --global yarn \ + && wget -O /tmp/google-chrome-stable_current_amd64.deb https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb \ + && apt-get install -y /tmp/google-chrome-stable_current_amd64.deb + +ENV CHROME_BIN=/usr/bin/google-chrome +ENV SHARDS_OVERRIDE=$(pwd)/shard.override.yml + +COPY shard.yml shard.lock ./ +RUN shards install --production + +COPY . . + +FROM base AS build +RUN shards build lucky --without-development + + +FROM build AS e2e_full_web +RUN lucky init.custom test-project +WORKDIR /workdir/test-project +RUN crystal tool format --check src spec config +RUN yarn install --no-progress \ + && yarn dev \ + && shards install +RUN crystal build src/start_server.cr +RUN crystal build src/test_project.cr +RUN crystal run src/app.cr + + +FROM build AS e2e_web_noauth +RUN lucky init.custom test-project --no-auth +WORKDIR /workdir/test-project +RUN yarn install --no-progress \ + && yarn dev \ + && shards install +RUN lucky gen.action.api Api::Users::Show \ + && lucky gen.action.browser Users::Show \ + && lucky gen.migration CreateThings \ + && lucky gen.model User \ + && lucky gen.page Users::IndexPage \ + && lucky gen.component Users::Header \ + && lucky gen.resource.browser Comment title:String \ + && lucky gen.task email.monthly_update \ + && lucky gen.secret_key +RUN crystal tool format --check src spec config +RUN crystal build src/start_server.cr +RUN crystal build src/test_project.cr +RUN crystal run src/app.cr + + +FROM build AS e2e_full_api +RUN lucky init.custom test-project --api +WORKDIR /workdir/test-project +RUN crystal tool format --check src spec config +RUN shards install +RUN crystal build src/start_server.cr +RUN crystal build src/test_project.cr +RUN crystal run src/app.cr + + +FROM build AS e2e_api_noauth +RUN lucky init.custom test-project --api --no-auth +WORKDIR /workdir/test-project +RUN crystal tool format --check src spec config +RUN shards install +RUN crystal build src/start_server.cr +RUN crystal build src/test_project.cr +RUN crystal run src/app.cr + + +FROM build AS e2e_security +ARG github_ref +ARG github_sha +ARG github_run_id +RUN lucky init.custom test-project --with-sec-test +WORKDIR /workdir/test-project +RUN crystal tool format --check src spec config +RUN yarn install --no-progress \ + && yarn dev \ + && shards install +ENV LUCKY_ENV=test +ENV RUN_SEC_TESTER_SPECS=1 +ENV GITHUB_REF=$github_ref +ENV GITHUB_SHA=$github_sha +ENV GITHUB_RUN_ID=$github_run_id diff --git a/Earthfile b/Earthfile deleted file mode 100644 index 928da24d..00000000 --- a/Earthfile +++ /dev/null @@ -1,301 +0,0 @@ -VERSION 0.8 -FROM 84codes/crystal:latest-ubuntu-24.04 -WORKDIR /workdir - -# gh-action-essential runs only the necessary recipes -gh-action-essential: - BUILD +format-check - BUILD +specs - -# gh-action-integration runs all integration specs -gh-action-integration: - BUILD +integration-specs - -# gh-action-e2e runs all end-to-end specs -gh-action-e2e: - BUILD +e2e-full-web-app - BUILD +e2e-full-web-app-noauth - BUILD +e2e-full-web-app-api - BUILD +e2e-full-web-app-api-noauth - -# gh-action-e2e-security runs all security tests (requires secrets) -gh-action-e2e-security: - BUILD +e2e-sec-tester - -# gh-action-weekly runs all weekly tests -gh-action-weekly: - BUILD +weekly-latest-full-web-app - BUILD +weekly-nightly-full-web-app - -# format-check checks the format of source files -format-check: - FROM +base-image - RUN crystal tool format --check src spec - -# specs runs unit tests -specs: - FROM +base-specs-image - RUN crystal spec --tag "~integration" - -# update-snapshot updates spec fixtures -update-snapshot: - FROM +base-specs-image - ARG spec - ENV SPEC_UPDATE_SNAPSHOT=1 - RUN crystal spec --tag "~integration" $spec - SAVE ARTIFACT ./fixtures AS LOCAL ./fixtures - -# lint runs ameba code linter -# lint: -# FROM ghcr.io/crystal-ameba/ameba:1.5.0 -# COPY --dir src ./ -# COPY --dir spec ./ -# RUN ameba - -# integration-specs runs integration tests -integration-specs: - FROM +base-image - COPY +build-lucky/lucky /usr/bin/lucky - COPY fixtures/hello_world.cr fixtures/ - COPY fixtures/hello_crystal.cr bin/lucky.hello_crystal.cr - COPY fixtures/tasks.cr fixtures/ - RUN shards build lucky.hello_world --without-development - RUN crystal spec --tag integration - -# e2e-full-web-app tests lucky full web app -e2e-full-web-app: - FROM earthly/dind:alpine - COPY docker-compose.yml ./ - WITH DOCKER \ - --compose docker-compose.yml \ - --load lucky-image:latest=+e2e-image - RUN docker run --network=host lucky-image:latest - END - -# e2e-full-web-app-noauth tests lucky full web app with no auth -e2e-full-web-app-noauth: - FROM earthly/dind:alpine - COPY docker-compose.yml ./ - WITH DOCKER \ - --compose docker-compose.yml \ - --load lucky-image:latest=+e2e-image-noauth - RUN docker run --network=host lucky-image:latest - END - -# e2e-full-web-app-api tests lucky full web app with api -e2e-full-web-app-api: - FROM earthly/dind:alpine - COPY docker-compose.yml ./ - WITH DOCKER \ - --compose docker-compose.yml \ - --load lucky-image:latest=+e2e-image-api - RUN docker run --network=host lucky-image:latest - END - -# e2e-full-web-app-api-noauth tests lucky full web app with api and no auth -e2e-full-web-app-api-noauth: - FROM earthly/dind:alpine - COPY docker-compose.yml ./ - WITH DOCKER \ - --compose docker-compose.yml \ - --load lucky-image:latest=+e2e-image-api-noauth - RUN docker run --network=host lucky-image:latest - END - -# e2e-sec-tester tests lucky full app with security tester enabled -e2e-sec-tester: - FROM earthly/dind:alpine - COPY docker-compose.yml ./ - WITH DOCKER \ - --compose docker-compose.yml \ - --load lucky-image:latest=+e2e-image-security - RUN --secret BRIGHT_TOKEN --secret BRIGHT_PROJECT_ID -- \ - docker run \ - --network=host \ - -e BRIGHT_TOKEN \ - -e BRIGHT_PROJECT_ID \ - lucky-image:latest - END - -# weekly-latest-full-web-app tests lucky full web app (crystal: latest) for catching potential issues on newer versions of packages -weekly-latest-full-web-app: - FROM earthly/dind:alpine - COPY docker-compose.yml ./ - WITH DOCKER \ - --compose docker-compose.yml \ - --load lucky-image:latest=+weekly-latest-image - RUN docker run --network=host lucky-image:latest - END - -# weekly-nightly-full-web-app tests lucky full web app (crystal: nightly) for more insight into upcoming crystal versions -weekly-nightly-full-web-app: - FROM earthly/dind:alpine - COPY docker-compose.yml ./ - WITH DOCKER \ - --compose docker-compose.yml \ - --load lucky-image:latest=+weekly-nightly-image - RUN docker run --network=host lucky-image:latest - END - -# release-static builds an executable statically linked -release-static: - FROM 84codes/crystal:latest-alpine - WORKDIR /workdir - COPY --dir src ./ - COPY shard.yml ./ - RUN apk add yaml-static - RUN shards build lucky --without-development --no-debug --release --static - SAVE ARTIFACT ./bin/lucky - -build-lucky: - WORKDIR /lucky_cli - COPY --dir src ./ - COPY fixtures/hello_world.cr fixtures/ - COPY shard.yml ./ - RUN shards build lucky --without-development - SAVE ARTIFACT ./bin/lucky - -base-image: - COPY --dir src ./ - COPY --dir spec ./ - COPY shard.yml ./ - -base-specs-image: - FROM +base-image - COPY --dir fixtures ./ - RUN shards install - -e2e-base-image: - COPY shard.override.yml ./ - RUN apt-get update \ - && apt-get install -y postgresql-client ca-certificates curl gnupg libnss3 libnss3-dev wget \ - && mkdir -p /etc/apt/keyrings \ - && curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg \ - && echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_20.x nodistro main" | tee /etc/apt/sources.list.d/nodesource.list \ - && apt-get update \ - && apt-get install -y nodejs \ - && npm install --global yarn \ - && wget -O /tmp/google-chrome-stable_current_amd64.deb https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb \ - && apt-get install -y /tmp/google-chrome-stable_current_amd64.deb - ENV CHROME_BIN=/usr/bin/google-chrome - ENV SHARDS_OVERRIDE=$(pwd)/shard.override.yml - COPY +build-lucky/lucky /usr/bin/lucky - -e2e-image: - FROM +e2e-base-image - RUN lucky init.custom test-project - WORKDIR /workdir/test-project - RUN crystal tool format --check src spec config - RUN yarn install --no-progress \ - && yarn dev \ - && shards install - RUN crystal build src/start_server.cr - RUN crystal build src/test_project.cr - RUN crystal run src/app.cr - ENTRYPOINT ["crystal", "spec"] - SAVE IMAGE lucky-image:base - -e2e-image-noauth: - FROM +e2e-base-image - RUN lucky init.custom test-project --no-auth - WORKDIR /workdir/test-project - RUN yarn install --no-progress \ - && yarn dev \ - && shards install - RUN lucky gen.action.api Api::Users::Show \ - && lucky gen.action.browser Users::Show \ - && lucky gen.migration CreateThings \ - && lucky gen.model User \ - && lucky gen.page Users::IndexPage \ - && lucky gen.component Users::Header \ - && lucky gen.resource.browser Comment title:String \ - && lucky gen.task email.monthly_update \ - && lucky gen.secret_key - RUN crystal tool format --check src spec config - RUN crystal build src/start_server.cr - RUN crystal build src/test_project.cr - RUN crystal run src/app.cr - ENTRYPOINT ["crystal", "spec"] - SAVE IMAGE lucky-image:noauth - -e2e-image-api: - FROM +e2e-base-image - RUN lucky init.custom test-project --api - WORKDIR /workdir/test-project - RUN crystal tool format --check src spec config - RUN shards install - RUN crystal build src/start_server.cr - RUN crystal build src/test_project.cr - RUN crystal run src/app.cr - ENTRYPOINT ["crystal", "spec"] - SAVE IMAGE lucky-image:api - -e2e-image-api-noauth: - FROM +e2e-base-image - RUN lucky init.custom test-project --api --no-auth - WORKDIR /workdir/test-project - RUN crystal tool format --check src spec config - RUN shards install - RUN crystal build src/start_server.cr - RUN crystal build src/test_project.cr - RUN crystal run src/app.cr - ENTRYPOINT ["crystal", "spec"] - SAVE IMAGE lucky-image:api-noauth - -e2e-image-security: - FROM +e2e-base-image - ARG github_ref - ARG github_sha - ARG github_run_id - RUN lucky init.custom test-project --with-sec-test - WORKDIR /workdir/test-project - RUN crystal tool format --check src spec config - RUN yarn install --no-progress \ - && yarn dev \ - && shards install - ENV LUCKY_ENV=test - ENV RUN_SEC_TESTER_SPECS=1 - ENV GITHUB_REF=$github_ref - ENV GITHUB_SHA=$github_sha - ENV GITHUB_RUN_ID=$github_run_id - ENTRYPOINT ["crystal", "spec", "-Dwith_sec_tests"] - SAVE IMAGE lucky-image:security - -weekly-latest-image: - FROM 84codes/crystal:latest-ubuntu-24.04 - DO +WEEKLY_IMAGE --shard_file=shard.edge.yml - SAVE IMAGE lucky-image:weekly-latest - -weekly-nightly-image: - FROM 84codes/crystal:master-ubuntu-24.04 - DO +WEEKLY_IMAGE --shard_file=shard.override.yml - SAVE IMAGE lucky-image:weekly-nightly - -WEEKLY_IMAGE: - COMMAND - ARG shard_file - WORKDIR /workdir - RUN apt-get update \ - && apt-get install -y postgresql-client ca-certificates curl gnupg libnss3 libnss3-dev wget \ - && mkdir -p /etc/apt/keyrings \ - && curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg \ - && echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_20.x nodistro main" | tee /etc/apt/sources.list.d/nodesource.list \ - && apt-get update \ - && apt-get install -y nodejs \ - && npm install --global yarn \ - && wget -O /tmp/google-chrome-stable_current_amd64.deb https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb \ - && apt-get install -y /tmp/google-chrome-stable_current_amd64.deb - ENV CHROME_BIN=/usr/bin/google-chrome - COPY +build-lucky/lucky /usr/bin/lucky - RUN lucky init.custom test-project - WORKDIR /workdir/test-project - COPY $shard_file ./ - ENV SHARDS_OVERRIDE=/workdir/test-project/$shard_file - RUN crystal tool format --check src spec config - RUN yarn install --no-progress \ - && yarn dev \ - && shards install - RUN crystal build src/start_server.cr - RUN crystal build src/test_project.cr - RUN crystal run src/app.cr - ENTRYPOINT ["crystal", "spec"] diff --git a/docker-compose.yml b/docker-compose.yml index d919ffca..19844c51 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,18 +1,40 @@ -version: '3' - services: - postgres: - image: postgres:16 - restart: always + db: + image: postgres:16-alpine environment: - POSTGRES_USER: postgres - POSTGRES_PASSWORD: postgres - TZ: "UTC" + POSTGRES_USER: lucky + POSTGRES_PASSWORD: developer + volumes: + - db:/var/lib/postgresql + networks: + - internal ports: - - 5432:5432 - hostname: postgres + - 5432 healthcheck: test: ["CMD", "pg_isready"] interval: 10s timeout: 5s retries: 5 + + app: + build: + context: . + dockerfile: Dockerfile + environment: + SHARDS_CACHE_PATH: /data/.shards + DB_HOST: db + DB_USERNAME: lucky + DB_PASSWORD: developer + volumes: + - .:/data + command: sleep infinity + depends_on: + - db + networks: + - internal + +volumes: + db: + +networks: + internal: diff --git a/fixtures/api_authentication_template/expected/spec/requests/api/me/show_spec.cr b/fixtures/api_authentication_template/expected/spec/requests/api/me/show_spec.cr deleted file mode 100644 index 0e1f91fe..00000000 --- a/fixtures/api_authentication_template/expected/spec/requests/api/me/show_spec.cr +++ /dev/null @@ -1,17 +0,0 @@ -require "../../../spec_helper" - -describe Api::Me::Show do - it "returns the signed in user" do - user = UserFactory.create - - response = ApiClient.auth(user).exec(Api::Me::Show) - - response.should send_json(200, email: user.email) - end - - it "fails if not authenticated" do - response = ApiClient.exec(Api::Me::Show) - - response.status_code.should eq(401) - end -end diff --git a/fixtures/api_authentication_template/expected/spec/requests/api/sign_ins/create_spec.cr b/fixtures/api_authentication_template/expected/spec/requests/api/sign_ins/create_spec.cr deleted file mode 100644 index 520c2dff..00000000 --- a/fixtures/api_authentication_template/expected/spec/requests/api/sign_ins/create_spec.cr +++ /dev/null @@ -1,33 +0,0 @@ -require "../../../spec_helper" - -describe Api::SignIns::Create do - it "returns a token" do - UserToken.stub_token("fake-token") do - user = UserFactory.create - - response = ApiClient.exec(Api::SignIns::Create, user: valid_params(user)) - - response.should send_json(200, token: "fake-token") - end - end - - it "returns an error if credentials are invalid" do - user = UserFactory.create - invalid_params = valid_params(user).merge(password: "incorrect") - - response = ApiClient.exec(Api::SignIns::Create, user: invalid_params) - - response.should send_json( - 400, - param: "password", - details: "password is wrong" - ) - end -end - -private def valid_params(user : User) - { - email: user.email, - password: "password", - } -end diff --git a/fixtures/api_authentication_template/expected/spec/requests/api/sign_ups/create_spec.cr b/fixtures/api_authentication_template/expected/spec/requests/api/sign_ups/create_spec.cr deleted file mode 100644 index 2a23542e..00000000 --- a/fixtures/api_authentication_template/expected/spec/requests/api/sign_ups/create_spec.cr +++ /dev/null @@ -1,34 +0,0 @@ -require "../../../spec_helper" - -describe Api::SignUps::Create do - it "creates user on sign up" do - UserToken.stub_token("fake-token") do - response = ApiClient.exec(Api::SignUps::Create, user: valid_params) - - response.should send_json(200, token: "fake-token") - new_user = UserQuery.first - new_user.email.should eq(valid_params[:email]) - end - end - - it "returns error for invalid params" do - invalid_params = valid_params.merge(password_confirmation: "wrong") - - response = ApiClient.exec(Api::SignUps::Create, user: invalid_params) - - UserQuery.new.select_count.should eq(0) - response.should send_json( - 400, - param: "password_confirmation", - details: "password_confirmation must match" - ) - end -end - -private def valid_params - { - email: "test@email.com", - password: "password", - password_confirmation: "password", - } -end diff --git a/fixtures/api_authentication_template/expected/src/actions/api/me/show.cr b/fixtures/api_authentication_template/expected/src/actions/api/me/show.cr deleted file mode 100644 index 00602713..00000000 --- a/fixtures/api_authentication_template/expected/src/actions/api/me/show.cr +++ /dev/null @@ -1,5 +0,0 @@ -class Api::Me::Show < ApiAction - get "/api/me" do - json UserSerializer.new(current_user) - end -end diff --git a/fixtures/api_authentication_template/expected/src/actions/api/sign_ins/create.cr b/fixtures/api_authentication_template/expected/src/actions/api/sign_ins/create.cr deleted file mode 100644 index 3670356c..00000000 --- a/fixtures/api_authentication_template/expected/src/actions/api/sign_ins/create.cr +++ /dev/null @@ -1,13 +0,0 @@ -class Api::SignIns::Create < ApiAction - include Api::Auth::SkipRequireAuthToken - - post "/api/sign_ins" do - SignInUser.run(params) do |operation, user| - if user - json({token: UserToken.generate(user)}) - else - raise Avram::InvalidOperationError.new(operation) - end - end - end -end diff --git a/fixtures/api_authentication_template/expected/src/actions/api/sign_ups/create.cr b/fixtures/api_authentication_template/expected/src/actions/api/sign_ups/create.cr deleted file mode 100644 index 15bbd04b..00000000 --- a/fixtures/api_authentication_template/expected/src/actions/api/sign_ups/create.cr +++ /dev/null @@ -1,8 +0,0 @@ -class Api::SignUps::Create < ApiAction - include Api::Auth::SkipRequireAuthToken - - post "/api/sign_ups" do - user = SignUpUser.create!(params) - json({token: UserToken.generate(user)}) - end -end diff --git a/fixtures/api_authentication_template/expected/src/actions/mixins/api/auth/helpers.cr b/fixtures/api_authentication_template/expected/src/actions/mixins/api/auth/helpers.cr deleted file mode 100644 index 6b51cb5a..00000000 --- a/fixtures/api_authentication_template/expected/src/actions/mixins/api/auth/helpers.cr +++ /dev/null @@ -1,28 +0,0 @@ -module Api::Auth::Helpers - # The 'memoize' macro makes sure only one query is issued to find the user - memoize def current_user? : User? - auth_token.try do |value| - user_from_auth_token(value) - end - end - - private def auth_token : String? - bearer_token || token_param - end - - private def bearer_token : String? - context.request.headers["Authorization"]? - .try(&.gsub("Bearer", "")) - .try(&.strip) - end - - private def token_param : String? - params.get?(:auth_token) - end - - private def user_from_auth_token(token : String) : User? - UserToken.decode_user_id(token).try do |user_id| - UserQuery.new.id(user_id).first? - end - end -end diff --git a/fixtures/api_authentication_template/expected/src/actions/mixins/api/auth/require_auth_token.cr b/fixtures/api_authentication_template/expected/src/actions/mixins/api/auth/require_auth_token.cr deleted file mode 100644 index e018638f..00000000 --- a/fixtures/api_authentication_template/expected/src/actions/mixins/api/auth/require_auth_token.cr +++ /dev/null @@ -1,34 +0,0 @@ -module Api::Auth::RequireAuthToken - macro included - before require_auth_token - end - - private def require_auth_token - if current_user? - continue - else - json auth_error_json, 401 - end - end - - private def auth_error_json - ErrorSerializer.new( - message: "Not authenticated.", - details: auth_error_details - ) - end - - private def auth_error_details : String - if auth_token - "The provided authentication token was incorrect." - else - "An authentication token is required. Please include a token in an 'auth_token' param or 'Authorization' header." - end - end - - # Tells the compiler that the current_user is not nil since we have checked - # that the user is signed in - private def current_user : User - current_user?.as(User) - end -end diff --git a/fixtures/api_authentication_template/expected/src/actions/mixins/api/auth/skip_require_auth_token.cr b/fixtures/api_authentication_template/expected/src/actions/mixins/api/auth/skip_require_auth_token.cr deleted file mode 100644 index 68098cf5..00000000 --- a/fixtures/api_authentication_template/expected/src/actions/mixins/api/auth/skip_require_auth_token.cr +++ /dev/null @@ -1,10 +0,0 @@ -module Api::Auth::SkipRequireAuthToken - macro included - skip require_auth_token - end - - # Since sign in is not required, current_user might be nil - def current_user : User? - current_user? - end -end diff --git a/fixtures/api_authentication_template/expected/src/models/user_token.cr b/fixtures/api_authentication_template/expected/src/models/user_token.cr deleted file mode 100644 index 65863032..00000000 --- a/fixtures/api_authentication_template/expected/src/models/user_token.cr +++ /dev/null @@ -1,30 +0,0 @@ -# Generates and decodes JSON Web Tokens for Authenticating users. -class UserToken - Habitat.create { setting stubbed_token : String? } - ALGORITHM = JWT::Algorithm::HS256 - - def self.generate(user : User) : String - payload = {"user_id" => user.id} - - settings.stubbed_token || create_token(payload) - end - - def self.create_token(payload) - JWT.encode(payload, Lucky::Server.settings.secret_key_base, ALGORITHM) - end - - def self.decode_user_id(token : String) : Int64? - payload, _header = JWT.decode(token, Lucky::Server.settings.secret_key_base, ALGORITHM) - payload["user_id"].to_s.to_i64 - rescue e : JWT::Error - Lucky::Log.dexter.error { {jwt_decode_error: e.message} } - nil - end - - # Used in tests to return a fake token to test against. - def self.stub_token(token : String, &) - temp_config(stubbed_token: token) do - yield - end - end -end diff --git a/fixtures/api_authentication_template/expected/src/serializers/user_serializer.cr b/fixtures/api_authentication_template/expected/src/serializers/user_serializer.cr deleted file mode 100644 index 1a86f14a..00000000 --- a/fixtures/api_authentication_template/expected/src/serializers/user_serializer.cr +++ /dev/null @@ -1,8 +0,0 @@ -class UserSerializer < BaseSerializer - def initialize(@user : User) - end - - def render - {email: @user.email} - end -end diff --git a/fixtures/app_sec_tester_template/expected/spec/flows/security_spec.cr b/fixtures/app_sec_tester_template/expected/spec/flows/security_spec.cr deleted file mode 100644 index 386a7d8c..00000000 --- a/fixtures/app_sec_tester_template/expected/spec/flows/security_spec.cr +++ /dev/null @@ -1,80 +0,0 @@ -{% skip_file unless flag?(:with_sec_tests) %} -# Run these specs with `crystal spec -Dwith_sec_tests` - -require "../spec_helper" - -describe "SecTester" do - it "tests the sign_in" do - scanner = LuckySecTester.new - target = scanner.build_target(SignIns::New) - scanner.run_check( - scan_name: "ref: #{ENV["GITHUB_REF"]?} commit: #{ENV["GITHUB_SHA"]?} run id: #{ENV["GITHUB_RUN_ID"]?}", - tests: [ - "xss", # Testing for XSS Injection issues (https://docs.brightsec.com/docs/reflective-cross-site-scripting-rxss) - "brute_force_login", # Testing for Brute Force on the Login (https://docs.brightsec.com/docs/brute-force-login) - ], - target: target - ) - end - - it "tests the sign_in action with params" do - scanner = LuckySecTester.new - target = scanner.build_target(SignIns::Create) do |request| - request.body = "user%3Aemail=test%40test.com&user%3Apassword=1234" - end - scanner.run_check( - scan_name: "ref: #{ENV["GITHUB_REF"]?} commit: #{ENV["GITHUB_SHA"]?} run id: #{ENV["GITHUB_RUN_ID"]?}", - tests: [ - "sqli", # Testing for SQL Injection issues (https://docs.brightsec.com/docs/sql-injection) - "xss", # Testing for XSS Injection issues (https://docs.brightsec.com/docs/reflective-cross-site-scripting-rxss) - "mass_assignment", # Testing for Mass Assignment (https://docs.brightsec.com/docs/mass-assignment) - ], - target: target - ) - end - - it "tests the sign_up action" do - scanner = LuckySecTester.new - target = scanner.build_target(SignUps::Create) do |request| - request.body = "user%3Aemail=aa%40aa.com&user%3Apassword=123456789&user%3Apassword_confirmation=123456789" - end - scanner.run_check( - scan_name: "ref: #{ENV["GITHUB_REF"]?} commit: #{ENV["GITHUB_SHA"]?} run id: #{ENV["GITHUB_RUN_ID"]?}", - tests: [ - "sqli", # Testing for SQL Injection issues (https://docs.brightsec.com/docs/sql-injection) - "xss", # Testing for XSS Injection issues (https://docs.brightsec.com/docs/reflective-cross-site-scripting-rxss) - "mass_assignment", # Testing for Mass Assignment issues (https://docs.brightsec.com/docs/mass-assignment) - "full_path_disclosure", # Testing for full path disclourse on api error (https://docs.brightsec.com/docs/full-path-disclosure) - ], - target: target - ) - end - it "tests the home page general infra issues" do - scanner = LuckySecTester.new - target = scanner.build_target(Home::Index) - scanner.run_check( - scan_name: "ref: #{ENV["GITHUB_REF"]?} commit: #{ENV["GITHUB_SHA"]?} run id: #{ENV["GITHUB_RUN_ID"]?}", - severity_threshold: SecTester::Severity::Medium, - tests: [ - "header_security", # Testing for header security issues (https://docs.brightsec.com/docs/misconfigured-security-headers) - "cookie_security", # Testing for Cookie Security issues (https://docs.brightsec.com/docs/sensitive-cookie-in-https-session-without-secure-attribute) - "proto_pollution", # Testing for proto pollution based vulnerabilities (https://docs.brightsec.com/docs/prototype-pollution) - "open_buckets", # Testing for open buckets (https://docs.brightsec.com/docs/open-bucket) - ], - target: target - ) - end - - it "tests app.js for 3rd party issues" do - scanner = LuckySecTester.new - target = SecTester::Target.new(Lucky::RouteHelper.settings.base_uri + Lucky::AssetHelpers.asset("js/app.js")) - scanner.run_check( - scan_name: "ref: #{ENV["GITHUB_REF"]?} commit: #{ENV["GITHUB_SHA"]?} run id: #{ENV["GITHUB_RUN_ID"]?}", - tests: [ - "retire_js", # Testing for 3rd party issues (https://docs.brightsec.com/docs/javascript-component-with-known-vulnerabilities) - "cve_test", # Testing for known CVEs (https://docs.brightsec.com/docs/cves) - ], - target: target - ) - end -end diff --git a/fixtures/app_sec_tester_template/expected/spec/setup/sec_tester.cr b/fixtures/app_sec_tester_template/expected/spec/setup/sec_tester.cr deleted file mode 100644 index 850a1291..00000000 --- a/fixtures/app_sec_tester_template/expected/spec/setup/sec_tester.cr +++ /dev/null @@ -1,9 +0,0 @@ -require "lucky_sec_tester" - -# Signup for a `BRIGHT_TOKEN` at -# [Bright Security](https://app.neuralegion.com/signup) -# Read more about the SecTester on https://github.com/luckyframework/lucky_sec_tester -LuckySecTester.configure do |setting| - setting.bright_token = ENV["BRIGHT_TOKEN"] - setting.project_id = ENV["BRIGHT_PROJECT_ID"] -end diff --git a/fixtures/app_sec_tester_template__browser/expected/spec/flows/security_spec.cr b/fixtures/app_sec_tester_template__browser/expected/spec/flows/security_spec.cr deleted file mode 100644 index 6447f45d..00000000 --- a/fixtures/app_sec_tester_template__browser/expected/spec/flows/security_spec.cr +++ /dev/null @@ -1,35 +0,0 @@ -{% skip_file unless flag?(:with_sec_tests) %} -# Run these specs with `crystal spec -Dwith_sec_tests` - -require "../spec_helper" - -describe "SecTester" do - it "tests the home page general infra issues" do - scanner = LuckySecTester.new - target = scanner.build_target(Home::Index) - scanner.run_check( - scan_name: "ref: #{ENV["GITHUB_REF"]?} commit: #{ENV["GITHUB_SHA"]?} run id: #{ENV["GITHUB_RUN_ID"]?}", - severity_threshold: SecTester::Severity::Medium, - tests: [ - "header_security", # Testing for header security issues (https://docs.brightsec.com/docs/misconfigured-security-headers) - "cookie_security", # Testing for Cookie Security issues (https://docs.brightsec.com/docs/sensitive-cookie-in-https-session-without-secure-attribute) - "proto_pollution", # Testing for proto pollution based vulnerabilities (https://docs.brightsec.com/docs/prototype-pollution) - "open_buckets", # Testing for open buckets (https://docs.brightsec.com/docs/open-bucket) - ], - target: target - ) - end - - it "tests app.js for 3rd party issues" do - scanner = LuckySecTester.new - target = SecTester::Target.new(Lucky::RouteHelper.settings.base_uri + Lucky::AssetHelpers.asset("js/app.js")) - scanner.run_check( - scan_name: "ref: #{ENV["GITHUB_REF"]?} commit: #{ENV["GITHUB_SHA"]?} run id: #{ENV["GITHUB_RUN_ID"]?}", - tests: [ - "retire_js", # Testing for 3rd party issues (https://docs.brightsec.com/docs/javascript-component-with-known-vulnerabilities) - "cve_test", # Testing for known CVEs (https://docs.brightsec.com/docs/cves) - ], - target: target - ) - end -end diff --git a/fixtures/app_sec_tester_template__browser/expected/spec/setup/sec_tester.cr b/fixtures/app_sec_tester_template__browser/expected/spec/setup/sec_tester.cr deleted file mode 100644 index 850a1291..00000000 --- a/fixtures/app_sec_tester_template__browser/expected/spec/setup/sec_tester.cr +++ /dev/null @@ -1,9 +0,0 @@ -require "lucky_sec_tester" - -# Signup for a `BRIGHT_TOKEN` at -# [Bright Security](https://app.neuralegion.com/signup) -# Read more about the SecTester on https://github.com/luckyframework/lucky_sec_tester -LuckySecTester.configure do |setting| - setting.bright_token = ENV["BRIGHT_TOKEN"] - setting.project_id = ENV["BRIGHT_PROJECT_ID"] -end diff --git a/fixtures/app_sec_tester_template__generate_auth/expected/spec/flows/security_spec.cr b/fixtures/app_sec_tester_template__generate_auth/expected/spec/flows/security_spec.cr deleted file mode 100644 index 76dcf49c..00000000 --- a/fixtures/app_sec_tester_template__generate_auth/expected/spec/flows/security_spec.cr +++ /dev/null @@ -1,26 +0,0 @@ -{% skip_file unless flag?(:with_sec_tests) %} -# Run these specs with `crystal spec -Dwith_sec_tests` - -require "../spec_helper" - -describe "SecTester" do - it "tests the sign_in API for SQLi, and JWT attacks" do - scanner = LuckySecTester.new - api_headers = HTTP::Headers{"Content-Type" => "application/json", "Accept" => "application/json"} - target = scanner.build_target(Api::SignIns::Create, headers: api_headers) do |request| - request.body = {"user" => {"email" => "aa@aa.com", "password" => "123456789"}}.to_json - end - scanner.run_check( - scan_name: "ref: #{ENV["GITHUB_REF"]?} commit: #{ENV["GITHUB_SHA"]?} run id: #{ENV["GITHUB_RUN_ID"]?}", - tests: [ - "sqli", # Testing for SQL Injection issues (https://docs.brightsec.com/docs/sql-injection) - "jwt", # Testing JWT usage (https://docs.brightsec.com/docs/broken-jwt-authentication) - "xss", # Testing for Cross Site Scripting attacks (https://docs.brightsec.com/docs/reflective-cross-site-scripting-rxss) - "ssrf", # Testing for SSRF (https://docs.brightsec.com/docs/server-side-request-forgery-ssrf) - "mass_assignment", # Testing for Mass Assignment issues (https://docs.brightsec.com/docs/mass-assignment) - "full_path_disclosure", # Testing for full path disclourse on api error (https://docs.brightsec.com/docs/full-path-disclosure) - ], - target: target - ) - end -end diff --git a/fixtures/app_sec_tester_template__generate_auth/expected/spec/setup/sec_tester.cr b/fixtures/app_sec_tester_template__generate_auth/expected/spec/setup/sec_tester.cr deleted file mode 100644 index 850a1291..00000000 --- a/fixtures/app_sec_tester_template__generate_auth/expected/spec/setup/sec_tester.cr +++ /dev/null @@ -1,9 +0,0 @@ -require "lucky_sec_tester" - -# Signup for a `BRIGHT_TOKEN` at -# [Bright Security](https://app.neuralegion.com/signup) -# Read more about the SecTester on https://github.com/luckyframework/lucky_sec_tester -LuckySecTester.configure do |setting| - setting.bright_token = ENV["BRIGHT_TOKEN"] - setting.project_id = ENV["BRIGHT_PROJECT_ID"] -end diff --git a/fixtures/app_sec_tester_template__no_browser_auth/expected/spec/flows/security_spec.cr b/fixtures/app_sec_tester_template__no_browser_auth/expected/spec/flows/security_spec.cr deleted file mode 100644 index e5a8aace..00000000 --- a/fixtures/app_sec_tester_template__no_browser_auth/expected/spec/flows/security_spec.cr +++ /dev/null @@ -1,7 +0,0 @@ -{% skip_file unless flag?(:with_sec_tests) %} -# Run these specs with `crystal spec -Dwith_sec_tests` - -require "../spec_helper" - -describe "SecTester" do -end diff --git a/fixtures/app_sec_tester_template__no_browser_auth/expected/spec/setup/sec_tester.cr b/fixtures/app_sec_tester_template__no_browser_auth/expected/spec/setup/sec_tester.cr deleted file mode 100644 index 850a1291..00000000 --- a/fixtures/app_sec_tester_template__no_browser_auth/expected/spec/setup/sec_tester.cr +++ /dev/null @@ -1,9 +0,0 @@ -require "lucky_sec_tester" - -# Signup for a `BRIGHT_TOKEN` at -# [Bright Security](https://app.neuralegion.com/signup) -# Read more about the SecTester on https://github.com/luckyframework/lucky_sec_tester -LuckySecTester.configure do |setting| - setting.bright_token = ENV["BRIGHT_TOKEN"] - setting.project_id = ENV["BRIGHT_PROJECT_ID"] -end diff --git a/fixtures/base_authentication_src_template/expected/config/authentic.cr b/fixtures/base_authentication_src_template/expected/config/authentic.cr deleted file mode 100644 index b9efc318..00000000 --- a/fixtures/base_authentication_src_template/expected/config/authentic.cr +++ /dev/null @@ -1,11 +0,0 @@ -require "./server" - -Authentic.configure do |settings| - settings.secret_key = Lucky::Server.settings.secret_key_base - - unless LuckyEnv.production? - # This value can be between 4 and 31 - fastest_encryption_possible = 4 - settings.encryption_cost = fastest_encryption_possible - end -end diff --git a/fixtures/base_authentication_src_template/expected/db/migrations/.keep b/fixtures/base_authentication_src_template/expected/db/migrations/.keep deleted file mode 100644 index e69de29b..00000000 diff --git a/fixtures/base_authentication_src_template/expected/db/migrations/00000000000001_create_users.cr b/fixtures/base_authentication_src_template/expected/db/migrations/00000000000001_create_users.cr deleted file mode 100644 index 96283bfa..00000000 --- a/fixtures/base_authentication_src_template/expected/db/migrations/00000000000001_create_users.cr +++ /dev/null @@ -1,17 +0,0 @@ -class CreateUsers::V00000000000001 < Avram::Migrator::Migration::V1 - def migrate - enable_extension "citext" - - create table_for(User) do - primary_key id : Int64 - add_timestamps - add email : String, unique: true, case_sensitive: false - add encrypted_password : String - end - end - - def rollback - drop table_for(User) - disable_extension "citext" - end -end diff --git a/fixtures/base_authentication_src_template/expected/spec/support/.keep b/fixtures/base_authentication_src_template/expected/spec/support/.keep deleted file mode 100644 index e69de29b..00000000 diff --git a/fixtures/base_authentication_src_template/expected/spec/support/factories/user_factory.cr b/fixtures/base_authentication_src_template/expected/spec/support/factories/user_factory.cr deleted file mode 100644 index bb837ee1..00000000 --- a/fixtures/base_authentication_src_template/expected/spec/support/factories/user_factory.cr +++ /dev/null @@ -1,6 +0,0 @@ -class UserFactory < Avram::Factory - def initialize - email "#{sequence("test-email")}@example.com" - encrypted_password Authentic.generate_encrypted_password("password") - end -end diff --git a/fixtures/base_authentication_src_template/expected/src/models/user.cr b/fixtures/base_authentication_src_template/expected/src/models/user.cr deleted file mode 100644 index 39729bb2..00000000 --- a/fixtures/base_authentication_src_template/expected/src/models/user.cr +++ /dev/null @@ -1,13 +0,0 @@ -class User < BaseModel - include Carbon::Emailable - include Authentic::PasswordAuthenticatable - - table do - column email : String - column encrypted_password : String - end - - def emailable : Carbon::Address - Carbon::Address.new(email) - end -end diff --git a/fixtures/base_authentication_src_template/expected/src/operations/.keep b/fixtures/base_authentication_src_template/expected/src/operations/.keep deleted file mode 100644 index e69de29b..00000000 diff --git a/fixtures/base_authentication_src_template/expected/src/operations/mixins/.keep b/fixtures/base_authentication_src_template/expected/src/operations/mixins/.keep deleted file mode 100644 index e69de29b..00000000 diff --git a/fixtures/base_authentication_src_template/expected/src/operations/mixins/password_validations.cr b/fixtures/base_authentication_src_template/expected/src/operations/mixins/password_validations.cr deleted file mode 100644 index c56b9750..00000000 --- a/fixtures/base_authentication_src_template/expected/src/operations/mixins/password_validations.cr +++ /dev/null @@ -1,12 +0,0 @@ -module PasswordValidations - macro included - before_save run_password_validations - end - - private def run_password_validations - validate_required password, password_confirmation - validate_confirmation_of password, with: password_confirmation - # 72 is a limitation of BCrypt - validate_size_of password, min: 6, max: 72 - end -end diff --git a/fixtures/base_authentication_src_template/expected/src/operations/mixins/user_from_email.cr b/fixtures/base_authentication_src_template/expected/src/operations/mixins/user_from_email.cr deleted file mode 100644 index 862fa9ac..00000000 --- a/fixtures/base_authentication_src_template/expected/src/operations/mixins/user_from_email.cr +++ /dev/null @@ -1,7 +0,0 @@ -module UserFromEmail - private def user_from_email : User? - email.value.try do |value| - UserQuery.new.email(value).first? - end - end -end diff --git a/fixtures/base_authentication_src_template/expected/src/operations/request_password_reset.cr b/fixtures/base_authentication_src_template/expected/src/operations/request_password_reset.cr deleted file mode 100644 index 4941aa7f..00000000 --- a/fixtures/base_authentication_src_template/expected/src/operations/request_password_reset.cr +++ /dev/null @@ -1,25 +0,0 @@ -class RequestPasswordReset < Avram::Operation - # You can modify this in src/operations/mixins/user_from_email.cr - include UserFromEmail - - attribute email : String - - # Run validations and yield the operation and the user if valid - def run - user = user_from_email - validate(user) - - if valid? - user - else - nil - end - end - - def validate(user : User?) - validate_required email - if user.nil? - email.add_error "is not in our system" - end - end -end diff --git a/fixtures/base_authentication_src_template/expected/src/operations/reset_password.cr b/fixtures/base_authentication_src_template/expected/src/operations/reset_password.cr deleted file mode 100644 index 3bdd3c89..00000000 --- a/fixtures/base_authentication_src_template/expected/src/operations/reset_password.cr +++ /dev/null @@ -1,11 +0,0 @@ -class ResetPassword < User::SaveOperation - # Change password validations in src/operations/mixins/password_validations.cr - include PasswordValidations - - attribute password : String - attribute password_confirmation : String - - before_save do - Authentic.copy_and_encrypt password, to: encrypted_password - end -end diff --git a/fixtures/base_authentication_src_template/expected/src/operations/sign_in_user.cr b/fixtures/base_authentication_src_template/expected/src/operations/sign_in_user.cr deleted file mode 100644 index de80342e..00000000 --- a/fixtures/base_authentication_src_template/expected/src/operations/sign_in_user.cr +++ /dev/null @@ -1,40 +0,0 @@ -class SignInUser < Avram::Operation - param_key :user - # You can modify this in src/operations/mixins/user_from_email.cr - include UserFromEmail - - attribute email : String - attribute password : String - - # Run validations and yields the operation and the user if valid - def run - user = user_from_email - validate_credentials(user) - - if valid? - user - else - nil - end - end - - # `validate_credentials` determines if a user can sign in. - # - # If desired, you can add additional checks in this method, e.g. - # - # if user.locked? - # email.add_error "is locked out" - # end - private def validate_credentials(user) - if user - unless Authentic.correct_password?(user, password.value.to_s) - password.add_error "is wrong" - end - else - # Usually ok to say that an email is not in the system: - # https://kev.inburke.com/kevin/invalid-username-or-password-useless/ - # https://github.com/luckyframework/lucky_cli/issues/192 - email.add_error "is not in our system" - end - end -end diff --git a/fixtures/base_authentication_src_template/expected/src/operations/sign_up_user.cr b/fixtures/base_authentication_src_template/expected/src/operations/sign_up_user.cr deleted file mode 100644 index 8c46fadc..00000000 --- a/fixtures/base_authentication_src_template/expected/src/operations/sign_up_user.cr +++ /dev/null @@ -1,14 +0,0 @@ -class SignUpUser < User::SaveOperation - param_key :user - # Change password validations in src/operations/mixins/password_validations.cr - include PasswordValidations - - permit_columns email - attribute password : String - attribute password_confirmation : String - - before_save do - validate_uniqueness_of email - Authentic.copy_and_encrypt(password, to: encrypted_password) if password.valid? - end -end diff --git a/fixtures/base_authentication_src_template/expected/src/queries/user_query.cr b/fixtures/base_authentication_src_template/expected/src/queries/user_query.cr deleted file mode 100644 index 8a7e9a7f..00000000 --- a/fixtures/base_authentication_src_template/expected/src/queries/user_query.cr +++ /dev/null @@ -1,2 +0,0 @@ -class UserQuery < User::BaseQuery -end diff --git a/fixtures/browser_authentication_src_template/expected/spec/flows/authentication_spec.cr b/fixtures/browser_authentication_src_template/expected/spec/flows/authentication_spec.cr deleted file mode 100644 index cee71bcd..00000000 --- a/fixtures/browser_authentication_src_template/expected/spec/flows/authentication_spec.cr +++ /dev/null @@ -1,34 +0,0 @@ -require "../spec_helper" - -# NOTE: LuckyFlow specs are temporarily set to pending as of Lucky v1.4.0 -# This is due to race conditions in LuckyFlow. -# Ref: https://github.com/luckyframework/lucky_cli/issues/883 -describe "Authentication flow", tags: "flow" do - pending "works" do - flow = AuthenticationFlow.new("test@example.com") - - flow.sign_up "password" - flow.should_be_signed_in - flow.sign_out - flow.sign_in "wrong-password" - flow.should_have_password_error - flow.sign_in "password" - flow.should_be_signed_in - end - - # This is to show you how to sign in as a user during tests. - # Use the `visit` method's `as` option in your tests to sign in as that user. - # - # Feel free to delete this once you have other tests using the 'as' option. - pending "allows sign in through backdoor when testing" do - user = UserFactory.create - flow = BaseFlow.new - - flow.visit Me::Show, as: user - should_be_signed_in(flow) - end -end - -private def should_be_signed_in(flow) - flow.should have_element("@sign-out-button") -end diff --git a/fixtures/browser_authentication_src_template/expected/spec/flows/reset_password_spec.cr b/fixtures/browser_authentication_src_template/expected/spec/flows/reset_password_spec.cr deleted file mode 100644 index 809a0322..00000000 --- a/fixtures/browser_authentication_src_template/expected/spec/flows/reset_password_spec.cr +++ /dev/null @@ -1,21 +0,0 @@ -require "../spec_helper" - -# NOTE: LuckyFlow specs are temporarily set to pending as of Lucky v1.4.0 -# This is due to race conditions in LuckyFlow. -# Ref: https://github.com/luckyframework/lucky_cli/issues/883 -describe "Reset password flow", tags: "flow" do - pending "works" do - user = UserFactory.create - flow = ResetPasswordFlow.new(user) - - flow.request_password_reset - flow.should_have_sent_reset_email - flow.reset_password "new-password" - flow.should_be_signed_in - flow.sign_out - flow.sign_in "wrong-password" - flow.should_have_password_error - flow.sign_in "new-password" - flow.should_be_signed_in - end -end diff --git a/fixtures/browser_authentication_src_template/expected/spec/support/.keep b/fixtures/browser_authentication_src_template/expected/spec/support/.keep deleted file mode 100644 index e69de29b..00000000 diff --git a/fixtures/browser_authentication_src_template/expected/spec/support/flows/authentication_flow.cr b/fixtures/browser_authentication_src_template/expected/spec/support/flows/authentication_flow.cr deleted file mode 100644 index 183697f9..00000000 --- a/fixtures/browser_authentication_src_template/expected/spec/support/flows/authentication_flow.cr +++ /dev/null @@ -1,45 +0,0 @@ -class AuthenticationFlow < BaseFlow - private getter email - - def initialize(@email : String) - end - - def sign_up(password) - visit SignUps::New - fill_form SignUpUser, - email: email, - password: password, - password_confirmation: password - click "@sign-up-button" - end - - def sign_out - visit Me::Show - sign_out_button.click - end - - def sign_in(password) - visit SignIns::New - fill_form SignInUser, - email: email, - password: password - click "@sign-in-button" - end - - def should_be_signed_in - current_page.should have_element("@sign-out-button") - end - - def should_have_password_error - current_page.should have_element("body", text: "Password is wrong") - end - - private def sign_out_button - el("@sign-out-button") - end - - # NOTE: this is a shim for readability - private def current_page - self - end -end diff --git a/fixtures/browser_authentication_src_template/expected/spec/support/flows/reset_password_flow.cr b/fixtures/browser_authentication_src_template/expected/spec/support/flows/reset_password_flow.cr deleted file mode 100644 index b1df7104..00000000 --- a/fixtures/browser_authentication_src_template/expected/spec/support/flows/reset_password_flow.cr +++ /dev/null @@ -1,42 +0,0 @@ -class ResetPasswordFlow < BaseFlow - private getter user, authentication_flow - delegate sign_in, sign_out, should_have_password_error, should_be_signed_in, - to: authentication_flow - delegate email, to: user - - def initialize(@user : User) - @authentication_flow = AuthenticationFlow.new(user.email) - end - - def request_password_reset - with_fake_token do - visit PasswordResetRequests::New - fill_form RequestPasswordReset, - email: email - click "@request-password-reset-button" - end - end - - def should_have_sent_reset_email - with_fake_token do - user = UserQuery.new.email(email).first - PasswordResetRequestEmail.new(user).should be_delivered - end - end - - def reset_password(password) - user = UserQuery.new.email(email).first - token = Authentic.generate_password_reset_token(user) - visit PasswordResets::New.with(user.id, token) - fill_form ResetPassword, - password: password, - password_confirmation: password - click "@update-password-button" - end - - private def with_fake_token(&) - PasswordResetRequestEmail.temp_config(stubbed_token: "fake") do - yield - end - end -end diff --git a/fixtures/browser_authentication_src_template/expected/src/actions/me/show.cr b/fixtures/browser_authentication_src_template/expected/src/actions/me/show.cr deleted file mode 100644 index 5e35848e..00000000 --- a/fixtures/browser_authentication_src_template/expected/src/actions/me/show.cr +++ /dev/null @@ -1,5 +0,0 @@ -class Me::Show < BrowserAction - get "/me" do - html ShowPage - end -end diff --git a/fixtures/browser_authentication_src_template/expected/src/actions/mixins/.keep b/fixtures/browser_authentication_src_template/expected/src/actions/mixins/.keep deleted file mode 100644 index e69de29b..00000000 diff --git a/fixtures/browser_authentication_src_template/expected/src/actions/mixins/auth/allow_guests.cr b/fixtures/browser_authentication_src_template/expected/src/actions/mixins/auth/allow_guests.cr deleted file mode 100644 index 3961399b..00000000 --- a/fixtures/browser_authentication_src_template/expected/src/actions/mixins/auth/allow_guests.cr +++ /dev/null @@ -1,10 +0,0 @@ -module Auth::AllowGuests - macro included - skip require_sign_in - end - - # Since sign in is not required, current_user might be nil - def current_user : User? - current_user? - end -end diff --git a/fixtures/browser_authentication_src_template/expected/src/actions/mixins/auth/password_resets/base.cr b/fixtures/browser_authentication_src_template/expected/src/actions/mixins/auth/password_resets/base.cr deleted file mode 100644 index 77166a97..00000000 --- a/fixtures/browser_authentication_src_template/expected/src/actions/mixins/auth/password_resets/base.cr +++ /dev/null @@ -1,7 +0,0 @@ -module Auth::PasswordResets::Base - macro included - include Auth::RedirectSignedInUsers - include Auth::PasswordResets::FindUser - include Auth::PasswordResets::RequireToken - end -end diff --git a/fixtures/browser_authentication_src_template/expected/src/actions/mixins/auth/password_resets/find_user.cr b/fixtures/browser_authentication_src_template/expected/src/actions/mixins/auth/password_resets/find_user.cr deleted file mode 100644 index cab02d5c..00000000 --- a/fixtures/browser_authentication_src_template/expected/src/actions/mixins/auth/password_resets/find_user.cr +++ /dev/null @@ -1,5 +0,0 @@ -module Auth::PasswordResets::FindUser - private def user : User - UserQuery.find(user_id) - end -end diff --git a/fixtures/browser_authentication_src_template/expected/src/actions/mixins/auth/password_resets/require_token.cr b/fixtures/browser_authentication_src_template/expected/src/actions/mixins/auth/password_resets/require_token.cr deleted file mode 100644 index 15da4238..00000000 --- a/fixtures/browser_authentication_src_template/expected/src/actions/mixins/auth/password_resets/require_token.cr +++ /dev/null @@ -1,17 +0,0 @@ -module Auth::PasswordResets::RequireToken - macro included - before require_valid_password_reset_token - end - - abstract def token : String - abstract def user : User - - private def require_valid_password_reset_token - if Authentic.valid_password_reset_token?(user, token) - continue - else - flash.failure = "The password reset link is incorrect or expired. Please try again." - redirect to: PasswordResetRequests::New - end - end -end diff --git a/fixtures/browser_authentication_src_template/expected/src/actions/mixins/auth/password_resets/token_from_session.cr b/fixtures/browser_authentication_src_template/expected/src/actions/mixins/auth/password_resets/token_from_session.cr deleted file mode 100644 index 820b91bc..00000000 --- a/fixtures/browser_authentication_src_template/expected/src/actions/mixins/auth/password_resets/token_from_session.cr +++ /dev/null @@ -1,5 +0,0 @@ -module Auth::PasswordResets::TokenFromSession - private def token : String - session.get?(:password_reset_token) || raise "Password reset token not found in session" - end -end diff --git a/fixtures/browser_authentication_src_template/expected/src/actions/mixins/auth/redirect_signed_in_users.cr b/fixtures/browser_authentication_src_template/expected/src/actions/mixins/auth/redirect_signed_in_users.cr deleted file mode 100644 index 546bf7bb..00000000 --- a/fixtures/browser_authentication_src_template/expected/src/actions/mixins/auth/redirect_signed_in_users.cr +++ /dev/null @@ -1,19 +0,0 @@ -module Auth::RedirectSignedInUsers - macro included - include Auth::AllowGuests - before redirect_signed_in_users - end - - private def redirect_signed_in_users - if current_user? - flash.success = "You are already signed in" - redirect to: Home::Index - else - continue - end - end - - # current_user returns nil because signed in users are redirected. - def current_user - end -end diff --git a/fixtures/browser_authentication_src_template/expected/src/actions/mixins/auth/require_sign_in.cr b/fixtures/browser_authentication_src_template/expected/src/actions/mixins/auth/require_sign_in.cr deleted file mode 100644 index 27a6f5ea..00000000 --- a/fixtures/browser_authentication_src_template/expected/src/actions/mixins/auth/require_sign_in.cr +++ /dev/null @@ -1,21 +0,0 @@ -module Auth::RequireSignIn - macro included - before require_sign_in - end - - private def require_sign_in - if current_user? - continue - else - Authentic.remember_requested_path(self) - flash.info = "Please sign in first" - redirect to: SignIns::New - end - end - - # Tells the compiler that the current_user is not nil since we have checked - # that the user is signed in - private def current_user : User - current_user?.as(User) - end -end diff --git a/fixtures/browser_authentication_src_template/expected/src/actions/mixins/auth/test_backdoor.cr b/fixtures/browser_authentication_src_template/expected/src/actions/mixins/auth/test_backdoor.cr deleted file mode 100644 index 68c9d91a..00000000 --- a/fixtures/browser_authentication_src_template/expected/src/actions/mixins/auth/test_backdoor.cr +++ /dev/null @@ -1,13 +0,0 @@ -module Auth::TestBackdoor - macro included - before test_backdoor - end - - private def test_backdoor - if LuckyEnv.test? && (user_id = params.get?(:backdoor_user_id)) - user = UserQuery.find(user_id) - sign_in user - end - continue - end -end diff --git a/fixtures/browser_authentication_src_template/expected/src/actions/password_reset_requests/create.cr b/fixtures/browser_authentication_src_template/expected/src/actions/password_reset_requests/create.cr deleted file mode 100644 index 8f3c5130..00000000 --- a/fixtures/browser_authentication_src_template/expected/src/actions/password_reset_requests/create.cr +++ /dev/null @@ -1,15 +0,0 @@ -class PasswordResetRequests::Create < BrowserAction - include Auth::RedirectSignedInUsers - - post "/password_reset_requests" do - RequestPasswordReset.run(params) do |operation, user| - if user - PasswordResetRequestEmail.new(user).deliver - flash.success = "You should receive an email on how to reset your password shortly" - redirect SignIns::New - else - html NewPage, operation: operation - end - end - end -end diff --git a/fixtures/browser_authentication_src_template/expected/src/actions/password_reset_requests/new.cr b/fixtures/browser_authentication_src_template/expected/src/actions/password_reset_requests/new.cr deleted file mode 100644 index 7d16a7dd..00000000 --- a/fixtures/browser_authentication_src_template/expected/src/actions/password_reset_requests/new.cr +++ /dev/null @@ -1,7 +0,0 @@ -class PasswordResetRequests::New < BrowserAction - include Auth::RedirectSignedInUsers - - get "/password_reset_requests/new" do - html NewPage, operation: RequestPasswordReset.new - end -end diff --git a/fixtures/browser_authentication_src_template/expected/src/actions/password_resets/create.cr b/fixtures/browser_authentication_src_template/expected/src/actions/password_resets/create.cr deleted file mode 100644 index da1e711b..00000000 --- a/fixtures/browser_authentication_src_template/expected/src/actions/password_resets/create.cr +++ /dev/null @@ -1,17 +0,0 @@ -class PasswordResets::Create < BrowserAction - include Auth::PasswordResets::Base - include Auth::PasswordResets::TokenFromSession - - post "/password_resets/:user_id" do - ResetPassword.update(user, params) do |operation, user| - if operation.saved? - session.delete(:password_reset_token) - sign_in user - flash.success = "Your password has been reset" - redirect to: Home::Index - else - html NewPage, operation: operation, user_id: user_id.to_i64 - end - end - end -end diff --git a/fixtures/browser_authentication_src_template/expected/src/actions/password_resets/edit.cr b/fixtures/browser_authentication_src_template/expected/src/actions/password_resets/edit.cr deleted file mode 100644 index 9408109c..00000000 --- a/fixtures/browser_authentication_src_template/expected/src/actions/password_resets/edit.cr +++ /dev/null @@ -1,8 +0,0 @@ -class PasswordResets::Edit < BrowserAction - include Auth::PasswordResets::Base - include Auth::PasswordResets::TokenFromSession - - get "/password_resets/:user_id/edit" do - html NewPage, operation: ResetPassword.new, user_id: user_id.to_i64 - end -end diff --git a/fixtures/browser_authentication_src_template/expected/src/actions/password_resets/new.cr b/fixtures/browser_authentication_src_template/expected/src/actions/password_resets/new.cr deleted file mode 100644 index 55034686..00000000 --- a/fixtures/browser_authentication_src_template/expected/src/actions/password_resets/new.cr +++ /dev/null @@ -1,20 +0,0 @@ -class PasswordResets::New < BrowserAction - include Auth::PasswordResets::Base - - param token : String - - get "/password_resets/:user_id" do - redirect_to_edit_form_without_token_param - end - - # This is to prevent password reset tokens from being scraped in the HTTP Referer header - # See more info here: https://github.com/thoughtbot/clearance/pull/707 - private def redirect_to_edit_form_without_token_param - make_token_available_to_future_actions - redirect to: PasswordResets::Edit.with(user_id) - end - - private def make_token_available_to_future_actions - session.set(:password_reset_token, token) - end -end diff --git a/fixtures/browser_authentication_src_template/expected/src/actions/sign_ins/create.cr b/fixtures/browser_authentication_src_template/expected/src/actions/sign_ins/create.cr deleted file mode 100644 index af225888..00000000 --- a/fixtures/browser_authentication_src_template/expected/src/actions/sign_ins/create.cr +++ /dev/null @@ -1,16 +0,0 @@ -class SignIns::Create < BrowserAction - include Auth::RedirectSignedInUsers - - post "/sign_in" do - SignInUser.run(params) do |operation, authenticated_user| - if authenticated_user - sign_in(authenticated_user) - flash.success = "You're now signed in" - Authentic.redirect_to_originally_requested_path(self, fallback: Home::Index) - else - flash.failure = "Sign in failed" - html NewPage, operation: operation - end - end - end -end diff --git a/fixtures/browser_authentication_src_template/expected/src/actions/sign_ins/delete.cr b/fixtures/browser_authentication_src_template/expected/src/actions/sign_ins/delete.cr deleted file mode 100644 index 8d34612f..00000000 --- a/fixtures/browser_authentication_src_template/expected/src/actions/sign_ins/delete.cr +++ /dev/null @@ -1,7 +0,0 @@ -class SignIns::Delete < BrowserAction - delete "/sign_out" do - sign_out - flash.info = "You have been signed out" - redirect to: SignIns::New - end -end diff --git a/fixtures/browser_authentication_src_template/expected/src/actions/sign_ins/new.cr b/fixtures/browser_authentication_src_template/expected/src/actions/sign_ins/new.cr deleted file mode 100644 index 3275b40f..00000000 --- a/fixtures/browser_authentication_src_template/expected/src/actions/sign_ins/new.cr +++ /dev/null @@ -1,7 +0,0 @@ -class SignIns::New < BrowserAction - include Auth::RedirectSignedInUsers - - get "/sign_in" do - html NewPage, operation: SignInUser.new - end -end diff --git a/fixtures/browser_authentication_src_template/expected/src/actions/sign_ups/create.cr b/fixtures/browser_authentication_src_template/expected/src/actions/sign_ups/create.cr deleted file mode 100644 index a291ca68..00000000 --- a/fixtures/browser_authentication_src_template/expected/src/actions/sign_ups/create.cr +++ /dev/null @@ -1,16 +0,0 @@ -class SignUps::Create < BrowserAction - include Auth::RedirectSignedInUsers - - post "/sign_up" do - SignUpUser.create(params) do |operation, user| - if user - flash.info = "Thanks for signing up" - sign_in(user) - redirect to: Home::Index - else - flash.info = "Couldn't sign you up" - html NewPage, operation: operation - end - end - end -end diff --git a/fixtures/browser_authentication_src_template/expected/src/actions/sign_ups/new.cr b/fixtures/browser_authentication_src_template/expected/src/actions/sign_ups/new.cr deleted file mode 100644 index 2299df6e..00000000 --- a/fixtures/browser_authentication_src_template/expected/src/actions/sign_ups/new.cr +++ /dev/null @@ -1,7 +0,0 @@ -class SignUps::New < BrowserAction - include Auth::RedirectSignedInUsers - - get "/sign_up" do - html NewPage, operation: SignUpUser.new - end -end diff --git a/fixtures/browser_authentication_src_template/expected/src/emails/password_reset_request_email.cr b/fixtures/browser_authentication_src_template/expected/src/emails/password_reset_request_email.cr deleted file mode 100644 index a41c8ba1..00000000 --- a/fixtures/browser_authentication_src_template/expected/src/emails/password_reset_request_email.cr +++ /dev/null @@ -1,13 +0,0 @@ -class PasswordResetRequestEmail < BaseEmail - Habitat.create { setting stubbed_token : String? } - delegate stubbed_token, to: :settings - - def initialize(@user : User) - @token = stubbed_token || Authentic.generate_password_reset_token(@user) - end - - to @user - from "myapp@support.com" # or set a default in src/emails/base_email.cr - subject "Reset your password" - templates html, text -end diff --git a/fixtures/browser_authentication_src_template/expected/src/emails/templates/password_reset_request_email/html.ecr b/fixtures/browser_authentication_src_template/expected/src/emails/templates/password_reset_request_email/html.ecr deleted file mode 100644 index 00c24fc9..00000000 --- a/fixtures/browser_authentication_src_template/expected/src/emails/templates/password_reset_request_email/html.ecr +++ /dev/null @@ -1,3 +0,0 @@ -

Please reset your password

- -Reset password diff --git a/fixtures/browser_authentication_src_template/expected/src/emails/templates/password_reset_request_email/text.ecr b/fixtures/browser_authentication_src_template/expected/src/emails/templates/password_reset_request_email/text.ecr deleted file mode 100644 index 7a7a0ab7..00000000 --- a/fixtures/browser_authentication_src_template/expected/src/emails/templates/password_reset_request_email/text.ecr +++ /dev/null @@ -1,3 +0,0 @@ -Please reset your password: - -<%= PasswordResets::New.url(@user.id, @token) %> diff --git a/fixtures/browser_authentication_src_template/expected/src/pages/auth_layout.cr b/fixtures/browser_authentication_src_template/expected/src/pages/auth_layout.cr deleted file mode 100644 index c2ac1b09..00000000 --- a/fixtures/browser_authentication_src_template/expected/src/pages/auth_layout.cr +++ /dev/null @@ -1,27 +0,0 @@ -abstract class AuthLayout - include Lucky::HTMLPage - - abstract def content - abstract def page_title - - # The default page title. It is passed to `Shared::LayoutHead`. - # - # Add a `page_title` method to pages to override it. You can also remove - # This method so every page is required to have its own page title. - def page_title - "Welcome" - end - - def render - html_doctype - - html lang: "en" do - mount Shared::LayoutHead, page_title: page_title - - body do - mount Shared::FlashMessages, context.flash - content - end - end - end -end diff --git a/fixtures/browser_authentication_src_template/expected/src/pages/main_layout.cr b/fixtures/browser_authentication_src_template/expected/src/pages/main_layout.cr deleted file mode 100644 index 06a1ed7a..00000000 --- a/fixtures/browser_authentication_src_template/expected/src/pages/main_layout.cr +++ /dev/null @@ -1,45 +0,0 @@ -abstract class MainLayout - include Lucky::HTMLPage - - # 'needs current_user : User' makes it so that the current_user - # is always required for pages using MainLayout - needs current_user : User - - abstract def content - abstract def page_title - - # MainLayout defines a default 'page_title'. - # - # Add a 'page_title' method to your indivual pages to customize each page's - # title. - # - # Or, if you want to require every page to set a title, change the - # 'page_title' method in this layout to: - # - # abstract def page_title : String - # - # This will force pages to define their own 'page_title' method. - def page_title - "Welcome" - end - - def render - html_doctype - - html lang: "en" do - mount Shared::LayoutHead, page_title: page_title - - body do - mount Shared::FlashMessages, context.flash - render_signed_in_user - content - end - end - end - - private def render_signed_in_user - text current_user.email - text " - " - link "Sign out", to: SignIns::Delete, flow_id: "sign-out-button" - end -end diff --git a/fixtures/browser_authentication_src_template/expected/src/pages/me/show_page.cr b/fixtures/browser_authentication_src_template/expected/src/pages/me/show_page.cr deleted file mode 100644 index 6a6bd879..00000000 --- a/fixtures/browser_authentication_src_template/expected/src/pages/me/show_page.cr +++ /dev/null @@ -1,21 +0,0 @@ -class Me::ShowPage < MainLayout - def content - h1 "This is your profile" - h3 "Email: #{@current_user.email}" - helpful_tips - end - - private def helpful_tips - h3 "Next, you may want to:" - ul do - li { link_to_authentication_guides } - li "Modify this page: src/pages/me/show_page.cr" - li "Change where you go after sign in: src/actions/home/index.cr" - end - end - - private def link_to_authentication_guides - a "Check out the authentication guides", - href: "https://luckyframework.org/guides/authentication" - end -end diff --git a/fixtures/browser_authentication_src_template/expected/src/pages/password_reset_requests/new_page.cr b/fixtures/browser_authentication_src_template/expected/src/pages/password_reset_requests/new_page.cr deleted file mode 100644 index 368784c9..00000000 --- a/fixtures/browser_authentication_src_template/expected/src/pages/password_reset_requests/new_page.cr +++ /dev/null @@ -1,15 +0,0 @@ -class PasswordResetRequests::NewPage < AuthLayout - needs operation : RequestPasswordReset - - def content - h1 "Reset your password" - render_form(@operation) - end - - private def render_form(op) - form_for PasswordResetRequests::Create do - mount Shared::Field, attribute: op.email, label_text: "Email", &.email_input - submit "Reset Password", flow_id: "request-password-reset-button" - end - end -end diff --git a/fixtures/browser_authentication_src_template/expected/src/pages/password_resets/new_page.cr b/fixtures/browser_authentication_src_template/expected/src/pages/password_resets/new_page.cr deleted file mode 100644 index 16a6635e..00000000 --- a/fixtures/browser_authentication_src_template/expected/src/pages/password_resets/new_page.cr +++ /dev/null @@ -1,18 +0,0 @@ -class PasswordResets::NewPage < AuthLayout - needs operation : ResetPassword - needs user_id : Int64 - - def content - h1 "Reset your password" - render_password_reset_form(@operation) - end - - private def render_password_reset_form(op) - form_for PasswordResets::Create.with(@user_id) do - mount Shared::Field, attribute: op.password, label_text: "Password", &.password_input(autofocus: "true") - mount Shared::Field, attribute: op.password_confirmation, label_text: "Confirm Password", &.password_input - - submit "Update Password", flow_id: "update-password-button" - end - end -end diff --git a/fixtures/browser_authentication_src_template/expected/src/pages/sign_ins/new_page.cr b/fixtures/browser_authentication_src_template/expected/src/pages/sign_ins/new_page.cr deleted file mode 100644 index 10188135..00000000 --- a/fixtures/browser_authentication_src_template/expected/src/pages/sign_ins/new_page.cr +++ /dev/null @@ -1,23 +0,0 @@ -class SignIns::NewPage < AuthLayout - needs operation : SignInUser - - def content - h1 "Sign In" - render_sign_in_form(@operation) - end - - private def render_sign_in_form(op) - form_for SignIns::Create do - sign_in_fields(op) - submit "Sign In", flow_id: "sign-in-button" - end - link "Reset password", to: PasswordResetRequests::New - text " | " - link "Sign up", to: SignUps::New - end - - private def sign_in_fields(op) - mount Shared::Field, attribute: op.email, label_text: "Email", &.email_input(autofocus: "true") - mount Shared::Field, attribute: op.password, label_text: "Password", &.password_input - end -end diff --git a/fixtures/browser_authentication_src_template/expected/src/pages/sign_ups/new_page.cr b/fixtures/browser_authentication_src_template/expected/src/pages/sign_ups/new_page.cr deleted file mode 100644 index 24f6cb25..00000000 --- a/fixtures/browser_authentication_src_template/expected/src/pages/sign_ups/new_page.cr +++ /dev/null @@ -1,22 +0,0 @@ -class SignUps::NewPage < AuthLayout - needs operation : SignUpUser - - def content - h1 "Sign Up" - render_sign_up_form(@operation) - end - - private def render_sign_up_form(op) - form_for SignUps::Create do - sign_up_fields(op) - submit "Sign Up", flow_id: "sign-up-button" - end - link "Sign in instead", to: SignIns::New - end - - private def sign_up_fields(op) - mount Shared::Field, attribute: op.email, label_text: "Email", &.email_input(autofocus: "true") - mount Shared::Field, attribute: op.password, label_text: "Password", &.password_input - mount Shared::Field, attribute: op.password_confirmation, label_text: "Confirm Password", &.password_input - end -end diff --git a/fixtures/browser_src_template/expected/config/html_page.cr b/fixtures/browser_src_template/expected/config/html_page.cr deleted file mode 100644 index dca168e5..00000000 --- a/fixtures/browser_src_template/expected/config/html_page.cr +++ /dev/null @@ -1,3 +0,0 @@ -Lucky::HTMLPage.configure do |settings| - settings.render_component_comments = !LuckyEnv.production? -end diff --git a/fixtures/browser_src_template/expected/db/migrations/.keep b/fixtures/browser_src_template/expected/db/migrations/.keep deleted file mode 100644 index e69de29b..00000000 diff --git a/fixtures/browser_src_template/expected/package.json b/fixtures/browser_src_template/expected/package.json deleted file mode 100644 index 3a64c995..00000000 --- a/fixtures/browser_src_template/expected/package.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "license": "UNLICENSED", - "private": true, - "type": "module", - "dependencies": { - "@rails/ujs": "^7.1.0", - "modern-normalize": "^2.0.0" - }, - "scripts": { - "heroku-postbuild": "yarn build", - "dev": "vite", - "build": "vite build", - "preview": "vite preview", - "watch": "vite build --watch" - }, - "devDependencies": { - "sass": "^1.69.5", - "vite": "^5.0.0", - "vite-plugin-compression": "^0.5.1", - "vite-plugin-dev-manifest": "^1.2.1" - } -} \ No newline at end of file diff --git a/fixtures/browser_src_template/expected/public/assets/images/.keep b/fixtures/browser_src_template/expected/public/assets/images/.keep deleted file mode 100644 index e69de29b..00000000 diff --git a/fixtures/browser_src_template/expected/public/favicon.ico b/fixtures/browser_src_template/expected/public/favicon.ico deleted file mode 100644 index e69de29b..00000000 diff --git a/fixtures/browser_src_template/expected/public/robots.txt b/fixtures/browser_src_template/expected/public/robots.txt deleted file mode 100644 index 12009050..00000000 --- a/fixtures/browser_src_template/expected/public/robots.txt +++ /dev/null @@ -1,4 +0,0 @@ -# Learn more about robots.txt: https://www.robotstxt.org/robotstxt.html -User-agent: * -# 'Disallow' with an empty value allows all paths to be crawled -Disallow: diff --git a/fixtures/browser_src_template/expected/spec/flows/.keep b/fixtures/browser_src_template/expected/spec/flows/.keep deleted file mode 100644 index e69de29b..00000000 diff --git a/fixtures/browser_src_template/expected/spec/setup/.keep b/fixtures/browser_src_template/expected/spec/setup/.keep deleted file mode 100644 index e69de29b..00000000 diff --git a/fixtures/browser_src_template/expected/spec/setup/configure_lucky_flow.cr b/fixtures/browser_src_template/expected/spec/setup/configure_lucky_flow.cr deleted file mode 100644 index 504a3d34..00000000 --- a/fixtures/browser_src_template/expected/spec/setup/configure_lucky_flow.cr +++ /dev/null @@ -1,37 +0,0 @@ -# For more detailed documentation, visit -# https://luckyframework.org/guides/testing/html-and-interactivity - -LuckyFlow.configure do |settings| - settings.stop_retrying_after = 200.milliseconds - settings.base_uri = Lucky::RouteHelper.settings.base_uri - - # LuckyFlow will install the chromedriver for you located in - # ~./webdrivers/. Uncomment this to point to a specific driver - # settings.driver_path = "/path/to/specific/chromedriver" -end - -# By default, LuckyFlow is set in "headless" mode (no browser window shown). -# Uncomment this to enable running `LuckyFlow` in a Google Chrome window instead. -# Be sure to disable for CI. -# -# LuckyFlow.default_driver = "chrome" - -# LuckyFlow uses a registry for each driver. By default, chrome, and headless_chrome -# are available. If you'd like to register your own custom driver, you can register -# it here. -# -# LuckyFlow::Registry.register :firefox do -# # add your custom driver here -# end - -# Setup specs to allow you to change the driver on the fly -# per spec by setting a tag on specific specs. Requires the -# driver to be registered through `LuckyFlow::Registry` first. -# -# ``` -# it "uses headless_chrome" do -# end -# it "uses webless", tags: "webless" do -# end -# ``` -LuckyFlow::Spec.setup diff --git a/fixtures/browser_src_template/expected/spec/support/.keep b/fixtures/browser_src_template/expected/spec/support/.keep deleted file mode 100644 index e69de29b..00000000 diff --git a/fixtures/browser_src_template/expected/spec/support/factories/.keep b/fixtures/browser_src_template/expected/spec/support/factories/.keep deleted file mode 100644 index e69de29b..00000000 diff --git a/fixtures/browser_src_template/expected/spec/support/flows/base_flow.cr b/fixtures/browser_src_template/expected/spec/support/flows/base_flow.cr deleted file mode 100644 index 93709b25..00000000 --- a/fixtures/browser_src_template/expected/spec/support/flows/base_flow.cr +++ /dev/null @@ -1,3 +0,0 @@ -# Add methods that all or most Flows need to share -class BaseFlow < LuckyFlow -end diff --git a/fixtures/browser_src_template/expected/src/actions/browser_action.cr b/fixtures/browser_src_template/expected/src/actions/browser_action.cr deleted file mode 100644 index 674f2088..00000000 --- a/fixtures/browser_src_template/expected/src/actions/browser_action.cr +++ /dev/null @@ -1,45 +0,0 @@ -abstract class BrowserAction < Lucky::Action - include Lucky::ProtectFromForgery - - # By default all actions are required to use underscores. - # Add `include Lucky::SkipRouteStyleCheck` to your actions if you wish to ignore this check for specific routes. - include Lucky::EnforceUnderscoredRoute - - # This module disables Google FLoC by setting the - # [Permissions-Policy](https://github.com/WICG/floc) HTTP header to `interest-cohort=()`. - # - # This header is a part of Google's Federated Learning of Cohorts (FLoC) which is used - # to track browsing history instead of using 3rd-party cookies. - # - # Remove this include if you want to use the FLoC tracking. - include Lucky::SecureHeaders::DisableFLoC - - accepted_formats [:html, :json], default: :html - - # This module provides current_user, sign_in, and sign_out methods - include Authentic::ActionHelpers(User) - - # When testing you can skip normal sign in by using `visit` with the `as` param - # - # flow.visit Me::Show, as: UserFactory.create - include Auth::TestBackdoor - - # By default all actions that inherit 'BrowserAction' require sign in. - # - # You can remove the 'include Auth::RequireSignIn' below to allow anyone to - # access actions that inherit from 'BrowserAction' or you can - # 'include Auth::AllowGuests' in individual actions to skip sign in. - include Auth::RequireSignIn - - # `expose` means that `current_user` will be passed to pages automatically. - # - # In default Lucky apps, the `MainLayout` declares it `needs current_user : User` - # so that any page that inherits from MainLayout can use the `current_user` - expose current_user - - # This method tells Authentic how to find the current user - # The 'memoize' macro makes sure only one query is issued to find the user - private memoize def find_current_user(id : String | User::PrimaryKeyType) : User? - UserQuery.new.id(id).first? - end -end diff --git a/fixtures/browser_src_template/expected/src/components/.keep b/fixtures/browser_src_template/expected/src/components/.keep deleted file mode 100644 index e69de29b..00000000 diff --git a/fixtures/browser_src_template/expected/src/components/base_component.cr b/fixtures/browser_src_template/expected/src/components/base_component.cr deleted file mode 100644 index c9829b48..00000000 --- a/fixtures/browser_src_template/expected/src/components/base_component.cr +++ /dev/null @@ -1,2 +0,0 @@ -abstract class BaseComponent < Lucky::BaseComponent -end diff --git a/fixtures/browser_src_template/expected/src/components/shared/field.cr b/fixtures/browser_src_template/expected/src/components/shared/field.cr deleted file mode 100644 index 5c32e8a8..00000000 --- a/fixtures/browser_src_template/expected/src/components/shared/field.cr +++ /dev/null @@ -1,57 +0,0 @@ -# This component is used to make it easier to render the same fields styles -# throughout your app. -# -# Extensive documentation at: https://luckyframework.org/guides/frontend/html-forms#shared-components -# -# ## Basic usage: -# -# # Renders a text input by default and will guess the label name "Name" -# mount Shared::Field, op.name -# # Call any of the input methods on the block -# mount Shared::Field, op.email, &.email_input -# # Add other HTML attributes -# mount Shared::Field, op.email, &.email_input(autofocus: "true") -# # Pass an explicit label name -# mount Shared::Field, attribute: op.username, label_text: "Your username" -# -# ## Customization -# -# You can customize this component so that fields render like you expect. -# For example, you might wrap it in a div with a "field-wrapper" class. -# -# div class: "field-wrapper" -# label_for field -# yield field -# mount Shared::FieldErrors, field -# end -# -# You may also want to have more components if your fields look -# different in different parts of your app, e.g. `CompactField` or -# `InlineTextField` -class Shared::Field(T) < BaseComponent - # Raises a helpful error if component receives an unpermitted attribute - include Lucky::CatchUnpermittedAttribute - - needs attribute : Avram::PermittedAttribute(T) - needs label_text : String? - - def render(&) - label_for attribute, label_text - - # You can add more default options here. For example: - # - # tag_defaults field: attribute, class: "input" - # - # Will add the class "input" to the generated HTML. - tag_defaults field: attribute do |tag_builder| - yield tag_builder - end - - mount Shared::FieldErrors, attribute - end - - # Use a text_input by default - def render - render &.text_input - end -end diff --git a/fixtures/browser_src_template/expected/src/components/shared/field_errors.cr b/fixtures/browser_src_template/expected/src/components/shared/field_errors.cr deleted file mode 100644 index 3f2937a0..00000000 --- a/fixtures/browser_src_template/expected/src/components/shared/field_errors.cr +++ /dev/null @@ -1,16 +0,0 @@ -class Shared::FieldErrors(T) < BaseComponent - needs attribute : Avram::PermittedAttribute(T) - - # Customize the markup and styles to match your application - def render - unless attribute.valid? - div class: "error" do - text "#{label_text} #{attribute.errors.first}" - end - end - end - - def label_text : String - Wordsmith::Inflector.humanize(attribute.name.to_s) - end -end diff --git a/fixtures/browser_src_template/expected/src/components/shared/flash_messages.cr b/fixtures/browser_src_template/expected/src/components/shared/flash_messages.cr deleted file mode 100644 index bc44440d..00000000 --- a/fixtures/browser_src_template/expected/src/components/shared/flash_messages.cr +++ /dev/null @@ -1,11 +0,0 @@ -class Shared::FlashMessages < BaseComponent - needs flash : Lucky::FlashStore - - def render - flash.each do |flash_type, flash_message| - div class: "flash-#{flash_type}", flow_id: "flash" do - text flash_message - end - end - end -end diff --git a/fixtures/browser_src_template/expected/src/components/shared/layout_head.cr b/fixtures/browser_src_template/expected/src/components/shared/layout_head.cr deleted file mode 100644 index 5a053315..00000000 --- a/fixtures/browser_src_template/expected/src/components/shared/layout_head.cr +++ /dev/null @@ -1,18 +0,0 @@ -class Shared::LayoutHead < BaseComponent - needs page_title : String - - def render - head do - utf8_charset - title "My App - #{@page_title}" - css_link asset("css/app.css") - js_link asset("js/app.js"), defer: "true" - csrf_meta_tags - responsive_meta_tag - - # Development helper used with the `lucky watch` command. - # Reloads the browser when files are updated. - live_reload_connect_tag if LuckyEnv.development? - end - end -end diff --git a/fixtures/browser_src_template/expected/src/css/app.scss b/fixtures/browser_src_template/expected/src/css/app.scss deleted file mode 100644 index 48d219d7..00000000 --- a/fixtures/browser_src_template/expected/src/css/app.scss +++ /dev/null @@ -1,66 +0,0 @@ -// Lucky generates 3 folders to help you organize your CSS: -// -// - src/css/variables # Files for colors, spacing, etc. -// - src/css/mixins # Put your mixin functions in files here -// - src/css/components # CSS for your components -// -// Remember to import your new CSS files or they won't be loaded: -// -// @import "./variables/colors" # Imports the file in src/css/variables/_colors.scss -// -// Note: Vite automatically resolves imports from node_modules -// https://stackoverflow.com/questions/39535760/what-does-a-tilde-in-a-css-url-do - -@import 'modern-normalize/modern-normalize.css'; -// Add your own components and import them like this: -// -// @import "components/my_new_component"; - -// Default Lucky styles. -// Delete these when you're ready to bring in your own CSS. -body { - font-family: system-ui, BlinkMacSystemFont, -apple-system, Segoe UI, - Roboto, Oxygen, Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, - sans-serif; - margin: 0 auto; - max-width: 800px; - padding: 20px 40px; -} - -label, input { - display: flex; -} - -label { - font-weight: 500; -} - -[type='color'], -[type='date'], -[type='datetime'], -[type='datetime-local'], -[type='email'], -[type='month'], -[type='number'], -[type='password'], -[type='search'], -[type='tel'], -[type='text'], -[type='time'], -[type='url'], -[type='week'], -input:not([type]), -textarea { - border-radius: 3px; - border: 1px solid #bbb; - margin: 7px 0 14px 0; - max-width: 400px; - padding: 8px 6px; - width: 100%; -} - -[type='submit'] { - font-weight: 900; - margin: 9px 0; - padding: 6px 9px; -} diff --git a/fixtures/browser_src_template/expected/src/emails/.keep b/fixtures/browser_src_template/expected/src/emails/.keep deleted file mode 100644 index e69de29b..00000000 diff --git a/fixtures/browser_src_template/expected/src/js/app.js b/fixtures/browser_src_template/expected/src/js/app.js deleted file mode 100644 index cca98fa2..00000000 --- a/fixtures/browser_src_template/expected/src/js/app.js +++ /dev/null @@ -1,7 +0,0 @@ -/* eslint no-console:0 */ - -// Rails Unobtrusive JavaScript (UJS) is *required* for links in Lucky that use DELETE, POST and PUT. -// Though it says "Rails" it actually works with any framework. -import Rails from "@rails/ujs"; -Rails.start(); - diff --git a/fixtures/browser_src_template/expected/src/models/mixins/.keep b/fixtures/browser_src_template/expected/src/models/mixins/.keep deleted file mode 100644 index e69de29b..00000000 diff --git a/fixtures/browser_src_template/expected/src/operations/.keep b/fixtures/browser_src_template/expected/src/operations/.keep deleted file mode 100644 index e69de29b..00000000 diff --git a/fixtures/browser_src_template/expected/src/operations/mixins/.keep b/fixtures/browser_src_template/expected/src/operations/mixins/.keep deleted file mode 100644 index e69de29b..00000000 diff --git a/fixtures/browser_src_template/expected/src/pages/errors/show_page.cr b/fixtures/browser_src_template/expected/src/pages/errors/show_page.cr deleted file mode 100644 index e7636de9..00000000 --- a/fixtures/browser_src_template/expected/src/pages/errors/show_page.cr +++ /dev/null @@ -1,93 +0,0 @@ -class Errors::ShowPage - include Lucky::HTMLPage - - needs message : String - needs status_code : Int32 - - def render - html_doctype - html lang: "en" do - head do - utf8_charset - title "Something went wrong" - load_lato_font - normalize_styles - error_page_styles - end - - body do - div class: "container" do - h2 status_code, class: "status-code" - h1 message, class: "message" - - ul class: "helpful-links" do - li do - a "Try heading back to home", href: "/", class: "helpful-link" - end - end - end - end - end - end - - def load_lato_font - css_link "https://fonts.googleapis.com/css?family=Lato" - end - - def normalize_styles - style <<-CSS - /*! normalize.css v7.0.0 | MIT License | github.com/necolas/normalize.css */html{line-height:1.15;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}article,aside,footer,header,nav,section{display:block}h1{font-size:2em;margin:.67em 0}figcaption,figure,main{display:block}figure{margin:1em 40px}hr{box-sizing:content-box;height:0;overflow:visible}pre{font-family:monospace,monospace;font-size:1em}a{background-color:transparent;-webkit-text-decoration-skip:objects}abbr[title]{border-bottom:none;text-decoration:underline;text-decoration:underline dotted}b,strong{font-weight:inherit}b,strong{font-weight:bolder}code,kbd,samp{font-family:monospace,monospace;font-size:1em}dfn{font-style:italic}mark{background-color:#ff0;color:#000}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}audio,video{display:inline-block}audio:not([controls]){display:none;height:0}img{border-style:none}svg:not(:root){overflow:hidden}button,input,optgroup,select,textarea{font-family:sans-serif;font-size:100%;line-height:1.15;margin:0}button,input{overflow:visible}button,select{text-transform:none}[type=reset],[type=submit],button,html [type=button]{-webkit-appearance:button}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{border-style:none;padding:0}[type=button]:-moz-focusring,[type=reset]:-moz-focusring,[type=submit]:-moz-focusring,button:-moz-focusring{outline:1px dotted ButtonText}fieldset{padding:.35em .75em .625em}legend{box-sizing:border-box;color:inherit;display:table;max-width:100%;padding:0;white-space:normal}progress{display:inline-block;vertical-align:baseline}textarea{overflow:auto}[type=checkbox],[type=radio]{box-sizing:border-box;padding:0}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}[type=search]::-webkit-search-cancel-button,[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}details,menu{display:block}summary{display:list-item}canvas{display:inline-block}template{display:none}[hidden]{display:none} - CSS - end - - def error_page_styles - style <<-CSS - body { - background-color: #f5f5f5; - color: #000; - font-family: 'Lato', sans-serif; - padding-top: 100px; - } - - .helpful-links { - list-style-type: none; - margin: 0; - padding: 0; - } - - .helpful-link { - color: #15A38B; - } - - .status-code { - opacity: 0.4; - font-size: 26px; - font-weight: normal; - } - - .message { - font-size: 34px; - line-height: 56px; - font-weight: normal; - } - - .container { - margin: 0 auto; - max-width: 450px; - padding: 55px; - } - - @media only screen and (max-width: 500px) { - .status-code { - font-size: 18px; - } - - .message { - font-size: 26px; - line-height: 40px; - margin: 20px 0 35px 0; - } - } - CSS - end -end diff --git a/fixtures/browser_src_template/expected/src/pages/main_layout.cr b/fixtures/browser_src_template/expected/src/pages/main_layout.cr deleted file mode 100644 index 40f7c5ce..00000000 --- a/fixtures/browser_src_template/expected/src/pages/main_layout.cr +++ /dev/null @@ -1,27 +0,0 @@ -abstract class MainLayout - include Lucky::HTMLPage - - abstract def content - abstract def page_title - - # The default page title. It is passed to `Shared::LayoutHead`. - # - # Add a `page_title` method to pages to override it. You can also remove - # This method so every page is required to have its own page title. - def page_title - "Welcome" - end - - def render - html_doctype - - html lang: "en" do - mount Shared::LayoutHead, page_title: page_title - - body do - mount Shared::FlashMessages, context.flash - content - end - end - end -end diff --git a/fixtures/browser_src_template/expected/vite.config.js b/fixtures/browser_src_template/expected/vite.config.js deleted file mode 100644 index 2076b094..00000000 --- a/fixtures/browser_src_template/expected/vite.config.js +++ /dev/null @@ -1,87 +0,0 @@ -import { defineConfig } from 'vite' -import { resolve } from 'path' -import compression from 'vite-plugin-compression' -import devManifest from 'vite-plugin-dev-manifest' - -// https://vitejs.dev/config/ -export default defineConfig({ - // Root directory is project root (where vite.config.js is) - root: '.', - - // Public directory for static assets - publicDir: 'public/assets', - - // Build configuration - build: { - // Output directory - outDir: 'public', - // Don't empty the output directory (Lucky serves from public/) - emptyOutDir: false, - // Generate manifest for Lucky asset helpers - manifest: true, - // Define entry points - rollupOptions: { - input: { - // These entry names map to asset paths in Lucky: - // "app" -> asset("js/app.js") - // "styles" -> asset("css/app.scss") - app: resolve(__dirname, 'src/js/app.js'), - styles: resolve(__dirname, 'src/css/app.scss') - } - }, - // Asset output configuration - assetsDir: 'assets', - // Source maps for production - sourcemap: process.env.NODE_ENV === 'production' ? false : 'inline' - }, - - // CSS configuration - css: { - devSourcemap: true - }, - - // Server configuration for development - server: { - // This allows Vite to be accessed from Lucky's dev server - origin: 'http://localhost:3001', - port: 3001, - strictPort: true, - // Enable HMR - hmr: { - host: 'localhost' - } - }, - - // Preview server configuration (for testing production builds) - preview: { - port: 3001 - }, - - // Plugins - plugins: [ - // Generate dev manifest for Lucky's compile-time asset validation - devManifest({ - manifestName: 'manifest.dev', - clearOnClose: false - }), - // Gzip compression for production builds - process.env.NODE_ENV === 'production' && compression({ - algorithm: 'gzip', - ext: '.gz', - threshold: 1024, - }), - // Add Brotli compression if desired - // process.env.NODE_ENV === 'production' && compression({ - // algorithm: 'brotliCompress', - // ext: '.br', - // threshold: 1024, - // }), - ].filter(Boolean), - - // Resolve configuration - resolve: { - alias: { - '@': resolve(__dirname, 'src') - } - } -}) \ No newline at end of file diff --git a/fixtures/browser_src_template__generate_auth/expected/config/html_page.cr b/fixtures/browser_src_template__generate_auth/expected/config/html_page.cr deleted file mode 100644 index dca168e5..00000000 --- a/fixtures/browser_src_template__generate_auth/expected/config/html_page.cr +++ /dev/null @@ -1,3 +0,0 @@ -Lucky::HTMLPage.configure do |settings| - settings.render_component_comments = !LuckyEnv.production? -end diff --git a/fixtures/browser_src_template__generate_auth/expected/db/migrations/.keep b/fixtures/browser_src_template__generate_auth/expected/db/migrations/.keep deleted file mode 100644 index e69de29b..00000000 diff --git a/fixtures/browser_src_template__generate_auth/expected/package.json b/fixtures/browser_src_template__generate_auth/expected/package.json deleted file mode 100644 index 3a64c995..00000000 --- a/fixtures/browser_src_template__generate_auth/expected/package.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "license": "UNLICENSED", - "private": true, - "type": "module", - "dependencies": { - "@rails/ujs": "^7.1.0", - "modern-normalize": "^2.0.0" - }, - "scripts": { - "heroku-postbuild": "yarn build", - "dev": "vite", - "build": "vite build", - "preview": "vite preview", - "watch": "vite build --watch" - }, - "devDependencies": { - "sass": "^1.69.5", - "vite": "^5.0.0", - "vite-plugin-compression": "^0.5.1", - "vite-plugin-dev-manifest": "^1.2.1" - } -} \ No newline at end of file diff --git a/fixtures/browser_src_template__generate_auth/expected/public/assets/images/.keep b/fixtures/browser_src_template__generate_auth/expected/public/assets/images/.keep deleted file mode 100644 index e69de29b..00000000 diff --git a/fixtures/browser_src_template__generate_auth/expected/public/favicon.ico b/fixtures/browser_src_template__generate_auth/expected/public/favicon.ico deleted file mode 100644 index e69de29b..00000000 diff --git a/fixtures/browser_src_template__generate_auth/expected/public/robots.txt b/fixtures/browser_src_template__generate_auth/expected/public/robots.txt deleted file mode 100644 index 12009050..00000000 --- a/fixtures/browser_src_template__generate_auth/expected/public/robots.txt +++ /dev/null @@ -1,4 +0,0 @@ -# Learn more about robots.txt: https://www.robotstxt.org/robotstxt.html -User-agent: * -# 'Disallow' with an empty value allows all paths to be crawled -Disallow: diff --git a/fixtures/browser_src_template__generate_auth/expected/spec/flows/.keep b/fixtures/browser_src_template__generate_auth/expected/spec/flows/.keep deleted file mode 100644 index e69de29b..00000000 diff --git a/fixtures/browser_src_template__generate_auth/expected/spec/setup/.keep b/fixtures/browser_src_template__generate_auth/expected/spec/setup/.keep deleted file mode 100644 index e69de29b..00000000 diff --git a/fixtures/browser_src_template__generate_auth/expected/spec/setup/configure_lucky_flow.cr b/fixtures/browser_src_template__generate_auth/expected/spec/setup/configure_lucky_flow.cr deleted file mode 100644 index 504a3d34..00000000 --- a/fixtures/browser_src_template__generate_auth/expected/spec/setup/configure_lucky_flow.cr +++ /dev/null @@ -1,37 +0,0 @@ -# For more detailed documentation, visit -# https://luckyframework.org/guides/testing/html-and-interactivity - -LuckyFlow.configure do |settings| - settings.stop_retrying_after = 200.milliseconds - settings.base_uri = Lucky::RouteHelper.settings.base_uri - - # LuckyFlow will install the chromedriver for you located in - # ~./webdrivers/. Uncomment this to point to a specific driver - # settings.driver_path = "/path/to/specific/chromedriver" -end - -# By default, LuckyFlow is set in "headless" mode (no browser window shown). -# Uncomment this to enable running `LuckyFlow` in a Google Chrome window instead. -# Be sure to disable for CI. -# -# LuckyFlow.default_driver = "chrome" - -# LuckyFlow uses a registry for each driver. By default, chrome, and headless_chrome -# are available. If you'd like to register your own custom driver, you can register -# it here. -# -# LuckyFlow::Registry.register :firefox do -# # add your custom driver here -# end - -# Setup specs to allow you to change the driver on the fly -# per spec by setting a tag on specific specs. Requires the -# driver to be registered through `LuckyFlow::Registry` first. -# -# ``` -# it "uses headless_chrome" do -# end -# it "uses webless", tags: "webless" do -# end -# ``` -LuckyFlow::Spec.setup diff --git a/fixtures/browser_src_template__generate_auth/expected/spec/support/.keep b/fixtures/browser_src_template__generate_auth/expected/spec/support/.keep deleted file mode 100644 index e69de29b..00000000 diff --git a/fixtures/browser_src_template__generate_auth/expected/spec/support/factories/.keep b/fixtures/browser_src_template__generate_auth/expected/spec/support/factories/.keep deleted file mode 100644 index e69de29b..00000000 diff --git a/fixtures/browser_src_template__generate_auth/expected/spec/support/flows/base_flow.cr b/fixtures/browser_src_template__generate_auth/expected/spec/support/flows/base_flow.cr deleted file mode 100644 index 93709b25..00000000 --- a/fixtures/browser_src_template__generate_auth/expected/spec/support/flows/base_flow.cr +++ /dev/null @@ -1,3 +0,0 @@ -# Add methods that all or most Flows need to share -class BaseFlow < LuckyFlow -end diff --git a/fixtures/browser_src_template__generate_auth/expected/src/actions/browser_action.cr b/fixtures/browser_src_template__generate_auth/expected/src/actions/browser_action.cr deleted file mode 100644 index a72377f4..00000000 --- a/fixtures/browser_src_template__generate_auth/expected/src/actions/browser_action.cr +++ /dev/null @@ -1,18 +0,0 @@ -abstract class BrowserAction < Lucky::Action - include Lucky::ProtectFromForgery - - # By default all actions are required to use underscores. - # Add `include Lucky::SkipRouteStyleCheck` to your actions if you wish to ignore this check for specific routes. - include Lucky::EnforceUnderscoredRoute - - # This module disables Google FLoC by setting the - # [Permissions-Policy](https://github.com/WICG/floc) HTTP header to `interest-cohort=()`. - # - # This header is a part of Google's Federated Learning of Cohorts (FLoC) which is used - # to track browsing history instead of using 3rd-party cookies. - # - # Remove this include if you want to use the FLoC tracking. - include Lucky::SecureHeaders::DisableFLoC - - accepted_formats [:html, :json], default: :html -end diff --git a/fixtures/browser_src_template__generate_auth/expected/src/components/.keep b/fixtures/browser_src_template__generate_auth/expected/src/components/.keep deleted file mode 100644 index e69de29b..00000000 diff --git a/fixtures/browser_src_template__generate_auth/expected/src/components/base_component.cr b/fixtures/browser_src_template__generate_auth/expected/src/components/base_component.cr deleted file mode 100644 index c9829b48..00000000 --- a/fixtures/browser_src_template__generate_auth/expected/src/components/base_component.cr +++ /dev/null @@ -1,2 +0,0 @@ -abstract class BaseComponent < Lucky::BaseComponent -end diff --git a/fixtures/browser_src_template__generate_auth/expected/src/components/shared/field.cr b/fixtures/browser_src_template__generate_auth/expected/src/components/shared/field.cr deleted file mode 100644 index 5c32e8a8..00000000 --- a/fixtures/browser_src_template__generate_auth/expected/src/components/shared/field.cr +++ /dev/null @@ -1,57 +0,0 @@ -# This component is used to make it easier to render the same fields styles -# throughout your app. -# -# Extensive documentation at: https://luckyframework.org/guides/frontend/html-forms#shared-components -# -# ## Basic usage: -# -# # Renders a text input by default and will guess the label name "Name" -# mount Shared::Field, op.name -# # Call any of the input methods on the block -# mount Shared::Field, op.email, &.email_input -# # Add other HTML attributes -# mount Shared::Field, op.email, &.email_input(autofocus: "true") -# # Pass an explicit label name -# mount Shared::Field, attribute: op.username, label_text: "Your username" -# -# ## Customization -# -# You can customize this component so that fields render like you expect. -# For example, you might wrap it in a div with a "field-wrapper" class. -# -# div class: "field-wrapper" -# label_for field -# yield field -# mount Shared::FieldErrors, field -# end -# -# You may also want to have more components if your fields look -# different in different parts of your app, e.g. `CompactField` or -# `InlineTextField` -class Shared::Field(T) < BaseComponent - # Raises a helpful error if component receives an unpermitted attribute - include Lucky::CatchUnpermittedAttribute - - needs attribute : Avram::PermittedAttribute(T) - needs label_text : String? - - def render(&) - label_for attribute, label_text - - # You can add more default options here. For example: - # - # tag_defaults field: attribute, class: "input" - # - # Will add the class "input" to the generated HTML. - tag_defaults field: attribute do |tag_builder| - yield tag_builder - end - - mount Shared::FieldErrors, attribute - end - - # Use a text_input by default - def render - render &.text_input - end -end diff --git a/fixtures/browser_src_template__generate_auth/expected/src/components/shared/field_errors.cr b/fixtures/browser_src_template__generate_auth/expected/src/components/shared/field_errors.cr deleted file mode 100644 index 3f2937a0..00000000 --- a/fixtures/browser_src_template__generate_auth/expected/src/components/shared/field_errors.cr +++ /dev/null @@ -1,16 +0,0 @@ -class Shared::FieldErrors(T) < BaseComponent - needs attribute : Avram::PermittedAttribute(T) - - # Customize the markup and styles to match your application - def render - unless attribute.valid? - div class: "error" do - text "#{label_text} #{attribute.errors.first}" - end - end - end - - def label_text : String - Wordsmith::Inflector.humanize(attribute.name.to_s) - end -end diff --git a/fixtures/browser_src_template__generate_auth/expected/src/components/shared/flash_messages.cr b/fixtures/browser_src_template__generate_auth/expected/src/components/shared/flash_messages.cr deleted file mode 100644 index bc44440d..00000000 --- a/fixtures/browser_src_template__generate_auth/expected/src/components/shared/flash_messages.cr +++ /dev/null @@ -1,11 +0,0 @@ -class Shared::FlashMessages < BaseComponent - needs flash : Lucky::FlashStore - - def render - flash.each do |flash_type, flash_message| - div class: "flash-#{flash_type}", flow_id: "flash" do - text flash_message - end - end - end -end diff --git a/fixtures/browser_src_template__generate_auth/expected/src/components/shared/layout_head.cr b/fixtures/browser_src_template__generate_auth/expected/src/components/shared/layout_head.cr deleted file mode 100644 index 5a053315..00000000 --- a/fixtures/browser_src_template__generate_auth/expected/src/components/shared/layout_head.cr +++ /dev/null @@ -1,18 +0,0 @@ -class Shared::LayoutHead < BaseComponent - needs page_title : String - - def render - head do - utf8_charset - title "My App - #{@page_title}" - css_link asset("css/app.css") - js_link asset("js/app.js"), defer: "true" - csrf_meta_tags - responsive_meta_tag - - # Development helper used with the `lucky watch` command. - # Reloads the browser when files are updated. - live_reload_connect_tag if LuckyEnv.development? - end - end -end diff --git a/fixtures/browser_src_template__generate_auth/expected/src/css/app.scss b/fixtures/browser_src_template__generate_auth/expected/src/css/app.scss deleted file mode 100644 index 48d219d7..00000000 --- a/fixtures/browser_src_template__generate_auth/expected/src/css/app.scss +++ /dev/null @@ -1,66 +0,0 @@ -// Lucky generates 3 folders to help you organize your CSS: -// -// - src/css/variables # Files for colors, spacing, etc. -// - src/css/mixins # Put your mixin functions in files here -// - src/css/components # CSS for your components -// -// Remember to import your new CSS files or they won't be loaded: -// -// @import "./variables/colors" # Imports the file in src/css/variables/_colors.scss -// -// Note: Vite automatically resolves imports from node_modules -// https://stackoverflow.com/questions/39535760/what-does-a-tilde-in-a-css-url-do - -@import 'modern-normalize/modern-normalize.css'; -// Add your own components and import them like this: -// -// @import "components/my_new_component"; - -// Default Lucky styles. -// Delete these when you're ready to bring in your own CSS. -body { - font-family: system-ui, BlinkMacSystemFont, -apple-system, Segoe UI, - Roboto, Oxygen, Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, - sans-serif; - margin: 0 auto; - max-width: 800px; - padding: 20px 40px; -} - -label, input { - display: flex; -} - -label { - font-weight: 500; -} - -[type='color'], -[type='date'], -[type='datetime'], -[type='datetime-local'], -[type='email'], -[type='month'], -[type='number'], -[type='password'], -[type='search'], -[type='tel'], -[type='text'], -[type='time'], -[type='url'], -[type='week'], -input:not([type]), -textarea { - border-radius: 3px; - border: 1px solid #bbb; - margin: 7px 0 14px 0; - max-width: 400px; - padding: 8px 6px; - width: 100%; -} - -[type='submit'] { - font-weight: 900; - margin: 9px 0; - padding: 6px 9px; -} diff --git a/fixtures/browser_src_template__generate_auth/expected/src/emails/.keep b/fixtures/browser_src_template__generate_auth/expected/src/emails/.keep deleted file mode 100644 index e69de29b..00000000 diff --git a/fixtures/browser_src_template__generate_auth/expected/src/js/app.js b/fixtures/browser_src_template__generate_auth/expected/src/js/app.js deleted file mode 100644 index cca98fa2..00000000 --- a/fixtures/browser_src_template__generate_auth/expected/src/js/app.js +++ /dev/null @@ -1,7 +0,0 @@ -/* eslint no-console:0 */ - -// Rails Unobtrusive JavaScript (UJS) is *required* for links in Lucky that use DELETE, POST and PUT. -// Though it says "Rails" it actually works with any framework. -import Rails from "@rails/ujs"; -Rails.start(); - diff --git a/fixtures/browser_src_template__generate_auth/expected/src/models/mixins/.keep b/fixtures/browser_src_template__generate_auth/expected/src/models/mixins/.keep deleted file mode 100644 index e69de29b..00000000 diff --git a/fixtures/browser_src_template__generate_auth/expected/src/operations/.keep b/fixtures/browser_src_template__generate_auth/expected/src/operations/.keep deleted file mode 100644 index e69de29b..00000000 diff --git a/fixtures/browser_src_template__generate_auth/expected/src/operations/mixins/.keep b/fixtures/browser_src_template__generate_auth/expected/src/operations/mixins/.keep deleted file mode 100644 index e69de29b..00000000 diff --git a/fixtures/browser_src_template__generate_auth/expected/src/pages/errors/show_page.cr b/fixtures/browser_src_template__generate_auth/expected/src/pages/errors/show_page.cr deleted file mode 100644 index e7636de9..00000000 --- a/fixtures/browser_src_template__generate_auth/expected/src/pages/errors/show_page.cr +++ /dev/null @@ -1,93 +0,0 @@ -class Errors::ShowPage - include Lucky::HTMLPage - - needs message : String - needs status_code : Int32 - - def render - html_doctype - html lang: "en" do - head do - utf8_charset - title "Something went wrong" - load_lato_font - normalize_styles - error_page_styles - end - - body do - div class: "container" do - h2 status_code, class: "status-code" - h1 message, class: "message" - - ul class: "helpful-links" do - li do - a "Try heading back to home", href: "/", class: "helpful-link" - end - end - end - end - end - end - - def load_lato_font - css_link "https://fonts.googleapis.com/css?family=Lato" - end - - def normalize_styles - style <<-CSS - /*! normalize.css v7.0.0 | MIT License | github.com/necolas/normalize.css */html{line-height:1.15;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}article,aside,footer,header,nav,section{display:block}h1{font-size:2em;margin:.67em 0}figcaption,figure,main{display:block}figure{margin:1em 40px}hr{box-sizing:content-box;height:0;overflow:visible}pre{font-family:monospace,monospace;font-size:1em}a{background-color:transparent;-webkit-text-decoration-skip:objects}abbr[title]{border-bottom:none;text-decoration:underline;text-decoration:underline dotted}b,strong{font-weight:inherit}b,strong{font-weight:bolder}code,kbd,samp{font-family:monospace,monospace;font-size:1em}dfn{font-style:italic}mark{background-color:#ff0;color:#000}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}audio,video{display:inline-block}audio:not([controls]){display:none;height:0}img{border-style:none}svg:not(:root){overflow:hidden}button,input,optgroup,select,textarea{font-family:sans-serif;font-size:100%;line-height:1.15;margin:0}button,input{overflow:visible}button,select{text-transform:none}[type=reset],[type=submit],button,html [type=button]{-webkit-appearance:button}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{border-style:none;padding:0}[type=button]:-moz-focusring,[type=reset]:-moz-focusring,[type=submit]:-moz-focusring,button:-moz-focusring{outline:1px dotted ButtonText}fieldset{padding:.35em .75em .625em}legend{box-sizing:border-box;color:inherit;display:table;max-width:100%;padding:0;white-space:normal}progress{display:inline-block;vertical-align:baseline}textarea{overflow:auto}[type=checkbox],[type=radio]{box-sizing:border-box;padding:0}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}[type=search]::-webkit-search-cancel-button,[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}details,menu{display:block}summary{display:list-item}canvas{display:inline-block}template{display:none}[hidden]{display:none} - CSS - end - - def error_page_styles - style <<-CSS - body { - background-color: #f5f5f5; - color: #000; - font-family: 'Lato', sans-serif; - padding-top: 100px; - } - - .helpful-links { - list-style-type: none; - margin: 0; - padding: 0; - } - - .helpful-link { - color: #15A38B; - } - - .status-code { - opacity: 0.4; - font-size: 26px; - font-weight: normal; - } - - .message { - font-size: 34px; - line-height: 56px; - font-weight: normal; - } - - .container { - margin: 0 auto; - max-width: 450px; - padding: 55px; - } - - @media only screen and (max-width: 500px) { - .status-code { - font-size: 18px; - } - - .message { - font-size: 26px; - line-height: 40px; - margin: 20px 0 35px 0; - } - } - CSS - end -end diff --git a/fixtures/browser_src_template__generate_auth/expected/src/pages/main_layout.cr b/fixtures/browser_src_template__generate_auth/expected/src/pages/main_layout.cr deleted file mode 100644 index 40f7c5ce..00000000 --- a/fixtures/browser_src_template__generate_auth/expected/src/pages/main_layout.cr +++ /dev/null @@ -1,27 +0,0 @@ -abstract class MainLayout - include Lucky::HTMLPage - - abstract def content - abstract def page_title - - # The default page title. It is passed to `Shared::LayoutHead`. - # - # Add a `page_title` method to pages to override it. You can also remove - # This method so every page is required to have its own page title. - def page_title - "Welcome" - end - - def render - html_doctype - - html lang: "en" do - mount Shared::LayoutHead, page_title: page_title - - body do - mount Shared::FlashMessages, context.flash - content - end - end - end -end diff --git a/fixtures/browser_src_template__generate_auth/expected/vite.config.js b/fixtures/browser_src_template__generate_auth/expected/vite.config.js deleted file mode 100644 index 2076b094..00000000 --- a/fixtures/browser_src_template__generate_auth/expected/vite.config.js +++ /dev/null @@ -1,87 +0,0 @@ -import { defineConfig } from 'vite' -import { resolve } from 'path' -import compression from 'vite-plugin-compression' -import devManifest from 'vite-plugin-dev-manifest' - -// https://vitejs.dev/config/ -export default defineConfig({ - // Root directory is project root (where vite.config.js is) - root: '.', - - // Public directory for static assets - publicDir: 'public/assets', - - // Build configuration - build: { - // Output directory - outDir: 'public', - // Don't empty the output directory (Lucky serves from public/) - emptyOutDir: false, - // Generate manifest for Lucky asset helpers - manifest: true, - // Define entry points - rollupOptions: { - input: { - // These entry names map to asset paths in Lucky: - // "app" -> asset("js/app.js") - // "styles" -> asset("css/app.scss") - app: resolve(__dirname, 'src/js/app.js'), - styles: resolve(__dirname, 'src/css/app.scss') - } - }, - // Asset output configuration - assetsDir: 'assets', - // Source maps for production - sourcemap: process.env.NODE_ENV === 'production' ? false : 'inline' - }, - - // CSS configuration - css: { - devSourcemap: true - }, - - // Server configuration for development - server: { - // This allows Vite to be accessed from Lucky's dev server - origin: 'http://localhost:3001', - port: 3001, - strictPort: true, - // Enable HMR - hmr: { - host: 'localhost' - } - }, - - // Preview server configuration (for testing production builds) - preview: { - port: 3001 - }, - - // Plugins - plugins: [ - // Generate dev manifest for Lucky's compile-time asset validation - devManifest({ - manifestName: 'manifest.dev', - clearOnClose: false - }), - // Gzip compression for production builds - process.env.NODE_ENV === 'production' && compression({ - algorithm: 'gzip', - ext: '.gz', - threshold: 1024, - }), - // Add Brotli compression if desired - // process.env.NODE_ENV === 'production' && compression({ - // algorithm: 'brotliCompress', - // ext: '.br', - // threshold: 1024, - // }), - ].filter(Boolean), - - // Resolve configuration - resolve: { - alias: { - '@': resolve(__dirname, 'src') - } - } -}) \ No newline at end of file diff --git a/fixtures/cat.gif b/fixtures/cat.gif deleted file mode 100644 index d47e9572..00000000 Binary files a/fixtures/cat.gif and /dev/null differ diff --git a/fixtures/hello_crystal.cr b/fixtures/hello_crystal.cr deleted file mode 100644 index 58d66257..00000000 --- a/fixtures/hello_crystal.cr +++ /dev/null @@ -1 +0,0 @@ -puts "Hello, Crystal!" diff --git a/fixtures/hello_world.cr b/fixtures/hello_world.cr deleted file mode 100644 index 01a178ad..00000000 --- a/fixtures/hello_world.cr +++ /dev/null @@ -1 +0,0 @@ -puts "Hello World!" diff --git a/fixtures/shard_file_template/expected/shard.yml b/fixtures/shard_file_template/expected/shard.yml deleted file mode 100644 index 10a7483f..00000000 --- a/fixtures/shard_file_template/expected/shard.yml +++ /dev/null @@ -1,39 +0,0 @@ ---- -name: test-shard -version: 0.1.0 -targets: - test-shard: - main: src/test-shard.cr -crystal: '>= 1.16.1' -dependencies: - lucky: - github: luckyframework/lucky - version: ~> 1.4.0 - avram: - github: luckyframework/avram - version: ~> 1.4.0 - carbon: - github: luckyframework/carbon - version: ~> 0.6.0 - carbon_sendgrid_adapter: - github: luckyframework/carbon_sendgrid_adapter - version: ~> 0.6.0 - lucky_env: - github: luckyframework/lucky_env - version: ~> 0.3.0 - lucky_task: - github: luckyframework/lucky_task - version: ~> 0.3.0 - authentic: - github: luckyframework/authentic - version: '>= 1.0.2, < 2.0.0' - jwt: - github: crystal-community/jwt - version: ~> 1.6.1 -development_dependencies: - lucky_flow: - github: luckyframework/lucky_flow - version: ~> 0.10.1 - lucky_sec_tester: - github: luckyframework/lucky_sec_tester - version: ~> 0.3.3 diff --git a/fixtures/shard_file_template__browser/expected/shard.yml b/fixtures/shard_file_template__browser/expected/shard.yml deleted file mode 100644 index 76a3bf27..00000000 --- a/fixtures/shard_file_template__browser/expected/shard.yml +++ /dev/null @@ -1,30 +0,0 @@ ---- -name: test-shard -version: 0.1.0 -targets: - test-shard: - main: src/test-shard.cr -crystal: '>= 1.16.1' -dependencies: - lucky: - github: luckyframework/lucky - version: ~> 1.4.0 - avram: - github: luckyframework/avram - version: ~> 1.4.0 - carbon: - github: luckyframework/carbon - version: ~> 0.6.0 - carbon_sendgrid_adapter: - github: luckyframework/carbon_sendgrid_adapter - version: ~> 0.6.0 - lucky_env: - github: luckyframework/lucky_env - version: ~> 0.3.0 - lucky_task: - github: luckyframework/lucky_task - version: ~> 0.3.0 -development_dependencies: - lucky_flow: - github: luckyframework/lucky_flow - version: ~> 0.10.1 diff --git a/fixtures/shard_file_template__generate_auth/expected/shard.yml b/fixtures/shard_file_template__generate_auth/expected/shard.yml deleted file mode 100644 index b8305cbc..00000000 --- a/fixtures/shard_file_template__generate_auth/expected/shard.yml +++ /dev/null @@ -1,33 +0,0 @@ ---- -name: test-shard -version: 0.1.0 -targets: - test-shard: - main: src/test-shard.cr -crystal: '>= 1.16.1' -dependencies: - lucky: - github: luckyframework/lucky - version: ~> 1.4.0 - avram: - github: luckyframework/avram - version: ~> 1.4.0 - carbon: - github: luckyframework/carbon - version: ~> 0.6.0 - carbon_sendgrid_adapter: - github: luckyframework/carbon_sendgrid_adapter - version: ~> 0.6.0 - lucky_env: - github: luckyframework/lucky_env - version: ~> 0.3.0 - lucky_task: - github: luckyframework/lucky_task - version: ~> 0.3.0 - authentic: - github: luckyframework/authentic - version: '>= 1.0.2, < 2.0.0' - jwt: - github: crystal-community/jwt - version: ~> 1.6.1 -development_dependencies: {} diff --git a/fixtures/shard_file_template__with_sec_tester/expected/shard.yml b/fixtures/shard_file_template__with_sec_tester/expected/shard.yml deleted file mode 100644 index 877221c3..00000000 --- a/fixtures/shard_file_template__with_sec_tester/expected/shard.yml +++ /dev/null @@ -1,30 +0,0 @@ ---- -name: test-shard -version: 0.1.0 -targets: - test-shard: - main: src/test-shard.cr -crystal: '>= 1.16.1' -dependencies: - lucky: - github: luckyframework/lucky - version: ~> 1.4.0 - avram: - github: luckyframework/avram - version: ~> 1.4.0 - carbon: - github: luckyframework/carbon - version: ~> 0.6.0 - carbon_sendgrid_adapter: - github: luckyframework/carbon_sendgrid_adapter - version: ~> 0.6.0 - lucky_env: - github: luckyframework/lucky_env - version: ~> 0.3.0 - lucky_task: - github: luckyframework/lucky_task - version: ~> 0.3.0 -development_dependencies: - lucky_sec_tester: - github: luckyframework/lucky_sec_tester - version: ~> 0.3.3 diff --git a/fixtures/src_template/expected/.crystal-version b/fixtures/src_template/expected/.crystal-version deleted file mode 100644 index 41c11ffb..00000000 --- a/fixtures/src_template/expected/.crystal-version +++ /dev/null @@ -1 +0,0 @@ -1.16.1 diff --git a/fixtures/src_template/expected/.env b/fixtures/src_template/expected/.env deleted file mode 100644 index e69de29b..00000000 diff --git a/fixtures/src_template/expected/.github/workflows/ci.yml b/fixtures/src_template/expected/.github/workflows/ci.yml deleted file mode 100644 index 8955cbf5..00000000 --- a/fixtures/src_template/expected/.github/workflows/ci.yml +++ /dev/null @@ -1,88 +0,0 @@ -name: test-project CI - -on: - push: - branches: "*" - pull_request: - branches: "*" - -jobs: - check-format: - strategy: - fail-fast: false - matrix: - crystal_version: - - 1.16.1 - experimental: - - false - runs-on: ubuntu-latest - continue-on-error: ${{ matrix.experimental }} - steps: - - uses: actions/checkout@v4 - - name: Install Crystal - uses: crystal-lang/install-crystal@v1 - with: - crystal: ${{ matrix.crystal_version }} - - name: Format - run: crystal tool format --check - - specs: - strategy: - fail-fast: false - matrix: - crystal_version: - - 1.16.1 - experimental: - - false - runs-on: ubuntu-latest - env: - LUCKY_ENV: test - DB_HOST: localhost - continue-on-error: ${{ matrix.experimental }} - services: - postgres: - image: postgres:14-alpine - env: - POSTGRES_PASSWORD: postgres - ports: - - 5432:5432 - # Set health checks to wait until postgres has started - options: >- - --health-cmd pg_isready - --health-interval 10s - --health-timeout 5s - --health-retries 5 - - steps: - - uses: actions/checkout@v4 - - name: Install Crystal - uses: crystal-lang/install-crystal@v1 - with: - crystal: ${{ matrix.crystal_version }} - - - name: Set up Crystal cache - uses: actions/cache@v4 - id: crystal-cache - with: - path: | - ~/.cache/crystal - lib - key: ${{ runner.os }}-crystal-${{ hashFiles('**/shard.lock') }} - restore-keys: | - ${{ runner.os }}-crystal- - - - name: Install shards - if: steps.crystal-cache.outputs.cache-hit != 'true' - run: shards check || shards install - - - name: Build lucky_tasks - run: crystal build tasks.cr -o ./lucky_tasks - - - name: Prepare database - run: | - ./lucky_tasks db.create - ./lucky_tasks db.migrate - ./lucky_tasks db.seed.required_data - - - name: Run tests - run: crystal spec -Dwith_sec_tests \ No newline at end of file diff --git a/fixtures/src_template/expected/Procfile b/fixtures/src_template/expected/Procfile deleted file mode 100644 index e524d70d..00000000 --- a/fixtures/src_template/expected/Procfile +++ /dev/null @@ -1,2 +0,0 @@ -web: bin/app -release: lucky db.migrate diff --git a/fixtures/src_template/expected/Procfile.dev b/fixtures/src_template/expected/Procfile.dev deleted file mode 100644 index dc39e8fe..00000000 --- a/fixtures/src_template/expected/Procfile.dev +++ /dev/null @@ -1,2 +0,0 @@ -system_check: crystal script/system_check.cr -web: lucky watch diff --git a/fixtures/src_template/expected/README.md b/fixtures/src_template/expected/README.md deleted file mode 100644 index da2d97cc..00000000 --- a/fixtures/src_template/expected/README.md +++ /dev/null @@ -1,23 +0,0 @@ -# test-project - -This is a project written using [Lucky](https://luckyframework.org). Enjoy! - -### Setting up the project - -1. [Install required dependencies](https://luckyframework.org/guides/getting-started/installing#install-required-dependencies) -1. Update database settings in `config/database.cr` -1. Run `script/setup` -1. Run `lucky dev` to start the app - -### Using Docker for development - -1. [Install Docker](https://docs.docker.com/engine/install/) -1. Run `docker compose up` - -The Docker container will boot all of the necessary components needed to run your Lucky application. -To configure the container, update the `docker-compose.yml` file, and the `docker/development.dockerfile` file. - - -### Learning Lucky - -Lucky uses the [Crystal](https://crystal-lang.org) programming language. You can learn about Lucky from the [Lucky Guides](https://luckyframework.org/guides/getting-started/why-lucky). diff --git a/fixtures/src_template/expected/config/application.cr b/fixtures/src_template/expected/config/application.cr deleted file mode 100644 index c807149a..00000000 --- a/fixtures/src_template/expected/config/application.cr +++ /dev/null @@ -1,24 +0,0 @@ -# This file may be used for custom Application configurations. -# It will be loaded before other config files. -# -# Read more on configuration: -# https://luckyframework.org/guides/getting-started/configuration#configuring-your-own-code - -# Use this code as an example: -# -# ``` -# module Application -# Habitat.create do -# setting support_email : String -# setting lock_with_basic_auth : Bool -# end -# end -# -# Application.configure do |settings| -# settings.support_email = "support@myapp.io" -# settings.lock_with_basic_auth = LuckyEnv.staging? -# end -# -# # In your application, call -# # `Application.settings.support_email` anywhere you need it. -# ``` diff --git a/fixtures/src_template/expected/config/colors.cr b/fixtures/src_template/expected/config/colors.cr deleted file mode 100644 index 761ae940..00000000 --- a/fixtures/src_template/expected/config/colors.cr +++ /dev/null @@ -1,4 +0,0 @@ -# This enables the color output when in development or test -# Check out the Colorize docs for more information -# https://crystal-lang.org/api/Colorize.html -Colorize.enabled = LuckyEnv.development? || LuckyEnv.test? diff --git a/fixtures/src_template/expected/config/cookies.cr b/fixtures/src_template/expected/config/cookies.cr deleted file mode 100644 index 2d5055f2..00000000 --- a/fixtures/src_template/expected/config/cookies.cr +++ /dev/null @@ -1,25 +0,0 @@ -require "./server" - -Lucky::Session.configure do |settings| - settings.key = "_test_project_session" -end - -Lucky::CookieJar.configure do |settings| - settings.on_set = ->(cookie : HTTP::Cookie) { - # If ForceSSLHandler is enabled, only send cookies over HTTPS - cookie.secure(Lucky::ForceSSLHandler.settings.enabled) - - # By default, don't allow reading cookies with JavaScript - cookie.http_only(true) - - # Restrict cookies to a first-party or same-site context - cookie.samesite(:lax) - - # Set all cookies to the root path by default - cookie.path("/") - - # You can set other defaults for cookies here. For example: - # - # cookie.expires(1.year.from_now).domain("mydomain.com") - } -end diff --git a/fixtures/src_template/expected/config/database.cr b/fixtures/src_template/expected/config/database.cr deleted file mode 100644 index f614299a..00000000 --- a/fixtures/src_template/expected/config/database.cr +++ /dev/null @@ -1,29 +0,0 @@ -database_name = "test_project_#{LuckyEnv.environment}" - -AppDatabase.configure do |settings| - if LuckyEnv.production? - settings.credentials = Avram::Credentials.parse(ENV["DATABASE_URL"]) - else - settings.credentials = Avram::Credentials.parse?(ENV["DATABASE_URL"]?) || Avram::Credentials.new( - database: database_name, - hostname: ENV["DB_HOST"]? || "localhost", - port: ENV["DB_PORT"]?.try(&.to_i) || 5432, - # Some common usernames are "postgres", "root", or your system username (run 'whoami') - username: ENV["DB_USERNAME"]? || "postgres", - # Some Postgres installations require no password. Use "" if that is the case. - password: ENV["DB_PASSWORD"]? || "postgres" - ) - end -end - -Avram.configure do |settings| - settings.database_to_migrate = AppDatabase - - # In production, allow lazy loading (N+1). - # In development and test, raise an error if you forget to preload associations - settings.lazy_load_enabled = LuckyEnv.production? - - # Always parse `Time` values with these specific formats. - # Used for both database values, and datetime input fields. - # settings.time_formats << "%F" -end diff --git a/fixtures/src_template/expected/config/email.cr b/fixtures/src_template/expected/config/email.cr deleted file mode 100644 index 7c875449..00000000 --- a/fixtures/src_template/expected/config/email.cr +++ /dev/null @@ -1,26 +0,0 @@ -require "carbon_sendgrid_adapter" - -BaseEmail.configure do |settings| - if LuckyEnv.production? - # If you don't need to send emails, set the adapter to DevAdapter instead: - # - # settings.adapter = Carbon::DevAdapter.new - # - # If you do need emails, get a key from SendGrid and set an ENV variable - send_grid_key = send_grid_key_from_env - settings.adapter = Carbon::SendGridAdapter.new(api_key: send_grid_key) - elsif LuckyEnv.development? - settings.adapter = Carbon::DevAdapter.new(print_emails: true) - else - settings.adapter = Carbon::DevAdapter.new - end -end - -private def send_grid_key_from_env - ENV["SEND_GRID_KEY"]? || raise_missing_key_message -end - -private def raise_missing_key_message - puts "Missing SEND_GRID_KEY. Set the SEND_GRID_KEY env variable to 'unused' if not sending emails, or set the SEND_GRID_KEY ENV var.".colorize.red - exit(1) -end diff --git a/fixtures/src_template/expected/config/env.cr b/fixtures/src_template/expected/config/env.cr deleted file mode 100644 index 3f364072..00000000 --- a/fixtures/src_template/expected/config/env.cr +++ /dev/null @@ -1,33 +0,0 @@ -# Environments are managed using `LuckyEnv`. By default, development, production -# and test are supported. See -# https://luckyframework.org/guides/getting-started/configuration for details. -# -# The default environment is development unless the environment variable -# LUCKY_ENV is set. -# -# Example: -# ``` -# LuckyEnv.environment # => "development" -# LuckyEnv.development? # => true -# LuckyEnv.production? # => false -# LuckyEnv.test? # => false -# ``` -# -# New environments can be added using the `LuckyEnv.add_env` macro. -# -# Example: -# ``` -# LuckyEnv.add_env :staging -# LuckyEnv.staging? # => false -# ``` -# -# To determine whether or not a `LuckyTask` is currently running, you can use -# the `LuckyEnv.task?` predicate. -# -# Example: -# ``` -# LuckyEnv.task? # => false -# ``` - -# Add a staging environment. -# LuckyEnv.add_env :staging diff --git a/fixtures/src_template/expected/config/error_handler.cr b/fixtures/src_template/expected/config/error_handler.cr deleted file mode 100644 index c6b736e3..00000000 --- a/fixtures/src_template/expected/config/error_handler.cr +++ /dev/null @@ -1,3 +0,0 @@ -Lucky::ErrorHandler.configure do |settings| - settings.show_debug_output = !LuckyEnv.production? -end diff --git a/fixtures/src_template/expected/config/log.cr b/fixtures/src_template/expected/config/log.cr deleted file mode 100644 index a43940d9..00000000 --- a/fixtures/src_template/expected/config/log.cr +++ /dev/null @@ -1,50 +0,0 @@ -require "file_utils" - -if LuckyEnv.test? - # Logs to `tmp/test.log` so you can see what's happening without having - # a bunch of log output in your spec results. - FileUtils.mkdir_p("tmp") - - backend = Log::IOBackend.new(File.new("tmp/test.log", mode: "w")) - backend.formatter = Lucky::PrettyLogFormatter.proc - Log.dexter.configure(:debug, backend) -elsif LuckyEnv.production? - # Lucky uses JSON in production so logs can be searched more easily - # - # If you want logs like in development use 'Lucky::PrettyLogFormatter.proc'. - backend = Log::IOBackend.new - backend.formatter = Dexter::JSONLogFormatter.proc - Log.dexter.configure(:info, backend) -else - # Use a pretty formatter printing to STDOUT in development - backend = Log::IOBackend.new - backend.formatter = Lucky::PrettyLogFormatter.proc - Log.dexter.configure(:debug, backend) - DB::Log.level = :info -end - -# Lucky only logs when before/after pipes halt by redirecting, or rendering a -# response. Pipes that run without halting are not logged. -# -# If you want to log every pipe that runs, set the log level to ':info' -Lucky::ContinuedPipeLog.dexter.configure(:none) - -# Lucky only logs failed queries by default. -# -# Set the log to ':info' to log all queries -Avram::QueryLog.dexter.configure(:none) - -# Subscribe to Pulsar events to log when queries are made, -# queries fail, or save operations fail. Remove this to -# disable these log events without disabling all logging. -Avram.initialize_logging - -# Skip logging static assets requests in development -Lucky::LogHandler.configure do |settings| - if LuckyEnv.development? - settings.skip_if = ->(context : HTTP::Server::Context) { - context.request.method.downcase == "get" && - context.request.resource.starts_with?(/\/css\/|\/js\/|\/assets\/|\/favicon\.ico/) - } - end -end diff --git a/fixtures/src_template/expected/config/route_helper.cr b/fixtures/src_template/expected/config/route_helper.cr deleted file mode 100644 index ede1f328..00000000 --- a/fixtures/src_template/expected/config/route_helper.cr +++ /dev/null @@ -1,10 +0,0 @@ -# This is used when generating URLs for your application -Lucky::RouteHelper.configure do |settings| - if LuckyEnv.production? - # Example: https://my_app.com - settings.base_uri = ENV.fetch("APP_DOMAIN") - else - # Set domain to the default host/port in development/test - settings.base_uri = "http://localhost:#{Lucky::ServerSettings.port}" - end -end diff --git a/fixtures/src_template/expected/config/server.cr b/fixtures/src_template/expected/config/server.cr deleted file mode 100644 index b7cca25c..00000000 --- a/fixtures/src_template/expected/config/server.cr +++ /dev/null @@ -1,68 +0,0 @@ -# Here is where you configure the Lucky server -# -# Look at config/route_helper.cr if you want to change the domain used when -# generating links with `Action.url`. -Lucky::Server.configure do |settings| - if LuckyEnv.production? - settings.secret_key_base = secret_key_from_env - settings.host = "0.0.0.0" - settings.port = ENV["PORT"].to_i - settings.gzip_enabled = true - # By default certain content types will be gzipped. - # For a full list look in - # https://github.com/luckyframework/lucky/blob/main/src/lucky/server.cr - # To add additional extensions do something like this: - # settings.gzip_content_types << "content/type" - else - settings.secret_key_base = "1234567890" - # Change host/port in config/watch.yml - # Alternatively, you can set the DEV_PORT env to set the port for local development - settings.host = Lucky::ServerSettings.host - settings.port = Lucky::ServerSettings.port - end - - # Configure the asset build system (default is Vite) - settings.asset_build_system = Lucky::AssetBuilder::Vite.new - - # Configure asset host for Vite - if LuckyEnv.development? - # In development, Vite serves assets from its dev server - settings.asset_host = "http://localhost:3001" - elsif LuckyEnv.production? - # In production, Lucky serves the built assets - # You could also use a CDN here: - # settings.asset_host = "https://mycdnhost.com" - settings.asset_host = "" - else - settings.asset_host = "" - end -end - -Lucky::ForceSSLHandler.configure do |settings| - # To force SSL in production, uncomment the lines below. - # This will cause http requests to be redirected to https: - # - # settings.enabled = LuckyEnv.production? - # settings.strict_transport_security = {max_age: 1.year, include_subdomains: true} - # - # Or, leave it disabled: - settings.enabled = false -end - -# Set a unique ID for each HTTP request. -# To enable the request ID, uncomment the lines below. -# You can set your own custom String, or use a random UUID. -# Lucky::RequestIdHandler.configure do |settings| -# settings.set_request_id = ->(context : HTTP::Server::Context) { -# UUID.random.to_s -# } -# end - -private def secret_key_from_env - ENV["SECRET_KEY_BASE"]? || raise_missing_secret_key_in_production -end - -private def raise_missing_secret_key_in_production - puts "Please set the SECRET_KEY_BASE environment variable. You can generate a secret key with 'lucky gen.secret_key'".colorize.red - exit(1) -end \ No newline at end of file diff --git a/fixtures/src_template/expected/config/watch.yml b/fixtures/src_template/expected/config/watch.yml deleted file mode 100644 index 3a59b410..00000000 --- a/fixtures/src_template/expected/config/watch.yml +++ /dev/null @@ -1,3 +0,0 @@ -host: 127.0.0.1 -port: 3000 -reload_port: 3001 diff --git a/fixtures/src_template/expected/db/migrations/.keep b/fixtures/src_template/expected/db/migrations/.keep deleted file mode 100644 index e69de29b..00000000 diff --git a/fixtures/src_template/expected/docker-compose.yml b/fixtures/src_template/expected/docker-compose.yml deleted file mode 100644 index d00779db..00000000 --- a/fixtures/src_template/expected/docker-compose.yml +++ /dev/null @@ -1,45 +0,0 @@ -version: "3.8" -services: - lucky: - build: - context: . - dockerfile: docker/development.dockerfile - environment: - DATABASE_URL: postgres://lucky:password@postgres:5432/lucky - DEV_HOST: "0.0.0.0" - volumes: - - .:/app - - node_modules:/app/node_modules - - shards_lib:/app/lib - - app_bin:/app/bin - - build_cache:/root/.cache - depends_on: - - postgres - ports: - - 3000:3000 # This is the Lucky Server port - - 3001:3001 # This is the Lucky watcher reload port - - entrypoint: ["docker/dev_entrypoint.sh"] - - postgres: - image: postgres:14-alpine - environment: - POSTGRES_USER: lucky - POSTGRES_PASSWORD: password - POSTGRES_DB: lucky - volumes: - - postgres_data:/var/lib/postgresql/data - ports: - # The postgres database container is exposed on the host at port 6543 to - # allow connecting directly to it with postgres clients. The port differs - # from the postgres default to avoid conflict with existing postgres - # servers. Connect to a running postgres container with: - # postgres://lucky:password@localhost:6543/lucky - - 6543:5432 - -volumes: - postgres_data: - node_modules: - shards_lib: - app_bin: - build_cache: diff --git a/fixtures/src_template/expected/docker/dev_entrypoint.sh b/fixtures/src_template/expected/docker/dev_entrypoint.sh deleted file mode 100755 index f5aab877..00000000 --- a/fixtures/src_template/expected/docker/dev_entrypoint.sh +++ /dev/null @@ -1,44 +0,0 @@ -#!/bin/bash - -set -euo pipefail - -# This is the entrypoint script used for development docker workflows. -# By default it will: -# - Install dependencies. -# - Run migrations. -# - Start the dev server. -# It also accepts any commands to be run instead. - - -warnfail () { - echo "$@" >&2 - exit 1 -} - -case ${1:-} in - "") # If no arguments are provided, start lucky dev server. - ;; - - *) # If any arguments are provided, execute them instead. - exec "$@" -esac - -if ! [ -d bin ] ; then - echo 'Creating bin directory' - mkdir bin -fi -if ! shards check ; then - echo 'Installing shards...' - shards install -fi - -echo 'Waiting for postgres to be available...' -./docker/wait-for-it.sh -q postgres:5432 - -if ! psql -d "$DATABASE_URL" -c '\d migrations' > /dev/null ; then - echo 'Finishing database setup...' - lucky db.migrate -fi - -echo 'Starting lucky dev server...' -exec lucky dev diff --git a/fixtures/src_template/expected/docker/development.dockerfile b/fixtures/src_template/expected/docker/development.dockerfile deleted file mode 100644 index a4e5b267..00000000 --- a/fixtures/src_template/expected/docker/development.dockerfile +++ /dev/null @@ -1,25 +0,0 @@ -FROM crystallang/crystal:1.16.1 - -# Install utilities required to make this Dockerfile run -RUN apt-get update && \ - apt-get install -y wget - -# Apt installs: -# - Postgres cli tools are required for lucky-cli. -# - tmux is required for the Overmind process manager. -RUN apt-get update && \ - apt-get install -y postgresql-client tmux && \ - rm -rf /var/lib/apt/lists/* - -# Install lucky cli -WORKDIR /lucky/cli -RUN git clone https://github.com/luckyframework/lucky_cli . && \ - git checkout v1.3.0 && \ - shards build --without-development && \ - cp bin/lucky /usr/bin - -WORKDIR /app -ENV DATABASE_URL=postgres://postgres:postgres@host.docker.internal:5432/postgres -EXPOSE 3000 -EXPOSE 3001 - diff --git a/fixtures/src_template/expected/docker/wait-for-it.sh b/fixtures/src_template/expected/docker/wait-for-it.sh deleted file mode 100755 index 06e0638c..00000000 --- a/fixtures/src_template/expected/docker/wait-for-it.sh +++ /dev/null @@ -1,189 +0,0 @@ -#!/usr/bin/bash -# -# Pulled from https://github.com/vishnubob/wait-for-it on 2022-02-28. -# Licensed under the MIT license as of 81b1373f. -# -# Below this line, wait-for-it is the original work of the author. -# -# Use this script to test if a given TCP host/port are available - -WAITFORIT_cmdname=${0##*/} - -echoerr() { if [[ $WAITFORIT_QUIET -ne 1 ]]; then echo "$@" 1>&2; fi } - -usage() -{ - cat << USAGE >&2 -Usage: - $WAITFORIT_cmdname host:port [-s] [-t timeout] [-- command args] - -h HOST | --host=HOST Host or IP under test - -p PORT | --port=PORT TCP port under test - Alternatively, you specify the host and port as host:port - -s | --strict Only execute subcommand if the test succeeds - -q | --quiet Don't output any status messages - -t TIMEOUT | --timeout=TIMEOUT - Timeout in seconds, zero for no timeout - -- COMMAND ARGS Execute command with args after the test finishes -USAGE - exit 1 -} - -wait_for() -{ - if [[ $WAITFORIT_TIMEOUT -gt 0 ]]; then - echoerr "$WAITFORIT_cmdname: waiting $WAITFORIT_TIMEOUT seconds for $WAITFORIT_HOST:$WAITFORIT_PORT" - else - echoerr "$WAITFORIT_cmdname: waiting for $WAITFORIT_HOST:$WAITFORIT_PORT without a timeout" - fi - WAITFORIT_start_ts=$(date +%s) - while : - do - if [[ $WAITFORIT_ISBUSY -eq 1 ]]; then - nc -z $WAITFORIT_HOST $WAITFORIT_PORT - WAITFORIT_result=$? - else - (echo -n > /dev/tcp/$WAITFORIT_HOST/$WAITFORIT_PORT) >/dev/null 2>&1 - WAITFORIT_result=$? - fi - if [[ $WAITFORIT_result -eq 0 ]]; then - WAITFORIT_end_ts=$(date +%s) - echoerr "$WAITFORIT_cmdname: $WAITFORIT_HOST:$WAITFORIT_PORT is available after $((WAITFORIT_end_ts - WAITFORIT_start_ts)) seconds" - break - fi - sleep 1 - done - return $WAITFORIT_result -} - -wait_for_wrapper() -{ - # In order to support SIGINT during timeout: http://unix.stackexchange.com/a/57692 - if [[ $WAITFORIT_QUIET -eq 1 ]]; then - timeout $WAITFORIT_BUSYTIMEFLAG $WAITFORIT_TIMEOUT $0 --quiet --child --host=$WAITFORIT_HOST --port=$WAITFORIT_PORT --timeout=$WAITFORIT_TIMEOUT & - else - timeout $WAITFORIT_BUSYTIMEFLAG $WAITFORIT_TIMEOUT $0 --child --host=$WAITFORIT_HOST --port=$WAITFORIT_PORT --timeout=$WAITFORIT_TIMEOUT & - fi - WAITFORIT_PID=$! - trap "kill -INT -$WAITFORIT_PID" INT - wait $WAITFORIT_PID - WAITFORIT_RESULT=$? - if [[ $WAITFORIT_RESULT -ne 0 ]]; then - echoerr "$WAITFORIT_cmdname: timeout occurred after waiting $WAITFORIT_TIMEOUT seconds for $WAITFORIT_HOST:$WAITFORIT_PORT" - fi - return $WAITFORIT_RESULT -} - -# process arguments -while [[ $# -gt 0 ]] -do - case "$1" in - *:* ) - WAITFORIT_hostport=(${1//:/ }) - WAITFORIT_HOST=${WAITFORIT_hostport[0]} - WAITFORIT_PORT=${WAITFORIT_hostport[1]} - shift 1 - ;; - --child) - WAITFORIT_CHILD=1 - shift 1 - ;; - -q | --quiet) - WAITFORIT_QUIET=1 - shift 1 - ;; - -s | --strict) - WAITFORIT_STRICT=1 - shift 1 - ;; - -h) - WAITFORIT_HOST="$2" - if [[ $WAITFORIT_HOST == "" ]]; then break; fi - shift 2 - ;; - --host=*) - WAITFORIT_HOST="${1#*=}" - shift 1 - ;; - -p) - WAITFORIT_PORT="$2" - if [[ $WAITFORIT_PORT == "" ]]; then break; fi - shift 2 - ;; - --port=*) - WAITFORIT_PORT="${1#*=}" - shift 1 - ;; - -t) - WAITFORIT_TIMEOUT="$2" - if [[ $WAITFORIT_TIMEOUT == "" ]]; then break; fi - shift 2 - ;; - --timeout=*) - WAITFORIT_TIMEOUT="${1#*=}" - shift 1 - ;; - --) - shift - WAITFORIT_CLI=("$@") - break - ;; - --help) - usage - ;; - *) - echoerr "Unknown argument: $1" - usage - ;; - esac -done - -if [[ "$WAITFORIT_HOST" == "" || "$WAITFORIT_PORT" == "" ]]; then - echoerr "Error: you need to provide a host and port to test." - usage -fi - -WAITFORIT_TIMEOUT=${WAITFORIT_TIMEOUT:-15} -WAITFORIT_STRICT=${WAITFORIT_STRICT:-0} -WAITFORIT_CHILD=${WAITFORIT_CHILD:-0} -WAITFORIT_QUIET=${WAITFORIT_QUIET:-0} - -# Check to see if timeout is from busybox? -WAITFORIT_TIMEOUT_PATH=$(type -p timeout) -WAITFORIT_TIMEOUT_PATH=$(realpath $WAITFORIT_TIMEOUT_PATH 2>/dev/null || readlink -f $WAITFORIT_TIMEOUT_PATH) - -WAITFORIT_BUSYTIMEFLAG="" -if [[ $WAITFORIT_TIMEOUT_PATH =~ "busybox" ]]; then - WAITFORIT_ISBUSY=1 - # Check if busybox timeout uses -t flag - # (recent Alpine versions don't support -t anymore) - if timeout &>/dev/stdout | grep -q -e '-t '; then - WAITFORIT_BUSYTIMEFLAG="-t" - fi -else - WAITFORIT_ISBUSY=0 -fi - -if [[ $WAITFORIT_CHILD -gt 0 ]]; then - wait_for - WAITFORIT_RESULT=$? - exit $WAITFORIT_RESULT -else - if [[ $WAITFORIT_TIMEOUT -gt 0 ]]; then - wait_for_wrapper - WAITFORIT_RESULT=$? - else - wait_for - WAITFORIT_RESULT=$? - fi -fi - -if [[ $WAITFORIT_CLI != "" ]]; then - if [[ $WAITFORIT_RESULT -ne 0 && $WAITFORIT_STRICT -eq 1 ]]; then - echoerr "$WAITFORIT_cmdname: strict mode, refusing to execute subprocess" - exit $WAITFORIT_RESULT - fi - exec "${WAITFORIT_CLI[@]}" -else - exit $WAITFORIT_RESULT -fi - diff --git a/fixtures/src_template/expected/script/helpers/function_helpers.cr b/fixtures/src_template/expected/script/helpers/function_helpers.cr deleted file mode 100644 index 8abcb6a2..00000000 --- a/fixtures/src_template/expected/script/helpers/function_helpers.cr +++ /dev/null @@ -1,32 +0,0 @@ -require "colorize" - -# These are helper methods provided to help keep your code -# clean. Add new methods, or alter these as needed. - -def notice(message : String) : Nil - puts "\n▸ #{message}" -end - -def print_done : Nil - puts "✔ Done" -end - -def print_error(message : String) : Nil - puts "There is a problem with your system setup:\n".colorize.red.bold - puts "#{message}\n".colorize.red.bold - Process.exit(1) -end - -def command_not_found(command : String) : Bool - Process.find_executable(command).nil? -end - -def command_not_running(command : String, *args) : Bool - output = IO::Memory.new - code = Process.run(command, args, output: output).exit_code - code > 0 -end - -def run_command(command : String, *args) : Nil - Process.run(command, args, output: STDOUT, error: STDERR, input: STDIN) -end diff --git a/fixtures/src_template/expected/script/setup.cr b/fixtures/src_template/expected/script/setup.cr deleted file mode 100644 index f8d4a907..00000000 --- a/fixtures/src_template/expected/script/setup.cr +++ /dev/null @@ -1,28 +0,0 @@ -require "./helpers/*" - -notice "Running System Check" - -require "./system_check" - -print_done - - -notice "Installing shards" -run_command "shards", "install" - -if !File.exists?(".env") - notice "No .env found. Creating one." - File.touch ".env" - print_done -end - -notice "Setting up the database" - -run_command "lucky", "db.setup" - -notice "Seeding the database with required and sample records" -run_command "lucky", "db.seed.required_data" -run_command "lucky", "db.seed.sample_data" - -print_done -notice "Run 'lucky dev' to start the app" \ No newline at end of file diff --git a/fixtures/src_template/expected/script/system_check.cr b/fixtures/src_template/expected/script/system_check.cr deleted file mode 100644 index b76720ba..00000000 --- a/fixtures/src_template/expected/script/system_check.cr +++ /dev/null @@ -1,18 +0,0 @@ -require "./helpers/*" - -# Use this script to check the system for required tools and process that your app needs. -# A few helper functions are provided to keep the code simple. See the -# script/helpers/function_helpers.cr file for more examples. -# -# A few examples you might use here: -# * 'lucky db.verify_connection' to test postgres can be connected -# * Checking that elasticsearch, redis, or postgres is installed and/or booted -# * Note: Booting additional processes for things like mail, background jobs, etc... -# should go in your Procfile.dev. - - -# CUSTOM PRE-BOOT CHECKS -# example: -# if command_not_running "redis-cli", "ping" -# print_error "Redis is not running." -# end diff --git a/fixtures/src_template/expected/spec/setup/clean_database.cr b/fixtures/src_template/expected/spec/setup/clean_database.cr deleted file mode 100644 index a1bc631c..00000000 --- a/fixtures/src_template/expected/spec/setup/clean_database.cr +++ /dev/null @@ -1,3 +0,0 @@ -Spec.before_each do - AppDatabase.truncate -end diff --git a/fixtures/src_template/expected/spec/setup/reset_emails.cr b/fixtures/src_template/expected/spec/setup/reset_emails.cr deleted file mode 100644 index 140ab416..00000000 --- a/fixtures/src_template/expected/spec/setup/reset_emails.cr +++ /dev/null @@ -1,3 +0,0 @@ -Spec.before_each do - Carbon::DevAdapter.reset -end diff --git a/fixtures/src_template/expected/spec/setup/setup_database.cr b/fixtures/src_template/expected/spec/setup/setup_database.cr deleted file mode 100644 index 393c6da3..00000000 --- a/fixtures/src_template/expected/spec/setup/setup_database.cr +++ /dev/null @@ -1,2 +0,0 @@ -Db::Create.new(quiet: true).call -Db::Migrate.new(quiet: true).call diff --git a/fixtures/src_template/expected/spec/setup/start_app_server.cr b/fixtures/src_template/expected/spec/setup/start_app_server.cr deleted file mode 100644 index 3a64c702..00000000 --- a/fixtures/src_template/expected/spec/setup/start_app_server.cr +++ /dev/null @@ -1,9 +0,0 @@ -app_server = AppServer.new - -spawn do - app_server.listen -end - -Spec.after_suite do - app_server.close -end diff --git a/fixtures/src_template/expected/spec/spec_helper.cr b/fixtures/src_template/expected/spec/spec_helper.cr deleted file mode 100644 index d876014d..00000000 --- a/fixtures/src_template/expected/spec/spec_helper.cr +++ /dev/null @@ -1,19 +0,0 @@ -ENV["LUCKY_ENV"] = "test" -ENV["DEV_PORT"] = "5001" -require "spec" -require "../src/app" -require "./support/**" -require "../db/migrations/**" - -# Add/modify files in spec/setup to start/configure programs or run hooks -# -# By default there are scripts for setting up and cleaning the database, -# configuring LuckyFlow, starting the app server, etc. -require "./setup/**" - -include Carbon::Expectations -include Lucky::RequestExpectations - -Avram::Migrator::Runner.new.ensure_migrated! -Avram::SchemaEnforcer.ensure_correct_column_mappings! -Habitat.raise_if_missing_settings! diff --git a/fixtures/src_template/expected/spec/support/.keep b/fixtures/src_template/expected/spec/support/.keep deleted file mode 100644 index e69de29b..00000000 diff --git a/fixtures/src_template/expected/spec/support/api_client.cr b/fixtures/src_template/expected/spec/support/api_client.cr deleted file mode 100644 index 46d449a8..00000000 --- a/fixtures/src_template/expected/spec/support/api_client.cr +++ /dev/null @@ -1,12 +0,0 @@ -class ApiClient < Lucky::BaseHTTPClient - app AppServer.new - - def initialize - super - headers("Content-Type": "application/json") - end - - def self.auth(user : User) - new.headers("Authorization": UserToken.generate(user)) - end -end diff --git a/fixtures/src_template/expected/spec/support/factories/.keep b/fixtures/src_template/expected/spec/support/factories/.keep deleted file mode 100644 index e69de29b..00000000 diff --git a/fixtures/src_template/expected/src/actions/api_action.cr b/fixtures/src_template/expected/src/actions/api_action.cr deleted file mode 100644 index a16fd09e..00000000 --- a/fixtures/src_template/expected/src/actions/api_action.cr +++ /dev/null @@ -1,17 +0,0 @@ -# Include modules and add methods that are for all API requests -abstract class ApiAction < Lucky::Action - # APIs typically do not need to send cookie/session data. - # Remove this line if you want to send cookies in the response header. - disable_cookies - accepted_formats [:json] - - include Api::Auth::Helpers - - # By default all actions require sign in. - # Add 'include Api::Auth::SkipRequireAuthToken' to your actions to allow all requests. - include Api::Auth::RequireAuthToken - - # By default all actions are required to use underscores to separate words. - # Add 'include Lucky::SkipRouteStyleCheck' to your actions if you wish to ignore this check for specific routes. - include Lucky::EnforceUnderscoredRoute -end diff --git a/fixtures/src_template/expected/src/actions/errors/show.cr b/fixtures/src_template/expected/src/actions/errors/show.cr deleted file mode 100644 index a80eaa4d..00000000 --- a/fixtures/src_template/expected/src/actions/errors/show.cr +++ /dev/null @@ -1,42 +0,0 @@ -# This class handles error responses and reporting. -# -# https://luckyframework.org/guides/http-and-routing/error-handling -class Errors::Show < Lucky::ErrorAction - DEFAULT_MESSAGE = "Something went wrong." - default_format :json - dont_report [Lucky::RouteNotFoundError, Avram::RecordNotFoundError] - - def render(error : Lucky::RouteNotFoundError | Avram::RecordNotFoundError) - error_json "Not found", status: 404 - end - - # When an InvalidOperationError is raised, show a helpful error with the - # param that is invalid, and what was wrong with it. - def render(error : Avram::InvalidOperationError) - error_json \ - message: error.renderable_message, - details: error.renderable_details, - param: error.invalid_attribute_name, - status: 400 - end - - # Always keep this below other 'render' methods or it may override your - # custom 'render' methods. - def render(error : Lucky::RenderableError) - error_json error.renderable_message, status: error.renderable_status - end - - # If none of the 'render' methods return a response for the raised Exception, - # Lucky will use this method. - def default_render(error : Exception) : Lucky::Response - error_json DEFAULT_MESSAGE, status: 500 - end - - private def error_json(message : String, status : Int, details = nil, param = nil) - json ErrorSerializer.new(message: message, details: details, param: param), status: status - end - - private def report(error : Exception) : Nil - # Send to Rollbar, send an email, etc. - end -end diff --git a/fixtures/src_template/expected/src/actions/home/index.cr b/fixtures/src_template/expected/src/actions/home/index.cr deleted file mode 100644 index 5a72b779..00000000 --- a/fixtures/src_template/expected/src/actions/home/index.cr +++ /dev/null @@ -1,7 +0,0 @@ -class Home::Index < ApiAction - include Api::Auth::SkipRequireAuthToken - - get "/" do - json({hello: "Hello World from Home::Index"}) - end -end diff --git a/fixtures/src_template/expected/src/actions/mixins/.keep b/fixtures/src_template/expected/src/actions/mixins/.keep deleted file mode 100644 index e69de29b..00000000 diff --git a/fixtures/src_template/expected/src/app.cr b/fixtures/src_template/expected/src/app.cr deleted file mode 100644 index a658febc..00000000 --- a/fixtures/src_template/expected/src/app.cr +++ /dev/null @@ -1,20 +0,0 @@ -require "./shards" - -require "../config/server" -require "./app_database" -require "../config/**" -require "./models/base_model" -require "./models/mixins/**" -require "./models/**" -require "./queries/mixins/**" -require "./queries/**" -require "./operations/mixins/**" -require "./operations/**" -require "./serializers/base_serializer" -require "./serializers/**" -require "./emails/base_email" -require "./emails/**" -require "./actions/mixins/**" -require "./actions/**" -require "../db/migrations/**" -require "./app_server" \ No newline at end of file diff --git a/fixtures/src_template/expected/src/app_database.cr b/fixtures/src_template/expected/src/app_database.cr deleted file mode 100644 index 0efd4f50..00000000 --- a/fixtures/src_template/expected/src/app_database.cr +++ /dev/null @@ -1,2 +0,0 @@ -class AppDatabase < Avram::Database -end diff --git a/fixtures/src_template/expected/src/app_server.cr b/fixtures/src_template/expected/src/app_server.cr deleted file mode 100644 index 53f483d1..00000000 --- a/fixtures/src_template/expected/src/app_server.cr +++ /dev/null @@ -1,28 +0,0 @@ -class AppServer < Lucky::BaseAppServer - # Learn about middleware with HTTP::Handlers: - # https://luckyframework.org/guides/http-and-routing/http-handlers - def middleware : Array(HTTP::Handler) - [ - Lucky::RequestIdHandler.new, - Lucky::ForceSSLHandler.new, - Lucky::HttpMethodOverrideHandler.new, - Lucky::LogHandler.new, - Lucky::ErrorHandler.new(action: Errors::Show), - Lucky::RemoteIpHandler.new, - Lucky::RouteHandler.new, - - # Disabled in API mode: - # Lucky::StaticCompressionHandler.new("./public", file_ext: "gz", content_encoding: "gzip"), - # Lucky::StaticFileHandler.new("./public", fallthrough: false, directory_listing: false), - Lucky::RouteNotFoundHandler.new, - ] of HTTP::Handler - end - - def protocol - "http" - end - - def listen - server.listen(host, port, reuse_port: false) - end -end diff --git a/fixtures/src_template/expected/src/emails/base_email.cr b/fixtures/src_template/expected/src/emails/base_email.cr deleted file mode 100644 index 656f4f11..00000000 --- a/fixtures/src_template/expected/src/emails/base_email.cr +++ /dev/null @@ -1,15 +0,0 @@ -# Learn about sending emails -# https://luckyframework.org/guides/emails/sending-emails-with-carbon -abstract class BaseEmail < Carbon::Email - # You can add defaults using the 'inherited' hook - # - # Example: - # - # macro inherited - # from default_from - # end - # - # def default_from - # Carbon::Address.new("support@app.com") - # end -end diff --git a/fixtures/src_template/expected/src/models/base_model.cr b/fixtures/src_template/expected/src/models/base_model.cr deleted file mode 100644 index 6bafeb84..00000000 --- a/fixtures/src_template/expected/src/models/base_model.cr +++ /dev/null @@ -1,5 +0,0 @@ -abstract class BaseModel < Avram::Model - def self.database : Avram::Database.class - AppDatabase - end -end diff --git a/fixtures/src_template/expected/src/models/mixins/.keep b/fixtures/src_template/expected/src/models/mixins/.keep deleted file mode 100644 index e69de29b..00000000 diff --git a/fixtures/src_template/expected/src/operations/.keep b/fixtures/src_template/expected/src/operations/.keep deleted file mode 100644 index e69de29b..00000000 diff --git a/fixtures/src_template/expected/src/operations/mixins/.keep b/fixtures/src_template/expected/src/operations/mixins/.keep deleted file mode 100644 index e69de29b..00000000 diff --git a/fixtures/src_template/expected/src/queries/.keep b/fixtures/src_template/expected/src/queries/.keep deleted file mode 100644 index e69de29b..00000000 diff --git a/fixtures/src_template/expected/src/queries/mixins/.keep b/fixtures/src_template/expected/src/queries/mixins/.keep deleted file mode 100644 index e69de29b..00000000 diff --git a/fixtures/src_template/expected/src/serializers/.keep b/fixtures/src_template/expected/src/serializers/.keep deleted file mode 100644 index e69de29b..00000000 diff --git a/fixtures/src_template/expected/src/serializers/base_serializer.cr b/fixtures/src_template/expected/src/serializers/base_serializer.cr deleted file mode 100644 index e769f5c0..00000000 --- a/fixtures/src_template/expected/src/serializers/base_serializer.cr +++ /dev/null @@ -1,18 +0,0 @@ -abstract class BaseSerializer - include Lucky::Serializable - - def self.for_collection(collection : Enumerable, *args, **named_args) : Array(self) - collection.map do |object| - new(object, *args, **named_args) - end - end - - def self.for_collection(collection : Enumerable, pages : Lucky::Paginator, *args, **named_args) - { - "items" => collection.map do |object| - new(object, *args, **named_args) - end, - "pagination" => PaginationSerializer.new(pages), - } - end -end diff --git a/fixtures/src_template/expected/src/serializers/error_serializer.cr b/fixtures/src_template/expected/src/serializers/error_serializer.cr deleted file mode 100644 index b7b55283..00000000 --- a/fixtures/src_template/expected/src/serializers/error_serializer.cr +++ /dev/null @@ -1,14 +0,0 @@ -# This is the default error serializer generated by Lucky. -# Feel free to customize it in any way you like. -class ErrorSerializer < BaseSerializer - def initialize( - @message : String, - @details : String? = nil, - @param : String? = nil, # so you can track which param (if any) caused the problem - ) - end - - def render - {message: @message, param: @param, details: @details} - end -end diff --git a/fixtures/src_template/expected/src/serializers/pagination_serializer.cr b/fixtures/src_template/expected/src/serializers/pagination_serializer.cr deleted file mode 100644 index 9e44788c..00000000 --- a/fixtures/src_template/expected/src/serializers/pagination_serializer.cr +++ /dev/null @@ -1,15 +0,0 @@ -# This is the default pagination serializer generated by Lucky. -# Feel free to customize it in any way you like. -class PaginationSerializer < BaseSerializer - def initialize(@pages : Lucky::Paginator) - end - - def render - { - next_page: @pages.path_to_next, - previous_page: @pages.path_to_previous, - total_items: @pages.item_count, - total_pages: @pages.total, - } - end -end diff --git a/fixtures/src_template/expected/src/shards.cr b/fixtures/src_template/expected/src/shards.cr deleted file mode 100644 index 7cadec18..00000000 --- a/fixtures/src_template/expected/src/shards.cr +++ /dev/null @@ -1,10 +0,0 @@ -# Load .env file before any other config or app code -require "lucky_env" -LuckyEnv.load?(".env") - -# Require your shards here -require "lucky" -require "avram/lucky" -require "carbon" -require "authentic" -require "jwt" diff --git a/fixtures/src_template/expected/src/start_server.cr b/fixtures/src_template/expected/src/start_server.cr deleted file mode 100644 index de8af78e..00000000 --- a/fixtures/src_template/expected/src/start_server.cr +++ /dev/null @@ -1,17 +0,0 @@ -require "./app" - -Habitat.raise_if_missing_settings! - -if LuckyEnv.development? - Avram::Migrator::Runner.new.ensure_migrated! - Avram::SchemaEnforcer.ensure_correct_column_mappings! -end - -app_server = AppServer.new -puts "Listening on http://#{app_server.host}:#{app_server.port}" - -Signal::INT.trap do - app_server.close -end - -app_server.listen diff --git a/fixtures/src_template/expected/src/test_project.cr b/fixtures/src_template/expected/src/test_project.cr deleted file mode 100644 index 68e1a8d2..00000000 --- a/fixtures/src_template/expected/src/test_project.cr +++ /dev/null @@ -1,6 +0,0 @@ -# Typically you will not use or modify this file. 'shards build' and some -# other crystal tools will sometimes use this. -# -# When this file is compiled/run it will require and run 'start_server', -# which as its name implies will start the server for you app. -require "./start_server" diff --git a/fixtures/src_template/expected/tasks.cr b/fixtures/src_template/expected/tasks.cr deleted file mode 100644 index 5a892d4d..00000000 --- a/fixtures/src_template/expected/tasks.cr +++ /dev/null @@ -1,25 +0,0 @@ -# This file loads your app and all your tasks when running 'lucky' -# -# Run 'lucky --help' to see all available tasks. -# -# Learn to create your own tasks: -# https://luckyframework.org/guides/command-line-tasks/custom-tasks - -# See `LuckyEnv#task?` -ENV["LUCKY_TASK"] = "true" - -# Load Lucky and the app (actions, models, etc.) -require "./src/app" -require "lucky_task" - -# You can add your own tasks here in the ./tasks folder -require "./tasks/**" - -# Load migrations -require "./db/migrations/**" - -# Load Lucky tasks (dev, routes, etc.) -require "lucky/tasks/**" -require "avram/lucky/tasks" - -LuckyTask::Runner.run diff --git a/fixtures/src_template/expected/tasks/.keep b/fixtures/src_template/expected/tasks/.keep deleted file mode 100644 index e69de29b..00000000 diff --git a/fixtures/src_template/expected/tasks/db/seed/required_data.cr b/fixtures/src_template/expected/tasks/db/seed/required_data.cr deleted file mode 100644 index d866040f..00000000 --- a/fixtures/src_template/expected/tasks/db/seed/required_data.cr +++ /dev/null @@ -1,30 +0,0 @@ -require "../../../spec/support/factories/**" - -# Add seeds here that are *required* for your app to work. -# For example, you might need at least one admin user or you might need at least -# one category for your blog posts for the app to work. -# -# Use `Db::Seed::SampleData` if your only want to add sample data helpful for -# development. -class Db::Seed::RequiredData < LuckyTask::Task - summary "Add database records required for the app to work" - - def call - # Using a Avram::Factory: - # - # Use the defaults, but override just the email - # UserFactory.create &.email("me@example.com") - - # Using a SaveOperation: - # - # SaveUser.create!(email: "me@example.com", name: "Jane") - # - # You likely want to be able to run this file more than once. To do that, - # only create the record if it doesn't exist yet: - # - # unless UserQuery.new.email("me@example.com").first? - # SaveUser.create!(email: "me@example.com", name: "Jane") - # end - puts "Done adding required data" - end -end diff --git a/fixtures/src_template/expected/tasks/db/seed/sample_data.cr b/fixtures/src_template/expected/tasks/db/seed/sample_data.cr deleted file mode 100644 index 231d7e8d..00000000 --- a/fixtures/src_template/expected/tasks/db/seed/sample_data.cr +++ /dev/null @@ -1,30 +0,0 @@ -require "../../../spec/support/factories/**" - -# Add sample data helpful for development, e.g. (fake users, blog posts, etc.) -# -# Use `Db::Seed::RequiredData` if you need to create data *required* for your -# app to work. -class Db::Seed::SampleData < LuckyTask::Task - summary "Add sample database records helpful for development" - - def call - # Using an Avram::Factory: - # - # Use the defaults, but override just the email - # UserFactory.create &.email("me@example.com") - - # Using a SaveOperation: - # ``` - # SignUpUser.create!(email: "me@example.com", password: "test123", password_confirmation: "test123") - # ``` - # - # You likely want to be able to run this file more than once. To do that, - # only create the record if it doesn't exist yet: - # ``` - # if UserQuery.new.email("me@example.com").none? - # SignUpUser.create!(email: "me@example.com", password: "test123", password_confirmation: "test123") - # end - # ``` - puts "Done adding sample data" - end -end diff --git a/fixtures/src_template__api_only/expected/.crystal-version b/fixtures/src_template__api_only/expected/.crystal-version deleted file mode 100644 index 41c11ffb..00000000 --- a/fixtures/src_template__api_only/expected/.crystal-version +++ /dev/null @@ -1 +0,0 @@ -1.16.1 diff --git a/fixtures/src_template__api_only/expected/.env b/fixtures/src_template__api_only/expected/.env deleted file mode 100644 index e69de29b..00000000 diff --git a/fixtures/src_template__api_only/expected/.github/workflows/ci.yml b/fixtures/src_template__api_only/expected/.github/workflows/ci.yml deleted file mode 100644 index 67005cad..00000000 --- a/fixtures/src_template__api_only/expected/.github/workflows/ci.yml +++ /dev/null @@ -1,88 +0,0 @@ -name: test-project CI - -on: - push: - branches: "*" - pull_request: - branches: "*" - -jobs: - check-format: - strategy: - fail-fast: false - matrix: - crystal_version: - - 1.16.1 - experimental: - - false - runs-on: ubuntu-latest - continue-on-error: ${{ matrix.experimental }} - steps: - - uses: actions/checkout@v4 - - name: Install Crystal - uses: crystal-lang/install-crystal@v1 - with: - crystal: ${{ matrix.crystal_version }} - - name: Format - run: crystal tool format --check - - specs: - strategy: - fail-fast: false - matrix: - crystal_version: - - 1.16.1 - experimental: - - false - runs-on: ubuntu-latest - env: - LUCKY_ENV: test - DB_HOST: localhost - continue-on-error: ${{ matrix.experimental }} - services: - postgres: - image: postgres:14-alpine - env: - POSTGRES_PASSWORD: postgres - ports: - - 5432:5432 - # Set health checks to wait until postgres has started - options: >- - --health-cmd pg_isready - --health-interval 10s - --health-timeout 5s - --health-retries 5 - - steps: - - uses: actions/checkout@v4 - - name: Install Crystal - uses: crystal-lang/install-crystal@v1 - with: - crystal: ${{ matrix.crystal_version }} - - - name: Set up Crystal cache - uses: actions/cache@v4 - id: crystal-cache - with: - path: | - ~/.cache/crystal - lib - key: ${{ runner.os }}-crystal-${{ hashFiles('**/shard.lock') }} - restore-keys: | - ${{ runner.os }}-crystal- - - - name: Install shards - if: steps.crystal-cache.outputs.cache-hit != 'true' - run: shards check || shards install - - - name: Build lucky_tasks - run: crystal build tasks.cr -o ./lucky_tasks - - - name: Prepare database - run: | - ./lucky_tasks db.create - ./lucky_tasks db.migrate - ./lucky_tasks db.seed.required_data - - - name: Run tests - run: crystal spec \ No newline at end of file diff --git a/fixtures/src_template__api_only/expected/Procfile b/fixtures/src_template__api_only/expected/Procfile deleted file mode 100644 index e524d70d..00000000 --- a/fixtures/src_template__api_only/expected/Procfile +++ /dev/null @@ -1,2 +0,0 @@ -web: bin/app -release: lucky db.migrate diff --git a/fixtures/src_template__api_only/expected/Procfile.dev b/fixtures/src_template__api_only/expected/Procfile.dev deleted file mode 100644 index dc39e8fe..00000000 --- a/fixtures/src_template__api_only/expected/Procfile.dev +++ /dev/null @@ -1,2 +0,0 @@ -system_check: crystal script/system_check.cr -web: lucky watch diff --git a/fixtures/src_template__api_only/expected/README.md b/fixtures/src_template__api_only/expected/README.md deleted file mode 100644 index da2d97cc..00000000 --- a/fixtures/src_template__api_only/expected/README.md +++ /dev/null @@ -1,23 +0,0 @@ -# test-project - -This is a project written using [Lucky](https://luckyframework.org). Enjoy! - -### Setting up the project - -1. [Install required dependencies](https://luckyframework.org/guides/getting-started/installing#install-required-dependencies) -1. Update database settings in `config/database.cr` -1. Run `script/setup` -1. Run `lucky dev` to start the app - -### Using Docker for development - -1. [Install Docker](https://docs.docker.com/engine/install/) -1. Run `docker compose up` - -The Docker container will boot all of the necessary components needed to run your Lucky application. -To configure the container, update the `docker-compose.yml` file, and the `docker/development.dockerfile` file. - - -### Learning Lucky - -Lucky uses the [Crystal](https://crystal-lang.org) programming language. You can learn about Lucky from the [Lucky Guides](https://luckyframework.org/guides/getting-started/why-lucky). diff --git a/fixtures/src_template__api_only/expected/config/application.cr b/fixtures/src_template__api_only/expected/config/application.cr deleted file mode 100644 index c807149a..00000000 --- a/fixtures/src_template__api_only/expected/config/application.cr +++ /dev/null @@ -1,24 +0,0 @@ -# This file may be used for custom Application configurations. -# It will be loaded before other config files. -# -# Read more on configuration: -# https://luckyframework.org/guides/getting-started/configuration#configuring-your-own-code - -# Use this code as an example: -# -# ``` -# module Application -# Habitat.create do -# setting support_email : String -# setting lock_with_basic_auth : Bool -# end -# end -# -# Application.configure do |settings| -# settings.support_email = "support@myapp.io" -# settings.lock_with_basic_auth = LuckyEnv.staging? -# end -# -# # In your application, call -# # `Application.settings.support_email` anywhere you need it. -# ``` diff --git a/fixtures/src_template__api_only/expected/config/colors.cr b/fixtures/src_template__api_only/expected/config/colors.cr deleted file mode 100644 index 761ae940..00000000 --- a/fixtures/src_template__api_only/expected/config/colors.cr +++ /dev/null @@ -1,4 +0,0 @@ -# This enables the color output when in development or test -# Check out the Colorize docs for more information -# https://crystal-lang.org/api/Colorize.html -Colorize.enabled = LuckyEnv.development? || LuckyEnv.test? diff --git a/fixtures/src_template__api_only/expected/config/cookies.cr b/fixtures/src_template__api_only/expected/config/cookies.cr deleted file mode 100644 index 2d5055f2..00000000 --- a/fixtures/src_template__api_only/expected/config/cookies.cr +++ /dev/null @@ -1,25 +0,0 @@ -require "./server" - -Lucky::Session.configure do |settings| - settings.key = "_test_project_session" -end - -Lucky::CookieJar.configure do |settings| - settings.on_set = ->(cookie : HTTP::Cookie) { - # If ForceSSLHandler is enabled, only send cookies over HTTPS - cookie.secure(Lucky::ForceSSLHandler.settings.enabled) - - # By default, don't allow reading cookies with JavaScript - cookie.http_only(true) - - # Restrict cookies to a first-party or same-site context - cookie.samesite(:lax) - - # Set all cookies to the root path by default - cookie.path("/") - - # You can set other defaults for cookies here. For example: - # - # cookie.expires(1.year.from_now).domain("mydomain.com") - } -end diff --git a/fixtures/src_template__api_only/expected/config/database.cr b/fixtures/src_template__api_only/expected/config/database.cr deleted file mode 100644 index f614299a..00000000 --- a/fixtures/src_template__api_only/expected/config/database.cr +++ /dev/null @@ -1,29 +0,0 @@ -database_name = "test_project_#{LuckyEnv.environment}" - -AppDatabase.configure do |settings| - if LuckyEnv.production? - settings.credentials = Avram::Credentials.parse(ENV["DATABASE_URL"]) - else - settings.credentials = Avram::Credentials.parse?(ENV["DATABASE_URL"]?) || Avram::Credentials.new( - database: database_name, - hostname: ENV["DB_HOST"]? || "localhost", - port: ENV["DB_PORT"]?.try(&.to_i) || 5432, - # Some common usernames are "postgres", "root", or your system username (run 'whoami') - username: ENV["DB_USERNAME"]? || "postgres", - # Some Postgres installations require no password. Use "" if that is the case. - password: ENV["DB_PASSWORD"]? || "postgres" - ) - end -end - -Avram.configure do |settings| - settings.database_to_migrate = AppDatabase - - # In production, allow lazy loading (N+1). - # In development and test, raise an error if you forget to preload associations - settings.lazy_load_enabled = LuckyEnv.production? - - # Always parse `Time` values with these specific formats. - # Used for both database values, and datetime input fields. - # settings.time_formats << "%F" -end diff --git a/fixtures/src_template__api_only/expected/config/email.cr b/fixtures/src_template__api_only/expected/config/email.cr deleted file mode 100644 index 7c875449..00000000 --- a/fixtures/src_template__api_only/expected/config/email.cr +++ /dev/null @@ -1,26 +0,0 @@ -require "carbon_sendgrid_adapter" - -BaseEmail.configure do |settings| - if LuckyEnv.production? - # If you don't need to send emails, set the adapter to DevAdapter instead: - # - # settings.adapter = Carbon::DevAdapter.new - # - # If you do need emails, get a key from SendGrid and set an ENV variable - send_grid_key = send_grid_key_from_env - settings.adapter = Carbon::SendGridAdapter.new(api_key: send_grid_key) - elsif LuckyEnv.development? - settings.adapter = Carbon::DevAdapter.new(print_emails: true) - else - settings.adapter = Carbon::DevAdapter.new - end -end - -private def send_grid_key_from_env - ENV["SEND_GRID_KEY"]? || raise_missing_key_message -end - -private def raise_missing_key_message - puts "Missing SEND_GRID_KEY. Set the SEND_GRID_KEY env variable to 'unused' if not sending emails, or set the SEND_GRID_KEY ENV var.".colorize.red - exit(1) -end diff --git a/fixtures/src_template__api_only/expected/config/env.cr b/fixtures/src_template__api_only/expected/config/env.cr deleted file mode 100644 index 3f364072..00000000 --- a/fixtures/src_template__api_only/expected/config/env.cr +++ /dev/null @@ -1,33 +0,0 @@ -# Environments are managed using `LuckyEnv`. By default, development, production -# and test are supported. See -# https://luckyframework.org/guides/getting-started/configuration for details. -# -# The default environment is development unless the environment variable -# LUCKY_ENV is set. -# -# Example: -# ``` -# LuckyEnv.environment # => "development" -# LuckyEnv.development? # => true -# LuckyEnv.production? # => false -# LuckyEnv.test? # => false -# ``` -# -# New environments can be added using the `LuckyEnv.add_env` macro. -# -# Example: -# ``` -# LuckyEnv.add_env :staging -# LuckyEnv.staging? # => false -# ``` -# -# To determine whether or not a `LuckyTask` is currently running, you can use -# the `LuckyEnv.task?` predicate. -# -# Example: -# ``` -# LuckyEnv.task? # => false -# ``` - -# Add a staging environment. -# LuckyEnv.add_env :staging diff --git a/fixtures/src_template__api_only/expected/config/error_handler.cr b/fixtures/src_template__api_only/expected/config/error_handler.cr deleted file mode 100644 index c6b736e3..00000000 --- a/fixtures/src_template__api_only/expected/config/error_handler.cr +++ /dev/null @@ -1,3 +0,0 @@ -Lucky::ErrorHandler.configure do |settings| - settings.show_debug_output = !LuckyEnv.production? -end diff --git a/fixtures/src_template__api_only/expected/config/log.cr b/fixtures/src_template__api_only/expected/config/log.cr deleted file mode 100644 index a43940d9..00000000 --- a/fixtures/src_template__api_only/expected/config/log.cr +++ /dev/null @@ -1,50 +0,0 @@ -require "file_utils" - -if LuckyEnv.test? - # Logs to `tmp/test.log` so you can see what's happening without having - # a bunch of log output in your spec results. - FileUtils.mkdir_p("tmp") - - backend = Log::IOBackend.new(File.new("tmp/test.log", mode: "w")) - backend.formatter = Lucky::PrettyLogFormatter.proc - Log.dexter.configure(:debug, backend) -elsif LuckyEnv.production? - # Lucky uses JSON in production so logs can be searched more easily - # - # If you want logs like in development use 'Lucky::PrettyLogFormatter.proc'. - backend = Log::IOBackend.new - backend.formatter = Dexter::JSONLogFormatter.proc - Log.dexter.configure(:info, backend) -else - # Use a pretty formatter printing to STDOUT in development - backend = Log::IOBackend.new - backend.formatter = Lucky::PrettyLogFormatter.proc - Log.dexter.configure(:debug, backend) - DB::Log.level = :info -end - -# Lucky only logs when before/after pipes halt by redirecting, or rendering a -# response. Pipes that run without halting are not logged. -# -# If you want to log every pipe that runs, set the log level to ':info' -Lucky::ContinuedPipeLog.dexter.configure(:none) - -# Lucky only logs failed queries by default. -# -# Set the log to ':info' to log all queries -Avram::QueryLog.dexter.configure(:none) - -# Subscribe to Pulsar events to log when queries are made, -# queries fail, or save operations fail. Remove this to -# disable these log events without disabling all logging. -Avram.initialize_logging - -# Skip logging static assets requests in development -Lucky::LogHandler.configure do |settings| - if LuckyEnv.development? - settings.skip_if = ->(context : HTTP::Server::Context) { - context.request.method.downcase == "get" && - context.request.resource.starts_with?(/\/css\/|\/js\/|\/assets\/|\/favicon\.ico/) - } - end -end diff --git a/fixtures/src_template__api_only/expected/config/route_helper.cr b/fixtures/src_template__api_only/expected/config/route_helper.cr deleted file mode 100644 index ede1f328..00000000 --- a/fixtures/src_template__api_only/expected/config/route_helper.cr +++ /dev/null @@ -1,10 +0,0 @@ -# This is used when generating URLs for your application -Lucky::RouteHelper.configure do |settings| - if LuckyEnv.production? - # Example: https://my_app.com - settings.base_uri = ENV.fetch("APP_DOMAIN") - else - # Set domain to the default host/port in development/test - settings.base_uri = "http://localhost:#{Lucky::ServerSettings.port}" - end -end diff --git a/fixtures/src_template__api_only/expected/config/server.cr b/fixtures/src_template__api_only/expected/config/server.cr deleted file mode 100644 index b7cca25c..00000000 --- a/fixtures/src_template__api_only/expected/config/server.cr +++ /dev/null @@ -1,68 +0,0 @@ -# Here is where you configure the Lucky server -# -# Look at config/route_helper.cr if you want to change the domain used when -# generating links with `Action.url`. -Lucky::Server.configure do |settings| - if LuckyEnv.production? - settings.secret_key_base = secret_key_from_env - settings.host = "0.0.0.0" - settings.port = ENV["PORT"].to_i - settings.gzip_enabled = true - # By default certain content types will be gzipped. - # For a full list look in - # https://github.com/luckyframework/lucky/blob/main/src/lucky/server.cr - # To add additional extensions do something like this: - # settings.gzip_content_types << "content/type" - else - settings.secret_key_base = "1234567890" - # Change host/port in config/watch.yml - # Alternatively, you can set the DEV_PORT env to set the port for local development - settings.host = Lucky::ServerSettings.host - settings.port = Lucky::ServerSettings.port - end - - # Configure the asset build system (default is Vite) - settings.asset_build_system = Lucky::AssetBuilder::Vite.new - - # Configure asset host for Vite - if LuckyEnv.development? - # In development, Vite serves assets from its dev server - settings.asset_host = "http://localhost:3001" - elsif LuckyEnv.production? - # In production, Lucky serves the built assets - # You could also use a CDN here: - # settings.asset_host = "https://mycdnhost.com" - settings.asset_host = "" - else - settings.asset_host = "" - end -end - -Lucky::ForceSSLHandler.configure do |settings| - # To force SSL in production, uncomment the lines below. - # This will cause http requests to be redirected to https: - # - # settings.enabled = LuckyEnv.production? - # settings.strict_transport_security = {max_age: 1.year, include_subdomains: true} - # - # Or, leave it disabled: - settings.enabled = false -end - -# Set a unique ID for each HTTP request. -# To enable the request ID, uncomment the lines below. -# You can set your own custom String, or use a random UUID. -# Lucky::RequestIdHandler.configure do |settings| -# settings.set_request_id = ->(context : HTTP::Server::Context) { -# UUID.random.to_s -# } -# end - -private def secret_key_from_env - ENV["SECRET_KEY_BASE"]? || raise_missing_secret_key_in_production -end - -private def raise_missing_secret_key_in_production - puts "Please set the SECRET_KEY_BASE environment variable. You can generate a secret key with 'lucky gen.secret_key'".colorize.red - exit(1) -end \ No newline at end of file diff --git a/fixtures/src_template__api_only/expected/config/watch.yml b/fixtures/src_template__api_only/expected/config/watch.yml deleted file mode 100644 index 3a59b410..00000000 --- a/fixtures/src_template__api_only/expected/config/watch.yml +++ /dev/null @@ -1,3 +0,0 @@ -host: 127.0.0.1 -port: 3000 -reload_port: 3001 diff --git a/fixtures/src_template__api_only/expected/db/migrations/.keep b/fixtures/src_template__api_only/expected/db/migrations/.keep deleted file mode 100644 index e69de29b..00000000 diff --git a/fixtures/src_template__api_only/expected/docker-compose.yml b/fixtures/src_template__api_only/expected/docker-compose.yml deleted file mode 100644 index d00779db..00000000 --- a/fixtures/src_template__api_only/expected/docker-compose.yml +++ /dev/null @@ -1,45 +0,0 @@ -version: "3.8" -services: - lucky: - build: - context: . - dockerfile: docker/development.dockerfile - environment: - DATABASE_URL: postgres://lucky:password@postgres:5432/lucky - DEV_HOST: "0.0.0.0" - volumes: - - .:/app - - node_modules:/app/node_modules - - shards_lib:/app/lib - - app_bin:/app/bin - - build_cache:/root/.cache - depends_on: - - postgres - ports: - - 3000:3000 # This is the Lucky Server port - - 3001:3001 # This is the Lucky watcher reload port - - entrypoint: ["docker/dev_entrypoint.sh"] - - postgres: - image: postgres:14-alpine - environment: - POSTGRES_USER: lucky - POSTGRES_PASSWORD: password - POSTGRES_DB: lucky - volumes: - - postgres_data:/var/lib/postgresql/data - ports: - # The postgres database container is exposed on the host at port 6543 to - # allow connecting directly to it with postgres clients. The port differs - # from the postgres default to avoid conflict with existing postgres - # servers. Connect to a running postgres container with: - # postgres://lucky:password@localhost:6543/lucky - - 6543:5432 - -volumes: - postgres_data: - node_modules: - shards_lib: - app_bin: - build_cache: diff --git a/fixtures/src_template__api_only/expected/docker/dev_entrypoint.sh b/fixtures/src_template__api_only/expected/docker/dev_entrypoint.sh deleted file mode 100755 index f5aab877..00000000 --- a/fixtures/src_template__api_only/expected/docker/dev_entrypoint.sh +++ /dev/null @@ -1,44 +0,0 @@ -#!/bin/bash - -set -euo pipefail - -# This is the entrypoint script used for development docker workflows. -# By default it will: -# - Install dependencies. -# - Run migrations. -# - Start the dev server. -# It also accepts any commands to be run instead. - - -warnfail () { - echo "$@" >&2 - exit 1 -} - -case ${1:-} in - "") # If no arguments are provided, start lucky dev server. - ;; - - *) # If any arguments are provided, execute them instead. - exec "$@" -esac - -if ! [ -d bin ] ; then - echo 'Creating bin directory' - mkdir bin -fi -if ! shards check ; then - echo 'Installing shards...' - shards install -fi - -echo 'Waiting for postgres to be available...' -./docker/wait-for-it.sh -q postgres:5432 - -if ! psql -d "$DATABASE_URL" -c '\d migrations' > /dev/null ; then - echo 'Finishing database setup...' - lucky db.migrate -fi - -echo 'Starting lucky dev server...' -exec lucky dev diff --git a/fixtures/src_template__api_only/expected/docker/development.dockerfile b/fixtures/src_template__api_only/expected/docker/development.dockerfile deleted file mode 100644 index a4e5b267..00000000 --- a/fixtures/src_template__api_only/expected/docker/development.dockerfile +++ /dev/null @@ -1,25 +0,0 @@ -FROM crystallang/crystal:1.16.1 - -# Install utilities required to make this Dockerfile run -RUN apt-get update && \ - apt-get install -y wget - -# Apt installs: -# - Postgres cli tools are required for lucky-cli. -# - tmux is required for the Overmind process manager. -RUN apt-get update && \ - apt-get install -y postgresql-client tmux && \ - rm -rf /var/lib/apt/lists/* - -# Install lucky cli -WORKDIR /lucky/cli -RUN git clone https://github.com/luckyframework/lucky_cli . && \ - git checkout v1.3.0 && \ - shards build --without-development && \ - cp bin/lucky /usr/bin - -WORKDIR /app -ENV DATABASE_URL=postgres://postgres:postgres@host.docker.internal:5432/postgres -EXPOSE 3000 -EXPOSE 3001 - diff --git a/fixtures/src_template__api_only/expected/docker/wait-for-it.sh b/fixtures/src_template__api_only/expected/docker/wait-for-it.sh deleted file mode 100755 index 06e0638c..00000000 --- a/fixtures/src_template__api_only/expected/docker/wait-for-it.sh +++ /dev/null @@ -1,189 +0,0 @@ -#!/usr/bin/bash -# -# Pulled from https://github.com/vishnubob/wait-for-it on 2022-02-28. -# Licensed under the MIT license as of 81b1373f. -# -# Below this line, wait-for-it is the original work of the author. -# -# Use this script to test if a given TCP host/port are available - -WAITFORIT_cmdname=${0##*/} - -echoerr() { if [[ $WAITFORIT_QUIET -ne 1 ]]; then echo "$@" 1>&2; fi } - -usage() -{ - cat << USAGE >&2 -Usage: - $WAITFORIT_cmdname host:port [-s] [-t timeout] [-- command args] - -h HOST | --host=HOST Host or IP under test - -p PORT | --port=PORT TCP port under test - Alternatively, you specify the host and port as host:port - -s | --strict Only execute subcommand if the test succeeds - -q | --quiet Don't output any status messages - -t TIMEOUT | --timeout=TIMEOUT - Timeout in seconds, zero for no timeout - -- COMMAND ARGS Execute command with args after the test finishes -USAGE - exit 1 -} - -wait_for() -{ - if [[ $WAITFORIT_TIMEOUT -gt 0 ]]; then - echoerr "$WAITFORIT_cmdname: waiting $WAITFORIT_TIMEOUT seconds for $WAITFORIT_HOST:$WAITFORIT_PORT" - else - echoerr "$WAITFORIT_cmdname: waiting for $WAITFORIT_HOST:$WAITFORIT_PORT without a timeout" - fi - WAITFORIT_start_ts=$(date +%s) - while : - do - if [[ $WAITFORIT_ISBUSY -eq 1 ]]; then - nc -z $WAITFORIT_HOST $WAITFORIT_PORT - WAITFORIT_result=$? - else - (echo -n > /dev/tcp/$WAITFORIT_HOST/$WAITFORIT_PORT) >/dev/null 2>&1 - WAITFORIT_result=$? - fi - if [[ $WAITFORIT_result -eq 0 ]]; then - WAITFORIT_end_ts=$(date +%s) - echoerr "$WAITFORIT_cmdname: $WAITFORIT_HOST:$WAITFORIT_PORT is available after $((WAITFORIT_end_ts - WAITFORIT_start_ts)) seconds" - break - fi - sleep 1 - done - return $WAITFORIT_result -} - -wait_for_wrapper() -{ - # In order to support SIGINT during timeout: http://unix.stackexchange.com/a/57692 - if [[ $WAITFORIT_QUIET -eq 1 ]]; then - timeout $WAITFORIT_BUSYTIMEFLAG $WAITFORIT_TIMEOUT $0 --quiet --child --host=$WAITFORIT_HOST --port=$WAITFORIT_PORT --timeout=$WAITFORIT_TIMEOUT & - else - timeout $WAITFORIT_BUSYTIMEFLAG $WAITFORIT_TIMEOUT $0 --child --host=$WAITFORIT_HOST --port=$WAITFORIT_PORT --timeout=$WAITFORIT_TIMEOUT & - fi - WAITFORIT_PID=$! - trap "kill -INT -$WAITFORIT_PID" INT - wait $WAITFORIT_PID - WAITFORIT_RESULT=$? - if [[ $WAITFORIT_RESULT -ne 0 ]]; then - echoerr "$WAITFORIT_cmdname: timeout occurred after waiting $WAITFORIT_TIMEOUT seconds for $WAITFORIT_HOST:$WAITFORIT_PORT" - fi - return $WAITFORIT_RESULT -} - -# process arguments -while [[ $# -gt 0 ]] -do - case "$1" in - *:* ) - WAITFORIT_hostport=(${1//:/ }) - WAITFORIT_HOST=${WAITFORIT_hostport[0]} - WAITFORIT_PORT=${WAITFORIT_hostport[1]} - shift 1 - ;; - --child) - WAITFORIT_CHILD=1 - shift 1 - ;; - -q | --quiet) - WAITFORIT_QUIET=1 - shift 1 - ;; - -s | --strict) - WAITFORIT_STRICT=1 - shift 1 - ;; - -h) - WAITFORIT_HOST="$2" - if [[ $WAITFORIT_HOST == "" ]]; then break; fi - shift 2 - ;; - --host=*) - WAITFORIT_HOST="${1#*=}" - shift 1 - ;; - -p) - WAITFORIT_PORT="$2" - if [[ $WAITFORIT_PORT == "" ]]; then break; fi - shift 2 - ;; - --port=*) - WAITFORIT_PORT="${1#*=}" - shift 1 - ;; - -t) - WAITFORIT_TIMEOUT="$2" - if [[ $WAITFORIT_TIMEOUT == "" ]]; then break; fi - shift 2 - ;; - --timeout=*) - WAITFORIT_TIMEOUT="${1#*=}" - shift 1 - ;; - --) - shift - WAITFORIT_CLI=("$@") - break - ;; - --help) - usage - ;; - *) - echoerr "Unknown argument: $1" - usage - ;; - esac -done - -if [[ "$WAITFORIT_HOST" == "" || "$WAITFORIT_PORT" == "" ]]; then - echoerr "Error: you need to provide a host and port to test." - usage -fi - -WAITFORIT_TIMEOUT=${WAITFORIT_TIMEOUT:-15} -WAITFORIT_STRICT=${WAITFORIT_STRICT:-0} -WAITFORIT_CHILD=${WAITFORIT_CHILD:-0} -WAITFORIT_QUIET=${WAITFORIT_QUIET:-0} - -# Check to see if timeout is from busybox? -WAITFORIT_TIMEOUT_PATH=$(type -p timeout) -WAITFORIT_TIMEOUT_PATH=$(realpath $WAITFORIT_TIMEOUT_PATH 2>/dev/null || readlink -f $WAITFORIT_TIMEOUT_PATH) - -WAITFORIT_BUSYTIMEFLAG="" -if [[ $WAITFORIT_TIMEOUT_PATH =~ "busybox" ]]; then - WAITFORIT_ISBUSY=1 - # Check if busybox timeout uses -t flag - # (recent Alpine versions don't support -t anymore) - if timeout &>/dev/stdout | grep -q -e '-t '; then - WAITFORIT_BUSYTIMEFLAG="-t" - fi -else - WAITFORIT_ISBUSY=0 -fi - -if [[ $WAITFORIT_CHILD -gt 0 ]]; then - wait_for - WAITFORIT_RESULT=$? - exit $WAITFORIT_RESULT -else - if [[ $WAITFORIT_TIMEOUT -gt 0 ]]; then - wait_for_wrapper - WAITFORIT_RESULT=$? - else - wait_for - WAITFORIT_RESULT=$? - fi -fi - -if [[ $WAITFORIT_CLI != "" ]]; then - if [[ $WAITFORIT_RESULT -ne 0 && $WAITFORIT_STRICT -eq 1 ]]; then - echoerr "$WAITFORIT_cmdname: strict mode, refusing to execute subprocess" - exit $WAITFORIT_RESULT - fi - exec "${WAITFORIT_CLI[@]}" -else - exit $WAITFORIT_RESULT -fi - diff --git a/fixtures/src_template__api_only/expected/script/helpers/function_helpers.cr b/fixtures/src_template__api_only/expected/script/helpers/function_helpers.cr deleted file mode 100644 index 8abcb6a2..00000000 --- a/fixtures/src_template__api_only/expected/script/helpers/function_helpers.cr +++ /dev/null @@ -1,32 +0,0 @@ -require "colorize" - -# These are helper methods provided to help keep your code -# clean. Add new methods, or alter these as needed. - -def notice(message : String) : Nil - puts "\n▸ #{message}" -end - -def print_done : Nil - puts "✔ Done" -end - -def print_error(message : String) : Nil - puts "There is a problem with your system setup:\n".colorize.red.bold - puts "#{message}\n".colorize.red.bold - Process.exit(1) -end - -def command_not_found(command : String) : Bool - Process.find_executable(command).nil? -end - -def command_not_running(command : String, *args) : Bool - output = IO::Memory.new - code = Process.run(command, args, output: output).exit_code - code > 0 -end - -def run_command(command : String, *args) : Nil - Process.run(command, args, output: STDOUT, error: STDERR, input: STDIN) -end diff --git a/fixtures/src_template__api_only/expected/script/setup.cr b/fixtures/src_template__api_only/expected/script/setup.cr deleted file mode 100644 index f8d4a907..00000000 --- a/fixtures/src_template__api_only/expected/script/setup.cr +++ /dev/null @@ -1,28 +0,0 @@ -require "./helpers/*" - -notice "Running System Check" - -require "./system_check" - -print_done - - -notice "Installing shards" -run_command "shards", "install" - -if !File.exists?(".env") - notice "No .env found. Creating one." - File.touch ".env" - print_done -end - -notice "Setting up the database" - -run_command "lucky", "db.setup" - -notice "Seeding the database with required and sample records" -run_command "lucky", "db.seed.required_data" -run_command "lucky", "db.seed.sample_data" - -print_done -notice "Run 'lucky dev' to start the app" \ No newline at end of file diff --git a/fixtures/src_template__api_only/expected/script/system_check.cr b/fixtures/src_template__api_only/expected/script/system_check.cr deleted file mode 100644 index b76720ba..00000000 --- a/fixtures/src_template__api_only/expected/script/system_check.cr +++ /dev/null @@ -1,18 +0,0 @@ -require "./helpers/*" - -# Use this script to check the system for required tools and process that your app needs. -# A few helper functions are provided to keep the code simple. See the -# script/helpers/function_helpers.cr file for more examples. -# -# A few examples you might use here: -# * 'lucky db.verify_connection' to test postgres can be connected -# * Checking that elasticsearch, redis, or postgres is installed and/or booted -# * Note: Booting additional processes for things like mail, background jobs, etc... -# should go in your Procfile.dev. - - -# CUSTOM PRE-BOOT CHECKS -# example: -# if command_not_running "redis-cli", "ping" -# print_error "Redis is not running." -# end diff --git a/fixtures/src_template__api_only/expected/spec/setup/clean_database.cr b/fixtures/src_template__api_only/expected/spec/setup/clean_database.cr deleted file mode 100644 index a1bc631c..00000000 --- a/fixtures/src_template__api_only/expected/spec/setup/clean_database.cr +++ /dev/null @@ -1,3 +0,0 @@ -Spec.before_each do - AppDatabase.truncate -end diff --git a/fixtures/src_template__api_only/expected/spec/setup/reset_emails.cr b/fixtures/src_template__api_only/expected/spec/setup/reset_emails.cr deleted file mode 100644 index 140ab416..00000000 --- a/fixtures/src_template__api_only/expected/spec/setup/reset_emails.cr +++ /dev/null @@ -1,3 +0,0 @@ -Spec.before_each do - Carbon::DevAdapter.reset -end diff --git a/fixtures/src_template__api_only/expected/spec/setup/setup_database.cr b/fixtures/src_template__api_only/expected/spec/setup/setup_database.cr deleted file mode 100644 index 393c6da3..00000000 --- a/fixtures/src_template__api_only/expected/spec/setup/setup_database.cr +++ /dev/null @@ -1,2 +0,0 @@ -Db::Create.new(quiet: true).call -Db::Migrate.new(quiet: true).call diff --git a/fixtures/src_template__api_only/expected/spec/setup/start_app_server.cr b/fixtures/src_template__api_only/expected/spec/setup/start_app_server.cr deleted file mode 100644 index 3a64c702..00000000 --- a/fixtures/src_template__api_only/expected/spec/setup/start_app_server.cr +++ /dev/null @@ -1,9 +0,0 @@ -app_server = AppServer.new - -spawn do - app_server.listen -end - -Spec.after_suite do - app_server.close -end diff --git a/fixtures/src_template__api_only/expected/spec/spec_helper.cr b/fixtures/src_template__api_only/expected/spec/spec_helper.cr deleted file mode 100644 index d876014d..00000000 --- a/fixtures/src_template__api_only/expected/spec/spec_helper.cr +++ /dev/null @@ -1,19 +0,0 @@ -ENV["LUCKY_ENV"] = "test" -ENV["DEV_PORT"] = "5001" -require "spec" -require "../src/app" -require "./support/**" -require "../db/migrations/**" - -# Add/modify files in spec/setup to start/configure programs or run hooks -# -# By default there are scripts for setting up and cleaning the database, -# configuring LuckyFlow, starting the app server, etc. -require "./setup/**" - -include Carbon::Expectations -include Lucky::RequestExpectations - -Avram::Migrator::Runner.new.ensure_migrated! -Avram::SchemaEnforcer.ensure_correct_column_mappings! -Habitat.raise_if_missing_settings! diff --git a/fixtures/src_template__api_only/expected/spec/support/.keep b/fixtures/src_template__api_only/expected/spec/support/.keep deleted file mode 100644 index e69de29b..00000000 diff --git a/fixtures/src_template__api_only/expected/spec/support/api_client.cr b/fixtures/src_template__api_only/expected/spec/support/api_client.cr deleted file mode 100644 index ef251251..00000000 --- a/fixtures/src_template__api_only/expected/spec/support/api_client.cr +++ /dev/null @@ -1,8 +0,0 @@ -class ApiClient < Lucky::BaseHTTPClient - app AppServer.new - - def initialize - super - headers("Content-Type": "application/json") - end -end diff --git a/fixtures/src_template__api_only/expected/spec/support/factories/.keep b/fixtures/src_template__api_only/expected/spec/support/factories/.keep deleted file mode 100644 index e69de29b..00000000 diff --git a/fixtures/src_template__api_only/expected/src/actions/api_action.cr b/fixtures/src_template__api_only/expected/src/actions/api_action.cr deleted file mode 100644 index fac02c8b..00000000 --- a/fixtures/src_template__api_only/expected/src/actions/api_action.cr +++ /dev/null @@ -1,11 +0,0 @@ -# Include modules and add methods that are for all API requests -abstract class ApiAction < Lucky::Action - # APIs typically do not need to send cookie/session data. - # Remove this line if you want to send cookies in the response header. - disable_cookies - accepted_formats [:json] - - # By default all actions are required to use underscores to separate words. - # Add 'include Lucky::SkipRouteStyleCheck' to your actions if you wish to ignore this check for specific routes. - include Lucky::EnforceUnderscoredRoute -end diff --git a/fixtures/src_template__api_only/expected/src/actions/errors/show.cr b/fixtures/src_template__api_only/expected/src/actions/errors/show.cr deleted file mode 100644 index a80eaa4d..00000000 --- a/fixtures/src_template__api_only/expected/src/actions/errors/show.cr +++ /dev/null @@ -1,42 +0,0 @@ -# This class handles error responses and reporting. -# -# https://luckyframework.org/guides/http-and-routing/error-handling -class Errors::Show < Lucky::ErrorAction - DEFAULT_MESSAGE = "Something went wrong." - default_format :json - dont_report [Lucky::RouteNotFoundError, Avram::RecordNotFoundError] - - def render(error : Lucky::RouteNotFoundError | Avram::RecordNotFoundError) - error_json "Not found", status: 404 - end - - # When an InvalidOperationError is raised, show a helpful error with the - # param that is invalid, and what was wrong with it. - def render(error : Avram::InvalidOperationError) - error_json \ - message: error.renderable_message, - details: error.renderable_details, - param: error.invalid_attribute_name, - status: 400 - end - - # Always keep this below other 'render' methods or it may override your - # custom 'render' methods. - def render(error : Lucky::RenderableError) - error_json error.renderable_message, status: error.renderable_status - end - - # If none of the 'render' methods return a response for the raised Exception, - # Lucky will use this method. - def default_render(error : Exception) : Lucky::Response - error_json DEFAULT_MESSAGE, status: 500 - end - - private def error_json(message : String, status : Int, details = nil, param = nil) - json ErrorSerializer.new(message: message, details: details, param: param), status: status - end - - private def report(error : Exception) : Nil - # Send to Rollbar, send an email, etc. - end -end diff --git a/fixtures/src_template__api_only/expected/src/actions/home/index.cr b/fixtures/src_template__api_only/expected/src/actions/home/index.cr deleted file mode 100644 index eb326da9..00000000 --- a/fixtures/src_template__api_only/expected/src/actions/home/index.cr +++ /dev/null @@ -1,5 +0,0 @@ -class Home::Index < ApiAction - get "/" do - json({hello: "Hello World from Home::Index"}) - end -end diff --git a/fixtures/src_template__api_only/expected/src/actions/mixins/.keep b/fixtures/src_template__api_only/expected/src/actions/mixins/.keep deleted file mode 100644 index e69de29b..00000000 diff --git a/fixtures/src_template__api_only/expected/src/app.cr b/fixtures/src_template__api_only/expected/src/app.cr deleted file mode 100644 index a658febc..00000000 --- a/fixtures/src_template__api_only/expected/src/app.cr +++ /dev/null @@ -1,20 +0,0 @@ -require "./shards" - -require "../config/server" -require "./app_database" -require "../config/**" -require "./models/base_model" -require "./models/mixins/**" -require "./models/**" -require "./queries/mixins/**" -require "./queries/**" -require "./operations/mixins/**" -require "./operations/**" -require "./serializers/base_serializer" -require "./serializers/**" -require "./emails/base_email" -require "./emails/**" -require "./actions/mixins/**" -require "./actions/**" -require "../db/migrations/**" -require "./app_server" \ No newline at end of file diff --git a/fixtures/src_template__api_only/expected/src/app_database.cr b/fixtures/src_template__api_only/expected/src/app_database.cr deleted file mode 100644 index 0efd4f50..00000000 --- a/fixtures/src_template__api_only/expected/src/app_database.cr +++ /dev/null @@ -1,2 +0,0 @@ -class AppDatabase < Avram::Database -end diff --git a/fixtures/src_template__api_only/expected/src/app_server.cr b/fixtures/src_template__api_only/expected/src/app_server.cr deleted file mode 100644 index 53f483d1..00000000 --- a/fixtures/src_template__api_only/expected/src/app_server.cr +++ /dev/null @@ -1,28 +0,0 @@ -class AppServer < Lucky::BaseAppServer - # Learn about middleware with HTTP::Handlers: - # https://luckyframework.org/guides/http-and-routing/http-handlers - def middleware : Array(HTTP::Handler) - [ - Lucky::RequestIdHandler.new, - Lucky::ForceSSLHandler.new, - Lucky::HttpMethodOverrideHandler.new, - Lucky::LogHandler.new, - Lucky::ErrorHandler.new(action: Errors::Show), - Lucky::RemoteIpHandler.new, - Lucky::RouteHandler.new, - - # Disabled in API mode: - # Lucky::StaticCompressionHandler.new("./public", file_ext: "gz", content_encoding: "gzip"), - # Lucky::StaticFileHandler.new("./public", fallthrough: false, directory_listing: false), - Lucky::RouteNotFoundHandler.new, - ] of HTTP::Handler - end - - def protocol - "http" - end - - def listen - server.listen(host, port, reuse_port: false) - end -end diff --git a/fixtures/src_template__api_only/expected/src/emails/base_email.cr b/fixtures/src_template__api_only/expected/src/emails/base_email.cr deleted file mode 100644 index 656f4f11..00000000 --- a/fixtures/src_template__api_only/expected/src/emails/base_email.cr +++ /dev/null @@ -1,15 +0,0 @@ -# Learn about sending emails -# https://luckyframework.org/guides/emails/sending-emails-with-carbon -abstract class BaseEmail < Carbon::Email - # You can add defaults using the 'inherited' hook - # - # Example: - # - # macro inherited - # from default_from - # end - # - # def default_from - # Carbon::Address.new("support@app.com") - # end -end diff --git a/fixtures/src_template__api_only/expected/src/models/base_model.cr b/fixtures/src_template__api_only/expected/src/models/base_model.cr deleted file mode 100644 index 6bafeb84..00000000 --- a/fixtures/src_template__api_only/expected/src/models/base_model.cr +++ /dev/null @@ -1,5 +0,0 @@ -abstract class BaseModel < Avram::Model - def self.database : Avram::Database.class - AppDatabase - end -end diff --git a/fixtures/src_template__api_only/expected/src/models/mixins/.keep b/fixtures/src_template__api_only/expected/src/models/mixins/.keep deleted file mode 100644 index e69de29b..00000000 diff --git a/fixtures/src_template__api_only/expected/src/operations/.keep b/fixtures/src_template__api_only/expected/src/operations/.keep deleted file mode 100644 index e69de29b..00000000 diff --git a/fixtures/src_template__api_only/expected/src/operations/mixins/.keep b/fixtures/src_template__api_only/expected/src/operations/mixins/.keep deleted file mode 100644 index e69de29b..00000000 diff --git a/fixtures/src_template__api_only/expected/src/queries/.keep b/fixtures/src_template__api_only/expected/src/queries/.keep deleted file mode 100644 index e69de29b..00000000 diff --git a/fixtures/src_template__api_only/expected/src/queries/mixins/.keep b/fixtures/src_template__api_only/expected/src/queries/mixins/.keep deleted file mode 100644 index e69de29b..00000000 diff --git a/fixtures/src_template__api_only/expected/src/serializers/.keep b/fixtures/src_template__api_only/expected/src/serializers/.keep deleted file mode 100644 index e69de29b..00000000 diff --git a/fixtures/src_template__api_only/expected/src/serializers/base_serializer.cr b/fixtures/src_template__api_only/expected/src/serializers/base_serializer.cr deleted file mode 100644 index e769f5c0..00000000 --- a/fixtures/src_template__api_only/expected/src/serializers/base_serializer.cr +++ /dev/null @@ -1,18 +0,0 @@ -abstract class BaseSerializer - include Lucky::Serializable - - def self.for_collection(collection : Enumerable, *args, **named_args) : Array(self) - collection.map do |object| - new(object, *args, **named_args) - end - end - - def self.for_collection(collection : Enumerable, pages : Lucky::Paginator, *args, **named_args) - { - "items" => collection.map do |object| - new(object, *args, **named_args) - end, - "pagination" => PaginationSerializer.new(pages), - } - end -end diff --git a/fixtures/src_template__api_only/expected/src/serializers/error_serializer.cr b/fixtures/src_template__api_only/expected/src/serializers/error_serializer.cr deleted file mode 100644 index b7b55283..00000000 --- a/fixtures/src_template__api_only/expected/src/serializers/error_serializer.cr +++ /dev/null @@ -1,14 +0,0 @@ -# This is the default error serializer generated by Lucky. -# Feel free to customize it in any way you like. -class ErrorSerializer < BaseSerializer - def initialize( - @message : String, - @details : String? = nil, - @param : String? = nil, # so you can track which param (if any) caused the problem - ) - end - - def render - {message: @message, param: @param, details: @details} - end -end diff --git a/fixtures/src_template__api_only/expected/src/serializers/pagination_serializer.cr b/fixtures/src_template__api_only/expected/src/serializers/pagination_serializer.cr deleted file mode 100644 index 9e44788c..00000000 --- a/fixtures/src_template__api_only/expected/src/serializers/pagination_serializer.cr +++ /dev/null @@ -1,15 +0,0 @@ -# This is the default pagination serializer generated by Lucky. -# Feel free to customize it in any way you like. -class PaginationSerializer < BaseSerializer - def initialize(@pages : Lucky::Paginator) - end - - def render - { - next_page: @pages.path_to_next, - previous_page: @pages.path_to_previous, - total_items: @pages.item_count, - total_pages: @pages.total, - } - end -end diff --git a/fixtures/src_template__api_only/expected/src/shards.cr b/fixtures/src_template__api_only/expected/src/shards.cr deleted file mode 100644 index 1afc72cb..00000000 --- a/fixtures/src_template__api_only/expected/src/shards.cr +++ /dev/null @@ -1,8 +0,0 @@ -# Load .env file before any other config or app code -require "lucky_env" -LuckyEnv.load?(".env") - -# Require your shards here -require "lucky" -require "avram/lucky" -require "carbon" diff --git a/fixtures/src_template__api_only/expected/src/start_server.cr b/fixtures/src_template__api_only/expected/src/start_server.cr deleted file mode 100644 index de8af78e..00000000 --- a/fixtures/src_template__api_only/expected/src/start_server.cr +++ /dev/null @@ -1,17 +0,0 @@ -require "./app" - -Habitat.raise_if_missing_settings! - -if LuckyEnv.development? - Avram::Migrator::Runner.new.ensure_migrated! - Avram::SchemaEnforcer.ensure_correct_column_mappings! -end - -app_server = AppServer.new -puts "Listening on http://#{app_server.host}:#{app_server.port}" - -Signal::INT.trap do - app_server.close -end - -app_server.listen diff --git a/fixtures/src_template__api_only/expected/src/test_project.cr b/fixtures/src_template__api_only/expected/src/test_project.cr deleted file mode 100644 index 68e1a8d2..00000000 --- a/fixtures/src_template__api_only/expected/src/test_project.cr +++ /dev/null @@ -1,6 +0,0 @@ -# Typically you will not use or modify this file. 'shards build' and some -# other crystal tools will sometimes use this. -# -# When this file is compiled/run it will require and run 'start_server', -# which as its name implies will start the server for you app. -require "./start_server" diff --git a/fixtures/src_template__api_only/expected/tasks.cr b/fixtures/src_template__api_only/expected/tasks.cr deleted file mode 100644 index 5a892d4d..00000000 --- a/fixtures/src_template__api_only/expected/tasks.cr +++ /dev/null @@ -1,25 +0,0 @@ -# This file loads your app and all your tasks when running 'lucky' -# -# Run 'lucky --help' to see all available tasks. -# -# Learn to create your own tasks: -# https://luckyframework.org/guides/command-line-tasks/custom-tasks - -# See `LuckyEnv#task?` -ENV["LUCKY_TASK"] = "true" - -# Load Lucky and the app (actions, models, etc.) -require "./src/app" -require "lucky_task" - -# You can add your own tasks here in the ./tasks folder -require "./tasks/**" - -# Load migrations -require "./db/migrations/**" - -# Load Lucky tasks (dev, routes, etc.) -require "lucky/tasks/**" -require "avram/lucky/tasks" - -LuckyTask::Runner.run diff --git a/fixtures/src_template__api_only/expected/tasks/.keep b/fixtures/src_template__api_only/expected/tasks/.keep deleted file mode 100644 index e69de29b..00000000 diff --git a/fixtures/src_template__api_only/expected/tasks/db/seed/required_data.cr b/fixtures/src_template__api_only/expected/tasks/db/seed/required_data.cr deleted file mode 100644 index d866040f..00000000 --- a/fixtures/src_template__api_only/expected/tasks/db/seed/required_data.cr +++ /dev/null @@ -1,30 +0,0 @@ -require "../../../spec/support/factories/**" - -# Add seeds here that are *required* for your app to work. -# For example, you might need at least one admin user or you might need at least -# one category for your blog posts for the app to work. -# -# Use `Db::Seed::SampleData` if your only want to add sample data helpful for -# development. -class Db::Seed::RequiredData < LuckyTask::Task - summary "Add database records required for the app to work" - - def call - # Using a Avram::Factory: - # - # Use the defaults, but override just the email - # UserFactory.create &.email("me@example.com") - - # Using a SaveOperation: - # - # SaveUser.create!(email: "me@example.com", name: "Jane") - # - # You likely want to be able to run this file more than once. To do that, - # only create the record if it doesn't exist yet: - # - # unless UserQuery.new.email("me@example.com").first? - # SaveUser.create!(email: "me@example.com", name: "Jane") - # end - puts "Done adding required data" - end -end diff --git a/fixtures/src_template__api_only/expected/tasks/db/seed/sample_data.cr b/fixtures/src_template__api_only/expected/tasks/db/seed/sample_data.cr deleted file mode 100644 index 231d7e8d..00000000 --- a/fixtures/src_template__api_only/expected/tasks/db/seed/sample_data.cr +++ /dev/null @@ -1,30 +0,0 @@ -require "../../../spec/support/factories/**" - -# Add sample data helpful for development, e.g. (fake users, blog posts, etc.) -# -# Use `Db::Seed::RequiredData` if you need to create data *required* for your -# app to work. -class Db::Seed::SampleData < LuckyTask::Task - summary "Add sample database records helpful for development" - - def call - # Using an Avram::Factory: - # - # Use the defaults, but override just the email - # UserFactory.create &.email("me@example.com") - - # Using a SaveOperation: - # ``` - # SignUpUser.create!(email: "me@example.com", password: "test123", password_confirmation: "test123") - # ``` - # - # You likely want to be able to run this file more than once. To do that, - # only create the record if it doesn't exist yet: - # ``` - # if UserQuery.new.email("me@example.com").none? - # SignUpUser.create!(email: "me@example.com", password: "test123", password_confirmation: "test123") - # end - # ``` - puts "Done adding sample data" - end -end diff --git a/fixtures/src_template__generate_auth/expected/.crystal-version b/fixtures/src_template__generate_auth/expected/.crystal-version deleted file mode 100644 index 41c11ffb..00000000 --- a/fixtures/src_template__generate_auth/expected/.crystal-version +++ /dev/null @@ -1 +0,0 @@ -1.16.1 diff --git a/fixtures/src_template__generate_auth/expected/.env b/fixtures/src_template__generate_auth/expected/.env deleted file mode 100644 index e69de29b..00000000 diff --git a/fixtures/src_template__generate_auth/expected/.github/workflows/ci.yml b/fixtures/src_template__generate_auth/expected/.github/workflows/ci.yml deleted file mode 100644 index 3ebc17ed..00000000 --- a/fixtures/src_template__generate_auth/expected/.github/workflows/ci.yml +++ /dev/null @@ -1,113 +0,0 @@ -name: test-project CI - -on: - push: - branches: "*" - pull_request: - branches: "*" - -jobs: - check-format: - strategy: - fail-fast: false - matrix: - crystal_version: - - 1.16.1 - experimental: - - false - runs-on: ubuntu-latest - continue-on-error: ${{ matrix.experimental }} - steps: - - uses: actions/checkout@v4 - - name: Install Crystal - uses: crystal-lang/install-crystal@v1 - with: - crystal: ${{ matrix.crystal_version }} - - name: Format - run: crystal tool format --check - - specs: - strategy: - fail-fast: false - matrix: - crystal_version: - - 1.16.1 - experimental: - - false - runs-on: ubuntu-latest - env: - LUCKY_ENV: test - DB_HOST: localhost - continue-on-error: ${{ matrix.experimental }} - services: - postgres: - image: postgres:14-alpine - env: - POSTGRES_PASSWORD: postgres - ports: - - 5432:5432 - # Set health checks to wait until postgres has started - options: >- - --health-cmd pg_isready - --health-interval 10s - --health-timeout 5s - --health-retries 5 - - steps: - - uses: actions/checkout@v4 - - name: Install Crystal - uses: crystal-lang/install-crystal@v1 - with: - crystal: ${{ matrix.crystal_version }} - - - name: Get yarn cache directory path - id: yarn-cache-dir-path - run: echo "::set-output name=dir::$(yarn cache dir)" - - - name: Set up Yarn cache - uses: actions/cache@v4 - with: - path: ${{ steps.yarn-cache-dir-path.outputs.dir }} - key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }} - restore-keys: | - ${{ runner.os }}-yarn- - - - name: Set up Node cache - uses: actions/cache@v4 - id: node-cache # use this to check for `cache-hit` (`steps.node-cache.outputs.cache-hit != 'true'`) - with: - path: '**/node_modules' - key: ${{ runner.os }}-node-${{ hashFiles('**/yarn.lock') }} - restore-keys: | - ${{ runner.os }}-node- - - name: Set up Crystal cache - uses: actions/cache@v4 - id: crystal-cache - with: - path: | - ~/.cache/crystal - lib - key: ${{ runner.os }}-crystal-${{ hashFiles('**/shard.lock') }} - restore-keys: | - ${{ runner.os }}-crystal- - - - name: Install shards - if: steps.crystal-cache.outputs.cache-hit != 'true' - run: shards check || shards install - - - name: Install yarn packages - if: steps.node-cache.outputs.cache-hit != 'true' - run: yarn install --frozen-lockfile --no-progress - - name: Compiling assets - run: yarn prod - - name: Build lucky_tasks - run: crystal build tasks.cr -o ./lucky_tasks - - - name: Prepare database - run: | - ./lucky_tasks db.create - ./lucky_tasks db.migrate - ./lucky_tasks db.seed.required_data - - - name: Run tests - run: crystal spec \ No newline at end of file diff --git a/fixtures/src_template__generate_auth/expected/Procfile b/fixtures/src_template__generate_auth/expected/Procfile deleted file mode 100644 index e524d70d..00000000 --- a/fixtures/src_template__generate_auth/expected/Procfile +++ /dev/null @@ -1,2 +0,0 @@ -web: bin/app -release: lucky db.migrate diff --git a/fixtures/src_template__generate_auth/expected/Procfile.dev b/fixtures/src_template__generate_auth/expected/Procfile.dev deleted file mode 100644 index 80369f14..00000000 --- a/fixtures/src_template__generate_auth/expected/Procfile.dev +++ /dev/null @@ -1,3 +0,0 @@ -system_check: crystal script/system_check.cr -web: lucky watch --reload-browser -assets: yarn dev diff --git a/fixtures/src_template__generate_auth/expected/README.md b/fixtures/src_template__generate_auth/expected/README.md deleted file mode 100644 index da2d97cc..00000000 --- a/fixtures/src_template__generate_auth/expected/README.md +++ /dev/null @@ -1,23 +0,0 @@ -# test-project - -This is a project written using [Lucky](https://luckyframework.org). Enjoy! - -### Setting up the project - -1. [Install required dependencies](https://luckyframework.org/guides/getting-started/installing#install-required-dependencies) -1. Update database settings in `config/database.cr` -1. Run `script/setup` -1. Run `lucky dev` to start the app - -### Using Docker for development - -1. [Install Docker](https://docs.docker.com/engine/install/) -1. Run `docker compose up` - -The Docker container will boot all of the necessary components needed to run your Lucky application. -To configure the container, update the `docker-compose.yml` file, and the `docker/development.dockerfile` file. - - -### Learning Lucky - -Lucky uses the [Crystal](https://crystal-lang.org) programming language. You can learn about Lucky from the [Lucky Guides](https://luckyframework.org/guides/getting-started/why-lucky). diff --git a/fixtures/src_template__generate_auth/expected/config/application.cr b/fixtures/src_template__generate_auth/expected/config/application.cr deleted file mode 100644 index c807149a..00000000 --- a/fixtures/src_template__generate_auth/expected/config/application.cr +++ /dev/null @@ -1,24 +0,0 @@ -# This file may be used for custom Application configurations. -# It will be loaded before other config files. -# -# Read more on configuration: -# https://luckyframework.org/guides/getting-started/configuration#configuring-your-own-code - -# Use this code as an example: -# -# ``` -# module Application -# Habitat.create do -# setting support_email : String -# setting lock_with_basic_auth : Bool -# end -# end -# -# Application.configure do |settings| -# settings.support_email = "support@myapp.io" -# settings.lock_with_basic_auth = LuckyEnv.staging? -# end -# -# # In your application, call -# # `Application.settings.support_email` anywhere you need it. -# ``` diff --git a/fixtures/src_template__generate_auth/expected/config/colors.cr b/fixtures/src_template__generate_auth/expected/config/colors.cr deleted file mode 100644 index 761ae940..00000000 --- a/fixtures/src_template__generate_auth/expected/config/colors.cr +++ /dev/null @@ -1,4 +0,0 @@ -# This enables the color output when in development or test -# Check out the Colorize docs for more information -# https://crystal-lang.org/api/Colorize.html -Colorize.enabled = LuckyEnv.development? || LuckyEnv.test? diff --git a/fixtures/src_template__generate_auth/expected/config/cookies.cr b/fixtures/src_template__generate_auth/expected/config/cookies.cr deleted file mode 100644 index 2d5055f2..00000000 --- a/fixtures/src_template__generate_auth/expected/config/cookies.cr +++ /dev/null @@ -1,25 +0,0 @@ -require "./server" - -Lucky::Session.configure do |settings| - settings.key = "_test_project_session" -end - -Lucky::CookieJar.configure do |settings| - settings.on_set = ->(cookie : HTTP::Cookie) { - # If ForceSSLHandler is enabled, only send cookies over HTTPS - cookie.secure(Lucky::ForceSSLHandler.settings.enabled) - - # By default, don't allow reading cookies with JavaScript - cookie.http_only(true) - - # Restrict cookies to a first-party or same-site context - cookie.samesite(:lax) - - # Set all cookies to the root path by default - cookie.path("/") - - # You can set other defaults for cookies here. For example: - # - # cookie.expires(1.year.from_now).domain("mydomain.com") - } -end diff --git a/fixtures/src_template__generate_auth/expected/config/database.cr b/fixtures/src_template__generate_auth/expected/config/database.cr deleted file mode 100644 index f614299a..00000000 --- a/fixtures/src_template__generate_auth/expected/config/database.cr +++ /dev/null @@ -1,29 +0,0 @@ -database_name = "test_project_#{LuckyEnv.environment}" - -AppDatabase.configure do |settings| - if LuckyEnv.production? - settings.credentials = Avram::Credentials.parse(ENV["DATABASE_URL"]) - else - settings.credentials = Avram::Credentials.parse?(ENV["DATABASE_URL"]?) || Avram::Credentials.new( - database: database_name, - hostname: ENV["DB_HOST"]? || "localhost", - port: ENV["DB_PORT"]?.try(&.to_i) || 5432, - # Some common usernames are "postgres", "root", or your system username (run 'whoami') - username: ENV["DB_USERNAME"]? || "postgres", - # Some Postgres installations require no password. Use "" if that is the case. - password: ENV["DB_PASSWORD"]? || "postgres" - ) - end -end - -Avram.configure do |settings| - settings.database_to_migrate = AppDatabase - - # In production, allow lazy loading (N+1). - # In development and test, raise an error if you forget to preload associations - settings.lazy_load_enabled = LuckyEnv.production? - - # Always parse `Time` values with these specific formats. - # Used for both database values, and datetime input fields. - # settings.time_formats << "%F" -end diff --git a/fixtures/src_template__generate_auth/expected/config/email.cr b/fixtures/src_template__generate_auth/expected/config/email.cr deleted file mode 100644 index 7c875449..00000000 --- a/fixtures/src_template__generate_auth/expected/config/email.cr +++ /dev/null @@ -1,26 +0,0 @@ -require "carbon_sendgrid_adapter" - -BaseEmail.configure do |settings| - if LuckyEnv.production? - # If you don't need to send emails, set the adapter to DevAdapter instead: - # - # settings.adapter = Carbon::DevAdapter.new - # - # If you do need emails, get a key from SendGrid and set an ENV variable - send_grid_key = send_grid_key_from_env - settings.adapter = Carbon::SendGridAdapter.new(api_key: send_grid_key) - elsif LuckyEnv.development? - settings.adapter = Carbon::DevAdapter.new(print_emails: true) - else - settings.adapter = Carbon::DevAdapter.new - end -end - -private def send_grid_key_from_env - ENV["SEND_GRID_KEY"]? || raise_missing_key_message -end - -private def raise_missing_key_message - puts "Missing SEND_GRID_KEY. Set the SEND_GRID_KEY env variable to 'unused' if not sending emails, or set the SEND_GRID_KEY ENV var.".colorize.red - exit(1) -end diff --git a/fixtures/src_template__generate_auth/expected/config/env.cr b/fixtures/src_template__generate_auth/expected/config/env.cr deleted file mode 100644 index 3f364072..00000000 --- a/fixtures/src_template__generate_auth/expected/config/env.cr +++ /dev/null @@ -1,33 +0,0 @@ -# Environments are managed using `LuckyEnv`. By default, development, production -# and test are supported. See -# https://luckyframework.org/guides/getting-started/configuration for details. -# -# The default environment is development unless the environment variable -# LUCKY_ENV is set. -# -# Example: -# ``` -# LuckyEnv.environment # => "development" -# LuckyEnv.development? # => true -# LuckyEnv.production? # => false -# LuckyEnv.test? # => false -# ``` -# -# New environments can be added using the `LuckyEnv.add_env` macro. -# -# Example: -# ``` -# LuckyEnv.add_env :staging -# LuckyEnv.staging? # => false -# ``` -# -# To determine whether or not a `LuckyTask` is currently running, you can use -# the `LuckyEnv.task?` predicate. -# -# Example: -# ``` -# LuckyEnv.task? # => false -# ``` - -# Add a staging environment. -# LuckyEnv.add_env :staging diff --git a/fixtures/src_template__generate_auth/expected/config/error_handler.cr b/fixtures/src_template__generate_auth/expected/config/error_handler.cr deleted file mode 100644 index c6b736e3..00000000 --- a/fixtures/src_template__generate_auth/expected/config/error_handler.cr +++ /dev/null @@ -1,3 +0,0 @@ -Lucky::ErrorHandler.configure do |settings| - settings.show_debug_output = !LuckyEnv.production? -end diff --git a/fixtures/src_template__generate_auth/expected/config/log.cr b/fixtures/src_template__generate_auth/expected/config/log.cr deleted file mode 100644 index a43940d9..00000000 --- a/fixtures/src_template__generate_auth/expected/config/log.cr +++ /dev/null @@ -1,50 +0,0 @@ -require "file_utils" - -if LuckyEnv.test? - # Logs to `tmp/test.log` so you can see what's happening without having - # a bunch of log output in your spec results. - FileUtils.mkdir_p("tmp") - - backend = Log::IOBackend.new(File.new("tmp/test.log", mode: "w")) - backend.formatter = Lucky::PrettyLogFormatter.proc - Log.dexter.configure(:debug, backend) -elsif LuckyEnv.production? - # Lucky uses JSON in production so logs can be searched more easily - # - # If you want logs like in development use 'Lucky::PrettyLogFormatter.proc'. - backend = Log::IOBackend.new - backend.formatter = Dexter::JSONLogFormatter.proc - Log.dexter.configure(:info, backend) -else - # Use a pretty formatter printing to STDOUT in development - backend = Log::IOBackend.new - backend.formatter = Lucky::PrettyLogFormatter.proc - Log.dexter.configure(:debug, backend) - DB::Log.level = :info -end - -# Lucky only logs when before/after pipes halt by redirecting, or rendering a -# response. Pipes that run without halting are not logged. -# -# If you want to log every pipe that runs, set the log level to ':info' -Lucky::ContinuedPipeLog.dexter.configure(:none) - -# Lucky only logs failed queries by default. -# -# Set the log to ':info' to log all queries -Avram::QueryLog.dexter.configure(:none) - -# Subscribe to Pulsar events to log when queries are made, -# queries fail, or save operations fail. Remove this to -# disable these log events without disabling all logging. -Avram.initialize_logging - -# Skip logging static assets requests in development -Lucky::LogHandler.configure do |settings| - if LuckyEnv.development? - settings.skip_if = ->(context : HTTP::Server::Context) { - context.request.method.downcase == "get" && - context.request.resource.starts_with?(/\/css\/|\/js\/|\/assets\/|\/favicon\.ico/) - } - end -end diff --git a/fixtures/src_template__generate_auth/expected/config/route_helper.cr b/fixtures/src_template__generate_auth/expected/config/route_helper.cr deleted file mode 100644 index ede1f328..00000000 --- a/fixtures/src_template__generate_auth/expected/config/route_helper.cr +++ /dev/null @@ -1,10 +0,0 @@ -# This is used when generating URLs for your application -Lucky::RouteHelper.configure do |settings| - if LuckyEnv.production? - # Example: https://my_app.com - settings.base_uri = ENV.fetch("APP_DOMAIN") - else - # Set domain to the default host/port in development/test - settings.base_uri = "http://localhost:#{Lucky::ServerSettings.port}" - end -end diff --git a/fixtures/src_template__generate_auth/expected/config/server.cr b/fixtures/src_template__generate_auth/expected/config/server.cr deleted file mode 100644 index b7cca25c..00000000 --- a/fixtures/src_template__generate_auth/expected/config/server.cr +++ /dev/null @@ -1,68 +0,0 @@ -# Here is where you configure the Lucky server -# -# Look at config/route_helper.cr if you want to change the domain used when -# generating links with `Action.url`. -Lucky::Server.configure do |settings| - if LuckyEnv.production? - settings.secret_key_base = secret_key_from_env - settings.host = "0.0.0.0" - settings.port = ENV["PORT"].to_i - settings.gzip_enabled = true - # By default certain content types will be gzipped. - # For a full list look in - # https://github.com/luckyframework/lucky/blob/main/src/lucky/server.cr - # To add additional extensions do something like this: - # settings.gzip_content_types << "content/type" - else - settings.secret_key_base = "1234567890" - # Change host/port in config/watch.yml - # Alternatively, you can set the DEV_PORT env to set the port for local development - settings.host = Lucky::ServerSettings.host - settings.port = Lucky::ServerSettings.port - end - - # Configure the asset build system (default is Vite) - settings.asset_build_system = Lucky::AssetBuilder::Vite.new - - # Configure asset host for Vite - if LuckyEnv.development? - # In development, Vite serves assets from its dev server - settings.asset_host = "http://localhost:3001" - elsif LuckyEnv.production? - # In production, Lucky serves the built assets - # You could also use a CDN here: - # settings.asset_host = "https://mycdnhost.com" - settings.asset_host = "" - else - settings.asset_host = "" - end -end - -Lucky::ForceSSLHandler.configure do |settings| - # To force SSL in production, uncomment the lines below. - # This will cause http requests to be redirected to https: - # - # settings.enabled = LuckyEnv.production? - # settings.strict_transport_security = {max_age: 1.year, include_subdomains: true} - # - # Or, leave it disabled: - settings.enabled = false -end - -# Set a unique ID for each HTTP request. -# To enable the request ID, uncomment the lines below. -# You can set your own custom String, or use a random UUID. -# Lucky::RequestIdHandler.configure do |settings| -# settings.set_request_id = ->(context : HTTP::Server::Context) { -# UUID.random.to_s -# } -# end - -private def secret_key_from_env - ENV["SECRET_KEY_BASE"]? || raise_missing_secret_key_in_production -end - -private def raise_missing_secret_key_in_production - puts "Please set the SECRET_KEY_BASE environment variable. You can generate a secret key with 'lucky gen.secret_key'".colorize.red - exit(1) -end \ No newline at end of file diff --git a/fixtures/src_template__generate_auth/expected/config/watch.yml b/fixtures/src_template__generate_auth/expected/config/watch.yml deleted file mode 100644 index 3a59b410..00000000 --- a/fixtures/src_template__generate_auth/expected/config/watch.yml +++ /dev/null @@ -1,3 +0,0 @@ -host: 127.0.0.1 -port: 3000 -reload_port: 3001 diff --git a/fixtures/src_template__generate_auth/expected/db/migrations/.keep b/fixtures/src_template__generate_auth/expected/db/migrations/.keep deleted file mode 100644 index e69de29b..00000000 diff --git a/fixtures/src_template__generate_auth/expected/docker-compose.yml b/fixtures/src_template__generate_auth/expected/docker-compose.yml deleted file mode 100644 index d00779db..00000000 --- a/fixtures/src_template__generate_auth/expected/docker-compose.yml +++ /dev/null @@ -1,45 +0,0 @@ -version: "3.8" -services: - lucky: - build: - context: . - dockerfile: docker/development.dockerfile - environment: - DATABASE_URL: postgres://lucky:password@postgres:5432/lucky - DEV_HOST: "0.0.0.0" - volumes: - - .:/app - - node_modules:/app/node_modules - - shards_lib:/app/lib - - app_bin:/app/bin - - build_cache:/root/.cache - depends_on: - - postgres - ports: - - 3000:3000 # This is the Lucky Server port - - 3001:3001 # This is the Lucky watcher reload port - - entrypoint: ["docker/dev_entrypoint.sh"] - - postgres: - image: postgres:14-alpine - environment: - POSTGRES_USER: lucky - POSTGRES_PASSWORD: password - POSTGRES_DB: lucky - volumes: - - postgres_data:/var/lib/postgresql/data - ports: - # The postgres database container is exposed on the host at port 6543 to - # allow connecting directly to it with postgres clients. The port differs - # from the postgres default to avoid conflict with existing postgres - # servers. Connect to a running postgres container with: - # postgres://lucky:password@localhost:6543/lucky - - 6543:5432 - -volumes: - postgres_data: - node_modules: - shards_lib: - app_bin: - build_cache: diff --git a/fixtures/src_template__generate_auth/expected/docker/dev_entrypoint.sh b/fixtures/src_template__generate_auth/expected/docker/dev_entrypoint.sh deleted file mode 100755 index d16ef6ab..00000000 --- a/fixtures/src_template__generate_auth/expected/docker/dev_entrypoint.sh +++ /dev/null @@ -1,46 +0,0 @@ -#!/bin/bash - -set -euo pipefail - -# This is the entrypoint script used for development docker workflows. -# By default it will: -# - Install dependencies. -# - Run migrations. -# - Start the dev server. -# It also accepts any commands to be run instead. - - -warnfail () { - echo "$@" >&2 - exit 1 -} - -case ${1:-} in - "") # If no arguments are provided, start lucky dev server. - ;; - - *) # If any arguments are provided, execute them instead. - exec "$@" -esac - -if ! [ -d bin ] ; then - echo 'Creating bin directory' - mkdir bin -fi -echo 'Installing npm packages...' -yarn install -if ! shards check ; then - echo 'Installing shards...' - shards install -fi - -echo 'Waiting for postgres to be available...' -./docker/wait-for-it.sh -q postgres:5432 - -if ! psql -d "$DATABASE_URL" -c '\d migrations' > /dev/null ; then - echo 'Finishing database setup...' - lucky db.migrate -fi - -echo 'Starting lucky dev server...' -exec lucky dev diff --git a/fixtures/src_template__generate_auth/expected/docker/development.dockerfile b/fixtures/src_template__generate_auth/expected/docker/development.dockerfile deleted file mode 100644 index 962ad66c..00000000 --- a/fixtures/src_template__generate_auth/expected/docker/development.dockerfile +++ /dev/null @@ -1,33 +0,0 @@ -FROM crystallang/crystal:1.16.1 - -# Install utilities required to make this Dockerfile run -RUN apt-get update && \ - apt-get install -y wget -# Add the nodesource ppa to apt. Update this to change the nodejs version. -RUN wget https://deb.nodesource.com/setup_16.x -O- | bash - -# Apt installs: -# - nodejs (from above ppa) is required for front-end apps. -# - Postgres cli tools are required for lucky-cli. -# - tmux is required for the Overmind process manager. -RUN apt-get update && \ - apt-get install -y nodejs postgresql-client tmux && \ - rm -rf /var/lib/apt/lists/* - -# NPM global installs: -# - Yarn is the default package manager for the node component of a lucky -# browser app. -RUN npm install -g yarn - -# Install lucky cli -WORKDIR /lucky/cli -RUN git clone https://github.com/luckyframework/lucky_cli . && \ - git checkout v1.3.0 && \ - shards build --without-development && \ - cp bin/lucky /usr/bin - -WORKDIR /app -ENV DATABASE_URL=postgres://postgres:postgres@host.docker.internal:5432/postgres -EXPOSE 3000 -EXPOSE 3001 - diff --git a/fixtures/src_template__generate_auth/expected/docker/wait-for-it.sh b/fixtures/src_template__generate_auth/expected/docker/wait-for-it.sh deleted file mode 100755 index 06e0638c..00000000 --- a/fixtures/src_template__generate_auth/expected/docker/wait-for-it.sh +++ /dev/null @@ -1,189 +0,0 @@ -#!/usr/bin/bash -# -# Pulled from https://github.com/vishnubob/wait-for-it on 2022-02-28. -# Licensed under the MIT license as of 81b1373f. -# -# Below this line, wait-for-it is the original work of the author. -# -# Use this script to test if a given TCP host/port are available - -WAITFORIT_cmdname=${0##*/} - -echoerr() { if [[ $WAITFORIT_QUIET -ne 1 ]]; then echo "$@" 1>&2; fi } - -usage() -{ - cat << USAGE >&2 -Usage: - $WAITFORIT_cmdname host:port [-s] [-t timeout] [-- command args] - -h HOST | --host=HOST Host or IP under test - -p PORT | --port=PORT TCP port under test - Alternatively, you specify the host and port as host:port - -s | --strict Only execute subcommand if the test succeeds - -q | --quiet Don't output any status messages - -t TIMEOUT | --timeout=TIMEOUT - Timeout in seconds, zero for no timeout - -- COMMAND ARGS Execute command with args after the test finishes -USAGE - exit 1 -} - -wait_for() -{ - if [[ $WAITFORIT_TIMEOUT -gt 0 ]]; then - echoerr "$WAITFORIT_cmdname: waiting $WAITFORIT_TIMEOUT seconds for $WAITFORIT_HOST:$WAITFORIT_PORT" - else - echoerr "$WAITFORIT_cmdname: waiting for $WAITFORIT_HOST:$WAITFORIT_PORT without a timeout" - fi - WAITFORIT_start_ts=$(date +%s) - while : - do - if [[ $WAITFORIT_ISBUSY -eq 1 ]]; then - nc -z $WAITFORIT_HOST $WAITFORIT_PORT - WAITFORIT_result=$? - else - (echo -n > /dev/tcp/$WAITFORIT_HOST/$WAITFORIT_PORT) >/dev/null 2>&1 - WAITFORIT_result=$? - fi - if [[ $WAITFORIT_result -eq 0 ]]; then - WAITFORIT_end_ts=$(date +%s) - echoerr "$WAITFORIT_cmdname: $WAITFORIT_HOST:$WAITFORIT_PORT is available after $((WAITFORIT_end_ts - WAITFORIT_start_ts)) seconds" - break - fi - sleep 1 - done - return $WAITFORIT_result -} - -wait_for_wrapper() -{ - # In order to support SIGINT during timeout: http://unix.stackexchange.com/a/57692 - if [[ $WAITFORIT_QUIET -eq 1 ]]; then - timeout $WAITFORIT_BUSYTIMEFLAG $WAITFORIT_TIMEOUT $0 --quiet --child --host=$WAITFORIT_HOST --port=$WAITFORIT_PORT --timeout=$WAITFORIT_TIMEOUT & - else - timeout $WAITFORIT_BUSYTIMEFLAG $WAITFORIT_TIMEOUT $0 --child --host=$WAITFORIT_HOST --port=$WAITFORIT_PORT --timeout=$WAITFORIT_TIMEOUT & - fi - WAITFORIT_PID=$! - trap "kill -INT -$WAITFORIT_PID" INT - wait $WAITFORIT_PID - WAITFORIT_RESULT=$? - if [[ $WAITFORIT_RESULT -ne 0 ]]; then - echoerr "$WAITFORIT_cmdname: timeout occurred after waiting $WAITFORIT_TIMEOUT seconds for $WAITFORIT_HOST:$WAITFORIT_PORT" - fi - return $WAITFORIT_RESULT -} - -# process arguments -while [[ $# -gt 0 ]] -do - case "$1" in - *:* ) - WAITFORIT_hostport=(${1//:/ }) - WAITFORIT_HOST=${WAITFORIT_hostport[0]} - WAITFORIT_PORT=${WAITFORIT_hostport[1]} - shift 1 - ;; - --child) - WAITFORIT_CHILD=1 - shift 1 - ;; - -q | --quiet) - WAITFORIT_QUIET=1 - shift 1 - ;; - -s | --strict) - WAITFORIT_STRICT=1 - shift 1 - ;; - -h) - WAITFORIT_HOST="$2" - if [[ $WAITFORIT_HOST == "" ]]; then break; fi - shift 2 - ;; - --host=*) - WAITFORIT_HOST="${1#*=}" - shift 1 - ;; - -p) - WAITFORIT_PORT="$2" - if [[ $WAITFORIT_PORT == "" ]]; then break; fi - shift 2 - ;; - --port=*) - WAITFORIT_PORT="${1#*=}" - shift 1 - ;; - -t) - WAITFORIT_TIMEOUT="$2" - if [[ $WAITFORIT_TIMEOUT == "" ]]; then break; fi - shift 2 - ;; - --timeout=*) - WAITFORIT_TIMEOUT="${1#*=}" - shift 1 - ;; - --) - shift - WAITFORIT_CLI=("$@") - break - ;; - --help) - usage - ;; - *) - echoerr "Unknown argument: $1" - usage - ;; - esac -done - -if [[ "$WAITFORIT_HOST" == "" || "$WAITFORIT_PORT" == "" ]]; then - echoerr "Error: you need to provide a host and port to test." - usage -fi - -WAITFORIT_TIMEOUT=${WAITFORIT_TIMEOUT:-15} -WAITFORIT_STRICT=${WAITFORIT_STRICT:-0} -WAITFORIT_CHILD=${WAITFORIT_CHILD:-0} -WAITFORIT_QUIET=${WAITFORIT_QUIET:-0} - -# Check to see if timeout is from busybox? -WAITFORIT_TIMEOUT_PATH=$(type -p timeout) -WAITFORIT_TIMEOUT_PATH=$(realpath $WAITFORIT_TIMEOUT_PATH 2>/dev/null || readlink -f $WAITFORIT_TIMEOUT_PATH) - -WAITFORIT_BUSYTIMEFLAG="" -if [[ $WAITFORIT_TIMEOUT_PATH =~ "busybox" ]]; then - WAITFORIT_ISBUSY=1 - # Check if busybox timeout uses -t flag - # (recent Alpine versions don't support -t anymore) - if timeout &>/dev/stdout | grep -q -e '-t '; then - WAITFORIT_BUSYTIMEFLAG="-t" - fi -else - WAITFORIT_ISBUSY=0 -fi - -if [[ $WAITFORIT_CHILD -gt 0 ]]; then - wait_for - WAITFORIT_RESULT=$? - exit $WAITFORIT_RESULT -else - if [[ $WAITFORIT_TIMEOUT -gt 0 ]]; then - wait_for_wrapper - WAITFORIT_RESULT=$? - else - wait_for - WAITFORIT_RESULT=$? - fi -fi - -if [[ $WAITFORIT_CLI != "" ]]; then - if [[ $WAITFORIT_RESULT -ne 0 && $WAITFORIT_STRICT -eq 1 ]]; then - echoerr "$WAITFORIT_cmdname: strict mode, refusing to execute subprocess" - exit $WAITFORIT_RESULT - fi - exec "${WAITFORIT_CLI[@]}" -else - exit $WAITFORIT_RESULT -fi - diff --git a/fixtures/src_template__generate_auth/expected/script/helpers/function_helpers.cr b/fixtures/src_template__generate_auth/expected/script/helpers/function_helpers.cr deleted file mode 100644 index 8abcb6a2..00000000 --- a/fixtures/src_template__generate_auth/expected/script/helpers/function_helpers.cr +++ /dev/null @@ -1,32 +0,0 @@ -require "colorize" - -# These are helper methods provided to help keep your code -# clean. Add new methods, or alter these as needed. - -def notice(message : String) : Nil - puts "\n▸ #{message}" -end - -def print_done : Nil - puts "✔ Done" -end - -def print_error(message : String) : Nil - puts "There is a problem with your system setup:\n".colorize.red.bold - puts "#{message}\n".colorize.red.bold - Process.exit(1) -end - -def command_not_found(command : String) : Bool - Process.find_executable(command).nil? -end - -def command_not_running(command : String, *args) : Bool - output = IO::Memory.new - code = Process.run(command, args, output: output).exit_code - code > 0 -end - -def run_command(command : String, *args) : Nil - Process.run(command, args, output: STDOUT, error: STDERR, input: STDIN) -end diff --git a/fixtures/src_template__generate_auth/expected/script/setup.cr b/fixtures/src_template__generate_auth/expected/script/setup.cr deleted file mode 100644 index faa74914..00000000 --- a/fixtures/src_template__generate_auth/expected/script/setup.cr +++ /dev/null @@ -1,32 +0,0 @@ -require "./helpers/*" - -notice "Running System Check" - -require "./system_check" - -print_done - -notice "Installing node dependencies" -run_command "yarn", "install", "--no-progress" - -print_done - -notice "Installing shards" -run_command "shards", "install" - -if !File.exists?(".env") - notice "No .env found. Creating one." - File.touch ".env" - print_done -end - -notice "Setting up the database" - -run_command "lucky", "db.setup" - -notice "Seeding the database with required and sample records" -run_command "lucky", "db.seed.required_data" -run_command "lucky", "db.seed.sample_data" - -print_done -notice "Run 'lucky dev' to start the app" \ No newline at end of file diff --git a/fixtures/src_template__generate_auth/expected/script/system_check.cr b/fixtures/src_template__generate_auth/expected/script/system_check.cr deleted file mode 100644 index c56ce3e9..00000000 --- a/fixtures/src_template__generate_auth/expected/script/system_check.cr +++ /dev/null @@ -1,21 +0,0 @@ -require "./helpers/*" - -# Use this script to check the system for required tools and process that your app needs. -# A few helper functions are provided to keep the code simple. See the -# script/helpers/function_helpers.cr file for more examples. -# -# A few examples you might use here: -# * 'lucky db.verify_connection' to test postgres can be connected -# * Checking that elasticsearch, redis, or postgres is installed and/or booted -# * Note: Booting additional processes for things like mail, background jobs, etc... -# should go in your Procfile.dev. - -if command_not_found "yarn" - print_error "Yarn is not installed\n See https://yarnpkg.com/lang/en/docs/install/ for install instructions." -end - -# CUSTOM PRE-BOOT CHECKS -# example: -# if command_not_running "redis-cli", "ping" -# print_error "Redis is not running." -# end diff --git a/fixtures/src_template__generate_auth/expected/spec/setup/clean_database.cr b/fixtures/src_template__generate_auth/expected/spec/setup/clean_database.cr deleted file mode 100644 index a1bc631c..00000000 --- a/fixtures/src_template__generate_auth/expected/spec/setup/clean_database.cr +++ /dev/null @@ -1,3 +0,0 @@ -Spec.before_each do - AppDatabase.truncate -end diff --git a/fixtures/src_template__generate_auth/expected/spec/setup/reset_emails.cr b/fixtures/src_template__generate_auth/expected/spec/setup/reset_emails.cr deleted file mode 100644 index 140ab416..00000000 --- a/fixtures/src_template__generate_auth/expected/spec/setup/reset_emails.cr +++ /dev/null @@ -1,3 +0,0 @@ -Spec.before_each do - Carbon::DevAdapter.reset -end diff --git a/fixtures/src_template__generate_auth/expected/spec/setup/setup_database.cr b/fixtures/src_template__generate_auth/expected/spec/setup/setup_database.cr deleted file mode 100644 index 393c6da3..00000000 --- a/fixtures/src_template__generate_auth/expected/spec/setup/setup_database.cr +++ /dev/null @@ -1,2 +0,0 @@ -Db::Create.new(quiet: true).call -Db::Migrate.new(quiet: true).call diff --git a/fixtures/src_template__generate_auth/expected/spec/setup/start_app_server.cr b/fixtures/src_template__generate_auth/expected/spec/setup/start_app_server.cr deleted file mode 100644 index ff0bfeeb..00000000 --- a/fixtures/src_template__generate_auth/expected/spec/setup/start_app_server.cr +++ /dev/null @@ -1,10 +0,0 @@ -app_server = AppServer.new - -spawn do - app_server.listen -end - -Spec.after_suite do - LuckyFlow.shutdown - app_server.close -end diff --git a/fixtures/src_template__generate_auth/expected/spec/spec_helper.cr b/fixtures/src_template__generate_auth/expected/spec/spec_helper.cr deleted file mode 100644 index 91223fd7..00000000 --- a/fixtures/src_template__generate_auth/expected/spec/spec_helper.cr +++ /dev/null @@ -1,29 +0,0 @@ -ENV["LUCKY_ENV"] = "test" -ENV["DEV_PORT"] = "5001" -require "spec" -require "lucky_flow" -require "lucky_flow/ext/lucky" -require "lucky_flow/ext/avram" - -require "lucky_flow/ext/authentic" -require "../src/app" -require "./support/flows/base_flow" -require "./support/**" -require "../db/migrations/**" - -# Add/modify files in spec/setup to start/configure programs or run hooks -# -# By default there are scripts for setting up and cleaning the database, -# configuring LuckyFlow, starting the app server, etc. -require "./setup/**" - -include Carbon::Expectations -include Lucky::RequestExpectations -# NOTE: LuckyFlow specs are temporarily set to pending as of Lucky v1.4.0 -# This is due to race conditions in LuckyFlow. -# Ref: https://github.com/luckyframework/lucky_cli/issues/883 -include LuckyFlow::Expectations - -Avram::Migrator::Runner.new.ensure_migrated! -Avram::SchemaEnforcer.ensure_correct_column_mappings! -Habitat.raise_if_missing_settings! diff --git a/fixtures/src_template__generate_auth/expected/spec/support/.keep b/fixtures/src_template__generate_auth/expected/spec/support/.keep deleted file mode 100644 index e69de29b..00000000 diff --git a/fixtures/src_template__generate_auth/expected/spec/support/api_client.cr b/fixtures/src_template__generate_auth/expected/spec/support/api_client.cr deleted file mode 100644 index 46d449a8..00000000 --- a/fixtures/src_template__generate_auth/expected/spec/support/api_client.cr +++ /dev/null @@ -1,12 +0,0 @@ -class ApiClient < Lucky::BaseHTTPClient - app AppServer.new - - def initialize - super - headers("Content-Type": "application/json") - end - - def self.auth(user : User) - new.headers("Authorization": UserToken.generate(user)) - end -end diff --git a/fixtures/src_template__generate_auth/expected/spec/support/factories/.keep b/fixtures/src_template__generate_auth/expected/spec/support/factories/.keep deleted file mode 100644 index e69de29b..00000000 diff --git a/fixtures/src_template__generate_auth/expected/src/actions/api_action.cr b/fixtures/src_template__generate_auth/expected/src/actions/api_action.cr deleted file mode 100644 index a16fd09e..00000000 --- a/fixtures/src_template__generate_auth/expected/src/actions/api_action.cr +++ /dev/null @@ -1,17 +0,0 @@ -# Include modules and add methods that are for all API requests -abstract class ApiAction < Lucky::Action - # APIs typically do not need to send cookie/session data. - # Remove this line if you want to send cookies in the response header. - disable_cookies - accepted_formats [:json] - - include Api::Auth::Helpers - - # By default all actions require sign in. - # Add 'include Api::Auth::SkipRequireAuthToken' to your actions to allow all requests. - include Api::Auth::RequireAuthToken - - # By default all actions are required to use underscores to separate words. - # Add 'include Lucky::SkipRouteStyleCheck' to your actions if you wish to ignore this check for specific routes. - include Lucky::EnforceUnderscoredRoute -end diff --git a/fixtures/src_template__generate_auth/expected/src/actions/errors/show.cr b/fixtures/src_template__generate_auth/expected/src/actions/errors/show.cr deleted file mode 100644 index d01ed541..00000000 --- a/fixtures/src_template__generate_auth/expected/src/actions/errors/show.cr +++ /dev/null @@ -1,63 +0,0 @@ -# This class handles error responses and reporting. -# -# https://luckyframework.org/guides/http-and-routing/error-handling -class Errors::Show < Lucky::ErrorAction - DEFAULT_MESSAGE = "Something went wrong." - default_format :html - dont_report [Lucky::RouteNotFoundError, Avram::RecordNotFoundError] - - def render(error : Lucky::RouteNotFoundError | Avram::RecordNotFoundError) - if html? - error_html "Sorry, we couldn't find that page.", status: 404 - else - error_json "Not found", status: 404 - end - end - - # When the request is JSON and an InvalidOperationError is raised, show a - # helpful error with the param that is invalid, and what was wrong with it. - def render(error : Avram::InvalidOperationError) - if html? - error_html DEFAULT_MESSAGE, status: 500 - else - error_json \ - message: error.renderable_message, - details: error.renderable_details, - param: error.invalid_attribute_name, - status: 400 - end - end - - # Always keep this below other 'render' methods or it may override your - # custom 'render' methods. - def render(error : Lucky::RenderableError) - if html? - error_html DEFAULT_MESSAGE, status: error.renderable_status - else - error_json error.renderable_message, status: error.renderable_status - end - end - - # If none of the 'render' methods return a response for the raised Exception, - # Lucky will use this method. - def default_render(error : Exception) : Lucky::Response - if html? - error_html DEFAULT_MESSAGE, status: 500 - else - error_json DEFAULT_MESSAGE, status: 500 - end - end - - private def error_html(message : String, status : Int) - context.response.status_code = status - html_with_status Errors::ShowPage, status, message: message, status_code: status - end - - private def error_json(message : String, status : Int, details = nil, param = nil) - json ErrorSerializer.new(message: message, details: details, param: param), status: status - end - - private def report(error : Exception) : Nil - # Send to Rollbar, send an email, etc. - end -end diff --git a/fixtures/src_template__generate_auth/expected/src/actions/home/index.cr b/fixtures/src_template__generate_auth/expected/src/actions/home/index.cr deleted file mode 100644 index f780130a..00000000 --- a/fixtures/src_template__generate_auth/expected/src/actions/home/index.cr +++ /dev/null @@ -1,18 +0,0 @@ -class Home::Index < BrowserAction - include Auth::AllowGuests - - get "/" do - if current_user? - redirect Me::Show - else - # When you're ready change this line to: - # - # redirect SignIns::New - # - # Or maybe show signed out users a marketing page: - # - # html Marketing::IndexPage - html Lucky::WelcomePage - end - end -end diff --git a/fixtures/src_template__generate_auth/expected/src/actions/mixins/.keep b/fixtures/src_template__generate_auth/expected/src/actions/mixins/.keep deleted file mode 100644 index e69de29b..00000000 diff --git a/fixtures/src_template__generate_auth/expected/src/app.cr b/fixtures/src_template__generate_auth/expected/src/app.cr deleted file mode 100644 index d343c8cd..00000000 --- a/fixtures/src_template__generate_auth/expected/src/app.cr +++ /dev/null @@ -1,37 +0,0 @@ -require "./shards" - -# Load the asset manifest -# In development, vite-plugin-dev-manifest creates public/manifest.dev.json -# In production, Vite creates public/.vite/manifest.json -# The manifest path is determined by which file exists at compile time -{% if File.exists?("public/manifest.dev.json") %} - Lucky::AssetHelpers.load_manifest "public/manifest.dev.json", use_vite: true -{% elsif File.exists?("public/.vite/manifest.json") %} - Lucky::AssetHelpers.load_manifest "public/.vite/manifest.json", use_vite: true -{% else %} - # For initial compilation, we'll assume development mode - # The dev server will create the manifest before the app is recompiled - Lucky::AssetHelpers.load_manifest "public/manifest.dev.json", use_vite: true -{% end %} - -require "../config/server" -require "./app_database" -require "../config/**" -require "./models/base_model" -require "./models/mixins/**" -require "./models/**" -require "./queries/mixins/**" -require "./queries/**" -require "./operations/mixins/**" -require "./operations/**" -require "./serializers/base_serializer" -require "./serializers/**" -require "./emails/base_email" -require "./emails/**" -require "./actions/mixins/**" -require "./actions/**" -require "./components/base_component" -require "./components/**" -require "./pages/**" -require "../db/migrations/**" -require "./app_server" \ No newline at end of file diff --git a/fixtures/src_template__generate_auth/expected/src/app_database.cr b/fixtures/src_template__generate_auth/expected/src/app_database.cr deleted file mode 100644 index 0efd4f50..00000000 --- a/fixtures/src_template__generate_auth/expected/src/app_database.cr +++ /dev/null @@ -1,2 +0,0 @@ -class AppDatabase < Avram::Database -end diff --git a/fixtures/src_template__generate_auth/expected/src/app_server.cr b/fixtures/src_template__generate_auth/expected/src/app_server.cr deleted file mode 100644 index 8ec16c3c..00000000 --- a/fixtures/src_template__generate_auth/expected/src/app_server.cr +++ /dev/null @@ -1,26 +0,0 @@ -class AppServer < Lucky::BaseAppServer - # Learn about middleware with HTTP::Handlers: - # https://luckyframework.org/guides/http-and-routing/http-handlers - def middleware : Array(HTTP::Handler) - [ - Lucky::RequestIdHandler.new, - Lucky::ForceSSLHandler.new, - Lucky::HttpMethodOverrideHandler.new, - Lucky::LogHandler.new, - Lucky::ErrorHandler.new(action: Errors::Show), - Lucky::RemoteIpHandler.new, - Lucky::RouteHandler.new, - Lucky::StaticCompressionHandler.new("./public", file_ext: "gz", content_encoding: "gzip"), - Lucky::StaticFileHandler.new("./public", fallthrough: false, directory_listing: false), - Lucky::RouteNotFoundHandler.new, - ] of HTTP::Handler - end - - def protocol - "http" - end - - def listen - server.listen(host, port, reuse_port: false) - end -end diff --git a/fixtures/src_template__generate_auth/expected/src/emails/base_email.cr b/fixtures/src_template__generate_auth/expected/src/emails/base_email.cr deleted file mode 100644 index 656f4f11..00000000 --- a/fixtures/src_template__generate_auth/expected/src/emails/base_email.cr +++ /dev/null @@ -1,15 +0,0 @@ -# Learn about sending emails -# https://luckyframework.org/guides/emails/sending-emails-with-carbon -abstract class BaseEmail < Carbon::Email - # You can add defaults using the 'inherited' hook - # - # Example: - # - # macro inherited - # from default_from - # end - # - # def default_from - # Carbon::Address.new("support@app.com") - # end -end diff --git a/fixtures/src_template__generate_auth/expected/src/models/base_model.cr b/fixtures/src_template__generate_auth/expected/src/models/base_model.cr deleted file mode 100644 index 6bafeb84..00000000 --- a/fixtures/src_template__generate_auth/expected/src/models/base_model.cr +++ /dev/null @@ -1,5 +0,0 @@ -abstract class BaseModel < Avram::Model - def self.database : Avram::Database.class - AppDatabase - end -end diff --git a/fixtures/src_template__generate_auth/expected/src/models/mixins/.keep b/fixtures/src_template__generate_auth/expected/src/models/mixins/.keep deleted file mode 100644 index e69de29b..00000000 diff --git a/fixtures/src_template__generate_auth/expected/src/operations/.keep b/fixtures/src_template__generate_auth/expected/src/operations/.keep deleted file mode 100644 index e69de29b..00000000 diff --git a/fixtures/src_template__generate_auth/expected/src/operations/mixins/.keep b/fixtures/src_template__generate_auth/expected/src/operations/mixins/.keep deleted file mode 100644 index e69de29b..00000000 diff --git a/fixtures/src_template__generate_auth/expected/src/queries/.keep b/fixtures/src_template__generate_auth/expected/src/queries/.keep deleted file mode 100644 index e69de29b..00000000 diff --git a/fixtures/src_template__generate_auth/expected/src/queries/mixins/.keep b/fixtures/src_template__generate_auth/expected/src/queries/mixins/.keep deleted file mode 100644 index e69de29b..00000000 diff --git a/fixtures/src_template__generate_auth/expected/src/serializers/.keep b/fixtures/src_template__generate_auth/expected/src/serializers/.keep deleted file mode 100644 index e69de29b..00000000 diff --git a/fixtures/src_template__generate_auth/expected/src/serializers/base_serializer.cr b/fixtures/src_template__generate_auth/expected/src/serializers/base_serializer.cr deleted file mode 100644 index e769f5c0..00000000 --- a/fixtures/src_template__generate_auth/expected/src/serializers/base_serializer.cr +++ /dev/null @@ -1,18 +0,0 @@ -abstract class BaseSerializer - include Lucky::Serializable - - def self.for_collection(collection : Enumerable, *args, **named_args) : Array(self) - collection.map do |object| - new(object, *args, **named_args) - end - end - - def self.for_collection(collection : Enumerable, pages : Lucky::Paginator, *args, **named_args) - { - "items" => collection.map do |object| - new(object, *args, **named_args) - end, - "pagination" => PaginationSerializer.new(pages), - } - end -end diff --git a/fixtures/src_template__generate_auth/expected/src/serializers/error_serializer.cr b/fixtures/src_template__generate_auth/expected/src/serializers/error_serializer.cr deleted file mode 100644 index b7b55283..00000000 --- a/fixtures/src_template__generate_auth/expected/src/serializers/error_serializer.cr +++ /dev/null @@ -1,14 +0,0 @@ -# This is the default error serializer generated by Lucky. -# Feel free to customize it in any way you like. -class ErrorSerializer < BaseSerializer - def initialize( - @message : String, - @details : String? = nil, - @param : String? = nil, # so you can track which param (if any) caused the problem - ) - end - - def render - {message: @message, param: @param, details: @details} - end -end diff --git a/fixtures/src_template__generate_auth/expected/src/serializers/pagination_serializer.cr b/fixtures/src_template__generate_auth/expected/src/serializers/pagination_serializer.cr deleted file mode 100644 index 9e44788c..00000000 --- a/fixtures/src_template__generate_auth/expected/src/serializers/pagination_serializer.cr +++ /dev/null @@ -1,15 +0,0 @@ -# This is the default pagination serializer generated by Lucky. -# Feel free to customize it in any way you like. -class PaginationSerializer < BaseSerializer - def initialize(@pages : Lucky::Paginator) - end - - def render - { - next_page: @pages.path_to_next, - previous_page: @pages.path_to_previous, - total_items: @pages.item_count, - total_pages: @pages.total, - } - end -end diff --git a/fixtures/src_template__generate_auth/expected/src/shards.cr b/fixtures/src_template__generate_auth/expected/src/shards.cr deleted file mode 100644 index 7cadec18..00000000 --- a/fixtures/src_template__generate_auth/expected/src/shards.cr +++ /dev/null @@ -1,10 +0,0 @@ -# Load .env file before any other config or app code -require "lucky_env" -LuckyEnv.load?(".env") - -# Require your shards here -require "lucky" -require "avram/lucky" -require "carbon" -require "authentic" -require "jwt" diff --git a/fixtures/src_template__generate_auth/expected/src/start_server.cr b/fixtures/src_template__generate_auth/expected/src/start_server.cr deleted file mode 100644 index de8af78e..00000000 --- a/fixtures/src_template__generate_auth/expected/src/start_server.cr +++ /dev/null @@ -1,17 +0,0 @@ -require "./app" - -Habitat.raise_if_missing_settings! - -if LuckyEnv.development? - Avram::Migrator::Runner.new.ensure_migrated! - Avram::SchemaEnforcer.ensure_correct_column_mappings! -end - -app_server = AppServer.new -puts "Listening on http://#{app_server.host}:#{app_server.port}" - -Signal::INT.trap do - app_server.close -end - -app_server.listen diff --git a/fixtures/src_template__generate_auth/expected/src/test_project.cr b/fixtures/src_template__generate_auth/expected/src/test_project.cr deleted file mode 100644 index 68e1a8d2..00000000 --- a/fixtures/src_template__generate_auth/expected/src/test_project.cr +++ /dev/null @@ -1,6 +0,0 @@ -# Typically you will not use or modify this file. 'shards build' and some -# other crystal tools will sometimes use this. -# -# When this file is compiled/run it will require and run 'start_server', -# which as its name implies will start the server for you app. -require "./start_server" diff --git a/fixtures/src_template__generate_auth/expected/tasks.cr b/fixtures/src_template__generate_auth/expected/tasks.cr deleted file mode 100644 index 5a892d4d..00000000 --- a/fixtures/src_template__generate_auth/expected/tasks.cr +++ /dev/null @@ -1,25 +0,0 @@ -# This file loads your app and all your tasks when running 'lucky' -# -# Run 'lucky --help' to see all available tasks. -# -# Learn to create your own tasks: -# https://luckyframework.org/guides/command-line-tasks/custom-tasks - -# See `LuckyEnv#task?` -ENV["LUCKY_TASK"] = "true" - -# Load Lucky and the app (actions, models, etc.) -require "./src/app" -require "lucky_task" - -# You can add your own tasks here in the ./tasks folder -require "./tasks/**" - -# Load migrations -require "./db/migrations/**" - -# Load Lucky tasks (dev, routes, etc.) -require "lucky/tasks/**" -require "avram/lucky/tasks" - -LuckyTask::Runner.run diff --git a/fixtures/src_template__generate_auth/expected/tasks/.keep b/fixtures/src_template__generate_auth/expected/tasks/.keep deleted file mode 100644 index e69de29b..00000000 diff --git a/fixtures/src_template__generate_auth/expected/tasks/db/seed/required_data.cr b/fixtures/src_template__generate_auth/expected/tasks/db/seed/required_data.cr deleted file mode 100644 index d866040f..00000000 --- a/fixtures/src_template__generate_auth/expected/tasks/db/seed/required_data.cr +++ /dev/null @@ -1,30 +0,0 @@ -require "../../../spec/support/factories/**" - -# Add seeds here that are *required* for your app to work. -# For example, you might need at least one admin user or you might need at least -# one category for your blog posts for the app to work. -# -# Use `Db::Seed::SampleData` if your only want to add sample data helpful for -# development. -class Db::Seed::RequiredData < LuckyTask::Task - summary "Add database records required for the app to work" - - def call - # Using a Avram::Factory: - # - # Use the defaults, but override just the email - # UserFactory.create &.email("me@example.com") - - # Using a SaveOperation: - # - # SaveUser.create!(email: "me@example.com", name: "Jane") - # - # You likely want to be able to run this file more than once. To do that, - # only create the record if it doesn't exist yet: - # - # unless UserQuery.new.email("me@example.com").first? - # SaveUser.create!(email: "me@example.com", name: "Jane") - # end - puts "Done adding required data" - end -end diff --git a/fixtures/src_template__generate_auth/expected/tasks/db/seed/sample_data.cr b/fixtures/src_template__generate_auth/expected/tasks/db/seed/sample_data.cr deleted file mode 100644 index 231d7e8d..00000000 --- a/fixtures/src_template__generate_auth/expected/tasks/db/seed/sample_data.cr +++ /dev/null @@ -1,30 +0,0 @@ -require "../../../spec/support/factories/**" - -# Add sample data helpful for development, e.g. (fake users, blog posts, etc.) -# -# Use `Db::Seed::RequiredData` if you need to create data *required* for your -# app to work. -class Db::Seed::SampleData < LuckyTask::Task - summary "Add sample database records helpful for development" - - def call - # Using an Avram::Factory: - # - # Use the defaults, but override just the email - # UserFactory.create &.email("me@example.com") - - # Using a SaveOperation: - # ``` - # SignUpUser.create!(email: "me@example.com", password: "test123", password_confirmation: "test123") - # ``` - # - # You likely want to be able to run this file more than once. To do that, - # only create the record if it doesn't exist yet: - # ``` - # if UserQuery.new.email("me@example.com").none? - # SignUpUser.create!(email: "me@example.com", password: "test123", password_confirmation: "test123") - # end - # ``` - puts "Done adding sample data" - end -end diff --git a/fixtures/src_template__sec_tester/expected/.crystal-version b/fixtures/src_template__sec_tester/expected/.crystal-version deleted file mode 100644 index 41c11ffb..00000000 --- a/fixtures/src_template__sec_tester/expected/.crystal-version +++ /dev/null @@ -1 +0,0 @@ -1.16.1 diff --git a/fixtures/src_template__sec_tester/expected/.env b/fixtures/src_template__sec_tester/expected/.env deleted file mode 100644 index e69de29b..00000000 diff --git a/fixtures/src_template__sec_tester/expected/.github/workflows/ci.yml b/fixtures/src_template__sec_tester/expected/.github/workflows/ci.yml deleted file mode 100644 index 310ca50d..00000000 --- a/fixtures/src_template__sec_tester/expected/.github/workflows/ci.yml +++ /dev/null @@ -1,113 +0,0 @@ -name: test-project CI - -on: - push: - branches: "*" - pull_request: - branches: "*" - -jobs: - check-format: - strategy: - fail-fast: false - matrix: - crystal_version: - - 1.16.1 - experimental: - - false - runs-on: ubuntu-latest - continue-on-error: ${{ matrix.experimental }} - steps: - - uses: actions/checkout@v4 - - name: Install Crystal - uses: crystal-lang/install-crystal@v1 - with: - crystal: ${{ matrix.crystal_version }} - - name: Format - run: crystal tool format --check - - specs: - strategy: - fail-fast: false - matrix: - crystal_version: - - 1.16.1 - experimental: - - false - runs-on: ubuntu-latest - env: - LUCKY_ENV: test - DB_HOST: localhost - continue-on-error: ${{ matrix.experimental }} - services: - postgres: - image: postgres:14-alpine - env: - POSTGRES_PASSWORD: postgres - ports: - - 5432:5432 - # Set health checks to wait until postgres has started - options: >- - --health-cmd pg_isready - --health-interval 10s - --health-timeout 5s - --health-retries 5 - - steps: - - uses: actions/checkout@v4 - - name: Install Crystal - uses: crystal-lang/install-crystal@v1 - with: - crystal: ${{ matrix.crystal_version }} - - - name: Get yarn cache directory path - id: yarn-cache-dir-path - run: echo "::set-output name=dir::$(yarn cache dir)" - - - name: Set up Yarn cache - uses: actions/cache@v4 - with: - path: ${{ steps.yarn-cache-dir-path.outputs.dir }} - key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }} - restore-keys: | - ${{ runner.os }}-yarn- - - - name: Set up Node cache - uses: actions/cache@v4 - id: node-cache # use this to check for `cache-hit` (`steps.node-cache.outputs.cache-hit != 'true'`) - with: - path: '**/node_modules' - key: ${{ runner.os }}-node-${{ hashFiles('**/yarn.lock') }} - restore-keys: | - ${{ runner.os }}-node- - - name: Set up Crystal cache - uses: actions/cache@v4 - id: crystal-cache - with: - path: | - ~/.cache/crystal - lib - key: ${{ runner.os }}-crystal-${{ hashFiles('**/shard.lock') }} - restore-keys: | - ${{ runner.os }}-crystal- - - - name: Install shards - if: steps.crystal-cache.outputs.cache-hit != 'true' - run: shards check || shards install - - - name: Install yarn packages - if: steps.node-cache.outputs.cache-hit != 'true' - run: yarn install --frozen-lockfile --no-progress - - name: Compiling assets - run: yarn prod - - name: Build lucky_tasks - run: crystal build tasks.cr -o ./lucky_tasks - - - name: Prepare database - run: | - ./lucky_tasks db.create - ./lucky_tasks db.migrate - ./lucky_tasks db.seed.required_data - - - name: Run tests - run: crystal spec -Dwith_sec_tests \ No newline at end of file diff --git a/fixtures/src_template__sec_tester/expected/Procfile b/fixtures/src_template__sec_tester/expected/Procfile deleted file mode 100644 index e524d70d..00000000 --- a/fixtures/src_template__sec_tester/expected/Procfile +++ /dev/null @@ -1,2 +0,0 @@ -web: bin/app -release: lucky db.migrate diff --git a/fixtures/src_template__sec_tester/expected/Procfile.dev b/fixtures/src_template__sec_tester/expected/Procfile.dev deleted file mode 100644 index 80369f14..00000000 --- a/fixtures/src_template__sec_tester/expected/Procfile.dev +++ /dev/null @@ -1,3 +0,0 @@ -system_check: crystal script/system_check.cr -web: lucky watch --reload-browser -assets: yarn dev diff --git a/fixtures/src_template__sec_tester/expected/README.md b/fixtures/src_template__sec_tester/expected/README.md deleted file mode 100644 index da2d97cc..00000000 --- a/fixtures/src_template__sec_tester/expected/README.md +++ /dev/null @@ -1,23 +0,0 @@ -# test-project - -This is a project written using [Lucky](https://luckyframework.org). Enjoy! - -### Setting up the project - -1. [Install required dependencies](https://luckyframework.org/guides/getting-started/installing#install-required-dependencies) -1. Update database settings in `config/database.cr` -1. Run `script/setup` -1. Run `lucky dev` to start the app - -### Using Docker for development - -1. [Install Docker](https://docs.docker.com/engine/install/) -1. Run `docker compose up` - -The Docker container will boot all of the necessary components needed to run your Lucky application. -To configure the container, update the `docker-compose.yml` file, and the `docker/development.dockerfile` file. - - -### Learning Lucky - -Lucky uses the [Crystal](https://crystal-lang.org) programming language. You can learn about Lucky from the [Lucky Guides](https://luckyframework.org/guides/getting-started/why-lucky). diff --git a/fixtures/src_template__sec_tester/expected/config/application.cr b/fixtures/src_template__sec_tester/expected/config/application.cr deleted file mode 100644 index c807149a..00000000 --- a/fixtures/src_template__sec_tester/expected/config/application.cr +++ /dev/null @@ -1,24 +0,0 @@ -# This file may be used for custom Application configurations. -# It will be loaded before other config files. -# -# Read more on configuration: -# https://luckyframework.org/guides/getting-started/configuration#configuring-your-own-code - -# Use this code as an example: -# -# ``` -# module Application -# Habitat.create do -# setting support_email : String -# setting lock_with_basic_auth : Bool -# end -# end -# -# Application.configure do |settings| -# settings.support_email = "support@myapp.io" -# settings.lock_with_basic_auth = LuckyEnv.staging? -# end -# -# # In your application, call -# # `Application.settings.support_email` anywhere you need it. -# ``` diff --git a/fixtures/src_template__sec_tester/expected/config/colors.cr b/fixtures/src_template__sec_tester/expected/config/colors.cr deleted file mode 100644 index 761ae940..00000000 --- a/fixtures/src_template__sec_tester/expected/config/colors.cr +++ /dev/null @@ -1,4 +0,0 @@ -# This enables the color output when in development or test -# Check out the Colorize docs for more information -# https://crystal-lang.org/api/Colorize.html -Colorize.enabled = LuckyEnv.development? || LuckyEnv.test? diff --git a/fixtures/src_template__sec_tester/expected/config/cookies.cr b/fixtures/src_template__sec_tester/expected/config/cookies.cr deleted file mode 100644 index 2d5055f2..00000000 --- a/fixtures/src_template__sec_tester/expected/config/cookies.cr +++ /dev/null @@ -1,25 +0,0 @@ -require "./server" - -Lucky::Session.configure do |settings| - settings.key = "_test_project_session" -end - -Lucky::CookieJar.configure do |settings| - settings.on_set = ->(cookie : HTTP::Cookie) { - # If ForceSSLHandler is enabled, only send cookies over HTTPS - cookie.secure(Lucky::ForceSSLHandler.settings.enabled) - - # By default, don't allow reading cookies with JavaScript - cookie.http_only(true) - - # Restrict cookies to a first-party or same-site context - cookie.samesite(:lax) - - # Set all cookies to the root path by default - cookie.path("/") - - # You can set other defaults for cookies here. For example: - # - # cookie.expires(1.year.from_now).domain("mydomain.com") - } -end diff --git a/fixtures/src_template__sec_tester/expected/config/database.cr b/fixtures/src_template__sec_tester/expected/config/database.cr deleted file mode 100644 index f614299a..00000000 --- a/fixtures/src_template__sec_tester/expected/config/database.cr +++ /dev/null @@ -1,29 +0,0 @@ -database_name = "test_project_#{LuckyEnv.environment}" - -AppDatabase.configure do |settings| - if LuckyEnv.production? - settings.credentials = Avram::Credentials.parse(ENV["DATABASE_URL"]) - else - settings.credentials = Avram::Credentials.parse?(ENV["DATABASE_URL"]?) || Avram::Credentials.new( - database: database_name, - hostname: ENV["DB_HOST"]? || "localhost", - port: ENV["DB_PORT"]?.try(&.to_i) || 5432, - # Some common usernames are "postgres", "root", or your system username (run 'whoami') - username: ENV["DB_USERNAME"]? || "postgres", - # Some Postgres installations require no password. Use "" if that is the case. - password: ENV["DB_PASSWORD"]? || "postgres" - ) - end -end - -Avram.configure do |settings| - settings.database_to_migrate = AppDatabase - - # In production, allow lazy loading (N+1). - # In development and test, raise an error if you forget to preload associations - settings.lazy_load_enabled = LuckyEnv.production? - - # Always parse `Time` values with these specific formats. - # Used for both database values, and datetime input fields. - # settings.time_formats << "%F" -end diff --git a/fixtures/src_template__sec_tester/expected/config/email.cr b/fixtures/src_template__sec_tester/expected/config/email.cr deleted file mode 100644 index 7c875449..00000000 --- a/fixtures/src_template__sec_tester/expected/config/email.cr +++ /dev/null @@ -1,26 +0,0 @@ -require "carbon_sendgrid_adapter" - -BaseEmail.configure do |settings| - if LuckyEnv.production? - # If you don't need to send emails, set the adapter to DevAdapter instead: - # - # settings.adapter = Carbon::DevAdapter.new - # - # If you do need emails, get a key from SendGrid and set an ENV variable - send_grid_key = send_grid_key_from_env - settings.adapter = Carbon::SendGridAdapter.new(api_key: send_grid_key) - elsif LuckyEnv.development? - settings.adapter = Carbon::DevAdapter.new(print_emails: true) - else - settings.adapter = Carbon::DevAdapter.new - end -end - -private def send_grid_key_from_env - ENV["SEND_GRID_KEY"]? || raise_missing_key_message -end - -private def raise_missing_key_message - puts "Missing SEND_GRID_KEY. Set the SEND_GRID_KEY env variable to 'unused' if not sending emails, or set the SEND_GRID_KEY ENV var.".colorize.red - exit(1) -end diff --git a/fixtures/src_template__sec_tester/expected/config/env.cr b/fixtures/src_template__sec_tester/expected/config/env.cr deleted file mode 100644 index 3f364072..00000000 --- a/fixtures/src_template__sec_tester/expected/config/env.cr +++ /dev/null @@ -1,33 +0,0 @@ -# Environments are managed using `LuckyEnv`. By default, development, production -# and test are supported. See -# https://luckyframework.org/guides/getting-started/configuration for details. -# -# The default environment is development unless the environment variable -# LUCKY_ENV is set. -# -# Example: -# ``` -# LuckyEnv.environment # => "development" -# LuckyEnv.development? # => true -# LuckyEnv.production? # => false -# LuckyEnv.test? # => false -# ``` -# -# New environments can be added using the `LuckyEnv.add_env` macro. -# -# Example: -# ``` -# LuckyEnv.add_env :staging -# LuckyEnv.staging? # => false -# ``` -# -# To determine whether or not a `LuckyTask` is currently running, you can use -# the `LuckyEnv.task?` predicate. -# -# Example: -# ``` -# LuckyEnv.task? # => false -# ``` - -# Add a staging environment. -# LuckyEnv.add_env :staging diff --git a/fixtures/src_template__sec_tester/expected/config/error_handler.cr b/fixtures/src_template__sec_tester/expected/config/error_handler.cr deleted file mode 100644 index c6b736e3..00000000 --- a/fixtures/src_template__sec_tester/expected/config/error_handler.cr +++ /dev/null @@ -1,3 +0,0 @@ -Lucky::ErrorHandler.configure do |settings| - settings.show_debug_output = !LuckyEnv.production? -end diff --git a/fixtures/src_template__sec_tester/expected/config/log.cr b/fixtures/src_template__sec_tester/expected/config/log.cr deleted file mode 100644 index a43940d9..00000000 --- a/fixtures/src_template__sec_tester/expected/config/log.cr +++ /dev/null @@ -1,50 +0,0 @@ -require "file_utils" - -if LuckyEnv.test? - # Logs to `tmp/test.log` so you can see what's happening without having - # a bunch of log output in your spec results. - FileUtils.mkdir_p("tmp") - - backend = Log::IOBackend.new(File.new("tmp/test.log", mode: "w")) - backend.formatter = Lucky::PrettyLogFormatter.proc - Log.dexter.configure(:debug, backend) -elsif LuckyEnv.production? - # Lucky uses JSON in production so logs can be searched more easily - # - # If you want logs like in development use 'Lucky::PrettyLogFormatter.proc'. - backend = Log::IOBackend.new - backend.formatter = Dexter::JSONLogFormatter.proc - Log.dexter.configure(:info, backend) -else - # Use a pretty formatter printing to STDOUT in development - backend = Log::IOBackend.new - backend.formatter = Lucky::PrettyLogFormatter.proc - Log.dexter.configure(:debug, backend) - DB::Log.level = :info -end - -# Lucky only logs when before/after pipes halt by redirecting, or rendering a -# response. Pipes that run without halting are not logged. -# -# If you want to log every pipe that runs, set the log level to ':info' -Lucky::ContinuedPipeLog.dexter.configure(:none) - -# Lucky only logs failed queries by default. -# -# Set the log to ':info' to log all queries -Avram::QueryLog.dexter.configure(:none) - -# Subscribe to Pulsar events to log when queries are made, -# queries fail, or save operations fail. Remove this to -# disable these log events without disabling all logging. -Avram.initialize_logging - -# Skip logging static assets requests in development -Lucky::LogHandler.configure do |settings| - if LuckyEnv.development? - settings.skip_if = ->(context : HTTP::Server::Context) { - context.request.method.downcase == "get" && - context.request.resource.starts_with?(/\/css\/|\/js\/|\/assets\/|\/favicon\.ico/) - } - end -end diff --git a/fixtures/src_template__sec_tester/expected/config/route_helper.cr b/fixtures/src_template__sec_tester/expected/config/route_helper.cr deleted file mode 100644 index ede1f328..00000000 --- a/fixtures/src_template__sec_tester/expected/config/route_helper.cr +++ /dev/null @@ -1,10 +0,0 @@ -# This is used when generating URLs for your application -Lucky::RouteHelper.configure do |settings| - if LuckyEnv.production? - # Example: https://my_app.com - settings.base_uri = ENV.fetch("APP_DOMAIN") - else - # Set domain to the default host/port in development/test - settings.base_uri = "http://localhost:#{Lucky::ServerSettings.port}" - end -end diff --git a/fixtures/src_template__sec_tester/expected/config/server.cr b/fixtures/src_template__sec_tester/expected/config/server.cr deleted file mode 100644 index b7cca25c..00000000 --- a/fixtures/src_template__sec_tester/expected/config/server.cr +++ /dev/null @@ -1,68 +0,0 @@ -# Here is where you configure the Lucky server -# -# Look at config/route_helper.cr if you want to change the domain used when -# generating links with `Action.url`. -Lucky::Server.configure do |settings| - if LuckyEnv.production? - settings.secret_key_base = secret_key_from_env - settings.host = "0.0.0.0" - settings.port = ENV["PORT"].to_i - settings.gzip_enabled = true - # By default certain content types will be gzipped. - # For a full list look in - # https://github.com/luckyframework/lucky/blob/main/src/lucky/server.cr - # To add additional extensions do something like this: - # settings.gzip_content_types << "content/type" - else - settings.secret_key_base = "1234567890" - # Change host/port in config/watch.yml - # Alternatively, you can set the DEV_PORT env to set the port for local development - settings.host = Lucky::ServerSettings.host - settings.port = Lucky::ServerSettings.port - end - - # Configure the asset build system (default is Vite) - settings.asset_build_system = Lucky::AssetBuilder::Vite.new - - # Configure asset host for Vite - if LuckyEnv.development? - # In development, Vite serves assets from its dev server - settings.asset_host = "http://localhost:3001" - elsif LuckyEnv.production? - # In production, Lucky serves the built assets - # You could also use a CDN here: - # settings.asset_host = "https://mycdnhost.com" - settings.asset_host = "" - else - settings.asset_host = "" - end -end - -Lucky::ForceSSLHandler.configure do |settings| - # To force SSL in production, uncomment the lines below. - # This will cause http requests to be redirected to https: - # - # settings.enabled = LuckyEnv.production? - # settings.strict_transport_security = {max_age: 1.year, include_subdomains: true} - # - # Or, leave it disabled: - settings.enabled = false -end - -# Set a unique ID for each HTTP request. -# To enable the request ID, uncomment the lines below. -# You can set your own custom String, or use a random UUID. -# Lucky::RequestIdHandler.configure do |settings| -# settings.set_request_id = ->(context : HTTP::Server::Context) { -# UUID.random.to_s -# } -# end - -private def secret_key_from_env - ENV["SECRET_KEY_BASE"]? || raise_missing_secret_key_in_production -end - -private def raise_missing_secret_key_in_production - puts "Please set the SECRET_KEY_BASE environment variable. You can generate a secret key with 'lucky gen.secret_key'".colorize.red - exit(1) -end \ No newline at end of file diff --git a/fixtures/src_template__sec_tester/expected/config/watch.yml b/fixtures/src_template__sec_tester/expected/config/watch.yml deleted file mode 100644 index 3a59b410..00000000 --- a/fixtures/src_template__sec_tester/expected/config/watch.yml +++ /dev/null @@ -1,3 +0,0 @@ -host: 127.0.0.1 -port: 3000 -reload_port: 3001 diff --git a/fixtures/src_template__sec_tester/expected/db/migrations/.keep b/fixtures/src_template__sec_tester/expected/db/migrations/.keep deleted file mode 100644 index e69de29b..00000000 diff --git a/fixtures/src_template__sec_tester/expected/docker-compose.yml b/fixtures/src_template__sec_tester/expected/docker-compose.yml deleted file mode 100644 index d00779db..00000000 --- a/fixtures/src_template__sec_tester/expected/docker-compose.yml +++ /dev/null @@ -1,45 +0,0 @@ -version: "3.8" -services: - lucky: - build: - context: . - dockerfile: docker/development.dockerfile - environment: - DATABASE_URL: postgres://lucky:password@postgres:5432/lucky - DEV_HOST: "0.0.0.0" - volumes: - - .:/app - - node_modules:/app/node_modules - - shards_lib:/app/lib - - app_bin:/app/bin - - build_cache:/root/.cache - depends_on: - - postgres - ports: - - 3000:3000 # This is the Lucky Server port - - 3001:3001 # This is the Lucky watcher reload port - - entrypoint: ["docker/dev_entrypoint.sh"] - - postgres: - image: postgres:14-alpine - environment: - POSTGRES_USER: lucky - POSTGRES_PASSWORD: password - POSTGRES_DB: lucky - volumes: - - postgres_data:/var/lib/postgresql/data - ports: - # The postgres database container is exposed on the host at port 6543 to - # allow connecting directly to it with postgres clients. The port differs - # from the postgres default to avoid conflict with existing postgres - # servers. Connect to a running postgres container with: - # postgres://lucky:password@localhost:6543/lucky - - 6543:5432 - -volumes: - postgres_data: - node_modules: - shards_lib: - app_bin: - build_cache: diff --git a/fixtures/src_template__sec_tester/expected/docker/dev_entrypoint.sh b/fixtures/src_template__sec_tester/expected/docker/dev_entrypoint.sh deleted file mode 100755 index d16ef6ab..00000000 --- a/fixtures/src_template__sec_tester/expected/docker/dev_entrypoint.sh +++ /dev/null @@ -1,46 +0,0 @@ -#!/bin/bash - -set -euo pipefail - -# This is the entrypoint script used for development docker workflows. -# By default it will: -# - Install dependencies. -# - Run migrations. -# - Start the dev server. -# It also accepts any commands to be run instead. - - -warnfail () { - echo "$@" >&2 - exit 1 -} - -case ${1:-} in - "") # If no arguments are provided, start lucky dev server. - ;; - - *) # If any arguments are provided, execute them instead. - exec "$@" -esac - -if ! [ -d bin ] ; then - echo 'Creating bin directory' - mkdir bin -fi -echo 'Installing npm packages...' -yarn install -if ! shards check ; then - echo 'Installing shards...' - shards install -fi - -echo 'Waiting for postgres to be available...' -./docker/wait-for-it.sh -q postgres:5432 - -if ! psql -d "$DATABASE_URL" -c '\d migrations' > /dev/null ; then - echo 'Finishing database setup...' - lucky db.migrate -fi - -echo 'Starting lucky dev server...' -exec lucky dev diff --git a/fixtures/src_template__sec_tester/expected/docker/development.dockerfile b/fixtures/src_template__sec_tester/expected/docker/development.dockerfile deleted file mode 100644 index 962ad66c..00000000 --- a/fixtures/src_template__sec_tester/expected/docker/development.dockerfile +++ /dev/null @@ -1,33 +0,0 @@ -FROM crystallang/crystal:1.16.1 - -# Install utilities required to make this Dockerfile run -RUN apt-get update && \ - apt-get install -y wget -# Add the nodesource ppa to apt. Update this to change the nodejs version. -RUN wget https://deb.nodesource.com/setup_16.x -O- | bash - -# Apt installs: -# - nodejs (from above ppa) is required for front-end apps. -# - Postgres cli tools are required for lucky-cli. -# - tmux is required for the Overmind process manager. -RUN apt-get update && \ - apt-get install -y nodejs postgresql-client tmux && \ - rm -rf /var/lib/apt/lists/* - -# NPM global installs: -# - Yarn is the default package manager for the node component of a lucky -# browser app. -RUN npm install -g yarn - -# Install lucky cli -WORKDIR /lucky/cli -RUN git clone https://github.com/luckyframework/lucky_cli . && \ - git checkout v1.3.0 && \ - shards build --without-development && \ - cp bin/lucky /usr/bin - -WORKDIR /app -ENV DATABASE_URL=postgres://postgres:postgres@host.docker.internal:5432/postgres -EXPOSE 3000 -EXPOSE 3001 - diff --git a/fixtures/src_template__sec_tester/expected/docker/wait-for-it.sh b/fixtures/src_template__sec_tester/expected/docker/wait-for-it.sh deleted file mode 100755 index 06e0638c..00000000 --- a/fixtures/src_template__sec_tester/expected/docker/wait-for-it.sh +++ /dev/null @@ -1,189 +0,0 @@ -#!/usr/bin/bash -# -# Pulled from https://github.com/vishnubob/wait-for-it on 2022-02-28. -# Licensed under the MIT license as of 81b1373f. -# -# Below this line, wait-for-it is the original work of the author. -# -# Use this script to test if a given TCP host/port are available - -WAITFORIT_cmdname=${0##*/} - -echoerr() { if [[ $WAITFORIT_QUIET -ne 1 ]]; then echo "$@" 1>&2; fi } - -usage() -{ - cat << USAGE >&2 -Usage: - $WAITFORIT_cmdname host:port [-s] [-t timeout] [-- command args] - -h HOST | --host=HOST Host or IP under test - -p PORT | --port=PORT TCP port under test - Alternatively, you specify the host and port as host:port - -s | --strict Only execute subcommand if the test succeeds - -q | --quiet Don't output any status messages - -t TIMEOUT | --timeout=TIMEOUT - Timeout in seconds, zero for no timeout - -- COMMAND ARGS Execute command with args after the test finishes -USAGE - exit 1 -} - -wait_for() -{ - if [[ $WAITFORIT_TIMEOUT -gt 0 ]]; then - echoerr "$WAITFORIT_cmdname: waiting $WAITFORIT_TIMEOUT seconds for $WAITFORIT_HOST:$WAITFORIT_PORT" - else - echoerr "$WAITFORIT_cmdname: waiting for $WAITFORIT_HOST:$WAITFORIT_PORT without a timeout" - fi - WAITFORIT_start_ts=$(date +%s) - while : - do - if [[ $WAITFORIT_ISBUSY -eq 1 ]]; then - nc -z $WAITFORIT_HOST $WAITFORIT_PORT - WAITFORIT_result=$? - else - (echo -n > /dev/tcp/$WAITFORIT_HOST/$WAITFORIT_PORT) >/dev/null 2>&1 - WAITFORIT_result=$? - fi - if [[ $WAITFORIT_result -eq 0 ]]; then - WAITFORIT_end_ts=$(date +%s) - echoerr "$WAITFORIT_cmdname: $WAITFORIT_HOST:$WAITFORIT_PORT is available after $((WAITFORIT_end_ts - WAITFORIT_start_ts)) seconds" - break - fi - sleep 1 - done - return $WAITFORIT_result -} - -wait_for_wrapper() -{ - # In order to support SIGINT during timeout: http://unix.stackexchange.com/a/57692 - if [[ $WAITFORIT_QUIET -eq 1 ]]; then - timeout $WAITFORIT_BUSYTIMEFLAG $WAITFORIT_TIMEOUT $0 --quiet --child --host=$WAITFORIT_HOST --port=$WAITFORIT_PORT --timeout=$WAITFORIT_TIMEOUT & - else - timeout $WAITFORIT_BUSYTIMEFLAG $WAITFORIT_TIMEOUT $0 --child --host=$WAITFORIT_HOST --port=$WAITFORIT_PORT --timeout=$WAITFORIT_TIMEOUT & - fi - WAITFORIT_PID=$! - trap "kill -INT -$WAITFORIT_PID" INT - wait $WAITFORIT_PID - WAITFORIT_RESULT=$? - if [[ $WAITFORIT_RESULT -ne 0 ]]; then - echoerr "$WAITFORIT_cmdname: timeout occurred after waiting $WAITFORIT_TIMEOUT seconds for $WAITFORIT_HOST:$WAITFORIT_PORT" - fi - return $WAITFORIT_RESULT -} - -# process arguments -while [[ $# -gt 0 ]] -do - case "$1" in - *:* ) - WAITFORIT_hostport=(${1//:/ }) - WAITFORIT_HOST=${WAITFORIT_hostport[0]} - WAITFORIT_PORT=${WAITFORIT_hostport[1]} - shift 1 - ;; - --child) - WAITFORIT_CHILD=1 - shift 1 - ;; - -q | --quiet) - WAITFORIT_QUIET=1 - shift 1 - ;; - -s | --strict) - WAITFORIT_STRICT=1 - shift 1 - ;; - -h) - WAITFORIT_HOST="$2" - if [[ $WAITFORIT_HOST == "" ]]; then break; fi - shift 2 - ;; - --host=*) - WAITFORIT_HOST="${1#*=}" - shift 1 - ;; - -p) - WAITFORIT_PORT="$2" - if [[ $WAITFORIT_PORT == "" ]]; then break; fi - shift 2 - ;; - --port=*) - WAITFORIT_PORT="${1#*=}" - shift 1 - ;; - -t) - WAITFORIT_TIMEOUT="$2" - if [[ $WAITFORIT_TIMEOUT == "" ]]; then break; fi - shift 2 - ;; - --timeout=*) - WAITFORIT_TIMEOUT="${1#*=}" - shift 1 - ;; - --) - shift - WAITFORIT_CLI=("$@") - break - ;; - --help) - usage - ;; - *) - echoerr "Unknown argument: $1" - usage - ;; - esac -done - -if [[ "$WAITFORIT_HOST" == "" || "$WAITFORIT_PORT" == "" ]]; then - echoerr "Error: you need to provide a host and port to test." - usage -fi - -WAITFORIT_TIMEOUT=${WAITFORIT_TIMEOUT:-15} -WAITFORIT_STRICT=${WAITFORIT_STRICT:-0} -WAITFORIT_CHILD=${WAITFORIT_CHILD:-0} -WAITFORIT_QUIET=${WAITFORIT_QUIET:-0} - -# Check to see if timeout is from busybox? -WAITFORIT_TIMEOUT_PATH=$(type -p timeout) -WAITFORIT_TIMEOUT_PATH=$(realpath $WAITFORIT_TIMEOUT_PATH 2>/dev/null || readlink -f $WAITFORIT_TIMEOUT_PATH) - -WAITFORIT_BUSYTIMEFLAG="" -if [[ $WAITFORIT_TIMEOUT_PATH =~ "busybox" ]]; then - WAITFORIT_ISBUSY=1 - # Check if busybox timeout uses -t flag - # (recent Alpine versions don't support -t anymore) - if timeout &>/dev/stdout | grep -q -e '-t '; then - WAITFORIT_BUSYTIMEFLAG="-t" - fi -else - WAITFORIT_ISBUSY=0 -fi - -if [[ $WAITFORIT_CHILD -gt 0 ]]; then - wait_for - WAITFORIT_RESULT=$? - exit $WAITFORIT_RESULT -else - if [[ $WAITFORIT_TIMEOUT -gt 0 ]]; then - wait_for_wrapper - WAITFORIT_RESULT=$? - else - wait_for - WAITFORIT_RESULT=$? - fi -fi - -if [[ $WAITFORIT_CLI != "" ]]; then - if [[ $WAITFORIT_RESULT -ne 0 && $WAITFORIT_STRICT -eq 1 ]]; then - echoerr "$WAITFORIT_cmdname: strict mode, refusing to execute subprocess" - exit $WAITFORIT_RESULT - fi - exec "${WAITFORIT_CLI[@]}" -else - exit $WAITFORIT_RESULT -fi - diff --git a/fixtures/src_template__sec_tester/expected/script/helpers/function_helpers.cr b/fixtures/src_template__sec_tester/expected/script/helpers/function_helpers.cr deleted file mode 100644 index 8abcb6a2..00000000 --- a/fixtures/src_template__sec_tester/expected/script/helpers/function_helpers.cr +++ /dev/null @@ -1,32 +0,0 @@ -require "colorize" - -# These are helper methods provided to help keep your code -# clean. Add new methods, or alter these as needed. - -def notice(message : String) : Nil - puts "\n▸ #{message}" -end - -def print_done : Nil - puts "✔ Done" -end - -def print_error(message : String) : Nil - puts "There is a problem with your system setup:\n".colorize.red.bold - puts "#{message}\n".colorize.red.bold - Process.exit(1) -end - -def command_not_found(command : String) : Bool - Process.find_executable(command).nil? -end - -def command_not_running(command : String, *args) : Bool - output = IO::Memory.new - code = Process.run(command, args, output: output).exit_code - code > 0 -end - -def run_command(command : String, *args) : Nil - Process.run(command, args, output: STDOUT, error: STDERR, input: STDIN) -end diff --git a/fixtures/src_template__sec_tester/expected/script/setup.cr b/fixtures/src_template__sec_tester/expected/script/setup.cr deleted file mode 100644 index faa74914..00000000 --- a/fixtures/src_template__sec_tester/expected/script/setup.cr +++ /dev/null @@ -1,32 +0,0 @@ -require "./helpers/*" - -notice "Running System Check" - -require "./system_check" - -print_done - -notice "Installing node dependencies" -run_command "yarn", "install", "--no-progress" - -print_done - -notice "Installing shards" -run_command "shards", "install" - -if !File.exists?(".env") - notice "No .env found. Creating one." - File.touch ".env" - print_done -end - -notice "Setting up the database" - -run_command "lucky", "db.setup" - -notice "Seeding the database with required and sample records" -run_command "lucky", "db.seed.required_data" -run_command "lucky", "db.seed.sample_data" - -print_done -notice "Run 'lucky dev' to start the app" \ No newline at end of file diff --git a/fixtures/src_template__sec_tester/expected/script/system_check.cr b/fixtures/src_template__sec_tester/expected/script/system_check.cr deleted file mode 100644 index c56ce3e9..00000000 --- a/fixtures/src_template__sec_tester/expected/script/system_check.cr +++ /dev/null @@ -1,21 +0,0 @@ -require "./helpers/*" - -# Use this script to check the system for required tools and process that your app needs. -# A few helper functions are provided to keep the code simple. See the -# script/helpers/function_helpers.cr file for more examples. -# -# A few examples you might use here: -# * 'lucky db.verify_connection' to test postgres can be connected -# * Checking that elasticsearch, redis, or postgres is installed and/or booted -# * Note: Booting additional processes for things like mail, background jobs, etc... -# should go in your Procfile.dev. - -if command_not_found "yarn" - print_error "Yarn is not installed\n See https://yarnpkg.com/lang/en/docs/install/ for install instructions." -end - -# CUSTOM PRE-BOOT CHECKS -# example: -# if command_not_running "redis-cli", "ping" -# print_error "Redis is not running." -# end diff --git a/fixtures/src_template__sec_tester/expected/spec/setup/clean_database.cr b/fixtures/src_template__sec_tester/expected/spec/setup/clean_database.cr deleted file mode 100644 index a1bc631c..00000000 --- a/fixtures/src_template__sec_tester/expected/spec/setup/clean_database.cr +++ /dev/null @@ -1,3 +0,0 @@ -Spec.before_each do - AppDatabase.truncate -end diff --git a/fixtures/src_template__sec_tester/expected/spec/setup/reset_emails.cr b/fixtures/src_template__sec_tester/expected/spec/setup/reset_emails.cr deleted file mode 100644 index 140ab416..00000000 --- a/fixtures/src_template__sec_tester/expected/spec/setup/reset_emails.cr +++ /dev/null @@ -1,3 +0,0 @@ -Spec.before_each do - Carbon::DevAdapter.reset -end diff --git a/fixtures/src_template__sec_tester/expected/spec/setup/setup_database.cr b/fixtures/src_template__sec_tester/expected/spec/setup/setup_database.cr deleted file mode 100644 index 393c6da3..00000000 --- a/fixtures/src_template__sec_tester/expected/spec/setup/setup_database.cr +++ /dev/null @@ -1,2 +0,0 @@ -Db::Create.new(quiet: true).call -Db::Migrate.new(quiet: true).call diff --git a/fixtures/src_template__sec_tester/expected/spec/setup/start_app_server.cr b/fixtures/src_template__sec_tester/expected/spec/setup/start_app_server.cr deleted file mode 100644 index ff0bfeeb..00000000 --- a/fixtures/src_template__sec_tester/expected/spec/setup/start_app_server.cr +++ /dev/null @@ -1,10 +0,0 @@ -app_server = AppServer.new - -spawn do - app_server.listen -end - -Spec.after_suite do - LuckyFlow.shutdown - app_server.close -end diff --git a/fixtures/src_template__sec_tester/expected/spec/spec_helper.cr b/fixtures/src_template__sec_tester/expected/spec/spec_helper.cr deleted file mode 100644 index 87be38b6..00000000 --- a/fixtures/src_template__sec_tester/expected/spec/spec_helper.cr +++ /dev/null @@ -1,27 +0,0 @@ -ENV["LUCKY_ENV"] = "test" -ENV["DEV_PORT"] = "5001" -require "spec" -require "lucky_flow" -require "lucky_flow/ext/lucky" -require "lucky_flow/ext/avram" -require "../src/app" -require "./support/flows/base_flow" -require "./support/**" -require "../db/migrations/**" - -# Add/modify files in spec/setup to start/configure programs or run hooks -# -# By default there are scripts for setting up and cleaning the database, -# configuring LuckyFlow, starting the app server, etc. -require "./setup/**" - -include Carbon::Expectations -include Lucky::RequestExpectations -# NOTE: LuckyFlow specs are temporarily set to pending as of Lucky v1.4.0 -# This is due to race conditions in LuckyFlow. -# Ref: https://github.com/luckyframework/lucky_cli/issues/883 -include LuckyFlow::Expectations - -Avram::Migrator::Runner.new.ensure_migrated! -Avram::SchemaEnforcer.ensure_correct_column_mappings! -Habitat.raise_if_missing_settings! diff --git a/fixtures/src_template__sec_tester/expected/spec/support/.keep b/fixtures/src_template__sec_tester/expected/spec/support/.keep deleted file mode 100644 index e69de29b..00000000 diff --git a/fixtures/src_template__sec_tester/expected/spec/support/api_client.cr b/fixtures/src_template__sec_tester/expected/spec/support/api_client.cr deleted file mode 100644 index ef251251..00000000 --- a/fixtures/src_template__sec_tester/expected/spec/support/api_client.cr +++ /dev/null @@ -1,8 +0,0 @@ -class ApiClient < Lucky::BaseHTTPClient - app AppServer.new - - def initialize - super - headers("Content-Type": "application/json") - end -end diff --git a/fixtures/src_template__sec_tester/expected/spec/support/factories/.keep b/fixtures/src_template__sec_tester/expected/spec/support/factories/.keep deleted file mode 100644 index e69de29b..00000000 diff --git a/fixtures/src_template__sec_tester/expected/src/actions/api_action.cr b/fixtures/src_template__sec_tester/expected/src/actions/api_action.cr deleted file mode 100644 index fac02c8b..00000000 --- a/fixtures/src_template__sec_tester/expected/src/actions/api_action.cr +++ /dev/null @@ -1,11 +0,0 @@ -# Include modules and add methods that are for all API requests -abstract class ApiAction < Lucky::Action - # APIs typically do not need to send cookie/session data. - # Remove this line if you want to send cookies in the response header. - disable_cookies - accepted_formats [:json] - - # By default all actions are required to use underscores to separate words. - # Add 'include Lucky::SkipRouteStyleCheck' to your actions if you wish to ignore this check for specific routes. - include Lucky::EnforceUnderscoredRoute -end diff --git a/fixtures/src_template__sec_tester/expected/src/actions/errors/show.cr b/fixtures/src_template__sec_tester/expected/src/actions/errors/show.cr deleted file mode 100644 index d01ed541..00000000 --- a/fixtures/src_template__sec_tester/expected/src/actions/errors/show.cr +++ /dev/null @@ -1,63 +0,0 @@ -# This class handles error responses and reporting. -# -# https://luckyframework.org/guides/http-and-routing/error-handling -class Errors::Show < Lucky::ErrorAction - DEFAULT_MESSAGE = "Something went wrong." - default_format :html - dont_report [Lucky::RouteNotFoundError, Avram::RecordNotFoundError] - - def render(error : Lucky::RouteNotFoundError | Avram::RecordNotFoundError) - if html? - error_html "Sorry, we couldn't find that page.", status: 404 - else - error_json "Not found", status: 404 - end - end - - # When the request is JSON and an InvalidOperationError is raised, show a - # helpful error with the param that is invalid, and what was wrong with it. - def render(error : Avram::InvalidOperationError) - if html? - error_html DEFAULT_MESSAGE, status: 500 - else - error_json \ - message: error.renderable_message, - details: error.renderable_details, - param: error.invalid_attribute_name, - status: 400 - end - end - - # Always keep this below other 'render' methods or it may override your - # custom 'render' methods. - def render(error : Lucky::RenderableError) - if html? - error_html DEFAULT_MESSAGE, status: error.renderable_status - else - error_json error.renderable_message, status: error.renderable_status - end - end - - # If none of the 'render' methods return a response for the raised Exception, - # Lucky will use this method. - def default_render(error : Exception) : Lucky::Response - if html? - error_html DEFAULT_MESSAGE, status: 500 - else - error_json DEFAULT_MESSAGE, status: 500 - end - end - - private def error_html(message : String, status : Int) - context.response.status_code = status - html_with_status Errors::ShowPage, status, message: message, status_code: status - end - - private def error_json(message : String, status : Int, details = nil, param = nil) - json ErrorSerializer.new(message: message, details: details, param: param), status: status - end - - private def report(error : Exception) : Nil - # Send to Rollbar, send an email, etc. - end -end diff --git a/fixtures/src_template__sec_tester/expected/src/actions/home/index.cr b/fixtures/src_template__sec_tester/expected/src/actions/home/index.cr deleted file mode 100644 index 2d39a100..00000000 --- a/fixtures/src_template__sec_tester/expected/src/actions/home/index.cr +++ /dev/null @@ -1,5 +0,0 @@ -class Home::Index < BrowserAction - get "/" do - html Lucky::WelcomePage - end -end diff --git a/fixtures/src_template__sec_tester/expected/src/actions/mixins/.keep b/fixtures/src_template__sec_tester/expected/src/actions/mixins/.keep deleted file mode 100644 index e69de29b..00000000 diff --git a/fixtures/src_template__sec_tester/expected/src/app.cr b/fixtures/src_template__sec_tester/expected/src/app.cr deleted file mode 100644 index d343c8cd..00000000 --- a/fixtures/src_template__sec_tester/expected/src/app.cr +++ /dev/null @@ -1,37 +0,0 @@ -require "./shards" - -# Load the asset manifest -# In development, vite-plugin-dev-manifest creates public/manifest.dev.json -# In production, Vite creates public/.vite/manifest.json -# The manifest path is determined by which file exists at compile time -{% if File.exists?("public/manifest.dev.json") %} - Lucky::AssetHelpers.load_manifest "public/manifest.dev.json", use_vite: true -{% elsif File.exists?("public/.vite/manifest.json") %} - Lucky::AssetHelpers.load_manifest "public/.vite/manifest.json", use_vite: true -{% else %} - # For initial compilation, we'll assume development mode - # The dev server will create the manifest before the app is recompiled - Lucky::AssetHelpers.load_manifest "public/manifest.dev.json", use_vite: true -{% end %} - -require "../config/server" -require "./app_database" -require "../config/**" -require "./models/base_model" -require "./models/mixins/**" -require "./models/**" -require "./queries/mixins/**" -require "./queries/**" -require "./operations/mixins/**" -require "./operations/**" -require "./serializers/base_serializer" -require "./serializers/**" -require "./emails/base_email" -require "./emails/**" -require "./actions/mixins/**" -require "./actions/**" -require "./components/base_component" -require "./components/**" -require "./pages/**" -require "../db/migrations/**" -require "./app_server" \ No newline at end of file diff --git a/fixtures/src_template__sec_tester/expected/src/app_database.cr b/fixtures/src_template__sec_tester/expected/src/app_database.cr deleted file mode 100644 index 0efd4f50..00000000 --- a/fixtures/src_template__sec_tester/expected/src/app_database.cr +++ /dev/null @@ -1,2 +0,0 @@ -class AppDatabase < Avram::Database -end diff --git a/fixtures/src_template__sec_tester/expected/src/app_server.cr b/fixtures/src_template__sec_tester/expected/src/app_server.cr deleted file mode 100644 index 8ec16c3c..00000000 --- a/fixtures/src_template__sec_tester/expected/src/app_server.cr +++ /dev/null @@ -1,26 +0,0 @@ -class AppServer < Lucky::BaseAppServer - # Learn about middleware with HTTP::Handlers: - # https://luckyframework.org/guides/http-and-routing/http-handlers - def middleware : Array(HTTP::Handler) - [ - Lucky::RequestIdHandler.new, - Lucky::ForceSSLHandler.new, - Lucky::HttpMethodOverrideHandler.new, - Lucky::LogHandler.new, - Lucky::ErrorHandler.new(action: Errors::Show), - Lucky::RemoteIpHandler.new, - Lucky::RouteHandler.new, - Lucky::StaticCompressionHandler.new("./public", file_ext: "gz", content_encoding: "gzip"), - Lucky::StaticFileHandler.new("./public", fallthrough: false, directory_listing: false), - Lucky::RouteNotFoundHandler.new, - ] of HTTP::Handler - end - - def protocol - "http" - end - - def listen - server.listen(host, port, reuse_port: false) - end -end diff --git a/fixtures/src_template__sec_tester/expected/src/emails/base_email.cr b/fixtures/src_template__sec_tester/expected/src/emails/base_email.cr deleted file mode 100644 index 656f4f11..00000000 --- a/fixtures/src_template__sec_tester/expected/src/emails/base_email.cr +++ /dev/null @@ -1,15 +0,0 @@ -# Learn about sending emails -# https://luckyframework.org/guides/emails/sending-emails-with-carbon -abstract class BaseEmail < Carbon::Email - # You can add defaults using the 'inherited' hook - # - # Example: - # - # macro inherited - # from default_from - # end - # - # def default_from - # Carbon::Address.new("support@app.com") - # end -end diff --git a/fixtures/src_template__sec_tester/expected/src/models/base_model.cr b/fixtures/src_template__sec_tester/expected/src/models/base_model.cr deleted file mode 100644 index 6bafeb84..00000000 --- a/fixtures/src_template__sec_tester/expected/src/models/base_model.cr +++ /dev/null @@ -1,5 +0,0 @@ -abstract class BaseModel < Avram::Model - def self.database : Avram::Database.class - AppDatabase - end -end diff --git a/fixtures/src_template__sec_tester/expected/src/models/mixins/.keep b/fixtures/src_template__sec_tester/expected/src/models/mixins/.keep deleted file mode 100644 index e69de29b..00000000 diff --git a/fixtures/src_template__sec_tester/expected/src/operations/.keep b/fixtures/src_template__sec_tester/expected/src/operations/.keep deleted file mode 100644 index e69de29b..00000000 diff --git a/fixtures/src_template__sec_tester/expected/src/operations/mixins/.keep b/fixtures/src_template__sec_tester/expected/src/operations/mixins/.keep deleted file mode 100644 index e69de29b..00000000 diff --git a/fixtures/src_template__sec_tester/expected/src/queries/.keep b/fixtures/src_template__sec_tester/expected/src/queries/.keep deleted file mode 100644 index e69de29b..00000000 diff --git a/fixtures/src_template__sec_tester/expected/src/queries/mixins/.keep b/fixtures/src_template__sec_tester/expected/src/queries/mixins/.keep deleted file mode 100644 index e69de29b..00000000 diff --git a/fixtures/src_template__sec_tester/expected/src/serializers/.keep b/fixtures/src_template__sec_tester/expected/src/serializers/.keep deleted file mode 100644 index e69de29b..00000000 diff --git a/fixtures/src_template__sec_tester/expected/src/serializers/base_serializer.cr b/fixtures/src_template__sec_tester/expected/src/serializers/base_serializer.cr deleted file mode 100644 index e769f5c0..00000000 --- a/fixtures/src_template__sec_tester/expected/src/serializers/base_serializer.cr +++ /dev/null @@ -1,18 +0,0 @@ -abstract class BaseSerializer - include Lucky::Serializable - - def self.for_collection(collection : Enumerable, *args, **named_args) : Array(self) - collection.map do |object| - new(object, *args, **named_args) - end - end - - def self.for_collection(collection : Enumerable, pages : Lucky::Paginator, *args, **named_args) - { - "items" => collection.map do |object| - new(object, *args, **named_args) - end, - "pagination" => PaginationSerializer.new(pages), - } - end -end diff --git a/fixtures/src_template__sec_tester/expected/src/serializers/error_serializer.cr b/fixtures/src_template__sec_tester/expected/src/serializers/error_serializer.cr deleted file mode 100644 index b7b55283..00000000 --- a/fixtures/src_template__sec_tester/expected/src/serializers/error_serializer.cr +++ /dev/null @@ -1,14 +0,0 @@ -# This is the default error serializer generated by Lucky. -# Feel free to customize it in any way you like. -class ErrorSerializer < BaseSerializer - def initialize( - @message : String, - @details : String? = nil, - @param : String? = nil, # so you can track which param (if any) caused the problem - ) - end - - def render - {message: @message, param: @param, details: @details} - end -end diff --git a/fixtures/src_template__sec_tester/expected/src/serializers/pagination_serializer.cr b/fixtures/src_template__sec_tester/expected/src/serializers/pagination_serializer.cr deleted file mode 100644 index 9e44788c..00000000 --- a/fixtures/src_template__sec_tester/expected/src/serializers/pagination_serializer.cr +++ /dev/null @@ -1,15 +0,0 @@ -# This is the default pagination serializer generated by Lucky. -# Feel free to customize it in any way you like. -class PaginationSerializer < BaseSerializer - def initialize(@pages : Lucky::Paginator) - end - - def render - { - next_page: @pages.path_to_next, - previous_page: @pages.path_to_previous, - total_items: @pages.item_count, - total_pages: @pages.total, - } - end -end diff --git a/fixtures/src_template__sec_tester/expected/src/shards.cr b/fixtures/src_template__sec_tester/expected/src/shards.cr deleted file mode 100644 index 1afc72cb..00000000 --- a/fixtures/src_template__sec_tester/expected/src/shards.cr +++ /dev/null @@ -1,8 +0,0 @@ -# Load .env file before any other config or app code -require "lucky_env" -LuckyEnv.load?(".env") - -# Require your shards here -require "lucky" -require "avram/lucky" -require "carbon" diff --git a/fixtures/src_template__sec_tester/expected/src/start_server.cr b/fixtures/src_template__sec_tester/expected/src/start_server.cr deleted file mode 100644 index de8af78e..00000000 --- a/fixtures/src_template__sec_tester/expected/src/start_server.cr +++ /dev/null @@ -1,17 +0,0 @@ -require "./app" - -Habitat.raise_if_missing_settings! - -if LuckyEnv.development? - Avram::Migrator::Runner.new.ensure_migrated! - Avram::SchemaEnforcer.ensure_correct_column_mappings! -end - -app_server = AppServer.new -puts "Listening on http://#{app_server.host}:#{app_server.port}" - -Signal::INT.trap do - app_server.close -end - -app_server.listen diff --git a/fixtures/src_template__sec_tester/expected/src/test_project.cr b/fixtures/src_template__sec_tester/expected/src/test_project.cr deleted file mode 100644 index 68e1a8d2..00000000 --- a/fixtures/src_template__sec_tester/expected/src/test_project.cr +++ /dev/null @@ -1,6 +0,0 @@ -# Typically you will not use or modify this file. 'shards build' and some -# other crystal tools will sometimes use this. -# -# When this file is compiled/run it will require and run 'start_server', -# which as its name implies will start the server for you app. -require "./start_server" diff --git a/fixtures/src_template__sec_tester/expected/tasks.cr b/fixtures/src_template__sec_tester/expected/tasks.cr deleted file mode 100644 index 5a892d4d..00000000 --- a/fixtures/src_template__sec_tester/expected/tasks.cr +++ /dev/null @@ -1,25 +0,0 @@ -# This file loads your app and all your tasks when running 'lucky' -# -# Run 'lucky --help' to see all available tasks. -# -# Learn to create your own tasks: -# https://luckyframework.org/guides/command-line-tasks/custom-tasks - -# See `LuckyEnv#task?` -ENV["LUCKY_TASK"] = "true" - -# Load Lucky and the app (actions, models, etc.) -require "./src/app" -require "lucky_task" - -# You can add your own tasks here in the ./tasks folder -require "./tasks/**" - -# Load migrations -require "./db/migrations/**" - -# Load Lucky tasks (dev, routes, etc.) -require "lucky/tasks/**" -require "avram/lucky/tasks" - -LuckyTask::Runner.run diff --git a/fixtures/src_template__sec_tester/expected/tasks/.keep b/fixtures/src_template__sec_tester/expected/tasks/.keep deleted file mode 100644 index e69de29b..00000000 diff --git a/fixtures/src_template__sec_tester/expected/tasks/db/seed/required_data.cr b/fixtures/src_template__sec_tester/expected/tasks/db/seed/required_data.cr deleted file mode 100644 index d866040f..00000000 --- a/fixtures/src_template__sec_tester/expected/tasks/db/seed/required_data.cr +++ /dev/null @@ -1,30 +0,0 @@ -require "../../../spec/support/factories/**" - -# Add seeds here that are *required* for your app to work. -# For example, you might need at least one admin user or you might need at least -# one category for your blog posts for the app to work. -# -# Use `Db::Seed::SampleData` if your only want to add sample data helpful for -# development. -class Db::Seed::RequiredData < LuckyTask::Task - summary "Add database records required for the app to work" - - def call - # Using a Avram::Factory: - # - # Use the defaults, but override just the email - # UserFactory.create &.email("me@example.com") - - # Using a SaveOperation: - # - # SaveUser.create!(email: "me@example.com", name: "Jane") - # - # You likely want to be able to run this file more than once. To do that, - # only create the record if it doesn't exist yet: - # - # unless UserQuery.new.email("me@example.com").first? - # SaveUser.create!(email: "me@example.com", name: "Jane") - # end - puts "Done adding required data" - end -end diff --git a/fixtures/src_template__sec_tester/expected/tasks/db/seed/sample_data.cr b/fixtures/src_template__sec_tester/expected/tasks/db/seed/sample_data.cr deleted file mode 100644 index 231d7e8d..00000000 --- a/fixtures/src_template__sec_tester/expected/tasks/db/seed/sample_data.cr +++ /dev/null @@ -1,30 +0,0 @@ -require "../../../spec/support/factories/**" - -# Add sample data helpful for development, e.g. (fake users, blog posts, etc.) -# -# Use `Db::Seed::RequiredData` if you need to create data *required* for your -# app to work. -class Db::Seed::SampleData < LuckyTask::Task - summary "Add sample database records helpful for development" - - def call - # Using an Avram::Factory: - # - # Use the defaults, but override just the email - # UserFactory.create &.email("me@example.com") - - # Using a SaveOperation: - # ``` - # SignUpUser.create!(email: "me@example.com", password: "test123", password_confirmation: "test123") - # ``` - # - # You likely want to be able to run this file more than once. To do that, - # only create the record if it doesn't exist yet: - # ``` - # if UserQuery.new.email("me@example.com").none? - # SignUpUser.create!(email: "me@example.com", password: "test123", password_confirmation: "test123") - # end - # ``` - puts "Done adding sample data" - end -end diff --git a/fixtures/tasks.cr b/fixtures/tasks.cr deleted file mode 100644 index d488be48..00000000 --- a/fixtures/tasks.cr +++ /dev/null @@ -1,22 +0,0 @@ -require "../src/lucky_cli" - -class PlaceholderTask < LuckyTask::Task - summary "placeholder" - help_message "Custom help message" - switch :test_mode, "Run in test mode." - - def call - output.puts "Calling Placeholder. Test: #{test_mode?}" - end -end - -class TaskWithInput < LuckyTask::Task - summary "this should be first" - - def call - input = gets - puts "input: #{input}" - end -end - -LuckyTask::Runner.run diff --git a/shard.yml b/shard.yml index e6efd2b6..c6e855d8 100644 --- a/shard.yml +++ b/shard.yml @@ -7,8 +7,6 @@ authors: targets: lucky: main: src/lucky.cr - lucky.hello_world: - main: fixtures/hello_world.cr crystal: ~> 1.16 diff --git a/spec/end_to_end/api_no_auth_spec.cr b/spec/end_to_end/api_no_auth_spec.cr new file mode 100644 index 00000000..c327716c --- /dev/null +++ b/spec/end_to_end/api_no_auth_spec.cr @@ -0,0 +1,26 @@ +require "../spec_helper" + +include WithProjectCleanup +include ShouldRunSuccessfully + +describe "Lucky CLI", tags: "end_to_end" do + describe "building an API app without authentication" do + it "generates the app and runs the included specs" do + with_project_cleanup do + should_run_successfully "crystal run src/lucky.cr -- init.custom test-project --api --no-auth" + + FileUtils.cd "test-project" do + {% if !flag?(:windows) %} + # Due to formatter on Windows checking different line endings, this will report changes to all crystal files + # We only need to test this on 1 OS to ensure things are good + should_run_successfully "crystal tool format --check spec src config" + {% end %} + should_run_successfully "crystal script/setup.cr" + should_run_successfully "crystal build src/test_project.cr" + should_run_successfully "crystal spec" + should_run_successfully "lucky tasks" + end + end + end + end +end diff --git a/spec/end_to_end/api_with_auth_spec.cr b/spec/end_to_end/api_with_auth_spec.cr new file mode 100644 index 00000000..e0cb4010 --- /dev/null +++ b/spec/end_to_end/api_with_auth_spec.cr @@ -0,0 +1,26 @@ +require "../spec_helper" + +include WithProjectCleanup +include ShouldRunSuccessfully + +describe "Lucky CLI", tags: "end_to_end" do + describe "building an API app with authentication included" do + it "generates the app and runs the included specs" do + with_project_cleanup do + should_run_successfully "crystal run src/lucky.cr -- init.custom test-project --api" + + FileUtils.cd "test-project" do + {% if !flag?(:windows) %} + # Due to formatter on Windows checking different line endings, this will report changes to all crystal files + # We only need to test this on 1 OS to ensure things are good + should_run_successfully "crystal tool format --check spec src config" + {% end %} + should_run_successfully "crystal script/setup.cr" + should_run_successfully "crystal build src/test_project.cr" + should_run_successfully "crystal spec" + should_run_successfully "lucky tasks" + end + end + end + end +end diff --git a/spec/end_to_end/browser_no_auth_spec.cr b/spec/end_to_end/browser_no_auth_spec.cr new file mode 100644 index 00000000..174fd8d7 --- /dev/null +++ b/spec/end_to_end/browser_no_auth_spec.cr @@ -0,0 +1,35 @@ +require "../spec_helper" + +include WithProjectCleanup +include ShouldRunSuccessfully + +describe "Lucky CLI", tags: "end_to_end" do + describe "building a full browser app without authentication" do + it "generates the app and runs the included specs" do + with_project_cleanup do + should_run_successfully "crystal run src/lucky.cr -- init.custom test-project --no-auth" + + FileUtils.cd "test-project" do + should_run_successfully "crystal script/setup.cr" + should_run_successfully "crystal build src/test_project.cr" + should_run_successfully "lucky gen.action.api Api::Users::Show" + should_run_successfully "lucky gen.action.browser Users::Show" + should_run_successfully "lucky gen.migration CreateThings" + should_run_successfully "lucky gen.model User" + should_run_successfully "lucky gen.page Users::IndexPage" + should_run_successfully "lucky gen.component Users::Header" + should_run_successfully "lucky gen.resource.browser Comment title:String" + should_run_successfully "lucky gen.task email.monthly_update" + should_run_successfully "lucky gen.secret_key" + should_run_successfully "crystal spec" + + {% if !flag?(:windows) %} + # Due to formatter on Windows checking different line endings, this will report changes to all crystal files + # We only need to test this on 1 OS to ensure things are good + should_run_successfully "crystal tool format --check spec src config" + {% end %} + end + end + end + end +end diff --git a/spec/end_to_end/browser_with_auth_spec.cr b/spec/end_to_end/browser_with_auth_spec.cr new file mode 100644 index 00000000..c3e653d9 --- /dev/null +++ b/spec/end_to_end/browser_with_auth_spec.cr @@ -0,0 +1,26 @@ +require "../spec_helper" + +include WithProjectCleanup +include ShouldRunSuccessfully + +describe "Lucky CLI", tags: "end_to_end" do + describe "building a full browser app with authentication included" do + it "generates the app and runs the included specs" do + with_project_cleanup do + should_run_successfully "crystal run src/lucky.cr -- init.custom test-project" + + FileUtils.cd "test-project" do + {% if !flag?(:windows) %} + # Due to formatter on Windows checking different line endings, this will report changes to all crystal files + # We only need to test this on 1 OS to ensure things are good + should_run_successfully "crystal tool format --check spec src config" + {% end %} + should_run_successfully "crystal script/setup.cr" + should_run_successfully "crystal build src/test_project.cr" + should_run_successfully "crystal spec" + should_run_successfully "lucky tasks" + end + end + end + end +end diff --git a/spec/end_to_end/browser_with_security_spec.cr b/spec/end_to_end/browser_with_security_spec.cr new file mode 100644 index 00000000..63c9acb6 --- /dev/null +++ b/spec/end_to_end/browser_with_security_spec.cr @@ -0,0 +1,26 @@ +require "../spec_helper" + +include WithProjectCleanup +include ShouldRunSuccessfully + +describe "Lucky CLI", tags: "end_to_end" do + describe "building a full browser app with authentication and sec tester included" do + it "generates the app and runs the included specs" do + with_project_cleanup do + should_run_successfully "crystal run src/lucky.cr -- init.custom test-project --with-sec-test" + + FileUtils.cd "test-project" do + {% if !flag?(:windows) %} + # Due to formatter on Windows checking different line endings, this will report changes to all crystal files + # We only need to test this on 1 OS to ensure things are good + should_run_successfully "crystal tool format --check spec src config" + {% end %} + should_run_successfully "crystal script/setup.cr" + should_run_successfully "crystal build src/test_project.cr" + should_run_successfully "crystal spec" + should_run_successfully "lucky tasks" + end + end + end + end +end diff --git a/spec/integration/lucky_cli_spec.cr b/spec/integration/lucky_cli_spec.cr index f262ae74..375927db 100644 --- a/spec/integration/lucky_cli_spec.cr +++ b/spec/integration/lucky_cli_spec.cr @@ -2,47 +2,47 @@ require "../spec_helper" describe "Lucky CLI", tags: "integration" do describe "running a task", tags: "task" do - it "runs precompiled tasks" do - io = IO::Memory.new - status = run_lucky( - args: %w[hello_world], - shell: true, - output: io, - env: { - "LUCKY_TASKS_FILE" => "#{__DIR__}/../../fixtures/hello_world.cr", - } - ) - status.exit_code.should eq(0) - io.to_s.should eq("Hello World!\n") - end + # it "runs precompiled tasks" do + # io = IO::Memory.new + # status = run_lucky( + # args: %w[hello_world], + # shell: true, + # output: io, + # env: { + # "LUCKY_TASKS_FILE" => "#{__DIR__}/../../fixtures/hello_world.cr", + # } + # ) + # status.exit_code.should eq(0) + # io.to_s.should eq("Hello World!\n") + # end - it "runs non-compiled tasks" do - io = IO::Memory.new - status = run_lucky( - args: %w[hello_crystal], - shell: true, - output: io, - env: { - "LUCKY_TASKS_FILE" => "#{__DIR__}/../../fixtures/hello_crystal.cr", - } - ) - status.exit_code.should eq(0) - io.to_s.should eq("Hello, Crystal!\n") - end + # it "runs non-compiled tasks" do + # io = IO::Memory.new + # status = run_lucky( + # args: %w[hello_crystal], + # shell: true, + # output: io, + # env: { + # "LUCKY_TASKS_FILE" => "#{__DIR__}/../../fixtures/hello_crystal.cr", + # } + # ) + # status.exit_code.should eq(0) + # io.to_s.should eq("Hello, Crystal!\n") + # end - it "allows tasks to accept input from STDIN" do - io = IO::Memory.new - run_lucky( - args: %w[task_with_input], - shell: true, - input: IO::Memory.new("hello world"), - output: io, - env: { - "LUCKY_TASKS_FILE" => fixtures_tasks_path.to_s, - } - ) - io.to_s.should eq("input: hello world\n") - end + # it "allows tasks to accept input from STDIN" do + # io = IO::Memory.new + # run_lucky( + # args: %w[task_with_input], + # shell: true, + # input: IO::Memory.new("hello world"), + # output: io, + # env: { + # "LUCKY_TASKS_FILE" => fixtures_tasks_path.to_s, + # } + # ) + # io.to_s.should eq("input: hello world\n") + # end end describe "getting help", tags: "lucky" do @@ -54,49 +54,49 @@ describe "Lucky CLI", tags: "integration" do end describe "returns the proper help message for built-in CLI commands" do - it "for 'tasks'" do - io = IO::Memory.new - status = run_lucky( - args: %w[tasks -h], - shell: true, - output: io, - env: { - "LUCKY_TASKS_FILE" => fixtures_tasks_path.to_s, - } - ) - status.exit_code.should eq(0) - io.to_s.should contain("Usage: lucky tasks") - end + # it "for 'tasks'" do + # io = IO::Memory.new + # status = run_lucky( + # args: %w[tasks -h], + # shell: true, + # output: io, + # env: { + # "LUCKY_TASKS_FILE" => fixtures_tasks_path.to_s, + # } + # ) + # status.exit_code.should eq(0) + # io.to_s.should contain("Usage: lucky tasks") + # end - it "for 'dev'" do - io = IO::Memory.new - status = run_lucky( - args: %w[dev -h], - shell: true, - output: io, - env: { - "LUCKY_TASKS_FILE" => fixtures_tasks_path.to_s, - } - ) - status.exit_code.should eq(0) - io.to_s.should contain("Usage: lucky dev") - end + # it "for 'dev'" do + # io = IO::Memory.new + # status = run_lucky( + # args: %w[dev -h], + # shell: true, + # output: io, + # env: { + # "LUCKY_TASKS_FILE" => fixtures_tasks_path.to_s, + # } + # ) + # status.exit_code.should eq(0) + # io.to_s.should contain("Usage: lucky dev") + # end end - # NOTE: This must be `error` because of how the messages are printed out from the custom tasks - it "returns custom help messages from custom tasks" do - io = IO::Memory.new - status = run_lucky( - args: %w[placeholder_task -h], - shell: true, - error: io, - env: { - "LUCKY_TASKS_FILE" => fixtures_tasks_path.to_s, - } - ) - status.exit_code.should eq(0) - io.to_s.should contain("Custom help message") - end + # # NOTE: This must be `error` because of how the messages are printed out from the custom tasks + # it "returns custom help messages from custom tasks" do + # io = IO::Memory.new + # status = run_lucky( + # args: %w[placeholder_task -h], + # shell: true, + # error: io, + # env: { + # "LUCKY_TASKS_FILE" => fixtures_tasks_path.to_s, + # } + # ) + # status.exit_code.should eq(0) + # io.to_s.should contain("Custom help message") + # end end describe "custom init", tags: "init" do diff --git a/spec/spec_helper.cr b/spec/spec_helper.cr index d098d79b..00d7d05a 100644 --- a/spec/spec_helper.cr +++ b/spec/spec_helper.cr @@ -8,46 +8,6 @@ require "../src/lucky_cli" include LuckyTemplate::Spec -SPEC_UPDATE_SNAPSHOT = ENV["SPEC_UPDATE_SNAPSHOT"]? == "1" - -# Generates a snapshot of a generator with *fixture_name* folder -# -# NOTE: Can update a snapshot via `earthly +update-snapshot --spec=:` -def generate_snapshot(fixture_name, file = __FILE__, line = __LINE__, &) - generator = yield - - actual_path = Path[Dir.current] - expected_path = Path["#{__DIR__}/../fixtures"] / fixture_name / "expected" - - if SPEC_UPDATE_SNAPSHOT - FileUtils.rm_rf(expected_path) - FileUtils.mkdir_p(expected_path) - generator.render(expected_path) - end - - FileUtils.mkdir_p(actual_path) - generator.render(actual_path) - - generator.template_folder.should be_valid_at(actual_path), file: file, line: line - - snapshot = LuckyTemplate.snapshot(generator.template_folder) - snapshot.select { |_, type| type.file? }.each do |filename, _| - actual_filename = actual_path / filename - expected_filename = expected_path / filename - - unless File.same_content?(actual_filename, expected_filename) - actual_lines = File.read_lines(actual_filename) - expected_lines = File.read_lines(expected_filename) - - actual_lines.each_with_index do |actual_line, index| - actual_line.should eq(expected_lines[index]), file: file, line: line - end - end - end - - generator -end - # Executes a new `lucky` process # # NOTE: will mark the spec as pending if lucky command is not found @@ -57,7 +17,3 @@ def run_lucky(**kwargs) end Process.run("lucky", **kwargs) end - -def fixtures_tasks_path - Path["#{__DIR__}/../fixtures/tasks.cr"] -end diff --git a/spec/support/should_run_successfully.cr b/spec/support/should_run_successfully.cr new file mode 100644 index 00000000..2d46a894 --- /dev/null +++ b/spec/support/should_run_successfully.cr @@ -0,0 +1,17 @@ +module ShouldRunSuccessfully + private def should_run_successfully(command, output : IO = STDOUT) : Nil + result = Process.run( + command, + shell: true, + env: ENV.to_h, + output: output, + error: STDERR + ) + + result.exit_code.should be_successful + end + + private def be_successful + eq 0 + end +end diff --git a/spec/support/with_project_cleanup.cr b/spec/support/with_project_cleanup.cr new file mode 100644 index 00000000..209fdd34 --- /dev/null +++ b/spec/support/with_project_cleanup.cr @@ -0,0 +1,18 @@ +module WithProjectCleanup + private def with_project_cleanup(project_directory = "test-project", skip_db_drop = false, &) : Nil + yield + + FileUtils.cd(project_directory) { + output = IO::Memory.new + status = run_lucky( + args: %w[db.drop], + shell: true, + output: output, + ) + status.exit_code.should eq(0) + output.to_s.should contain("Done dropping") + } unless skip_db_drop + ensure + FileUtils.rm_rf project_directory + end +end diff --git a/spec/unit/api_authentication_template_spec.cr b/spec/unit/api_authentication_template_spec.cr deleted file mode 100644 index 67e0f220..00000000 --- a/spec/unit/api_authentication_template_spec.cr +++ /dev/null @@ -1,18 +0,0 @@ -require "../spec_helper" - -describe ApiAuthenticationTemplate do - around_each do |example| - with_tempfile("tmp") do |tmp| - Dir.mkdir_p(tmp) - Dir.cd(tmp) do - example.run - end - end - end - - it "generates api authentication template" do - generate_snapshot("api_authentication_template") do - ApiAuthenticationTemplate.new - end - end -end diff --git a/spec/unit/app_with_sec_tester_template_spec.cr b/spec/unit/app_with_sec_tester_template_spec.cr deleted file mode 100644 index 835c9bb3..00000000 --- a/spec/unit/app_with_sec_tester_template_spec.cr +++ /dev/null @@ -1,48 +0,0 @@ -require "../spec_helper" - -describe AppWithSecTesterTemplate do - around_each do |example| - with_tempfile("tmp") do |tmp| - Dir.mkdir_p(tmp) - Dir.cd(tmp) do - example.run - end - end - end - - it "generates app with sec tester template" do - generate_snapshot("app_sec_tester_template") do - AppWithSecTesterTemplate.new( - generate_auth: true, - browser: true - ) - end - end - - it "generates app with sec tester template with only generate auth option" do - generate_snapshot("app_sec_tester_template__generate_auth") do - AppWithSecTesterTemplate.new( - generate_auth: true, - browser: false - ) - end - end - - it "generates app with sec tester template with only browser option" do - generate_snapshot("app_sec_tester_template__browser") do - AppWithSecTesterTemplate.new( - generate_auth: false, - browser: true - ) - end - end - - it "generates app with sec tester template without generate auth or browser" do - generate_snapshot("app_sec_tester_template__no_browser_auth") do - AppWithSecTesterTemplate.new( - generate_auth: false, - browser: false - ) - end - end -end diff --git a/spec/unit/base_authentication_src_template_spec.cr b/spec/unit/base_authentication_src_template_spec.cr deleted file mode 100644 index e82b84bb..00000000 --- a/spec/unit/base_authentication_src_template_spec.cr +++ /dev/null @@ -1,18 +0,0 @@ -require "../spec_helper" - -describe BaseAuthenticationSrcTemplate do - around_each do |example| - with_tempfile("tmp") do |tmp| - Dir.mkdir_p(tmp) - Dir.cd(tmp) do - example.run - end - end - end - - it "generates base authentication src template" do - generate_snapshot("base_authentication_src_template") do - BaseAuthenticationSrcTemplate.new - end - end -end diff --git a/spec/unit/browser_authentication_src_template_spec.cr b/spec/unit/browser_authentication_src_template_spec.cr deleted file mode 100644 index 2fa3fa62..00000000 --- a/spec/unit/browser_authentication_src_template_spec.cr +++ /dev/null @@ -1,18 +0,0 @@ -require "../spec_helper" - -describe BrowserAuthenticationSrcTemplate do - around_each do |example| - with_tempfile("tmp") do |tmp| - Dir.mkdir_p(tmp) - Dir.cd(tmp) do - example.run - end - end - end - - it "generates browser authentication src template" do - generate_snapshot("browser_authentication_src_template") do - BrowserAuthenticationSrcTemplate.new - end - end -end diff --git a/spec/unit/browser_src_template_spec.cr b/spec/unit/browser_src_template_spec.cr deleted file mode 100644 index 0ba2281a..00000000 --- a/spec/unit/browser_src_template_spec.cr +++ /dev/null @@ -1,24 +0,0 @@ -require "../spec_helper" - -describe BrowserSrcTemplate do - around_each do |example| - with_tempfile("tmp") do |tmp| - Dir.mkdir_p(tmp) - Dir.cd(tmp) do - example.run - end - end - end - - it "generates browser src template" do - generate_snapshot("browser_src_template") do - BrowserSrcTemplate.new(generate_auth: true) - end - end - - it "generates browser src template without generate auth" do - generate_snapshot("browser_src_template__generate_auth") do - BrowserSrcTemplate.new(generate_auth: false) - end - end -end diff --git a/spec/unit/shard_file_generator_spec.cr b/spec/unit/shard_file_generator_spec.cr deleted file mode 100644 index 1e2644fc..00000000 --- a/spec/unit/shard_file_generator_spec.cr +++ /dev/null @@ -1,64 +0,0 @@ -require "../spec_helper" - -describe ShardFileGenerator do - around_each do |example| - with_tempfile("tmp") do |tmp| - Dir.mkdir_p(tmp) - Dir.cd(tmp) do - example.run - end - end - end - - it "generates shard file template" do - generate_snapshot("shard_file_template") do - ShardFileGenerator.new( - "test-shard", - generate_auth: true, - browser: true, - with_sec_tester: true - ).tap do |instance| - instance.crystal_version = "1.16.1" - end - end - end - - it "generates shard file template with only browser option" do - generate_snapshot("shard_file_template__browser") do - ShardFileGenerator.new( - "test-shard", - generate_auth: false, - browser: true, - with_sec_tester: false - ).tap do |instance| - instance.crystal_version = "1.16.1" - end - end - end - - it "generates shard file template with only generate auth option" do - generate_snapshot("shard_file_template__generate_auth") do - ShardFileGenerator.new( - "test-shard", - generate_auth: true, - browser: false, - with_sec_tester: false - ).tap do |instance| - instance.crystal_version = "1.16.1" - end - end - end - - it "generates shard file template with only sec tester option" do - generate_snapshot("shard_file_template__with_sec_tester") do - ShardFileGenerator.new( - "test-shard", - generate_auth: false, - browser: false, - with_sec_tester: true - ).tap do |instance| - instance.crystal_version = "1.16.1" - end - end - end -end diff --git a/spec/unit/src_template_spec.cr b/spec/unit/src_template_spec.cr deleted file mode 100644 index 0ba63efb..00000000 --- a/spec/unit/src_template_spec.cr +++ /dev/null @@ -1,72 +0,0 @@ -require "../spec_helper" - -describe SrcTemplate do - around_each do |example| - with_tempfile("tmp") do |tmp| - Dir.mkdir_p(tmp) - Dir.cd(tmp) do - example.run - end - end - end - - it "generates src template" do - generate_snapshot("src_template") do - SrcTemplate.new( - "test-project", - generate_auth: true, - api_only: true, - with_sec_tester: true - ).tap do |instance| - instance.secret_key_base = "1234567890" - instance.crystal_version = "1.16.1" - instance.lucky_cli_version = "1.3.0" - end - end - end - - it "generates src template with only generate auth option" do - generate_snapshot("src_template__generate_auth") do - SrcTemplate.new( - "test-project", - generate_auth: true, - api_only: false, - with_sec_tester: false - ).tap do |instance| - instance.secret_key_base = "1234567890" - instance.crystal_version = "1.16.1" - instance.lucky_cli_version = "1.3.0" - end - end - end - - it "generates src template with only api option" do - generate_snapshot("src_template__api_only") do - SrcTemplate.new( - "test-project", - generate_auth: false, - api_only: true, - with_sec_tester: false - ).tap do |instance| - instance.secret_key_base = "1234567890" - instance.crystal_version = "1.16.1" - instance.lucky_cli_version = "1.3.0" - end - end - end - - it "generates src template with only sec tester option" do - generate_snapshot("src_template__sec_tester") do - SrcTemplate.new( - "test-project", - generate_auth: false, - api_only: false, - with_sec_tester: true - ).tap do |instance| - instance.secret_key_base = "1234567890" - instance.crystal_version = "1.16.1" - instance.lucky_cli_version = "1.3.0" - end - end - end -end diff --git a/src/lucky_cli/src_template.cr b/src/lucky_cli/src_template.cr index acf4a1af..7c1f1951 100644 --- a/src/lucky_cli/src_template.cr +++ b/src/lucky_cli/src_template.cr @@ -37,6 +37,9 @@ class SrcTemplate root_dir.add_file(".env") do |io| ECR.embed("#{__DIR__}/../web_app_skeleton/.env.ecr", io) end + root_dir.add_file(".gitattributes") do |io| + ECR.embed("#{__DIR__}/../web_app_skeleton/.gitattributes.ecr", io) + end root_dir.add_file("docker-compose.yml") do |io| ECR.embed("#{__DIR__}/../web_app_skeleton/docker-compose.yml.ecr", io) end diff --git a/src/web_app_skeleton/.gitattributes.ecr b/src/web_app_skeleton/.gitattributes.ecr new file mode 100644 index 00000000..fdd3f45e --- /dev/null +++ b/src/web_app_skeleton/.gitattributes.ecr @@ -0,0 +1 @@ +*.cr text eol=lf \ No newline at end of file diff --git a/src/web_app_skeleton/.github/workflows/ci.yml.ecr b/src/web_app_skeleton/.github/workflows/ci.yml.ecr index 6c555142..2b931f0e 100644 --- a/src/web_app_skeleton/.github/workflows/ci.yml.ecr +++ b/src/web_app_skeleton/.github/workflows/ci.yml.ecr @@ -18,7 +18,7 @@ jobs: runs-on: ubuntu-latest continue-on-error: ${{ matrix.experimental }} steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - name: Install Crystal uses: crystal-lang/install-crystal@v1 with: @@ -41,7 +41,7 @@ jobs: continue-on-error: ${{ matrix.experimental }} services: postgres: - image: postgres:14-alpine + image: postgres:18-alpine env: POSTGRES_PASSWORD: postgres ports: @@ -54,7 +54,7 @@ jobs: --health-retries 5 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - name: Install Crystal uses: crystal-lang/install-crystal@v1 with: @@ -66,7 +66,7 @@ jobs: run: echo "::set-output name=dir::$(yarn cache dir)" - name: Set up Yarn cache - uses: actions/cache@v4 + uses: actions/cache@v5 with: path: ${{ steps.yarn-cache-dir-path.outputs.dir }} key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }} @@ -74,7 +74,7 @@ jobs: ${{ runner.os }}-yarn- - name: Set up Node cache - uses: actions/cache@v4 + uses: actions/cache@v5 id: node-cache # use this to check for `cache-hit` (`steps.node-cache.outputs.cache-hit != 'true'`) with: path: '**/node_modules' @@ -83,7 +83,7 @@ jobs: ${{ runner.os }}-node- <%- end -%> - name: Set up Crystal cache - uses: actions/cache@v4 + uses: actions/cache@v5 id: crystal-cache with: path: |