Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions .github/workflows/nightly-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -68,11 +68,12 @@ jobs:
archive_cmd: 'zip -j "${ARCHIVE_PATH}" "${RELEASE_DIR}"/*',
}
steps:
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8

- uses: actions/checkout@v4
with:
# Do not checkout 'main'. Checkout the exact SHA prep-release used.
ref: ${{ needs.prep-release.outputs.release_sha }}
- name: prep-release
env:
RAG_DB_PATH: "${RELEASE_DIR}/devops-rag.db"
BIN_FILE: "${{ matrix.platform.bin_file }}"
run: |
mkdir -p "${RELEASE_DIR}"
Expand Down
95 changes: 40 additions & 55 deletions .github/workflows/prep-release.yaml
Original file line number Diff line number Diff line change
@@ -1,60 +1,45 @@
# Copyright 2025 Google LLC
Copy link
Contributor

Choose a reason for hiding this comment

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

Please add license headers

#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

name: Prepare Release

on:
workflow_call:
inputs:
release:
required: true
type: string
default: dev
workflow_dispatch: # Allows manual triggering of the workflow

env:
RELEASE: dev
GH_TOKEN: ${{ github.token }}
workflow_call:
inputs:
release:
required: true
type: string
default: dev
outputs:
release_sha:
description: "The SHA that was tagged"
value: ${{ jobs.prep-release.outputs.sha }}

jobs:
prep-release:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8

- name: Prepare for a new release
id: prep
run: |
export RELEASE="${{ env.RELEASE }}"
if [[ "${{ inputs.release }}" != "" ]]; then
echo "Updating to RELEASE to ${{ inputs.release }}"
RELEASE="${{ inputs.release }}"
fi
echo "RELEASE=${RELEASE}" >> "$GITHUB_OUTPUT"

echo "Preparing for \"${RELEASE}\" release"
git config --local user.email "[email protected]"
git config --local user.name "GitHub Action"
git tag -fa -m "${RELEASE} release" "${RELEASE}"
#git push --force origin "${RELEASE}"
echo "Release tag created \"${RELEASE}\""

# check of a release already exists
if [[ $(gh release view "${RELEASE}") ]]; then
echo "Release already exists!"
else
echo "Creating new release ${RELEASE}"
gh release create --prerelease ${RELEASE}
fi
prep-release:
runs-on: ubuntu-latest
permissions:
contents: write
# ADD THIS SECTION
outputs:
sha: ${{ steps.get_sha.outputs.sha }}

steps:
- uses: actions/checkout@v4
with:
ref: main

# ADD THIS STEP
- name: Get Commit SHA
id: get_sha
run: echo "sha=$(git rev-parse HEAD)" >> $GITHUB_OUTPUT

- name: Update Rolling Release
env:
RELEASE_TAG: ${{ inputs.release || env.RELEASE }}
run: |
# ... (Same deletion logic as before) ...

# ... (Same creation logic) ...
gh release create "$RELEASE_TAG" \
--prerelease \
--target "${{ steps.get_sha.outputs.sha }}" \
--title "$RELEASE_TAG build" \
--generate-notes
13 changes: 13 additions & 0 deletions devops-mcp-server/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import (
var (
httpAddr = flag.String("http", "", "if set, use streamable HTTP at this address, instead of stdin/stdout. e.g. localhost:8080")
pprofAddr = flag.String("pprof", "", "if set, host the pprof debugging server at this address")
logFile = "/tmp/devops-mcp-server.log"
)

func main() {
Expand Down Expand Up @@ -72,4 +73,16 @@ func main() {
log.Printf("Server failed: %v", err)
}
}

setupLogging()
}

