Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ Gitify uses a forge adapter pattern (see [`MAINTAINERS.md`](MAINTAINERS.md)) so
| **GitHub** Enterprise Server (≥ 3.13) | ✅ Supported | ✅ | ✅ | ✅ | ✅ | ✅ |
| **GitHub** Enterprise Cloud with Data Residency | ✅ Supported | ✅ | ✅ | ✅ | ✅ | ✅ |
| **Gitea** (incl. Forgejo, Codeberg) | ✅ Supported | ✅ | ✅ | — | — | — |
| **Bitbucket** Cloud | 🚧 | | ✅ | ✅ | ✅ | — |
| **GitLab** (todos) | 💭 Considering | — | — | — | — | — |
| **Bitbucket** Cloud | 💭 Considering | — | — | — | — | — |
| **Azure DevOps** | 💭 Considering | — | — | — | — | — |
| **Gerrit** | 💭 Considering | — | — | — | — | — |

Expand Down
53 changes: 38 additions & 15 deletions codegen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,35 +3,58 @@ import dotenv from 'dotenv';

dotenv.config();

if (!process.env.GITHUB_TOKEN) {
const githubConfig: CodegenConfig['generates'][string] | null = process.env
.GITHUB_TOKEN
? {
plugins: ['typescript-operations', 'typed-document-node'],
config: {
documentMode: 'string',
scalars: {
DateTime: 'string',
URI: '../../../../../types#Link',
},
useTypeImports: true,
},
}
: null;

if (!githubConfig) {
// biome-ignore lint/suspicious/noConsole: CLI script output
console.warn(
'\x1b[33m⚠ GITHUB_TOKEN is not set. Skipping GraphQL codegen.\n' +
' To generate updated types, create a .env file with a valid GitHub PAT.\n' +
'\x1b[33m⚠ GITHUB_TOKEN is not set. Skipping GitHub GraphQL codegen.\n' +
' To generate updated GitHub types, create a .env file with a valid GitHub PAT.\n' +
' See .env.template for details.\x1b[0m',
);
process.exit(0);
}

const config: CodegenConfig = {
overwrite: true,
schema: {
'https://api.github.com/graphql': {
headers: {
Authorization: `Bearer ${process.env.GITHUB_TOKEN}`,
},
},
},
documents: ['src/renderer/utils/forges/github/**/*.graphql'],
generates: {
'src/renderer/utils/forges/github/graphql/generated/graphql.ts': {
...(githubConfig
? {
'src/renderer/utils/forges/github/graphql/generated/graphql.ts': {
schema: {
'https://api.github.com/graphql': {
headers: {
Authorization: `Bearer ${process.env.GITHUB_TOKEN}`,
},
},
},
documents: ['src/renderer/utils/forges/github/**/*.graphql'],
...githubConfig,
},
}
: {}),
'src/renderer/utils/forges/bitbucket/graphql/generated/graphql.ts': {
schema: 'https://developer.atlassian.com/gateway/api/graphql',
documents: ['src/renderer/utils/forges/bitbucket/**/*.graphql'],
plugins: ['typescript-operations', 'typed-document-node'],
config: {
documentMode: 'string',
// enumType: 'native',
enumType: 'native',
scalars: {
DateTime: 'string',
URI: '../../../../../types#Link',
URL: '../../../../../types#Link',
},
useTypeImports: true,
},
Expand Down
10 changes: 10 additions & 0 deletions src/renderer/__mocks__/account-mocks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,16 @@ export const mockGiteaAccount: Account = {
user: mockGitifyUser,
};

export const mockBitbucketAccount: Account = {
forge: 'bitbucket',
platform: 'Bitbucket Cloud',
method: 'Personal Access Token',
token: 'token-bitbucket' as Token,
hostname: 'bitbucket.org' as Hostname,
username: 'user@example.com',
user: mockGitifyUser,
};

export function mockAccountWithError(error: GitifyError): AccountNotifications {
return {
account: mockGitHubCloudAccount,
Expand Down
9 changes: 8 additions & 1 deletion src/renderer/context/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -561,12 +561,18 @@ export const AppProvider = ({ children }: { children: ReactNode }) => {
* Login with Personal Access Token (PAT).
*/
const loginWithPersonalAccessToken = useCallback(
async ({ token, hostname, forge }: LoginPersonalAccessTokenOptions) => {
async ({
token,
hostname,
username,
forge,
}: LoginPersonalAccessTokenOptions) => {
const resolvedForge: Forge = forge ?? 'github';
const encryptedToken = (await encryptValue(token)) as Token;
await getAdapter(resolvedForge).fetchAuthenticatedUser({
forge: resolvedForge,
hostname,
username,
token: encryptedToken,
} as Account);

Expand All @@ -586,6 +592,7 @@ export const AppProvider = ({ children }: { children: ReactNode }) => {
token,
hostname,
resolvedForge,
username,
);

persistAuth(updatedAuth);
Expand Down
20 changes: 20 additions & 0 deletions src/renderer/routes/Accounts.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -292,5 +292,25 @@ describe('renderer/routes/Accounts.tsx', () => {
},
);
});

it('should show login with bitbucket personal access token', async () => {
await act(async () => {
renderWithProviders(<AccountsRoute />, {
auth: { accounts: [mockOAuthAccount] },
});
});

await userEvent.click(screen.getByTestId('account-add-new'));
await userEvent.click(screen.getByTestId('account-add-bitbucket-pat'));

expect(navigateMock).toHaveBeenCalledTimes(1);
expect(navigateMock).toHaveBeenCalledWith(
'/login-personal-access-token',
{
replace: true,
state: { forge: 'bitbucket' },
},
);
});
});
});
17 changes: 17 additions & 0 deletions src/renderer/routes/Accounts.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,13 @@ export const AccountsRoute: FC = () => {
});
};

const loginWithBitbucketPersonalAccessToken = () => {
return navigate('/login-personal-access-token', {
replace: true,
state: { forge: 'bitbucket' as const },
});
};

const loginWithOAuthApp = () => {
return navigate('/login-oauth-app', { replace: true });
};
Expand Down Expand Up @@ -374,6 +381,16 @@ export const AccountsRoute: FC = () => {
</ActionList.LeadingVisual>
Login with Gitea (Personal Access Token)
</ActionList.Item>

<ActionList.Item
data-testid="account-add-bitbucket-pat"
onSelect={() => loginWithBitbucketPersonalAccessToken()}
>
<ActionList.LeadingVisual>
<KeyIcon />
</ActionList.LeadingVisual>
Login with Bitbucket (Atlassian API Token)
</ActionList.Item>
</ActionList>
</ActionMenu.Overlay>
</ActionMenu>
Expand Down
Loading
Loading