Skip to content
Draft
Show file tree
Hide file tree
Changes from 6 commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
f100edb
add team sync function
Alaurant Jul 7, 2024
d2e1f1a
fix upper case issue
Alaurant Jul 7, 2024
4d25a7b
Rename yamlTeamLoader.java to YAMLTeamLoader.java
Alaurant Jul 7, 2024
59b6820
fix safe path
Alaurant Jul 7, 2024
632e24e
change file type
Alaurant Jul 7, 2024
1a7ce9f
change workflow path
Alaurant Jul 7, 2024
ca4e835
Update naming conventions
Alaurant Jul 22, 2024
a7b86fd
Update variable names
Alaurant Jul 22, 2024
3674be9
Update related variable names
Alaurant Jul 22, 2024
3654aff
Update funcs based on feedback
Alaurant Jul 29, 2024
5da05b9
Merge branch 'jenkins-infra:master' into master
Alaurant Jul 29, 2024
1c15445
update definition file
Alaurant Jul 29, 2024
7a853aa
update definition name
Alaurant Jul 29, 2024
ecad765
remove system exit
Alaurant Jul 29, 2024
93d4959
Fix case sensitivity issues in filenames
Alaurant Jul 29, 2024
bb6369c
Remove unwanted file with incorrect case
Alaurant Jul 29, 2024
d02abbb
new features
Alaurant Aug 24, 2024
9305041
Merge branch 'jenkins-infra:master' into master
Alaurant Aug 24, 2024
2138e2d
remove first run check
Alaurant Aug 26, 2024
6a11556
Merge branch 'jenkins-infra:master' into master
Alaurant Aug 26, 2024
45a2b0f
Merge branch 'feature'
Alaurant Aug 26, 2024
5e3d6af
fix the problem of static method
Alaurant Aug 26, 2024
c3f766d
Revert "fix the problem of static method"
Alaurant Aug 26, 2024
c8993bd
Provide a default or empty file path
Alaurant Aug 26, 2024
e24ecda
update static method
Alaurant Aug 26, 2024
3f0fc8f
Merge branch 'jenkins-infra:master' into master
Alaurant Sep 9, 2024
9d7a0aa
Merge branch 'jenkins-infra:master' into master
Alaurant Sep 12, 2024
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
54 changes: 54 additions & 0 deletions .github/workflows/teamsync_check_for_changes.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
name: teamSync check for changes

on:
push:
branches:
- master
pull_request:
branches:
- master

jobs:
check-permissions:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Set up JDK
uses: actions/setup-java@v4
with:
java-version: '21'
distribution: 'adopt'

- name: Build project
run: mvn clean install

- name: Check for yml changes
id: files
run: |
echo "Checking for changes in permissions/*.yml files..."
FILES=$(git diff --name-only ${{ github.event.before }} ${{ github.sha }} -- 'permissions/*.yml')
Copy link
Contributor

Choose a reason for hiding this comment

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

This relies on every single execution being successful (assuming no infra trouble ever), which seems unsafe.

Copy link
Member

Choose a reason for hiding this comment

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

There's a sweeper that runs once per week, I umm'ed and erred on this. Only operating on changes files will certainly be quicker, but why re-invent the wheel instead of using something like terraform which can maintain the state?

Copy link
Member

Choose a reason for hiding this comment

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

Wouldn't terraform be a bit over the top for this PR?

Copy link
Member

Choose a reason for hiding this comment

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

its a standard infra as code tool, rather than re-implementing the wheel, it allows more people to collaborate especially from e.g. the infra team.


if [[ -z "$FILES" ]]; then
echo "No changes detected in permissions files."
else
echo "Changes detected. Processing..."
for file in $FILES
do
echo "Processing changes in $file"
GIT_DIFF=$(git diff ${{ github.event.before }} ${{ github.sha }} -- "$file")

