Skip to content

feat(blog): auto-update project board on publish#693

Merged
antoinedc merged 3 commits intodevelopfrom
feature/blog-stack
Mar 14, 2026
Merged

feat(blog): auto-update project board on publish#693
antoinedc merged 3 commits intodevelopfrom
feature/blog-stack

Conversation

@antoinedc
Copy link
Member

Moves the project card from Drafting to Published when the publish workflow runs.

Antoine de Chevigné and others added 3 commits March 14, 2026 13:19
GITHUB_TOKEN lacks admin permissions to merge PRs that require
approving reviews. Use GH_PAT (already available as repo secret)
for both checkout and PR merge.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The "Create and merge PR" step was running even when the article
was already published, causing failures with empty branch/slug vars.
Now gates on publish step outputs being set.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Uses existing pipeline helpers (getProjectItems, updateCardStatus)
to find the card by article path and move it to Published status.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@antoinedc antoinedc merged commit f4e4b4a into develop Mar 14, 2026
2 checks passed
@antoinedc antoinedc deleted the feature/blog-stack branch March 14, 2026 12:26
@greptile-apps
Copy link

greptile-apps bot commented Mar 14, 2026

Greptile Summary

This PR extends the blog-publish.yml workflow to automatically move the associated GitHub Projects V2 card from "Drafting" to "Published" after an article is merged. It also switches the checkout and PR creation steps from GITHUB_TOKEN to GH_PAT, which is necessary to allow downstream workflow triggers and to access the Projects V2 API.

Key changes:

  • Checkout and Create and merge PR steps now use secrets.GH_PAT instead of secrets.GITHUB_TOKEN, enabling Projects V2 write access.
  • Condition on Create and merge PR is tightened from steps.resolve.outputs.article != '' to steps.publish.outputs.slug != '', ensuring the step only runs when publishing actually proceeded.
  • Adds actions/setup-node@v4 (Node 20) + an inline Node.js step that calls getProjectItems() and updateCardStatus() from blog/pipeline/project.js to transition the card to Published.
  • Critical issue: The inline node -e script uses ESM import syntax, but Node.js does not apply package.json's "type": "module" to --eval / -e input. Without the --input-type=module flag, the step will always throw a SyntaxError and fail, meaning no project card will ever be updated.

Confidence Score: 2/5

  • The article publish flow itself is unaffected, but the new feature (project card update) will always fail due to an ESM/CommonJS mismatch in the inline Node.js script.
  • The critical bug — using ESM import inside node -e without --input-type=module — means the sole new capability introduced by this PR (updating the project board card) will never execute. The underlying publish and PR-merge steps are unchanged and will continue to work, but the feature goal of the PR is broken out of the box.
  • .github/workflows/blog-publish.yml lines 122–132 — the node -e inline script requires --input-type=module to use ESM import syntax.

Important Files Changed

Filename Overview
.github/workflows/blog-publish.yml Adds a "Update project card to Published" step and switches checkout/PR tokens from GITHUB_TOKEN to GH_PAT. The new Node.js inline script uses ESM import syntax without the required --input-type=module flag, which will cause a SyntaxError at runtime and prevent the project card from ever being updated.

Sequence Diagram

sequenceDiagram
    actor Dev as Developer
    participant WD as workflow_dispatch
    participant GHA as GitHub Actions
    participant FS as File System
    participant GH as GitHub API (GH_PAT)
    participant PB as Project Board V2

    Dev->>WD: Trigger (slug or empty)
    WD->>GHA: Start publish job

    GHA->>FS: Resolve article path (by slug or oldest draft)
    FS-->>GHA: article path

    GHA->>FS: Update frontmatter status → published
    GHA->>GH: git push new branch
    GHA->>GH: gh pr create + merge (squash, admin)
    GH-->>GHA: PR merged ✓

    GHA->>GHA: actions/setup-node@v4 (Node 20)

    GHA->>PB: getProjectItems() via gh project item-list
    PB-->>GHA: items[]
    GHA->>GHA: find card where articlePath == ARTICLE
    alt card found
        GHA->>PB: updateCardStatus(card.id, 'published')
        PB-->>GHA: ✓ Card moved to Published
    else card not found
        GHA->>GHA: log warning, continue
    end
Loading

Fix All in Claude Code

Prompt To Fix All With AI
This is a comment left during a code review.
Path: .github/workflows/blog-publish.yml
Line: 122-132

Comment:
**`node -e` ignores `"type": "module"` — ESM import will fail**

The inline script uses `import` (ESM) syntax, but `node -e` always runs in CommonJS mode regardless of the `"type": "module"` setting in `blog/pipeline/package.json`. Node.js only applies that file to disk-based `.js` files, not to `--eval`/`-e` input. At runtime this will throw:

