Files
dingtalk-workspace-cli/.github/workflows/ci.yml
T
修雨 e3cedc8f67 feat(release): add guarded prerelease and stable pipeline (#54)
* feat(release): add guarded prerelease and stable pipeline

* feat(release): add guided dws-release entry

(cherry picked from commit f7fa7b78f325f3574f0487862fc3e65bba5cdc96)
2026-07-13 15:34:21 +08:00

351 lines
9.8 KiB
YAML

name: CI
on:
push:
branches:
- main
pull_request:
permissions:
contents: read
jobs:
lint:
name: Lint
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- name: Check out repository
uses: actions/checkout@v4
- name: Set up Go
uses: actions/setup-go@v5
with:
go-version-file: go.mod
- name: Format Check
run: |
unformatted="$(find cmd internal test -name '*.go' -print0 | xargs -0r gofmt -l)"
test -z "$unformatted" || (printf '%s\n' "$unformatted" && exit 1)
- name: Go Vet
run: go vet ./...
# golangci-lint temporarily disabled: v1.64.8 built with Go 1.24 is incompatible with Go 1.25
# - name: golangci-lint
# uses: golangci/golangci-lint-action@v6
# with:
# version: v1.64.8
# args: ./...
test:
name: Test
runs-on: ubuntu-latest
timeout-minutes: 20
steps:
- name: Check out repository
uses: actions/checkout@v4
- name: Set up Go
uses: actions/setup-go@v5
with:
go-version-file: go.mod
- name: Install archive tooling
run: sudo apt-get update && sudo apt-get install -y zip unzip
- name: Build
run: make build
- name: Test with Race Detection
run: |
go test -v -race -count=1 -timeout=5m \
./cmd/... \
./internal/... \
./pkg/... \
./test/unit/...
go test -v -count=1 -timeout=5m \
./test/cli/...
- name: Test engineering scripts
run: go test -v -count=1 -timeout=5m ./test/scripts/...
test-darwin:
name: Test (macOS auth/keychain)
runs-on: macos-latest
timeout-minutes: 15
steps:
- name: Check out repository
uses: actions/checkout@v4
- name: Set up Go
uses: actions/setup-go@v5
with:
go-version-file: go.mod
- name: Test macOS auth and Keychain paths with Race Detection
run: go test -v -race -count=1 -timeout=10m ./internal/keychain ./internal/auth ./internal/app
test-windows:
name: Test (Windows)
runs-on: windows-latest
timeout-minutes: 15
steps:
- name: Check out repository
uses: actions/checkout@v4
- name: Set up Go
uses: actions/setup-go@v5
with:
go-version-file: go.mod
- name: Build Windows CLI
run: go build -o dws.exe ./cmd
- name: Test Windows auth and DPAPI paths
run: |
go test -v -count=1 -timeout=10m ./internal/keychain ./internal/auth
go test -v -count=1 -timeout=5m ./internal/app -run '^TestAuth(MigrateKeychain|StatusDiagnosticReportsCiphertextKeyMismatch)'
coverage:
name: Coverage
runs-on: ubuntu-latest
timeout-minutes: 20
steps:
- name: Check out repository
uses: actions/checkout@v4
- name: Set up Go
uses: actions/setup-go@v5
with:
go-version-file: go.mod
- name: Install archive tooling
run: sudo apt-get update && sudo apt-get install -y zip unzip
- name: Build
run: make build
- name: Run tests with coverage
run: |
go test -coverprofile=coverage.txt -covermode=atomic ./cmd/... ./internal/...
go tool cover -func=coverage.txt
- name: Generate coverage report
run: go tool cover -html=coverage.txt -o coverage.html
- name: Upload coverage artifact
uses: actions/upload-artifact@v4
with:
name: coverage-report
path: |
coverage.txt
coverage.html
policy:
name: Policy Check
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- name: Check out repository
uses: actions/checkout@v4
- name: Set up Go
uses: actions/setup-go@v5
with:
go-version-file: go.mod
- name: Build
run: make build
- name: Policy
run: make policy
- name: Generated Drift
run: ./scripts/policy/check-generated-drift.sh
edition-tests:
name: Edition Contract Tests
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- name: Check out repository
uses: actions/checkout@v4
- name: Set up Go
uses: actions/setup-go@v5
with:
go-version-file: go.mod
- name: Run edition contract tests
run: go test -v -count=1 ./pkg/editiontest/...
code-check:
name: Code Check
needs: [lint, test, test-darwin, test-windows, coverage, policy, edition-tests]
if: ${{ always() }}
runs-on: ubuntu-latest
timeout-minutes: 5
permissions: {}
steps:
- name: Verify code checks
env:
LINT_RESULT: ${{ needs.lint.result }}
TEST_RESULT: ${{ needs.test.result }}
TEST_DARWIN_RESULT: ${{ needs.test-darwin.result }}
TEST_WINDOWS_RESULT: ${{ needs.test-windows.result }}
COVERAGE_RESULT: ${{ needs.coverage.result }}
POLICY_RESULT: ${{ needs.policy.result }}
EDITION_TESTS_RESULT: ${{ needs.edition-tests.result }}
run: |
set -eu
failed=0
for check in \
"Lint:$LINT_RESULT" \
"Test:$TEST_RESULT" \
"Test (macOS auth/keychain):$TEST_DARWIN_RESULT" \
"Test (Windows):$TEST_WINDOWS_RESULT" \
"Coverage:$COVERAGE_RESULT" \
"Policy Check:$POLICY_RESULT" \
"Edition Contract Tests:$EDITION_TESTS_RESULT"
do
name="${check%%:*}"
result="${check#*:}"
printf '%s: %s\n' "$name" "$result"
if [ "$result" != "success" ]; then
failed=1
fi
done
test "$failed" -eq 0
command-compatibility:
name: Command Compatibility
runs-on: ubuntu-latest
timeout-minutes: 10
permissions:
actions: read
contents: read
steps:
- name: Check out repository
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Fetch official release tags
run: |
git fetch --force --no-tags \
https://github.com/DingTalk-Real-AI/dingtalk-workspace-cli.git \
'+refs/tags/v*:refs/tags/v*'
- name: Set up Go
uses: actions/setup-go@v5
with:
go-version-file: go.mod
- name: Check command compatibility
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
PR_BASE_SHA: ${{ github.event.pull_request.base.sha }}
PUSH_BEFORE_SHA: ${{ github.event.before }}
run: |
set -eu
base_ref="$PUSH_BEFORE_SHA"
if [ "$GITHUB_EVENT_NAME" = "pull_request" ]; then
base_ref="$PR_BASE_SHA"
fi
stable_ref="$(git tag --merged HEAD --list 'v*' --sort=-version:refname | awk '/^v[0-9]+\.[0-9]+\.[0-9]+$/ { print; exit }')"
test -n "$base_ref"
test -n "$stable_ref"
stable_commit="$(git rev-parse "$stable_ref^{commit}")"
./scripts/release/verify-delivered-stable.sh "$stable_ref" "$stable_commit"
./scripts/policy/check-command-compatibility.sh \
--base-ref "$base_ref" \
--stable-ref "$stable_ref"
cli-smoke:
name: CLI Smoke
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- name: Check out repository
uses: actions/checkout@v4
- name: Set up Go
uses: actions/setup-go@v5
with:
go-version-file: go.mod
- name: Run CLI smoke tests
run: go test -count=1 -timeout=5m ./test/smoke/...
mock-mcp-smoke:
name: Mock MCP Smoke
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- name: Check out repository
uses: actions/checkout@v4
- name: Set up Go
uses: actions/setup-go@v5
with:
go-version-file: go.mod
- name: Run Mock MCP smoke tests
run: go test -count=1 -timeout=5m ./test/mock_mcp/...
ci-gate:
name: CI Gate
needs: [code-check, command-compatibility, cli-smoke, mock-mcp-smoke]
if: ${{ always() }}
runs-on: ubuntu-latest
timeout-minutes: 5
permissions: {}
steps:
- name: Verify required checks
env:
CODE_CHECK_RESULT: ${{ needs.code-check.result }}
COMMAND_COMPATIBILITY_RESULT: ${{ needs.command-compatibility.result }}
CLI_SMOKE_RESULT: ${{ needs.cli-smoke.result }}
MOCK_MCP_SMOKE_RESULT: ${{ needs.mock-mcp-smoke.result }}
run: |
set -eu
failed=0
for check in \
"Code Check:$CODE_CHECK_RESULT" \
"Command Compatibility:$COMMAND_COMPATIBILITY_RESULT" \
"CLI Smoke:$CLI_SMOKE_RESULT" \
"Mock MCP Smoke:$MOCK_MCP_SMOKE_RESULT"
do
name="${check%%:*}"
result="${check#*:}"
printf '%s: %s\n' "$name" "$result"
if [ "$result" != "success" ]; then
failed=1
fi
done
test "$failed" -eq 0
notify-downstream:
name: Notify Wukong Overlay
needs: [ci-gate]
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/main' && github.event_name == 'push'
permissions: {}
steps:
- name: Trigger downstream CI
run: |
# Trigger internal GitLab CI pipeline via webhook.
# WUKONG_TRIGGER_TOKEN is a repository secret.
if [ -n "${{ secrets.WUKONG_TRIGGER_TOKEN }}" ]; then
curl --fail --silent --show-error \
-X POST \
-F "token=${{ secrets.WUKONG_TRIGGER_TOKEN }}" \
-F "ref=main" \
-F "variables[UPSTREAM_SHA]=${{ github.sha }}" \
"${{ secrets.WUKONG_TRIGGER_URL }}"
echo "Downstream CI triggered."
else
echo "No WUKONG_TRIGGER_TOKEN configured, skipping downstream notification."
fi