mmcux commited on
Commit
89b6a89
·
1 Parent(s): ae9f077

skip posts marked draft: true

Browse files

Lets unpublished posts live in the content repo alongside published ones.
Also documents using a token URL for a private content repo.

Dockerfile CHANGED
@@ -30,9 +30,8 @@ COPY . .
30
  # `*.md` files into the image; leave it unset and the /news section simply
31
  # does not appear. The clone itself is done by the `prebuild` npm script, so
32
  # that Nixpacks builds (which never read this Dockerfile) behave identically.
33
- #
34
- # Use a public repo: build args are recorded in the image history, so a URL
35
- # carrying an access token would leak to anyone who can pull the image.
36
  ARG NEWS_CONTENT_REPO=
37
  ARG NEWS_CONTENT_REF=main
38
  ENV NEWS_CONTENT_REPO=$NEWS_CONTENT_REPO
 
30
  # `*.md` files into the image; leave it unset and the /news section simply
31
  # does not appear. The clone itself is done by the `prebuild` npm script, so
32
  # that Nixpacks builds (which never read this Dockerfile) behave identically.
33
+ # For a private repo the URL carries a token — see the README for what that
34
+ # means for the built image.
 
35
  ARG NEWS_CONTENT_REPO=
36
  ARG NEWS_CONTENT_REF=main
37
  ENV NEWS_CONTENT_REPO=$NEWS_CONTENT_REPO
README.md CHANGED
@@ -38,9 +38,12 @@ which never reads the `Dockerfile`, and `prebuild` is the one hook both build pa
38
  On Coolify these must be marked as **build variables**, not just runtime env vars, or the
39
  build will not see them.
40
 
41
- Use a **public** repo: with a Docker build these arrive as build args, which are recorded
42
- in the image history, so a URL carrying an access token would be readable by anyone who
43
- can pull the image.
 
 
 
44
 
45
  A clone failure fails the build rather than silently shipping a site with no
46
  announcements.
@@ -54,6 +57,7 @@ title: Ranking switches from Elo to Arena Score
54
  date: 2026-07-23
55
  summary: Optional one-line teaser shown in the listing.
56
  author: Optional byline
 
57
  ---
58
 
59
  Body in Markdown. Headings, lists, links, tables, code and block quotes are styled.
@@ -62,6 +66,12 @@ Body in Markdown. Headings, lists, links, tables, code and block quotes are styl
62
  `title` and `date` are required; a post missing either is skipped with a build warning.
63
  Posts are listed newest first by `date`.
64
 
 
 
 
 
 
 
65
  Publishing a post is a push to the content repo followed by a redeploy of the frontend —
66
  the Markdown is baked into the image, so a rebuild is what makes a new post appear.
67
 
 
38
  On Coolify these must be marked as **build variables**, not just runtime env vars, or the
39
  build will not see them.
40
 
41
+ For a **private** content repo, put an access token in the URL
42
+ (`https://<token>@github.com/<org>/<repo>.git`). Note that the token is then recorded in
43
+ the built image. TS-Arena's own deployment accepts that: the images never leave internal
44
+ hosts, and anyone with Docker access there can read the content repo anyway. If you run
45
+ an instance where that is not true, use a public repo or a read-only token you are willing
46
+ to rotate.
47
 
48
  A clone failure fails the build rather than silently shipping a site with no
49
  announcements.
 
57
  date: 2026-07-23
58
  summary: Optional one-line teaser shown in the listing.
59
  author: Optional byline
60
+ draft: true
61
  ---
62
 
63
  Body in Markdown. Headings, lists, links, tables, code and block quotes are styled.
 
66
  `title` and `date` are required; a post missing either is skipped with a build warning.
67
  Posts are listed newest first by `date`.
68
 
69
+ `draft: true` keeps a post out of the build entirely — no page, no route, no listing entry
70
+ — so unfinished posts can sit in the content repo next to the published ones. Drop the
71
+ line (or set it to `false`) to publish on the next redeploy. The draft's Markdown file is
72
+ still copied into the image, it is just never rendered or routed; treat drafts as hidden
73
+ from site visitors, not as a secret from anyone who can read the image.
74
+
75
  Publishing a post is a push to the content repo followed by a redeploy of the frontend —
76
  the Markdown is baked into the image, so a rebuild is what makes a new post appear.
77
 
