From d1cebaca1a0e9df0ed076281c62feff2d3a7fe1e Mon Sep 17 00:00:00 2001 From: cghislai Date: Sun, 8 Jun 2025 13:27:23 +0200 Subject: [PATCH] WIP --- .../src/services/processor-service.ts | 7 +- .../src/services/project-workitems-service.ts | 11 +- .../services/gemini-file-system-service.ts | 60 ++-- .../shared/src/services/gemini-service.ts | 7 +- .../shared/src/services/repository-service.ts | 302 +++++++++--------- .../services/project-test-specs-service.ts | 11 +- .../prompts-to-test-spec/nitro-back/INFO.md | 2 +- .../2025-06-08-document-archvigin.md | 23 ++ .../nitro-back/workitems/2025-06-08-test.md | 5 + .../nitro-back/AI.md | 9 +- .../nitro-back/INFO.md | 2 +- 11 files changed, 244 insertions(+), 195 deletions(-) create mode 100644 src/prompts/prompts-to-test-spec/nitro-back/workitems/2025-06-08-document-archvigin.md diff --git a/src/functions/prompts-to-test-spec/src/services/processor-service.ts b/src/functions/prompts-to-test-spec/src/services/processor-service.ts index 3902e6b..fe64970 100644 --- a/src/functions/prompts-to-test-spec/src/services/processor-service.ts +++ b/src/functions/prompts-to-test-spec/src/services/processor-service.ts @@ -206,7 +206,12 @@ export class ProcessorService { } } - // Commit and push changes if any workitems were updated + if (USE_LOCAL_REPO) { + console.log('Skipping commit and push changes to main repository: Using local repository'); + return; + } + + // Commit and push changes if any qworkitems were updated if (updatedAnyWorkitem) { console.log('Committing changes to workitem files...'); await this.sharedRepositoryService.commitChanges( diff --git a/src/functions/prompts-to-test-spec/src/services/project-workitems-service.ts b/src/functions/prompts-to-test-spec/src/services/project-workitems-service.ts index cdc5e38..ff76c5b 100644 --- a/src/functions/prompts-to-test-spec/src/services/project-workitems-service.ts +++ b/src/functions/prompts-to-test-spec/src/services/project-workitems-service.ts @@ -199,13 +199,14 @@ export class ProjectWorkitemsService { guidelinePaths .map(g => g.trim()) .forEach(fileName => { + console.debug("Collected guideline file: " + fileName); const filePath = path.join(projectRepoPath, fileName); if (fs.existsSync(filePath)) { relevantFiles[fileName] = fs.readFileSync(filePath, 'utf-8'); } }); - console.log(`ProjectWorkitemsService: Collected ${Object.keys(relevantFiles).length} relevant files for workitem ${workitem.name}`); + console.log(`ProjectWorkitemsService: Collected ${Object.keys(relevantFiles).length} guideline files for workitem ${workitem.name}`); } catch (error) { console.error(`Error collecting relevant files for workitem ${workitem.name}:`, error); } @@ -270,10 +271,16 @@ export class ProjectWorkitemsService { DRY_RUN_SKIP_GEMINI ); + const workItemPrompt = `\n` + + `---\n` + + `Here is the work item prompt: ${workitemName}\n` + + `${workitemContent}\n` + + `---\n`; + // Process the model stream const result = await geminiFileSystemService.processModelStream( guidelines, - workitemContent, + workItemPrompt, projectRepoPath ); diff --git a/src/functions/shared/src/services/gemini-file-system-service.ts b/src/functions/shared/src/services/gemini-file-system-service.ts index e08fdce..b81fd07 100644 --- a/src/functions/shared/src/services/gemini-file-system-service.ts +++ b/src/functions/shared/src/services/gemini-file-system-service.ts @@ -20,7 +20,7 @@ export interface FunctionArgs { dirPath?: string; searchString?: string; filePattern?: string; - decision?: 'create' | 'update' | 'delete' | 'skip'; + outcome?: 'create' | 'update' | 'delete' | 'skip'; reason?: string; } @@ -144,7 +144,7 @@ export class GeminiFileSystemService { properties: { searchString: { type: FunctionDeclarationSchemaType.STRING, - description: "String to search for in project files" + description: "String to search for in project files (case sensitive)" }, filePattern: { type: FunctionDeclarationSchemaType.STRING, @@ -169,22 +169,22 @@ export class GeminiFileSystemService { } }, { - name: "makeDecision", - description: "State your decision about implementing the workitem", + name: "reportFinalOutcome", + description: "Submit the final outcome for compliance with guidelines. Can only be called once.", parameters: { type: FunctionDeclarationSchemaType.OBJECT, properties: { - decision: { + outcome: { type: FunctionDeclarationSchemaType.STRING, - description: "Your decision: 'create', 'update', 'delete', or 'skip'", + description: "The final outcome: 'create', 'update', 'delete', or 'skip'", enum: ["create", "update", "delete", "skip"] }, reason: { type: FunctionDeclarationSchemaType.STRING, - description: "Reason for your decision" + description: "Reason for this outcome. For instance, 'create' when files have been created, 'skip' when no files has been created, or 'update' when files have been updated." } }, - required: ["decision", "reason"] + required: ["outcome", "reason"] } } ] @@ -322,7 +322,7 @@ export class GeminiFileSystemService { } } else if (entry.isFile()) { // Check if the file matches the pattern - if (!filePattern || this.matchesPattern(entry.name, filePattern)) { + if (!filePattern || this.matchesPattern(relativePath, filePattern)) { searchInFile(fullPath, relativePath); } } @@ -335,6 +335,7 @@ export class GeminiFileSystemService { // Start the search from the root path searchInDirectory(rootPath, rootPath); + console.debug(`Search returned ${results.length} results`) return results; } @@ -387,8 +388,12 @@ export class GeminiFileSystemService { // Create the prompt const prompt = ` +Here is your guideline: + ${guidelines} +Additional content: + ${additionalContent} You have access to the following function calls to help you understand the project structure and create implementations: @@ -398,11 +403,13 @@ You have access to the following function calls to help you understand the proje - listFiles(dirPath): List files in a directory in the project repository - grepFiles(searchString, filePattern): Search for a string in project files, optionally filtered by a file pattern - deleteFile(filePath): Delete a file from the project repository -- makeDecision(decision, reason): State your decision about implementing the workitem. Decision must be one of: 'create', 'update', 'delete', 'skip' -IMPORTANT!!: First use the function calls above to actually implement the workitem. Make all necessary function calls to fully implement the workitem. +IMPORTANT: First use the function calls above to comply with the guidelines. Create, update, or delete all required files. -After you have implemented the workitem using function calls, use the makeDecision function to state your final decision with a reason. +Then, once finished with all the guidelines above, use this function once to report the overall outcome: +- reportFinalOutcome(outcome, reason): Outcome must be one of: 'create', 'update', 'delete', 'skip' + +You won't be able to update other files once you've made a decision. `; // Instantiate the model with our file operation tools @@ -410,9 +417,9 @@ After you have implemented the workitem using function calls, use the makeDecisi model: this.model, tools: this.fileOperationTools, generation_config: { - temperature: 0.1, // Very low temperature for more deterministic responses - top_p: 0.95, // Higher top_p to allow more diverse completions when needed - top_k: 40, // Consider only the top 40 tokens + temperature: 0.3, // Very low temperature for more deterministic responses + top_p: 0.8, // Higher top_p to allow more diverse completions when needed + top_k: 60, // Consider only the top 40 tokens }, }); @@ -498,14 +505,14 @@ After you have implemented the workitem using function calls, use the makeDecisi // Track the file deleted filesDeleted.push(functionArgs.filePath!); break; - case 'makeDecision': - console.debug(`- received makeDecision function call: ${functionArgs.decision} - ${functionArgs.reason}`); + case 'reportFinalOutcome': + console.debug(`- received reportFinalOutcome function call: ${functionArgs.outcome} - ${functionArgs.reason}`); // Store the decision decision = { - decision: functionArgs.decision!, + decision: functionArgs.outcome!, reason: functionArgs.reason! }; - functionResponse = `Decision recorded: ${functionArgs.decision} - ${functionArgs.reason}`; + functionResponse = `Outcome recorded: ${functionArgs.outcome} - ${functionArgs.reason}`; break; default: throw new Error(`Unknown function: ${functionName}`); @@ -532,6 +539,10 @@ After you have implemented the workitem using function calls, use the makeDecisi modelResponses.push(nextResult.textContent); } if (nextResult.functionCall) { + if (decision != null) { + console.warn(`Received another function call for ${nextResult.functionCall.name}, but a decision hsa been recorded. Ignoring stream`); + break; + } pendingFunctionCalls.push(nextResult.functionCall); } @@ -560,14 +571,19 @@ After you have implemented the workitem using function calls, use the makeDecisi modelResponses.push(nextResult.textContent); } if (nextResult.functionCall) { + if (decision != null) { + console.warn(`Received another function call for ${nextResult.functionCall.name}, but a decision hsa been recorded. Ignoring stream`); + break; + } pendingFunctionCalls.push(nextResult.functionCall); } } } } - // If no explicit decision was made using the makeDecision function, try to parse it from the text + // If no explicit decision was made using the reportFinalOutcome function, try to parse it from the text if (!decision) { + console.warn(`No decision function call made during the stream session`); try { // Try to parse a JSON decision from the text const jsonMatch = finalResponse.match(/\{[\s\S]*"decision"[\s\S]*\}/); @@ -579,11 +595,11 @@ After you have implemented the workitem using function calls, use the makeDecisi } } - console.debug(`- Completed gemini stream processing. Final response: ${decision}`); + console.debug(`- Completed gemini stream processing. Final response: ${decision?.decision} - ${decision?.reason}`); return { text: finalResponse, - decision: decision, + decision: decision ?? {decision: "skip", reason: "No decision received/parsed"}, modelResponses: modelResponses, filesWritten: filesWritten, filesDeleted: filesDeleted diff --git a/src/functions/shared/src/services/gemini-service.ts b/src/functions/shared/src/services/gemini-service.ts index 1fba4a3..8b75227 100644 --- a/src/functions/shared/src/services/gemini-service.ts +++ b/src/functions/shared/src/services/gemini-service.ts @@ -93,15 +93,12 @@ ${gitPatch} You are tasked with creating a pull request description for changes to test specifications. The following is a summary of the changes made: + ${description} ${gitPatch && gitPatch !== "No changes detected." ? gitPatchSection : ''} Create a clear, professional pull request description that: -1. Explains that this PR was automatically generated -2. Summarizes the changes (added, updated, deleted, and failed workitems) -3. If code changes are provided, analyze them and include a summary of the key changes -4. Uses markdown formatting for better readability -5. Keeps the description concise but informative +Keeps the description concise but informative The pull request description should be ready to use without further editing. `; diff --git a/src/functions/shared/src/services/repository-service.ts b/src/functions/shared/src/services/repository-service.ts index 7b58cce..ad7e620 100644 --- a/src/functions/shared/src/services/repository-service.ts +++ b/src/functions/shared/src/services/repository-service.ts @@ -4,180 +4,180 @@ import * as fs from 'fs'; import * as path from 'path'; import * as os from 'os'; -import { simpleGit, SimpleGit } from 'simple-git'; -import { Project, RepoCredentials } from '../types'; +import {simpleGit, SimpleGit} from 'simple-git'; +import {Project, RepoCredentials} from '../types'; export class RepositoryService { - private baseDir: string; + private baseDir: string; - constructor(baseDir?: string) { - this.baseDir = baseDir || path.join(os.tmpdir(), 'shared-repo-service'); + constructor(baseDir?: string) { + this.baseDir = baseDir || path.join(os.tmpdir(), 'shared-repo-service'); - // Ensure base directory exists - if (!fs.existsSync(this.baseDir)) { - fs.mkdirSync(this.baseDir, { recursive: true }); - } - } - - /** - * Clone the main repository containing prompts - * @param repoUrl URL of the repository - * @param credentials Optional credentials for private repositories - * @returns Path to the cloned repository - */ - async cloneMainRepository(repoUrl: string, credentials?: RepoCredentials): Promise { - const repoDir = path.join(this.baseDir, 'main-repo'); - - // Clean up existing directory if it exists - if (fs.existsSync(repoDir)) { - fs.rmSync(repoDir, { recursive: true, force: true }); + // Ensure base directory exists + if (!fs.existsSync(this.baseDir)) { + fs.mkdirSync(this.baseDir, {recursive: true}); + } } - fs.mkdirSync(repoDir, { recursive: true }); + /** + * Clone the main repository containing prompts + * @param repoUrl URL of the repository + * @param credentials Optional credentials for private repositories + * @returns Path to the cloned repository + */ + async cloneMainRepository(repoUrl: string, credentials?: RepoCredentials): Promise { + const repoDir = path.join(this.baseDir, 'main-repo'); - // Configure git with credentials if provided - const git = this.configureGit(repoDir, credentials); + // Clean up existing directory if it exists + if (fs.existsSync(repoDir)) { + fs.rmSync(repoDir, {recursive: true, force: true}); + } - // Clone the repository - await git.clone(repoUrl, repoDir); + fs.mkdirSync(repoDir, {recursive: true}); - return repoDir; - } + // Configure git with credentials if provided + const git = this.configureGit(repoDir, credentials); - /** - * Clone a project repository - * @param project Project information - * @param credentials Optional credentials for private repositories - * @returns Path to the cloned repository - */ - async cloneProjectRepository(project: Project, credentials?: RepoCredentials): Promise { - if (!project.repoUrl) { - throw new Error(`Repository URL not found for project ${project.name}`); + // Clone the repository + await git.clone(repoUrl, repoDir); + + return repoDir; } - const projectRepoDir = path.join(this.baseDir, `project-${project.name}`); + /** + * Clone a project repository + * @param project Project information + * @param credentials Optional credentials for private repositories + * @returns Path to the cloned repository + */ + async cloneProjectRepository(project: Project, credentials?: RepoCredentials): Promise { + if (!project.repoUrl) { + throw new Error(`Repository URL not found for project ${project.name}`); + } - // Clean up existing directory if it exists - if (fs.existsSync(projectRepoDir)) { - fs.rmSync(projectRepoDir, { recursive: true, force: true }); + const projectRepoDir = path.join(this.baseDir, `project-${project.name}`); + + // Clean up existing directory if it exists + if (fs.existsSync(projectRepoDir)) { + fs.rmSync(projectRepoDir, {recursive: true, force: true}); + } + + fs.mkdirSync(projectRepoDir, {recursive: true}); + + // Configure git with credentials if provided + const git = this.configureGit(projectRepoDir, credentials); + + // Clone the repository + await git.clone(project.repoUrl, projectRepoDir); + + // Checkout the target branch if specified + if (project.targetBranch) { + await this.checkoutBranch(projectRepoDir, project.targetBranch); + } + + return projectRepoDir; } - fs.mkdirSync(projectRepoDir, { recursive: true }); - - // Configure git with credentials if provided - const git = this.configureGit(projectRepoDir, credentials); - - // Clone the repository - await git.clone(project.repoUrl, projectRepoDir); - - // Checkout the target branch if specified - if (project.targetBranch) { - await this.checkoutBranch(projectRepoDir, project.targetBranch); + /** + * Create a new branch in a repository + * @param repoDir Path to the repository + * @param branchName Name of the branch to create + */ + async createBranch(repoDir: string, branchName: string): Promise { + const git = simpleGit(repoDir); + await git.checkoutLocalBranch(branchName); } - return projectRepoDir; - } - - /** - * Create a new branch in a repository - * @param repoDir Path to the repository - * @param branchName Name of the branch to create - */ - async createBranch(repoDir: string, branchName: string): Promise { - const git = simpleGit(repoDir); - await git.checkoutLocalBranch(branchName); - } - - /** - * Commit changes to a repository - * @param repoDir Path to the repository - * @param message Commit message - */ - async commitChanges(repoDir: string, message: string): Promise { - const git = simpleGit(repoDir); - await git.add('.'); - await git.commit(message); - } - - /** - * Push changes to a repository - * @param repoDir Path to the repository - * @param branchName Name of the branch to push - * @param credentials Optional credentials for private repositories - */ - async pushChanges(repoDir: string, branchName: string, credentials?: RepoCredentials): Promise { - const git = this.configureGit(repoDir, credentials); - await git.push('origin', branchName, ['--set-upstream']); - } - - /** - * Generate a git patch of the changes in a repository - * @param repoDir Path to the repository - * @returns Git patch as a string - */ - async generateGitPatch(repoDir: string): Promise { - const git = simpleGit(repoDir); - - // Check if there are any changes - const status = await git.status(); - if (status.files.length === 0) { - return "No changes detected."; + /** + * Commit changes to a repository + * @param repoDir Path to the repository + * @param message Commit message + */ + async commitChanges(repoDir: string, message: string): Promise { + const git = simpleGit(repoDir); + await git.add('.'); + await git.commit(message); } - // Generate a diff of all changes (staged and unstaged) - const diff = await git.diff(['--staged', '--no-color']); - - // Only get untracked diff if there are untracked files - let untrackedDiff = ''; - if (status.not_added && status.not_added.length > 0) { - untrackedDiff = await git.diff(['--no-index', '/dev/null', ...status.not_added.map(file => path.join(repoDir, file))]).catch(() => ''); + /** + * Push changes to a repository + * @param repoDir Path to the repository + * @param branchName Name of the branch to push + * @param credentials Optional credentials for private repositories + */ + async pushChanges(repoDir: string, branchName: string, credentials?: RepoCredentials): Promise { + const git = this.configureGit(repoDir, credentials); + await git.push('origin', branchName, ['--set-upstream']); } - // Combine the diffs - let patch = diff; - if (untrackedDiff) { - patch += '\n\n' + untrackedDiff; + /** + * Generate a git patch of the changes in a repository + * @param repoDir Path to the repository + * @returns Git patch as a string + */ + async generateGitPatch(repoDir: string): Promise { + const git = simpleGit(repoDir); + + // Check if there are any changes + const status = await git.status(); + if (status.files.length === 0) { + return "No changes detected."; + } + + // Generate a diff of all changes (staged and unstaged) + const diff = await git.diff(['--staged', '--no-color']); + + // Only get untracked diff if there are untracked files + let untrackedDiff = ''; + if (status.not_added && status.not_added.length > 0) { + untrackedDiff = await git.diff(['--no-index', '/dev/null', ...status.not_added.map(file => path.join(repoDir, file))]).catch(() => ''); + } + + // Combine the diffs + let patch = diff; + if (untrackedDiff) { + patch += '\n\n' + untrackedDiff; + } + + return patch || "No changes detected."; } - return patch || "No changes detected."; - } - - /** - * Checkout an existing branch in a repository - * @param repoDir Path to the repository - * @param branchName Name of the branch to checkout - * @throws Error if checkout fails - */ - async checkoutBranch(repoDir: string, branchName: string): Promise { - const git = simpleGit(repoDir); - try { - await git.checkout(branchName); - } catch (error) { - throw new Error(`Failed to checkout branch ${branchName}: ${error instanceof Error ? error.message : String(error)}`); - } - } - - /** - * Configure git with credentials - * @param repoDir Path to the repository - * @param credentials Credentials for authentication - * @returns Configured SimpleGit instance - */ - private configureGit(repoDir: string, credentials?: RepoCredentials): SimpleGit { - const git = simpleGit(repoDir); - - if (credentials) { - if (credentials.type === 'username-password' && credentials.username && credentials.password) { - // For HTTPS URLs with username/password - const credentialHelper = `!f() { echo "username=${credentials.username}"; echo "password=${credentials.password}"; }; f`; - git.addConfig('credential.helper', credentialHelper, false, 'global'); - } else if (credentials.type === 'token' && credentials.token) { - // For HTTPS URLs with token - const credentialHelper = `!f() { echo "password=${credentials.token}"; }; f`; - git.addConfig('credential.helper', credentialHelper, false, 'global'); - } + /** + * Checkout an existing branch in a repository + * @param repoDir Path to the repository + * @param branchName Name of the branch to checkout + * @throws Error if checkout fails + */ + async checkoutBranch(repoDir: string, branchName: string): Promise { + const git = simpleGit(repoDir); + try { + await git.checkout(branchName); + } catch (error) { + throw new Error(`Failed to checkout branch ${branchName}: ${error instanceof Error ? error.message : String(error)}`); + } } - return git; - } + /** + * Configure git with credentials + * @param repoDir Path to the repository + * @param credentials Credentials for authentication + * @returns Configured SimpleGit instance + */ + private configureGit(repoDir: string, credentials?: RepoCredentials): SimpleGit { + const git = simpleGit(repoDir); + + if (credentials) { + if (credentials.type === 'username-password' && credentials.username && credentials.password) { + // For HTTPS URLs with username/password + const credentialHelper = `!f() { echo "username=${credentials.username}"; echo "password=${credentials.password}"; }; f`; + git.addConfig('credential.helper', credentialHelper, false, 'global'); + } else if (credentials.type === 'token' && credentials.token) { + // For HTTPS URLs with token + const credentialHelper = `!f() { echo "password=${credentials.token}"; }; f`; + git.addConfig('credential.helper', credentialHelper, false, 'global'); + } + } + + return git; + } } diff --git a/src/functions/test-spec-to-test-implementation/src/services/project-test-specs-service.ts b/src/functions/test-spec-to-test-implementation/src/services/project-test-specs-service.ts index bd9831a..1ceedf5 100644 --- a/src/functions/test-spec-to-test-implementation/src/services/project-test-specs-service.ts +++ b/src/functions/test-spec-to-test-implementation/src/services/project-test-specs-service.ts @@ -32,7 +32,7 @@ export class ProjectTestSpecsService { // Read project guidelines const projectGuidelines = await this.projectService.readProjectGuidelines(project.path); - const result = await this.processTestSpec(project, projectRepoPath, projectGuidelines); + const result = await this.generateTestSpecs(project, projectRepoPath, projectGuidelines); // Generate git patch if any files were written let gitPatch: string | undefined = undefined; @@ -64,11 +64,10 @@ export class ProjectTestSpecsService { * Process a test spec using Gemini * @param project Project containing the test spec * @param projectRepoPath Path to the project repository - * @param testSpec Test spec to process * @param projectGuidelines Project guidelines * @returns Result of the processing */ - private async processTestSpec( + private async generateTestSpecs( project: Project, projectRepoPath: string, projectGuidelines: string @@ -78,7 +77,7 @@ export class ProjectTestSpecsService { const relevantFiles = await this.collectRelevantFiles(project, projectRepoPath); // Let Gemini generate the implementation - const result = await this.generateImplementations( + const result = await this.generateAllTestSpecs( projectRepoPath, projectGuidelines, relevantFiles @@ -133,6 +132,7 @@ export class ProjectTestSpecsService { guidelinePaths .map(g => g.trim()) .forEach(fileName => { + console.debug("Collected guideline file: " + fileName); const filePath = path.join(projectRepoPath, fileName); if (fs.existsSync(filePath)) { relevantFiles[fileName] = fs.readFileSync(filePath, 'utf-8'); @@ -151,11 +151,10 @@ export class ProjectTestSpecsService { * Generate implementation using Gemini API * @param projectRepoPath Path to the project repository * @param guidelines Project guidelines - * @param testSpec Test spec to implement * @param relevantFiles Additional relevant files to include in the prompt * @returns Object containing the generated text, parsed decision, and files written/deleted */ - private async generateImplementations( + private async generateAllTestSpecs( projectRepoPath: string, guidelines: string, relevantFiles: Record = {} diff --git a/src/prompts/prompts-to-test-spec/nitro-back/INFO.md b/src/prompts/prompts-to-test-spec/nitro-back/INFO.md index 6d52611..b95bbd6 100644 --- a/src/prompts/prompts-to-test-spec/nitro-back/INFO.md +++ b/src/prompts/prompts-to-test-spec/nitro-back/INFO.md @@ -5,5 +5,5 @@ Nitro backend server in quarkus - [x] Repo host: https://gitea.fteamdev.valuya.be/ - [x] Repo url: https://gitea.fteamdev.valuya.be/cghislai/nitro-back.git - [x] Target branch: main -- [ ] AI guidelines: +- [x] AI guidelines: nitro-it/src/test/resources/workitems/AI_DEFINITION.md - [x] Jira component: nitro diff --git a/src/prompts/prompts-to-test-spec/nitro-back/workitems/2025-06-08-document-archvigin.md b/src/prompts/prompts-to-test-spec/nitro-back/workitems/2025-06-08-document-archvigin.md new file mode 100644 index 0000000..8442254 --- /dev/null +++ b/src/prompts/prompts-to-test-spec/nitro-back/workitems/2025-06-08-document-archvigin.md @@ -0,0 +1,23 @@ +## Document archiving + +Nitro admins want to be able to archive documents in every status. Once the document reaches the +status ARCHIVED, it cannot be COMPLETED afterwards. + +When a document is archived using the dedicated endpoint, its status should be set ARCHIVED directly. + +When a document in the status TO_EXPORT is archived, and that an export was in progress at that time, +the export should complete, but the document status must not change and the document must not be +set problematic once the export completes. + +Only users that are superAdmins may archive documents. + +- [ ] Jira: NITRO-0003 +- [ ] Implementation: +- [ ] Pull Request: +- [x] Active + +### Log + +2025-06-08T09:58:06.287Z - Workitem has been implemented. + +- Created nitro-it/src/test/resources/workitems/2025-06-08-document-archvigin.feature diff --git a/src/prompts/prompts-to-test-spec/nitro-back/workitems/2025-06-08-test.md b/src/prompts/prompts-to-test-spec/nitro-back/workitems/2025-06-08-test.md index 16b1a0d..b3cd452 100644 --- a/src/prompts/prompts-to-test-spec/nitro-back/workitems/2025-06-08-test.md +++ b/src/prompts/prompts-to-test-spec/nitro-back/workitems/2025-06-08-test.md @@ -11,5 +11,10 @@ The nitro-back backend should have a /test endpoint implemented returning the js ### Log +2025-06-08T09:58:26.902Z - Workitem has been updated. +- Created nitro-it/src/test/resources/workitems/test_workitem.feature +PR: https://gitea.fteamdev.valuya.be/cghislai/nitro-back/pulls/1 + + 2025-06-08T07:36:00.901Z - Workitem has been implemented. - Created nitro-it/src/test/resources/workitems/test_workitem.feature diff --git a/src/prompts/test-spec-to-test-implementation/nitro-back/AI.md b/src/prompts/test-spec-to-test-implementation/nitro-back/AI.md index af9c9af..2dfc4fd 100644 --- a/src/prompts/test-spec-to-test-implementation/nitro-back/AI.md +++ b/src/prompts/test-spec-to-test-implementation/nitro-back/AI.md @@ -1,7 +1,4 @@ -## Test spec implementation - -- Iterate over cucumber feature definitions in the `nitro-it/src/test/resources/workitems/` folder. -- For each of them, a corresponding test implementation should be created if it does not exist. -- Test implementations should be created in the `nitro-it/src/test/java/be/fiscalteam/nitro/bdd` folder, following the - same structure as the feature definition files. One test file per feature definition. +This is your guideline for the implementation of the feature file: +- Iterate over cucumber ".feature" definition files in the `nitro-it/src/test/resources/workitems/` directory. +- For each of them create all required files to implement the feature. diff --git a/src/prompts/test-spec-to-test-implementation/nitro-back/INFO.md b/src/prompts/test-spec-to-test-implementation/nitro-back/INFO.md index 6d52611..1f5495a 100644 --- a/src/prompts/test-spec-to-test-implementation/nitro-back/INFO.md +++ b/src/prompts/test-spec-to-test-implementation/nitro-back/INFO.md @@ -5,5 +5,5 @@ Nitro backend server in quarkus - [x] Repo host: https://gitea.fteamdev.valuya.be/ - [x] Repo url: https://gitea.fteamdev.valuya.be/cghislai/nitro-back.git - [x] Target branch: main -- [ ] AI guidelines: +- [x] AI guidelines: nitro-it/src/test/resources/workitems/AI_IMPLEMENTATION.md - [x] Jira component: nitro