if [[ "$GIT_DIFF" == *"github_team"* || "$GIT_DIFF" == *"developers"* ]]; then
file="${file#permissions/}"
echo "Updating the team in: $file"
java -jar target/github_team_sync.jar "$file"
else
echo "No relevant changes to the team in: $file"
fi
done
fi
env:
GITHUB_OAUTH: ${{ secrets.HOSTING_PAT }}
35 changes: 35 additions & 0 deletions .github/workflows/teamsync_update_automatically.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
name: teamSync Update Automatically

on:
schedule:
- cron: '00 00 * * 1' # UTC time at 00:00 on Monday

jobs:
check-permissions:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Set up JDK
uses: actions/setup-java@v4
with:
java-version: '21'
distribution: 'adopt'

- name: Build project
run: mvn clean install

- name: Update all yml files in permissions directory
Copy link
Contributor

Choose a reason for hiding this comment

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

This message appears to be misleading, as it claims to modify yml files, rather than use them as a reference (which seems to be what YmlTeamLoader#loadTeam does).

run: |
echo "Updating all permissions files..."
for file in permissions/*.yml; do
file="${file#permissions/}"
echo "Updating the team in: $file"
java -jar target/github_team_sync.jar "$file"
done
echo "All permissions files updated."
env:
GITHUB_OAUTH: ${{ secrets.HOSTING_PAT }}
24 changes: 23 additions & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -67,10 +67,32 @@
<phase>package</phase>
<configuration>
<descriptors>
<descriptor>src/assembly.xml</descriptor>
<descriptor>src/assembly/assembly.xml</descriptor>
</descriptors>
</configuration>
</execution>
<execution> <!-- GitHub TeamSync -->
<id>GitHub TeamSync</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
<configuration>
<descriptors>
<descriptor>src/assembly/teamSync.xml</descriptor>
</descriptors>
<archive>
<manifest>
<mainClass>io.jenkins.infra.repository_permissions_updater.github_team_sync.GitHubTeamSyncExecutor</mainClass>
</manifest>
</archive>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
<finalName>github_team_sync</finalName>
<appendAssemblyId>false</appendAssemblyId>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
Expand Down
12 changes: 0 additions & 12 deletions src/assembly.xml

This file was deleted.

21 changes: 21 additions & 0 deletions src/assembly/assembly.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<assembly>
<id>bin</id>
<formats>
<format>dir</format>
</formats>
<includeBaseDirectory>false</includeBaseDirectory>
<fileSets>
<fileSet>
<directory>target/classes/</directory>
<outputDirectory>/</outputDirectory>
<excludes>
<exclude>io/jenkins/infra/repository_permissions_updater/github_team_sync/*.class</exclude>
</excludes>
</fileSet>
</fileSets>
<dependencySets>
<dependencySet>
<scope>runtime</scope>
</dependencySet>
</dependencySets>
</assembly>
16 changes: 16 additions & 0 deletions src/assembly/teamSync.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<assembly>
<id>GitHub TeamSync</id>
<formats>
<format>jar</format>
</formats>
<includeBaseDirectory>false</includeBaseDirectory>
<fileSets>
<fileSet>
<directory>target/classes/</directory>
<outputDirectory>/</outputDirectory>
<includes>
<include>io/jenkins/infra/repository_permissions_updater/github_team_sync/*.class</include>
</includes>
</fileSet>
</fileSets>
</assembly>
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package io.jenkins.infra.repository_permissions_updater.github_team_sync;

public class GitHubTeamSyncExecutor {

public static void main(String[] args) {

if (args.length == 0) {
System.out.println("No file path provided.");
System.exit(1);
}

String ymlFilePath = args[0];
GithubTeamDefinition team = YmlTeamLoader.loadTeam(ymlFilePath);
TeamUpdater.updateTeam(team);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package io.jenkins.infra.repository_permissions_updater.github_team_sync;

import java.util.Set;

public class GithubTeamDefinition {

private String RepoName = "";
private String TeamName = "";
private Set<String> developers;

public GithubTeamDefinition(String RepoName, String TeamName, Set<String> developers) {
this.RepoName = RepoName;
this.TeamName = TeamName;
this.developers = developers;
}

public GithubTeamDefinition() {
}

public String getName() {
return RepoName;
}

public void setName(String name) {
this.RepoName = name;
}

public Set<String> getDevelopers() {
return developers;
}

public void setDevelopers(Set<String> developers) {
this.developers = developers;
}

// Lauren part - team name
public String getTeamName(){
return TeamName;
}

public void setTeamName(String TeamName){
this.TeamName = TeamName;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
package io.jenkins.infra.repository_permissions_updater.github_team_sync;

import java.io.IOException;
import java.util.HashSet;
import java.util.Set;

import org.kohsuke.github.GHOrganization;
import org.kohsuke.github.GHRepository;
import org.kohsuke.github.GHTeam;
import org.kohsuke.github.GHUser;
import org.kohsuke.github.GitHub;
import org.kohsuke.github.GitHubBuilder;

public class TeamUpdater {



public static void updateTeam(GithubTeamDefinition team) {
try {
GitHub github = new GitHubBuilder().withOAuthToken(System.getenv("GITHUB_OAUTH")).build();

String[] parts = team.getName().split("/");
String orgName = parts[0];
String repoName = parts[1];

GHOrganization org = github.getOrganization(orgName);
GHRepository repo = org.getRepository(repoName);
GHTeam ghTeam = org.getTeamByName(team.getTeamName());

if (repo != null){

if (ghTeam == null){

if (team.getDevelopers().size() <= 0) {
System.out.println("No developers in the team. Team not created.");
return;

}else{
// Case 1: Team does not exist
ghTeam = org.createTeam(team.getTeamName()).privacy(GHTeam.Privacy.CLOSED).create();
updateDevelopers(github, ghTeam, team.getDevelopers(), Operation.ADD);
ghTeam.add(repo, GHOrganization.RepositoryRole.custom("push"));
System.out.println("Team: '" + team.getTeamName() + "' created and added to repository: " + repoName);
}


}

// Case 2: Team exists
Set<String> currentMembers = new HashSet<>();
for (GHUser member : ghTeam.listMembers()) {
currentMembers.add(member.getLogin());
}

// Case 2.1: developers to add
Set<String> toAdd = new HashSet<>(team.getDevelopers());
toAdd.removeAll(currentMembers);

if (!toAdd.isEmpty()) {
updateDevelopers(github, ghTeam, toAdd, Operation.ADD);
}

// Case 2.2: developers to remove
Set<String> toRemove = new HashSet<>(currentMembers);
toRemove.removeAll(team.getDevelopers());

if (!toRemove.isEmpty()){
if (team.getDevelopers().size() > 0) {
updateDevelopers(github, ghTeam, toRemove, Operation.REMOVE);
}else{
try {
ghTeam.delete();
System.out.println("No developers in the team, team deleted: " + ghTeam.getName());
} catch (IOException e) {
System.err.println("Failed to delete the team: " + ghTeam.getName() + ", error: " + e.getMessage());
}
}
}

} else {
System.out.println("Repository not found: " + repoName);
}


} catch (IOException e) {
System.out.println("Error connecting to GitHub or fetching repository.");
e.printStackTrace();
}
}

public enum Operation {
ADD,
REMOVE
}

public static void updateDevelopers(GitHub github, GHTeam ghTeam, Set<String> developers, Operation operation) {
for (String dev : developers) {
try {
GHUser user = github.getUser(dev);
if (operation == Operation.ADD) {
ghTeam.add(user);
System.out.println("Developer '" + dev + "' added to team: " + ghTeam.getName());
} else if (operation == Operation.REMOVE) {
ghTeam.remove(user);
System.out.println("Developer '" + dev + "' removed from team: " + ghTeam.getName());
}
} catch (IOException e) {
System.out.println("Developer '" + dev + "' not found in GitHub or error in updating: " + e.getMessage());
}
}
}



}
Loading