scripts/fetch-news.mjs CHANGED
@@ -10,6 +10,10 @@
10
  * NEWS_CONTENT_REPO clone URL of the content repo (unset = no news)
11
  * NEWS_CONTENT_REF branch or tag to clone (default: main)
12
  *
 
 
 
 
13
  * Deliberately lives in npm-script land rather than in the Dockerfile: the
14
  * Coolify apps build with Nixpacks, which never reads the Dockerfile. Hooking
15
  * into `prebuild` is the one place both build paths go through.
@@ -30,8 +34,6 @@ if (!repo) {
30
  process.exit(0);
31
  }
32
 
33
- // Never print `repo` itself: if someone ignores the advice and uses a URL with
34
- // an embedded token, it must not end up in the build log.
35
  console.log(`[news] cloning news content (ref: ${ref})`);
36
 
37
  // Clone into a staging directory and only swap it in once it succeeds, so a
@@ -44,6 +46,8 @@ fs.mkdirSync(path.dirname(TARGET), { recursive: true });
44
  try {
45
  execFileSync('git', ['clone', '--depth', '1', '--branch', ref, repo, staging], {
46
  stdio: ['ignore', 'inherit', 'pipe'],
 
 
47
  });
48
  } catch (err) {
49
  // Fail the build loudly. A silent fallback to "no news" would ship a site
 
10
  * NEWS_CONTENT_REPO clone URL of the content repo (unset = no news)
11
  * NEWS_CONTENT_REF branch or tag to clone (default: main)
12
  *
13
+ * For a private repo, put the access token in the URL. TS-Arena's own deploys
14
+ * are internal-only and anyone with Docker access on those hosts can read the
15
+ * content repo anyway, so the token ending up in the image is acceptable there.
16
+ *
17
  * Deliberately lives in npm-script land rather than in the Dockerfile: the
18
  * Coolify apps build with Nixpacks, which never reads the Dockerfile. Hooking
19
  * into `prebuild` is the one place both build paths go through.
 
34
  process.exit(0);
35
  }
36
 
 
 
37
  console.log(`[news] cloning news content (ref: ${ref})`);
38
 
39
  // Clone into a staging directory and only swap it in once it succeeds, so a
 
46
  try {
47
  execFileSync('git', ['clone', '--depth', '1', '--branch', ref, repo, staging], {
48
  stdio: ['ignore', 'inherit', 'pipe'],
49
+ // Bad credentials should fail the build, not hang it on a username prompt.
50
+ env: { ...process.env, GIT_TERMINAL_PROMPT: '0' },
51
  });
52
  } catch (err) {
53
  // Fail the build loudly. A silent fallback to "no news" would ship a site
src/content/news/index.ts CHANGED
@@ -57,6 +57,13 @@ function readPosts(): NewsPost[] {
57
  continue;
58
  }
59
 
 
 
 
 
 
 
 
60
  posts.push({
61
  slug,
62
  title,
 
57
  continue;
58
  }
59
 
60
+ // Drafts stay in the content repo but never reach the site. Not rendered
61
+ // and not routed, so there is no unlisted URL to stumble onto either.
62
+ if (data.draft === true) {
63
+ console.log(`[news] skipping draft content/news/${fileName}`);
64
+ continue;
65
+ }
66
+
67
  posts.push({
68
  slug,
69
  title,
src/content/news/types.ts CHANGED
@@ -7,13 +7,16 @@
7
  * date: 2026-07-23
8
  * summary: One-line teaser shown in the listing.
9
  * author: TS-Arena Team
 
10
  * ---
11
  *
12
  * Body in Markdown…
13
  * ```
14
  *
15
  * `title` and `date` are required; a post missing either is skipped with a
16
- * build-time warning rather than breaking the build.
 
 
17
  */
18
  export interface NewsPostMetadata {
19
  /** URL slug — derived from the file name (sans `.md`). */
 
7
  * date: 2026-07-23
8
  * summary: One-line teaser shown in the listing.
9
  * author: TS-Arena Team
10
+ * draft: true
11
  * ---
12
  *
13
  * Body in Markdown…
14
  * ```
15
  *
16
  * `title` and `date` are required; a post missing either is skipped with a
17
+ * build-time warning rather than breaking the build. `draft: true` keeps a
18
+ * post out of the build entirely, so unpublished work can live in the content
19
+ * repo alongside what is live.
20
  */
21
  export interface NewsPostMetadata {
22
  /** URL slug — derived from the file name (sans `.md`). */