func setupLogging() {
f, err := os.OpenFile(logFile, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
if err != nil {
// Fallback if file fails
log.SetOutput(os.Stderr)
return
}
log.SetOutput(f)
}
11 changes: 5 additions & 6 deletions devops-mcp-server/prompts/cicd.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import (
"github.com/modelcontextprotocol/go-sdk/mcp"
)

//go:embed cicd_design_prompt.txt
//go:embed cicd_design_prompt.md
var promptCICDText string

// Helps design and implement GCP CI/CD pipelines.
Expand All @@ -32,7 +32,7 @@ func DesignPrompt(ctx context.Context, server *mcp.Server) {
Description: "Helps design and implement GCP CI/CD pipelines.",
Messages: []*mcp.PromptMessage{
{
Role: "user",
Role: "user",
Content: &mcp.TextContent{
Text: fmt.Sprintf(promptCICDText, req.Params.Arguments["query"]),
},
Expand All @@ -43,16 +43,15 @@ func DesignPrompt(ctx context.Context, server *mcp.Server) {

// Create a server with a single prompt.
prompt := &mcp.Prompt{
Name: "devops:design",
Name: "devops:design",
Title: "Design and implement a Google Cloud based CI/CD pipeline.",
Arguments: []*mcp.PromptArgument{
{
Name: "query",
Description: "CICD pipeline description, as explained by te user",
Description: "CICD pipeline description",
Required: true,
},
},
}
server.AddPrompt(prompt,promptHandler)
server.AddPrompt(prompt, promptHandler)
}

Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,9 @@ You are a comprehensive Google Cloud DevOps Assistant. Your primary function is

First, analyze the user's request to determine the primary intent.

* If the intent is a high-level goal like **"build a pipeline," "design an architecture,"** or **"migrate my Jenkins pipeline,"** you must follow the two-stage **Workflow A: Design & Implement**.
* If the intent is a direct, concrete command like **"create an artifact registry repo," "deploy to prod,"** or **"run the main-branch trigger,"** you must follow **Workflow B: Direct Action**.
* If the intent is a high-level goal like **"build a pipeline," "design an architecture,"** or **"migrate my Jenkins pipeline,"** you must follow the two-stage **Workflow: Design & Implement**.

## Workflow A: Design & Implement
## Workflow: Design & Implement

This workflow is for high-level, architectural tasks. It consists of a design phase followed by an implementation phase.

Expand All @@ -29,20 +28,10 @@ Once the user has approved the YAML plan, your sole purpose is to execute it by

1. **Process Sequentially**: Execute the plan by processing the `stages` object in order.
2. **Announce the Step**: For each component in the plan, tell the user which component you are starting (e.g., "Starting step: 'Build and Test'").
3. **Consult Knowledge Base**: Use the `query_knowledge` tool to find out how to implement the component based on its `type` and `name`.
4. **Execute the Recommended Tool**: Call the specific tool recommended by the knowledge base (e.g., `create_cloud_build_trigger`), passing it the component's `details` block from the plan.
5. **Await and Report Success**: Wait for the tool to return a success message, report the completion to the user, and then proceed to the next component.
3. **Execute the Recommended Tool**: Call the specific tool recommended by the knowledge base (e.g., `create_cloud_build_trigger`), passing it the component's `details` block from the plan.
4. **Await and Report Success**: Wait for the tool to return a success message, report the completion to the user, and then proceed to the next component.


## Workflow B: Direct Action

This workflow is for executing single, direct commands.

1. **Identify the Intent**: Determine the single action the user wants to perform (e.g., `create_artifact_registry_repo`).
2. **Gather Parameters**: Analyze the request to find all necessary parameters (e.g., `repo_name: "my-app-images"`).
3. **Clarify if Needed**: If any mandatory parameters are missing, you MUST ask the user for them before proceeding. Do not guess or make assumptions.
4. **Execute**: Call the single, correct tool to perform the action.


## Universal Protocols & Constraints

Expand Down
9 changes: 4 additions & 5 deletions devops-mcp-server/prompts/deploy.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import (
"github.com/modelcontextprotocol/go-sdk/mcp"
)

//go:embed deploy_prompt.txt
//go:embed deploy_prompt.md
var promptDeployText string

// Helps deploy applications to GCP.
Expand All @@ -32,7 +32,7 @@ func DeployPrompt(ctx context.Context, server *mcp.Server) {
Description: "Helps deploy applications to GCP.",
Messages: []*mcp.PromptMessage{
{
Role: "user",
Role: "user",
Content: &mcp.TextContent{
Text: fmt.Sprintf(promptDeployText, req.Params.Arguments["query"]),
},
Expand All @@ -43,7 +43,7 @@ func DeployPrompt(ctx context.Context, server *mcp.Server) {

// Create a server with a single prompt.
prompt := &mcp.Prompt{
Name: "devops:deploy",
Name: "devops:deploy",
Title: "Deploy an application to GCP.",
Arguments: []*mcp.PromptArgument{
{
Expand All @@ -53,6 +53,5 @@ func DeployPrompt(ctx context.Context, server *mcp.Server) {
},
},
}
server.AddPrompt(prompt,promptHandler)
server.AddPrompt(prompt, promptHandler)
}

File renamed without changes.
Loading
Loading