```
SyntaxError: Cannot use import statement in an interactive module
```

The fix is to pass `--input-type=module` so Node treats the inline script as ESM:

```suggestion
          node --input-type=module -e "
            import { getProjectItems, updateCardStatus } from './project.js';
            const items = getProjectItems();
            const card = items.find(i => i.articlePath === process.env.ARTICLE);
            if (card) {
              updateCardStatus(card.id, 'published');
              console.log('Updated card to Published:', card.title);
            } else {
              console.log('No project card found for article:', process.env.ARTICLE);
            }
          "
```

Alternatively, write a small `update-status.js` script and invoke it with `node update-status.js` to avoid the flag entirely.

How can I resolve this? If you propose a fix, please make it concise.

---

This is a comment left during a code review.
Path: .github/workflows/blog-publish.yml
Line: 110-113

Comment:
**Missing `npm install` step**

`actions/setup-node@v4` installs the Node.js runtime but does not install npm dependencies. While `project.js` itself only uses Node built-ins (`child_process`) and the local `config.js`, the `package.json` in `blog/pipeline` lists `google-trends-api` and `rss-parser` as dependencies. If any transitive import in the module graph (e.g. a future change to `config.js`) pulls in an npm package, this step will silently break.

Consider adding an explicit install step so the environment is fully reproduced:

```yaml
      - uses: actions/setup-node@v4
        if: steps.publish.outputs.slug != ''
        with:
          node-version: 20

      - name: Install pipeline dependencies
        if: steps.publish.outputs.slug != ''
        run: npm ci --prefix blog/pipeline
```

How can I resolve this? If you propose a fix, please make it concise.

Last reviewed commit: 7c6ba54

Comment on lines +122 to +132
node -e "
import { getProjectItems, updateCardStatus } from './project.js';
const items = getProjectItems();
const card = items.find(i => i.articlePath === process.env.ARTICLE);
if (card) {
updateCardStatus(card.id, 'published');
console.log('Updated card to Published:', card.title);
} else {
console.log('No project card found for article:', process.env.ARTICLE);
}
"
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

node -e ignores "type": "module" — ESM import will fail

The inline script uses import (ESM) syntax, but node -e always runs in CommonJS mode regardless of the "type": "module" setting in blog/pipeline/package.json. Node.js only applies that file to disk-based .js files, not to --eval/-e input. At runtime this will throw:

SyntaxError: Cannot use import statement in an interactive module

The fix is to pass --input-type=module so Node treats the inline script as ESM:

Suggested change
node -e "
import { getProjectItems, updateCardStatus } from './project.js';
const items = getProjectItems();
const card = items.find(i => i.articlePath === process.env.ARTICLE);
if (card) {
updateCardStatus(card.id, 'published');
console.log('Updated card to Published:', card.title);
} else {
console.log('No project card found for article:', process.env.ARTICLE);
}
"
node --input-type=module -e "
import { getProjectItems, updateCardStatus } from './project.js';
const items = getProjectItems();
const card = items.find(i => i.articlePath === process.env.ARTICLE);
if (card) {
updateCardStatus(card.id, 'published');
console.log('Updated card to Published:', card.title);
} else {
console.log('No project card found for article:', process.env.ARTICLE);
}
"

Alternatively, write a small update-status.js script and invoke it with node update-status.js to avoid the flag entirely.

Prompt To Fix With AI
This is a comment left during a code review.
Path: .github/workflows/blog-publish.yml
Line: 122-132

Comment:
**`node -e` ignores `"type": "module"` — ESM import will fail**

The inline script uses `import` (ESM) syntax, but `node -e` always runs in CommonJS mode regardless of the `"type": "module"` setting in `blog/pipeline/package.json`. Node.js only applies that file to disk-based `.js` files, not to `--eval`/`-e` input. At runtime this will throw:

```
SyntaxError: Cannot use import statement in an interactive module
```

The fix is to pass `--input-type=module` so Node treats the inline script as ESM:

```suggestion
          node --input-type=module -e "
            import { getProjectItems, updateCardStatus } from './project.js';
            const items = getProjectItems();
            const card = items.find(i => i.articlePath === process.env.ARTICLE);
            if (card) {
              updateCardStatus(card.id, 'published');
              console.log('Updated card to Published:', card.title);
            } else {
              console.log('No project card found for article:', process.env.ARTICLE);
            }
          "
```

Alternatively, write a small `update-status.js` script and invoke it with `node update-status.js` to avoid the flag entirely.

How can I resolve this? If you propose a fix, please make it concise.

Fix in Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant