Compare commits
3
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
735ef6b3f2 | ||
|
|
eaf53bc2d2 | ||
|
|
3e148c6745 |
@@ -1,33 +1,33 @@
|
||||
class DingtalkWorkspaceCliBeta < Formula
|
||||
desc "Automate DingTalk workspace tasks from the terminal (beta channel)"
|
||||
homepage "https://github.com/DingTalk-Real-AI/dingtalk-workspace-cli"
|
||||
version "1.0.54-beta.2"
|
||||
version "1.0.55-beta.2"
|
||||
license "Apache-2.0"
|
||||
keg_only "it is the beta channel and conflicts with dingtalk-workspace-cli"
|
||||
|
||||
on_macos do
|
||||
if Hardware::CPU.arm?
|
||||
url "https://github.com/DingTalk-Real-AI/dingtalk-workspace-cli/releases/download/v1.0.54-beta.2/dws-darwin-arm64.tar.gz"
|
||||
sha256 "46b57bed1f6e9f7ba007d8a86a6f5eb280fdeb557fc9bb5946f14f9b1f8f0c9f"
|
||||
url "https://github.com/DingTalk-Real-AI/dingtalk-workspace-cli/releases/download/v1.0.55-beta.2/dws-darwin-arm64.tar.gz"
|
||||
sha256 "fd23353c473419ce8cfaf316e7afff757cc4606291f4ad41a62c6f5625f45c8f"
|
||||
else
|
||||
url "https://github.com/DingTalk-Real-AI/dingtalk-workspace-cli/releases/download/v1.0.54-beta.2/dws-darwin-amd64.tar.gz"
|
||||
sha256 "1b7fd08e64b1c86bbcee217604ffe07e0e8f1b3b5c4de518534386972bcf0f9b"
|
||||
url "https://github.com/DingTalk-Real-AI/dingtalk-workspace-cli/releases/download/v1.0.55-beta.2/dws-darwin-amd64.tar.gz"
|
||||
sha256 "0b429950a6449736338b504386d8009a4f2cdb0668f64f72a61cd503a25df193"
|
||||
end
|
||||
end
|
||||
|
||||
on_linux do
|
||||
if Hardware::CPU.arm?
|
||||
url "https://github.com/DingTalk-Real-AI/dingtalk-workspace-cli/releases/download/v1.0.54-beta.2/dws-linux-arm64.tar.gz"
|
||||
sha256 "108d3861ef606519f9934530d29654eab55a73607d1ee6775461f98ef5a6acd4"
|
||||
url "https://github.com/DingTalk-Real-AI/dingtalk-workspace-cli/releases/download/v1.0.55-beta.2/dws-linux-arm64.tar.gz"
|
||||
sha256 "c213a22d6187a8f68596b9f25d6277f5fd58cea5120f5b7caeef011fb41f1104"
|
||||
else
|
||||
url "https://github.com/DingTalk-Real-AI/dingtalk-workspace-cli/releases/download/v1.0.54-beta.2/dws-linux-amd64.tar.gz"
|
||||
sha256 "6cb96ee09419bbbcc1eb336218ac2aa1d9ca0ed5cbd5a80c79bc20e1e1f03ff7"
|
||||
url "https://github.com/DingTalk-Real-AI/dingtalk-workspace-cli/releases/download/v1.0.55-beta.2/dws-linux-amd64.tar.gz"
|
||||
sha256 "4e041ba7b1d8038fa34deba3a3f78af8377f4361131d8bfdb1f1913e5f9454dc"
|
||||
end
|
||||
end
|
||||
|
||||
resource "skills" do
|
||||
url "https://github.com/DingTalk-Real-AI/dingtalk-workspace-cli/releases/download/v1.0.54-beta.2/dws-skills.zip"
|
||||
sha256 "572b93f04a10268d185ad1f8e70e0d412949ae056be8494a9949387076fd14bc"
|
||||
url "https://github.com/DingTalk-Real-AI/dingtalk-workspace-cli/releases/download/v1.0.55-beta.2/dws-skills.zip"
|
||||
sha256 "1cec445c73b9ff569ca002b6548f4ee8383712447bc4cebd7701c6065774524a"
|
||||
end
|
||||
|
||||
def install
|
||||
|
||||
@@ -27,6 +27,10 @@ import (
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
// markdownStatUpload stats the prepared upload file. Tests override it to
|
||||
// deterministically simulate the file disappearing between write and stat.
|
||||
var markdownStatUpload = os.Stat
|
||||
|
||||
func newMarkdownCommand() *cobra.Command {
|
||||
root := &cobra.Command{
|
||||
Use: "markdown",
|
||||
@@ -257,7 +261,7 @@ func runMarkdownCreate(cmd *cobra.Command, _ []string) error {
|
||||
if !hasMarkdownExtension(nameFlag) {
|
||||
return fmt.Errorf("--name 必须以 .md 结尾,当前: %s", nameFlag)
|
||||
}
|
||||
info, err := os.Stat(uploadPath)
|
||||
info, err := markdownStatUpload(uploadPath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("读取上传文件失败: %w", err)
|
||||
}
|
||||
@@ -421,7 +425,7 @@ func runMarkdownOverwrite(cmd *cobra.Command, _ []string) error {
|
||||
if !hasMarkdownExtension(nameFlag) {
|
||||
return fmt.Errorf("--name 必须以 .md 结尾,当前: %s", nameFlag)
|
||||
}
|
||||
info, err := os.Stat(uploadPath)
|
||||
info, err := markdownStatUpload(uploadPath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("读取上传文件失败: %w", err)
|
||||
}
|
||||
@@ -563,7 +567,7 @@ func runMarkdownPatch(cmd *cobra.Command, _ []string) error {
|
||||
if err := os.WriteFile(uploadPath, []byte(newContent), 0o600); err != nil {
|
||||
return fmt.Errorf("写入临时文件失败: %w", err)
|
||||
}
|
||||
info, err := os.Stat(uploadPath)
|
||||
info, err := markdownStatUpload(uploadPath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("读取临时文件失败: %w", err)
|
||||
}
|
||||
|
||||
@@ -12,10 +12,8 @@ import (
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
@@ -26,47 +24,20 @@ func (markdownCIFailingReader) Read([]byte) (int, error) {
|
||||
return 0, errors.New("forced read failure")
|
||||
}
|
||||
|
||||
func startMarkdownCITempFileRemover(t *testing.T, root, dirPrefix, fileName string) <-chan error {
|
||||
// installMarkdownStatUploadRemover overrides the markdownStatUpload seam so
|
||||
// the prepared upload file is deterministically removed before stat runs,
|
||||
// simulating the file disappearing between write and stat without racing a
|
||||
// background goroutine.
|
||||
func installMarkdownStatUploadRemover(t *testing.T) {
|
||||
t.Helper()
|
||||
result := make(chan error, 1)
|
||||
go func() {
|
||||
deadline := time.Now().Add(10 * time.Second)
|
||||
for time.Now().Before(deadline) {
|
||||
entries, err := os.ReadDir(root)
|
||||
if err != nil {
|
||||
result <- err
|
||||
return
|
||||
}
|
||||
for _, entry := range entries {
|
||||
if !entry.IsDir() || !strings.HasPrefix(entry.Name(), dirPrefix) {
|
||||
continue
|
||||
}
|
||||
target := filepath.Join(root, entry.Name(), fileName)
|
||||
if err := os.Remove(target); err == nil {
|
||||
result <- nil
|
||||
return
|
||||
} else if !os.IsNotExist(err) {
|
||||
result <- err
|
||||
return
|
||||
}
|
||||
}
|
||||
runtime.Gosched()
|
||||
original := markdownStatUpload
|
||||
markdownStatUpload = func(name string) (os.FileInfo, error) {
|
||||
if err := os.Remove(name); err != nil && !os.IsNotExist(err) {
|
||||
t.Errorf("removing upload file %q: %v", name, err)
|
||||
}
|
||||
result <- fmt.Errorf("timed out waiting for %s/%s", dirPrefix, fileName)
|
||||
}()
|
||||
return result
|
||||
}
|
||||
|
||||
func waitMarkdownCIRemover(t *testing.T, result <-chan error) {
|
||||
t.Helper()
|
||||
select {
|
||||
case err := <-result:
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
case <-time.After(12 * time.Second):
|
||||
t.Fatal("timed out waiting for temporary-file remover")
|
||||
return os.Stat(name)
|
||||
}
|
||||
t.Cleanup(func() { markdownStatUpload = original })
|
||||
}
|
||||
|
||||
func TestMarkdownCICoverageFetchAndOutputPaths(t *testing.T) {
|
||||
@@ -189,13 +160,9 @@ func TestMarkdownCICoverageCreateEdges(t *testing.T) {
|
||||
|
||||
t.Run("temporary file disappears before stat", func(t *testing.T) {
|
||||
installMarkdownDriveDeps(t, &markdownDriveCaller{format: "json"})
|
||||
tempRoot := t.TempDir()
|
||||
t.Setenv("TMPDIR", tempRoot)
|
||||
removed := startMarkdownCITempFileRemover(t, tempRoot, "dws-markdown-create-", "a.md")
|
||||
content := strings.Repeat("x", 16<<20)
|
||||
installMarkdownStatUploadRemover(t)
|
||||
err := executeMarkdownDriveCommand(t, newMarkdownCommand(), nil,
|
||||
"markdown", "create", "--name", "a.md", "--content", content)
|
||||
waitMarkdownCIRemover(t, removed)
|
||||
"markdown", "create", "--name", "a.md", "--content", "body")
|
||||
if err == nil || !strings.Contains(err.Error(), "读取上传文件失败") {
|
||||
t.Fatalf("error = %v", err)
|
||||
}
|
||||
@@ -270,14 +237,10 @@ func TestMarkdownCICoverageOverwriteEdges(t *testing.T) {
|
||||
|
||||
t.Run("temporary file disappears before stat", func(t *testing.T) {
|
||||
installMarkdownDriveDeps(t, &markdownDriveCaller{format: "json"})
|
||||
tempRoot := t.TempDir()
|
||||
t.Setenv("TMPDIR", tempRoot)
|
||||
removed := startMarkdownCITempFileRemover(t, tempRoot, "dws-markdown-overwrite-", "a.md")
|
||||
content := strings.Repeat("x", 16<<20)
|
||||
installMarkdownStatUploadRemover(t)
|
||||
err := executeMarkdownDriveCommand(t, newMarkdownCommand(), nil,
|
||||
"markdown", "overwrite", "--node", "node-1", "--space-id", "space-1",
|
||||
"--name", "a.md", "--content", content)
|
||||
waitMarkdownCIRemover(t, removed)
|
||||
"--name", "a.md", "--content", "body")
|
||||
if err == nil || !strings.Contains(err.Error(), "读取上传文件失败") {
|
||||
t.Fatalf("error = %v", err)
|
||||
}
|
||||
@@ -451,14 +414,10 @@ func TestMarkdownCICoveragePatchEdges(t *testing.T) {
|
||||
}
|
||||
installMarkdownDriveDeps(t, caller)
|
||||
installMarkdownHTTPGet(t, "old")
|
||||
tempRoot := t.TempDir()
|
||||
t.Setenv("TMPDIR", tempRoot)
|
||||
removed := startMarkdownCITempFileRemover(t, tempRoot, "dws-markdown-patch-", "current.md")
|
||||
replacement := strings.Repeat("x", 16<<20)
|
||||
installMarkdownStatUploadRemover(t)
|
||||
err := executeMarkdownDriveCommand(t, newMarkdownCommand(), nil,
|
||||
"markdown", "patch", "--node", "node-1", "--space-id", "space-1",
|
||||
"--pattern", "old", "--content", replacement, "--yes")
|
||||
waitMarkdownCIRemover(t, removed)
|
||||
"--pattern", "old", "--content", "new", "--yes")
|
||||
if err == nil || !strings.Contains(err.Error(), "读取临时文件失败") {
|
||||
t.Fatalf("error = %v", err)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user