Skip to content

fix(ci): tolerate npm registry propagation delay - #2174

Merged
syzsunshine219 merged 1 commit into
MemTensor:mainfrom
syzsunshine219:codex/fix-npm-publish-verification
Jul 27, 2026
Merged

fix(ci): tolerate npm registry propagation delay#2174
syzsunshine219 merged 1 commit into
MemTensor:mainfrom
syzsunshine219:codex/fix-npm-publish-verification

Conversation

@syzsunshine219

Copy link
Copy Markdown
Collaborator

Description

Fixes false failures in the MemOS local-plugin npm release workflow when the npm Registry has not propagated a newly published version to npm view yet.

The publish logic is extracted into .github/scripts/publish-local-plugin.sh so it can be tested independently. The helper now:

  • keeps the immediate pre-publish lookup for duplicate detection;
  • waits for post-publish visibility with bounded, capped backoff;
  • continues Tag, GitHub Release, and release PR creation when npm publish succeeded but registry visibility is still delayed;
  • still fails after three publish failures when the requested version remains absent.

No new dependencies are required.

Related Issue (Required): N/A - follow-up to failed Action #35

Type of change

  • Bug fix (non-breaking change which fixes an issue)

How Has This Been Tested?

  • Unit Test
  • Test Script Or Test Steps (please provide)

Commands run:

node --test .github/scripts/publish-local-plugin.test.mjs .github/scripts/draft-local-plugin-release-notes.test.mjs
bash -n .github/scripts/publish-local-plugin.sh
shellcheck .github/scripts/publish-local-plugin.sh
actionlint .github/workflows/memos-local-plugin-publish.yml .github/workflows/memos-local-plugin-post-merge-dry-run.yml
git diff --check

The Node test suite passed 21/21 tests, including these regression scenarios:

  • two post-publish 404 responses followed by successful visibility;
  • successful publish with continued registry invisibility;
  • failed publish with the requested version remaining absent.

make format could not run locally because Poetry is not installed in this checkout; this PR does not change Python files.

Checklist

  • I have performed a self-review of my own code | 我已自行检查了自己的代码
  • I have commented my code in hard-to-understand areas | 我已在难以理解的地方对代码进行了注释
  • I have added tests that prove my fix is effective or that my feature works | 我已添加测试以证明我的修复有效或功能正常
  • I have created related documentation issue/PR in MemOS-Docs (if applicable) | N/A: no documentation behavior changed
  • I have linked the issue to this PR (if applicable) | N/A: linked the failed release run above
  • I have mentioned the person who will review this PR | @hijzy @whipser030

Reviewer Checklist

  • closes #xxxx (Replace xxxx with the GitHub issue number)
  • Made sure Checks passed
  • Tests have been provided

@Memtensor-AI Memtensor-AI added area:core MOS 编排层 / 框架底座 / 跨模块问题 status:in-progress Someone or AI is working on it | 人工或 AI 正在处理 labels Jul 27, 2026
@Memtensor-AI
Memtensor-AI requested a review from WeiminLee July 27, 2026 07:10
@Memtensor-AI

Copy link
Copy Markdown
Collaborator

🤖 Open Code Review

Target: PR #2174
Task: 42a67b9a6091d7ba
Base: main
Head: codex/fix-npm-publish-verification

🔍 OpenCodeReview found 5 issue(s) in this PR.

⚠️ 1 warning(s) occurred during review.


1. .github/scripts/publish-local-plugin.test.mjs (L73-L102)

The temporary directory created by mkdtempSync is cleaned up unconditionally at the end of runScenario, but there is no try/finally guard around the body. If any code between mkdtempSync and rmSync throws an uncaught exception (e.g., a future addition that can throw, or an unexpected spawnSync failure surface), the temp directory will be leaked on disk for the lifetime of the CI runner.

Suggested fix: wrap the body in a try/finally block so cleanup is guaranteed regardless of exceptions.

💡 Suggested Change

Before:

  const result = spawnSync("bash", [publishScript], {
    cwd: fixtureDirectory,
    encoding: "utf8",
    env: {
      ...process.env,
      PATH: `${binDirectory}:${process.env.PATH}`,
      RUNNER_TEMP: fixtureDirectory,
      PACKAGE_NAME: "@memtensor/memos-local-plugin",
      RELEASE_VERSION: "2.0.12",
      RELEASE_TAG: "memos-local-plugin-v2.0.12",
      NPM_DIST_TAG: "latest",
      RECOVER_EXISTING_NPM_RELEASE: "false",
      DOC_AGENT_RELEASE_FAILURE_URL: "",
      DOC_AGENT_RELEASE_NOTES_DRAFT_TOKEN: "",
      NPM_MOCK_SCENARIO: scenario,
      NPM_MOCK_STATE_DIR: stateDirectory,
      NPM_VISIBILITY_ATTEMPTS: "3",
      NPM_AMBIGUOUS_VISIBILITY_ATTEMPTS: "2",
      NPM_VISIBILITY_DELAY_SECONDS: "0",
      ...overrides,
    },
  });

  const outcome = {
    ...result,
    viewCount: readCounter(stateDirectory, "view"),
    publishCount: readCounter(stateDirectory, "publish"),
  };
  rmSync(fixtureDirectory, { recursive: true, force: true });
  return outcome;

