Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Locking and Deployment information changes #276

Draft
wants to merge 34 commits into
base: main
Choose a base branch
from

Conversation

TurkerKoc
Copy link
Contributor

@TurkerKoc TurkerKoc commented Jan 26, 2025

This PR introduces key improvements to environment visibility, deployment tracking, and user activity transparency. Below are the highlights:

Key changes

1. Environment Locking Enhancements

  • Lock Details: Now displays the user avatar of who locked the environment directly in the environment list.
  • Time Format: Lock durations are formatted as HH:MM:SS (e.g., 02:15:30) using a reusable client-side time-formatting service.

2. Deployment Visibility Without Expansion

  • At-a-Glance Info: Environments now show the latest deployment's:
    Faster Insights: Users instantly see deployment status, lock details, and deployment history without expanding rows.
  • Transparency: Clear audit trail of who deployed what, when, and from which branch.
  • Consistency: GitHub UI-triggered deployments now appear in Helios alongside manual deployments.User: Who triggered the deployment.
    • Branch: What branch was deployed.
    • Timestamp: When the deployment occurred.
  • Status Tags: Replaced text with intuitive icons (e.g., ✅ for success, ⏳ for in progress). Hover over icons for status details.

3. Real-Time Deployment Status

  • Immediate Feedback: Shows IN_QUEUE status instantly when a deployment is triggered, by harmonizing HeliosDeployment and Deployment entity.
  • Webhook handling: Matches incoming deployment webhooks to existing HeliosDeployment records, ensuring seamless transitions between Deployments and Helios deployment entities to show IN_QUEUE, IN_PROGRESS, and final states (✅/❌).

4. Activity History Enrichment

  • User Attribution: Displays the deployer’s name in the Activity History page for both manual and GitHub-triggered deployments.

Technical Improvements

  • Entity Harmonization: Unified HeliosDeployment (created on deploy-click) and Deployment (created via webhook) to provide end-to-end tracking.
    • HeliosDeployment created on deploy-click with deployment-id field empty.
    • Deployment entity created via webhook and updated HeliosDeployment to match with Deployment Entity
    • If we have HeliosDeployment in the environment without deployment-id we are showing that entity as latest deployment.
    • Otherwise Deployment Entity is used to show latest deployment information.
  • GitHub User Mapping: Added JWT-based GitHub user ID resolution for accurate user attribution.
  • Backend Sync Logic: Updated webhook handlers, controllers and data sync to prioritize HeliosDeployment until webhook data arrives.

Impact

  • Faster Insights: Users instantly see deployment status, lock details, and deployment history without expanding rows.
  • Transparency: Clear audit trail of who deployed what, when, and from which branch.
  • Consistency: GitHub UI-triggered deployments now appear in Helios alongside manual deployments.

Screenshots and Recordings

Deployment via Helios

deployment_helios.mov

Deployment via Github UI and monitoring in Helios

deployment_github.mov

Activity History

Screenshot 2025-02-01 at 19 12 47

Copy link

codacy-production bot commented Jan 26, 2025

Coverage summary from Codacy

See diff coverage on Codacy

Coverage variation Diff coverage
Report missing for 39612651 0.00%
Coverage variation details
Coverable lines Covered lines Coverage
Common ancestor commit (3961265) Report Missing Report Missing Report Missing
Head commit (b88b4b1) 849 266 31.33%

Coverage variation is the difference between the coverage for the head and common ancestor commits of the pull request branch: <coverage of head commit> - <coverage of common ancestor commit>

