Add check for permission denied in Linux and add action to fix permissions

Signed-off-by: Sanjula Ganepola <sanjulagane@gmail.com>
This commit is contained in:
Sanjula Ganepola
2024-11-24 18:00:49 -05:00
parent a61ceb8857
commit 195c296891
5 changed files with 86 additions and 10 deletions

View File

@@ -156,6 +156,12 @@
"title": "Start", "title": "Start",
"icon": "$(debug-start)" "icon": "$(debug-start)"
}, },
{
"category": "GitHub Local Actions",
"command": "githubLocalActions.fixPermissions",
"title": "Fix Permissions",
"icon": "$(unlock)"
},
{ {
"category": "GitHub Local Actions", "category": "GitHub Local Actions",
"command": "githubLocalActions.runAllWorkflows", "command": "githubLocalActions.runAllWorkflows",
@@ -366,6 +372,10 @@
"command": "githubLocalActions.startComponent", "command": "githubLocalActions.startComponent",
"when": "never" "when": "never"
}, },
{
"command": "githubLocalActions.fixPermissions",
"when": "never"
},
{ {
"command": "githubLocalActions.runAllWorkflows", "command": "githubLocalActions.runAllWorkflows",
"when": "never" "when": "never"
@@ -555,6 +565,11 @@
"when": "view == components && viewItem =~ /^githubLocalActions.component_Not Running.*/", "when": "view == components && viewItem =~ /^githubLocalActions.component_Not Running.*/",
"group": "inline@1" "group": "inline@1"
}, },
{
"command": "githubLocalActions.fixPermissions",
"when": "view == components && viewItem =~ /^githubLocalActions.component_Invalid Permissions.*/",
"group": "inline@1"
},
{ {
"command": "githubLocalActions.runAllWorkflows", "command": "githubLocalActions.runAllWorkflows",
"when": "view == workflows && viewItem =~ /^githubLocalActions.workspaceFolderWorkflows.*/ && workspaceFolderCount > 1", "when": "view == workflows && viewItem =~ /^githubLocalActions.workspaceFolderWorkflows.*/ && workspaceFolderCount > 1",

View File

@@ -369,7 +369,9 @@ export class Act {
await tasks.executeTask({ await tasks.executeTask({
name: 'nektos/act', name: 'nektos/act',
detail: 'Install nektos/act', detail: 'Install nektos/act',
definition: { type: 'nektos/act installation' }, definition: {
type: 'nektos/act installation'
},
source: 'GitHub Local Actions', source: 'GitHub Local Actions',
scope: TaskScope.Workspace, scope: TaskScope.Workspace,
isBackground: true, isBackground: true,

View File

@@ -14,6 +14,7 @@ export interface Component<T extends CliStatus | ExtensionStatus> {
information: string, information: string,
installation: () => Promise<void>, installation: () => Promise<void>,
start?: () => Promise<void>, start?: () => Promise<void>,
fixPermissions?: () => Promise<void>,
message?: string message?: string
} }
@@ -21,7 +22,8 @@ export enum CliStatus {
Installed = 'Installed', Installed = 'Installed',
NotInstalled = 'Not Installed', NotInstalled = 'Not Installed',
Running = 'Running', Running = 'Running',
NotRunning = 'Not Running' NotRunning = 'Not Running',
InvalidPermissions = 'Invalid Permissions'
} }
export enum ExtensionStatus { export enum ExtensionStatus {
@@ -145,7 +147,9 @@ export class ComponentsManager {
await tasks.executeTask({ await tasks.executeTask({
name: 'Docker Engine', name: 'Docker Engine',
detail: 'Start Docker Engine', detail: 'Start Docker Engine',
definition: { type: 'GitHub Local Actions' }, definition: {
type: 'Start Docker Engine'
},
source: 'GitHub Local Actions', source: 'GitHub Local Actions',
scope: TaskScope.Workspace, scope: TaskScope.Workspace,
isBackground: true, isBackground: true,
@@ -161,7 +165,7 @@ export class ComponentsManager {
problemMatchers: [], problemMatchers: [],
runOptions: {}, runOptions: {},
group: TaskGroup.Build, group: TaskGroup.Build,
execution: new ShellExecution('sudo dockerd') execution: new ShellExecution('systemctl start docker')
}); });
} else { } else {
window.showErrorMessage(`Invalid environment: ${process.platform}`, 'Report an Issue').then(async value => { window.showErrorMessage(`Invalid environment: ${process.platform}`, 'Report an Issue').then(async value => {
@@ -198,6 +202,53 @@ export class ComponentsManager {
}); });
} }
}); });
},
fixPermissions: async () => {
if (process.platform === Platform.linux) {
window.showInformationMessage('By default, the Docker daemon binds to a Unix socket owned by the root user. To manage Docker as a non-root user, a Unix group called "docker" should be created with your user added to it.', 'Proceed', 'Learn More').then(async value => {
if (value === 'Proceed') {
await tasks.executeTask({
name: 'Docker Engine',
detail: 'Fix Docker Engine Permissions',
definition: {
type: 'Fix Docker Engine Permissions'
},
source: 'GitHub Local Actions',
scope: TaskScope.Workspace,
isBackground: true,
presentationOptions: {
reveal: TaskRevealKind.Always,
focus: false,
clear: true,
close: false,
echo: true,
panel: TaskPanelKind.Shared,
showReuseMessage: false
},
problemMatchers: [],
runOptions: {},
group: TaskGroup.Build,
execution: new ShellExecution('sudo groupadd docker; sudo usermod -aG docker $USER; newgrp docker')
});
window.withProgress({ location: { viewId: ComponentsTreeDataProvider.VIEW_ID } }, async () => {
// Delay 4 seconds for Docker to be started
const delay = (ms: number) => new Promise(resolve => setTimeout(resolve, ms));
await delay(4000);
// Check again for docker status
const newDockerCliInfo = await this.getCliInfo('docker version', /Client:\n.+\n\sVersion:\s+(.+)/, true, true);
if (dockerCliInfo.status !== newDockerCliInfo.status) {
componentsTreeDataProvider.refresh();
}
});
} else if (value === 'Learn More') {
await env.openExternal(Uri.parse('https://docs.docker.com/engine/install/linux-postinstall/#manage-docker-as-a-non-root-user'));
}
});
} else {
window.showErrorMessage(`Permissions cannot be automatically fixed for ${process.platform} environment.`);
}
} }
}); });
@@ -234,7 +285,7 @@ export class ComponentsManager {
async getUnreadyComponents(): Promise<Component<CliStatus | ExtensionStatus>[]> { async getUnreadyComponents(): Promise<Component<CliStatus | ExtensionStatus>[]> {
const components = await this.getComponents(); const components = await this.getComponents();
return components.filter(component => component.required && [CliStatus.NotInstalled, CliStatus.NotRunning, ExtensionStatus.NotActivated].includes(component.status)); return components.filter(component => component.required && [CliStatus.NotInstalled, CliStatus.NotRunning, CliStatus.InvalidPermissions, ExtensionStatus.NotActivated].includes(component.status));
} }
async getCliInfo(command: string, versionRegex: RegExp, ignoreError: boolean, checksIfRunning: boolean): Promise<{ version?: string, status: CliStatus }> { async getCliInfo(command: string, versionRegex: RegExp, ignoreError: boolean, checksIfRunning: boolean): Promise<{ version?: string, status: CliStatus }> {
@@ -246,7 +297,9 @@ export class ComponentsManager {
if (ignoreError && version) { if (ignoreError && version) {
resolve({ resolve({
version: version[1], version: version[1],
status: CliStatus.NotRunning status: (process.platform === Platform.linux && error.message.toLowerCase().includes('permission denied')) ?
CliStatus.InvalidPermissions :
CliStatus.NotRunning
}); });
} else { } else {
resolve({ resolve({

View File

@@ -27,9 +27,15 @@ export default class ComponentsTreeDataProvider implements TreeDataProvider<Gith
const start = componentTreeItem.component.start; const start = componentTreeItem.component.start;
if (start) { if (start) {
await start(); await start();
}
this.refresh(); this.refresh();
}
}),
commands.registerCommand('githubLocalActions.fixPermissions', async (componentTreeItem: ComponentTreeItem) => {
const fixPermissions = componentTreeItem.component.fixPermissions;
if (fixPermissions) {
await fixPermissions();
this.refresh();
}
}) })
); );
} }

View File

@@ -17,12 +17,12 @@ export class DecorationProvider implements FileDecorationProvider {
badge: '✅', badge: '✅',
color: new ThemeColor('GitHubLocalActions.green') color: new ThemeColor('GitHubLocalActions.green')
}; };
} else if (!required && (status === CliStatus.NotInstalled || status === CliStatus.NotRunning || status === ExtensionStatus.NotActivated)) { } else if (!required && (status === CliStatus.NotInstalled || status === CliStatus.NotRunning || status === CliStatus.InvalidPermissions || status === ExtensionStatus.NotActivated)) {
return { return {
badge: '⚠️', badge: '⚠️',
color: new ThemeColor('GitHubLocalActions.yellow') color: new ThemeColor('GitHubLocalActions.yellow')
}; };
} else if (required && (status === CliStatus.NotInstalled || status === CliStatus.NotRunning || status === ExtensionStatus.NotActivated)) { } else if (required && (status === CliStatus.NotInstalled || status === CliStatus.NotRunning || status === CliStatus.InvalidPermissions || status === ExtensionStatus.NotActivated)) {
return { return {
badge: '❌', badge: '❌',
color: new ThemeColor('GitHubLocalActions.red') color: new ThemeColor('GitHubLocalActions.red')