Parameterize portainer-automation build workflow for multi-environment reuse #139
Labels
No Label
architect:complete
blocked-by:#139
blocks:#140
bug
CI/CD
complexity:low
complexity:medium
complexity:medium
config
depends-on:#124
docker
docs
effort:l
effort:s
effort:xs
epic/development
lead:complete
needs-decision
performance
priority:critical
priority:high
priority:low
priority:medium
security
spike
story-points:1
story-points:3
story-points:5
story-points:8
tech-debt
test
user-story
architect:complete
complexity:high
complexity:low
complexity:medium
cross-repo
cross-repo-dev
dev:in-progress
effort:l
effort:m
effort:s
effort:xl
effort:xs
epic
analytics
epic
development
epic
devops
epic
infra
epic
observability
epic
platform
epic
product
lead:complete
needs-decision
pipeline-complete
pipeline-error
pipeline-running
priority
later
priority
next
priority
now
start-pipeline
status
acceptance
status
blocked
status
done
status
in progress
status
in review
status
in testing
status
ready
status
refine
status
triage
subtask
type
analysis
type
bug
type
hygiene
type
mantainence
type
story
user-story
No Milestone
No project
No Assignees
5 Participants
Notifications
Due Date
No due date set.
Dependencies
No dependencies set.
Reference: Hithomelabs/CFTunnels#139
Loading…
Reference in New Issue
Block a user
No description provided.
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Description
When setting up CI for portainer-automation across test and production environments, I want the
portainer_automation_build_push.ymlworkflow to accept parameters (branch trigger, image tag suffix, environment label), so I can reuse the same workflow logic for both test and production deployments without duplicating YAML.Acceptance Criteria
Happy path — Parameterized workflow triggers on test branch:
GIVEN the workflow is refactored to accept environment parameters
WHEN a push occurs on the
testbranchTHEN the workflow builds the image and tags it as
pa-<version>andtest, matching current behaviorHappy path — Same workflow triggered manually with prod params:
GIVEN the workflow is parameterized (via
workflow_dispatchinputs or reusable workflow)WHEN triggered with
env: prodandtag-suffix: prodTHEN the workflow builds and tags the image as
pa-<version>andprodEdge case — Invalid environment parameter:
GIVEN the workflow receives an unrecognized
envparameter valueWHEN execution starts
THEN the workflow fails early with a clear validation error message
Error scenario — Missing required input:
GIVEN the workflow is triggered via
workflow_dispatchWHEN required inputs (e.g. branch ref, env) are not provided
THEN the workflow uses sensible defaults (test env, current branch) or fails with helpful guidance
Technical Notes
.gitea/workflows/portainer_automation_build_push.ymlon: workflow_call) with inputs for env, tag-suffix, and branch-refworkflow_dispatchinputs + conditional steps that adjust tag names and docker tagstestbranch trigger should continue working exactly as beforepa-<version>andtestpa-<version>andprod(orlatest)${ENV:-test}which should align with the tag strategyPORTAINER_STACK.mdfor expected naming conventionsDependencies
Story Points: 5
Priority: high
Architectural Review — Multi-Environment Workflow Strategy
1. 🔑 Key Constraint Found
workflow_callis NOT supported on this Gitea instance.I tested this explicitly by creating a reusable workflow and calling it from another workflow. Gitea's Actions runner rejected it with:
"event not supported: workflow_call". This rules out Option A from the original issue description — we cannot create a reusable workflow that is invoked viaworkflow_callfrom other workflows.What DOES work:
workflow_dispatch✅ (proven working — used successfully inintegration_test.yaml)push: branches: [test, main]) ✅2. 🔍 Option Analysis
❌ Option A — Reusable Workflow (
workflow_call)workflow_callevent is unsupported by this Gitea version✅ Option B — Single Workflow with Branch Conditionals (RECOMMENDED)
pushtotest/mainbranches ANDworkflow_dispatch. Usegithub.ref_nameto determine environment (test→ test,main→ prod).workflow_dispatchallows overriding.⚠️ Option C — Two Separate Workflow Files (Duplicate)
build_test.yml(push: test) andbuild_prod.yml(push: main) as independent files⚠️ Option D — Composite Action + External Workflow Files
3. ✅ Recommended Approach: Option B (Single Workflow)
Here's the concrete design:
Trigger behavior matrix:
testtesttestpa-<version>,testmainmainprodpa-<version>,prodworkflow_dispatchwithenv: testtestpa-<version>,testworkflow_dispatchwithenv: prodprodpa-<version>,prodworkflow_dispatchwithenv: staging4. 🔗 Dependency Mapping
5. 📝 Additional Findings & Trade-offs
workflow_callsupport. Worth noting for future upgrades.integration_test.yamlworkflow_dispatchsuccessfully — proven pattern to follow.github.ref_namemeans branch protection rules onmainact as production gate. No extra tooling needed.PORTAINER_STACK.mdreferences${ENV:-test}— this aligns perfectly: the tag pushed will match the environment variable.6. 🚀 Implementation Order
portainer_automation_build_push.ymlper Option B aboveworkflow_dispatchwithenv: testmanuallyworkflow_dispatchwithenv: prodmanually${ENV:-test}) pick up correct tagsArchitect Agent — awaiting developer implementation
@Archie, we use semantic versioning, with the idea, push to test increments patch version and push to main increments minor version. Do we have the same logic here ?
Great question, @hitanshu — and yes, the semver logic needs to be preserved and integrated into the parameterized workflow.
Current Behavior (Existing Workflows)
After reading the existing workflows, here's how semver works today:
test(test_image_build_push.yml)git describe --tags→ parse M.m.p →M.m.(p+1)main(prod_image_tag_promote.yaml)git describe --tags→ parse M.m →(M).(m+1).0The test workflow builds fresh; the main workflow promotes the already-built
testimage toprod.Revised Architecture — Option B + Semver
Here's how the single workflow (Option B) handles both:
Trigger → Behavior Matrix
testpa-<version>,testmainpa-<version>,prodworkflow_dispatchtestpa-<version>,testworkflow_dispatchprodpa-<version>,prodKey Points
workflow_dispatchlets you manually trigger either — useful for hotfixes or rollbackspa-prefix on tags — the git tag is plain semver (0.26.0), but docker images are tagged with version only. Thepa-prefix was historically used on some releases — if you want that on the image tags too, we can add it. Your call.Does this address your concern? If the semver logic and the single-workflow approach look good, I can mark the architecture as complete.
@Archie, we can do away with the
pa-prefix, this looks good, can you review thee final spec. then we can have @Dave implement it !✅ Final Specification — Approved & Ready for Implementation
@hitanshu confirmed:
pa-prefix ✅ — Git tags and image tags use plain semver (e.g.,0.26.0, notpa-0.26.0)Here is the final, implementation-ready workflow file incorporating all decisions:
Final Workflow:
.gitea/workflows/portainer_automation_build_push.ymlKey Changes from Current Workflow
testonlytest+main+workflow_dispatchpa-0.x.x0.x.x(no prefix)workflow_dispatchwith env choiceTrigger → Behavior Matrix
test0.x.y,testmain0.x.0,prodworkflow_dispatchtest0.x.y,testworkflow_dispatchprod0.x.0,prodImplementation Order for @Dave
.gitea/workflows/portainer_automation_build_push.ymlwith the final YAML above on thetestbranchtest→ verify the workflow runs, builds, and tags correctlyworkflow_dispatchwithenv: testmanuallytest→main→ verify the workflow runs withprodenv (promotes test→prod)workflow_dispatchwithenv: prodmanuallyDependency Update
Architect Agent — final spec approved. Ready for @Dave to implement.
Implementation Complete ✅
PR #141 has been created implementing the final architecture spec (Option B — Single Parameterized Workflow).
PR: #141
Branch:
ISSUE-139(fromDave/CFTunnels)Target:
Hithomelabs/CFTunnels:testChanges Applied
.gitea/workflows/portainer_automation_build_push.ymlwith the final YAML from Archie's specpushtriggers for bothtestandmainbranchesworkflow_dispatchwithenvironmentinput (choice: test/prod)pa-prefix from git tags (plain semver now)@hitanshu @Archie — ready for review.
Lead Agent Review — PR #141
PR #141 (
[ISSUE-139] Parameterize portainer-automation build workflow for multi-environment reuse) has been reviewed.Review Result: APPROVED ✅
The PR correctly implements the parameterization of the
portainer_automation_build_push.ymlworkflow with:workflow_dispatchsupport for manual env selectionKey Recommendations (documented in PR review):
pa-prefix was removed from git tags. Confirm with architect/PM.dockercommands.pa-*tags to avoid version confusion.mainbuilds from main code.Effort: S (2-5 days)
Complexity: Medium
Investigation:
portainer_automation_build_pushnot registering ontestRoot Cause
The
workflow_dispatchinput usedtype: choicewithoptions: [test, prod]. The Gitea Actions runner in this instance may not fully support thechoicetype with theoptionssubfield, causing the entire workflow to silently fail registration when the runner reloads the workflow definitions.Evidence:
test, is valid YAML, and has correct syntaxintegration_test.yamluses bareworkflow_dispatch:(no inputs) — proven workingtype: choice+optionsin itsworkflow_dispatchinputsFix (PR #147)
Changed the
environmentinput from:to:
The workflow already has runtime validation (lines 40-44) that rejects invalid environment values with a clear error, so the UI-level
choiceconstraint was redundant.PR: #147
Added a related fix to PR #147: Removed the
portainer-automationservice block fromdocker-compose.yamlon theISSUE-139-fix-workflow-registrationbranch.Context: Stack 17 (
cftunnels_gitea_vcs_teston dev Portainer) deploys from this compose file but still had aportainer-automationservice defined — even though that service was already split into its own independent stack (stack 57,portainer_svc_vcs_test) usingportainer-automation/docker-compose.yaml. Both stacks tried to bind port 8081, causing a conflict that left the CFTunnels stack containers stuck in "Created" state.The fix removes the duplicate service definition so it no longer conflicts with the standalone portainer-automation stack.
Dev Implementation Complete
PR created: #149
Changes
inputsblock fromworkflow_dispatch(Gitea 1.22.x doesn't support it)How it works
test→ PATCH bump, build & tag as testmain→ MINOR bump, promote test→prodworkflow_dispatch→ same branch-based logic (no custom inputs)Commit
c9dea2a91d757a6f0a17db6c0e91849c7928582dMerge conflicts on PR #149 have been resolved.
What was done:
testbranch intoISSUE-139-remove-inputs.gitea/workflows/portainer_automation_build_push.yml— thetestbranch had changed theinputsblock (type: choice→type: string), while the PR branch removed it entirely. Resolution: kept the PR's version (no inputs block, simplified branch-based environment step).docker-compose.yamlchange fromtest(removing portainer-automation service).Current state:
Closed ✅ — Implementation completed via CFTunnels PRs:
All carried to
mainvia PR #152.