mirror of
https://github.com/fluxerapp/fluxer
synced 2026-10-07 19:22:14 +09:00
chore(marketing): remove the private marketing submodule (#2732)
This commit is contained in:
@@ -14,7 +14,7 @@
|
|||||||
"DOCKER_HOST": "unix:///var/run/docker.sock"
|
"DOCKER_HOST": "unix:///var/run/docker.sock"
|
||||||
},
|
},
|
||||||
"runServices": ["workspace", "postgres", "valkey", "nats", "livekit", "meilisearch", "mailpit"],
|
"runServices": ["workspace", "postgres", "valkey", "nats", "livekit", "meilisearch", "mailpit"],
|
||||||
"forwardPorts": [3000, 8088, 8080, 8771, 8082, 8773, 3010, 3020, 8333],
|
"forwardPorts": [3000, 8088, 8080, 8771, 8082, 8773, 3020, 8333],
|
||||||
"portsAttributes": {
|
"portsAttributes": {
|
||||||
"8088": {
|
"8088": {
|
||||||
"label": "Fluxer dev proxy",
|
"label": "Fluxer dev proxy",
|
||||||
|
|||||||
@@ -256,7 +256,6 @@ services:
|
|||||||
- "127.0.0.1:${FLUXER_DEV_GATEWAY_PORT:-8771}:8771"
|
- "127.0.0.1:${FLUXER_DEV_GATEWAY_PORT:-8771}:8771"
|
||||||
- "127.0.0.1:${FLUXER_DEV_MEDIA_PROXY_PORT:-8082}:8082"
|
- "127.0.0.1:${FLUXER_DEV_MEDIA_PROXY_PORT:-8082}:8082"
|
||||||
- "127.0.0.1:${FLUXER_DEV_APP_PROXY_PORT:-8773}:8773"
|
- "127.0.0.1:${FLUXER_DEV_APP_PROXY_PORT:-8773}:8773"
|
||||||
- "127.0.0.1:${FLUXER_DEV_MARKETING_PORT:-3010}:3010"
|
|
||||||
- "127.0.0.1:${FLUXER_DEV_ADMIN_PORT:-3020}:3020"
|
- "127.0.0.1:${FLUXER_DEV_ADMIN_PORT:-3020}:3020"
|
||||||
- "127.0.0.1:${FLUXER_DEV_SEAWEEDFS_S3_PORT:-3900}:8333"
|
- "127.0.0.1:${FLUXER_DEV_SEAWEEDFS_S3_PORT:-3900}:8333"
|
||||||
depends_on:
|
depends_on:
|
||||||
|
|||||||
@@ -9,7 +9,6 @@
|
|||||||
**/.git/**
|
**/.git/**
|
||||||
/.github/
|
/.github/
|
||||||
/.pnpm-store/
|
/.pnpm-store/
|
||||||
/fluxer_marketing
|
|
||||||
|
|
||||||
**/.env
|
**/.env
|
||||||
**/.env.*.local
|
**/.env.*.local
|
||||||
|
|||||||
@@ -1,7 +1,2 @@
|
|||||||
/.github/CODEOWNERS @fluxerapp/developers
|
/.github/CODEOWNERS @fluxerapp/developers
|
||||||
/.github/workflows/ @fluxerapp/developers
|
/.github/workflows/ @fluxerapp/developers
|
||||||
/fluxer_marketing @fluxerapp/developers
|
|
||||||
/.gitmodules @fluxerapp/developers
|
|
||||||
/.github/workflows/dispatch-private-marketing-build.yaml @fluxerapp/developers
|
|
||||||
/packages/i18n/marketing/ @fluxerapp/developers
|
|
||||||
/scripts/setup-private-marketing.sh @fluxerapp/developers
|
|
||||||
|
|||||||
@@ -89,21 +89,3 @@ Submit translations through [Weblate](https://weblate.fluxer.tools), not through
|
|||||||
All repository activity is governed by the [Code of Conduct](https://github.com/fluxerapp/fluxer/blob/main/.github/CODE_OF_CONDUCT.md).
|
All repository activity is governed by the [Code of Conduct](https://github.com/fluxerapp/fluxer/blob/main/.github/CODE_OF_CONDUCT.md).
|
||||||
|
|
||||||
Fluxer is distributed under the [GNU Affero General Public License, version 3.0 or later](https://github.com/fluxerapp/fluxer/blob/main/LICENSE). By adding a DCO sign-off, you certify that you have the right to submit the contribution under that licence.
|
Fluxer is distributed under the [GNU Affero General Public License, version 3.0 or later](https://github.com/fluxerapp/fluxer/blob/main/LICENSE). By adding a DCO sign-off, you certify that you have the right to submit the contribution under that licence.
|
||||||
|
|
||||||
## Private marketing project
|
|
||||||
|
|
||||||
The marketing implementation is maintained in a private repository at the `fluxer_marketing` submodule path. The public workspace, bootstrap, checks, and development stack work without initializing it.
|
|
||||||
|
|
||||||
Authorized maintainers can initialize only that submodule and install its independent dependencies:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
./scripts/setup-private-marketing.sh
|
|
||||||
pnpm --dir fluxer_marketing install --frozen-lockfile
|
|
||||||
cargo metadata --locked --manifest-path fluxer_marketing/Cargo.toml
|
|
||||||
```
|
|
||||||
|
|
||||||
To run the private marketing service in the local development stack and direct application links to it, add this override to the ignored `config/env/local.env` file:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
FLUXER_MARKETING_ENDPOINT=http://localhost:8088/marketing
|
|
||||||
```
|
|
||||||
|
|||||||
@@ -22,11 +22,6 @@ f:docs:
|
|||||||
f:gateway:
|
f:gateway:
|
||||||
- changed-files:
|
- changed-files:
|
||||||
- any-glob-to-any-file: fluxer_gateway/**/*
|
- any-glob-to-any-file: fluxer_gateway/**/*
|
||||||
f:marketing:
|
|
||||||
- changed-files:
|
|
||||||
- any-glob-to-any-file:
|
|
||||||
- fluxer_marketing
|
|
||||||
- packages/i18n/marketing/**/*
|
|
||||||
f:media_proxy:
|
f:media_proxy:
|
||||||
- changed-files:
|
- changed-files:
|
||||||
- any-glob-to-any-file: fluxer_media_proxy/**/*
|
- any-glob-to-any-file: fluxer_media_proxy/**/*
|
||||||
|
|||||||
@@ -1,230 +0,0 @@
|
|||||||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
|
||||||
name: Dispatch private marketing build
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- main
|
|
||||||
paths:
|
|
||||||
- fluxer_marketing
|
|
||||||
- Cargo.toml
|
|
||||||
- fluxer_common/**
|
|
||||||
- packages/fonts/manifest.json
|
|
||||||
- packages/fonts/NOTICE.md
|
|
||||||
- packages/fonts/LICENSE-IBM-PLEX.txt
|
|
||||||
- packages/fonts/css/locale-fallbacks.css
|
|
||||||
- packages/fonts/files/FluxerSans/**
|
|
||||||
- packages/fonts/files/FluxerMono/**
|
|
||||||
- packages/fonts/marketing/**
|
|
||||||
- packages/i18n/marketing/**
|
|
||||||
- fluxer_static/marketing/branding/**
|
|
||||||
- .github/workflows/dispatch-private-marketing-build.yaml
|
|
||||||
|
|
||||||
permissions:
|
|
||||||
actions: read
|
|
||||||
contents: read
|
|
||||||
|
|
||||||
concurrency:
|
|
||||||
group: private-marketing-dispatch
|
|
||||||
cancel-in-progress: false
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
metadata:
|
|
||||||
name: resolve exact private build metadata
|
|
||||||
if: github.repository == 'fluxerapp/fluxer'
|
|
||||||
runs-on: ubuntu-24.04
|
|
||||||
timeout-minutes: 5
|
|
||||||
outputs:
|
|
||||||
parent_sha: ${{ steps.inputs.outputs.parent_sha }}
|
|
||||||
gitlink_sha: ${{ steps.inputs.outputs.gitlink_sha }}
|
|
||||||
build_version: ${{ steps.inputs.outputs.build_version }}
|
|
||||||
correlation_id: ${{ steps.inputs.outputs.correlation_id }}
|
|
||||||
steps:
|
|
||||||
- name: Create token
|
|
||||||
id: create-token
|
|
||||||
uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1
|
|
||||||
with:
|
|
||||||
client-id: ${{ vars.FLUXER_CI_APP_ID }}
|
|
||||||
private-key: ${{ secrets.FLUXER_CI_APP_KEY }}
|
|
||||||
owner: fluxerapp
|
|
||||||
repositories: fluxer
|
|
||||||
permission-contents: read
|
|
||||||
- name: Resolve trusted build inputs
|
|
||||||
id: inputs
|
|
||||||
env:
|
|
||||||
EVENT_AFTER: ${{ github.event.after }}
|
|
||||||
GH_TOKEN: ${{ steps.create-token.outputs.token }}
|
|
||||||
PARENT_SHA: ${{ github.sha }}
|
|
||||||
PUBLIC_REPOSITORY: ${{ github.repository }}
|
|
||||||
RUN_ID: ${{ github.run_id }}
|
|
||||||
RUN_ATTEMPT: ${{ github.run_attempt }}
|
|
||||||
run: |
|
|
||||||
set -euo pipefail
|
|
||||||
[[ "$GITHUB_EVENT_NAME" == "push" ]]
|
|
||||||
[[ "$GITHUB_REF" == "refs/heads/main" ]]
|
|
||||||
[[ "$PUBLIC_REPOSITORY" == "fluxerapp/fluxer" ]]
|
|
||||||
[[ "$PARENT_SHA" =~ ^[0-9a-f]{40}$ ]]
|
|
||||||
[[ "$EVENT_AFTER" == "$PARENT_SHA" ]]
|
|
||||||
[[ "$RUN_ID" =~ ^[1-9][0-9]*$ ]]
|
|
||||||
[[ "$RUN_ATTEMPT" =~ ^[1-9][0-9]*$ ]]
|
|
||||||
(( 10#$RUN_ATTEMPT <= 10 ))
|
|
||||||
|
|
||||||
main_sha="$(gh api "repos/$PUBLIC_REPOSITORY/git/ref/heads/main" --jq .object.sha)"
|
|
||||||
[[ "$main_sha" =~ ^[0-9a-f]{40}$ ]]
|
|
||||||
main_comparison="$(gh api "repos/$PUBLIC_REPOSITORY/compare/$PARENT_SHA...$main_sha")"
|
|
||||||
main_status="$(jq -r .status <<<"$main_comparison")"
|
|
||||||
[[ "$main_status" == "identical" || "$main_status" == "ahead" ]]
|
|
||||||
[[ "$(jq -r .merge_base_commit.sha <<<"$main_comparison")" == "$PARENT_SHA" ]]
|
|
||||||
|
|
||||||
commit="$(gh api "repos/$PUBLIC_REPOSITORY/git/commits/$PARENT_SHA")"
|
|
||||||
[[ "$(jq -r .sha <<<"$commit")" == "$PARENT_SHA" ]]
|
|
||||||
tree_sha="$(jq -r .tree.sha <<<"$commit")"
|
|
||||||
[[ "$tree_sha" =~ ^[0-9a-f]{40}$ ]]
|
|
||||||
entry="$(
|
|
||||||
gh api "repos/$PUBLIC_REPOSITORY/git/trees/$tree_sha" |
|
|
||||||
jq -cer '[.tree[] | select(.path == "fluxer_marketing")] | if length == 1 then .[0] else error("expected exactly one marketing gitlink") end'
|
|
||||||
)"
|
|
||||||
mode="$(jq -r .mode <<<"$entry")"
|
|
||||||
type="$(jq -r .type <<<"$entry")"
|
|
||||||
gitlink_sha="$(jq -r .sha <<<"$entry")"
|
|
||||||
path="$(jq -r .path <<<"$entry")"
|
|
||||||
if [[ "$mode" != "160000" || "$type" != "commit" || "$path" != "fluxer_marketing" || ! "$gitlink_sha" =~ ^[0-9a-f]{40}$ ]]; then
|
|
||||||
echo "::error::Public parent does not contain a valid fluxer_marketing gitlink."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
run="$(gh api "repos/$PUBLIC_REPOSITORY/actions/runs/$RUN_ID")"
|
|
||||||
[[ "$(jq -r .id <<<"$run")" == "$RUN_ID" ]]
|
|
||||||
[[ "$(jq -r .run_attempt <<<"$run")" == "$RUN_ATTEMPT" ]]
|
|
||||||
[[ "$(jq -r .event <<<"$run")" == "push" ]]
|
|
||||||
[[ "$(jq -r .head_sha <<<"$run")" == "$PARENT_SHA" ]]
|
|
||||||
run_created_at="$(jq -r .created_at <<<"$run")"
|
|
||||||
[[ "$run_created_at" =~ ^[1-9][0-9]{3}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}Z$ ]]
|
|
||||||
run_created_epoch="$(date -u -d "$run_created_at" +%s)"
|
|
||||||
[[ "$run_created_epoch" =~ ^[1-9][0-9]*$ ]]
|
|
||||||
build_epoch=$((run_created_epoch + 10#$RUN_ATTEMPT - 1))
|
|
||||||
read -r year month day time_segment <<<"$(date -u -d "@$build_epoch" '+%Y %m %d %H%M%S')"
|
|
||||||
month="$((10#$month))"
|
|
||||||
micro="$((10#$time_segment))"
|
|
||||||
build_version="$year.$month$day.$micro"
|
|
||||||
[[ "$build_version" =~ ^[1-9][0-9]{3}\.[1-9][0-9]{2,3}\.([0-9]|[1-9][0-9]{0,5})$ ]]
|
|
||||||
correlation_id="public-${RUN_ID}-${RUN_ATTEMPT}"
|
|
||||||
[[ "$correlation_id" =~ ^[A-Za-z0-9._:-]{1,64}$ ]]
|
|
||||||
{
|
|
||||||
echo "parent_sha=$PARENT_SHA"
|
|
||||||
echo "gitlink_sha=$gitlink_sha"
|
|
||||||
echo "build_version=$build_version"
|
|
||||||
echo "correlation_id=$correlation_id"
|
|
||||||
} >>"$GITHUB_OUTPUT"
|
|
||||||
|
|
||||||
dispatch:
|
|
||||||
name: dispatch exact private build
|
|
||||||
needs: metadata
|
|
||||||
runs-on: ubuntu-24.04
|
|
||||||
timeout-minutes: 65
|
|
||||||
environment: private-marketing-dispatch
|
|
||||||
permissions: {}
|
|
||||||
steps:
|
|
||||||
- name: Validate trusted build inputs
|
|
||||||
env:
|
|
||||||
DISPATCH_ENABLED: ${{ vars.MARKETING_DISPATCH_ENABLED }}
|
|
||||||
EXPECTED_PARENT_SHA: ${{ github.sha }}
|
|
||||||
EXPECTED_CORRELATION_ID: public-${{ github.run_id }}-${{ github.run_attempt }}
|
|
||||||
PARENT_SHA: ${{ needs.metadata.outputs.parent_sha }}
|
|
||||||
GITLINK_SHA: ${{ needs.metadata.outputs.gitlink_sha }}
|
|
||||||
BUILD_VERSION: ${{ needs.metadata.outputs.build_version }}
|
|
||||||
CORRELATION_ID: ${{ needs.metadata.outputs.correlation_id }}
|
|
||||||
run: |
|
|
||||||
set -euo pipefail
|
|
||||||
[[ "$GITHUB_EVENT_NAME" == "push" ]]
|
|
||||||
[[ "$GITHUB_REF" == "refs/heads/main" ]]
|
|
||||||
[[ "$GITHUB_REPOSITORY" == "fluxerapp/fluxer" ]]
|
|
||||||
[[ "$PARENT_SHA" == "$EXPECTED_PARENT_SHA" ]]
|
|
||||||
[[ "$PARENT_SHA" =~ ^[0-9a-f]{40}$ ]]
|
|
||||||
[[ "$GITLINK_SHA" =~ ^[0-9a-f]{40}$ ]]
|
|
||||||
[[ "$BUILD_VERSION" =~ ^[1-9][0-9]{3}\.[1-9][0-9]{2,3}\.([0-9]|[1-9][0-9]{0,5})$ ]]
|
|
||||||
[[ "$CORRELATION_ID" == "$EXPECTED_CORRELATION_ID" ]]
|
|
||||||
[[ "$CORRELATION_ID" =~ ^[A-Za-z0-9._:-]{1,64}$ ]]
|
|
||||||
if [[ "$DISPATCH_ENABLED" != "true" ]]; then
|
|
||||||
echo "::error::Private marketing dispatch is intentionally disabled until the package cutover guard completes."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
- name: Create private dispatch token
|
|
||||||
id: private-token
|
|
||||||
uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1
|
|
||||||
with:
|
|
||||||
client-id: ${{ vars.FLUXER_CI_APP_ID }}
|
|
||||||
private-key: ${{ secrets.FLUXER_CI_APP_KEY }}
|
|
||||||
owner: fluxerapp
|
|
||||||
repositories: marketing
|
|
||||||
permission-actions: write
|
|
||||||
|
|
||||||
- name: Dispatch exact private build
|
|
||||||
env:
|
|
||||||
GH_TOKEN: ${{ steps.private-token.outputs.token }}
|
|
||||||
PARENT_SHA: ${{ needs.metadata.outputs.parent_sha }}
|
|
||||||
GITLINK_SHA: ${{ needs.metadata.outputs.gitlink_sha }}
|
|
||||||
BUILD_VERSION: ${{ needs.metadata.outputs.build_version }}
|
|
||||||
CORRELATION_ID: ${{ needs.metadata.outputs.correlation_id }}
|
|
||||||
run: |
|
|
||||||
set -euo pipefail
|
|
||||||
gh api --method POST repos/fluxerapp/marketing/actions/workflows/build-marketing.yaml/dispatches \
|
|
||||||
--field ref=main \
|
|
||||||
--field "inputs[parent_sha]=$PARENT_SHA" \
|
|
||||||
--field "inputs[gitlink_sha]=$GITLINK_SHA" \
|
|
||||||
--field "inputs[build_version]=$BUILD_VERSION" \
|
|
||||||
--field "inputs[correlation_id]=$CORRELATION_ID"
|
|
||||||
|
|
||||||
- name: Wait for private build conclusion
|
|
||||||
env:
|
|
||||||
GH_TOKEN: ${{ steps.private-token.outputs.token }}
|
|
||||||
PARENT_SHA: ${{ needs.metadata.outputs.parent_sha }}
|
|
||||||
GITLINK_SHA: ${{ needs.metadata.outputs.gitlink_sha }}
|
|
||||||
BUILD_VERSION: ${{ needs.metadata.outputs.build_version }}
|
|
||||||
CORRELATION_ID: ${{ needs.metadata.outputs.correlation_id }}
|
|
||||||
run: |
|
|
||||||
set -euo pipefail
|
|
||||||
expected_title="marketing-build correlation=$CORRELATION_ID parent=$PARENT_SHA gitlink=$GITLINK_SHA version=$BUILD_VERSION"
|
|
||||||
deadline=$((SECONDS + 3600))
|
|
||||||
run_id=""
|
|
||||||
while (( SECONDS < deadline )); do
|
|
||||||
runs="$(gh api "repos/fluxerapp/marketing/actions/workflows/build-marketing.yaml/runs?event=workflow_dispatch&per_page=100" --jq '[.workflow_runs[] | {id, event, display_title, status, conclusion}]')"
|
|
||||||
matches="$(jq --arg title "$expected_title" '[.[] | select(.event == "workflow_dispatch" and .display_title == $title)]' <<<"$runs")"
|
|
||||||
count="$(jq 'length' <<<"$matches")"
|
|
||||||
if [[ "$count" == "1" ]]; then
|
|
||||||
run_id="$(jq -r '.[0].id' <<<"$matches")"
|
|
||||||
break
|
|
||||||
fi
|
|
||||||
if [[ "$count" != "0" ]]; then
|
|
||||||
echo "::error::Private build correlation matched multiple workflow runs."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
sleep 10
|
|
||||||
done
|
|
||||||
if [[ -z "$run_id" ]]; then
|
|
||||||
echo "::error::Timed out waiting for the private build dispatch to appear."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
while (( SECONDS < deadline )); do
|
|
||||||
runs="$(gh api "repos/fluxerapp/marketing/actions/workflows/build-marketing.yaml/runs?event=workflow_dispatch&per_page=100" --jq '[.workflow_runs[] | {id, event, display_title, status, conclusion}]')"
|
|
||||||
matches="$(jq --arg title "$expected_title" '[.[] | select(.event == "workflow_dispatch" and .display_title == $title)]' <<<"$runs")"
|
|
||||||
if [[ "$(jq 'length' <<<"$matches")" != "1" || "$(jq -r '.[0].id' <<<"$matches")" != "$run_id" ]]; then
|
|
||||||
echo "::error::Private build correlation is missing or ambiguous."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
run="$(jq '.[0]' <<<"$matches")"
|
|
||||||
status="$(jq -r '.status' <<<"$run")"
|
|
||||||
conclusion="$(jq -r '.conclusion // empty' <<<"$run")"
|
|
||||||
if [[ "$status" == "completed" ]]; then
|
|
||||||
if [[ "$conclusion" != "success" ]]; then
|
|
||||||
echo "::error::Private marketing build concluded with $conclusion."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
echo "Private marketing build completed successfully."
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
sleep 15
|
|
||||||
done
|
|
||||||
echo "::error::Timed out waiting for the private marketing build."
|
|
||||||
exit 1
|
|
||||||
@@ -77,14 +77,14 @@ jobs:
|
|||||||
GH_TOKEN: ${{ steps.create-token.outputs.token }}
|
GH_TOKEN: ${{ steps.create-token.outputs.token }}
|
||||||
run: |
|
run: |
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
if [[ -z "$(git status --porcelain -- fluxer_app/src/features/i18n/locales packages/i18n/marketing packages/errors/src/i18n fluxer_api/pkgs/email/src/email_i18n fluxer_api/src/api/content_i18n)" ]]; then
|
if [[ -z "$(git status --porcelain -- fluxer_app/src/features/i18n/locales packages/errors/src/i18n fluxer_api/pkgs/email/src/email_i18n fluxer_api/src/api/content_i18n)" ]]; then
|
||||||
echo "No generated catalog changes."
|
echo "No generated catalog changes."
|
||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
git config user.name "fluxer-ci[bot]"
|
git config user.name "fluxer-ci[bot]"
|
||||||
git config user.email "${{ vars.FLUXER_CI_APP_USER_ID }}+fluxer-ci[bot]@users.noreply.github.com"
|
git config user.email "${{ vars.FLUXER_CI_APP_USER_ID }}+fluxer-ci[bot]@users.noreply.github.com"
|
||||||
git add fluxer_app/src/features/i18n/locales packages/i18n/marketing packages/errors/src/i18n fluxer_api/pkgs/email/src/email_i18n fluxer_api/src/api/content_i18n
|
git add fluxer_app/src/features/i18n/locales packages/errors/src/i18n fluxer_api/pkgs/email/src/email_i18n fluxer_api/src/api/content_i18n
|
||||||
git commit -m "i18n: compile Weblate catalogs"
|
git commit -m "i18n: compile Weblate catalogs"
|
||||||
git remote set-url origin "https://x-access-token:${GH_TOKEN}@github.com/${GITHUB_REPOSITORY}.git"
|
git remote set-url origin "https://x-access-token:${GH_TOKEN}@github.com/${GITHUB_REPOSITORY}.git"
|
||||||
git push origin "HEAD:$WEBLATE_BRANCH"
|
git push origin "HEAD:$WEBLATE_BRANCH"
|
||||||
|
|||||||
@@ -1,4 +0,0 @@
|
|||||||
[submodule "fluxer_marketing"]
|
|
||||||
path = fluxer_marketing
|
|
||||||
url = https://github.com/fluxerapp/marketing.git
|
|
||||||
update = none
|
|
||||||
@@ -18,7 +18,6 @@ members = [
|
|||||||
"fluxer_recon",
|
"fluxer_recon",
|
||||||
]
|
]
|
||||||
exclude = [
|
exclude = [
|
||||||
"fluxer_marketing",
|
|
||||||
"packages/markdown_parser/rust/fuzz",
|
"packages/markdown_parser/rust/fuzz",
|
||||||
]
|
]
|
||||||
resolver = "2"
|
resolver = "2"
|
||||||
|
|||||||
Vendored
-4
@@ -95,10 +95,6 @@ FLUXER_ADMIN_BASE_PATH=/admin
|
|||||||
FLUXER_ADMIN_SECRET_KEY_BASE=dev-admin-secret-key-base
|
FLUXER_ADMIN_SECRET_KEY_BASE=dev-admin-secret-key-base
|
||||||
FLUXER_ADMIN_OAUTH_CLIENT_SECRET=dev-admin-oauth-secret
|
FLUXER_ADMIN_OAUTH_CLIENT_SECRET=dev-admin-oauth-secret
|
||||||
FLUXER_ADMIN_OAUTH_REDIRECT_URI=http://localhost:8088/admin/oauth2_callback
|
FLUXER_ADMIN_OAUTH_REDIRECT_URI=http://localhost:8088/admin/oauth2_callback
|
||||||
FLUXER_MARKETING_PORT=3010
|
|
||||||
FLUXER_MARKETING_HOST=0.0.0.0
|
|
||||||
FLUXER_MARKETING_BASE_PATH=/marketing
|
|
||||||
FLUXER_MARKETING_SECRET_KEY_BASE=dev-marketing-secret-key-base
|
|
||||||
|
|
||||||
FLUXER_SUDO_MODE_SECRET=dev-sudo-secret
|
FLUXER_SUDO_MODE_SECRET=dev-sudo-secret
|
||||||
FLUXER_CONNECTION_INITIATION_SECRET=dev-connection-initiation-secret
|
FLUXER_CONNECTION_INITIATION_SECRET=dev-connection-initiation-secret
|
||||||
|
|||||||
@@ -64,7 +64,6 @@ function setDefaultTestEnv(): void {
|
|||||||
FLUXER_MEDIA_PROXY_SECRET_KEY: 'test-media-secret',
|
FLUXER_MEDIA_PROXY_SECRET_KEY: 'test-media-secret',
|
||||||
FLUXER_ADMIN_SECRET_KEY_BASE: 'test-admin-secret',
|
FLUXER_ADMIN_SECRET_KEY_BASE: 'test-admin-secret',
|
||||||
FLUXER_ADMIN_OAUTH_CLIENT_SECRET: 'test-admin-oauth-secret',
|
FLUXER_ADMIN_OAUTH_CLIENT_SECRET: 'test-admin-oauth-secret',
|
||||||
FLUXER_MARKETING_SECRET_KEY_BASE: 'test-marketing-secret',
|
|
||||||
FLUXER_APP_PROXY_PORT: '8773',
|
FLUXER_APP_PROXY_PORT: '8773',
|
||||||
FLUXER_GATEWAY_MEDIA_PROXY_ENDPOINT: 'http://127.0.0.1:8088/media',
|
FLUXER_GATEWAY_MEDIA_PROXY_ENDPOINT: 'http://127.0.0.1:8088/media',
|
||||||
FLUXER_GATEWAY_RPC_AUTH_TOKEN: 'test-gateway-rpc-token',
|
FLUXER_GATEWAY_RPC_AUTH_TOKEN: 'test-gateway-rpc-token',
|
||||||
|
|||||||
Submodule fluxer_marketing deleted from 23cd1c9119
@@ -149,12 +149,6 @@ function defaultConfig(): MasterConfig {
|
|||||||
secret_key_base: '',
|
secret_key_base: '',
|
||||||
oauth_client_secret: '',
|
oauth_client_secret: '',
|
||||||
},
|
},
|
||||||
marketing: {
|
|
||||||
port: 3010,
|
|
||||||
host: '0.0.0.0',
|
|
||||||
base_path: '/marketing',
|
|
||||||
secret_key_base: '',
|
|
||||||
},
|
|
||||||
app_proxy: {
|
app_proxy: {
|
||||||
port: 8773,
|
port: 8773,
|
||||||
assets_dir: 'fluxer_app/dist',
|
assets_dir: 'fluxer_app/dist',
|
||||||
@@ -486,9 +480,6 @@ function normalizeConfig(config: MasterConfig): MasterConfig {
|
|||||||
validateUploadRelaySecret(config.services.media_proxy.upload_relay.secret_base64, config.services.media_proxy.mode);
|
validateUploadRelaySecret(config.services.media_proxy.upload_relay.secret_base64, config.services.media_proxy.mode);
|
||||||
requireString(config.services.admin.secret_key_base, 'FLUXER_ADMIN_SECRET_KEY_BASE');
|
requireString(config.services.admin.secret_key_base, 'FLUXER_ADMIN_SECRET_KEY_BASE');
|
||||||
requireString(config.services.admin.oauth_client_secret, 'FLUXER_ADMIN_OAUTH_CLIENT_SECRET');
|
requireString(config.services.admin.oauth_client_secret, 'FLUXER_ADMIN_OAUTH_CLIENT_SECRET');
|
||||||
if (!config.instance.self_hosted) {
|
|
||||||
requireString(config.services.marketing.secret_key_base, 'FLUXER_MARKETING_SECRET_KEY_BASE');
|
|
||||||
}
|
|
||||||
requireString(config.services.gateway.rpc_auth_token, 'FLUXER_GATEWAY_RPC_AUTH_TOKEN');
|
requireString(config.services.gateway.rpc_auth_token, 'FLUXER_GATEWAY_RPC_AUTH_TOKEN');
|
||||||
return config;
|
return config;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -155,12 +155,6 @@ export interface MasterConfig {
|
|||||||
secret_key_base: string;
|
secret_key_base: string;
|
||||||
oauth_client_secret: string;
|
oauth_client_secret: string;
|
||||||
};
|
};
|
||||||
marketing: {
|
|
||||||
port: number;
|
|
||||||
host: string;
|
|
||||||
base_path: string;
|
|
||||||
secret_key_base: string;
|
|
||||||
};
|
|
||||||
app_proxy: {
|
app_proxy: {
|
||||||
port: number;
|
port: number;
|
||||||
assets_dir: string;
|
assets_dir: string;
|
||||||
|
|||||||
@@ -22,7 +22,6 @@ const MINIMAL_ENV: Record<string, string> = {
|
|||||||
FLUXER_MEDIA_PROXY_UPLOAD_RELAY_SECRET_BASE64: 'AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8=',
|
FLUXER_MEDIA_PROXY_UPLOAD_RELAY_SECRET_BASE64: 'AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8=',
|
||||||
FLUXER_ADMIN_SECRET_KEY_BASE: 'test-admin-secret',
|
FLUXER_ADMIN_SECRET_KEY_BASE: 'test-admin-secret',
|
||||||
FLUXER_ADMIN_OAUTH_CLIENT_SECRET: 'test-admin-oauth-secret',
|
FLUXER_ADMIN_OAUTH_CLIENT_SECRET: 'test-admin-oauth-secret',
|
||||||
FLUXER_MARKETING_SECRET_KEY_BASE: 'test-marketing-secret',
|
|
||||||
FLUXER_APP_PROXY_PORT: '8773',
|
FLUXER_APP_PROXY_PORT: '8773',
|
||||||
FLUXER_GATEWAY_MEDIA_PROXY_ENDPOINT: 'http://127.0.0.1:8088/media',
|
FLUXER_GATEWAY_MEDIA_PROXY_ENDPOINT: 'http://127.0.0.1:8088/media',
|
||||||
FLUXER_GATEWAY_RPC_AUTH_TOKEN: 'test-gateway-token',
|
FLUXER_GATEWAY_RPC_AUTH_TOKEN: 'test-gateway-token',
|
||||||
@@ -406,23 +405,6 @@ describe('ConfigLoader', () => {
|
|||||||
expect(config.database.postgres.ssl).toBe(false);
|
expect(config.database.postgres.ssl).toBe(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('does not require a marketing secret for self-hosted instances', async () => {
|
|
||||||
stubMinimalEnv({FLUXER_SELF_HOSTED: 'true'});
|
|
||||||
vi.stubEnv('FLUXER_MARKETING_SECRET_KEY_BASE', undefined);
|
|
||||||
|
|
||||||
const config = await loadConfig();
|
|
||||||
|
|
||||||
expect(config.instance.self_hosted).toBe(true);
|
|
||||||
expect(config.services.marketing.secret_key_base).toBe('');
|
|
||||||
});
|
|
||||||
|
|
||||||
test('requires a marketing secret for hosted instances', async () => {
|
|
||||||
stubMinimalEnv();
|
|
||||||
vi.stubEnv('FLUXER_MARKETING_SECRET_KEY_BASE', undefined);
|
|
||||||
|
|
||||||
await expect(loadConfig()).rejects.toThrow('FLUXER_MARKETING_SECRET_KEY_BASE');
|
|
||||||
});
|
|
||||||
|
|
||||||
test('still requires TLS for non-self-hosted production Postgres', async () => {
|
test('still requires TLS for non-self-hosted production Postgres', async () => {
|
||||||
stubMinimalEnv({
|
stubMinimalEnv({
|
||||||
FLUXER_ENV: 'production',
|
FLUXER_ENV: 'production',
|
||||||
|
|||||||
@@ -166,10 +166,6 @@ const NAMED_FLUXER_ENV_OVERRIDES: Record<string, NamedEnvOverride> = {
|
|||||||
FLUXER_ADMIN_BASE_PATH: {path: ['services', 'admin', 'base_path']},
|
FLUXER_ADMIN_BASE_PATH: {path: ['services', 'admin', 'base_path']},
|
||||||
FLUXER_ADMIN_SECRET_KEY_BASE: {path: ['services', 'admin', 'secret_key_base']},
|
FLUXER_ADMIN_SECRET_KEY_BASE: {path: ['services', 'admin', 'secret_key_base']},
|
||||||
FLUXER_ADMIN_OAUTH_CLIENT_SECRET: {path: ['services', 'admin', 'oauth_client_secret']},
|
FLUXER_ADMIN_OAUTH_CLIENT_SECRET: {path: ['services', 'admin', 'oauth_client_secret']},
|
||||||
FLUXER_MARKETING_HOST: {path: ['services', 'marketing', 'host']},
|
|
||||||
FLUXER_MARKETING_PORT: {path: ['services', 'marketing', 'port'], parse: parseInteger},
|
|
||||||
FLUXER_MARKETING_BASE_PATH: {path: ['services', 'marketing', 'base_path']},
|
|
||||||
FLUXER_MARKETING_SECRET_KEY_BASE: {path: ['services', 'marketing', 'secret_key_base']},
|
|
||||||
FLUXER_APP_PROXY_PORT: {path: ['services', 'app_proxy', 'port'], parse: parseInteger},
|
FLUXER_APP_PROXY_PORT: {path: ['services', 'app_proxy', 'port'], parse: parseInteger},
|
||||||
FLUXER_STATIC_DIR: {path: ['services', 'app_proxy', 'assets_dir']},
|
FLUXER_STATIC_DIR: {path: ['services', 'app_proxy', 'assets_dir']},
|
||||||
FLUXER_GATEWAY_PORT: {path: ['services', 'gateway', 'port'], parse: parseInteger},
|
FLUXER_GATEWAY_PORT: {path: ['services', 'gateway', 'port'], parse: parseInteger},
|
||||||
|
|||||||
@@ -1,99 +0,0 @@
|
|||||||
Copyright 2022 The Radio Canada Big Project Authors
|
|
||||||
(https://github.com/googlefonts/radiocanadadisplay)
|
|
||||||
Copyright 2022 The Noto Project Authors
|
|
||||||
(https://github.com/notofonts/latin-greek-cyrillic)
|
|
||||||
Copyright 2022 The Noto Project Authors (https://github.com/notofonts/arabic)
|
|
||||||
Copyright 2024 The Noto Project Authors (https://github.com/notofonts/hebrew)
|
|
||||||
Copyright 2022 The Noto Project Authors (https://github.com/notofonts/thai)
|
|
||||||
|
|
||||||
This Font Software is licensed under the SIL Open Font License, Version 1.1.
|
|
||||||
This license is copied below, and is also available with a FAQ at:
|
|
||||||
https://openfontlicense.org
|
|
||||||
|
|
||||||
|
|
||||||
-----------------------------------------------------------
|
|
||||||
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
|
|
||||||
-----------------------------------------------------------
|
|
||||||
|
|
||||||
PREAMBLE
|
|
||||||
The goals of the Open Font License (OFL) are to stimulate worldwide
|
|
||||||
development of collaborative font projects, to support the font creation
|
|
||||||
efforts of academic and linguistic communities, and to provide a free and
|
|
||||||
open framework in which fonts may be shared and improved in partnership
|
|
||||||
with others.
|
|
||||||
|
|
||||||
The OFL allows the licensed fonts to be used, studied, modified and
|
|
||||||
redistributed freely as long as they are not sold by themselves. The
|
|
||||||
fonts, including any derivative works, can be bundled, embedded,
|
|
||||||
redistributed and/or sold with any software provided that any reserved
|
|
||||||
names are not used by derivative works. The fonts and derivatives,
|
|
||||||
however, cannot be released under any other type of license. The
|
|
||||||
requirement for fonts to remain under this license does not apply
|
|
||||||
to any document created using the fonts or their derivatives.
|
|
||||||
|
|
||||||
DEFINITIONS
|
|
||||||
"Font Software" refers to the set of files released by the Copyright
|
|
||||||
Holder(s) under this license and clearly marked as such. This may
|
|
||||||
include source files, build scripts and documentation.
|
|
||||||
|
|
||||||
"Reserved Font Name" refers to any names specified as such after the
|
|
||||||
copyright statement(s).
|
|
||||||
|
|
||||||
"Original Version" refers to the collection of Font Software components as
|
|
||||||
distributed by the Copyright Holder(s).
|
|
||||||
|
|
||||||
"Modified Version" refers to any derivative made by adding to, deleting,
|
|
||||||
or substituting -- in part or in whole -- any of the components of the
|
|
||||||
Original Version, by changing formats or by porting the Font Software to a
|
|
||||||
new environment.
|
|
||||||
|
|
||||||
"Author" refers to any designer, engineer, programmer, technical
|
|
||||||
writer or other person who contributed to the Font Software.
|
|
||||||
|
|
||||||
PERMISSION & CONDITIONS
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining
|
|
||||||
a copy of the Font Software, to use, study, copy, merge, embed, modify,
|
|
||||||
redistribute, and sell modified and unmodified copies of the Font
|
|
||||||
Software, subject to the following conditions:
|
|
||||||
|
|
||||||
1) Neither the Font Software nor any of its individual components,
|
|
||||||
in Original or Modified Versions, may be sold by itself.
|
|
||||||
|
|
||||||
2) Original or Modified Versions of the Font Software may be bundled,
|
|
||||||
redistributed and/or sold with any software, provided that each copy
|
|
||||||
contains the above copyright notice and this license. These can be
|
|
||||||
included either as stand-alone text files, human-readable headers or
|
|
||||||
in the appropriate machine-readable metadata fields within text or
|
|
||||||
binary files as long as those fields can be easily viewed by the user.
|
|
||||||
|
|
||||||
3) No Modified Version of the Font Software may use the Reserved Font
|
|
||||||
Name(s) unless explicit written permission is granted by the corresponding
|
|
||||||
Copyright Holder. This restriction only applies to the primary font name as
|
|
||||||
presented to the users.
|
|
||||||
|
|
||||||
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
|
|
||||||
Software shall not be used to promote, endorse or advertise any
|
|
||||||
Modified Version, except to acknowledge the contribution(s) of the
|
|
||||||
Copyright Holder(s) and the Author(s) or with their explicit written
|
|
||||||
permission.
|
|
||||||
|
|
||||||
5) The Font Software, modified or unmodified, in part or in whole,
|
|
||||||
must be distributed entirely under this license, and must not be
|
|
||||||
distributed under any other license. The requirement for fonts to
|
|
||||||
remain under this license does not apply to any document created
|
|
||||||
using the fonts.
|
|
||||||
|
|
||||||
TERMINATION
|
|
||||||
This license becomes null and void if any of the above conditions are
|
|
||||||
not met.
|
|
||||||
|
|
||||||
DISCLAIMER
|
|
||||||
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
||||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
|
|
||||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
|
||||||
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
|
|
||||||
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
|
||||||
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
|
|
||||||
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
||||||
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
|
|
||||||
OTHER DEALINGS IN THE FONT SOFTWARE.
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
# Marketing font licences
|
|
||||||
|
|
||||||
The Radio Canada Big and Noto Sans webfont files in this directory are
|
|
||||||
the unmodified variable-font subsets used by the Fluxer marketing site.
|
|
||||||
They are distributed under the SIL Open Font License, Version 1.1. The
|
|
||||||
complete license and the bundled copyright notice are in
|
|
||||||
`LICENSE-OFL-1.1.txt`.
|
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,116 +0,0 @@
|
|||||||
/* SPDX-License-Identifier: AGPL-3.0-or-later */
|
|
||||||
|
|
||||||
@font-face {
|
|
||||||
font-family: 'Radio Canada Big';
|
|
||||||
src: url('RadioCanadaBig-latin.woff2') format('woff2');
|
|
||||||
font-display: swap;
|
|
||||||
font-weight: 400 700;
|
|
||||||
font-style: normal;
|
|
||||||
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
|
|
||||||
}
|
|
||||||
|
|
||||||
@font-face {
|
|
||||||
font-family: 'Radio Canada Big';
|
|
||||||
src: url('RadioCanadaBig-latin-ext.woff2') format('woff2');
|
|
||||||
font-display: swap;
|
|
||||||
font-weight: 400 700;
|
|
||||||
font-style: normal;
|
|
||||||
unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
|
|
||||||
}
|
|
||||||
|
|
||||||
@font-face {
|
|
||||||
font-family: 'Noto Sans';
|
|
||||||
src: url('NotoSans-cyrillic.woff2') format('woff2');
|
|
||||||
font-display: swap;
|
|
||||||
font-weight: 100 900;
|
|
||||||
font-style: normal;
|
|
||||||
unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
|
|
||||||
}
|
|
||||||
|
|
||||||
@font-face {
|
|
||||||
font-family: 'Noto Sans';
|
|
||||||
src: url('NotoSans-cyrillic-ext.woff2') format('woff2');
|
|
||||||
font-display: swap;
|
|
||||||
font-weight: 100 900;
|
|
||||||
font-style: normal;
|
|
||||||
unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
|
|
||||||
}
|
|
||||||
|
|
||||||
@font-face {
|
|
||||||
font-family: 'Noto Sans';
|
|
||||||
src: url('NotoSans-devanagari.woff2') format('woff2');
|
|
||||||
font-display: swap;
|
|
||||||
font-weight: 100 900;
|
|
||||||
font-style: normal;
|
|
||||||
unicode-range: U+0900-097F, U+1CD0-1CF9, U+200C-200D, U+20A8, U+20B9, U+20F0, U+25CC, U+A830-A839, U+A8E0-A8FF, U+11B00-11B09;
|
|
||||||
}
|
|
||||||
|
|
||||||
@font-face {
|
|
||||||
font-family: 'Noto Sans';
|
|
||||||
src: url('NotoSans-greek.woff2') format('woff2');
|
|
||||||
font-display: swap;
|
|
||||||
font-weight: 100 900;
|
|
||||||
font-style: normal;
|
|
||||||
unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF;
|
|
||||||
}
|
|
||||||
|
|
||||||
@font-face {
|
|
||||||
font-family: 'Noto Sans';
|
|
||||||
src: url('NotoSans-greek-ext.woff2') format('woff2');
|
|
||||||
font-display: swap;
|
|
||||||
font-weight: 100 900;
|
|
||||||
font-style: normal;
|
|
||||||
unicode-range: U+1F00-1FFF;
|
|
||||||
}
|
|
||||||
|
|
||||||
@font-face {
|
|
||||||
font-family: 'Noto Sans';
|
|
||||||
src: url('NotoSans-vietnamese.woff2') format('woff2');
|
|
||||||
font-display: swap;
|
|
||||||
font-weight: 100 900;
|
|
||||||
font-style: normal;
|
|
||||||
unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
|
|
||||||
}
|
|
||||||
|
|
||||||
@font-face {
|
|
||||||
font-family: 'Noto Sans Arabic';
|
|
||||||
src: url('NotoSans-Arabic.woff2') format('woff2');
|
|
||||||
font-display: swap;
|
|
||||||
font-weight: 100 900;
|
|
||||||
font-style: normal;
|
|
||||||
unicode-range: U+0600-06FF, U+0750-077F, U+0870-088E, U+0890-0891, U+0897-08E1, U+08E3-08FF, U+200C-200E, U+2010-2011, U+204F, U+2E41, U+FB50-FDFF, U+FE70-FE74, U+FE76-FEFC, U+102E0-102FB, U+10E60-10E7E, U+10EC2-10EC4, U+10EFC-10EFF, U+1EE00-1EE03, U+1EE05-1EE1F, U+1EE21-1EE22, U+1EE24, U+1EE27, U+1EE29-1EE32, U+1EE34-1EE37, U+1EE39, U+1EE3B, U+1EE42, U+1EE47, U+1EE49, U+1EE4B, U+1EE4D-1EE4F, U+1EE51-1EE52, U+1EE54, U+1EE57, U+1EE59, U+1EE5B, U+1EE5D, U+1EE5F, U+1EE61-1EE62, U+1EE64, U+1EE67-1EE6A, U+1EE6C-1EE72, U+1EE74-1EE77, U+1EE79-1EE7C, U+1EE7E, U+1EE80-1EE89, U+1EE8B-1EE9B, U+1EEA1-1EEA3, U+1EEA5-1EEA9, U+1EEAB-1EEBB, U+1EEF0-1EEF1;
|
|
||||||
}
|
|
||||||
|
|
||||||
@font-face {
|
|
||||||
font-family: 'Noto Sans Hebrew';
|
|
||||||
src: url('NotoSans-Hebrew.woff2') format('woff2');
|
|
||||||
font-display: swap;
|
|
||||||
font-weight: 100 900;
|
|
||||||
font-style: normal;
|
|
||||||
unicode-range: U+0307-0308, U+0590-05FF, U+200C-2010, U+20AA, U+25CC, U+FB1D-FB4F;
|
|
||||||
}
|
|
||||||
|
|
||||||
@font-face {
|
|
||||||
font-family: 'Noto Sans Thai';
|
|
||||||
src: url('NotoSans-Thai.woff2') format('woff2');
|
|
||||||
font-display: swap;
|
|
||||||
font-weight: 100 900;
|
|
||||||
font-style: normal;
|
|
||||||
unicode-range: U+02D7, U+0303, U+0331, U+0E01-0E5B, U+200C-200D, U+25CC;
|
|
||||||
}
|
|
||||||
|
|
||||||
:root {
|
|
||||||
--fluxer-font-stack: 'Radio Canada Big', 'Noto Sans', system-ui, sans-serif;
|
|
||||||
}
|
|
||||||
|
|
||||||
:root:lang(ar) {
|
|
||||||
--fluxer-font-stack: 'Radio Canada Big', 'Noto Sans Arabic', 'Noto Sans', system-ui, sans-serif;
|
|
||||||
}
|
|
||||||
|
|
||||||
:root:lang(he) {
|
|
||||||
--fluxer-font-stack: 'Radio Canada Big', 'Noto Sans Hebrew', 'Noto Sans', system-ui, sans-serif;
|
|
||||||
}
|
|
||||||
|
|
||||||
:root:lang(th) {
|
|
||||||
--fluxer-font-stack: 'Radio Canada Big', 'Noto Sans Thai', 'Noto Sans', system-ui, sans-serif;
|
|
||||||
}
|
|
||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,30 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
|
||||||
|
|
||||||
set -euo pipefail
|
|
||||||
|
|
||||||
repo_root="$(git rev-parse --show-toplevel)"
|
|
||||||
cd "$repo_root"
|
|
||||||
|
|
||||||
initialize_command="git -c submodule.fluxer_marketing.update=checkout submodule update --init -- fluxer_marketing"
|
|
||||||
|
|
||||||
if ! git -c submodule.fluxer_marketing.update=checkout submodule update --init -- fluxer_marketing; then
|
|
||||||
printf '%s\n' \
|
|
||||||
"Unable to initialize the private fluxerapp/marketing repository." \
|
|
||||||
"Confirm that your GitHub account has access and that your existing Git credentials can authenticate, then run:" \
|
|
||||||
" $initialize_command" >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ ! -f fluxer_marketing/Cargo.toml ]]; then
|
|
||||||
printf '%s\n' \
|
|
||||||
"The marketing submodule initialized without its required Cargo.toml." \
|
|
||||||
"Remove the inconsistent checkout and run:" \
|
|
||||||
" $initialize_command" >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
printf '%s\n' \
|
|
||||||
"Private marketing source is initialized at fluxer_marketing." \
|
|
||||||
"Install its dependencies explicitly with:" \
|
|
||||||
" pnpm --dir fluxer_marketing install --frozen-lockfile"
|
|
||||||
@@ -522,10 +522,6 @@ fn validate_component(component: &str) -> Result<()> {
|
|||||||
}),
|
}),
|
||||||
"Invalid release component {component:?}: expected lowercase letters, digits, and single hyphen separators"
|
"Invalid release component {component:?}: expected lowercase letters, digits, and single hyphen separators"
|
||||||
);
|
);
|
||||||
ensure!(
|
|
||||||
component != "fluxer-marketing" && component != "marketing",
|
|
||||||
"Marketing must not publish a public GitHub Release"
|
|
||||||
);
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+2
-239
@@ -31,7 +31,6 @@ const DEFAULT_TASKS: &[&str] = &[
|
|||||||
"proxy",
|
"proxy",
|
||||||
"services",
|
"services",
|
||||||
"media",
|
"media",
|
||||||
"marketing",
|
|
||||||
"admin",
|
"admin",
|
||||||
"api",
|
"api",
|
||||||
"gateway-single",
|
"gateway-single",
|
||||||
@@ -45,32 +44,12 @@ const OBJECT_STORE_TASKS: &[&str] = &["api", "worker", "media"];
|
|||||||
const CLOUDFLARE_TUNNEL_TASK: &str = "cloudflare-tunnel";
|
const CLOUDFLARE_TUNNEL_TASK: &str = "cloudflare-tunnel";
|
||||||
const OBJECT_STORE_STARTUP_REPAIR_TIMEOUT_SECS: u64 = 60;
|
const OBJECT_STORE_STARTUP_REPAIR_TIMEOUT_SECS: u64 = 60;
|
||||||
const DEFAULT_OBJECT_STORE_MONITOR_INTERVAL_SECS: u64 = 15;
|
const DEFAULT_OBJECT_STORE_MONITOR_INTERVAL_SECS: u64 = 15;
|
||||||
const MARKETING_MANIFEST: &str = "fluxer_marketing/Cargo.toml";
|
|
||||||
const MARKETING_INITIALIZE_COMMAND: &str =
|
|
||||||
"git -c submodule.fluxer_marketing.update=checkout submodule update --init -- fluxer_marketing";
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
|
||||||
enum MarketingAvailability {
|
|
||||||
Unavailable,
|
|
||||||
Available,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn run_dev(task_names: &[String], cloudflare_tunnel: bool) -> Result<i32> {
|
pub async fn run_dev(task_names: &[String], cloudflare_tunnel: bool) -> Result<i32> {
|
||||||
let marketing_availability = marketing_availability()?;
|
let mut tasks = task_table()?;
|
||||||
if task_names.iter().any(|name| name == "marketing")
|
|
||||||
&& marketing_availability == MarketingAvailability::Unavailable
|
|
||||||
{
|
|
||||||
bail!(
|
|
||||||
"The private marketing project is unavailable. Authorized maintainers can initialize it with:\n {MARKETING_INITIALIZE_COMMAND}"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
let mut tasks = task_table_for_availability(marketing_availability)?;
|
|
||||||
let selected = if task_names.is_empty() {
|
let selected = if task_names.is_empty() {
|
||||||
DEFAULT_TASKS
|
DEFAULT_TASKS
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|name| {
|
|
||||||
**name != "marketing" || marketing_availability == MarketingAvailability::Available
|
|
||||||
})
|
|
||||||
.map(|name| (*name).to_owned())
|
.map(|name| (*name).to_owned())
|
||||||
.collect::<Vec<_>>()
|
.collect::<Vec<_>>()
|
||||||
} else {
|
} else {
|
||||||
@@ -344,20 +323,12 @@ fn normalize_selected_tasks(mut selected: Vec<String>, cloudflare_tunnel: bool)
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn task_table() -> Result<BTreeMap<&'static str, DevTask>> {
|
pub fn task_table() -> Result<BTreeMap<&'static str, DevTask>> {
|
||||||
task_table_for_availability(marketing_availability()?)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn task_table_for_availability(
|
|
||||||
marketing_availability: MarketingAvailability,
|
|
||||||
) -> Result<BTreeMap<&'static str, DevTask>> {
|
|
||||||
let self_tool = self_tool_command()?;
|
let self_tool = self_tool_command()?;
|
||||||
let api_dir = ROOT.join("fluxer_api");
|
let api_dir = ROOT.join("fluxer_api");
|
||||||
let api_tsx = api_dir.join("node_modules/.bin/tsx");
|
let api_tsx = api_dir.join("node_modules/.bin/tsx");
|
||||||
let app_dir = ROOT.join("fluxer_app");
|
let app_dir = ROOT.join("fluxer_app");
|
||||||
let app_dev_server = ROOT.join("tools/ci/run.sh");
|
let app_dev_server = ROOT.join("tools/ci/run.sh");
|
||||||
let public_url = public_url();
|
let public_url = public_url();
|
||||||
let marketing_endpoint = std::env::var("FLUXER_MARKETING_ENDPOINT")
|
|
||||||
.unwrap_or_else(|_| format!("{public_url}/marketing"));
|
|
||||||
let admin_endpoint =
|
let admin_endpoint =
|
||||||
std::env::var("FLUXER_ADMIN_ENDPOINT").unwrap_or_else(|_| format!("{public_url}/admin"));
|
std::env::var("FLUXER_ADMIN_ENDPOINT").unwrap_or_else(|_| format!("{public_url}/admin"));
|
||||||
let mut tasks = BTreeMap::new();
|
let mut tasks = BTreeMap::new();
|
||||||
@@ -515,70 +486,6 @@ fn task_table_for_availability(
|
|||||||
Some("true".to_owned()),
|
Some("true".to_owned()),
|
||||||
)],
|
)],
|
||||||
});
|
});
|
||||||
if marketing_availability == MarketingAvailability::Available {
|
|
||||||
insert(DevTask {
|
|
||||||
name: "marketing",
|
|
||||||
args: strings(&[
|
|
||||||
"cargo",
|
|
||||||
"watch",
|
|
||||||
"--no-dot-ignores",
|
|
||||||
"-w",
|
|
||||||
"fluxer_marketing/src",
|
|
||||||
"-w",
|
|
||||||
MARKETING_MANIFEST,
|
|
||||||
"-w",
|
|
||||||
"fluxer_marketing/build.rs",
|
|
||||||
"-w",
|
|
||||||
"fluxer_marketing/content",
|
|
||||||
"-w",
|
|
||||||
"fluxer_marketing/Cargo.lock",
|
|
||||||
"-w",
|
|
||||||
"fluxer_marketing/package.json",
|
|
||||||
"-w",
|
|
||||||
"fluxer_marketing/pnpm-lock.yaml",
|
|
||||||
"-w",
|
|
||||||
"fluxer_marketing/pnpm-workspace.yaml",
|
|
||||||
"-w",
|
|
||||||
"fluxer_marketing/static",
|
|
||||||
"-w",
|
|
||||||
"Cargo.toml",
|
|
||||||
"-w",
|
|
||||||
"fluxer_common",
|
|
||||||
"-w",
|
|
||||||
"packages/fonts/manifest.json",
|
|
||||||
"-w",
|
|
||||||
"packages/fonts/NOTICE.md",
|
|
||||||
"-w",
|
|
||||||
"packages/fonts/LICENSE-IBM-PLEX.txt",
|
|
||||||
"-w",
|
|
||||||
"packages/fonts/css/locale-fallbacks.css",
|
|
||||||
"-w",
|
|
||||||
"packages/fonts/files/FluxerSans",
|
|
||||||
"-w",
|
|
||||||
"packages/fonts/files/FluxerMono",
|
|
||||||
"-w",
|
|
||||||
"packages/i18n/marketing",
|
|
||||||
"-x",
|
|
||||||
"run --manifest-path fluxer_marketing/Cargo.toml -p fluxer_marketing",
|
|
||||||
]),
|
|
||||||
cwd: ROOT.clone(),
|
|
||||||
env: vec![
|
|
||||||
("FLUXER_APP_ENDPOINT".to_owned(), Some(public_url.clone())),
|
|
||||||
(
|
|
||||||
"FLUXER_MARKETING_BASE_PATH".to_owned(),
|
|
||||||
Some("/marketing".to_owned()),
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"FLUXER_MARKETING_ENDPOINT".to_owned(),
|
|
||||||
Some(marketing_endpoint),
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"FLUXER_STATIC_CDN_ENDPOINT".to_owned(),
|
|
||||||
Some(public_url.clone()),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
});
|
|
||||||
}
|
|
||||||
insert(DevTask {
|
insert(DevTask {
|
||||||
name: "admin",
|
name: "admin",
|
||||||
args: strings(&[
|
args: strings(&[
|
||||||
@@ -628,74 +535,6 @@ fn task_table_for_availability(
|
|||||||
Ok(tasks)
|
Ok(tasks)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn marketing_availability() -> Result<MarketingAvailability> {
|
|
||||||
let marketing_path = ROOT.join("fluxer_marketing");
|
|
||||||
let manifest_path = ROOT.join(MARKETING_MANIFEST);
|
|
||||||
if manifest_path.is_file() {
|
|
||||||
ensure_marketing_manifest(&manifest_path)?;
|
|
||||||
return Ok(MarketingAvailability::Available);
|
|
||||||
}
|
|
||||||
if marketing_path.exists() {
|
|
||||||
let mut entries = std::fs::read_dir(&marketing_path)
|
|
||||||
.with_context(|| format!("failed to inspect {}", marketing_path.display()))?;
|
|
||||||
if entries.next().transpose()?.is_some() {
|
|
||||||
bail!(
|
|
||||||
"The marketing path {} exists but does not contain the required Cargo.toml; remove the inconsistent checkout and run:\n {MARKETING_INITIALIZE_COMMAND}",
|
|
||||||
marketing_path.display()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(MarketingAvailability::Unavailable)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn ensure_marketing_manifest(path: &Path) -> Result<()> {
|
|
||||||
let output = Command::new("cargo")
|
|
||||||
.args([
|
|
||||||
"metadata",
|
|
||||||
"--manifest-path",
|
|
||||||
MARKETING_MANIFEST,
|
|
||||||
"--locked",
|
|
||||||
"--offline",
|
|
||||||
"--no-deps",
|
|
||||||
"--format-version",
|
|
||||||
"1",
|
|
||||||
])
|
|
||||||
.current_dir(ROOT.as_path())
|
|
||||||
.output()
|
|
||||||
.with_context(|| format!("failed to validate {}", path.display()))?;
|
|
||||||
if !output.status.success() {
|
|
||||||
bail!(
|
|
||||||
"The initialized private marketing manifest {} is malformed or inconsistent: {}",
|
|
||||||
path.display(),
|
|
||||||
String::from_utf8_lossy(&output.stderr).trim()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
let metadata: serde_json::Value = serde_json::from_slice(&output.stdout)
|
|
||||||
.with_context(|| format!("Cargo emitted invalid metadata for {}", path.display()))?;
|
|
||||||
let packages = metadata["packages"]
|
|
||||||
.as_array()
|
|
||||||
.with_context(|| format!("Cargo metadata for {} is missing packages", path.display()))?;
|
|
||||||
let expected_manifest_path = path
|
|
||||||
.canonicalize()
|
|
||||||
.with_context(|| format!("failed to resolve {}", path.display()))?;
|
|
||||||
let valid_package = packages.iter().any(|package| {
|
|
||||||
package["name"].as_str() == Some("fluxer_marketing")
|
|
||||||
&& package["manifest_path"]
|
|
||||||
.as_str()
|
|
||||||
.map(Path::new)
|
|
||||||
.and_then(|manifest_path| manifest_path.canonicalize().ok())
|
|
||||||
.as_deref()
|
|
||||||
== Some(expected_manifest_path.as_path())
|
|
||||||
});
|
|
||||||
if !valid_package {
|
|
||||||
bail!(
|
|
||||||
"The initialized private marketing manifest {} does not define the root package fluxer_marketing",
|
|
||||||
path.display()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn wait_for_search_backend_if_needed(selected: &[String]) -> Result<()> {
|
async fn wait_for_search_backend_if_needed(selected: &[String]) -> Result<()> {
|
||||||
if !selected
|
if !selected
|
||||||
.iter()
|
.iter()
|
||||||
@@ -781,26 +620,6 @@ async fn ensure_js_dependencies_if_needed(
|
|||||||
AwaitOutcome::Shutdown(signal) => return Ok(AwaitOutcome::Shutdown(signal)),
|
AwaitOutcome::Shutdown(signal) => return Ok(AwaitOutcome::Shutdown(signal)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if selected.iter().any(|name| name == "marketing") {
|
|
||||||
let marketing_dir = ROOT.join("fluxer_marketing");
|
|
||||||
match run_command_interruptible(
|
|
||||||
&["pnpm", "install", "--frozen-lockfile"],
|
|
||||||
RunOptions {
|
|
||||||
cwd: &marketing_dir,
|
|
||||||
env: PNPM_INSTALL_ENV
|
|
||||||
.iter()
|
|
||||||
.map(|(key, value)| ((*key).to_owned(), Some((*value).to_owned())))
|
|
||||||
.collect(),
|
|
||||||
..RunOptions::default()
|
|
||||||
},
|
|
||||||
shutdown,
|
|
||||||
)
|
|
||||||
.await?
|
|
||||||
{
|
|
||||||
AwaitOutcome::Completed(_) => {}
|
|
||||||
AwaitOutcome::Shutdown(signal) => return Ok(AwaitOutcome::Shutdown(signal)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(AwaitOutcome::Completed(()))
|
Ok(AwaitOutcome::Completed(()))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -950,15 +769,6 @@ async fn wait_for_cloudflare_tunnel_routes(
|
|||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
}
|
}
|
||||||
if has_task("marketing") {
|
|
||||||
wait_http_for_dev_tasks(
|
|
||||||
processes,
|
|
||||||
"dev proxy marketing",
|
|
||||||
&format!("{base_url}/marketing/"),
|
|
||||||
timeout,
|
|
||||||
)
|
|
||||||
.await?;
|
|
||||||
}
|
|
||||||
if has_task("admin") {
|
if has_task("admin") {
|
||||||
wait_http_for_dev_tasks(
|
wait_http_for_dev_tasks(
|
||||||
processes,
|
processes,
|
||||||
@@ -1096,7 +906,6 @@ mod tests {
|
|||||||
"proxy",
|
"proxy",
|
||||||
"services",
|
"services",
|
||||||
"media",
|
"media",
|
||||||
"marketing",
|
|
||||||
"admin",
|
"admin",
|
||||||
"api",
|
"api",
|
||||||
"gateway-single",
|
"gateway-single",
|
||||||
@@ -1171,7 +980,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn task_table_contains_recursive_binary_tasks() {
|
fn task_table_contains_recursive_binary_tasks() {
|
||||||
let tasks = task_table_for_availability(MarketingAvailability::Available).unwrap();
|
let tasks = task_table().unwrap();
|
||||||
let expected_public_url = public_url();
|
let expected_public_url = public_url();
|
||||||
let expected_app_port = APP_PORT.to_string();
|
let expected_app_port = APP_PORT.to_string();
|
||||||
let expected_admin_port = ADMIN_PORT.to_string();
|
let expected_admin_port = ADMIN_PORT.to_string();
|
||||||
@@ -1287,52 +1096,6 @@ mod tests {
|
|||||||
"-p".to_owned(),
|
"-p".to_owned(),
|
||||||
"fluxer-media-proxy".to_owned()
|
"fluxer-media-proxy".to_owned()
|
||||||
]));
|
]));
|
||||||
assert_eq!(
|
|
||||||
tasks["marketing"].args,
|
|
||||||
vec![
|
|
||||||
"cargo".to_owned(),
|
|
||||||
"watch".to_owned(),
|
|
||||||
"--no-dot-ignores".to_owned(),
|
|
||||||
"-w".to_owned(),
|
|
||||||
"fluxer_marketing/src".to_owned(),
|
|
||||||
"-w".to_owned(),
|
|
||||||
"fluxer_marketing/Cargo.toml".to_owned(),
|
|
||||||
"-w".to_owned(),
|
|
||||||
"fluxer_marketing/build.rs".to_owned(),
|
|
||||||
"-w".to_owned(),
|
|
||||||
"fluxer_marketing/content".to_owned(),
|
|
||||||
"-w".to_owned(),
|
|
||||||
"fluxer_marketing/Cargo.lock".to_owned(),
|
|
||||||
"-w".to_owned(),
|
|
||||||
"fluxer_marketing/package.json".to_owned(),
|
|
||||||
"-w".to_owned(),
|
|
||||||
"fluxer_marketing/pnpm-lock.yaml".to_owned(),
|
|
||||||
"-w".to_owned(),
|
|
||||||
"fluxer_marketing/pnpm-workspace.yaml".to_owned(),
|
|
||||||
"-w".to_owned(),
|
|
||||||
"fluxer_marketing/static".to_owned(),
|
|
||||||
"-w".to_owned(),
|
|
||||||
"Cargo.toml".to_owned(),
|
|
||||||
"-w".to_owned(),
|
|
||||||
"fluxer_common".to_owned(),
|
|
||||||
"-w".to_owned(),
|
|
||||||
"packages/fonts/manifest.json".to_owned(),
|
|
||||||
"-w".to_owned(),
|
|
||||||
"packages/fonts/NOTICE.md".to_owned(),
|
|
||||||
"-w".to_owned(),
|
|
||||||
"packages/fonts/LICENSE-IBM-PLEX.txt".to_owned(),
|
|
||||||
"-w".to_owned(),
|
|
||||||
"packages/fonts/css/locale-fallbacks.css".to_owned(),
|
|
||||||
"-w".to_owned(),
|
|
||||||
"packages/fonts/files/FluxerSans".to_owned(),
|
|
||||||
"-w".to_owned(),
|
|
||||||
"packages/fonts/files/FluxerMono".to_owned(),
|
|
||||||
"-w".to_owned(),
|
|
||||||
"packages/i18n/marketing".to_owned(),
|
|
||||||
"-x".to_owned(),
|
|
||||||
"run --manifest-path fluxer_marketing/Cargo.toml -p fluxer_marketing".to_owned()
|
|
||||||
]
|
|
||||||
);
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
tasks["admin"].args,
|
tasks["admin"].args,
|
||||||
vec![
|
vec![
|
||||||
|
|||||||
@@ -15,7 +15,6 @@ pub const API_PORT: u16 = 8080;
|
|||||||
pub const GATEWAY_PORT: u16 = 8771;
|
pub const GATEWAY_PORT: u16 = 8771;
|
||||||
pub const GATEWAY_WEBSOCKET_PORTS: &[u16] = &[8771, 8772, 8774];
|
pub const GATEWAY_WEBSOCKET_PORTS: &[u16] = &[8771, 8772, 8774];
|
||||||
pub const MEDIA_PROXY_PORT: u16 = 8082;
|
pub const MEDIA_PROXY_PORT: u16 = 8082;
|
||||||
pub const MARKETING_PORT: u16 = 3010;
|
|
||||||
pub const LIVEKIT_PORT: u16 = 7880;
|
pub const LIVEKIT_PORT: u16 = 7880;
|
||||||
pub const DEVMAIL_PORT: u16 = 8025;
|
pub const DEVMAIL_PORT: u16 = 8025;
|
||||||
|
|
||||||
@@ -108,13 +107,6 @@ pub const PROXY_ROUTES: &[ProxyRoute] = &[
|
|||||||
strip_prefix: false,
|
strip_prefix: false,
|
||||||
alternate_ports: &[],
|
alternate_ports: &[],
|
||||||
},
|
},
|
||||||
ProxyRoute {
|
|
||||||
prefix: "/marketing",
|
|
||||||
host: LOOPBACK_HOST,
|
|
||||||
port: MARKETING_PORT,
|
|
||||||
strip_prefix: true,
|
|
||||||
alternate_ports: &[],
|
|
||||||
},
|
|
||||||
ProxyRoute {
|
ProxyRoute {
|
||||||
prefix: "/assets",
|
prefix: "/assets",
|
||||||
host: LOOPBACK_HOST,
|
host: LOOPBACK_HOST,
|
||||||
|
|||||||
@@ -77,8 +77,6 @@ pub enum CatalogLayout {
|
|||||||
pub enum CatalogName {
|
pub enum CatalogName {
|
||||||
#[value(name = "app")]
|
#[value(name = "app")]
|
||||||
App,
|
App,
|
||||||
#[value(name = "marketing")]
|
|
||||||
Marketing,
|
|
||||||
#[value(name = "errors")]
|
#[value(name = "errors")]
|
||||||
Errors,
|
Errors,
|
||||||
#[value(name = "api-content", alias = "content")]
|
#[value(name = "api-content", alias = "content")]
|
||||||
@@ -91,7 +89,6 @@ impl CatalogName {
|
|||||||
fn label(self) -> &'static str {
|
fn label(self) -> &'static str {
|
||||||
match self {
|
match self {
|
||||||
CatalogName::App => "app",
|
CatalogName::App => "app",
|
||||||
CatalogName::Marketing => "marketing",
|
|
||||||
CatalogName::Errors => "errors",
|
CatalogName::Errors => "errors",
|
||||||
CatalogName::ApiContent => "api-content",
|
CatalogName::ApiContent => "api-content",
|
||||||
CatalogName::Email => "email",
|
CatalogName::Email => "email",
|
||||||
@@ -123,10 +120,6 @@ impl RuntimeConfig {
|
|||||||
.unwrap_or_else(|| PathBuf::from("."));
|
.unwrap_or_else(|| PathBuf::from("."));
|
||||||
let (locales_dir, catalog_layout) = match catalog {
|
let (locales_dir, catalog_layout) = match catalog {
|
||||||
CatalogName::App => (locales_dir(&app_dir), CatalogLayout::NestedMessages),
|
CatalogName::App => (locales_dir(&app_dir), CatalogLayout::NestedMessages),
|
||||||
CatalogName::Marketing => (
|
|
||||||
repo_root.join("packages/i18n/marketing"),
|
|
||||||
CatalogLayout::FlatPo,
|
|
||||||
),
|
|
||||||
CatalogName::Errors => (
|
CatalogName::Errors => (
|
||||||
repo_root
|
repo_root
|
||||||
.join("packages")
|
.join("packages")
|
||||||
@@ -277,14 +270,9 @@ struct RawTranslateArgs {
|
|||||||
#[arg(
|
#[arg(
|
||||||
long,
|
long,
|
||||||
value_enum,
|
value_enum,
|
||||||
help = "Catalog target to translate: app, marketing, errors, api-content, or email"
|
help = "Catalog target to translate: app, errors, api-content, or email"
|
||||||
)]
|
)]
|
||||||
catalog: Option<CatalogName>,
|
catalog: Option<CatalogName>,
|
||||||
#[arg(
|
|
||||||
long,
|
|
||||||
help = "Deprecated alias for --catalog marketing; use packages/i18n/marketing flat gettext catalogs"
|
|
||||||
)]
|
|
||||||
marketing: bool,
|
|
||||||
#[arg(
|
#[arg(
|
||||||
long = "msgctxt",
|
long = "msgctxt",
|
||||||
help = "Only translate entries with this PO msgctxt or static catalog key; repeatable. Email fields use <template>.<subject|body>."
|
help = "Only translate entries with this PO msgctxt or static catalog key; repeatable. Email fields use <template>.<subject|body>."
|
||||||
@@ -368,15 +356,7 @@ fn normalize_args(raw: RawTranslateArgs, env_overrides: &EnvOverlay) -> Result<T
|
|||||||
reset = true;
|
reset = true;
|
||||||
all = true;
|
all = true;
|
||||||
}
|
}
|
||||||
let catalog = match (raw.catalog, raw.marketing) {
|
let catalog = raw.catalog.unwrap_or(CatalogName::App);
|
||||||
(Some(CatalogName::Marketing), true) | (None, true) => CatalogName::Marketing,
|
|
||||||
(Some(catalog), false) => catalog,
|
|
||||||
(None, false) => CatalogName::App,
|
|
||||||
(Some(catalog), true) => bail!(
|
|
||||||
"--marketing cannot be combined with --catalog {}; use --catalog marketing",
|
|
||||||
catalog.label()
|
|
||||||
),
|
|
||||||
};
|
|
||||||
if !all && raw.locales.is_empty() {
|
if !all && raw.locales.is_empty() {
|
||||||
all = true;
|
all = true;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user