Diff coverage details
Coverable lines Covered lines Diff coverage
Pull request (#276) 38 0 0.00%

Diff coverage is the percentage of lines that are covered by tests out of the coverable lines that the pull request added or modified: <covered lines added or modified>/<coverable lines added or modified> * 100%

See your quality gate settings    Change summary preferences

Codacy stopped sending the deprecated coverage status on June 5th, 2024. Learn more

Footnotes

  1. Codacy didn't receive coverage data for the commit, or there was an error processing the received data. Check your integration for errors and validate that your coverage setup is correct.

@github-actions github-actions bot added size:XXL and removed size:XL labels Jan 27, 2025
@StefanNemeth
Copy link
Contributor

Just for your info: You'll probably need to create a migration file for the entity changes and merge main into the feat branch. If you need any assistance just hit me up :)

(a, b) -> {
OffsetDateTime timeA = a.timestamp();
OffsetDateTime timeB = b.timestamp();
if (timeA == null && timeB == null) return 0;
Copy link

Choose a reason for hiding this comment

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

🚫 [checkstyle] <com.puppycrawl.tools.checkstyle.checks.blocks.NeedBracesCheck> reported by reviewdog 🐶
'if' construct must use '{}'s.

OffsetDateTime timeA = a.timestamp();
OffsetDateTime timeB = b.timestamp();
if (timeA == null && timeB == null) return 0;
if (timeA == null) return 1;
Copy link

Choose a reason for hiding this comment

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

🚫 [checkstyle] <com.puppycrawl.tools.checkstyle.checks.blocks.NeedBracesCheck> reported by reviewdog 🐶
'if' construct must use '{}'s.

OffsetDateTime timeB = b.timestamp();
if (timeA == null && timeB == null) return 0;
if (timeA == null) return 1;
if (timeB == null) return -1;
Copy link

Choose a reason for hiding this comment

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

🚫 [checkstyle] <com.puppycrawl.tools.checkstyle.checks.blocks.NeedBracesCheck> reported by reviewdog 🐶
'if' construct must use '{}'s.

Copy link
Contributor

@egekocabas egekocabas left a comment

Choose a reason for hiding this comment

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

Had a review session with @TurkerKoc and below points will be changed 👍🏻

Also in an another PR we need to refactor this re-deploy logic where we have this hardcoded 20 minutes for any missing webhook events, we need to think about this case and how it effects our system.

<i-tabler name="user" class="w-6 h-6 text-gray-600" />
}
<span>
{{ environment.latestDeployment.user?.name }} deployed
Copy link
Contributor

Choose a reason for hiding this comment

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

Lets handle the case where the user is empty

Comment on lines +37 to +46
<p-avatar
class="w-6 h-6"
shape="circle"
size="normal"
[image]="environment.latestDeployment.user?.avatarUrl"
[pTooltip]="keycloakService.isCurrentUser(environment.latestDeployment.user?.login) ? 'You' : environment.latestDeployment.user?.name"
[styleClass]="getAvatarBorderClass(environment.latestDeployment.user?.login || '')"
(click)="openUserProfile(environment.latestDeployment.user?.login || '')"
>
</p-avatar>
Copy link
Contributor

Choose a reason for hiding this comment

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

it would be better if we make this a component so in pr list or other places we can use the user profile picture component

Comment on lines 58 to +60
permissionService = inject(PermissionService);
keycloakService = inject(KeycloakService);
dateService = inject(DateService);
Copy link
Contributor

Choose a reason for hiding this comment

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

would be better to use private

@@ -93,6 +108,7 @@ export class EnvironmentListViewComponent {
message: `Are you sure you want to deploy to ${environment.name}?`,
accept: () => {
this.deploy.emit(environment);
this.queryClient.invalidateQueries({ queryKey: this.queryKey() });
Copy link
Contributor

Choose a reason for hiding this comment

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

Lets invalidate query in the parent compoennt 👍🏻

Comment on lines +246 to 247
// 4) Combine the lists
List<ActivityHistoryDto> combined = new ArrayList<>();
Copy link
Contributor

Choose a reason for hiding this comment

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

We also need to add HeliosDeployment entities where deploymentId field is empty, in order to show failed workflowrun's of deployments
It is the case where we don't get the Deployment entity since the workflowrun failed before the Deployment entity is created

import io.micrometer.common.lang.Nullable;
import java.time.OffsetDateTime;
import org.springframework.lang.NonNull;

@JsonInclude(JsonInclude.Include.NON_EMPTY)
public record EnvironmentLockHistoryDto(
@NonNull Long id,
String lockedBy,
User lockedBy,
Copy link
Contributor

Choose a reason for hiding this comment

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

lets use userdto

FROM EnvironmentLockHistory elh
WHERE elh.environment.id = :environmentId
AND elh.unlockedAt IS NULL
Copy link
Contributor

Choose a reason for hiding this comment

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

lets also add
elh.environment.enabled = true

Comment on lines +71 to +78
private Optional<Deployment> findDeploymentById(Environment environment, Long deploymentId) {
if (deploymentId == null) {
return Optional.empty();
}
return environment.getDeployments().stream()
.filter(d -> d.getId().equals(deploymentId))
.findFirst();
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Lets remove this method

* <p>Returns a small wrapper object with either a real Deployment or a HeliosDeployment. This
* helps unify your "latest" logic into one place.
*/
public LatestDeploymentUnion findLatestDeployment(Environment env) {
Copy link
Contributor

Choose a reason for hiding this comment

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

maybe it would be better to get latest heliosdeployment and also deployment and then compare which one is the latest by createdAt or updatedAt fields?

Lets imagine a scenario where somebody triggered deployment from Helios and we don't get any webhook data related with that, but then somebody else triggered deployment from GitHub UI and then lets discuss this scenario and what happens in WorklowRun webhook listener, Deployment webhook listener and our final entity status and other fields and what this method returns

@TurkerKoc
Copy link
Contributor Author

Just for your info: You'll probably need to create a migration file for the entity changes and merge main into the feat branch. If you need any assistance just hit me up :)

Thanks for the heads up! Added the migration script :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
3 participants