After:

  try {
    const result = spawnSync("bash", [publishScript], {
      cwd: fixtureDirectory,
      encoding: "utf8",
      env: {
        ...process.env,
        PATH: `${binDirectory}:${process.env.PATH}`,
        RUNNER_TEMP: fixtureDirectory,
        PACKAGE_NAME: "@memtensor/memos-local-plugin",
        RELEASE_VERSION: "2.0.12",
        RELEASE_TAG: "memos-local-plugin-v2.0.12",
        NPM_DIST_TAG: "latest",
        RECOVER_EXISTING_NPM_RELEASE: "false",
        DOC_AGENT_RELEASE_FAILURE_URL: "",
        DOC_AGENT_RELEASE_NOTES_DRAFT_TOKEN: "",
        NPM_MOCK_SCENARIO: scenario,
        NPM_MOCK_STATE_DIR: stateDirectory,
        NPM_VISIBILITY_ATTEMPTS: "3",
        NPM_AMBIGUOUS_VISIBILITY_ATTEMPTS: "2",
        NPM_VISIBILITY_DELAY_SECONDS: "0",
        ...overrides,
      },
    });

    return {
      ...result,
      viewCount: readCounter(stateDirectory, "view"),
      publishCount: readCounter(stateDirectory, "publish"),
    };
  } finally {
    rmSync(fixtureDirectory, { recursive: true, force: true });
  }

2. .github/workflows/memos-local-plugin-publish.yml (L136-L138)

The "Test npm publish helper" step uses working-directory: . (workspace root) which overrides the global defaults: run: working-directory: apps/memos-local-plugin. This is intentional and correct for the path node --test .github/scripts/publish-local-plugin.test.mjs. However, the step does not declare a shell: key. On GitHub-hosted Linux runners this defaults to bash -e {0}, which works fine, but it is inconsistent with all other run: steps in the build-prebuilds job that explicitly set shell: bash. For robustness across runner environments and consistency within the file, add shell: bash.

💡 Suggested Change

Before:

      - name: Test npm publish helper
        working-directory: .
        run: node --test .github/scripts/publish-local-plugin.test.mjs

After:

      - name: Test npm publish helper
        working-directory: .
        shell: bash
        run: node --test .github/scripts/publish-local-plugin.test.mjs

3. .github/scripts/publish-local-plugin.sh (L98-L99)

All output from git ls-remote is discarded (>/dev/null 2>&1). If the command fails with a non-zero, non-2 status (e.g., authentication error, network timeout), the script retries silently and eventually calls exit "${status}" with no diagnostic information in the CI log.

By contrast, npm_version_exists captures output to ${npm_view_log} and prints it via sed before exiting. remote_tag_exists should do the same — either redirect to a log file and print it before exiting, or at minimum redirect stderr to stdout so GitHub Actions captures it.

Suggested fix:

local git_log
git_log="${RUNNER_TEMP}/memos-local-plugin-git-ls-remote.log"
git ls-remote --exit-code --tags origin "refs/tags/${release_tag}" >"${git_log}" 2>&1
status=$?

Then before exit "${status}", add:

sed -n '1,40p' "${git_log}"

4. .github/scripts/publish-local-plugin.sh (L69-L70)

npm_version_exists can call exit (not return) when npm view fails with a non-404 error after 3 inner retries. When this happens inside wait_for_npm_version, the exit escapes the function and terminates the entire script — including the call at line 162 (wait_for_npm_version "${npm_visibility_attempts}") which runs after publish_accepted=true has already been set.

This means a transient npm registry error during post-publish visibility polling can abort the script with a non-zero exit code even when npm publish itself succeeded, potentially preventing tag and release creation for a package that was actually published.

Consider catching the exit from within wait_for_npm_version, or restructuring npm_version_exists so that a "cannot determine" case returns a distinct exit code (e.g., return 2) instead of calling exit, allowing callers to handle the ambiguous case.


5. .github/scripts/publish-local-plugin.sh (L98)

The test harness shims npm via a mock binary in binDirectory, but never shims git. This means the idempotent-rerun path — where npm_version_exists returns true and remote_tag_exists is called — is not exercised by any test. The real git ls-remote against origin would run (or fail) in the test environment, so the scenario where a version already exists on npm is effectively untested.

A mock git binary (or at least a git-ls-remote stub) should be added to binDirectory to enable testing of the idempotent-rerun, recovery-mode, and conflict-detection branches (lines 116–123 of the script).


🧹 Filtered 2 low-confidence OCR finding(s) before posting/fix-loop (existing_code_mismatch: 2).

Generated by cloud-assistant via Open Code Review.

@Memtensor-AI

Copy link
Copy Markdown
Collaborator

✅ Automated Test Results: PASSED

All tests passed (1/1 executed). memos_github_open_source/smoke: 1/1. Duration: 1s

Branch: codex/fix-npm-publish-verification

@syzsunshine219
syzsunshine219 merged commit 344cab7 into MemTensor:main Jul 27, 2026
19 checks passed
@Memtensor-AI Memtensor-AI added status:ready Ready for implementation; waiting for assignee or AI dispatch | 可进入实现,等待认领或派发 and removed status:in-progress Someone or AI is working on it | 人工或 AI 正在处理 labels Jul 27, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:core MOS 编排层 / 框架底座 / 跨模块问题 status:ready Ready for implementation; waiting for assignee or AI dispatch | 可进入实现,等待认领或派发

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants